Xref: utzoo comp.lang.misc:1328 comp.unix.wizards:7368 comp.lang.c:8547 Path: utzoo!mnetor!uunet!nuchat!sugar!peter From: peter@sugar.UUCP (Peter da Silva) Newsgroups: comp.lang.misc,comp.unix.wizards,comp.lang.c Subject: Re: From Modula to Oberon Message-ID: <1758@sugar.UUCP> Date: 25 Mar 88 13:06:36 GMT References: <2827@enea.se><1557@pasteur.Berkeley.Edu><3764@bloom-beacon.MIT.EDU><1139@PT.CS.CMU.EDU> Organization: Sugar Land UNIX - Houston, TX Lines: 100 Summary: C almost supports coroutines. Her's what it needs. In article <1139@PT.CS.CMU.EDU>, edw@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*.