/* (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. */
/* SCCS Info: @(#)li.h	1.17 3/13/90 */

#ifndef li_included

#include <sys/types.h>

#include "stdnil.h"
#include "listp.h"
 
void nilerror();		/* print out a nil error. */
void nilperror();		/* print a nil error and the unix error msg. */

#undef DISTRIBUTED
				/* single machine implementation for now. */

#define HOSTIDSIZE 4		/* assume hostnumbers are 4 bytes */

typedef unsigned long remaddr;

typedef struct {
    char hostname[HOSTIDSIZE];
    unsigned number;
} interpname;

typedef struct {
    interpname interp;		/* interpreter where it originated */

    remaddr addr;		/* address within interpreter of object */

} remote_address;


#define MAXOPERANDS 256
				/* maximum operands per operation */
#define MAXPARAMETERS (MAXOPERANDS-1) 
				/* maximum operands per call. */

#define ARBSIZE    1
				/* fudge used for RECFM=V records.  when */
				/*  we define an array type with size */
				/*  ARBSIZE, it means we will always */
				/*  allocate this type of object with */
				/*  getmain(). */

#define VARIANT_SIZE  1
#define VARIANT_COMPONENT 0

#define NO_OBJECT ((object *) -1)
				/* can't use nil (0) since it is list */
				/*  ender.  this is portable on most */
				/*  machines (unix uses this hack), but on */
				/*  non-unix machines it should be checked. */

typedef int comparison;		/* type returned by keycompare routines. */

#define CMP_GREATER 1
#define CMP_EQUAL   0
#define CMP_LESS   -1

#define RAISE_ERROR -1
				/* if raising an exception causes an error */
				/*  this is the "statement number" returned. */

#define PROGRAM_SIZE 4
				/* size of predefined!program record */
				/*  plus one for the L-I code. */

#define program__LI_PROGRAM 3
				/* the fourth component is the L-I code */


/*****************************************************************************
 * EXCEPTION HANDLER FRAMES
 ****************************************************************************/ 
 

/* note: this has to be in synch with predefined!builtin_exception!!!! */
/* fix later */

typedef enum 
{
    CaseError=0, ConstraintError, ConstraintFailure, Depletion, Disconnected,
    DivideByZero, DuplicateKey, InterfaceMismatch, NotFound, PolymorphMismatch,
    DefinitionError, RangeError, Uncopyable, Normal

} predef_exception;		/* this is assumed to be a single-word */
				/*  quantity, since we treat the union */
				/*  type exception as a single word. */

/******************************************************************************
 * SCALAR TYPES
 *****************************************************************************/
 
/*
 * Scalars (with the exception of reals) are stored directly in the valcell
 * of an object since they are no bigger than a pointer.  
 */
 
typedef struct
{
    counter refcount;		/* how many refs to this value? */

    /* the rest is actually the unique value */

    time_t time;		/* time of creation */
    counter num;		/* disambiguating number */
#ifdef DISTRIBUTED
    interpname interp;		/* interpreter id for distributed systems */
#endif

} dfd_nominal;


typedef flag dfd_boolean;       /* booleans are flags which are 0 when false */
                                /*  and non-zero when true. */
 
#define nil_true -1             /* all bits set to one is a good true value. */
#define nil_false 0             /* false is always 0. */
 
typedef counter dfd_enumeration;
                                /* an enumeration is simply a natural number */
 
typedef counter dfd_ord_enumeration;
                                /* ditto for ordered enumerations. */
 
typedef int dfd_integer;        /* an integer is an integer -- we just use */
                                /*  the C operations. */
 
typedef double dfd_real;        /* our reals will probably be four byte */
                                /*  quantities, so we don't store them as */
                                /*  scalars.  we just use C double's, and */
                                /*  the C floating-point operations. */
 
 
/******************************************************************************
 * Forward Reference Definitions
 *****************************************************************************/
 
typedef struct poly_struct dfd_polymorph;
typedef struct cprocessdata_struct cprocessdata;
typedef struct dot_struct dotcontainer;
typedef dotcontainer dfd_record;
typedef dotcontainer dfd_variant;
typedef dotcontainer dfd_callmessage;
typedef dotcontainer pd_program;
 
typedef struct h_stack handlr_stack;

typedef struct run_struct run_proc;
 
typedef struct oplist_struct operand_list;
typedef struct op_struct operation;
 
typedef struct inport_struct local_inport;
typedef struct dfd_table_struct dfd_table;
 
typedef struct object_struct object;

typedef struct pcb_struct pcb;

typedef struct datarep_struct datarep;

typedef union valcell_union valcell;

typedef struct channel_struct channel;

