/* (C) Copyright International Business Machines Corporation 23 January */
/* 1990.  All Rights Reserved. */
/*  */
/* See the file USERAGREEMENT distributed with this software for full */
/* terms and conditions of use. */
/* File: o_cntl.c */
/* Author: David F. Bacon */
#ifndef lint
static char sccsinfo[] = "@(#)o_cntl.c	1.12 3/13/90";
#endif

/* /local/hermes/li/o_cntl.c, Tue Aug 30 09:39:16 1988, David F. Bacon */
/*  moved code to turn off waiting_owner fields of inports being selected */
/*  from the newly reveived select statement to the ip_enqueuer; otherwise, */
/*  waiting process could be revived more than once, trashing the ready list. */
/*  also, wasn't setting the selecting flag, which caused major lossage. */

#include "ops.h"
#include "storage.h"
#include "accessors.h"

#define Dst (DstObj->value)
#define Src (SrcObj->value)
#define Src1 (Src1Obj->value)
#define Src2 (Src2Obj->value)

NILOP(o_branch)
{
  args->nextop = args->qualifiers.integer;
				/* set next operation to the branch label. */
}


NILOP(o_branch_false)
{
  OPCHK(DstObj,boolean);
  if (not Dst.boolean)
    args->nextop = args->qualifiers.integer;
}


NILOP(o_branch_true)
{
  OPCHK(DstObj,boolean);
  if (Dst.boolean)
    args->nextop = args->qualifiers.integer;
}


/*ARGSUSED*/
NILOP(o_noop)
{
}



NILOP(o_block)
{
    context_info *context;
    handlr_stack *hstack;


    if ((hstack = new(handlr_stack)) is nil) {
	raise(Depletion);
	return;
    }

    context = args->sched->ready->ep.h->info.context;
				/* get current context. */
    hstack->handler = TRUE;	/* this is a handler, not a find frame. */
    hstack->frame.handler_set = args->qualifiers;
				/* set frame pointer. */
    cdr(hstack) = context->estack;
    context->estack = hstack;	/* push the new exception handler frame. */
}


NILOP(o_endblock)
{
    context_info *context;
    handlr_stack *deadtop;


    context = args->sched->ready->ep.h->info.context;

    deadtop = context->estack;
    context->estack = cdr(deadtop);
    { dispose(deadtop,handlr_stack); }
}


NILOP(o_exit)
{
    void raise_exit();

    raise_exit(args->qualifiers, args);
}


NILOP(o_raise)
{
    raise((predef_exception) args->qualifiers.enumeration);
}


NILOP(o_select)
{
    int i, j, label;
    flag open[MAXOPERANDS/2];
    objectp bool, ipobj;
    pcb *current;
    int maxopen;
    dfd_inport *ip;
    flag someconnected;


#ifdef OPCHECK
    for (i = 0; args->operandstack[i] isnt nil; i += 2) {
      if (args->operandstack[i] isnt NO_OBJECT)
	assert(OPISTYPE(args->operandstack[i],inport));
      if (args->operandstack[i+1] isnt NO_OBJECT)
	assert(OPISTYPE(args->operandstack[i+1],boolean));
    }
#endif
    current = args->sched->ready;

    maxopen = -1;
    someconnected = FALSE;
    
    for (i = 0, label = 0; args->operandstack[i] isnt nil; 
	 i += 2, label++) {
	bool = args->operandstack[i+1];
	if (bool is NO_OBJECT or bool->value.boolean) {
	    open[label] = TRUE;
	    maxopen = label;
	}
	else {		/* boolean guard exists and is false */
	    open[label] = FALSE;
	    continue;
	}
	
	ipobj = args->operandstack[i];
	if (ipobj isnt NO_OBJECT)
	  if (ipobj->value.inport->info.inport.queue is nil) {
	      if (ipobj->value.inport->refcount isnt 0)
		someconnected = TRUE;
	      continue;
	  }
	
	/* we've found an open guard */
	
	args->nextop = get_elem(args->qualifiers, label).integer;
	return;
    }
    
    if (maxopen is -1) {	/* no open guards... fall thru to otherwise */
	/* hack for compatibility with old codegen... remove later */
	if (size_of(args->qualifiers) is label+1)
	  args->nextop = get_elem(args->qualifiers, label).integer;
	return;	
    }
    
    /* there are open guards but we need to await a message.  open[i] */
    /* is true for every branch for which there is no guard or the guard */
    /* is true.  */
    
    if (not someconnected) { /* need to wait, but we would wait forever */
	raise(Disconnected);
	return;
    }
    
    for (i = 0, j = 0; i <= maxopen; i++) 
      if (open[i]) {
	  current->suspend_info.select.waiting_ports[j] = ip =
	    args->operandstack[i*2]->value.inport;
	  current->suspend_info.select.branch_labels[j] = 
	    get_elem(args->qualifiers, i).integer;
	  j++;
	  
	  ip->info.inport.waiting_owner = current;
      }
    
    current->suspend_info.select.opencount = j;
    current->selecting = TRUE;
    
    args->nextop--;		/* back up to this (select) operation */
    args->sched->suspend(args->sched, current, nil);
    /* take ourselves off the ready list */
}


NILOP(o_jumpselect)
{
    OPCHK(DstObj,integer);
    if (Dst.integer < 0 or 
	Dst.integer > (dfd_integer) size_of(args->qualifiers))
      return;			/* not in jump table... fall thru to next op */

    args->nextop = (counter) get_elem(args->qualifiers, Dst.integer).integer;
}
	
