stp.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include "copyright.h"
  2. #include "qt.h"
  3. #include "stp.h"
  4. #ifndef NULL
  5. #define NULL 0
  6. #endif
  7. #define STP_STKSIZE (0x1000)
  8. /* `alignment' must be a power of 2. */
  9. #define STP_STKALIGN(sp, alignment) \
  10. ((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
  11. /* The notion of a thread is merged with the notion of a queue.
  12. Thread stuff: thread status (sp) and stuff to use during
  13. (re)initialization. Queue stuff: next thread in the queue
  14. (next). */
  15. struct stp_t {
  16. qt_t *sp; /* QuickThreads handle. */
  17. void *sto; /* `malloc'-allocated stack. */
  18. struct stp_t *next; /* Next thread in the queue. */
  19. };
  20. /* A queue is a circular list of threads. The queue head is a
  21. designated list element. If this is a uniprocessor-only
  22. implementation we can store the `main' thread in this, but in a
  23. multiprocessor there are several `heavy' threads but only one run
  24. queue. A fancier implementation might have private run queues,
  25. which would lead to a simpler (trivial) implementation */
  26. typedef struct stp_q_t {
  27. stp_t t;
  28. stp_t *tail;
  29. } stp_q_t;
  30. /* Helper functions. */
  31. extern void *malloc (unsigned size);
  32. extern void perror (char const *msg);
  33. extern void free (void *sto);
  34. void *
  35. xmalloc (unsigned size)
  36. {
  37. void *sto;
  38. sto = malloc (size);
  39. if (!sto) {
  40. perror ("malloc");
  41. exit (1);
  42. }
  43. return (sto);
  44. }
  45. /* Queue access functions. */
  46. static void
  47. stp_qinit (stp_q_t *q)
  48. {
  49. q->t.next = q->tail = &q->t;
  50. }
  51. static stp_t *
  52. stp_qget (stp_q_t *q)
  53. {
  54. stp_t *t;
  55. t = q->t.next;
  56. q->t.next = t->next;
  57. if (t->next == &q->t) {
  58. if (t == &q->t) { /* If it was already empty .. */
  59. return (NULL); /* .. say so. */
  60. }
  61. q->tail = &q->t; /* Else now it is empty. */
  62. }
  63. return (t);
  64. }
  65. static void
  66. stp_qput (stp_q_t *q, stp_t *t)
  67. {
  68. q->tail->next = t;
  69. t->next = &q->t;
  70. q->tail = t;
  71. }
  72. /* Thread routines. */
  73. static stp_q_t stp_global_runq; /* A queue of runable threads. */
  74. static stp_t stp_global_main; /* Thread for the process. */
  75. static stp_t *stp_global_curr; /* Currently-executing thread. */
  76. static void *stp_starthelp (qt_t *old, void *ignore0, void *ignore1);
  77. static void stp_only (void *pu, void *pt, qt_userf_t *f);
  78. static void *stp_aborthelp (qt_t *sp, void *old, void *null);
  79. static void *stp_yieldhelp (qt_t *sp, void *old, void *blockq);
  80. void
  81. stp_init()
  82. {
  83. stp_qinit (&stp_global_runq);
  84. }
  85. void
  86. stp_start()
  87. {
  88. stp_t *next;
  89. while ((next = stp_qget (&stp_global_runq)) != NULL) {
  90. stp_global_curr = next;
  91. QT_BLOCK (stp_starthelp, 0, 0, next->sp);
  92. }
  93. }
  94. static void *
  95. stp_starthelp (qt_t *old, void *ignore0, void *ignore1)
  96. {
  97. stp_global_main.sp = old;
  98. stp_qput (&stp_global_runq, &stp_global_main);
  99. /* return (garbage); */
  100. }
  101. void
  102. stp_create (stp_userf_t *f, void *pu)
  103. {
  104. stp_t *t;
  105. void *sto;
  106. t = xmalloc (sizeof(stp_t));
  107. t->sto = xmalloc (STP_STKSIZE);
  108. sto = STP_STKALIGN (t->sto, QT_STKALIGN);
  109. t->sp = QT_SP (sto, STP_STKSIZE - QT_STKALIGN);
  110. t->sp = QT_ARGS (t->sp, pu, t, (qt_userf_t *)f, stp_only);
  111. stp_qput (&stp_global_runq, t);
  112. }
  113. static void
  114. stp_only (void *pu, void *pt, qt_userf_t *f)
  115. {
  116. stp_global_curr = (stp_t *)pt;
  117. (*(stp_userf_t *)f)(pu);
  118. stp_abort();
  119. /* NOTREACHED */
  120. }
  121. void
  122. stp_abort (void)
  123. {
  124. stp_t *old, *newthread;
  125. newthread = stp_qget (&stp_global_runq);
  126. old = stp_global_curr;
  127. stp_global_curr = newthread;
  128. QT_ABORT (stp_aborthelp, old, (void *)NULL, newthread->sp);
  129. }
  130. static void *
  131. stp_aborthelp (qt_t *sp, void *old, void *null)
  132. {
  133. free (((stp_t *)old)->sto);
  134. free (old);
  135. /* return (garbage); */
  136. }
  137. void
  138. stp_yield()
  139. {
  140. stp_t *old, *newthread;
  141. newthread = stp_qget (&stp_global_runq);
  142. old = stp_global_curr;
  143. stp_global_curr = newthread;
  144. QT_BLOCK (stp_yieldhelp, old, &stp_global_runq, newthread->sp);
  145. }
  146. static void *
  147. stp_yieldhelp (qt_t *sp, void *old, void *blockq)
  148. {
  149. ((stp_t *)old)->sp = sp;
  150. stp_qput ((stp_q_t *)blockq, (stp_t *)old);
  151. /* return (garbage); */
  152. }