From Modula to Oberon

Peter da Silva peter at sugar.UUCP
Fri Mar 25 23:06:36 AEST 1988


In article <1139 at PT.CS.CMU.EDU>, edw at IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>>
>>  The debate about CLU iterators misses an important point: CLU iterators are
>>coroutines, which C does not have.

Coroutines in 'C' are easy to implement, though. Why, this whole O/S we're
reading news on (UNIX) is written as a set of coroutines in 'C'. (yes, it's
a simplification... but not much of one).

I'd like to see the following functions become standard in 'C':

COROUTINE -- Build a jmp_buf for a coroutine.

int coroutine(jump, entry, stack, stacksize);
struct jmp_buf *jump;
void (*entry)();
char *stack;
int stacksize;

This sets up the stack and jmp_buf so that a call to "longjmp(jmp_buf)"
will appear to be a call to entry(). It will return an error only if the
stack isn't large enough for a small routine that does nothing but call
the following function:

int switch(from, to, status)
struct jmp_buf *from, *to;
int status;
{
	int code;

	if(!(code=setjmp(from)))
		longjmp(to, status);

	return code;
}

Voila! Co-routines! Lightweight processes (best if you have the Berkeley
signal handler, I guess, so you could run it off alarms...):

struct proc {
	struct proc *next;
	struct proc *prev;
	char *stack;
	struct jmp_buf context;
};

struct proc *runq;	/* doubly linked circular queue */

sleep()
{
	struct proc *self;
	/* do nothing if no procs or I'm alone */
	if(!runq)
		return;
	if(runq->next == runq)
		return;
	self = runq;
	runq = runq->next;
	switch(&self->context, &runq->context, 1);
}

int spawn(entry, stacksize)
void (*entry)();
int stacksize;
{
	struct proc *p;

	if(!(p = malloc(sizeof *p)))
		return 0;
	if(!(p->stack = malloc(stacksize))) {
		free(p);
		return 0;
	}
	if(!coroutine(p, entry, p->stack, stacksize)) {
		free(p->stack);
		free(p);
		return 0;
	}
	p->stacksize = p;
	p->next = runq->next;
	p->prev = runq;
	runq->next->prev = p;
	runq->next = p;
	return p;
}

int delete(p) /* note, this version doesn't allow a process to delete itself! */
struct process *p;
{
	if(p==runq)
		return 0;

	p->next->prev = p->prev;
	p->prev->next = p->next;
	free(p->stack);
	free(p);
}
-- 
-- Peter da Silva  `-_-'  ...!hoptoad!academ!uhnix1!sugar!peter
-- Disclaimer: These U aren't mere opinions... these are *values*.



More information about the Comp.unix.wizards mailing list