/*
 * Outport
 */
 
typedef channel *dfd_outport;
				/* an outport points to its matching inport. */
                                /*  outports are represented as scalars: */
                                /*  they are stored directly in */
                                /*  the valcell of the object. */

typedef channel dfd_inport;
 
union valcell_union
{
    dfd_nominal *nominal;       /* nominal */
    dfd_boolean boolean;        /* boolean */
    dfd_enumeration enumeration; /* enumeration */
    dfd_ord_enumeration ord_enum; /* ordered enumeration */
    dfd_integer integer;        /* integer */
    dfd_real *real;             /* real */
 
    dfd_record *record;         /* record */
    dfd_variant *variant;       /* variant */
    dfd_table *table;		/* table */
    dfd_polymorph *polymorph;	/* polymorph */

    dfd_inport *inport;         /* inport */
    dfd_outport outport;        /* outport */
    dfd_callmessage *callmessage; /* callmessage */
 
    pd_program *program;	/* a program (absprog + L-I) */

} /* valcell */ ;
 
/******************************************************************************
 * THE UNIVERSAL OBJECT REPRESENTATION
 ******************************************************************************
 *
 * An object has a value and a pointer to its data representation
 * specific generic routines (finalize, copy, equal).  
 */
 
typedef unsigned short tsdrno;

struct datarep_struct
{
    tsdrno number;		/* number of this datarep for file purposes */

    char *name;			/* name of this data representation. */

    void (*finalize)();		/* finalization routine. */

    predef_exception (*copy)();	/* copy routine. */

    status (*equal)();		/* comparison routine. */

    void (*print)();		/* debug printing */

    xdr_status (*xdr)();	/* xdr'ing for files and network */

    comparison (*comparekeys)(); /* compare as key (less, equal, greater) */

    void (*hash)();		/* hashing */

} /* datarep */ ;


extern datarep dr_bottom;

#define isbottom(obj) ((obj)->tsdr is &dr_bottom)


struct object_struct
{
    valcell value;              /* value of the object.  the value itself */
                                /*  if a scalar, otherwise a pointer to the */
                                /*  type-dependent structure. */
 
    datarep *tsdr;		/* typestate and data representation tag. */

} /* object */ ;

typedef object *objectp;


/* object finalization: objects may be freed in one of two ways: normally, */
/* they are discarded, which means that their finalization may cause actions */
/* to occur, such as a process waiting on a port being awoken and given a */
/* disconnected exception (F_DISCARD);  however, when objects are moved */
/* around on the network, we want to free them on the local machine without */
/* causing any side-effects, since the objects still exist, but have simply */
/* been reloacted to another interpreter (F_FREE). */

typedef enum {
    F_DISCARD,			/* do a real finalize. */
    F_FREE			/* when object changes location, just free */
				/*   storage. */
  } finalize_op;

/******************************************************************************
 * DOTTABLE OBJECTS
 *****************************************************************************/
 
/*
 * A "dottable" object is one which can contain visible components.  There
 * are three such types defined in the language: records, variants, and
 * callmessages.  In addition, we represent the rooting context of a process
 * as a dottable object.
 *
 * A dottable object consists of some type-family dependent information
 * and an array of object's.  First, define the info fields for each of the
 * dottable types:
 */
 
/*
 * record
 */
 
typedef counter record_info;    /* number of objects contained in the  */
                                /*  record (required for finalization). */
 
/*
 * variant
 */
 
typedef dfd_enumeration variant_info;
                                /* case of the variant. */
 
/*
 * callmessage
 */
 
typedef struct {
    pcb *caller;                /* calling process to which message is */
                                /*  returned. */

    object *parameters[MAXPARAMETERS];
				/* nil-terminated list of pointers to the */
				/*  parameters of the call. */
} local_cminfo;


typedef union {
    local_cminfo local;
    remote_address remote;
} cminfo_union;

typedef struct
{
    flag local;			/* is it live or is it memorex? */

    counter size;		/* how many components */

    cminfo_union cminfo;	/* appropriate info */

} callmessage_info;
 
/*
 * process context
 */
 
/*
 * the dot_info union type is the union of all of the possible info fields
 * for dottable objects.
 */
 
typedef struct con_struct context_info;

typedef union
{
    record_info record_size;    /* record: holds the size */
    variant_info variant_case;  /* variant: holds the case */
    callmessage_info *callmessage; /* callmessage */
    context_info *context;	/* process context */
    counter program_refcount;	/* number of refs to this process (size = 4) */
 
} dot_info;
 
/*
 * a dotcontainer is used as the default representation of records,
 * variants, and callmessages, as well as for process contexts.
 */
 
