stp.c

Go to the documentation of this file.
00001 #include "copyright.h"
00002 #include "qt.h"
00003 #include "stp.h"
00004 
00005 #ifndef NULL
00006 #define NULL    0
00007 #endif
00008 
00009 #define STP_STKSIZE (0x1000)
00010 
00011 /* `alignment' must be a power of 2. */
00012 #define STP_STKALIGN(sp, alignment) \
00013   ((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
00014 
00015 
00016 /* The notion of a thread is merged with the notion of a queue.
00017    Thread stuff: thread status (sp) and stuff to use during
00018    (re)initialization.  Queue stuff: next thread in the queue
00019    (next). */
00020 
00021 struct stp_t {
00022   qt_t *sp;              /* QuickThreads handle. */
00023   void *sto;             /* `malloc'-allocated stack. */
00024   struct stp_t *next;    /* Next thread in the queue. */
00025 };
00026 
00027 
00028 /* A queue is a circular list of threads.  The queue head is a
00029    designated list element.  If this is a uniprocessor-only
00030    implementation we can store the `main' thread in this, but in a
00031    multiprocessor there are several `heavy' threads but only one run
00032    queue.  A fancier implementation might have private run queues,
00033    which would lead to a simpler (trivial) implementation */
00034 
00035 typedef struct stp_q_t {
00036   stp_t t;
00037   stp_t *tail;
00038 } stp_q_t;
00039 
00040 
00041 /* Helper functions. */
00042 
00043 extern void *malloc (unsigned size);
00044 extern void perror (char const *msg);
00045 extern void free (void *sto);
00046 
00047   void *
00048 xmalloc (unsigned size)
00049 {
00050   void *sto;
00051 
00052   sto = malloc (size);
00053   if (!sto) {
00054     perror ("malloc");
00055     exit (1);
00056   }
00057   return (sto);
00058 }
00059 
00060 /* Queue access functions. */
00061 
00062   static void
00063 stp_qinit (stp_q_t *q)
00064 {
00065   q->t.next = q->tail = &q->t;
00066 }
00067 
00068 
00069   static stp_t *
00070 stp_qget (stp_q_t *q)
00071 {
00072   stp_t *t;
00073 
00074   t = q->t.next;
00075   q->t.next = t->next;
00076   if (t->next == &q->t) {
00077     if (t == &q->t) {       /* If it was already empty .. */
00078       return (NULL);        /* .. say so. */
00079     }
00080     q->tail = &q->t;        /* Else now it is empty. */
00081   }
00082   return (t);
00083 }
00084 
00085 
00086   static void
00087 stp_qput (stp_q_t *q, stp_t *t)
00088 {
00089   q->tail->next = t;
00090   t->next = &q->t;
00091   q->tail = t;
00092 }
00093 
00094 
00095 /* Thread routines. */
00096 
00097 static stp_q_t stp_global_runq; /* A queue of runable threads. */
00098 static stp_t stp_global_main;   /* Thread for the process. */
00099 static stp_t *stp_global_curr;  /* Currently-executing thread. */
00100 
00101 static void *stp_starthelp (qt_t *old, void *ignore0, void *ignore1);
00102 static void stp_only (void *pu, void *pt, qt_userf_t *f);
00103 static void *stp_aborthelp (qt_t *sp, void *old, void *null);
00104 static void *stp_yieldhelp (qt_t *sp, void *old, void *blockq);
00105 
00106 
00107   void
00108 stp_init()
00109 {
00110   stp_qinit (&stp_global_runq);
00111 }
00112 
00113 
00114   void
00115 stp_start()
00116 {
00117   stp_t *next;
00118 
00119   while ((next = stp_qget (&stp_global_runq)) != NULL) {
00120     stp_global_curr = next;
00121     QT_BLOCK (stp_starthelp, 0, 0, next->sp);
00122   }
00123 }
00124 
00125 
00126   static void *
00127 stp_starthelp (qt_t *old, void *ignore0, void *ignore1)
00128 {
00129   stp_global_main.sp = old;
00130   stp_qput (&stp_global_runq, &stp_global_main);
00131   /* return (garbage); */
00132 }
00133 
00134 
00135   void
00136 stp_create (stp_userf_t *f, void *pu)
00137 {
00138   stp_t *t;
00139   void *sto;
00140 
00141   t = xmalloc (sizeof(stp_t));
00142   t->sto = xmalloc (STP_STKSIZE);
00143   sto = STP_STKALIGN (t->sto, QT_STKALIGN);
00144   t->sp = QT_SP (sto, STP_STKSIZE - QT_STKALIGN);
00145   t->sp = QT_ARGS (t->sp, pu, t, (qt_userf_t *)f, stp_only);
00146   stp_qput (&stp_global_runq, t);
00147 }
00148 
00149 
00150   static void
00151 stp_only (void *pu, void *pt, qt_userf_t *f)
00152 {
00153   stp_global_curr = (stp_t *)pt;
00154   (*(stp_userf_t *)f)(pu);
00155   stp_abort();
00156   /* NOTREACHED */
00157 }
00158 
00159 
00160   void
00161 stp_abort (void)
00162 {
00163   stp_t *old, *newthread;
00164 
00165   newthread = stp_qget (&stp_global_runq);
00166   old = stp_global_curr;
00167   stp_global_curr = newthread;
00168   QT_ABORT (stp_aborthelp, old, (void *)NULL, newthread->sp);
00169 }
00170 
00171 
00172   static void *
00173 stp_aborthelp (qt_t *sp, void *old, void *null)
00174 {
00175   free (((stp_t *)old)->sto);
00176   free (old);
00177   /* return (garbage); */
00178 }
00179 
00180 
00181   void
00182 stp_yield()
00183 {
00184   stp_t *old, *newthread;
00185 
00186   newthread = stp_qget (&stp_global_runq);
00187   old = stp_global_curr;
00188   stp_global_curr = newthread;
00189   QT_BLOCK (stp_yieldhelp, old, &stp_global_runq, newthread->sp);
00190 }
00191 
00192 
00193   static void *
00194 stp_yieldhelp (qt_t *sp, void *old, void *blockq)
00195 {
00196   ((stp_t *)old)->sp = sp;
00197   stp_qput ((stp_q_t *)blockq, (stp_t *)old);
00198   /* return (garbage); */
00199 }

Generated on Wed Jan 21 15:32:10 2009 for SystemC by  doxygen 1.5.5