/*
 *	cifccsp.c -- C interface for CCSP
 *	Copyright (C) 2002 Fred Barnes <frmb2@ukc.ac.uk>
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdarg.h>

#include "dmem_if.h"
#include "mobproc.h"
#include "cifccsp.h"

#ifndef NotProcess_p
	#define NotProcess_p NULL
#endif
#ifndef Enabling_p
	#define Enabling_p NotProcess_p+1
#endif
#ifndef Waiting_p
	#define Waiting_p NotProcess_p+2
#endif
#ifndef Ready_p
	#define Ready_p NotProcess_p+3
#endif
#ifndef TimeSet_p
	#define TimeSet_p NotProcess_p+1
#endif
#ifndef TimeNotSet_p
	#define TimeNotSet_p NotProcess_p+2
#endif


/*
 *	note: these must only be accessed by a single thread context (the run-time kernel)
 */
Process *cifccsp_wptr = NULL;		/* this is used to hold the current Wptr, accessed by the asm bits */
void *cifccsp_savevar = NULL;		/* this is used to hold cifccsp_wptr during external calls */


extern void _killcall (int *);


/*{{{  static void cifccsp_QueueProcess (Process *p)*/
/*
 *	adds a process to the occam run-queue,
 *	done such that priority is handled correctly/respected
 */
static void cifccsp_QueueProcess (Process *p)
{
#if 0
fprintf (stderr, "cifccsp_QueueProcess(): p = %p, p[-3] = %d, p[-2] = %p\n", p, p[-3], (void *)(p[-2]));
#endif
	if (p[-3] == PPriority) {
		/* add to the current queue */
		if (cifccsp_wptr[8] == (int)NotProcess_p) {
			/* run-queue empty, so just this */
			cifccsp_wptr[8] = (int)p;
		} else {
			((int *)(cifccsp_wptr[9]))[-2] = (int)p;
		}
		cifccsp_wptr[9] = (int)p;
		p[-2] = (int)NotProcess_p;
	} else {
		/* add to a different priority queue (need scheduler call) */
		Process *ptrq[2];

		SavePri (p[-3], ptrq);
		if (ptrq[0] == NotProcess_p) {
			/* run-queue empty, so just this */
			ptrq[0] = p;
		} else {
			/* add to back of queue */
			((int *)(ptrq[1]))[-2] = (int)p;
		}
		ptrq[1] = p;
		p[-2] = (int)NotProcess_p;

		StPriF (p[-3], ptrq[0]);
		StPriB (p[-3], ptrq[1]);
	}
	return;
}
/*}}}*/
/*{{{  static void cifccsp_QueueQueue (Process *fptr, Process *bptr)*/
/*
 *	joins the given queue to the occam run-queue.
 *	this does not respect priority (all end up at the current priority level)
 */
static void cifccsp_QueueQueue (Process *fptr, Process *bptr)
{
	if (cifccsp_wptr[8] == (int)NotProcess_p) {
		/* run-queue empty, so just set */
		cifccsp_wptr[8] = (int)fptr;
	} else {
		/* run-queue not empty, add to bptr */
		((int *)(cifccsp_wptr[9]))[-2] = (int)fptr;
	}
	cifccsp_wptr[9] = (int)bptr;
	bptr[-2] = (int)NotProcess_p;

	return;
}
/*}}}*/


/*{{{  Process *cifccsp_ProcAlloc (void (*func)(void), int stacksize, int nparamwords, ...)*/
/*
 *	allocates a new process and initialises
 */