struct dot_struct
{
    dot_info info;		/* type-dependent information */

    object data[ARBSIZE];	/* some arbitrary number of objects */
 
} /* dotcontainer */ ;
 

struct con_struct
{
    counter size;               /* number of objects contained in this */
                                /*  context (for de-allocation). */
 
    handlr_stack *estack;      /* exception stack */
 
    dotcontainer *previous;
                                /* previous context.  this is always nil */
                                /*  for the main context of a process, but */
                                /*  non-nil if we are evaluating a */
                                /*  constraint expression. */

} /* context_info */ ;
 
/*
 * polymorph
 */

/* should this be a dotcontainer too??? */

struct poly_struct {

    object obj;			/* the wrapped object */
    object typename;		/* the typename */
    object typestate;		/* its formal typestate */

} /* dfd_polymorph */ ;

/******************************************************************************
 *                               PROCESS
 ******************************************************************************/
 
/* Process environment usage is defined in a separate header file so */
/* it can also be included in the code generator source */

#include "procenv.h"

typedef struct
{
    int opencount;		/* number of ports we are waiting on */

    dfd_inport *waiting_ports[MAXPARAMETERS/2];
				/* for select's, a list of */
				/*  ports we are waiting on. */
    int branch_labels[MAXPARAMETERS/2];
				/* index into selectarms list of operation */
				/*  which retrieves the appropriate branch */
				/*  label target. */
} select_suspend_info;


typedef struct message_struct   /* the queue within an inport */
{
    struct message_struct *next;
                                /* this is a linked_list type. */
 
    valcell value;              /* value it contains */
 
} message;
 
 
typedef struct
{
    dfd_callmessage callmessage;
    object filler[ (MAXPARAMETERS-ARBSIZE) ];
				/* reserves space for a callmessage with */
				/*  MAXPARAMETERS components.  This way, */
				/*  each call doesn't have to do a getmain. */

    callmessage_info cminfo;	/* the callmessage info to go with the */
				/*  above callmessage. */

    message msg;		/* message for the inport queue. */

} call_suspend_info;



typedef union
{
    select_suspend_info select;
    call_suspend_info call;
    object *remote_send;

} susp_info;



typedef enum 
{
    Process,			/* pcb for a regular process */

    ProcedurePrimaryUsed,	/* primary pcb for a procedure.  this is */
				/*  the one that the procports connect to. */
				/*  if it is used, it means that there is a */
				/*  procedure running with this pcb */

    ProcedurePrimaryFree,	/* a primary as above, but the pcb is free */

    ProcedurePrimaryDead,	/* a primary with no more connections to it, */
				/*  but which is still running.  garbage */
				/*  collected as soon as the final procedure */
				/*  terminates. */

    ProcedureSecondary,		/* secondary pcb for a procedure.  created */
				/*  when multiple simultaneous calls */
				/*  are made to a procedure. */

    CProcess			/* a non-Hermes process */

} proc_type;



typedef union {
    dotcontainer *h;		/* hermes process data is a dotcontainer */

    cprocessdata *c;		/* c processes have a special structure */

} processdata;


struct pcb_struct
{
    struct pcb_struct *next;	/* circular pointers relating */
    struct pcb_struct *prev;	/* ready/blocked/... processes */
  
    char *wake_key;		/* key with which to revive suspended proc */

    enum { READY, BLOCKED, REVIVED, KILLED } state;
				/* current state of this process wrt */
				/* scheduler */

    proc_type type;		/* is it a process, a primary procedure,  */
				/*  a secondary procedure, or a */
				/*  foreign proc? */ 

    void (*interpreter)();	/* the function to run which interprets a */
                                /*  single operation of this process. */
 
    processdata ep;		/* pointer to the context of this process. */
 
    counter ip;			/* index of next operation to be */
                                /*  executed (or the current operation if */
                                /*  we are waiting for an event). */

    /* these fields are not used by foreign processes */

    pd_program *prog;		/* absprog and L-I code; nil if this */
				/*  is not a Hermes process. */

    flag selecting;		/* set when we are waiting for a message to */
				/*  wake us up from a select.  when set, */
				/*  suspend_info holds a select_suspend_info */
				/*  struct. */

    susp_info suspend_info;	/* state stored while suspended due to */
				/* a call or a select. */

#ifdef TRACE
    counter call_level;		/* depth of this pcb in the call structure */

    valcell *profile;		/* pointer into vector of profiling info */
#endif
} /* pcb */ ;


/******************************************************************************
 * PROGRAMMING-IN-THE-LARGE TYPES
 *****************************************************************************/
 
/*
 * Inport
 */
 
