]> git.donarmstrong.com Git - lilypond.git/blobdiff - guile18/qt/stp.c
New upstream version 2.19.65
[lilypond.git] / guile18 / qt / stp.c
diff --git a/guile18/qt/stp.c b/guile18/qt/stp.c
new file mode 100644 (file)
index 0000000..bfacc89
--- /dev/null
@@ -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;
+
+
+\f/* 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);
+}
+
+\f/* 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;
+}
+
+
+\f/* 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); */
+}