home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / config / unix / pthreads.c < prev    next >
C/C++ Source or Header  |  2002-01-30  |  4KB  |  111 lines

  1. /*
  2.  * pthreads.c -- Icon context switch code using POSIX threads and semaphores
  3.  *
  4.  * This code implements co-expression context switching on any system that
  5.  * provides POSIX threads and semaphores.  It requires Icon 9.4.1 built
  6.  * with "#define CoClean" in order to free threads and semaphores when
  7.  * co-expressions are collected.  It is typically much slower than
  8.  * platform-specific custom code, but of course it is much more portable.
  9.  */
  10.  
  11. #include <pthread.h>
  12. #include <semaphore.h>
  13. #include <stdio.h>
  14.  
  15. extern void new_context(int, void *);
  16. extern void syserr(char *msg);
  17. extern void *alloc(unsigned int n);
  18. static void *nctramp(void *arg);
  19.  
  20. static int inited = 0;        /* has first-time initialization been done? */
  21.  
  22. /*
  23.  * Define a "context" struct to hold the thread information we need.
  24.  */
  25. typedef struct {
  26.    pthread_t thread;    /* thread ID (thread handle) */
  27.    sem_t sema;        /* synchronization semaphore */
  28.    int alive;        /* set zero when thread is to die */
  29.    } context;
  30.  
  31. /*
  32.  * Treat an Icon "cstate" array as an array of context pointers.
  33.  * cstate[0] is used by Icon code that thinks it's setting a stack pointer.
  34.  * We use cstate[1] to point to the actual context struct.
  35.  * (Both of these are initialized to NULL by Icon 9.4.1.)
  36.  */
  37. typedef context **cstate;
  38.  
  39. /*
  40.  * coswitch(old, new, first) -- switch contexts.
  41.  */
  42. int coswitch(void *o, void *n, int first) {
  43.  
  44.    cstate ocs = o;            /* old cstate pointer */
  45.    cstate ncs = n;            /* new cstate pointer */
  46.    context *old, *new;            /* old and new context pointers */
  47.  
  48.    if (inited)                /* if not first call */
  49.       old = ocs[1];            /* load current context pointer */
  50.    else {
  51.       /*
  52.        * This is the first coswitch() call.
  53.        * Allocate and initialize the context struct for &main.
  54.        */
  55.       old = ocs[1] = alloc(sizeof(context));
  56.       if (sem_init(&old->sema, 0, 0) == -1)
  57.          syserr("cannot init semaphore");
  58.       old->thread = pthread_self();
  59.       old->alive = 1;
  60.       inited = 1;
  61.       }
  62.  
  63.    if (first != 0)            /* if not first call for this cstate */
  64.       new = ncs[1];            /* load new context pointer */
  65.    else {
  66.       /*
  67.        * This is a newly allocated cstate array.
  68.        * Allocate and initialize a context struct.
  69.        */
  70.       new = ncs[1] = alloc(sizeof(context));
  71.       if (sem_init(&new->sema, 0, 0) == -1)
  72.          syserr("cannot init semaphore");
  73.       if (pthread_create(&new->thread, NULL, nctramp, new) != 0) 
  74.          syserr("cannot create thread");
  75.       new->alive = 1;
  76.       }
  77.  
  78.    sem_post(&new->sema);        /* unblock the new thread */
  79.    sem_wait(&old->sema);        /* block this thread */
  80.  
  81.    if (!old->alive)        
  82.       pthread_exit(NULL);        /* if unblocked because unwanted */
  83.    return 0;                /* else return to continue running */
  84.    }
  85.  
  86. /*
  87.  * coclean(old) -- clean up co-expression state before freeing.
  88.  */
  89. void coclean(void *o) {
  90.    cstate ocs = o;            /* old cstate pointer */
  91.    context *old = ocs[1];        /* old context pointer */
  92.    if (old == NULL)            /* if never initialized, do nothing */
  93.       return;
  94.    old->alive = 0;            /* signal thread to exit */
  95.    sem_post(&old->sema);        /* unblock it */
  96.    pthread_join(old->thread, NULL);    /* wait for thread to exit */
  97.    sem_destroy(&old->sema);        /* destroy associated semaphore */
  98.    free(old);                /* free context block */
  99.    }
  100.  
  101. /*
  102.  * nctramp() -- trampoline for calling new_context(0,0).
  103.  */
  104. static void *nctramp(void *arg) {
  105.    context *new = arg;            /* new context pointer */
  106.    sem_wait(&new->sema);        /* wait for signal */
  107.    new_context(0, 0);            /* call new_context; will not return */
  108.    syserr("new_context returned to nctramp");
  109.    return NULL;
  110.    }
  111.