home *** CD-ROM | disk | FTP | other *** search
- /* C.Coroutines - coroutine handling in C.
- *
- * Based on an article by David McQuillan in Archive, Vol 4 No 6.
- * The following notice is from the original article.
- *
- * No responsibility accepted if you come a cropper using the code.
- * In particular, I have not tried stack extension and interrupts with it.
- *
- * (c) put in Public Domain by David McQuillan, Jan 1991.
- *
- */
-
- #include <setjmp.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "kernel.h"
- #include "utils.h"
-
- /* Kernel stuff */
-
- #define STACK_DISP 0x230
- #define JMP_FP 6
- #define JMP_SP 7
- #define JMP_SL 8
- #define JMP_LR 9
-
- /* The environment of a coroutine */
- #define Env(co) (*((jmp_buf *)((co)->env)))
-
- /* Current coroutine */
-
- static coroutine_t *co_current = NULL;
- static void *co_parameter = NULL;
-
- void *co_resume (coroutine_t *coroutine, void *parameter)
- {
- if (setjmp(Env(co_current)) == 0)
- {
- co_current = coroutine;
- co_parameter = parameter;
- longjmp(Env(coroutine), 1);
- }
-
- return co_parameter;
- }
-
- void co_initialise (coroutine_t *coroutine)
- {
- if ((coroutine->env = malloc(sizeof(jmp_buf))) == NULL)
- {
- fprintf(stderr, "Internal error: Out of memory in co_initialise\n");
- exit(1);
- }
-
- setjmp(Env(coroutine));
- coroutine->stack = (struct stack_chunk *) (Env(coroutine)[JMP_SL] - STACK_DISP);
- co_current = coroutine;
- }
-
- static coroutine_t *co_starter;
- static co_procedure_t *co_start_proc;
-
- static void co_start (void)
- {
- co_procedure_t *proc = co_start_proc;
-
- (*proc)(co_resume(co_starter, NULL));
- fprintf(stderr, "Internal error: Coroutine returned in co_start\n");
- exit(1);
- }
-
- void co_create (coroutine_t *coroutine, size_t stack_size, co_procedure_t *proc)
- {
- struct stack_chunk *stack;
-
- /* Put STACK_DISP space at the beginning of the stack.
- * Do some trial-and-error initialisation.
- */
-
- stack_size += STACK_DISP;
-
- if ((coroutine->env = malloc(sizeof(jmp_buf))) == NULL)
- {
- fprintf(stderr, "Internal error: Out of memory in co_create\n");
- exit(1);
- }
-
- if ((stack = malloc(stack_size)) == NULL)
- {
- fprintf(stderr, "Internal error: Out of memory in co_create\n");
- exit(1);
- }
-
- memcpy(stack, co_current->stack, STACK_DISP);
-
- stack->sc_next = NULL;
- stack->sc_prev = NULL;
- stack->sc_size = stack_size;
-
- setjmp(Env(coroutine));
- Env(coroutine)[JMP_SL] = (int)stack + STACK_DISP;
- Env(coroutine)[JMP_SP] = (int)stack + stack_size;
- Env(coroutine)[JMP_LR] = (int)co_start;
- coroutine->stack = stack;
-
- co_start_proc = proc;
- co_starter = co_current;
-
- co_resume(coroutine, NULL);
- }
-
- void co_delete (coroutine_t *coroutine)
- {
- if (coroutine->stack != NULL)
- free(coroutine->stack);
-
- if (coroutine->env != NULL)
- free(coroutine->env);
-
- coroutine->stack = NULL;
- coroutine->env = NULL;
- }
-
- #ifdef TEST
-
- static coroutine_t main_coroutine;
- static coroutine_t input_coroutine;
- static coroutine_t output_coroutine;
-
- static co_procedure_t input;
- static co_procedure_t output;
-
- int main (void)
- {
- printf("Main...\n");
-
- co_initialise(&main_coroutine);
- co_create(&input_coroutine, 2000, &input);
- co_create(&output_coroutine, 2000, &output);
-
- co_resume(&output_coroutine, NULL);
- co_delete(&input_coroutine);
- co_delete(&output_coroutine);
- printf("... end main\n");
- }
-
- static void input (void *parameter)
- {
- int i,j,k;
- USE(parameter);
-
- printf("Input> Generates fib < 100\n");
-
- j = 0;
- printf("Input> Initial: %d\n",j);
- co_resume (&output_coroutine, &j);
- for (k = 1; k < 100; i = j, j = k, k = i+j)
- {
- printf("Input> %d\n", k);
- co_resume (&output_coroutine, &k);
- }
-
- co_resume(&output_coroutine, NULL);
- }
-
- static void output (void *parameter)
- {
- int *value;
- USE(parameter);
-
- printf("Output> Generates difference from last\n");
-
- if ((value = co_resume(&input_coroutine, NULL)) != NULL)
- {
- int last = *value;
- int this;
-
- printf("Output> Initial: %d\n", last);
-
- while ((value = co_resume(&input_coroutine, NULL)) != NULL)
- {
- this = *value;
- printf("Output> %d, %d\n", this, this-last);
- last = this;
- }
- }
-
- co_resume(&main_coroutine, NULL);
- }
-
- #endif
-