home *** CD-ROM | disk | FTP | other *** search
- /* CoRoutine.c - High level routines for coroutines package
- *
- * 01-10-90 AA Started
- *
- */
-
- #include "tracker.h"
-
- #include "CoRtn.h"
- #include <stdlib.h>
- #include <signal.h>
-
- #define FALSE 0
- #define TRUE (!FALSE)
-
- context *__launch_co(coproc p, context *from, void *handle);
- context *__switch_co(context *to, context *from);
- void __kill_co(context *co);
-
- static coroutine *costack = NULL; /* List of all coroutines */
- static context mainprog; /* Save slot for main program */
- static coroutine *currentco = MAIN_CO;
-
- /* Malloc and free routines exported to assembler */
-
- void *comalloc(size_t size)
- { return malloc(size);
- }
-
- void cofree(void *m)
- { free(m);
- }
-
- static context *getslot(coroutine *co)
- { if (co == MAIN_CO)
- return &mainprog;
-
- return &co->ctx;
- }
-
- static coroutine *unhitch(coroutine *stack, coroutine *onetokill)
- { if (!stack)
- return NULL;
-
- if (stack == onetokill)
- { coroutine *next = stack->next;
- cofree(onetokill);
- return next;
- }
-
- stack->next = unhitch(stack->next, onetokill);
- return stack;
- }
-
- coroutine *create_co(coproc p, void *handle)
- { coroutine *new;
-
- if (new = comalloc(sizeof(coroutine)), !new)
- return NULL;
-
- new->comain = p;
- new->handle = handle;
- new->active = 0;
-
- new->next = costack;
- costack = new;
-
- return new;
- }
-
- int delete_co(coroutine *co)
- { if (co == currentco || co == MAIN_CO)
- return FALSE;
-
- if (co->active)
- __kill_co(getslot(co));
-
- costack = unhitch(costack, co);
- return TRUE;
- }
-
- int monitor_co(coroutine *co)
- { if (co == MAIN_CO)
- return 1;
- else
- return co->active;
- }
-
- int start_co(coroutine *co)
- { if (co == currentco || co == MAIN_CO)
- return FALSE;
-
- if (co->active)
- __kill_co(getslot(co));
-
- co->active = 0;
- return goto_co(co);
- }
-
- int goto_co(coroutine *co)
- { context *old, *new;
- coroutine *oldcurrent;
- int stillgoing;
-
- if (co == currentco)
- return FALSE;
-
- old = getslot(currentco);
- new = getslot(co);
-
- oldcurrent = currentco;
- currentco = co;
-
- if (monitor_co(co))
- stillgoing = (int) __switch_co(new, old);
- else
- stillgoing = (int) __launch_co(co->comain, old,
- co == MAIN_CO ? NULL : co->handle);
-
- currentco = oldcurrent;
-
- if (stillgoing == -1)
- return FALSE;
-
- if (co != MAIN_CO)
- co->active = !!stillgoing;
-
- return TRUE;
- }
-