Process *cifccsp_ProcAlloc (void (*func)(void), int stacksize, int nparamwords, ...)
{
	va_list ap;
	char *c_stack;
	int *wsptr, i;

	wsptr = (int *)cifccsp_CHK_DMemAlloc (24 * sizeof (int));
	wsptr += PROCESS_OFFSET_ADJUST;		/* below Wptr */
	c_stack = (char *)cifccsp_CHK_DMemAlloc (stacksize - sizeof (int));

	wsptr[12] = nparamwords;	/* so ProcParam knows how many */
	wsptr[11] = 0;			/* where ENDP link gets stored (if relevant) */
	wsptr[10] = 0;			/* where the invoking process gets stored */
	wsptr[9] = 0;			/* where Bptr gets stored */
	wsptr[8] = 0;			/* where Fptr gets stored */
	wsptr[7] = (int)func;		/* entrypoint */
	wsptr[6] = 0;			/* where occam SP gets saved */
	wsptr[5] = (int)c_stack;	/* stack base */
	
	c_stack += (stacksize - ((nparamwords + 5) * sizeof(int)));

	/* stuff in the arguments */
	((int *)c_stack)[0] = (int)wsptr;		/* Process* argument */
	if (nparamwords > 0) {
		va_start (ap, nparamwords);
		for (i=0; i<nparamwords; i++) {
			int arg = va_arg (ap, int);

			((int *)c_stack)[i+1] = arg;
		}
		va_end (ap);
	}

	wsptr[4] = (int)c_stack;	/* stack pointer */
	wsptr[3] = 0xdeadbeef;		/* sanity check */
	wsptr[2] = 0;			/* used for PAR (savedpriority) */
	wsptr[1] = 0;			/* used for PAR (count) */
	wsptr[0] = 0;			/* Temp/used for PAR (successor IPtr) */
	wsptr[-1] = (int)occstub_entry_point;	/* Iptr */
	wsptr[-2] = (int)NULL;		/* Link */
	wsptr[-3] = (int)PPriority;	/* Priority */
	return (Process *)wsptr;
}
/*}}}*/
/*{{{  Process *cifccsp_ProcInit (void (*func)(void), int *stack, int stacksize, int nparamwords, ...)*/
/*
 *	allocates a new process.  Like ProcAlloc(), except that the stack
 *	is specified as a pointer.
 */
Process *cifccsp_ProcInit (void (*func)(void), int *stack, int stacksize, int nparamwords, ...)
{
	va_list ap;
	char *c_stack;
	int *wsptr, i;

	wsptr = (int *)cifccsp_CHK_DMemAlloc (24 * sizeof (int));
	wsptr += PROCESS_OFFSET_ADJUST;		/* below Wptr */
	/* use user-supplied stack */
	c_stack = (char *)stack;
	/* c_stack = (char *)cifccsp_CHK_DMemAlloc (stacksize - sizeof (int)); */

	wsptr[12] = nparamwords;	/* so ProcParam knows how many */
	wsptr[11] = 0;			/* where ENDP link gets stored (if relevant) */
	wsptr[10] = 0;			/* where the invoking process gets stored */
	wsptr[9] = 0;			/* where Bptr gets stored */
	wsptr[8] = 0;			/* where Fptr gets stored */
	wsptr[7] = (int)func;		/* entrypoint */
	wsptr[6] = 0;			/* where occam SP gets saved */
	wsptr[5] = 0;			/* stack base -- user supplied, don't free! */
	/* wsptr[5] = (int)c_stack; */	/* stack base */
	
	c_stack += (stacksize - ((nparamwords + 5) * sizeof(int)));

	/* stuff in the arguments */
	((int *)c_stack)[0] = (int)wsptr;		/* Process* argument */
	if (nparamwords > 0) {
		va_start (ap, nparamwords);
		for (i=0; i<nparamwords; i++) {
			int arg = va_arg (ap, int);

			((int *)c_stack)[i+1] = arg;
		}
		va_end (ap);
	}

	wsptr[4] = (int)c_stack;	/* stack pointer */
	wsptr[3] = 0xdeadbeef;		/* sanity check */
	wsptr[2] = 0;			/* used for PAR (savedpriority) */
	wsptr[1] = 0;			/* used for PAR (count) */
	wsptr[0] = 0;			/* Temp/used for PAR (successor IPtr) */
	wsptr[-1] = (int)occstub_entry_point;	/* Iptr */
	wsptr[-2] = (int)NULL;		/* Link */
	wsptr[-3] = (int)PPriority;	/* Priority */
	return (Process *)wsptr;
}
/*}}}*/
/*{{{  void cifccsp_ProcParam (Process *p, ...)*/
/*
 *	adjust the parameters of an initialised process
 */
