home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / threads / src / pthread.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  38KB  |  1,605 lines

  1. /* Copyright (C) 1992, the Florida State University
  2.    Distributed by the Florida State University under the terms of the
  3.    GNU Library General Public License.
  4.  
  5. This file is part of Pthreads.
  6.  
  7. Pthreads is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public
  9. License as published by the Free Software Foundation (version 2).
  10.  
  11. Pthreads is distributed "AS IS" in the hope that it will be
  12. useful, but WITHOUT ANY WARRANTY; without even the implied
  13. warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. See the GNU Library General Public License for more details.
  15.  
  16. You should have received a copy of the GNU Library General Public
  17. License along with Pthreads; see the file COPYING.  If not, write
  18. to the Free Software Foundation, 675 Mass Ave, Cambridge,
  19. MA 02139, USA.
  20.  
  21. Report problems and direct all questions to:
  22.  
  23.   pthreads-bugs@ada.cs.fsu.edu
  24.  
  25.   @(#)pthread.c    2.5 4/12/95
  26.  
  27. */
  28.  
  29. /*
  30.  * Implementation of fork, join, exit, etc.
  31.  */
  32.  
  33. #include "pthread_setjmp.h"
  34. #include "pthread_internals.h"
  35. #include <pthread/pthread_asm.h>
  36.  
  37. #ifdef STAND_ALONE
  38. #define MAX_THREADS 200
  39. static struct pthread tcb[MAX_THREADS];
  40.  
  41. extern char etext;
  42. #endif
  43.  
  44. volatile int pthread_started = FALSE;
  45. static volatile int n_pthreads = 0;
  46. static volatile pthread_key_t n_keys = 0;
  47. static void (*key_destructor[_POSIX_DATAKEYS_MAX])();
  48.  
  49. /*------------------------------------------------------------*/
  50. /*
  51.  * pthread_alloc - allocate pthread structure
  52.  */
  53. static pthread_t pthread_alloc(func, arg)
  54.      pthread_func_t func;
  55.      any_t arg;
  56. {
  57.   pthread_t t;
  58.   extern char *pthread_calloc();
  59.  
  60. #ifdef STAND_ALONE
  61.   int i;
  62.   char *c;
  63.  
  64.   for (i = 0; i < MAX_THREADS; i++) {
  65.     t = (pthread_t) SA((int) &tcb[i]);
  66.     if (t->state & T_RETURNED && t->state & T_DETACHED) {
  67.       t->state &= ~(T_RETURNED | T_DETACHED);
  68.       c = (char *) &tcb[i];
  69.       for (i = sizeof(*t); i > 0; i--, c++)
  70.     *c = '\0';
  71.  
  72.       break;
  73.     }
  74.   }
  75.   if (i >= MAX_THREADS)
  76.     t = NO_PTHREAD;
  77. #else !STAND_ALONE
  78. #ifdef MALLOC
  79.   if (!pthread_started)
  80.     t = (pthread_t) pthread_calloc(1, sizeof(struct pthread));
  81.   else
  82. #endif MALLOC
  83.     t = (pthread_t) calloc(1, sizeof(struct pthread));
  84. #endif STAND_ALONE
  85.   if (t != NO_PTHREAD) {
  86.     t->func = func;
  87.     t->arg = arg;
  88.     t->state = T_RUNNING | T_CONTROLLED;
  89.   }
  90.   return(t);
  91. }
  92.  
  93. /*------------------------------------------------------------*/
  94. /*
  95.  * pthread_self - returns immutable thread ID of calling thread
  96.  */
  97. pthread_t pthread_self()
  98. {
  99.   return(mac_pthread_self());
  100. }
  101.  
  102. /*------------------------------------------------------------*/
  103. /*
  104.  * pthread_init - initialize the threads package. This function is 
  105.  * the first function that be called by any program using this package.
  106.  * It initializes the main thread and sets up a stackspace for all the
  107.  * threads to use. Its main purpose is to setup the mutexes and 
  108.  * condition variables and allow one to access them.
  109.  */
  110. void pthread_init()
  111. {
  112.   pthread_t t;
  113.   int i;
  114.   sigjmp_buf env;
  115.  
  116. #ifdef SOLARIS
  117.   /*
  118.    * This dummy reference ensures that the initialization routine
  119.    * is always linked.
  120.    */
  121.   extern void pthread_dummy();
  122.   if (FALSE)
  123.     pthread_dummy();
  124. #endif SOLARIS
  125.  
  126.   if (pthread_started)
  127.     return;
  128.  
  129. #ifdef STAND_ALONE
  130.   init_malloc();
  131. /*  pthread_lock_code(PA(&etext));*/
  132.   pthread_lock_mem();
  133.   for (i = 0; i < MAX_THREADS; i++) {
  134.     t = (pthread_t) SA((int) &tcb[i]);
  135.     t->state |= (T_RETURNED | T_DETACHED);
  136.   }
  137.   init_clock();
  138.   start_clock();
  139. #endif
  140.  
  141.   pthread_init_signals();
  142.  
  143.   pthread_mutexattr_init(&pthread_mutexattr_default);
  144.   pthread_condattr_init(&pthread_condattr_default);
  145.   pthread_attr_init(&pthread_attr_default);
  146.  
  147.   t = pthread_alloc((pthread_func_t) 0, (any_t *) NULL);
  148.   t->state |= T_MAIN | T_CONTROLLED;
  149.  
  150.   sigsetjmp(env, FALSE);
  151.   process_stack_base = (char *) env[JB_SP];
  152.   pthread_stack_init(t);
  153.  
  154.   n_pthreads = 1;
  155.   t->attr.prio = MIN_PRIORITY;
  156. #ifdef _POSIX_THREADS_PRIO_PROTECT
  157.   t->base_prio = MIN_PRIORITY;
  158. #ifdef SRP
  159.   t->max_ceiling_prio = NO_PRIO;
  160.   t->new_prio = NO_PRIO;
  161. #endif
  162. #endif
  163. #ifdef DEF_RR
  164.   t->attr.sched = SCHED_RR;
  165. #else
  166.   t->attr.sched = SCHED_FIFO;
  167. #endif
  168.   /*
  169.    * 1st thread inherits signal mask from process
  170.    */
  171. #ifdef STAND_ALONE
  172.   pthread_sigcpyset2set(&t->mask, &proc_mask);
  173. #else
  174.   SIGPROCMASK(SIG_SETMASK, (struct sigaction *) NULL, &t->mask);
  175. #endif
  176.   mac_pthread_self() = t;    
  177.   pthread_q_all_enq(&all, t);
  178.   pthread_q_primary_enq(&ready, t);
  179.   state_change = FALSE;
  180.   pthread_started = TRUE;
  181. #ifdef DEF_RR
  182.   pthread_timed_sigwait(t, NULL, RR_TIME, NULL, t);
  183. #endif
  184. }
  185.  
  186. /*------------------------------------------------------------*/
  187. /*
  188.  * pthread_body - base of the pthreads implementation.
  189.  * Procedure invoked at the base of each pthread (as a wrapper).
  190.  */
  191. void pthread_body()
  192. {
  193.   pthread_t t = mac_pthread_self();
  194. #ifdef REAL_TIME
  195.   struct timespec tp;
  196. #endif REAL_TIME
  197.   static void pthread_terminate();
  198. #ifdef DEBUG
  199. #ifdef STAND_ALONE
  200. pthread_timer_q_t pthread_timer;              /* timer queue                 */
  201. #else
  202. pthread_timer_q pthread_timer;                /* timer queue                 */
  203. #endif
  204. #endif DEBUG
  205.  
  206. #ifdef C_CONTEXT_SWITCH
  207.   CLEAR_KERNEL_FLAG;
  208. #endif
  209.  
  210. #ifdef REAL_TIME
  211.   NTIMERCLEAR(tp);
  212.   if (ISNTIMERSET(t->attr.starttime)) {
  213.     tp.tv_sec = t->attr.starttime.tv_sec;
  214.     tp.tv_nsec = t->attr.starttime.tv_nsec;
  215.   }
  216.  
  217.   if (ISNTIMERSET(t->attr.deadline)) {
  218.     SET_KERNEL_FLAG;
  219.     pthread_timed_sigwait(t, &t->attr.deadline, ABS_TIME, pthread_exit, -1);
  220.     CLEAR_KERNEL_FLAG;
  221.   }
  222.  
  223.   do {
  224.     if (ISNTIMERSET(tp)) {
  225.       SET_KERNEL_FLAG;
  226.       pthread_timed_sigwait(t, &tp, ABS_TIME, pthread_exit, -1);
  227.       CLEAR_KERNEL_FLAG;
  228.     }
  229. #ifdef DEBUG
  230.     fprintf(stderr, "body time Q head %x\n", pthread_timer.head);
  231. #endif DEBUG
  232.     if (!sigsetjmp(t->body, FALSE))
  233. #endif
  234.  
  235.       t->result = (*(t->func))(t->arg);
  236.  
  237. #ifdef REAL_TIME
  238.     if (!LE0_NTIME(t->attr.period)) {
  239.       PLUS_NTIME(tp, tp, t->attr.period);
  240.       SET_KERNEL_FLAG;
  241.       pthread_cancel_timed_sigwait(t, FALSE, ALL_TIME, FALSE);
  242.       CLEAR_KERNEL_FLAG;
  243.       pthread_absnanosleep(&tp);
  244.     }
  245.   } while (!LE0_NTIME(t->attr.period));
  246. #endif REAL_TIME
  247.  
  248.   pthread_terminate();
  249. }
  250.  
  251. /*------------------------------------------------------------*/
  252. /*
  253.  * pthread_terminate - terminate thread: call cleanup handlers and
  254.  * destructor functions, allow no more signals, dequeue from ready,
  255.  * and switch context
  256.  */
  257. static void pthread_terminate()
  258. {
  259.   register pthread_t p, t = mac_pthread_self();
  260.   register pthread_key_t i;
  261.   register cleanup_t new;
  262. #ifdef CLEANUP_HEAP
  263.   register cleanup_t old;
  264. #endif
  265.   sigset_t abs_all_signals;
  266.  
  267.   /*
  268.    * No more signals, also remove from queue of all threads
  269.    */
  270.   pthread_sigcpyset2set(&abs_all_signals, &all_signals);
  271.   sigaddset(&abs_all_signals, SIGCANCEL);
  272.   if (!pthread_siggeset2set(&t->mask, &abs_all_signals)) {
  273.     SET_KERNEL_FLAG;
  274.  
  275.     if (t->state & (T_SIGWAIT | T_SIGSUSPEND)) {
  276.       t->state &= ~(T_SIGWAIT | T_SIGSUSPEND);
  277.       sigemptyset(&t->sigwaitset);
  278.     }
  279.  
  280.     pthread_q_deq(&all, t, ALL_QUEUE);
  281.     pthread_sigcpyset2set(&t->mask, &abs_all_signals);
  282.  
  283.     CLEAR_KERNEL_FLAG;
  284.   }
  285.  
  286.   /*
  287.    * call cleanup handlers in LIFO
  288.    */
  289. #ifdef CLEANUP_HEAP
  290.   for (old = (cleanup_t) NULL, new = t->cleanup_top; new;
  291.        old = new, new = new->next) {
  292.     (new->func)(new->arg);
  293.     if (old)
  294.       free(old);
  295.   }
  296.   if (old)
  297.     free(old);
  298. #else
  299.   for (new = t->cleanup_top; new; new = new->next)
  300.     (new->func)(new->arg);
  301. #endif
  302.  
  303.   /*
  304.    * call destructor functions for data keys (if both are defined)
  305.    */
  306.   for (i = 0; i < n_keys; i++)
  307.     if (t->key[i] && key_destructor[i])
  308.       (key_destructor[i])(t->key[i]);
  309.  
  310.   /*
  311.    * dequeue thread and schedule someone else
  312.    */
  313.  
  314.   SET_KERNEL_FLAG;
  315.   if (t->state & (T_SYNCTIMER | T_ASYNCTIMER)) {
  316. #ifdef TIMER_DEBUG
  317.     fprintf(stderr, "pthread_terminate: pthread_cancel_timed_sigwait\n");
  318. #endif
  319.     pthread_cancel_timed_sigwait(t, FALSE, ALL_TIME, FALSE);
  320.   }
  321.   t->state &= ~T_RUNNING;
  322.   t->state |= T_RETURNED;
  323.  
  324.   /*
  325.    * Terminating thread has to be detached if anyone tries to join
  326.    * but the memory is not freed until the dispatcher is called.
  327.    * This is required by pthread_join().
  328.    * The result is copied into the TCB of the joining threads to
  329.    * allow the memory of the current thread to be reclaimed before
  330.    * the joining thread accesses the result.
  331.    */
  332.   if (t->joinq.head) {
  333.     t->state |= T_DETACHED;
  334.     for (p = t->joinq.head; p; p = p->next[PRIMARY_QUEUE])
  335.       p->result = t->result;
  336.     pthread_q_wakeup_all(&t->joinq, PRIMARY_QUEUE);
  337.   }
  338.   
  339. #ifdef STACK_CHECK
  340.   if (!(t->state & T_MAIN))
  341.     pthread_unlock_all_stack(t);
  342. #endif
  343.  
  344.   /*
  345.    * The last threads switches off the light and calls UNIX exit
  346.    */
  347.   SIM_SYSCALL(TRUE);
  348.   if (--n_pthreads) {
  349.     pthread_q_deq(&ready, t, PRIMARY_QUEUE);
  350.     CLEAR_KERNEL_FLAG;
  351.   }
  352.   else {
  353. #ifdef STAND_ALONE
  354.     exit();
  355. #else
  356.     pthread_clear_sighandler();
  357.     pthread_process_exit(t->state & T_DETACHED ? 0 : 1);
  358. #endif
  359.   }
  360. }
  361.  
  362. /*------------------------------------------------------------*/
  363. /*
  364.  * pthread_create - Create a new thread of execution. the thread 
  365.  * structure and a queue and bind them together.
  366.  * The completely created pthread is then put on the active list before
  367.  * it is allowed to execute. Caution: The current implementation uses 
  368.  * pointers to the thread structure as thread ids. If a thread is not 
  369.  * valid it's pointer becomes a dangling reference but may still be 
  370.  * used for thread operations. It's up to the user to make sure he 
  371.  * never uses dangling thread ids. If, for example, the created thread
  372.  * has a higher priority than the caller of pthread_create() and the 
  373.  * created thread does not block, the caller will suspend until the 
  374.  * child has terminated and receives a DANGLING REFERENCE as the 
  375.  * thread id in the return value of pthread_create()! This 
  376.  * implementation could be enhanced by modifying the type pthread_t of
  377.  * a pointer to the thread control block and a serial number which had
  378.  * to be compared with the serial number in the thread control block 
  379.  * for each thread operation. Also, threads had to be allocated from a
  380.  * fixed-size thread control pool or the serial number would become a 
  381.  * "magic number".
  382.  */
  383. int pthread_create(thread, attr, func, arg)
  384.      pthread_t *thread;
  385.      pthread_attr_t *attr;
  386.      pthread_func_t func;
  387.      any_t arg;
  388. {
  389.   register pthread_t t;
  390.   pthread_t parent_t = mac_pthread_self();
  391.  
  392.   if (!attr)
  393.     attr = &pthread_attr_default;
  394.  
  395.   if (!attr->flags || thread == NULL) {
  396.     set_errno(EINVAL);
  397.     return(-1);
  398.   }
  399.  
  400. #ifdef REAL_TIME
  401.   {
  402.     struct timespec now;
  403.  
  404.     clock_gettime(CLOCK_REALTIME, &now);
  405.     if ((ISNTIMERSET(attr->starttime) && !GTEQ_NTIME(attr->starttime, now)) ||
  406.     (ISNTIMERSET(attr->deadline)  && !GTEQ_NTIME(attr->deadline , now)) ||
  407.     (ISNTIMERSET(attr->period) && !ISNTIMERSET(attr->starttime))) {
  408.       set_errno(EINVAL);
  409.       return(-1);
  410.     }
  411.   }
  412. #endif REAL_TIME
  413.  
  414.   t = pthread_alloc(func, arg);
  415.   if (t == NO_PTHREAD) {
  416.     set_errno(EAGAIN);
  417.     return(-1);
  418.   }
  419.  
  420.   t->attr.stacksize = attr->stacksize;
  421.   t->attr.flags = attr->flags;
  422. #ifdef _POSIX_THREADS_PRIO_PROTECT
  423. #ifdef SRP
  424.   t->max_ceiling_prio = NO_PRIO;
  425.   t->new_prio = NO_PRIO;
  426. #endif
  427. #endif
  428.   if (attr->inheritsched) {
  429.     t->attr.contentionscope = attr->contentionscope;
  430.     t->attr.inheritsched = attr->inheritsched;
  431.     t->attr.sched = attr->sched;
  432.     t->attr.prio = attr->prio;
  433. #ifdef _POSIX_THREADS_PRIO_PROTECT
  434.     t->base_prio = attr->prio;
  435. #endif
  436.   }
  437.   else {
  438.     t->attr.contentionscope = parent_t->attr.contentionscope;
  439.     t->attr.inheritsched = parent_t->attr.inheritsched;
  440.     t->attr.sched = parent_t->attr.sched;
  441. #ifdef _POSIX_THREADS_PRIO_PROTECT
  442.     t->attr.prio = t->base_prio = parent_t->base_prio;
  443. #else
  444.     t->attr.prio = parent_t->attr.prio;
  445. #endif
  446.   }
  447. #ifdef REAL_TIME
  448.   t->attr.starttime.tv_sec = attr->starttime.tv_sec;
  449.   t->attr.starttime.tv_nsec = attr->starttime.tv_nsec;
  450.   t->attr.deadline.tv_sec = attr->deadline.tv_sec;
  451.   t->attr.deadline.tv_nsec = attr->deadline.tv_nsec;
  452.   t->attr.period.tv_sec = attr->period.tv_sec;
  453.   t->attr.period.tv_nsec = attr->period.tv_nsec;
  454. #endif REAL_TIME
  455. #ifdef DEF_RR
  456.   t->num_timers = 0;
  457.   t->interval.tv_sec = 0;
  458.   t->interval.tv_usec = 0;
  459. #endif
  460.   pthread_queue_init(&t->joinq);
  461.   /*
  462.    * inherit the parent's signal mask
  463.    */
  464.   pthread_sigcpyset2set(&t->mask, &parent_t->mask);
  465.   if (attr->detachstate)
  466.     t->state |= T_DETACHED;
  467.   SET_KERNEL_FLAG;
  468.   ++n_pthreads; 
  469.   if (!pthread_alloc_stack(t)) {
  470.     CLEAR_KERNEL_FLAG;
  471.     set_errno(ENOMEM);
  472.     return(-1);
  473.   }
  474.   pthread_initialize(t);
  475.   pthread_q_all_enq(&all, t);
  476.   pthread_q_primary_enq(&ready, t);
  477.   SIM_SYSCALL(TRUE);
  478.   CLEAR_KERNEL_FLAG;
  479.     
  480.   *thread= t;
  481.   return(0);
  482. }
  483.  
  484. /*------------------------------------------------------------*/
  485. /*
  486.  * pthread_equal() - Cmpares two threads. Returns
  487.  *      0 if t1 <> t2
  488.  *      1 if t1 == t2
  489.  */
  490. int pthread_equal(t1, t2)
  491.      pthread_t t1, t2;
  492. {
  493.   return(t1 == t2);
  494. }
  495.  
  496. /*------------------------------------------------------------*/
  497. /*
  498.  * pthread_detach - Detaching a running thread simply consists of 
  499.  * marking it as such. If the thread has returned then the resources 
  500.  * are also freed.
  501.  */
  502. int pthread_detach(thread_ptr)
  503.      pthread_t *thread_ptr;
  504. {
  505.   pthread_t thread;
  506.  
  507.   if ((thread_ptr == NULL) || (*thread_ptr == NO_PTHREAD)) {
  508.     set_errno(EINVAL);
  509.     return(-1);
  510.   }
  511.  
  512.   thread = *thread_ptr;
  513.  
  514.   SET_KERNEL_FLAG;
  515.  
  516.   if (thread->state & T_DETACHED) {
  517.     CLEAR_KERNEL_FLAG;
  518.     set_errno(ESRCH);
  519.     return(-1);
  520.   }
  521.   
  522.   thread->state |= T_DETACHED;
  523.  
  524.   if (thread->state & T_RETURNED) {
  525. #if defined(MALLOC) || defined(STAND_ALONE)
  526.     pthread_free(thread->stack_base);
  527. #ifndef STAND_ALONE
  528.     pthread_free(thread);
  529. #endif !STAND_ALONE
  530. #else !(MALLOC || STAND_ALONE)
  531.     free(thread->stack_base);
  532.     free(thread);
  533. #endif MALLOC || STAND_ALONE
  534.     *thread_ptr = NO_PTHREAD;
  535.     SIM_SYSCALL(TRUE);
  536.   }
  537.  
  538.   CLEAR_KERNEL_FLAG;
  539.   return(0);
  540. }
  541.  
  542. /*------------------------------------------------------------*/
  543. /*
  544.  * pthread_join - Wait for a thread to exit. If the status parameter is
  545.  * non-NULL then that threads exit status is stored in it.
  546.  */
  547. int pthread_join(thread,status)
  548.      pthread_t thread;
  549.      any_t *status;
  550. {
  551.   register pthread_t p = mac_pthread_self();
  552.  
  553.   if (thread == NO_PTHREAD) {
  554.     set_errno(EINVAL);
  555.     return(-1);
  556.   }
  557.   
  558.   if (thread == p) {
  559.     set_errno(EDEADLK);
  560.     return(-1);
  561.   }
  562.  
  563.   SET_KERNEL_FLAG;
  564.   
  565.   if (thread->state & T_RETURNED) {
  566.     if (thread->state & T_DETACHED) {
  567.       CLEAR_KERNEL_FLAG;
  568.       set_errno(ESRCH);
  569.       return(-1);
  570.     }
  571.  
  572.     if (status)
  573.       *status = thread->result;
  574.  
  575. #ifndef DRAFT6
  576.     thread->state |= T_DETACHED;
  577.  
  578. #if defined(MALLOC) || defined(STAND_ALONE)
  579.     pthread_free(thread->stack_base);
  580. #ifndef STAND_ALONE
  581.     pthread_free(thread);
  582. #endif !STAND_ALONE
  583. #else !(MALLOC || STAND_ALONE)
  584.     free(thread->stack_base);
  585.     free(thread);
  586. #endif MALLOC || STAND_ALONE
  587. #endif DRAFT6
  588.     
  589.     CLEAR_KERNEL_FLAG;
  590.     return(0);
  591.   }
  592.   
  593.   /*
  594.    * clear error number before suspending
  595.    */
  596.   set_errno(0);
  597.  
  598.   pthread_q_sleep(&thread->joinq, PRIMARY_QUEUE);
  599.   p->state |= T_INTR_POINT;
  600.   if (sigismember(&p->pending, SIGCANCEL) &&
  601.       !sigismember(&p->mask, SIGCANCEL))
  602.     SIG_CLEAR_KERNEL_FLAG(TRUE);
  603.   else {
  604.     SIM_SYSCALL(TRUE);
  605.     CLEAR_KERNEL_FLAG;
  606.   }
  607.   
  608.   if (get_errno() == EINTR)
  609.     return(-1);
  610.  
  611.   /*
  612.    * status was copied into result field of current TCB by other thread
  613.    */
  614.   if (status)
  615.     *status = p->result;
  616.   return(0);
  617. }
  618.  
  619. /*------------------------------------------------------------*/
  620. /* Function:
  621.  *    pthread_yield -  Yield the processor to another thread.
  622.  *    The current process is taken off the queue and another executes
  623.  *    Simply put oneself at the tail of the queue.
  624.  */
  625. void pthread_yield(arg)
  626.      any_t arg;
  627. {
  628.   if (arg == NULL && ready.head != ready.tail) {
  629.     /*
  630.      * Place ourself at the end of the ready queue.
  631.      * This allows the other ready processes to execute thus
  632.      * in effect yielding the processor.
  633.      */
  634.     SET_KERNEL_FLAG;
  635.     pthread_q_primary_enq(&ready, pthread_q_deq_head(&ready, PRIMARY_QUEUE));
  636.     SIM_SYSCALL(TRUE);
  637.     CLEAR_KERNEL_FLAG;
  638.   }
  639. }
  640.  
  641. /*------------------------------------------------------------*/
  642. /*
  643.  * pthread_exit -  Save the exit status of the thread so that other 
  644.  * threads joining with this thread can find it.
  645.  */
  646. void pthread_exit(status)
  647.      any_t status;
  648. {
  649.   register pthread_t t = mac_pthread_self();
  650.   t->result = status;
  651.   pthread_terminate();
  652. }
  653.  
  654. /*------------------------------------------------------------*/
  655. /*
  656.  * pthread_attr_init - Initializes the attr (thread attribute object)
  657.  * with the default values.
  658.  */
  659. int pthread_attr_init(attr)
  660.      pthread_attr_t *attr;
  661. {
  662.   if (!attr) {
  663.     set_errno(EINVAL);
  664.     return(-1);
  665.   }
  666.  
  667.   attr->flags = TRUE;
  668.   attr->contentionscope = PTHREAD_SCOPE_LOCAL;
  669.   attr->inheritsched = PTHREAD_DEFAULT_SCHED;
  670.   attr->detachstate = 0;
  671. #ifdef DEF_RR
  672.   attr->sched = SCHED_RR;
  673. #else
  674.   attr->sched = SCHED_FIFO;
  675. #endif
  676.   attr->stacksize = DEFAULT_STACKSIZE;
  677.   attr->prio = DEFAULT_PRIORITY;
  678. #ifdef REAL_TIME
  679.   NTIMERCLEAR(attr->starttime);
  680.   NTIMERCLEAR(attr->deadline);
  681.   NTIMERCLEAR(attr->period);
  682. #endif REAL_TIME
  683.   return(0);
  684. }
  685.  
  686. /*------------------------------------------------------------*/
  687. /*
  688.  * pthread_attr_destroy - Destroys the thread attribute object.
  689.  */
  690. int pthread_attr_destroy(attr)
  691.      pthread_attr_t *attr;
  692. {
  693.   if (!attr || !attr->flags) {
  694.     set_errno(EINVAL);
  695.     return(-1);
  696.   }
  697.   attr->flags = FALSE;
  698.   return(0);
  699. }
  700.  
  701. /*------------------------------------------------------------*/
  702. /*
  703.  * pthread_getschedattr - get the thread scheduling attributes
  704.  */
  705. int pthread_getschedattr(thread, attrs)
  706.      pthread_t thread;
  707.      pthread_attr_t *attrs;
  708. {
  709.   if (thread == NO_PTHREAD)  {
  710.     set_errno(ESRCH);
  711.     return(-1);
  712.   }
  713.   
  714.   if (!attrs || !attrs->flags) {
  715.     set_errno(EINVAL);
  716.     return(-1);
  717.   }
  718.  
  719.   attrs->sched = thread->attr.sched;
  720. #ifdef _POSIX_THREADS_PRIO_PROTECT
  721.   attrs->prio = thread->base_prio;
  722. #else
  723.   attrs->prio = thread->attr.prio;
  724. #endif
  725.   return(0);
  726. }
  727.  
  728. /*------------------------------------------------------------*/
  729. /*
  730.  * pthread_setprio_np - D5 function. Used to speed up the setting of Priority
  731.  *                   of a thread.
  732.  */
  733. int pthread_setprio_np(thread,prio)
  734.      pthread_t thread;
  735.      int prio;
  736. {
  737. #ifndef DRAFT5
  738.   set_errno(ENOSYS);
  739.   return(-1);
  740. #else DRAFT5
  741.   pthread_queue_t q;
  742.   int oldprio, run_prio;
  743.  
  744.   if (thread == NO_PTHREAD)  {
  745.     set_errno(ESRCH);
  746.     return(-1);
  747.   }
  748.   if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) {
  749.     set_errno(EINVAL);
  750.     return(-1);
  751.   }
  752.  
  753.  
  754.   SET_KERNEL_FLAG;
  755.  
  756.   if (thread->state & T_RETURNED) {
  757.     CLEAR_KERNEL_FLAG;
  758.     set_errno(EINVAL);
  759.     return(-1);
  760.   }
  761.  
  762. #ifdef _POSIX_THREADS_PRIO_PROTECT
  763. #ifdef SRP
  764.   if (thread->new_prio == MUTEX_WAIT) {
  765.     thread->new_prio = prio;
  766.     CLEAR_KERNEL_FLAG;
  767.     return (0);
  768.   }
  769. #endif SRP
  770.   oldprio = thread->base_prio;
  771.   run_prio = thread->attr.prio;
  772.   thread->base_prio = prio;
  773.   if (thread->max_ceiling_prio != NO_PRIO)
  774.     thread->attr.prio = MAX(prio, thread->max_ceiling_prio);
  775.   else
  776.     thread->attr.prio = prio;
  777. #else !_POSIX_THREADS_PRIO_PROTECT
  778.   run_prio = oldprio = thread->attr.prio;
  779.   thread->attr.prio = prio;
  780. #endif !_POSIX_THREADS_PRIO_PROTECT
  781.   q=thread->queue;
  782.   if ((thread != mac_pthread_self()) ||
  783.       ((thread->attr.prio < run_prio) && (q->head != q->tail) &&
  784.        (thread->attr.prio < thread->next[PRIMARY_QUEUE]->attr.prio)))  {
  785.     pthread_q_deq(q, thread, PRIMARY_QUEUE);
  786.     pthread_q_primary_enq(q, thread);
  787.   }
  788.   SIM_SYSCALL(TRUE);
  789.   CLEAR_KERNEL_FLAG;
  790.   return(oldprio);
  791. #endif DRAFT5
  792. }
  793.  
  794. /*------------------------------------------------------------*/
  795. /*
  796.  * pthread_setschedattr - Set the thread specific scheduling attributes
  797.  */
  798. int pthread_setschedattr(thread,attrs)
  799.      pthread_t thread;
  800.      pthread_attr_t attrs;
  801. {
  802.   pthread_t p = mac_pthread_self();
  803.   pthread_queue_t q;
  804.   int oldsched, run_prio;
  805.  
  806.   if (thread == NO_PTHREAD)  {
  807.     set_errno(ESRCH);
  808.     return(-1);
  809.   }
  810.  
  811.   if (!attrs.flags) {
  812.     set_errno(EINVAL);
  813.     return(-1);
  814.   }
  815.   
  816. #ifdef DEF_RR
  817.   if (attrs.sched != SCHED_FIFO && attrs.sched != SCHED_RR) {
  818.  
  819. #else
  820.   if (attrs.sched != SCHED_FIFO) {
  821. #endif
  822.     set_errno(ENOTSUP);
  823.     return(-1);
  824.   }
  825.  
  826.   if (attrs.prio < MIN_PRIORITY || attrs.prio > MAX_PRIORITY) {
  827.     set_errno(EINVAL);
  828.     return(-1);
  829.   }
  830.  
  831. #ifdef REAL_TIME
  832.   if (ISNTIMERSET(attrs.starttime) ||
  833.       ISNTIMERSET(attrs.deadline) ||
  834.       ISNTIMERSET(attrs.period)) {
  835.     set_errno(EINVAL);
  836.     return(-1);
  837.   }
  838. #endif REAL_TIME
  839.  
  840.   SET_KERNEL_FLAG;
  841.  
  842.   if (thread->state & T_RETURNED) {
  843.     CLEAR_KERNEL_FLAG;
  844.     set_errno(EINVAL);
  845.     return(-1);
  846.   }
  847.  
  848.   oldsched = thread->attr.sched;
  849.   thread->attr.sched = attrs.sched;
  850. #ifdef DEF_RR
  851.   if (attrs.sched != oldsched && p == thread)
  852.     switch (oldsched) {
  853.     case SCHED_FIFO:
  854.       pthread_timed_sigwait(thread, NULL, RR_TIME, NULL, thread);
  855.       break;
  856.     case SCHED_RR:
  857.       pthread_cancel_timed_sigwait(thread, FALSE, RR_TIME,
  858.                      thread->queue != &ready);
  859.       break;
  860.     default:
  861.       ;
  862.     }
  863. #endif
  864. #ifdef _POSIX_THREADS_PRIO_PROTECT
  865. #ifdef SRP
  866.   if (thread->new_prio == MUTEX_WAIT) {
  867.     thread->new_prio = attrs.prio;
  868.     CLEAR_KERNEL_FLAG;
  869.     return (0);
  870.   }
  871. #endif
  872.   run_prio = thread->attr.prio;
  873.   thread->base_prio = attrs.prio;
  874.   if (thread->max_ceiling_prio != NO_PRIO)
  875.     thread->attr.prio = MAX(attrs.prio, thread->max_ceiling_prio);
  876.   else
  877.     thread->attr.prio = attrs.prio;
  878. #else
  879.   run_prio = thread->attr.prio;
  880.   thread->attr.prio = attrs.prio;
  881. #endif
  882.   q = thread->queue;
  883.   if (q->head != thread ||
  884.       (q->head != q->tail && thread->attr.prio < run_prio &&
  885.        thread->attr.prio < thread->next[PRIMARY_QUEUE]->attr.prio)) {
  886.     pthread_q_deq(q, thread, PRIMARY_QUEUE);
  887.     pthread_q_primary_enq(q, thread);
  888.   }
  889.  
  890.   SIM_SYSCALL(TRUE);
  891.   CLEAR_KERNEL_FLAG;
  892.   return(0);
  893. }
  894.  
  895. /*------------------------------------------------------------*/
  896. /*
  897.  * pthread_attr_setstacksize - Aligns the "stacksize" to double
  898.  * word boundary and then sets the size of the stack to "stacksize"
  899.  * in thread attribute object "attr".
  900.  */
  901. int pthread_attr_setstacksize(attr,stacksize)
  902.      pthread_attr_t *attr;
  903.      size_t stacksize;
  904. {
  905.   if (!attr || !attr->flags) {
  906.     set_errno(EINVAL);
  907.     return(-1);
  908.   }
  909.  
  910.   attr->stacksize = SA(stacksize); /* stack align, see asm_linkage.h */
  911.   return(0);    
  912. }
  913.  
  914. /*------------------------------------------------------------*/
  915. /*
  916.  * pthread_attr_getstacksize - gets the stacksize from an pthread 
  917.  * attribute object.
  918.  */
  919. int pthread_attr_getstacksize(attr,stacksize)
  920.      pthread_attr_t *attr;
  921.      size_t *stacksize;
  922. {
  923.   if (!attr || !attr->flags) {
  924.     set_errno(EINVAL);
  925.     return(-1);
  926.   }
  927.  
  928.   *stacksize = attr->stacksize;    
  929.   return(0);
  930. }
  931.  
  932. /*------------------------------------------------------------*/
  933. /*
  934.  * pthread_attr_setscope - Set the contentionscope attribute in a 
  935.  * thread attribute object.
  936.  */
  937. int pthread_attr_setscope(attr,contentionscope)
  938.      pthread_attr_t *attr;
  939.      int contentionscope;
  940. {
  941.   if (!attr || !attr->flags) {
  942.     set_errno(EINVAL);
  943.     return(-1);
  944.   }
  945.   if (contentionscope == PTHREAD_SCOPE_LOCAL) {
  946.     attr->contentionscope=contentionscope;
  947.     return(0);    
  948.   }
  949.   else {
  950.     set_errno(EINVAL);
  951.     return(-1);
  952.   }
  953. }
  954.  
  955. /*------------------------------------------------------------*/
  956. /*
  957.  * pthread_attr_setinheritsched - Set the inheritsched attribute.
  958.  */
  959. int pthread_attr_setinheritsched(attr, inherit)
  960.      pthread_attr_t *attr;
  961.      int inherit;
  962. {
  963.   if (!attr || !attr->flags) {
  964.     set_errno(EINVAL);
  965.     return(-1);
  966.   }
  967.   if (inherit == PTHREAD_INHERIT_SCHED || inherit == PTHREAD_DEFAULT_SCHED) {
  968.     attr->inheritsched = inherit;
  969.     return(0);    
  970.   }
  971.   else {
  972.     set_errno(EINVAL);
  973.     return(-1);
  974.   }
  975. }
  976.  
  977. /*------------------------------------------------------------*/
  978. /*
  979.  * pthread_attr_setsched - set the sched attribute
  980.  */
  981. int pthread_attr_setsched(attr, scheduler)
  982.      pthread_attr_t *attr;
  983.      int scheduler;
  984. {
  985.   if (!attr || !attr->flags) {
  986.     set_errno(EINVAL);
  987.     return(-1);
  988.   }
  989.  
  990. #ifdef DEF_RR
  991.   if (scheduler == SCHED_FIFO || scheduler == SCHED_RR) {
  992. #else
  993.   if (scheduler == SCHED_FIFO) {
  994. #endif
  995.     attr->sched = scheduler;
  996.     return(0);    
  997.   }
  998.   else {
  999.     set_errno(EINVAL);
  1000.     return(-1);
  1001.   }
  1002. }
  1003.  
  1004. /*------------------------------------------------------------*/
  1005. /*
  1006.  * pthread_attr_setprio - set the prio attribute
  1007.  */
  1008. int pthread_attr_setprio(attr, priority)
  1009.      pthread_attr_t *attr;
  1010.      int priority;
  1011. {
  1012.   if (!attr || !attr->flags) {
  1013.     set_errno(EINVAL);
  1014.     return(-1);
  1015.   }
  1016.  
  1017.   if (priority >= MIN_PRIORITY && priority <= MAX_PRIORITY) {
  1018.     attr->prio=priority;
  1019.     return(0);    
  1020.   }
  1021.   else {
  1022.     set_errno(EINVAL);
  1023.     return(-1);
  1024.   }
  1025. }
  1026.  
  1027. /*------------------------------------------------------------*/
  1028. /*
  1029.  * pthread_attr_getscope - get the contentionscope attribute
  1030.  */
  1031. int pthread_attr_getscope(attr)
  1032.      pthread_attr_t attr;
  1033. {
  1034.   if (!attr.flags) {
  1035.     set_errno(EINVAL);
  1036.     return(-1);
  1037.   }
  1038.   return(attr.contentionscope);
  1039. }
  1040.  
  1041. /*------------------------------------------------------------*/
  1042. /*
  1043.  * pthread_attr_getinheritsched - set the inheritsched attribute
  1044.  */
  1045. int pthread_attr_getinheritsched(attr)
  1046.      pthread_attr_t *attr;
  1047. {
  1048.   if (!attr || !attr->flags) {
  1049.     set_errno(EINVAL);
  1050.     return(-1);
  1051.   }
  1052.   return(attr->inheritsched);
  1053. }
  1054.  
  1055. /*------------------------------------------------------------*/
  1056. /*
  1057.  * pthread_attr_getsched - get the sched attribute
  1058.  */
  1059. int pthread_attr_getsched(attr)
  1060.      pthread_attr_t *attr;
  1061. {
  1062.   if (!attr || !attr->flags) {
  1063.     set_errno(EINVAL);
  1064.     return(-1);
  1065.   }
  1066.  
  1067.   return(attr->sched);
  1068. }
  1069.  
  1070. /*------------------------------------------------------------*/
  1071. /*
  1072.  * pthread_attr_getprio - get the prio attribute
  1073.  */
  1074. int pthread_attr_getprio(attr)
  1075.      pthread_attr_t *attr;
  1076. {
  1077.   if (!attr || !attr->flags) {
  1078.     set_errno(EINVAL);
  1079.     return(-1);
  1080.   }
  1081.  
  1082.   return(attr->prio);
  1083. }
  1084.  
  1085. /*------------------------------------------------------------*/
  1086. /*
  1087.  * pthread_attr_setstarttime_np - set the absolute start time
  1088.  */
  1089. int pthread_attr_setstarttime_np(attr, tp)
  1090.      pthread_attr_t *attr;
  1091.      struct timespec *tp;
  1092. {
  1093. #ifndef REAL_TIME
  1094.   set_errno(ENOSYS);
  1095.   return(-1);
  1096. #else REAL_TIME
  1097.   if (!attr || !attr->flags || !tp || !ISNTIMERSET(*tp)) {
  1098.     set_errno(EINVAL);
  1099.     return(-1);
  1100.   }
  1101.  
  1102.   attr->starttime.tv_sec = tp->tv_sec;
  1103.   attr->starttime.tv_nsec = tp->tv_nsec;
  1104.  
  1105.   return(0);
  1106. #endif REAL_TIME
  1107. }
  1108.  
  1109. /*------------------------------------------------------------*/
  1110. /*
  1111.  * pthread_attr_getstarttime_np - get the absolute start time
  1112.  */
  1113. int pthread_attr_getstarttime_np(attr, tp)
  1114.      pthread_attr_t *attr;
  1115.      struct timespec *tp;
  1116. {
  1117. #ifndef REAL_TIME
  1118.   set_errno(ENOSYS);
  1119.   return(-1);
  1120. #else REAL_TIME
  1121.   if (!attr || !attr->flags || !tp || !ISNTIMERSET(attr->starttime)) {
  1122.     set_errno(EINVAL);
  1123.     return(-1);
  1124.   }
  1125.  
  1126.   tp->tv_sec = attr->starttime.tv_sec;
  1127.   tp->tv_nsec = attr->starttime.tv_nsec;
  1128.  
  1129.   return(0);
  1130. #endif REAL_TIME
  1131. }
  1132.  
  1133. /*------------------------------------------------------------*/
  1134. /*
  1135.  * pthread_attr_setdeadline_np - set the absolute deadline (XOR period)
  1136.  */
  1137. int pthread_attr_setdeadline_np(attr, tp, func)
  1138.      pthread_attr_t *attr;
  1139.      struct timespec *tp;
  1140.      pthread_func_t func;
  1141. {
  1142. #ifndef REAL_TIME
  1143.   set_errno(ENOSYS);
  1144.   return(-1);
  1145. #else REAL_TIME
  1146.   extern struct sigaction pthread_user_handler[NNSIG];
  1147.  
  1148.   if (!attr || !attr->flags || !tp || !ISNTIMERSET(*tp) ||
  1149.       ISNTIMERSET(attr->period)) {
  1150.     set_errno(EINVAL);
  1151.     return(-1);
  1152.   }
  1153.  
  1154.   attr->deadline.tv_sec = tp->tv_sec;
  1155.   attr->deadline.tv_nsec = tp->tv_nsec;
  1156.   sigaddset(&handlerset, TIMER_SIG);
  1157.   pthread_user_handler[TIMER_SIG].sa_handler = (void(*)()) func;
  1158.  
  1159.   return(0);
  1160. #endif REAL_TIME
  1161. }
  1162.  
  1163. /*------------------------------------------------------------*/
  1164. /*
  1165.  * pthread_attr_getdeadline_np - get the absolute deadline
  1166.  */
  1167. int pthread_attr_getdeadline_np(attr, tp)
  1168.      pthread_attr_t *attr;
  1169.      struct timespec *tp;
  1170. {
  1171. #ifndef REAL_TIME
  1172.   set_errno(ENOSYS);
  1173.   return(-1);
  1174. #else REAL_TIME
  1175.   if (!attr || !attr->flags || !tp || !ISNTIMERSET(attr->deadline)) {
  1176.     set_errno(EINVAL);
  1177.     return(-1);
  1178.   }
  1179.  
  1180.   tp->tv_sec = attr->deadline.tv_sec;
  1181.   tp->tv_nsec = attr->deadline.tv_nsec;
  1182.  
  1183.   return(0);
  1184. #endif REAL_TIME
  1185. }
  1186.  
  1187. /*------------------------------------------------------------*/
  1188. /*
  1189.  * pthread_attr_setperiod_np - set the relative period (XOR deadline)
  1190.  */
  1191. int pthread_attr_setperiod_np(attr, tp, func)
  1192.      pthread_attr_t *attr;
  1193.      struct timespec *tp;
  1194.      pthread_func_t func;
  1195. {
  1196. #ifndef REAL_TIME
  1197.   set_errno(ENOSYS);
  1198.   return(-1);
  1199. #else REAL_TIME
  1200.   extern struct sigaction pthread_user_handler[NNSIG];
  1201.  
  1202.   if (!attr || !attr->flags || !tp || !ISNTIMERSET(*tp) ||
  1203.       ISNTIMERSET(attr->deadline)) {
  1204.     set_errno(EINVAL);
  1205.     return(-1);
  1206.   }
  1207.  
  1208.   attr->period.tv_sec = tp->tv_sec;
  1209.   attr->period.tv_nsec = tp->tv_nsec;
  1210.   sigaddset(&handlerset, TIMER_SIG);
  1211.   pthread_user_handler[TIMER_SIG].sa_handler = (void(*)()) func;
  1212.  
  1213.   return(0);
  1214. #endif REAL_TIME
  1215. }
  1216.  
  1217. /*------------------------------------------------------------*/
  1218. /*
  1219.  * pthread_attr_getperiod_np - get the relative period
  1220.  */
  1221. int pthread_attr_getperiod_np(attr, tp)
  1222.      pthread_attr_t *attr;
  1223.      struct timespec *tp;
  1224. {
  1225. #ifndef REAL_TIME
  1226.   set_errno(ENOSYS);
  1227.   return(-1);
  1228. #else REAL_TIME
  1229.   if (!attr || !attr->flags || !tp || !ISNTIMERSET(attr->period)) {
  1230.     set_errno(EINVAL);
  1231.     return(-1);
  1232.   }
  1233.  
  1234.   tp->tv_sec = attr->period.tv_sec;
  1235.   tp->tv_nsec = attr->period.tv_nsec;
  1236.  
  1237.   return(0);
  1238. #endif REAL_TIME
  1239. }
  1240.  
  1241. /*------------------------------------------------------------*/
  1242. /*
  1243.  * pthread_key_create - creates a new global key and spefies destructor call
  1244.  * returns -1 upon error with errno ENOMEM if name space exhausted,
  1245.  *                                  EAGAIN if insufficient memory.
  1246.  */
  1247. int pthread_key_create(key, destructor)
  1248.      pthread_key_t *key;
  1249.      void (*destructor)();
  1250. {
  1251.   if (n_keys >= _POSIX_DATAKEYS_MAX) {
  1252.     set_errno(ENOMEM);
  1253.     return(-1);
  1254.   }
  1255.  
  1256.   SET_KERNEL_FLAG;
  1257.   key_destructor[n_keys] = destructor;
  1258.   *key = n_keys++;
  1259.   CLEAR_KERNEL_FLAG;
  1260.   return(0);
  1261. }
  1262.  
  1263. /*------------------------------------------------------------*/
  1264. /*
  1265.  * pthread_setspecific - associate a value with a data key for some thread
  1266.  * returns -1 upon error with errno EINVAL if the key is invalid.
  1267.  */
  1268. int pthread_setspecific(key, value)
  1269.      pthread_key_t key;
  1270.      any_t value;
  1271. {
  1272.   if (key < 0 || key >= n_keys) {
  1273.     set_errno(EINVAL);
  1274.     return(-1);
  1275.   }
  1276.  
  1277.   mac_pthread_self()->key[key] = value;
  1278.   return(0);
  1279. }
  1280.  
  1281. /*------------------------------------------------------------*/
  1282. /*
  1283.  * pthread_getspecific - retrieve a value from a data key for some thread
  1284.  * returns -1 upon error with errno EINVAL if the key is invalid.
  1285.  */
  1286. int pthread_getspecific(key, value)
  1287.      pthread_key_t key;
  1288.      any_t *value;
  1289. {
  1290.   if (key < 0 || key >= n_keys) {
  1291.     set_errno(EINVAL);
  1292.     return(-1);
  1293.   }
  1294.  
  1295.   *value = mac_pthread_self()->key[key];
  1296.   return(0);
  1297. }
  1298.  
  1299. /*------------------------------------------------------------*/
  1300. /*
  1301.  * pthread_cleanup_push - push function on current thread's cleanup stack
  1302.  * and execute it with the specified argument when the thread.
  1303.  * Notice: pthread_cleanup_push_body() receives the address of the first
  1304.  * cleanup structure in an additional parameter "new".
  1305.  * (a) exits;
  1306.  * (b) is cancelled;
  1307.  * (c) calls pthread_cleanup_pop(0 with a non-zero argument;
  1308.  * (d) NOT IMPLEMENTED, CONTROVERSIAL: when a longjump reaches past the scope.
  1309.  */
  1310. #ifdef    CLEANUP_HEAP
  1311. int pthread_cleanup_push(func, arg)
  1312. #else
  1313. int pthread_cleanup_push_body(func, arg, new)
  1314. #endif
  1315.      void (*func)();
  1316.      any_t arg;
  1317. #ifdef    CLEANUP_HEAP
  1318. {
  1319.   cleanup_t new;
  1320. #else
  1321.      cleanup_t new;
  1322. {
  1323. #endif
  1324.   pthread_t p = mac_pthread_self();
  1325.  
  1326.   if (!func) {
  1327.     set_errno(EINVAL);
  1328.     return(-1);
  1329.   }
  1330.  
  1331. #ifdef    CLEANUP_HEAP
  1332.   if (!(new = (cleanup_t) malloc(sizeof(*new)))) {
  1333.     set_errno(ENOMEM);
  1334.     return(-1);
  1335.   }
  1336. #endif
  1337.  
  1338.   new->func = func;
  1339.   new->arg = arg;
  1340.  
  1341.   SET_KERNEL_FLAG;
  1342.   new->next = p->cleanup_top;
  1343.   p->cleanup_top = new;
  1344.   CLEAR_KERNEL_FLAG;
  1345.  
  1346.   return(0);
  1347. }
  1348.  
  1349.  
  1350. /*------------------------------------------------------------*/
  1351. /*
  1352.  * pthread_cleanup_pop - pop function off current thread's cleanup stack
  1353.  * and execute it with the specified argument if non-zero
  1354.  */
  1355. #ifdef    CLEANUP_HEAP
  1356. int pthread_cleanup_pop(execute)
  1357. #else
  1358. int pthread_cleanup_pop_body(execute)
  1359. #endif
  1360.      int execute;
  1361. {
  1362.   pthread_t p = mac_pthread_self();
  1363.   cleanup_t new;
  1364.  
  1365.   SET_KERNEL_FLAG;
  1366.   if (!(new = p->cleanup_top)) {
  1367.     CLEAR_KERNEL_FLAG;
  1368.     set_errno(EINVAL);
  1369.     return(-1);
  1370.   }
  1371.   p->cleanup_top = new->next;
  1372.   CLEAR_KERNEL_FLAG;
  1373.  
  1374.   if (execute)
  1375.     (new->func)(new->arg);
  1376. #ifdef    CLEANUP_HEAP
  1377.   free(new);
  1378. #endif
  1379.  
  1380.   return(0);
  1381. }
  1382.  
  1383. /*------------------------------------------------------------*/
  1384. /*
  1385.  * sched_get_priority_max - inquire maximum priority value (part of .4)
  1386.  */
  1387. int sched_get_priority_max(policy)
  1388.      int policy;
  1389. {
  1390.   return(MAX_PRIORITY);
  1391. }
  1392.  
  1393. /*------------------------------------------------------------*/
  1394. /*
  1395.  * sched_get_priority_min - inquire minimum priority value (part of .4)
  1396.  */
  1397. int sched_get_priority_min(policy)
  1398.      int policy;
  1399. {
  1400.   return(MIN_PRIORITY);
  1401. }
  1402.  
  1403. /*------------------------------------------------------------*/
  1404. /*
  1405.  * pthread_attr_setdetachstate - Sets the detachstate attribute in 
  1406.  *                               attr object
  1407.  */
  1408. int pthread_attr_setdetachstate(attr, detachstate)
  1409.      pthread_attr_t *attr;
  1410.      int *detachstate;
  1411. {
  1412.   if (!attr || !attr->flags || (*detachstate > 1) || (*detachstate < 0)) {
  1413.     set_errno(EINVAL);
  1414.     return(-1);
  1415.   }
  1416.   attr->detachstate = *detachstate;
  1417.   return(0);
  1418. }
  1419.  
  1420. /*------------------------------------------------------------*/
  1421. /*
  1422.  * pthread_attr_getdetachstate - Gets the value of detachstate attribute
  1423.  *                               from attr object
  1424.  */
  1425. int pthread_attr_getdetachstate(attr)
  1426.      pthread_attr_t *attr;
  1427. {
  1428.   if (!attr || !attr->flags) { 
  1429.     set_errno(EINVAL);
  1430.     return(-1);    
  1431.   } 
  1432.   return(attr->detachstate); 
  1433. }
  1434.  
  1435. /*------------------------------------------------------------*/
  1436. /*
  1437.  * pthread_once - The first call to this will call the init_routine()
  1438.  *                with no arguments. Subsequent calls to pthread_once()
  1439.  *                will not call the init_routine.
  1440.  */
  1441. int pthread_once(once_control, init_routine)
  1442.      pthread_once_t *once_control;
  1443.      void (*init_routine)();
  1444. {
  1445.   SET_KERNEL_FLAG;
  1446.   if (!once_control->init) {
  1447.     once_control->init = TRUE;
  1448.     pthread_mutex_init(&once_control->mutex, NULL);
  1449.   }
  1450.   CLEAR_KERNEL_FLAG;
  1451.  
  1452.   pthread_mutex_lock(&once_control->mutex);
  1453.   if (!once_control->exec) {
  1454.     once_control->exec = TRUE;
  1455.     (*init_routine)();
  1456.   }
  1457.   pthread_mutex_unlock(&once_control->mutex);
  1458.   return(0);
  1459. }
  1460.  
  1461. #if defined(MALLOC) || defined(STAND_ALONE)
  1462.  
  1463. /*------------------------------------------------------------*/
  1464. malloc_t malloc (size)
  1465.      size_t size;
  1466. {
  1467.   malloc_t ret;
  1468.   extern char *pthread_malloc();
  1469.  
  1470.   /*
  1471.    * kludge: X malloc convention: for X, even malloc(0) must not return NULL!
  1472.    */
  1473.   if (size == 0) 
  1474.     size = 1;
  1475.  
  1476.   SET_KERNEL_FLAG;
  1477.   ret = pthread_malloc(size);
  1478.   CLEAR_KERNEL_FLAG;
  1479.   return(ret);
  1480. }
  1481.  
  1482. /*------------------------------------------------------------*/
  1483. #if defined (__cplusplus) || defined (__STDC__)
  1484. void free(ptr)
  1485. #else /* Not C++ or ANSI C.  */
  1486. int free (ptr)
  1487. #endif
  1488.      malloc_t ptr;
  1489. {
  1490.   int ret;
  1491.   extern int pthread_free();
  1492.  
  1493.   SET_KERNEL_FLAG;
  1494.   ret = pthread_free(ptr);
  1495.   CLEAR_KERNEL_FLAG;
  1496. #if !(defined (__cplusplus) || defined (__STDC__))
  1497.   return(ret);
  1498. #endif
  1499. }
  1500.  
  1501. #endif MALLOC || STAND_ALONE
  1502.  
  1503. #ifdef MALLOC
  1504.  
  1505. /*------------------------------------------------------------*/
  1506. malloc_t realloc (ptr, size)
  1507.      malloc_t ptr;
  1508.      size_t size;
  1509. {
  1510.   malloc_t ret;
  1511.   extern char *pthread_realloc();
  1512.  
  1513.   /*
  1514.    * kludge: X malloc convention: for X, even malloc(0) must not return NULL!
  1515.    */
  1516.   if (size == 0) 
  1517.     size = 1;
  1518.  
  1519.   SET_KERNEL_FLAG;
  1520.   ret = pthread_realloc(ptr, size);
  1521.   CLEAR_KERNEL_FLAG;
  1522.   return(ret);
  1523. }
  1524.  
  1525. /*------------------------------------------------------------*/
  1526. malloc_t calloc (nmemb, elsize)
  1527.      size_t nmemb, elsize;
  1528. {
  1529.   malloc_t ret;
  1530.   extern char *pthread_calloc();
  1531.  
  1532.   /*
  1533.    * kludge: X malloc convention: for X, even malloc(0) must not return NULL!
  1534.    */
  1535.   if (elsize == 0) 
  1536.     elsize = 1;
  1537.   if (nmemb == 0)
  1538.     nmemb = 1;
  1539.  
  1540.   SET_KERNEL_FLAG;
  1541.   ret = pthread_calloc(nmemb, elsize);
  1542.   CLEAR_KERNEL_FLAG;
  1543.   return(ret);
  1544. }
  1545.  
  1546. /*------------------------------------------------------------*/
  1547. void cfree (ptr)
  1548.      malloc_t ptr;
  1549. {
  1550.   extern pthread_cfree();
  1551.  
  1552.   SET_KERNEL_FLAG;
  1553.   pthread_cfree(ptr);
  1554.   CLEAR_KERNEL_FLAG;
  1555. }
  1556.  
  1557. /*------------------------------------------------------------*/
  1558. malloc_t memalign(alignment, size)
  1559.      size_t alignment, size;
  1560. {
  1561.   malloc_t ret;
  1562.   extern char *pthread_memalign();
  1563.  
  1564.   SET_KERNEL_FLAG;
  1565.   ret = pthread_memalign(alignment, size);
  1566.   CLEAR_KERNEL_FLAG;
  1567.   return(ret);
  1568. }
  1569.  
  1570. /*------------------------------------------------------------*/
  1571. malloc_t valloc(size)
  1572.      size_t size;
  1573. {
  1574.   malloc_t ret;
  1575.   extern char *pthread_valloc();
  1576.  
  1577.   /*
  1578.    * kludge: X malloc convention: for X, even malloc(0) must not return NULL!
  1579.    */
  1580.   if (size == 0) 
  1581.     size = 1;
  1582.  
  1583.   SET_KERNEL_FLAG;
  1584.   ret = pthread_valloc(size);
  1585.   CLEAR_KERNEL_FLAG;
  1586.   return(ret);
  1587. }
  1588.  
  1589. #endif MALLOC
  1590.  
  1591. /*------------------------------------------------------------*/
  1592.  
  1593. #ifdef IO
  1594. /* foo - The following is intentionally dead code since foo is never called.
  1595.  * It ensures that the new versions of read and write are always linked in.
  1596.  */
  1597. static void pthread_dead_code()
  1598. {
  1599.   char *buf;
  1600.  
  1601.   READ(0, buf, 0);
  1602.   WRITE(1, buf, 0);
  1603. }
  1604. #endif IO
  1605.