home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / a043_1 / C / Coroutines < prev    next >
Encoding:
Text File  |  1991-05-26  |  3.9 KB  |  193 lines

  1. /* C.Coroutines - coroutine handling in C.
  2.  *
  3.  * Based on an article by David McQuillan in Archive, Vol 4 No 6.
  4.  * The following notice is from the original article.
  5.  *
  6.  * No responsibility accepted if you come a cropper using the code.
  7.  * In particular, I have not tried stack extension and interrupts with it.
  8.  *
  9.  * (c) put in Public Domain by David McQuillan, Jan 1991.
  10.  *
  11.  */
  12.  
  13. #include <setjmp.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "kernel.h"
  18. #include "utils.h"
  19.  
  20. /* Kernel stuff */
  21.  
  22. #define STACK_DISP    0x230
  23. #define JMP_FP        6
  24. #define JMP_SP        7
  25. #define JMP_SL        8
  26. #define JMP_LR        9
  27.  
  28. /* The environment of a coroutine */
  29. #define Env(co) (*((jmp_buf *)((co)->env)))
  30.  
  31. /* Current coroutine */
  32.  
  33. static coroutine_t *co_current = NULL;
  34. static void *co_parameter = NULL;
  35.  
  36. void *co_resume (coroutine_t *coroutine, void *parameter)
  37. {
  38.     if (setjmp(Env(co_current)) == 0)
  39.     {
  40.         co_current = coroutine;
  41.         co_parameter = parameter;
  42.         longjmp(Env(coroutine), 1);
  43.     }
  44.  
  45.     return co_parameter;
  46. }
  47.  
  48. void co_initialise (coroutine_t *coroutine)
  49. {
  50.     if ((coroutine->env = malloc(sizeof(jmp_buf))) == NULL)
  51.     {
  52.         fprintf(stderr, "Internal error: Out of memory in co_initialise\n");
  53.         exit(1);
  54.     }
  55.  
  56.     setjmp(Env(coroutine));
  57.     coroutine->stack = (struct stack_chunk *) (Env(coroutine)[JMP_SL] - STACK_DISP);
  58.     co_current = coroutine;
  59. }
  60.  
  61. static coroutine_t *co_starter;
  62. static co_procedure_t *co_start_proc;
  63.  
  64. static void co_start (void)
  65. {
  66.     co_procedure_t *proc = co_start_proc;
  67.  
  68.     (*proc)(co_resume(co_starter, NULL));
  69.     fprintf(stderr, "Internal error: Coroutine returned in co_start\n");
  70.     exit(1);
  71. }
  72.  
  73. void co_create (coroutine_t *coroutine, size_t stack_size, co_procedure_t *proc)
  74. {
  75.     struct stack_chunk *stack;
  76.  
  77.     /* Put STACK_DISP space at the beginning of the stack.
  78.      * Do some trial-and-error initialisation.
  79.      */
  80.  
  81.     stack_size += STACK_DISP;
  82.  
  83.     if ((coroutine->env = malloc(sizeof(jmp_buf))) == NULL)
  84.     {
  85.         fprintf(stderr, "Internal error: Out of memory in co_create\n");
  86.         exit(1);
  87.     }
  88.  
  89.     if ((stack = malloc(stack_size)) == NULL)
  90.     {
  91.         fprintf(stderr, "Internal error: Out of memory in co_create\n");
  92.         exit(1);
  93.     }
  94.  
  95.     memcpy(stack, co_current->stack, STACK_DISP);
  96.  
  97.     stack->sc_next = NULL;
  98.     stack->sc_prev = NULL;
  99.     stack->sc_size = stack_size;
  100.  
  101.     setjmp(Env(coroutine));
  102.     Env(coroutine)[JMP_SL] = (int)stack + STACK_DISP;
  103.     Env(coroutine)[JMP_SP] = (int)stack + stack_size;
  104.     Env(coroutine)[JMP_LR] = (int)co_start;
  105.     coroutine->stack = stack;
  106.  
  107.     co_start_proc = proc;
  108.     co_starter = co_current;
  109.  
  110.     co_resume(coroutine, NULL);
  111. }
  112.  
  113. void co_delete (coroutine_t *coroutine)
  114. {
  115.     if (coroutine->stack != NULL)
  116.         free(coroutine->stack);
  117.  
  118.     if (coroutine->env != NULL)
  119.         free(coroutine->env);
  120.  
  121.     coroutine->stack = NULL;
  122.     coroutine->env = NULL;
  123. }
  124.  
  125. #ifdef TEST
  126.  
  127. static coroutine_t main_coroutine;
  128. static coroutine_t input_coroutine;
  129. static coroutine_t output_coroutine;
  130.  
  131. static co_procedure_t input;
  132. static co_procedure_t output;
  133.  
  134. int main (void)
  135. {
  136.     printf("Main...\n");
  137.  
  138.     co_initialise(&main_coroutine);
  139.     co_create(&input_coroutine, 2000, &input);
  140.     co_create(&output_coroutine, 2000, &output);
  141.  
  142.     co_resume(&output_coroutine, NULL);
  143.     co_delete(&input_coroutine);
  144.     co_delete(&output_coroutine);
  145.     printf("... end main\n");
  146. }
  147.  
  148. static void input (void *parameter)
  149. {
  150.     int i,j,k;
  151.     USE(parameter);
  152.  
  153.     printf("Input> Generates fib < 100\n");
  154.  
  155.     j = 0;
  156.     printf("Input> Initial: %d\n",j);
  157.     co_resume (&output_coroutine, &j);
  158.     for (k = 1; k < 100; i = j, j = k, k = i+j)
  159.     {
  160.         printf("Input> %d\n", k);
  161.         co_resume (&output_coroutine, &k);
  162.     }
  163.  
  164.     co_resume(&output_coroutine, NULL);
  165. }
  166.  
  167. static void output (void *parameter)
  168. {
  169.     int *value;
  170.     USE(parameter);
  171.  
  172.     printf("Output> Generates difference from last\n");
  173.  
  174.     if ((value = co_resume(&input_coroutine, NULL)) != NULL)
  175.     {
  176.         int last = *value;
  177.         int this;
  178.  
  179.         printf("Output> Initial: %d\n", last);
  180.  
  181.         while ((value = co_resume(&input_coroutine, NULL)) != NULL)
  182.         {
  183.             this = *value;
  184.             printf("Output> %d, %d\n", this, this-last);
  185.             last = this;
  186.         }
  187.     }
  188.  
  189.     co_resume(&main_coroutine, NULL);
  190. }
  191.  
  192. #endif
  193.