summaryrefslogtreecommitdiff
path: root/ext/systemc/src/sysc/qt/stp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/systemc/src/sysc/qt/stp.c')
-rw-r--r--ext/systemc/src/sysc/qt/stp.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/ext/systemc/src/sysc/qt/stp.c b/ext/systemc/src/sysc/qt/stp.c
new file mode 100644
index 000000000..bfacc893b
--- /dev/null
+++ b/ext/systemc/src/sysc/qt/stp.c
@@ -0,0 +1,199 @@
+#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); */
+}