void cifccsp_ProcParam (Process *p, ...)
{
	va_list ap;
	int *wsptr = (int *)p;
	int nparamwords = wsptr[12];		/* nparamwords for process */
	char *c_stack = (char *)(wsptr[4]);	/* stack pointer for process */
	int i;

	if (nparamwords > 0) {
		va_start (ap, p);
		for (i=0; i<nparamwords; i++) {
			int arg = va_arg (ap, int);

			((int *)c_stack)[i+1] = arg;
		}
		va_end (ap);
	}
	return;
}
/*}}}*/
/*{{{  void cifccsp_ProcAllocClean (Process *p)*/
/*
 *	releases resources held by a process, currently stack
 *	and the control-block
 */
void cifccsp_ProcAllocClean (Process *p)
{
	char *c_stack;
	int *wsptr = (int *)p;

	c_stack = (char *)(wsptr[5]);	/* stack base */
	if (c_stack) {
		cifccsp_CHK_DMemFree (c_stack);
	}
	wsptr -= PROCESS_OFFSET_ADJUST;
	cifccsp_CHK_DMemFree (wsptr);
	return;
}
/*}}}*/
/*{{{  void cifccsp_ProcPar (Process *first, ...)*/
/*
 *	runs the given processes in parallel.  List is terminated
 *	with a NULL
 */
void cifccsp_ProcPar (Process *first, ...)
{
	va_list ap;
	int *wsptr;
	int count;

	/* note: we are cifccsp_wptr */
	if (!first) {
		return;
	}
	count = 1;		/* us */
	((int *)cifccsp_wptr)[0] = (int)(NULL);		/* IptrSucc */
	va_start (ap, first);
	wsptr = (int *)first;
	while (wsptr) {
		count++;
		/* "start" this process */
		wsptr[11] = (int)cifccsp_wptr;		/* link to us */
		occstub_RunProcess (wsptr);
		wsptr = va_arg (ap, int*);
	}
	va_end (ap);
	count--;		/* us */
	((int *)cifccsp_wptr)[1] = count;
	((int *)cifccsp_wptr)[2] = PPriority;		/* current process priority */
	/* now we wait for them to finish */
	occstub_StopProcess ();
	return;
}
/*}}}*/
/*{{{  void cifccsp_ProcPriPar (Process *first, int priority, ...)*/
/*
 *	runs the processes given in parallel.  Pairs of process and
 *	priority are given, terminated with a NULL
 */
void cifccsp_ProcPriPar (Process *first, int priority, ...)
{
	va_list ap;
	int *wsptr;
	int count;

	/* note: we are cifccsp_wptr */
	if (!first) {
		return;
	}
	count = 1;		/* us */
	((int *)cifccsp_wptr)[0] = (int)(NULL);		/* IptrSucc */
	va_start (ap, priority);
	wsptr = (int *)first;
	while (wsptr) {
		count++;
		/* "start" this process */
		wsptr[11] = (int)cifccsp_wptr;		/* link to us */
		wsptr[-3] = priority;			/* set priority */
		occstub_RunProcess (wsptr);
		wsptr = va_arg (ap, int*);
		if (wsptr) {
			priority = va_arg (ap, int);
		}
	}
	va_end (ap);
	count--;		/* us */
	((int *)cifccsp_wptr)[1] = count;
	((int *)cifccsp_wptr)[2] = PPriority;		/* current process priority */
	/* now we wait for them to finish */
	occstub_StopProcess ();
	return;
}
/*}}}*/
/*{{{  void cifccsp_ProcParList (Process **list)*/
/*
 *	runs in parallel the NULL-terminated list of processes
 *	given by "list"
 */
void cifccsp_ProcParList (Process **list)
{
	int *wsptr;
	int count, i;

	/* note: we are cifccsp_wptr */
	if (!list) {
		return;
	}
	count = 1;		/* us */
	((int *)cifccsp_wptr)[0] = (int)(NULL);		/* IptrSucc */
	i = 0;
	while (list[i]) {
		wsptr = (int *)(list[i]);
		count++;
		/* "start" this process */
		wsptr[11] = (int)cifccsp_wptr;		/* link to us */
		occstub_RunProcess (wsptr);
		i++;
	}
	count--;		/* us */
	((int *)cifccsp_wptr)[1] = count;
	((int *)cifccsp_wptr)[2] = PPriority;		/* current process priority */
	/* now we wait for them to finish */
	occstub_StopProcess ();
	return;
}
/*}}}*/
/*{{{  void cifccsp_ProcPriParList (Process **list, int *plist)*/
/*
 *	runs a NULL-terminated list of processes at the
 *	given list of priorities respectively
 */
