home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / os / kludge03.tz / kludge03 / mk74 / user / threads / cthreads.c < prev    next >
C/C++ Source or Header  |  1991-08-29  |  10KB  |  443 lines

  1. /* 
  2.  * Mach Operating System
  3.  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
  4.  * All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify and distribute this software and its
  7.  * documentation is hereby granted, provided that both the copyright
  8.  * notice and this permission notice appear in all copies of the
  9.  * software, derivative works or modified versions, and any portions
  10.  * thereof, and that both notices appear in supporting documentation.
  11.  * 
  12.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15.  * 
  16.  * Carnegie Mellon requests users of this software to return to
  17.  * 
  18.  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  19.  *  School of Computer Science
  20.  *  Carnegie Mellon University
  21.  *  Pittsburgh PA 15213-3890
  22.  * 
  23.  * any improvements or extensions that they make and grant Carnegie Mellon
  24.  * the rights to redistribute these changes.
  25.  */
  26. /*
  27.  * HISTORY
  28.  * $Log:    cthreads.c,v $
  29.  * Revision 2.10  91/08/28  11:19:26  jsb
  30.  *     Fixed mig_init initialization in cthread_fork_child.
  31.  *     [91/08/23            rpd]
  32.  * 
  33.  * Revision 2.9  91/07/31  18:34:23  dbg
  34.  *     Fix bad self-pointer reference.
  35.  * 
  36.  *     Don't declare _setjmp and _longjmp; they are included by
  37.  *     cthreads.h.
  38.  *     [91/07/30  17:33:50  dbg]
  39.  * 
  40.  * Revision 2.8  91/05/14  17:56:31  mrt
  41.  *     Correcting copyright
  42.  * 
  43.  * Revision 2.7  91/02/14  14:19:47  mrt
  44.  *     Added new Mach copyright
  45.  *     [91/02/13  12:41:07  mrt]
  46.  * 
  47.  * Revision 2.6  90/11/05  14:37:03  rpd
  48.  *     Added cthread_fork_{prepare,parent,child}.
  49.  *     [90/11/02            rwd]
  50.  * 
  51.  *     Add spin_lock_t.
  52.  *     [90/10/31            rwd]
  53.  * 
  54.  * Revision 2.5  90/08/07  14:30:58  rpd
  55.  *     Removed RCS keyword nonsense.
  56.  * 
  57.  * Revision 2.4  90/06/02  15:13:49  rpd
  58.  *     Converted to new IPC.
  59.  *     [90/03/20  20:56:44  rpd]
  60.  * 
  61.  * Revision 2.3  90/01/19  14:37:12  rwd
  62.  *     Make cthread_init return pointer to new stack.
  63.  *     [89/12/18  19:17:45  rwd]
  64.  * 
  65.  * Revision 2.2  89/12/08  19:53:37  rwd
  66.  *     Change cproc and cthread counters to globals with better names.
  67.  *     [89/11/02            rwd]
  68.  * 
  69.  * Revision 2.1  89/08/03  17:09:34  rwd
  70.  * Created.
  71.  * 
  72.  *
  73.  * 31-Dec-87  Eric Cooper (ecc) at Carnegie Mellon University
  74.  *    Changed cthread_exit() logic for the case of the main thread,
  75.  *    to fix thread and stack memory leak found by Camelot group.
  76.  *
  77.  * 21-Aug-87  Eric Cooper (ecc) at Carnegie Mellon University
  78.  *    Added consistency check in beginning of cthread_body().
  79.  *
  80.  * 11-Aug-87  Eric Cooper (ecc) at Carnegie Mellon University
  81.  *    Removed cthread_port() and cthread_set_port().
  82.  *    Removed port deallocation from cthread_free().
  83.  *    Minor changes to cthread_body(), cthread_exit(), and cthread_done().
  84.  *
  85.  * 10-Aug-87  Eric Cooper (ecc) at Carnegie Mellon University
  86.  *    Changed call to mig_init() in cthread_init() to pass 1 as argument.
  87.  *
  88.  * 31-Jul-87  Eric Cooper (ecc) at Carnegie Mellon University
  89.  *    Added call to mig_init() from cthread_init().
  90.  */
  91. /*
  92.  *     File:    cthreads.c
  93.  *    Author:    Eric Cooper, Carnegie Mellon University
  94.  *    Date:    July, 1987
  95.  *
  96.  *     Implementation of fork, join, exit, etc.
  97.  */
  98.  
  99. #include <cthreads.h>
  100. #include "cthread_internals.h"
  101.  
  102. /*
  103.  * C Threads imports:
  104.  */
  105. extern void cproc_create();
  106. extern vm_offset_t cproc_init();
  107. extern void mig_init();
  108.  
  109. /*
  110.  * Mach imports:
  111.  */
  112.  
  113. /*
  114.  * C library imports:
  115.  */
  116.  
  117. /*
  118.  * Thread status bits.
  119.  */
  120. #define    T_MAIN        0x1
  121. #define    T_RETURNED    0x2
  122. #define    T_DETACHED    0x4
  123.  
  124. #ifdef    DEBUG
  125. int cthread_debug = FALSE;
  126. #endif    DEBUG
  127.  
  128. private struct cthread_queue cthreads = QUEUE_INITIALIZER;
  129. private struct mutex cthread_lock = MUTEX_INITIALIZER;
  130. private struct condition cthread_needed = CONDITION_INITIALIZER;
  131. private struct condition cthread_idle = CONDITION_INITIALIZER;
  132. int cthread_cprocs = 0;
  133. int cthread_cthreads = 0;
  134. int cthread_max_cprocs = 0;
  135.  
  136. private cthread_t free_cthreads = NO_CTHREAD;        /* free list */
  137. private spin_lock_t free_lock = SPIN_LOCK_INITIALIZER;    /* unlocked */
  138.  
  139. private struct cthread initial_cthread = { 0 };
  140.  
  141. private cthread_t
  142. cthread_alloc(func, arg)
  143.     cthread_fn_t func;
  144.     any_t arg;
  145. {
  146.     register cthread_t t = NO_CTHREAD;
  147.  
  148.     if (free_cthreads != NO_CTHREAD) {
  149.         /*
  150.          * Don't try for the lock unless
  151.          * the list is likely to be nonempty.
  152.          * We can't be sure, though, until we lock it.
  153.          */
  154.         spin_lock(&free_lock);
  155.         t = free_cthreads;
  156.         if (t != NO_CTHREAD)
  157.             free_cthreads = t->next;
  158.         spin_unlock(&free_lock);
  159.     }
  160.     if (t == NO_CTHREAD) {
  161.         /*
  162.          * The free list was empty.
  163.          * We may have only found this out after
  164.          * locking it, which is why this isn't an
  165.          * "else" branch of the previous statement.
  166.          */
  167.         t = (cthread_t) malloc(sizeof(struct cthread));
  168.     }
  169.     *t = initial_cthread;
  170.     t->func = func;
  171.     t->arg = arg;
  172.     return t;
  173. }
  174.  
  175. private void
  176. cthread_free(t)
  177.     register cthread_t t;
  178. {
  179.     spin_lock(&free_lock);
  180.     t->next = free_cthreads;
  181.     free_cthreads = t;
  182.     spin_unlock(&free_lock);
  183. }
  184.  
  185. int
  186. cthread_init()
  187. {
  188.     static int cthreads_started = FALSE;
  189.     register cproc_t p;
  190.     register cthread_t t;
  191.     vm_offset_t stack;
  192.  
  193.     if (cthreads_started)
  194.         return 0;
  195.     stack = cproc_init();
  196.     cthread_cprocs = 1;
  197.     t = cthread_alloc((cthread_fn_t) 0, (any_t) 0);
  198.     cthread_cthreads = 1;
  199.     t->state |= T_MAIN;
  200.     cthread_set_name(t, "main");
  201.  
  202.     /* cproc_self() doesn't work yet, because
  203.        we haven't yet switched to the new stack. */
  204.  
  205.     p = *(cproc_t *)&ur_cthread_ptr(stack);
  206.     p->incarnation = t;
  207.     mig_init(p);        /* enable multi-threaded mig interfaces */
  208.  
  209.     cthreads_started = TRUE;
  210.     return stack;
  211. }
  212.  
  213. /*
  214.  * Used for automatic initialization by crt0.
  215.  * Cast needed since too many C compilers choke on the type void (*)().
  216.  */
  217. int (*_cthread_init_routine)() = (int (*)()) cthread_init;
  218.  
  219. /*
  220.  * Procedure invoked at the base of each cthread.
  221.  */
  222. void
  223. cthread_body(self)
  224.     cproc_t self;
  225. {
  226.     register cthread_t t;
  227.  
  228.     ASSERT(cproc_self() == self);
  229.     TRACE(printf("[idle] cthread_body(%x)\n", self));
  230.     mutex_lock(&cthread_lock);
  231.     for (;;) {
  232.         /*
  233.          * Dequeue a thread invocation request.
  234.          */
  235.         cthread_queue_deq(&cthreads, cthread_t, t);
  236.         if (t != NO_CTHREAD) {
  237.             /*
  238.              * We have a thread to execute.
  239.              */
  240.             mutex_unlock(&cthread_lock);
  241.             cthread_assoc(self, t);        /* assume thread's identity */
  242.             if (_setjmp(t->catch) == 0) {    /* catch for cthread_exit() */
  243.                 /*
  244.                  * Execute the fork request.
  245.                  */
  246.                 t->result = (*(t->func))(t->arg);
  247.             }
  248.             /*
  249.              * Return result from thread.
  250.              */
  251.             TRACE(printf("[%s] done()\n", cthread_name(t)));
  252.             mutex_lock(&t->lock);
  253.             if (t->state & T_DETACHED) {
  254.                 mutex_unlock(&t->lock);
  255.                 cthread_free(t);
  256.             } else {
  257.                 t->state |= T_RETURNED;
  258.                 mutex_unlock(&t->lock);
  259.                 condition_signal(&t->done);
  260.             }
  261.             cthread_assoc(self, NO_CTHREAD);
  262.             mutex_lock(&cthread_lock);
  263.             cthread_cthreads -= 1;
  264.         } else {
  265.             /*
  266.              * Queue is empty.
  267.              * Signal that we're idle in case the main thread
  268.              * is waiting to exit, then wait for reincarnation.
  269.              */
  270.             condition_signal(&cthread_idle);
  271.             condition_wait(&cthread_needed, &cthread_lock);
  272.         }
  273.     }
  274. }
  275.  
  276. cthread_t
  277. cthread_fork(func, arg)
  278.     cthread_fn_t func;
  279.     any_t arg;
  280. {
  281.     register cthread_t t;
  282.  
  283.     TRACE(printf("[%s] fork()\n", cthread_name(cthread_self())));
  284.     mutex_lock(&cthread_lock);
  285.     t = cthread_alloc(func, arg);
  286.     cthread_queue_enq(&cthreads, t);
  287.     if (++cthread_cthreads > cthread_cprocs && (cthread_max_cprocs == 0 || cthread_cprocs < cthread_max_cprocs)) {
  288.         cthread_cprocs += 1;
  289.         cproc_create();
  290.     }
  291.     mutex_unlock(&cthread_lock);
  292.     condition_signal(&cthread_needed);
  293.     return t;
  294. }
  295.  
  296. void
  297. cthread_detach(t)
  298.     cthread_t t;
  299. {
  300.     TRACE(printf("[%s] detach(%s)\n", cthread_name(cthread_self()), cthread_name(t)));
  301.     mutex_lock(&t->lock);
  302.     if (t->state & T_RETURNED) {
  303.         mutex_unlock(&t->lock);
  304.         cthread_free(t);
  305.     } else {
  306.         t->state |= T_DETACHED;
  307.         mutex_unlock(&t->lock);
  308.     }
  309. }
  310.  
  311. any_t
  312. cthread_join(t)
  313.     cthread_t t;
  314. {
  315.     any_t result;
  316.  
  317.     TRACE(printf("[%s] join(%s)\n", cthread_name(cthread_self()), cthread_name(t)));
  318.     mutex_lock(&t->lock);
  319.     ASSERT(! (t->state & T_DETACHED));
  320.     while (! (t->state & T_RETURNED))
  321.         condition_wait(&t->done, &t->lock);
  322.     result = t->result;
  323.     mutex_unlock(&t->lock);
  324.     cthread_free(t);
  325.     return result;
  326. }
  327.  
  328. void
  329. cthread_exit(result)
  330.     any_t result;
  331. {
  332.     register cthread_t t = cthread_self();
  333.  
  334.     TRACE(printf("[%s] exit()\n", cthread_name(t)));
  335.     t->result = result;
  336.     if (t->state & T_MAIN) {
  337.         mutex_lock(&cthread_lock);
  338.         while (cthread_cthreads > 1)
  339.             condition_wait(&cthread_idle, &cthread_lock);
  340.         mutex_unlock(&cthread_lock);
  341.         exit((int) result);
  342.     } else {
  343.         _longjmp(t->catch, TRUE);
  344.     }
  345. }
  346.  
  347. /*
  348.  * Used for automatic finalization by crt0.  Cast needed since too many C
  349.  * compilers choke on the type void (*)().
  350.  */
  351. int (*_cthread_exit_routine)() = (int (*)()) cthread_exit;
  352.  
  353. void
  354. cthread_set_name(t, name)
  355.     cthread_t t;
  356.     char *name;
  357. {
  358.     t->name = name;
  359. }
  360.  
  361. char *
  362. cthread_name(t)
  363.     cthread_t t;
  364. {
  365.     return (t == NO_CTHREAD
  366.         ? "idle"
  367.         : (t->name == 0 ? "?" : t->name));
  368. }
  369.  
  370. int
  371. cthread_limit()
  372. {
  373.     return cthread_max_cprocs;
  374. }
  375.  
  376. void
  377. cthread_set_limit(n)
  378.     int n;
  379. {
  380.     cthread_max_cprocs = n;
  381. }
  382.  
  383. int
  384. cthread_count()
  385. {
  386.     return cthread_cthreads;
  387. }
  388.  
  389. cthread_fork_prepare()
  390. {
  391.     spin_lock(&free_lock);
  392.     mutex_lock(&cthread_lock);
  393.     malloc_fork_prepare();
  394.     cproc_fork_prepare();
  395. }
  396.  
  397. cthread_fork_parent()
  398. {
  399.     cproc_fork_parent();
  400.     malloc_fork_parent();
  401.     mutex_unlock(&cthread_lock);
  402.     spin_unlock(&free_lock);
  403. }
  404.  
  405. cthread_fork_child()
  406. {
  407.     cthread_t t;
  408.     cproc_t p;
  409.  
  410.     cproc_fork_child();
  411.     malloc_fork_child();
  412.     mutex_unlock(&cthread_lock);
  413.     spin_unlock(&free_lock);
  414.     condition_init(&cthread_needed);
  415.     condition_init(&cthread_idle);
  416.  
  417.     cthread_max_cprocs = 0;
  418.  
  419.     stack_fork_child();
  420.  
  421.     while (TRUE) {        /* Free cthread runnable list */
  422.     cthread_queue_deq(&cthreads, cthread_t, t);
  423.     if (t == NO_CTHREAD) break;
  424.     free((char *) t);
  425.     }
  426.  
  427.     while (free_cthreads != NO_CTHREAD) {    /* Free cthread free list */
  428.     t = free_cthreads;
  429.     free_cthreads = free_cthreads->next;
  430.     free((char *) t);
  431.     }
  432.  
  433.     cthread_cprocs = 1;
  434.     t = cthread_self();
  435.     cthread_cthreads = 1;
  436.     t->state |= T_MAIN;
  437.     cthread_set_name(t, "main");
  438.  
  439.     p = cproc_self();
  440.     p->incarnation = t;
  441.     mig_init(p);        /* enable multi-threaded mig interfaces */
  442. }
  443.