We need to agree on a preliminary "Portable xKernel Interface".  I
expect this interface to be refined during the next few months as we
implement the portable xkernel on different platforms---SunOS_user,
SunOS_embedded, Mach_user, Mach_embedded---but we need to start
somewhere, so here goes...


Typedefs
========

typedef	struct xobj {
  XObjType type;
  char  *name;
  char	*state;
  Bind  binding;
  int   rcnt;
  int	id;
  int	instance;
  Pfi	open;
  Pfi 	close;
  Pfi   closedone;
  Pfi	openenable;
  Pfi	opendisable;
  Pfi	opendone;
  Pfi 	demux;
  Pfi 	pop;
  Pfi 	push;
  Pfi 	control; 
  int 	numdown;
  int	downlistsz;
  struct xobj  *down[8];
  struct xobj **downlist;
  struct xobj  *myprotl;
  struct xobj  *up;
} *XObj;


typedef struct xenable {
  XObj	hlp;
  XBind	binding;
  int	rcnt;
} Enable;


Protocol-Protocol Operations
============================

/* same as in 3.1 */
XObj xOpen(XObj hlp, XObj llp, Part *participants)

/* saves a binding to an enable object in its passive map */
int xOpenEnable(XObj hlp, XObj llp, Part *participants)

/* Remove enable object from passive map if rcnt goes to 0 */
int xOpenDisable(XObj hlp, XObj llp, Part *participants)

/* like 3.1's x_callopendone; the original x_opendone goes away */
int xOpenDone(XObj hlp, XObj s, Part *participants)

/* same as in 3.1 */
int xCloseDone(XObj s)
					
/* applies to both protocol and session objects */
int xClose(XObj objext)

/* same as in 3.1 */
int xDemux(XObj s, Msg *msg)

/* same as in 3.1 */
int xPush(XObj s, Msg *msg, Msg *rmsg)

/* same as in 3.1 */
int xPop(XObj self, XObj s, Msg *msg)

/* controlsessn and controlprotl go away */
int xControl(XObj self, int opcode, char *buf, int len)


Initialization Operations
=========================
				
/* replaces x_instantiateprotl and xcreateprotl (the user routine); */
/* eliminates the need for x_getproc; every protocol has to provide */
/* an init function (with a well-known name like tcp_init) that gets */
/* called to initialize a protocol object; this routine does what */
/* x_init does now plus fills in the protocol functions currently */
/* done in x_getproc; it mallocs an xobj and fills in the down */
/* pointers before calling the init routine */
XObj xCreateProtl(Pfi f, char *name, int id, int downc, XObj *downv)	

/* symmetric w/ createprotl; mallocs an xobj, fills in the down */
/* pointers, etc, and then calls the the init function f to fill */
/* in the function pointers; the name of f need not be well-known */
/* because createsessn is called from within the protocol */
XObj xCreateSessn(Pfi f, XObj hlp, XObj llp, int downc, XObj *downv)

/* destroys protocol and session objects; called by closeprotl & closesessn */
int xDestroy(XObj object)



Utility Routines
================

/* same as in 3.1 */
XObj xGetProtlByName(char *name)

/* manipulate the down pointer; Set increments numdown as a side effect */
xSetDown(XObj self, int index, XObj object)			
XObj xGetDown(XObj self, int index)

/* just like malloc and free */
char *xMalloc(int size)			
int xFree(char *buf)

/* just like in Unix */
u_short ntohs(u_short n)
u_long ntohl(u_long n)
u_short htons(u_short n)
u_long htonl(u_long n)


Message Library
===============

typedef struct {
  long       length;
  long       offset;
  MNode*     tree;
  MNodeLeaf* stack;
  void*	     attr;
} Msg;

/* initializer; must be called before any messages are  */
/* created; returns TRUE after successful intialization	*/
bool msgInit();


/************* constructors/destructors **************/
/* construct; an empty Msg */
void msgConstructEmpty(Msg* this);

/* construct a Msg with a copy of the content of the buffer buf with */
/* length len; this constructor causes data to be copied!! */
void msgConstructBuffer(Msg* this, char *buf, long len);

/* construct a Msg from another Msg */
void msgConstructCopy(Msg* this, Msg *another);

/* construct a Msg that refers to a contig */
void msgConstructContig(Msg* this, MContig* contig);

/* constructor... to this Msg an uninitialized contig */
/* of length len and return a pointer to the contig in buf */
void msgConstructAllocate(Msg* this, long len, char **buf);

/* destructor */
void msgDestroy(Msg* this);



/************* regular protocols call these **************/
/* assignment */
void msgAssign(Msg* this, Msg* m);

/* return the current length of the message */
long msgLen(Msg *this);

/* truncate this Msg to length newLength */
void msgTruncate(Msg* this, long newLength);

/* remove a chunk of length len from the head of this Msg */
/* and assign it to head; like old break */
void msgChopOff(Msg* this, Msg* head, long len);