void cifccsp_ProcPriParList (Process **list, int *plist)
{
	int *wsptr;
	int count, i;
	int priority;

	/* note: we are cifccsp_wptr */
	if (!list) {
		return;
	}
	count = 1;		/* us */
	((int *)cifccsp_wptr)[0] = (int)(NULL);		/* IptrSucc */
	i = 0;
	while (list[i]) {
		wsptr = (int *)(list[i]);
		priority = plist[i];
		count++;
		/* "start" this process */
		wsptr[11] = (int)cifccsp_wptr;		/* link to us */
		wsptr[-3] = priority;			/* set priority */
		occstub_RunProcess (wsptr);
		i++;
	}
	count--;		/* us */
	((int *)cifccsp_wptr)[1] = count;
	((int *)cifccsp_wptr)[2] = PPriority;		/* current process priority */
	/* now we wait for them to finish */
	occstub_StopProcess ();
	return;
}
/*}}}*/
/*{{{  Channel *cifccsp_ChanAlloc (void)*/
/*
 *	allocates a new channel
 */
Channel *cifccsp_ChanAlloc (void)
{
	void *p;
	
	occstub_DMemMalloc (sizeof (Channel), &p);

	return (Channel *)p;
}
/*}}}*/
/*{{{  void cifccsp_ChanAllocClean (Channel *c)*/
/*
 *	releases the channel (frees it)
 */
void cifccsp_ChanAllocClean (Channel *c)
{
	occstub_DMemRelease (c);
	return;
}
/*}}}*/
/*{{{  int cifccsp_ProcAlt (Channel *first, ...)*/
/*
 *	does an ALT over the channels given, list is
 *	terminated with a NULL
 */
int cifccsp_ProcAlt (Channel *first, ...)
{
	va_list ap;
	Channel *c = first;
	int index = -1;
	int i;

	if (!c) {
		SetErr ();
	}

	/*{{{  ALT pre-enabling */
	va_start (ap, first);
	index = 0;
	do {
		if (*(int *)c) {
			/* something here! */
			break;	/* do/while() */
		}
		c = va_arg (ap, Channel*);
		index++;
	} while (c);
	va_end (ap);
	if (c && (index >= 0)) {
		return index;		/* something was ready */
	}
	/*}}}*/
	/*{{{  ALT start */
	((int *)cifccsp_wptr)[-4] = (int)Enabling_p;
	/*}}}*/
	/*{{{  ALT enable */
	c = first;
	va_start (ap, first);
	do {
		if (*(int *)c == (int)NotProcess_p) {
			*(int *)c = (int)cifccsp_wptr;
		} else {
			/* really ought not to happen..! */
			((int *)cifccsp_wptr)[-4] = (int)Ready_p;
		}
		c = va_arg (ap, Channel*);
	} while (c);
	va_end (ap);
	/*}}}*/
	/*{{{  ALT wait */
	if (((int *)cifccsp_wptr)[-4] != (int)Ready_p) {
		occstub_AltWait ();
	}
	/*}}}*/
	/*{{{  ALT disable */
	index = -1;
	i = 0;
	c = first;
	va_start (ap, first);
	do {
		if (*(int *)c == (int)cifccsp_wptr) {
			*(int *)c = (int)NotProcess_p;
		} else {
			index = i;
		}
		c = va_arg (ap, Channel*);
		i++;
	} while (c);
	va_end (ap);
	/*}}}*/

	/* should do nicely.. */

	if (index < 0) {
		SetErr ();
	}
	return index;
}
/*}}}*/
/*{{{  int cifccsp_ProcAltList (Channel **ca)*/
/*
 *	does an alternative over the list of channels given,
 *	terminated with a NULL
 */
