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_disp.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  18KB  |  694 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_disp.c    2.5 4/12/95
  26.  
  27. */
  28.  
  29. #include "pthread_setjmp.h"
  30. #include "pthread_internals.h"
  31.  
  32. static int old_stack_ptr;
  33. static sigjmp_buf stack_env;
  34. static int status;
  35.  
  36. /*
  37.  * SWITCH_TO_STACK - macro to switch stacks
  38.  * CAUTION: Variables used across calls to this macro must be declared as static
  39.  */
  40. #define SWITCH_TO_STACK(new_sp, val) \
  41.   { \
  42.     static int ret; \
  43.     if (!(ret = sigsetjmp(stack_env, FALSE))) { \
  44.       ret = new_sp; \
  45.       old_stack_ptr = stack_env[JB_SP]; \
  46.       stack_env[JB_SP] = ret; \
  47.       siglongjmp(stack_env, (int) val); \
  48.     } \
  49.     val = (pthread_t) ret; \
  50.   }
  51.     
  52. #ifdef C_CONTEXT_SWITCH
  53. /*
  54.  * Context switch (preemptive), now coded in C instead of assembly
  55.  *
  56.  * Do NOT compile with -O3 or more. This file contains several signal
  57.  * handling routines which modify global data. Thus, the last optimization
  58.  * which is safe is -O2!
  59.  *
  60.  * Notice that functions within ifdef _ASM are still not to be
  61.  * compiled. The code of these functions simply serves as pseudo-
  62.  * code to better understand the assembly code.
  63.  *
  64.  * Portability notes:
  65.  * System calls to BSD routines have to be changed to SVR4.
  66.  * Some system calls (e.g. sigprocmask) are redefined by Pthreads.
  67.  * Thus, uses of sigsetmask cannot be replaced by sigprocmask
  68.  * but rather have to be translated into direct syscall()'s.
  69.  */
  70.  
  71. /*
  72.  * temporary stack for dispatcher, pthread_handle_many_process_signals,
  73.  * N nested function calls by pthread_handle_many_process_signals,
  74.  * a possible sigtramp and universal handler, plus 1 window spare
  75.  */
  76. KERNEL_STACK pthread_tempstack;
  77.  
  78. /*------------------------------------------------------------*/
  79. /* 
  80.  * pthread_sched - dispatcher
  81.  * assumes SET_KERNEL_FLAG
  82.  */
  83. void pthread_sched()
  84. {
  85.   static pthread_t old, new;
  86.   pthread_t pthread_sched_new_signals();
  87.   
  88.   old = mac_pthread_self();
  89.  
  90.   do {
  91.     if (old && old->state & T_RETURNED && old->state & T_DETACHED) {
  92.       SWITCH_TO_STACK(SA((int) pthread_tempstack_top) - SA(WINDOWSIZE), old);
  93. #ifdef MALLOC
  94.       pthread_free(old->stack_base);
  95.       pthread_free(old);
  96. #else !MALLOC
  97.       free(old->stack_base);
  98.       free(old);
  99. #endif MALLOC
  100.       mac_pthread_self() = old = NO_PTHREAD;
  101.     }
  102.     
  103.     if ((new = ready.head) == NO_PTHREAD ||
  104.     pthread_signonemptyset(&new_signals))
  105.       old = pthread_sched_new_signals(old, FALSE);
  106.   } while ((new = ready.head) == NO_PTHREAD ||
  107.        pthread_signonemptyset(&new_signals));
  108.  
  109.   mac_pthread_self() = new;
  110. #ifdef DEF_RR
  111.   if (new->attr.sched == SCHED_RR)
  112.     pthread_timed_sigwait(new, (struct timespec *) NULL, RR_TIME, NULL, new);
  113. #endif DEF_RR
  114.   
  115.   if (!pthread_not_called_from_sighandler(new->context[JB_PC]))
  116.     SIGPROCMASK(SIG_BLOCK, &all_signals, (struct sigset_t *) NULL);
  117.   
  118.   RESTORE_CONTEXT(new);
  119. }
  120.  
  121. /*------------------------------------------------------------*/
  122. /*
  123.  * pthread_sched_new_signals - handle signals which came in while inside
  124.  * the kernel by switching over to the temporary stack
  125.  */
  126. pthread_t pthread_sched_new_signals(p, masked)
  127.      pthread_t p;
  128.      int masked;
  129. {
  130.   static pthread_t old, new;
  131.   extern pthread_t pthread_handle_many_process_signals();
  132.  
  133.   old = p;
  134.  
  135.   if (masked && old && !pthread_not_called_from_sighandler(old->context[JB_PC]))
  136.     SIGPROCMASK(SIG_UNBLOCK, &all_signals, (struct sigset_t *) NULL);
  137.     
  138.   /*
  139.    * always flush windows before the stack is changed to preserve the proper
  140.    * linking of frame pointers
  141.    */
  142.   if (old)
  143.     SWITCH_TO_STACK(SA((int) pthread_tempstack_top) - SA(WINDOWSIZE), old);
  144.   new = pthread_handle_many_process_signals();
  145.   if (old)
  146.     SWITCH_TO_STACK(old_stack_ptr, new);
  147.  
  148.   return(new);
  149. }
  150.  
  151. /*------------------------------------------------------------*/
  152. /*
  153.  * pthread_sched_wrapper -
  154.  * assumes the following actions before/after call:
  155.  * PRE:  save errno(p);
  156.  * POST: restore errno(p);
  157.  */
  158. #ifdef C_CONTEXT_SWITCH
  159. void pthread_sched_wrapper(sig, code, p)
  160. int sig, code;
  161. pthread_t p;
  162. #else !C_CONTEXT_SWITCH
  163. void pthread_sched_wrapper(sig, code)
  164. int sig, code;
  165. #endif !C_CONTEXT_SWITCH
  166. {
  167.   void pthread_signal_sched();
  168.  
  169. #ifdef C_CONTEXT_SWITCH
  170.   if (!SAVE_CONTEXT(p))
  171. #endif C_CONTEXT_SWITCH
  172.     pthread_signal_sched(sig, code);
  173. }
  174.  
  175. /*------------------------------------------------------------*/
  176. /*
  177.  * pthread_not_called_from_sighandler -
  178.  * This routine must textually follow pthread_sched_wrapper!!!
  179.  */
  180. int pthread_not_called_from_sighandler(addr)
  181. int addr;
  182. {
  183.   return(addr < (int) pthread_sched_wrapper ||
  184.      addr >= (int) pthread_not_called_from_sighandler);
  185. }
  186.  
  187. /*
  188.  * NOTICE: THE FOLLOWING C CODE IS ONLY TO ANNOTATE THE CORRESPONDING
  189.  * ASSEMBLY CODE. THE C CODE DOES NOT COMPILE AND NEVER WILL!
  190.  */
  191. #ifdef _ASM
  192. /*------------------------------------------------------------*/
  193. /*
  194.  * pthread_test_and_set -
  195.  */
  196. int pthread_test_and_set(flag)
  197. int *flag;
  198. {
  199.   return(ldstub(flag));
  200. }
  201.  
  202. /*------------------------------------------------------------*/
  203. /*
  204.  * pthread_get_sp -
  205.  */
  206. char *pthread_get_sp()
  207. {
  208.   return(sp);
  209. }
  210.  
  211. /*------------------------------------------------------------*/
  212. /*
  213.  * pthread_set_sp -
  214.  */
  215. void pthread_set_sp(new_sp)
  216. char *new_sp;
  217. {
  218.   sp = new_sp;
  219. }
  220.  
  221. /*------------------------------------------------------------*/
  222. /*
  223.  * pthread_get_fp -
  224.  */
  225. char *pthread_get_fp()
  226. {
  227.   return(fp);
  228. }
  229.  
  230. /*------------------------------------------------------------*/
  231. /*
  232.  * pthread_set_fp -
  233.  */
  234. void pthread_set_fp(new_fp)
  235. char *new_fp;
  236. {
  237.   fp = new_fp;
  238. }
  239.  
  240. /*------------------------------------------------------------*/
  241. /*
  242.  * pthread_ST_FLUSH_WINDOWS -
  243.  */
  244. void pthread_ST_FLUSH_WINDOWS()
  245. {
  246.   ST_FLUSH_WINDOWS();
  247. }
  248. #endif _ASM
  249.  
  250. /*------------------------------------------------------------*/
  251. /*
  252.  * pthread_fake_call_wrapper_wrapper -
  253.  */
  254. void pthread_fake_call_wrapper_wrapper()
  255. {
  256.   pthread_t p = mac_pthread_self();
  257.   int sig = p->sig;
  258.   sigset_t smask;
  259.   struct context_t scp;
  260.   int new_context = p->nscp == (struct context_t *) DIRECTED_AT_THREAD;
  261.   void pthread_fake_call_wrapper();
  262.   extern struct sigaction pthread_user_handler[];
  263.  
  264.   if (new_context) {
  265.     pthread_sigcpyset2set(&scp.sc_mask, &p->mask);
  266.     scp.sc_sp = p->osp;
  267.     scp.sc_pc = p->opc;
  268.   }
  269.   pthread_sigcpyset2set(&smask, &p->mask);
  270.   pthread_sigcpyset2set(&p->mask, &pthread_user_handler[sig].sa_mask);
  271.   if (sig != -1)
  272.     sigaddset(&p->mask, sig);
  273.   pthread_fake_call_wrapper(sig == -1 ?
  274.                 pthread_exit : pthread_user_handler[sig].sa_handler,
  275.                 &smask,
  276.                 sig,
  277.                 &p->sig_info[sig == -1 ? 0 : sig],
  278.                 new_context ? &scp : p->nscp,
  279.                 new_context, p->scp, &p->cond);
  280. }
  281.  
  282. /*------------------------------------------------------------*/
  283. /*
  284.  * pthread_clear_kernel_flag_wrapper - after a fake call with modified pc in the
  285.  * context structure, return though this wrapper which clears the kernel
  286.  * flag before jumping into user code.
  287.  */
  288. void pthread_clear_kernel_flag_wrapper()
  289. {
  290.   register pthread_t p = mac_pthread_self();
  291.   register int osp = p->osp;
  292.   register int opc = p->opc;
  293.  
  294.   CLEAR_KERNEL_FLAG;
  295.  
  296.   p->context[JB_SP] = osp;
  297.   p->context[JB_PC] = opc;
  298.   RESTORE_CONTEXT(p);
  299. }
  300.  
  301. /*------------------------------------------------------------*/
  302. /*
  303.  * pthread_fake_call_wrapper - invoke a fake call on a thread's stack
  304.  * fake_call already puts the address of a user-defined handler
  305.  * in %i0, the signal mask (to be restored) in %i1, and a flag
  306.  * restore_context in %i5 which indicates if the context has to be
  307.  * copied back by the wrapper (o.w. it is done by UNIX).
  308.  * It calls the user handler with parameters sig, infop, scp.
  309.  * Notice that the address of the condition variable is
  310.  * passed on stack if the signal came in during a conditional wait.
  311.  * In this case, the conditional wait terminates and the mutex is relocked
  312.  * before the user handler is called. This is only done once for
  313.  * nested handlers by the innermost handler (see check for zero-value
  314.  * of the condition variable).
  315.  * Notice that oscp is passed on stack and is restored as p->nscp
  316.  * upon return from the wrapper.
  317.  * The errno is saved across the user handler call.
  318.  * assumes SET_KERNEL_FLAG still set from context switch after pushing fake call
  319.  */
  320. void pthread_fake_call_wrapper(user_handler, smask, sig, infop, scp,
  321.                                restore_context, oscp, cond)
  322.      void (*user_handler)();
  323.      sigset_t *smask;
  324.      int sig;
  325.      struct siginfo *infop;
  326.      struct context_t *scp;
  327.      int restore_context;
  328.      struct context_t *oscp;
  329.      pthread_cond_t **cond;
  330. {
  331.   register pthread_t p = mac_pthread_self();
  332.   sigset_t omask;
  333.   register int saved_errno = errno;
  334.   register struct frame *framep;
  335.   register int old_pc = scp->sc_pc;
  336.   register int old_sp = scp->sc_sp;
  337.   register int new_sp = p->osp;
  338.   register int new_pc = p->opc;
  339.   void pthread_handle_pending_signals_wrapper();
  340.  
  341.   pthread_sigcpyset2set(&omask, &scp->sc_mask);
  342.  
  343.   if (*cond)
  344.     pthread_cond_wait_terminate();
  345.  
  346.   CLEAR_KERNEL_FLAG;
  347.   (*user_handler)(sig, infop, scp);
  348.   SET_KERNEL_FLAG;
  349.  
  350.   errno = saved_errno;
  351.  
  352.   if (restore_context) {
  353.     if (old_pc != scp->sc_pc) {
  354.       p->context[JB_SP] = old_sp;
  355.       p->context[JB_PC] = (int) pthread_clear_kernel_flag_wrapper;
  356.       new_sp = scp->sc_sp;
  357.       new_pc = scp->sc_pc;
  358. #ifdef ASM_SETJMP
  359.       new_pc -= RETURN_OFFSET;
  360. #endif ASM_SETMP
  361.     }
  362.     else {
  363.       p->context[JB_SP] = scp->sc_sp;
  364.       p->context[JB_PC] = scp->sc_pc;
  365.     }
  366. #ifdef ASM_SETJMP
  367.     p->context[JB_PC] -= RETURN_OFFSET;
  368. #endif ASM_SETMP
  369.     pthread_sigcpyset2set(smask, &scp->sc_mask);
  370.   }
  371.   else {
  372.     pthread_sigcpyset2set(smask, &scp->sc_mask);
  373.     pthread_sigcpyset2set(&scp->sc_mask, &omask);
  374.   }
  375.  
  376.   pthread_sigcpyset2set(&p->mask, smask);
  377.  
  378.   pthread_sigcpyset2set(smask, &p->pending);
  379.   pthread_sigaddset2set(smask, &pending_signals);
  380.   pthread_sigdelset2set(smask, &p->mask);
  381.  
  382.   p->errno = errno;
  383.  
  384.   if (restore_context) {
  385.     old_sp = p->context[JB_SP];
  386.     old_pc = p->context[JB_PC];
  387.   }
  388.  
  389.   if (pthread_signonemptyset(smask))
  390.     if (!SAVE_CONTEXT(p))
  391.       pthread_handle_pending_signals_wrapper();
  392.       /* never returns from call */
  393.     else if (restore_context) {
  394.       p->context[JB_SP] = old_sp;
  395.       p->context[JB_PC] = old_pc;
  396.     }
  397.  
  398.   p->nscp = oscp;
  399.  
  400.   if (restore_context) {
  401.     p->osp = new_sp;
  402.     p->opc = new_pc;
  403.   }
  404.   else {
  405.     p->context[JB_SP] = new_sp;
  406.     p->context[JB_PC] = new_pc;
  407. #ifdef ASM_SETJMP
  408.     p->context[JB_PC] -= RETURN_OFFSET;
  409. #endif ASM_SETJMP
  410.   }
  411.  
  412.   pthread_sched();
  413.   /* never returns from call */
  414. }
  415.           
  416. /*------------------------------------------------------------*/
  417. /*
  418.  * pthread_handle_pending_signals_wrapper - 
  419.  * change to temp stack and call pthread_handle_pending_signals()
  420.  * then jumps into regular scheduler
  421.  * assumes SET_KERNEL_FLAG
  422.  */
  423. void pthread_handle_pending_signals_wrapper()
  424. {
  425.   static pthread_t old;
  426.  
  427.   old = mac_pthread_self();
  428.  
  429.   /*
  430.    * always flush windows before the stack is changed to preserve the proper
  431.    * linking of frame pointers
  432.    */
  433.   SWITCH_TO_STACK(SA((int) pthread_tempstack_top) - SA(WINDOWSIZE), old);
  434.   pthread_handle_pending_signals();
  435.   SWITCH_TO_STACK(old_stack_ptr, old);
  436.  
  437.   pthread_sched();
  438.   /* never returns from call */
  439. }
  440.  
  441. /*------------------------------------------------------------*/
  442. /*
  443.  * pthread_signal_sched - 
  444.  * change to temp stack and call pthread_handle_one_process_signal(sig)
  445.  * then jumps into regular scheduler
  446.  * This is called by the universal signal handler to minimize calls
  447.  * to set the process mask which is an expensive UNIX system call.
  448.  * assumes SET_KERNEL_FLAG
  449.  */
  450. void pthread_signal_sched(sig, code)
  451.      int sig, code;
  452. {
  453.   static pthread_t old;
  454.  
  455.   old = mac_pthread_self();
  456.   old->sig = sig;
  457.   old->code = code;
  458.  
  459.   /*
  460.    * always flush windows before the stack is changed to preserve the proper
  461.    * linking of frame pointers
  462.    */
  463.   SWITCH_TO_STACK(SA((int) pthread_tempstack_top) - SA(WINDOWSIZE), old);
  464.   pthread_handle_one_process_signal(old->sig, old->code);
  465.   SWITCH_TO_STACK(old_stack_ptr, old);
  466.   
  467.   pthread_sched();
  468.   /* never returns from call */
  469. }
  470.   
  471. #ifdef _ASM
  472. /*------------------------------------------------------------*/
  473. /*
  474.  * setjmp - 
  475.  */
  476. int setjmp(env)
  477.      jmp_buf env;
  478. {
  479.   return(sigsetjmp(env, TRUE));
  480. }
  481.  
  482. /*------------------------------------------------------------*/
  483. /*
  484.  * longjmp - 
  485.  */
  486. void longjmp(env, val)
  487.      jmp_buf env;
  488.      int val;
  489. {
  490.   siglongjmp(env, val);
  491. }
  492.  
  493. /*------------------------------------------------------------*/
  494. /*
  495.  * sigsetjmp - 
  496.  */
  497. int sigsetjmp(env, savemask)
  498.      sigjmp_buf env;
  499.      int savemask;
  500. {
  501.   env[JB_SP] = sp;
  502.   env[JB_PC] = pc;
  503.   env[JB_SVMASK] = savemask;
  504.   if (env[JB_SVMASK])
  505.     pthread_sigcpyset2set(&env[JB_MASK], &mac_pthread_self()->mask);
  506.   return(0);
  507. }
  508.  
  509. /*------------------------------------------------------------*/
  510. /*
  511.  * siglongjmp - 
  512.  */
  513. void siglongjmp(env, val)
  514.      sigjmp_buf env;
  515.      int val;
  516. {
  517.   int new_sp;
  518.  
  519.   if (env[JB_SVMASK])
  520.     sigprocmask(SIG_SETMASK, &env[SV_MASK], (struct sigaction *) NULL);
  521.   ST_FLUSH_WINDOWS();
  522.   fp = env[JB_SP];
  523.   pc = env[JB_PC];
  524.   if (val == 0)
  525.     val = 1;
  526.   ret;
  527. }
  528.  
  529. #ifdef NOERR_CHECK
  530. /*------------------------------------------------------------*/
  531. /*
  532.  * pthread_mutex_lock - 
  533.  */
  534. int pthread_mutex_lock(mutex)
  535.      pthread_mutex_t *mutex;
  536. {
  537. #ifdef _POSIX_THREADS_PRIO_PROTECT
  538.   if (mutex->protocol == PRIO_PROTECT)
  539.     goto slow_lock;
  540. #endif
  541.   if (test_and_set(&mutex->lock)) {
  542.     mutex->owner = mac_pthread_self();
  543.     return(0);
  544.   }
  545.   /*
  546.    * if the queue is not empty or if someone holds the mutex,
  547.    * we need to enter the kernel to queue up.
  548.    */
  549. #ifdef _POSIX_THREADS_PRIO_PROTECT
  550. slow_lock:
  551. #endif
  552.   return(slow_mutex_lock(mutex));
  553. }
  554.  
  555. /*------------------------------------------------------------*/
  556. /*
  557.  * pthread_mutex_trylock - 
  558.  */
  559. int pthread_mutex_trylock(mutex)
  560.      pthread_mutex_t *mutex;
  561. {
  562. #ifdef _POSIX_THREADS_PRIO_PROTECT
  563.   if (mutex->protocol == PRIO_PROTECT)
  564.     return slow_mutex_trylock(mutex);
  565. #endif
  566.   if (test_and_set(&mutex->lock)) {
  567.     mutex->owner = mac_pthread_self();
  568.     set_errno(EBUSY);
  569.     return(-1);
  570.   }
  571.   return(0);
  572. }
  573.  
  574. /*------------------------------------------------------------*/
  575. /*
  576.  * pthread_mutex_unlock - 
  577.  */
  578. int pthread_mutex_unlock(mutex)
  579.      pthread_mutex_t *mutex;
  580. {
  581.  
  582. #ifdef _POSIX_THREADS_PRIO_PROTECT
  583.   if (mutex->protocol == PRIO_PROTECT)
  584.     goto slow_unlock;
  585. #endif
  586.  
  587.   mutex->owner = NO_PTHREAD;
  588.   if (mutex->queue.head == NULL) {
  589.     mutex->lock = FALSE;
  590.     /*
  591.      * We have to test the queue again since there is a window
  592.      * between the previous test and the unlocking of the mutex
  593.      * where someone could have queued up.
  594.      */
  595.     if (mutex->queue.head == NULL)
  596.       return(0);
  597.     if (test_and_set(&mutex->lock))
  598.       /*
  599.        * if the test & set is not successful, someone else must
  600.        * have acquired the mutex and will handle proper queueing,
  601.        * so we're done.
  602.        */
  603.       return(0);
  604.   }
  605.   /*
  606.    * if the queue is not empty, we need to enter the kernel to unqueue.
  607.    */
  608. #ifdef _POSIX_THREADS_PRIO_PROTECT
  609. slow_unlock:
  610. #endif
  611.   return(slow_mutex_unlock(mutex));
  612. }
  613. #endif NOERR_CHECK
  614.  
  615. #ifndef CLEANUP_HEAP
  616. /*------------------------------------------------------------*/
  617. /*
  618.  * pthread_cleanup_push - 
  619.  */
  620. int pthread_cleanup_push(func, arg)
  621.      pthread_func_t func;
  622.      any_t arg;
  623. {
  624.   cleanup_t *new;
  625.  
  626. #ifndef C_INTERFACE
  627.   sp -= SA(sizeof(*new)+SA(MINFRAME)-WINDOWSIZE);
  628. #else
  629.   sp -= SA(sizeof(*new));
  630. #endif
  631.   new = sp + SA(MINFRAME);
  632.   pthread_cleanup_push_body(func, arg, new);
  633. }
  634.  
  635. /*------------------------------------------------------------*/
  636. /*
  637.  * pthread_cleanup_pop - 
  638.  */
  639. int pthread_cleanup_pop(execute)
  640.      int execute;
  641. {
  642.   pthread_cleanup_pop_body(execute);
  643. #ifndef C_INTERFACE
  644.   sp += SA(sizeof(*new)+SA(MINFRAME)-WINDOWSIZE);
  645. #else
  646.   sp += SA(sizeof(*new));
  647. #endif
  648. }
  649. #endif !CLEANUP_HEAP
  650.  
  651. #ifndef SOLARIS
  652. /*------------------------------------------------------------*/
  653. /*
  654.  * start_float -
  655.  */
  656. void start_float()
  657. {
  658.   pthread_init();
  659. }
  660. #endif !SOLARIS
  661. #endif _ASM
  662. #endif C_CONTEXT_SWITCH
  663.  
  664. /*------------------------------------------------------------*/
  665. /*
  666.  * pthread_process_exit - switches stacks to process stack and
  667.  * calls UNIX exit with parameter status
  668.  */
  669. static void process_exit()
  670. {
  671.   CLEAR_KERNEL_FLAG;
  672.   exit((int) status);
  673. }
  674.  
  675. /*------------------------------------------------------------*/
  676. /*
  677.  * pthread_process_exit - switches stacks to process stack and
  678.  * calls UNIX exit with parameter status
  679.  */
  680. void pthread_process_exit(p_status)
  681.      int p_status;
  682. {
  683.   status = p_status;
  684.  
  685.   /*
  686.    * always flush windows before the stack is changed to preserve the proper
  687.    * linking of frame pointers
  688.    */
  689.   sigsetjmp(stack_env, FALSE);
  690.   stack_env[JB_SP] = (int) process_stack_base;
  691.   stack_env[JB_PC] = (int) process_exit - RETURN_OFFSET;
  692.   siglongjmp(stack_env, p_status);
  693. }
  694.