/* assign to this Msg the concatenation of m1 and m2 */
void msgJoin(Msg* this, Msg* m1, Msg* m2);

/* push a header onto this Msg.  arg is passed through to the store function */
void msgPush(Msg* this, MStoreFun store, void *hdr, long hdrLen, void *arg);

/* pop a header from this Msg.  arg is passed through to the load function. */
/* returns TRUE after successful pop */
bool msgPop(Msg* this, MLoadFun load, void *hdr, long hdrLen, void *arg);

/* pop and discard an object of length len */
/* returns TRUE after successful pop */
bool msgPopDiscard(Msg *this, long len);

/*
 * associate an attribute with a message
 */
void msgSetAttr(Msg *this, void *attribute);

/*
 * retrieve an attribute associated with a message
 */
void msgGetAttr(Msg *this, void *attribute);



/************* get to the data in the message **************/
/* for every contig in this Msg, invoke the function f with */
/* arguments const char *buf (=address of contig), long len */
/* (=length of contig), and void *arg (=user-supplied argument), */  
/* while f returns TRUE */
void msgForEach(Msg *this, MCharFun f, void *arg);

/* for every contig in this Msg, invoke the function f with  */
/* arguments MContig *contig (=address of contig object), long offset, */
/* long length, and void *arg (=user-supplied argument), */
/* while f returns TRUE */
/* the memory described by contig may not be accessible!! */
void msgForEachContig(Msg *this, MContigFun f, void *arg);



/************* virtual memory funniness **************/
/* import a Msg from a different address space */
/* makes the content of the Msg foreign (contigs which may reside in */
/* a different address space) accessible in the current address space */
void msgImport(Msg* this, Msg* foreign);

/* lock the memory associated with the Msg in physical memory */
/* returns FALSE, if not all contigs of the Msg can be locked */
bool msgLock(Msg* this);

/* unlock the memory associated with the Msg */
/* returns FALSE, if not all contigs of the Msg can be unlocked */
bool msgUnlock(Msg* this);	



/* 
 * types of user functions called in ForEach()
 */
typedef bool (*MCharFun)(char *ptr, long len, void *arg);
typedef bool (*MContigFun)(MContig *contig, long offset, long len, void *arg);

/*
 * the MContig structure
 * the memory descriptor structure
 */
typedef struct {
  /* size of contig */
  long   size;
  char*  addr;
 
  /* copy from a buffer into the contig at offset; */
  /* return the number of bytes copied */
  long (*copyIn)(char* from, long offset, long size);

  /* copy from the contig at offset to a buffer; */
  /* return the number of bytes copied */
  long (*copyOut)(char* to, long offset, long size);

} MContig;


/*
 * types of load and store functions for headers
 */

/* function to convert the header to network byte order and store it 
 * in a potentially unaligned buffer;  				     
 * 'len' is the number of bytes to be read and 'arg' is an arbitrary
 * argument passed through msgPop
 */
void (*MStoreFun)(void *hdr, char *des, long len, void *arg);

/* function to load the header from a potentially unaligned buffer, 	
 * and convert it to machine byte order.
 * 'len' is the number of bytes to be read and 'arg' is an arbitrary
 * argument passed through msgPop
 */
void (*MLoadFun)(void *hdr, char *src, long len, void *arg);



Map_Library
===========

Same as before except it supports only one "remove binding" operation:

	int mapResolve(Map, char *ext)
	Bind mapBind(Map, char *ext, int intern)
	int mapRemove(Map, Bind)


Event Library
=============

/* schedule an event that executes f w/ argument a after delay t usec; */
/* t may equal 0, which implies createprocess */
Event evSchedule(Pfi f, int a, int t)


/* releases a handel to an event; as soon f completes, the resources
/* associated with the event are freed */
evDetach(Event e)

/* cancel event e; returns TRUE if can guarantee f will not execute; */
/* returns FALSE if can guarantee to execute f */
evCancel(Event e)


Participant Library
===================

Same as in 3.1

	partInit(Part *, int num, type)
	partSet(Part *, int which, value)
	partGet(Part *, int which, type)


Synchronization Library
=======================

/* initalize semaphore to given count; /*
/* The platform is reponsible for defining typedef Semaphore */
semInit(Semaphore *s, int cnt)
semWait(Semaphore *s)
semSignal(Semaphore *s)


Time
====

/* Same time structure as Unix */

typedef struct {
  long sec;
  long usec;
} XTime;

/* set *t to the current time of day */
void xGetTime(XTime *t)



Debugging Library
=================

/* same as 3.1 (no printf's); we'll probably define some standard */
/* trace variables, e.g., protocols, events... */
xTrace*(...)
xIfTrace(bool exp)

/* same as in 3.1 */
xAssert(bool exp)



Errors
======

ERR_XOBJ
ERR_BIND
ERR_ENABLE


TODO
====
checkLen