int cifccsp_ProcAltList (Channel **ca)
{
	int i, index;

	if (!ca || !*ca) {
		SetErr ();
	}
	/*{{{  ALT pre-enabling */
	index = -1;
	for (i=0; ca[i]; i++) {
		if (*(int *)(ca[i])) {
			index = i;
			break;		/* for() */
		}
	}
	if (index >= 0) {
		return index;		/* something was ready */
	}
	/*}}}*/
	/*{{{  ALT start */
	((int *)cifccsp_wptr)[-4] = (int)Enabling_p;
	/*}}}*/
	/*{{{  ALT enable */
	for (i=0; ca[i]; i++) {
		if (*(int *)(ca[i]) == (int)NotProcess_p) {
			*(int *)(ca[i]) = (int)cifccsp_wptr;
		} else {
			/* really ought not to happen..! */
			((int *)cifccsp_wptr)[-4] = (int)Ready_p;
		}
	}
	/*}}}*/
	/*{{{  ALT wait */
	if (((int *)cifccsp_wptr)[-4] != (int)Ready_p) {
		occstub_AltWait ();
	}
	/*}}}*/
	/*{{{  ALT disable */
	index = -1;
	for (i=0; ca[i]; i++) {
		if (*(int *)(ca[i]) == (int)cifccsp_wptr) {
			*(int *)(ca[i]) = (int)NotProcess_p;
		} else {
			index = i;
		}
	}
	/*}}}*/

	if (index < 0) {
		SetErr ();
	}
	return index;
}
/*}}}*/
/*{{{  int cifccsp_GetPri (void)*/
/*
 *	gets the current process priority
 */
int cifccsp_GetPri (void)
{
	return PPriority;
}
/*}}}*/
/*{{{  int cifccsp_ProcProcPriAlt (Channel *first, ...)*/
/*
 *	does an ALT over the channels given, list is
 *	terminated with a NULL.  The highest priority process is selected first.
 */
int cifccsp_ProcProcPriAlt (Channel *first, ...)
{
	va_list ap;
	Channel *c = first;
	int index = -1;
	int i, idxpri;

	if (!c) {
		SetErr ();
	}

	/*{{{  ALT pre-enabling */
	va_start (ap, first);
	i = 0;
	index = -1;
	idxpri = 32;
	do {
		if (*(int *)c && ((index < 0) || (((int *)c)[-3] < idxpri))) {
			/* something ready! */
			index = i;
			idxpri = ((int *)c)[-3];
			break;	/* do/while() */
		}
		c = va_arg (ap, Channel*);
		i++;
	} while (c);
	va_end (ap);
	if (c && (index >= 0)) {
		return index;		/* something was ready */
	}
	/*}}}*/
	/*{{{  ALT start */
	((int *)cifccsp_wptr)[-4] = (int)Enabling_p;
	/*}}}*/
	/*{{{  ALT enable */
	c = first;
	va_start (ap, first);
	do {
		if (*(int *)c == (int)NotProcess_p) {
			*(int *)c = (int)cifccsp_wptr;
		} else {
			/* really ought not to happen..! */
			((int *)cifccsp_wptr)[-4] = (int)Ready_p;
		}
		c = va_arg (ap, Channel*);
	} while (c);
	va_end (ap);
	/*}}}*/
	/*{{{  ALT wait */
	if (((int *)cifccsp_wptr)[-4] != (int)Ready_p) {
		occstub_AltWait ();
	}
	/*}}}*/
	/*{{{  ALT disable */
	index = -1;
	i = 0;
	idxpri = 32;
	c = first;
	va_start (ap, first);
	do {
		if (*(int *)c == (int)cifccsp_wptr) {
			*(int *)c = (int)NotProcess_p;
		} else if ((index < 0) || (((int *)c)[-3] < idxpri)){
			index = i;
			idxpri = ((int *)c)[-3];
		}
		c = va_arg (ap, Channel*);
		i++;
	} while (c);
	va_end (ap);
	/*}}}*/

	/* should do nicely.. */

	if (index < 0) {
		SetErr ();
	}
	return index;
}
/*}}}*/
/*{{{  int cifccsp_ProcProcPriAltList (Channel **ca)*/
/*
 *	does an alternative over the list of channels given,
 *	terminated with a NULL.  The highest priority process is selected first.
 */
