123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- #include "copyright.h"
- #include "qt.h"
- #include "stp.h"
- #ifndef NULL
- #define NULL 0
- #endif
- #define STP_STKSIZE (0x1000)
- /* `alignment' must be a power of 2. */
- #define STP_STKALIGN(sp, alignment) \
- ((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
- /* The notion of a thread is merged with the notion of a queue.
- Thread stuff: thread status (sp) and stuff to use during
- (re)initialization. Queue stuff: next thread in the queue
- (next). */
- struct stp_t {
- qt_t *sp; /* QuickThreads handle. */
- void *sto; /* `malloc'-allocated stack. */
- struct stp_t *next; /* Next thread in the queue. */
- };
- /* A queue is a circular list of threads. The queue head is a
- designated list element. If this is a uniprocessor-only
- implementation we can store the `main' thread in this, but in a
- multiprocessor there are several `heavy' threads but only one run
- queue. A fancier implementation might have private run queues,
- which would lead to a simpler (trivial) implementation */
- typedef struct stp_q_t {
- stp_t t;
- stp_t *tail;
- } stp_q_t;
- /* Helper functions. */
- extern void *malloc (unsigned size);
- extern void perror (char const *msg);
- extern void free (void *sto);
- void *
- xmalloc (unsigned size)
- {
- void *sto;
- sto = malloc (size);
- if (!sto) {
- perror ("malloc");
- exit (1);
- }
- return (sto);
- }
- /* Queue access functions. */
- static void
- stp_qinit (stp_q_t *q)
- {
- q->t.next = q->tail = &q->t;
- }
- static stp_t *
- stp_qget (stp_q_t *q)
- {
- stp_t *t;
- t = q->t.next;
- q->t.next = t->next;
- if (t->next == &q->t) {
- if (t == &q->t) { /* If it was already empty .. */
- return (NULL); /* .. say so. */
- }
- q->tail = &q->t; /* Else now it is empty. */
- }
- return (t);
- }
- static void
- stp_qput (stp_q_t *q, stp_t *t)
- {
- q->tail->next = t;
- t->next = &q->t;
- q->tail = t;
- }
- /* Thread routines. */
- static stp_q_t stp_global_runq; /* A queue of runable threads. */
- static stp_t stp_global_main; /* Thread for the process. */
- static stp_t *stp_global_curr; /* Currently-executing thread. */
- static void *stp_starthelp (qt_t *old, void *ignore0, void *ignore1);
- static void stp_only (void *pu, void *pt, qt_userf_t *f);
- static void *stp_aborthelp (qt_t *sp, void *old, void *null);
- static void *stp_yieldhelp (qt_t *sp, void *old, void *blockq);
- void
- stp_init()
- {
- stp_qinit (&stp_global_runq);
- }
- void
- stp_start()
- {
- stp_t *next;
- while ((next = stp_qget (&stp_global_runq)) != NULL) {
- stp_global_curr = next;
- QT_BLOCK (stp_starthelp, 0, 0, next->sp);
- }
- }
- static void *
- stp_starthelp (qt_t *old, void *ignore0, void *ignore1)
- {
- stp_global_main.sp = old;
- stp_qput (&stp_global_runq, &stp_global_main);
- /* return (garbage); */
- }
- void
- stp_create (stp_userf_t *f, void *pu)
- {
- stp_t *t;
- void *sto;
- t = xmalloc (sizeof(stp_t));
- t->sto = xmalloc (STP_STKSIZE);
- sto = STP_STKALIGN (t->sto, QT_STKALIGN);
- t->sp = QT_SP (sto, STP_STKSIZE - QT_STKALIGN);
- t->sp = QT_ARGS (t->sp, pu, t, (qt_userf_t *)f, stp_only);
- stp_qput (&stp_global_runq, t);
- }
- static void
- stp_only (void *pu, void *pt, qt_userf_t *f)
- {
- stp_global_curr = (stp_t *)pt;
- (*(stp_userf_t *)f)(pu);
- stp_abort();
- /* NOTREACHED */
- }
- void
- stp_abort (void)
- {
- stp_t *old, *newthread;
- newthread = stp_qget (&stp_global_runq);
- old = stp_global_curr;
- stp_global_curr = newthread;
- QT_ABORT (stp_aborthelp, old, (void *)NULL, newthread->sp);
- }
- static void *
- stp_aborthelp (qt_t *sp, void *old, void *null)
- {
- free (((stp_t *)old)->sto);
- free (old);
- /* return (garbage); */
- }
- void
- stp_yield()
- {
- stp_t *old, *newthread;
- newthread = stp_qget (&stp_global_runq);
- old = stp_global_curr;
- stp_global_curr = newthread;
- QT_BLOCK (stp_yieldhelp, old, &stp_global_runq, newthread->sp);
- }
- static void *
- stp_yieldhelp (qt_t *sp, void *old, void *blockq)
- {
- ((stp_t *)old)->sp = sp;
- stp_qput ((stp_q_t *)blockq, (stp_t *)old);
- /* return (garbage); */
- }
|