struct inport_struct
{
    void (*enqueuer)();		/* function used to enqueue objects at this */
                                /*  inport.  normally, this function just */
                                /*  builds a new message and sticks it at */
                                /*  the end of the queue;  but if the port */
                                /*  is to an external function, it might */
                                /*  actually perform the service and return. */

				/* NB: no longer needed now that we have */
				/*  channels?? */

    message *queue;             /* queue of messages at this inport. */
 
    datarep *tsdr;		/* typestate and data representation of the */
				/*  elements of the queue. */

    message *tail;              /* end of queue */
 
    pcb *waiting_owner;         /* if a process suspends itself waiting for */
                                /*  a message on an inport, it makes the */
                                /*  inport point back to it so that the */
                                /*  inport can wake it up when a message */
                                /*  arrives. */
 
} /* local_inport */ ;
 
/*
 * channel
 */

typedef enum {
    LocalInport, LocalProcport, RemotePort
} channel_type;

typedef union {

    local_inport inport;

    pcb *procedure;

    remote_address remote;

} channel_info;

struct channel_struct
{
    channel_type type;		/* local inport, local procport, or remote */

    predef_exception (*port_enq)();
				/* this function enqueues a message on */
				/*  the port.  if a procport, this may */
				/*  cause a new pcb to be allocated. */

    flag disconnected;          /* disconnected flag.  set when the */
				/*  local inport is finalized, or when the */
				/*  remote port NACKs a call/send.  tested a */
                                /*  when send or call is performed. */
				/* never set for procports. */
 
    counter refcount;		/* for a local inport, number of outports */
                                /*  connected to the inport. */
				/* for local procport, number of outports */
				/*  connected to the channel. */
				/* for a remport, number of local */
				/*  connections. */

    channel_info info;		/* channel-type dependent info */

} /* channel */;

/*********** tables *************/

#include "table.h"

typedef struct {

    object *inspectobj;		/* object containing inspected value */
    object *inspectee;		/* table or polymorph it comes from */
    trepnum repnum;		/* table rep in inspectee we are using. */
    position pos;		/* current position (for find, etc). */
    counter rmvcount;		/* # of elements deleted from table */
				/* since frame was established */
} inspect_frame;


typedef union {
    valcell handler_set;	/* interpform!block_handler */
    inspect_frame *inspect;	/* state information for inspect */
} handler_frame;


struct h_stack
{
    struct h_stack *next;	/* next frame down on the stack, which is */
				/*  the frame for the enclosing scope. */

    flag handler;		/* is this a handler or an inspect frame? */

    handler_frame frame;	/* the frame for the current scope */

} /* handlr_stack */ ;

/******************************************************************************
 * RUN-TIME INTERPRETER DATA STRUCTURE
 *****************************************************************************/
 
typedef struct 
{
  pcb *ready;			/* circular queue of ready processes, */
				/* nil if none; 1st proc is always */
				/* currently executing proc */ 
 
  pcb *blocked_nokey;		/* circular list of processes blocked */
				/* on a null key */
  pcb *blocked;			/* circluar list of processes blocked */
				/* on a non-null key */
  pcb *newprocs;		/* circular list of newly created or */
				/* awakened processes */
    
  void (*suspend)(/* schedblock *sched; pcb *proc; char *key */);
				/* fn to suspend a given process */
  void (*wakeup)(/* schedblock *sched; char *key */);
				/* fn to wake up all procs blocked on a */
				/* given key */
  void (*wakeup_proc)(/* schedblock *sched; pcb *proc */);
				/* fn to wake up a given proc */
  void (*kill)(/* schedblock *sched; pcb *proc */);
				/* fn to remove a proc from sched structures */
  void (*add)(/* schedblock *sched; pcb *proc */);
				/* fn to add a new process to the */
				/* ready list */
  void (*make_current)(/* schedblock *sched; pcb *proc */);
				/* fn to make a given pcb current */
  void (*advance)(/* schedblock *sched */);
				/* fn to perform deferred updates to */
				/* scheduling queues at the end of the */
				/* current operation, and advance */
				/* queues to select next ready proc */
} schedblock;



typedef struct
{
    object *operandstack[MAXOPERANDS]; 
				/* addresses of the operands to the */
				/*  current operation */

    counter nextop;		/* the next operation in the current process */
 
    valcell qualifiers;		/* non-object operand of the current */
				/*  operations. */

    schedblock *sched;		/* ready ring pointers and scheduling */
				/*  functions. */
} argblock;
 
 
struct cprocessdata_struct {
    object initport;		/* the initialization port */

    int data[ARBSIZE];		/* arbitrary additional data */

} /* cprocessdata */ ;

#endif
#define li_included