int cifccsp_ProcProcPriAltList (Channel **ca)
{
	int i, index;

	if (!ca || !*ca) {
		SetErr ();
	}
	/*{{{  ALT pre-enabling */
	index = -1;
	for (i=0; ca[i]; i++) {
		if (*(int *)(ca[i]) && ((index < 0) ||
					((int *)(ca[i])[-3] < (int *)(ca[index])[-3]))) {		/* at lower priority value ? (higher level) */
			index = i;
		}
	}
	if (index >= 0) {
		return index;		/* something was ready */
	}
	/*}}}*/
	/*{{{  ALT start */
	((int *)cifccsp_wptr)[-4] = (int)Enabling_p;
	/*}}}*/
	/*{{{  ALT enable */
	for (i=0; ca[i]; i++) {
		if (*(int *)(ca[i]) == (int)NotProcess_p) {
			*(int *)(ca[i]) = (int)cifccsp_wptr;
		} else {
			/* really ought not to happen..! */
			((int *)cifccsp_wptr)[-4] = (int)Ready_p;
		}
	}
	/*}}}*/
	/*{{{  ALT wait */
	if (((int *)cifccsp_wptr)[-4] != (int)Ready_p) {
		occstub_AltWait ();
	}
	/*}}}*/
	/*{{{  ALT disable */
	index = -1;
	for (i=0; ca[i]; i++) {
		if (*(int *)(ca[i]) == (int)cifccsp_wptr) {
			*(int *)(ca[i]) = (int)NotProcess_p;
		} else if ((index < 0) || ((int *)(ca[i])[-3] < (int *)(ca[index])[-3])) {
			index = i;
		}
	}
	/*}}}*/

	if (index < 0) {
		SetErr ();
	}
	return index;
}
/*}}}*/
/*{{{  void *cifccsp_DMemAlloc (int bytes)*/
/*
 *	allocates a block of memory from the occam dynamic heap
 */
void *cifccsp_DMemAlloc (int bytes)
{
	void *ptr;

#ifdef KROC_USES_PTHREADS
	/* need thread context */
	occstub_DMemMalloc (bytes, &ptr);
#else
	ptr = (void *)dmem_alloc (bytes);
#endif

	return ptr;
}
/*}}}*/
/*{{{  void cifccsp_DMemFree (void *ptr)*/
/*
 *	frees a block of memory allocated from the occam dynamic heap
 */
void cifccsp_DMemFree (void *ptr)
{
#ifdef KROC_USES_PTHREADS
	/* need thread context */
	occstub_DMemRelease (ptr);
#else
	dmem_release (ptr);
#endif

	return;
}
/*}}}*/
/*{{{  void *cifccsp_CHK_DMemAlloc (int bytes)*/
/*
 *	allocates a block of memory from the occam dynamic heap
 *	this version checks to see whether a thread context is in use
 *	and calls dmem_alloc() appropriately
 */
void *cifccsp_CHK_DMemAlloc (int bytes)
{
	void *ptr;

#ifdef KROC_USES_PTHREADS
	if (cifccsp_wptr == (Process *)0) {
		ptr = (void *)dmem_alloc (bytes);
	} else {
		occstub_DMemMalloc (bytes, &ptr);
	}
#else
	ptr = (void *)dmem_alloc (bytes);
#endif

	return ptr;
}
/*}}}*/
/*{{{  void cifccsp_CHK_DMemFree (void *ptr)*/
/*
 *	frees a block of memory allocated from the occam dynamic heap
 *	this version checks to see whether a thread context is in use
 *	and calls dmem_release() appropriately
 */
void cifccsp_CHK_DMemFree (void *ptr)
{
#ifdef KROC_USES_PTHREADS
	if (cifccsp_wptr == (Process *)0) {
		dmem_release (ptr);
	} else {
		occstub_DMemRelease (ptr);
	}
#else
	dmem_release (ptr);
#endif

	return;
}
/*}}}*/
/*{{{  void cifccsp_CTSemInit (CTSem *sem)*/
/*
 *	initialises a channel-type semaphore
 */
void cifccsp_CTSemInit (CTSem *sem)
{
	sem->fptr = (void *)1;		/* free */
	sem->bptr = NotProcess_p;
	return;
}
/*}}}*/
/*{{{  void cifccsp_CTSemClaim (CTSem *sem)*/
/*
 *	claims a channel-type semaphore
 */
void cifccsp_CTSemClaim (CTSem *sem)
{
	if (sem->fptr == (void *)1) {
		sem->fptr = NotProcess_p;
	} else {
		/* semaphore already claimed by another process, queue and deschedule */
		if (sem->fptr) {
			((void **)sem->bptr)[-2] = (void *)cifccsp_wptr;
		} else {
			sem->fptr = (void *)cifccsp_wptr;
		}
		((void **)cifccsp_wptr)[-2] = (void *)NotProcess_p;
		sem->bptr = (void *)cifccsp_wptr;

		/* deschedule */
		occstub_StopP ();
	}
	return;
}
/*}}}*/
/*{{{  void cifccsp_CTSemRelease (CTSem *sem)*/
/*
 *	releases a channel-type semaphore
 */
void cifccsp_CTSemRelease (CTSem *sem)
{
	if (sem->fptr == NotProcess_p) {
		sem->fptr = (void *)1;
	} else {
		/* schedule the next process off the semaphore */
		Process *p = (Process *)(sem->fptr);

		sem->fptr = (void *)(p[-2]);
		/* occstub_RunProcess (p); */
		cifccsp_QueueProcess (p);
	}
	return;
}
/*}}}*/
/*{{{  void cifccsp_SaveL (Process **pptr)*/
/*
 *	stores the current Fptr/Bptr in the array given
 */
void cifccsp_SaveL (Process **pptr)
{
	pptr[0] = (Process *)(cifccsp_wptr[8]);
	pptr[1] = (Process *)(cifccsp_wptr[9]);
	return;
}
/*}}}*/
/*{{{  void cifccsp_StLF (Process *fptr)*/
/*
 *	sets the current priority-level Fptr
 */
void cifccsp_StLF (Process *fptr)
{
	cifccsp_wptr[8] = (int)fptr;
	return;
}
/*}}}*/
/*{{{  void cifccsp_StLB (Process *bptr)*/
/*
 *	sets the current priority-level Fptr
 */
void cifccsp_StLB (Process *bptr)
{
	cifccsp_wptr[9] = (int)bptr;
	return;
}
/*}}}*/
/*{{{  MBarrier *cifccsp_MBarrierAlloc (void)*/
/*
 *	allocates a new mobile barrier
 */
MBarrier *cifccsp_MBarrierAlloc (void)
{
	MBarrier *b = (MBarrier *)DMemAlloc (sizeof (MBarrier));

	b->ecount = 1;
	b->scount = 1;
	b->fptr = NotProcess_p;
	b->bptr = NotProcess_p;
	b->refcount = 1;

	return b;
}
/*}}}*/
/*{{{  void cifccsp_MBarrierAllocClean (MBarrier *b)*/
/*
 *	frees a mobile barrier
 */
void cifccsp_MBarrierAllocClean (MBarrier *b)
{
	DMemFree ((void *)b);

	return;
}
/*}}}*/
/*{{{  void cifccsp_MBarrierInit (MBarrier *b)*/
/*
 *	initialises a mobile barrier (not expected to be used much)
 */
void cifccsp_MBarrierInit (MBarrier *b)
{
	b->ecount = 1;
	b->scount = 1;
	b->fptr = NotProcess_p;
	b->bptr = NotProcess_p;
	b->refcount = 1;

	return;
}
/*}}}*/
/*{{{  void cifccsp_MBarrierEnroll (MBarrier *b, int count)*/
/*
 *	enrolls "count" processes on the mobile barrier "b"
 */
void cifccsp_MBarrierEnroll (MBarrier *b, int count)
{
	b->ecount += count;
	b->scount += count;
	return;
}
/*}}}*/
/*{{{  void cifccsp_MBarrierResign (MBarrier *b, int count)*/
/*
 *	resigns "count" processes from the mobile barrier "b"
 */
void cifccsp_MBarrierResign (MBarrier *b, int count)
{
	b->ecount -= count;
	b->scount -= count;
	if (!b->scount) {
		/* completed the barrier, reschedule other processes */
		b->scount = b->ecount;

		if (b->fptr) {
			cifccsp_QueueQueue ((Process *)b->fptr, (Process *)b->bptr);
			b->fptr = NotProcess_p;
		}
	}
	return;
}
/*}}}*/
/*{{{  void cifccsp_MBarrierSync (MBarrier *b)*/
/*
 *	synchronises on the mobile barrier "b"
 */
void cifccsp_MBarrierSync (MBarrier *b)
{
	b->scount--;
	if (!b->scount) {
		/* completed the barrier, reschedule other processes */
		b->scount = b->ecount;

		if (b->fptr) {
			cifccsp_QueueQueue ((Process *)b->fptr, (Process *)b->bptr);
			b->fptr = NotProcess_p;
		}
	} else {
		/* put ourselves on the barrier queue and deschedule */
		if (b->fptr == NotProcess_p) {
			/* queue empty, set */
			b->fptr = (void *)cifccsp_wptr;
		} else {
			/* queue not empty */
			((void **)(b->bptr))[-2] = (void *)cifccsp_wptr;
		}
		((void **)cifccsp_wptr)[-2] = (void *)NotProcess_p;
		b->bptr = (void *)cifccsp_wptr;

		/* deschedule */
		occstub_StopP ();
	}
	return;
}
/*}}}*/
/*{{{  void cifccsp_blocking_killcall (Channel *c, int *result)*/
/*
 *	used to terminate an in-progress blocking sys-call
 */
void cifccsp_blocking_killcall (Channel *c, int *result)
{
	int args[2];

	args[0] = (int)c;
	args[1] = (int)result;

	_killcall ((int *)args);

	return;
}
/*}}}*/

/*{{{  void cifccsp_MProcSerialise (MProcess *p, char **ap, int *al)*/
/*
 *	serialises a mobile process into the given array (allocated)
 */
void cifccsp_MProcSerialise (MProcess *p, char **ap, int *al)
{
	if (!mpcb_mpp_serialise ((mp_ctrlblk **)&p, NULL, (int *)ap, al)) {
		*ap = NULL;
		*al = 0;
	}
	return;
}
/*}}}*/
/*{{{  void cifccsp_MProcDeserialise (char *a, int l, MProcess **pp)*/
/*
 *	deserlialises a mobile process (leaves the array intact)
 */
void cifccsp_MProcDeserialise (char *a, int l, MProcess **pp)
{
	if (!mpcb_mpp_deserialise ((int)a, l, (mp_ctrlblk **)pp, NULL)) {
		/* hrm, failed -- will have barged */
		*pp = NULL;
	}
	return;
}
/*}}}*/
/*{{{  int cifccsp_MProcCheckRoutine (char *name)*/
/*
 *	checks whether the given routine is available (e.g. "m.integrate")
 *	returns 0 on failure, non-zero on success
 */
int cifccsp_MProcCheckRoutine (char *name)
{
	if (!name) {
		return 0;
	}
	return mpp_checkroutine (name);
}
/*}}}*/
/*{{{  int cifccsp_MProcLoadLibrary (char *lname)*/
/*
 *	loads a library into the run-time system
 *	returns 0 on failure, non-zero on success
 */
int cifccsp_MProcLoadLibrary (char *lname)
{
	if (!lname) {
		return 0;
	}
	return mpp_loadlibrary (lname);
}
/*}}}*/
/*{{{  int cifccsp_MProcUnloadLibrary (char *lname)*/
/*
 *	unloads a library from the run-time system
 *	returns 0 on failure, non-zero on success
 */
int cifccsp_MProcUnloadLibrary (char *lname)
{
	if (!lname) {
		return 0;
	}
	return mpp_unloadlibrary (lname);
}
/*}}}*/


#if 0
extern void cifccsp_main (Process *);

/*{{{  static void real_cifccsp_init (int *rptr, int stacksize)*/
/*
 *	sets up the "top-level" C function, called cifccsp_main
 */
static void real_cifccsp_init (int *rptr, int stacksize)
{
	Process *p = ProcAlloc (cifccsp_main, stacksize, 1, NULL, NULL);

	*rptr = (int)p;
	return;
}
/*}}}*/
/*{{{  void _cifccsp_init (int *wsptr) */
void _cifccsp_init (int *wsptr)
{
	real_cifccsp_init ((int *)(wsptr[0]), (int)(wsptr[1]));
}
/*}}}*/

#endif

