48bc9884f2b0f60f2625458b8adc55e74daf68b7
[openafs.git] / src / lwp / lwp.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*******************************************************************\
11 *                                                                   *
12 *       Information Technology Center                               *
13 *       Carnegie-Mellon University                                  *
14 *                                                                   *
15 \*******************************************************************/
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20 RCSID("$Header$");
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <time.h>
25
26 /* allocate externs here */
27 #define  LWP_KERNEL
28 #include "lwp.h"
29 #ifdef  AFS_AIX32_ENV
30 #include <ulimit.h>
31 #include <sys/errno.h>
32 #include <sys/user.h>
33 #include <sys/pseg.h>
34 #include <sys/core.h>
35 #pragma alloca
36 #endif
37 #ifdef AFS_SGI64_ENV
38 extern char *getenv();
39 #include <time.h>
40 #endif
41 #ifdef HAVE_STRING_H
42 #include <string.h>
43 #else
44 #ifdef HAVE_STRINGS_H
45 #include <strings.h>
46 #endif
47 #endif
48
49 #if     !defined(USE_PTHREADS) && !defined(USE_SOLARIS_THREADS)
50
51 #ifdef  AFS_OSF_ENV
52 extern void *malloc(int size);
53 extern void *realloc(void *ptr, int size);
54 #endif
55 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
56 extern int PRE_Block;           /* from preempt.c */
57 #else
58 extern char PRE_Block;          /* from preempt.c */
59 #endif
60
61 #define ON              1
62 #define OFF             0
63 #define TRUE            1
64 #define FALSE           0
65 #define READY           2
66 #define WAITING         3
67 #define DESTROYED       4
68 #define QWAITING        5
69 #define MAXINT     (~(1<<((sizeof(int)*8)-1)))
70 #define MINSTACK   44
71
72 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
73 #define MINFRAME 128
74 #define STACK_ALIGN 8
75 #else
76 #ifdef __s390__
77 #define MINFRAME    96
78 #define STACK_ALIGN 8
79 #else
80 #define STACK_ALIGN 4
81 #endif
82 #endif
83
84 /* Debugging macro */
85 #ifdef DEBUG
86 #define Debug(level, msg) do {                                          \
87     if (lwp_debug && lwp_debug >= level) {                              \
88         printf("***LWP (0x%x): ", lwp_cpptr);                           \
89         printf msg;                                                     \
90         putchar('\n');                                                  \
91     }                                                                   \
92 } while (0)
93 #else
94 #define Debug(level, msg) do {                                          \
95     ;                                                                   \
96 } while (0)
97 #endif
98 \f
99 static int Dispatcher();
100 static int Create_Process_Part2();
101 static int Exit_LWP();
102 static afs_int32 Initialize_Stack();
103 static int Stack_Used();
104 char (*RC_to_ASCII());
105
106 static void Abort_LWP();
107 static void Overflow_Complain();
108 static void Initialize_PCB();
109 static void Dispose_of_Dead_PCB();
110 static void Free_PCB();
111 static int Internal_Signal();
112 static purge_dead_pcbs();
113
114 #define MAX_PRIORITIES  (LWP_MAX_PRIORITY+1)
115
116 struct QUEUE {
117     PROCESS head;
118     int count;
119 } runnable[MAX_PRIORITIES], blocked, qwaiting;
120 /* Invariant for runnable queues: The head of each queue points to the currently running process if it is in that queue, or it points to the next process in that queue that should run. */
121
122 /* Offset of stack field within pcb -- used by stack checking stuff */
123 int stack_offset;
124
125 /* special user-tweakable option for AIX */
126 int lwp_MaxStackSize = 32768;
127
128 /* biggest LWP stack created so far */
129 int lwp_MaxStackSeen = 0;
130
131 /* Stack checking action */
132 int lwp_overflowAction = LWP_SOABORT;
133
134 /* Controls stack size counting. */
135 int lwp_stackUseEnabled = TRUE; /* pay the price */
136
137 int lwp_nextindex;
138
139 /* Minimum stack size */
140 int lwp_MinStackSize = 0;
141
142 static int
143 lwp_remove(p, q)
144      register PROCESS p;
145      register struct QUEUE *q;
146 {
147     /* Special test for only element on queue */
148     if (q->count == 1)
149         q->head = NULL;
150     else {
151         /* Not only element, do normal remove */
152         p->next->prev = p->prev;
153         p->prev->next = p->next;
154     }
155     /* See if head pointing to this element */
156     if (q->head == p)
157         q->head = p->next;
158     q->count--;
159     p->next = p->prev = NULL;
160     return 0;
161 }
162
163 static int
164 insert(p, q)
165      register PROCESS p;
166      register struct QUEUE *q;
167 {
168     if (q->head == NULL) {      /* Queue is empty */
169         q->head = p;
170         p->next = p->prev = p;
171     } else {                    /* Regular insert */
172         p->prev = q->head->prev;
173         q->head->prev->next = p;
174         q->head->prev = p;
175         p->next = q->head;
176     }
177     q->count++;
178     return 0;
179 }
180
181 static int
182 move(p, from, to)
183      PROCESS p;
184      struct QUEUE *from, *to;
185 {
186
187     lwp_remove(p, from);
188
189     insert(p, to);
190     return 0;
191 }
192
193 /* Iterator macro */
194 #define for_all_elts(var, q, body)\
195         {\
196             register PROCESS var, _NEXT_;\
197             register int _I_;\
198             for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
199                 _NEXT_ = var -> next;\
200                 body\
201             }\
202         }
203 \f
204 /*                                                                          */
205 /*****************************************************************************\
206 *                                                                             *
207 *  Following section documents the Assembler interfaces used by LWP code      *
208 *                                                                             *
209 \*****************************************************************************/
210
211 /*
212         savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
213
214 Stub for Assembler routine that will
215 save the current SP value in the passed
216 context savearea and call the function
217 whose entry point is in ep.  If the sp
218 parameter is NULL, the current stack is
219 used, otherwise sp becomes the new stack
220 pointer.
221
222         returnto(struct lwp_context *savearea);
223
224 Stub for Assembler routine that will
225 restore context from a passed savearea
226 and return to the restored C frame.
227
228 */
229
230 /* Macro to force a re-schedule.  Strange name is historical */
231 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
232
233 static struct lwp_ctl *lwp_init = 0;
234
235 int
236 LWP_QWait(void)
237 {
238     register PROCESS tp;
239     (tp = lwp_cpptr)->status = QWAITING;
240     move(tp, &runnable[tp->priority], qwaiting);
241     Set_LWP_RC();
242     return LWP_SUCCESS;
243 }
244
245 int
246 LWP_QSignal(pid)
247      register PROCESS pid;
248 {
249     if (pid->status == QWAITING) {
250         pid->status = READY;
251         move(pid, qwaiting, &runnable[pid->priority]);
252         return LWP_SUCCESS;
253     } else
254         return LWP_ENOWAIT;
255 }
256
257 #ifdef  AFS_AIX32_ENV
258 char *
259 reserveFromStack(register afs_int32 size)
260 {
261     char *x;
262     x = alloca(size);
263     return x;
264 }
265 #endif
266
267 int
268 LWP_CreateProcess(int (*ep) (), int stacksize, int priority, void *parm,
269                   char *name, PROCESS * pid)
270 {
271     PROCESS temp, temp2;
272 #ifdef  AFS_AIX32_ENV
273     static char *stackptr = 0;
274 #else
275     char *stackptr;
276 #endif
277
278 #if defined(AFS_LWP_MINSTACKSIZE)
279     /*
280      * on some systems (e.g. hpux), a minimum usable stack size has
281      * been discovered
282      */
283     if (stacksize < lwp_MinStackSize) {
284         stacksize = lwp_MinStackSize;
285     }
286 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
287     /* more stack size computations; keep track of for IOMGR */
288     if (lwp_MaxStackSeen < stacksize)
289         lwp_MaxStackSeen = stacksize;
290
291     Debug(0, ("Entered LWP_CreateProcess"));
292     /* Throw away all dead process control blocks */
293     purge_dead_pcbs();
294     if (lwp_init) {
295         temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
296         if (temp == NULL) {
297             Set_LWP_RC();
298             return LWP_ENOMEM;
299         }
300         if (stacksize < MINSTACK)
301             stacksize = 1000;
302         else
303             stacksize =
304                 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
305 #ifdef  AFS_AIX32_ENV
306         if (!stackptr) {
307             /*
308              * The following signal action for AIX is necessary so that in case of a 
309              * crash (i.e. core is generated) we can include the user's data section 
310              * in the core dump. Unfortunately, by default, only a partial core is
311              * generated which, in many cases, isn't too useful.
312              *
313              * We also do it here in case the main program forgets to do it.
314              */
315             struct sigaction nsa;
316             extern uid_t geteuid();
317
318             sigemptyset(&nsa.sa_mask);
319             nsa.sa_handler = SIG_DFL;
320             nsa.sa_flags = SA_FULLDUMP;
321             sigaction(SIGABRT, &nsa, NULL);
322             sigaction(SIGSEGV, &nsa, NULL);
323
324             /*
325              * First we need to increase the default resource limits,
326              * if necessary, so that we can guarantee that we have the
327              * resources to create the core file, but we can't always 
328              * do it as an ordinary user.
329              */
330             if (!geteuid()) {
331                 /* vos dump causes problems */
332                 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
333                 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
334                 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
335             }
336             /*
337              * Now reserve in one scoop all the stack space that will be used
338              * by the particular application's main (i.e. non-lwp) body. This
339              * is plenty space for any of our applications.
340              */
341             stackptr = reserveFromStack(lwp_MaxStackSize);
342         }
343         stackptr -= stacksize;
344 #else
345         if ((stackptr = (char *)malloc(stacksize + 7)) == NULL) {
346             Set_LWP_RC();
347             return LWP_ENOMEM;
348         }
349         /* Round stack pointer to byte boundary */
350         stackptr = (char *)(8 * (((long)stackptr + 7) / 8));
351 #endif
352         if (priority < 0 || priority >= MAX_PRIORITIES) {
353             Set_LWP_RC();
354             return LWP_EBADPRI;
355         }
356         Initialize_Stack(stackptr, stacksize);
357         Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
358         insert(temp, &runnable[priority]);
359         temp2 = lwp_cpptr;
360         if (PRE_Block != 0)
361             Abort_LWP("PRE_Block not 0");
362
363         /* Gross hack: beware! */
364         PRE_Block = 1;
365         lwp_cpptr = temp;
366 #if defined(AFS_PARISC_LINUX24_ENV)
367         savecontext(Create_Process_Part2, &temp2->context,
368                     stackptr + MINFRAME);
369 #else
370 #ifdef __hp9000s800
371         savecontext(Create_Process_Part2, &temp2->context,
372                     stackptr + MINFRAME);
373 #else
374 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
375         /* Need to have the sp on an 8-byte boundary for storing doubles. */
376         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16);  /* 16 = 2 * jmp_buf_type */
377 #else
378 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
379         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40);        /* lomgjmp does something
380                                                                                                  * with %fp + 0x38 */
381 #else
382 #if defined(AFS_S390_LINUX20_ENV)
383         savecontext(Create_Process_Part2, &temp2->context,
384                     stackptr + stacksize - MINFRAME);
385 #else /* !AFS_S390_LINUX20_ENV */
386         savecontext(Create_Process_Part2, &temp2->context,
387                     stackptr + stacksize - sizeof(void *));
388 #endif /* AFS_S390_LINUX20_ENV */
389 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
390 #endif /* AFS_SGI62_ENV */
391 #endif
392 #endif
393         /* End of gross hack */
394
395         Set_LWP_RC();
396         *pid = temp;
397         return 0;
398     } else
399         return LWP_EINIT;
400 }
401
402 #ifdef  AFS_AIX32_ENV
403 int
404 LWP_CreateProcess2(int (*ep) (), int stacksize, int priority, void *parm,
405                    char *name, PROCESS * pid)
406 {
407     PROCESS temp, temp2;
408     char *stackptr;
409
410 #if defined(AFS_LWP_MINSTACKSIZE)
411     /*
412      * on some systems (e.g. hpux), a minimum usable stack size has
413      * been discovered
414      */
415     if (stacksize < lwp_MinStackSize) {
416         stacksize = lwp_MinStackSize;
417     }
418 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
419     /* more stack size computations; keep track of for IOMGR */
420     if (lwp_MaxStackSeen < stacksize)
421         lwp_MaxStackSeen = stacksize;
422
423     Debug(0, ("Entered LWP_CreateProcess"));
424     /* Throw away all dead process control blocks */
425     purge_dead_pcbs();
426     if (lwp_init) {
427         temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
428         if (temp == NULL) {
429             Set_LWP_RC();
430             return LWP_ENOMEM;
431         }
432         if (stacksize < MINSTACK)
433             stacksize = 1000;
434         else
435             stacksize =
436                 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
437         if ((stackptr = (char *)malloc(stacksize)) == NULL) {
438             Set_LWP_RC();
439             return LWP_ENOMEM;
440         }
441         if (priority < 0 || priority >= MAX_PRIORITIES) {
442             Set_LWP_RC();
443             return LWP_EBADPRI;
444         }
445         Initialize_Stack(stackptr, stacksize);
446         Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
447         insert(temp, &runnable[priority]);
448         temp2 = lwp_cpptr;
449         if (PRE_Block != 0)
450             Abort_LWP("PRE_Block not 0");
451
452         /* Gross hack: beware! */
453         PRE_Block = 1;
454         lwp_cpptr = temp;
455         savecontext(Create_Process_Part2, &temp2->context,
456                     stackptr + stacksize - sizeof(void *));
457         /* End of gross hack */
458
459         Set_LWP_RC();
460         *pid = temp;
461         return 0;
462     } else
463         return LWP_EINIT;
464 }
465 #endif
466
467 int
468 LWP_CurrentProcess(PROCESS * pid)
469 {                               /* returns pid of current process */
470     Debug(0, ("Entered Current_Process"));
471     if (lwp_init) {
472         *pid = lwp_cpptr;
473         return LWP_SUCCESS;
474     } else
475         return LWP_EINIT;
476 }
477
478 PROCESS
479 LWP_ThreadId(void)
480 {
481     Debug(0, ("Entered ThreadId"));
482     if (lwp_init)
483         return lwp_cpptr;
484     else
485         return (PROCESS) 0;
486 }
487
488 #define LWPANCHOR (*lwp_init)
489
490 int
491 LWP_DestroyProcess(PROCESS pid)
492 {                               /* destroy a lightweight process */
493     PROCESS temp;
494
495     Debug(0, ("Entered Destroy_Process"));
496     if (lwp_init) {
497         if (lwp_cpptr != pid) {
498             Dispose_of_Dead_PCB(pid);
499             Set_LWP_RC();
500         } else {
501             pid->status = DESTROYED;
502             move(pid, &runnable[pid->priority], &blocked);
503             temp = lwp_cpptr;
504 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
505             savecontext(Dispatcher, &(temp->context),
506                         &(LWPANCHOR.dsptchstack[MINFRAME]));
507 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
508             savecontext(Dispatcher, &(temp->context),
509                         &(LWPANCHOR.
510                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
511 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
512             savecontext(Dispatcher, &(temp->context),
513                         &(LWPANCHOR.
514                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
515                                       0x40]));
516 #elif defined(AFS_S390_LINUX20_ENV)
517             savecontext(Dispatcher, &(temp->context),
518                         &(LWPANCHOR.
519                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
520                                       MINFRAME]));
521 #else
522             savecontext(Dispatcher, &(temp->context),
523                         &(LWPANCHOR.
524                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
525                                       sizeof(void *)]));
526 #endif
527         }
528         return LWP_SUCCESS;
529     } else
530         return LWP_EINIT;
531 }
532
533 int
534 LWP_DispatchProcess(void)
535 {                               /* explicit voluntary preemption */
536     Debug(2, ("Entered Dispatch_Process"));
537     if (lwp_init) {
538         Set_LWP_RC();
539         return LWP_SUCCESS;
540     } else
541         return LWP_EINIT;
542 }
543
544 #ifdef DEBUG
545 int
546 Dump_Processes(void)
547 {
548     if (lwp_init) {
549         register int i;
550         for (i = 0; i < MAX_PRIORITIES; i++)
551             for_all_elts(x, runnable[i], {
552                          printf("[Priority %d]\n", i);
553                          Dump_One_Process(x);
554                          }
555         )
556             for_all_elts(x, blocked, {
557                          Dump_One_Process(x);}
558         )
559             for_all_elts(x, qwaiting, {
560                          Dump_One_Process(x);}
561         )
562     } else
563         printf("***LWP: LWP support not initialized\n");
564     return 0;
565 }
566 #endif
567
568 int
569 LWP_GetProcessPriority(PROCESS pid, int *priority)
570 {                               /* returns process priority */
571     Debug(0, ("Entered Get_Process_Priority"));
572     if (lwp_init) {
573         *priority = pid->priority;
574         return 0;
575     } else
576         return LWP_EINIT;
577 }
578
579 int
580 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
581 {
582     PROCESS temp;
583     struct lwp_pcb dummy;
584     register int i;
585     char *value;
586
587     Debug(0, ("Entered LWP_InitializeProcessSupport"));
588     if (lwp_init != NULL)
589         return LWP_SUCCESS;
590
591     /* Set up offset for stack checking -- do this as soon as possible */
592     stack_offset = (char *)&dummy.stack - (char *)&dummy;
593
594     if (priority >= MAX_PRIORITIES)
595         return LWP_EBADPRI;
596     for (i = 0; i < MAX_PRIORITIES; i++) {
597         runnable[i].head = NULL;
598         runnable[i].count = 0;
599     }
600     blocked.head = NULL;
601     blocked.count = 0;
602     qwaiting.head = NULL;
603     qwaiting.count = 0;
604     lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
605     temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
606     if (lwp_init == NULL || temp == NULL)
607         Abort_LWP("Insufficient Storage to Initialize LWP Support");
608     LWPANCHOR.processcnt = 1;
609     LWPANCHOR.outerpid = temp;
610     LWPANCHOR.outersp = NULL;
611     Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
612                    "Main Process [created by LWP]");
613     insert(temp, &runnable[priority]);
614     savecontext(Dispatcher, &temp->context, NULL);
615     LWPANCHOR.outersp = temp->context.topstack;
616     Set_LWP_RC();
617     *pid = temp;
618
619     /* get minimum stack size from the environment. this allows the  administrator
620      * to change the lwp stack dynamically without getting a new binary version.
621      */
622     if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
623         lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
624     else
625         lwp_MinStackSize =
626             (AFS_LWP_MINSTACKSIZE >
627              atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
628
629     return LWP_SUCCESS;
630 }
631
632 int
633 LWP_INTERNALSIGNAL(char *event, int yield)
634 {                               /* signal the occurence of an event */
635     Debug(2, ("Entered LWP_SignalProcess"));
636     if (lwp_init) {
637         int rc;
638         rc = Internal_Signal(event);
639         if (yield)
640             Set_LWP_RC();
641         return rc;
642     } else
643         return LWP_EINIT;
644 }
645
646 int
647 LWP_TerminateProcessSupport(void)
648 {                               /* terminate all LWP support */
649     register int i;
650
651     Debug(0, ("Entered Terminate_Process_Support"));
652     if (lwp_init == NULL)
653         return LWP_EINIT;
654     if (lwp_cpptr != LWPANCHOR.outerpid)
655         Abort_LWP("Terminate_Process_Support invoked from wrong process!");
656     for (i = 0; i < MAX_PRIORITIES; i++)
657         for_all_elts(cur, runnable[i], {
658                      Free_PCB(cur);}
659     )
660         for_all_elts(cur, blocked, {
661                      Free_PCB(cur);}
662     )
663         for_all_elts(cur, qwaiting, {
664                      Free_PCB(cur);}
665     )
666         free(lwp_init);
667     lwp_init = NULL;
668     return LWP_SUCCESS;
669 }
670
671 int
672 LWP_WaitProcess(char *event)
673 {                               /* wait on a single event */
674     char *tempev[2];
675
676     Debug(2, ("Entered Wait_Process"));
677     if (event == NULL)
678         return LWP_EBADEVENT;
679     tempev[0] = event;
680     tempev[1] = NULL;
681     return LWP_MwaitProcess(1, tempev);
682 }
683
684 int
685 LWP_MwaitProcess(int wcount, char *evlist[])
686 {                               /* wait on m of n events */
687     register int ecount, i;
688
689
690     Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
691
692     if (evlist == NULL) {
693         Set_LWP_RC();
694         return LWP_EBADCOUNT;
695     }
696
697     for (ecount = 0; evlist[ecount] != NULL; ecount++);
698
699     if (ecount == 0) {
700         Set_LWP_RC();
701         return LWP_EBADCOUNT;
702     }
703
704     if (lwp_init) {
705
706         if (wcount > ecount || wcount < 0) {
707             Set_LWP_RC();
708             return LWP_EBADCOUNT;
709         }
710         if (ecount > lwp_cpptr->eventlistsize) {
711
712             lwp_cpptr->eventlist =
713                 (char **)realloc(lwp_cpptr->eventlist,
714                                  ecount * sizeof(char *));
715             lwp_cpptr->eventlistsize = ecount;
716         }
717         for (i = 0; i < ecount; i++)
718             lwp_cpptr->eventlist[i] = evlist[i];
719         if (wcount > 0) {
720             lwp_cpptr->status = WAITING;
721
722             move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
723
724         }
725         lwp_cpptr->wakevent = 0;
726         lwp_cpptr->waitcnt = wcount;
727         lwp_cpptr->eventcnt = ecount;
728
729         Set_LWP_RC();
730
731         return LWP_SUCCESS;
732     }
733
734     return LWP_EINIT;
735 }
736
737 int
738 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
739 {
740     *maxa = pid->stacksize;
741     *used = Stack_Used(pid->stack, *maxa);
742     if (*used == 0)
743         return LWP_NO_STACK;
744     return LWP_SUCCESS;
745 }
746 \f
747 /*
748  *  The following functions are strictly
749  *  INTERNAL to the LWP support package.
750  */
751
752 static void
753 Abort_LWP(char *msg)
754 {
755     struct lwp_context tempcontext;
756
757     Debug(0, ("Entered Abort_LWP"));
758     printf("***LWP: %s\n", msg);
759     printf("***LWP: Abort --- dumping PCBs ...\n");
760 #ifdef DEBUG
761     Dump_Processes();
762 #endif
763     if (LWPANCHOR.outersp == NULL)
764         Exit_LWP();
765     else
766         savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
767     return;
768 }
769
770 static int
771 Create_Process_Part2(void)
772 {                               /* creates a context for the new process */
773     PROCESS temp;
774
775     Debug(2, ("Entered Create_Process_Part2"));
776     temp = lwp_cpptr;           /* Get current process id */
777     savecontext(Dispatcher, &temp->context, NULL);
778     (*temp->ep) (temp->parm);
779     LWP_DestroyProcess(temp);
780     return 0;
781 }
782
783 static int
784 Delete_PCB(register PROCESS pid)
785 {                               /* remove a PCB from the process list */
786     Debug(4, ("Entered Delete_PCB"));
787     lwp_remove(pid,
788                (pid->blockflag || pid->status == WAITING
789                 || pid->status ==
790                 DESTROYED ? &blocked : 
791                 (pid->status == QWAITING) ? &qwaiting :
792                 &runnable[pid->priority]));
793     LWPANCHOR.processcnt--;
794     return 0;
795 }
796
797 #ifdef DEBUG
798 static int
799 Dump_One_Process(PROCESS pid)
800 {
801     int i;
802
803     printf("***LWP: Process Control Block at 0x%x\n", pid);
804     printf("***LWP: Name: %s\n", pid->name);
805     if (pid->ep != NULL)
806         printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
807     if (pid->blockflag)
808         printf("BLOCKED and ");
809     switch (pid->status) {
810     case READY:
811         printf("READY");
812         break;
813     case WAITING:
814         printf("WAITING");
815         break;
816     case DESTROYED:
817         printf("DESTROYED");
818         break;
819     case QWAITING:
820         printf("QWAITING");
821         break;
822     default:
823         printf("unknown");
824     }
825     putchar('\n');
826     printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
827            pid->parm);
828     if (pid->stacksize != 0) {
829         printf("***LWP:  Stacksize: %d \tStack base address: 0x%x\n",
830                pid->stacksize, pid->stack);
831         printf("***LWP: HWM stack usage: ");
832         printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
833         free(pid->stack);
834     }
835     printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
836     if (pid->eventcnt > 0) {
837         printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
838         printf("***LWP: Event id list:");
839         for (i = 0; i < pid->eventcnt; i++)
840             printf(" 0x%x", pid->eventlist[i]);
841         putchar('\n');
842     }
843     if (pid->wakevent > 0)
844         printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
845     return 0;
846 }
847 #endif
848
849 static int
850 purge_dead_pcbs(void)
851 {
852     for_all_elts(cur, blocked, {
853                  if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
854     )
855         return 0;
856 }
857
858 int LWP_TraceProcesses = 0;
859
860 static int
861 Dispatcher(void)
862 {                               /* Lightweight process dispatcher */
863     register int i;
864 #ifdef DEBUG
865     static int dispatch_count = 0;
866
867     if (LWP_TraceProcesses > 0) {
868         for (i = 0; i < MAX_PRIORITIES; i++) {
869             printf("[Priority %d, runnable (%d):", i, runnable[i].count);
870             for_all_elts(p, runnable[i], {
871                          printf(" \"%s\"", p->name);
872                          }
873             )
874                 puts("]");
875         }
876         printf("[Blocked (%d):", blocked.count);
877         for_all_elts(p, blocked, {
878                      printf(" \"%s\"", p->name);
879                      }
880         )
881         puts("]");
882         printf("[Qwaiting (%d):", qwaiting.count);
883         for_all_elts(p, qwaiting, {
884                      printf(" \"%s\"", p->name);
885                      }
886         )
887         puts("]");
888     }
889 #endif
890
891     /* Check for stack overflowif this lwp has a stack.  Check for
892      * the guard word at the front of the stack being damaged and
893      * for the stack pointer being below the front of the stack.
894      * WARNING!  This code assumes that stacks grow downward. */
895 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
896     /* Fix this (stackcheck at other end of stack?) */
897     if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
898         && (lwp_cpptr->stackcheck !=
899             *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
900             || lwp_cpptr->context.topstack >
901             lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
902 #else
903     if (lwp_cpptr && lwp_cpptr->stack
904         && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
905             || lwp_cpptr->context.topstack < lwp_cpptr->stack
906             || lwp_cpptr->context.topstack >
907             (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
908 #endif
909         printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
910                *(int *)lwp_cpptr->stack);
911         printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
912                lwp_cpptr->context.topstack, lwp_cpptr->stack,
913                lwp_cpptr->stacksize);
914
915         switch (lwp_overflowAction) {
916         case LWP_SOQUIET:
917             break;
918         case LWP_SOABORT:
919             Overflow_Complain();
920             abort();
921         case LWP_SOMESSAGE:
922         default:
923             Overflow_Complain();
924             lwp_overflowAction = LWP_SOQUIET;
925             break;
926         }
927     }
928
929     /* Move head of current runnable queue forward if current LWP is still in it. */
930     if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
931         runnable[lwp_cpptr->priority].head =
932             runnable[lwp_cpptr->priority].head->next;
933     /* Find highest priority with runnable processes. */
934     for (i = MAX_PRIORITIES - 1; i >= 0; i--)
935         if (runnable[i].head != NULL)
936             break;
937
938     if (i < 0)
939         Abort_LWP("No READY processes");
940
941 #ifdef DEBUG
942     if (LWP_TraceProcesses > 0)
943         printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
944                runnable[i].head, runnable[i].head->name);
945 #endif
946     if (PRE_Block != 1)
947         Abort_LWP("PRE_Block not 1");
948     lwp_cpptr = runnable[i].head;
949
950     returnto(&lwp_cpptr->context);
951 }
952
953 /* Complain of a stack overflow to stderr without using stdio. */
954 static void
955 Overflow_Complain(void)
956 {
957     time_t currenttime;
958     char *timeStamp;
959     char *msg1 = " LWP: stack overflow in process ";
960     char *msg2 = "!\n";
961
962     currenttime = time(0);
963     timeStamp = ctime(&currenttime);
964     timeStamp[24] = 0;
965     write(2, timeStamp, strlen(timeStamp));
966
967     write(2, msg1, strlen(msg1));
968     write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
969     write(2, msg2, strlen(msg2));
970 }
971
972 static void
973 Dispose_of_Dead_PCB(PROCESS cur)
974 {
975     Debug(4, ("Entered Dispose_of_Dead_PCB"));
976     Delete_PCB(cur);
977     Free_PCB(cur);
978 /*
979     Internal_Signal(cur);
980 */
981 }
982
983 static int
984 Exit_LWP(void)
985 {
986     abort();
987 }
988
989 static void
990 Free_PCB(PROCESS pid)
991 {
992     Debug(4, ("Entered Free_PCB"));
993     if (pid->stack != NULL) {
994         Debug(0,
995               ("HWM stack usage: %d, [PCB at 0x%x]",
996                Stack_Used(pid->stack, pid->stacksize), pid));
997         free(pid->stack);
998     }
999     if (pid->eventlist != NULL)
1000         free(pid->eventlist);
1001     free(pid);
1002 }
1003
1004 static void
1005 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1006                int (*ep) (), void *parm, char *name)
1007 {
1008     register int i = 0;
1009
1010     Debug(4, ("Entered Initialize_PCB"));
1011     if (name != NULL)
1012         while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1013             i++;
1014     temp->name[31] = '\0';
1015     temp->status = READY;
1016     temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
1017     temp->eventlistsize = EVINITSIZE;
1018     temp->eventcnt = 0;
1019     temp->wakevent = 0;
1020     temp->waitcnt = 0;
1021     temp->blockflag = 0;
1022     temp->iomgrRequest = 0;
1023     temp->priority = priority;
1024     temp->index = lwp_nextindex++;
1025     temp->stack = stack;
1026     temp->stacksize = stacksize;
1027 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1028     if (temp->stack != NULL)
1029         temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1030 #else
1031     if (temp->stack != NULL)
1032         temp->stackcheck = *(int *)(temp->stack);
1033 #endif
1034     temp->ep = ep;
1035     temp->parm = parm;
1036     temp->misc = NULL;          /* currently unused */
1037     temp->next = NULL;
1038     temp->prev = NULL;
1039     temp->lwp_rused = 0;
1040     temp->level = 1;            /* non-preemptable */
1041 }
1042
1043 static int
1044 Internal_Signal(register char *event)
1045 {
1046     int rc = LWP_ENOWAIT;
1047     register int i;
1048
1049     Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1050     if (!lwp_init)
1051         return LWP_EINIT;
1052     if (event == NULL)
1053         return LWP_EBADEVENT;
1054     for_all_elts(temp, blocked, {
1055                  if (temp->status == WAITING)
1056                  for (i = 0; i < temp->eventcnt; i++) {
1057                  if (temp->eventlist[i] == event) {
1058                  temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1059                  Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1060                  if (--temp->waitcnt == 0) {
1061                  temp->status = READY; temp->wakevent = i + 1;
1062                  move(temp, &blocked, &runnable[temp->priority]); break;}
1063                  }
1064                  }
1065                  }
1066     )
1067         return rc;
1068 }
1069
1070 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1071 #define STACKMAGIC      0xBADBADBA
1072 static afs_int32
1073 Initialize_Stack(char *stackptr, int stacksize)
1074 {
1075     register int i;
1076
1077     Debug(4, ("Entered Initialize_Stack"));
1078     if (lwp_stackUseEnabled)
1079         for (i = 0; i < stacksize; i++)
1080             stackptr[i] = i & 0xff;
1081     else
1082 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1083         *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1084 #else
1085         *(afs_int32 *) stackptr = STACKMAGIC;
1086 #endif
1087     return 0;
1088 }
1089
1090 static int
1091 Stack_Used(register char *stackptr, int stacksize)
1092 {
1093     register int i;
1094
1095 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1096     if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1097         return 0;
1098     else {
1099         for (i = stacksize - 1; i >= 0; i--)
1100             if ((unsigned char)stackptr[i] != (i & 0xff))
1101                 return (i);
1102         return 0;
1103     }
1104 #else
1105     if (*(afs_int32 *) stackptr == STACKMAGIC)
1106         return 0;
1107     else {
1108         for (i = 0; i < stacksize; i++)
1109             if ((unsigned char)stackptr[i] != (i & 0xff))
1110                 return (stacksize - i);
1111         return 0;
1112     }
1113 #endif
1114 }
1115
1116
1117 int
1118 LWP_NewRock(int Tag, char *Value)
1119     /* Finds a free rock and sets its value to Value.
1120      * Return codes:
1121      * LWP_SUCCESS      Rock did not exist and a new one was used
1122      * LWP_EBADROCK     Rock already exists.
1123      * LWP_ENOROCKS     All rocks are in use.
1124      * 
1125      * From the above semantics, you can only set a rock value once.  This is specifically
1126      * to prevent multiple users of the LWP package from accidentally using the same Tag
1127      * value and clobbering others.  You can always use one level of indirection to obtain
1128      * a rock whose contents can change.
1129      */
1130 {
1131     register int i;
1132     register struct rock *ra;   /* rock array */
1133
1134     ra = lwp_cpptr->lwp_rlist;
1135
1136     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1137         if (ra[i].tag == Tag)
1138             return (LWP_EBADROCK);
1139
1140     if (lwp_cpptr->lwp_rused < MAXROCKS) {
1141         ra[lwp_cpptr->lwp_rused].tag = Tag;
1142         ra[lwp_cpptr->lwp_rused].value = Value;
1143         lwp_cpptr->lwp_rused++;
1144         return (LWP_SUCCESS);
1145     } else
1146         return (LWP_ENOROCKS);
1147 }
1148
1149
1150 int
1151 LWP_GetRock(int Tag, char **Value)
1152     /* Obtains the pointer Value associated with the rock Tag of this LWP.
1153      * Returns:
1154      * LWP_SUCCESS              if specified rock exists and Value has been filled
1155      * LWP_EBADROCK     rock specified does not exist
1156      */
1157 {
1158     register int i;
1159     register struct rock *ra;
1160
1161     ra = lwp_cpptr->lwp_rlist;
1162
1163     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1164         if (ra[i].tag == Tag) {
1165             *Value = ra[i].value;
1166             return (LWP_SUCCESS);
1167         }
1168     return (LWP_EBADROCK);
1169 }
1170
1171
1172 #ifdef  AFS_AIX32_ENV
1173 int
1174 setlim(int limcon, uchar_t hard, int limit)
1175 {
1176     struct rlimit rlim;
1177
1178     (void)getrlimit(limcon, &rlim);
1179
1180     limit = limit * 1024;
1181     if (hard)
1182         rlim.rlim_max = limit;
1183     else if (limit == RLIM_INFINITY && geteuid() != 0)
1184         rlim.rlim_cur = rlim.rlim_max;
1185     else
1186         rlim.rlim_cur = limit;
1187
1188     /* Must use ulimit() due to Posix constraints */
1189     if (limcon == RLIMIT_FSIZE) {
1190         if (ulimit
1191             (UL_SETFSIZE,
1192              ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1193             printf("Can't %s%s limit\n",
1194                    limit == RLIM_INFINITY ? "remove" : "set",
1195                    hard ? " hard" : "");
1196             return (-1);
1197         }
1198     } else {
1199         if (setrlimit(limcon, &rlim) < 0) {
1200             perror("");
1201             printf("Can't %s%s limit\n",
1202                    limit == RLIM_INFINITY ? "remove" : "set",
1203                    hard ? " hard" : "");
1204             return (-1);
1205         }
1206     }
1207     return (0);
1208 }
1209
1210
1211 #ifdef  notdef
1212 /*
1213  * Print the specific limit out
1214  */
1215 int
1216 plim(char *name, afs_int32 lc, uchar_t hard)
1217 {
1218     struct rlimit rlim;
1219     int lim;
1220
1221     printf("%s \t", name);
1222     (void)getrlimit(lc, &rlim);
1223     lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1224     if (lim == RLIM_INFINITY)
1225         printf("unlimited");
1226     printf("%d %s", lim / 1024, "kbytes");
1227     printf("\n");
1228 }
1229 #endif
1230 #endif
1231
1232 #ifdef  AFS_SUN5_ENV
1233 int
1234 LWP_NoYieldSignal(char *event)
1235 {
1236     return (LWP_INTERNALSIGNAL(event, 0));
1237 }
1238
1239 int
1240 LWP_SignalProcess(char *event)
1241 {
1242     return (LWP_INTERNALSIGNAL(event, 1));
1243 }
1244
1245 #endif
1246 #else
1247 #ifdef  USE_SOLARIS_THREADS
1248 #include <thread.h>
1249 #else
1250 #include "pthread.h"
1251 #endif
1252 #include <stdio.h>
1253 #include <assert.h>
1254
1255 pthread_mutex_t lwp_mutex;      /* Mutex to ensure mutual exclusion of all LWP threads */
1256
1257 PROCESS lwp_process_list;       /* List of LWP initiated threads */
1258
1259 pthread_key_t lwp_process_key;  /* Key associating lwp pid with thread */
1260
1261 #define CHECK check(__LINE__);
1262
1263 typedef struct event {
1264     struct event *next;         /* next in hash chain */
1265     char *event;                /* lwp event: an address */
1266     int refcount;               /* Is it in use? */
1267     pthread_cond_t cond;        /* Currently associated condition variable */
1268     int seq;                    /* Sequence number: this is incremented
1269                                  * by wakeup calls; wait will not return until
1270                                  * it changes */
1271 } event_t;
1272
1273 #define HASHSIZE 127
1274 event_t *hashtable[HASHSIZE];   /* Hash table for events */
1275 #define hash(event)     ((unsigned long) (event) % HASHSIZE);
1276
1277 #if CMA_DEBUG || DEBUGF
1278 char *
1279 lwp_process_string(void)
1280 {
1281     static char id[200];
1282     PROCESS p;
1283     LWP_CurrentProcess(&p);
1284     sprintf(id, "PID %x <%s>", p, p->name);
1285     return id;
1286 }
1287 #endif
1288
1289 void
1290 lwp_unimplemented(char *interface)
1291 {
1292     fprintf(stderr,
1293             "cmalwp: %s is not currently implemented: program aborted\n",
1294             interface);
1295     exit(1);
1296 }
1297
1298 static void
1299 lwpabort(char *interface)
1300 {
1301     fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1302     abort();
1303 }
1304
1305 int
1306 LWP_QWait(void)
1307 {
1308     lwp_unimplemented("LWP_QWait");
1309 }
1310
1311 int
1312 LWP_QSignal(int pid)
1313 {
1314     lwp_unimplemented("LWP_QSignal");
1315 }
1316
1317 /* Allocate and initialize an LWP process handle. The associated pthread handle
1318  * must be added by the caller, and the structure threaded onto the LWP active
1319  * process list by lwp_thread_process */
1320 static PROCESS
1321 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1322 {
1323     PROCESS lp;
1324     assert(lp = (PROCESS) malloc(sizeof(*lp)));
1325     memset((char *)lp, 0, sizeof(*lp));
1326     if (!name) {
1327         char temp[100];
1328         static procnum;
1329         sprintf(temp, "unnamed_process_%04d", ++procnum);
1330         assert(name = (char *)malloc(strlen(temp) + 1));
1331         strcpy(name, temp);
1332     }
1333     lp->name = name;
1334     lp->ep = ep;
1335     lp->arg = arg;
1336     return lp;
1337 }
1338
1339 /* Thread the LWP process descriptor *lp onto the lwp active process list
1340  * and associate a back pointer to the process descriptor from the associated
1341  * thread */
1342 static
1343 lwp_thread_process(PROCESS lp)
1344 {
1345     lp->next = lwp_process_list;
1346     lwp_process_list = lp;
1347     assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1348 }
1349
1350 /* The top-level routine used as entry point to explicitly created LWP
1351  * processes. This completes a few details of process creation left
1352  * out by LWP_CreateProcess and calls the user-specified entry point */
1353 static int
1354 lwp_top_level(pthread_addr_t argp)
1355 {
1356     PROCESS lp = (PROCESS) argp;
1357
1358     assert(!pthread_mutex_lock(&lwp_mutex));
1359     lwp_thread_process(lp);
1360     (lp->ep) (lp->arg);
1361     assert(!pthread_mutex_unlock(&lwp_mutex));
1362     /* Should cleanup state */
1363 }
1364
1365 int
1366 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1367                   void *parm, char *name, PROCESS * pid)
1368 {
1369     int status;
1370     pthread_attr_t attr;
1371     pthread_t handle;
1372     PROCESS lp;
1373
1374 #ifndef LWP_NO_PRIORITIES
1375     if (!cmalwp_pri_inrange(priority))
1376         return LWP_EBADPRI;
1377 #endif
1378     assert(!pthread_attr_create(&attr));
1379     assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1380     if (stacksize)
1381         assert(!pthread_attr_setstacksize(&attr, stacksize));
1382 #ifndef BDE_THREADS
1383     (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1384     (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1385 #ifndef LWP_NO_PRIORITIES
1386     (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1387 #endif
1388 #endif
1389     lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1390                            (pthread_addr_t) parm);
1391
1392     /* allow new thread to run if higher priority */
1393     assert(!pthread_mutex_unlock(&lwp_mutex));
1394     /* process is only added to active list after first time it runs (it adds itself) */
1395     status =
1396         pthread_create(&lp->handle, attr,
1397                        (pthread_startroutine_t) lwp_top_level,
1398                        (pthread_addr_t) lp);
1399     assert(!pthread_attr_delete(&attr));
1400     assert(!pthread_mutex_lock(&lwp_mutex));
1401     if (status != 0) {
1402         free(lp);
1403         return LWP_ENOMEM;
1404     }
1405     *pid = lp;
1406     return LWP_SUCCESS;
1407 }
1408
1409 PROCESS
1410 LWP_ActiveProcess(void)
1411 {                               /* returns pid of current process */
1412     PROCESS pid;
1413     assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1414     return pid;
1415 }
1416
1417 int
1418 LWP_CurrentProcess(PROCESS * pid)
1419 {                               /* get pid of current process */
1420     assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1421     return LWP_SUCCESS;
1422 }
1423
1424 int
1425 LWP_DestroyProcess(PROCESS pid)
1426 {                               /* destroy a lightweight process */
1427     lwp_unimplemented("LWP_DestroyProcess");
1428 }
1429
1430 int
1431 LWP_DispatchProcess(void)
1432 {                               /* explicit voluntary preemption */
1433     assert(!pthread_mutex_unlock(&lwp_mutex));
1434     pthread_yield();
1435     assert(!pthread_mutex_lock(&lwp_mutex));
1436     return LWP_SUCCESS;
1437 }
1438
1439 static int
1440 lwp_process_key_destructor(void)
1441 {
1442 }
1443
1444 int
1445 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1446 {
1447     static int initialized = 0;
1448     int status;
1449     static PROCESS lp;
1450     extern main;
1451     int state;
1452
1453     if (initialized) {
1454         *pid = lp;
1455         return LWP_SUCCESS;
1456     }
1457 #ifndef LWP_NO_PRIORITIES
1458     if (priority < 0 || priority > LWP_MAX_PRIORITY)
1459         return LWP_EBADPRI;
1460 #endif
1461
1462     /* Create pthread key to associate LWP process descriptor with each
1463      * LWP-created thread */
1464     assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1465                               lwp_process_key_destructor));
1466
1467     lp = lwp_alloc_process("main process", main, 0);
1468     lp->handle = pthread_self();
1469     lwp_thread_process(lp);
1470 #ifndef LWP_NO_PRIORITIES
1471     (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1472                                cmalwp_lwppri_to_cmapri(priority));
1473
1474 #endif
1475     assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1476     assert(pthread_mutex_lock(&lwp_mutex) == 0);
1477     initialized = 1;
1478     *pid = lp;
1479     return LWP_SUCCESS;
1480 }
1481
1482 int
1483 LWP_TerminateProcessSupport(void)
1484 {                               /* terminate all LWP support */
1485     lwp_unimplemented("LWP_TerminateProcessSupport");
1486 }
1487
1488 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1489 static event_t *
1490 getevent(char *event)
1491 {
1492     event_t *evp, *newp;
1493     int hashcode;
1494
1495     hashcode = hash(event);
1496     evp = hashtable[hashcode];
1497     newp = 0;
1498     while (evp) {
1499         if (evp->event == event) {
1500             evp->refcount++;
1501             return evp;
1502         }
1503         if (evp->refcount == 0)
1504             newp = evp;
1505         evp = evp->next;
1506     }
1507     if (!newp) {
1508         newp = (event_t *) malloc(sizeof(event_t));
1509         assert(newp);
1510         newp->next = hashtable[hashcode];
1511         hashtable[hashcode] = newp;
1512         assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1513         newp->seq = 0;
1514     }
1515     newp->event = event;
1516     newp->refcount = 1;
1517     return newp;
1518 }
1519
1520 /* Release the specified event */
1521 #define relevent(evp) ((evp)->refcount--)
1522
1523 int
1524 LWP_WaitProcess(char *event)
1525 {                               /* wait on a single event */
1526     struct event *ev;
1527     int seq;
1528     debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1529     if (event == NULL)
1530         return LWP_EBADEVENT;
1531     ev = getevent(event);
1532     seq = ev->seq;
1533     while (seq == ev->seq) {
1534         assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1535     }
1536     debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1537     relevent(ev);
1538     return LWP_SUCCESS;
1539 }
1540
1541 int
1542 LWP_MwaitProcess(int wcount, char *evlist[])
1543 {                               /* wait on m of n events */
1544     lwp_unimplemented("LWP_MWaitProcess");
1545 }
1546
1547 int
1548 LWP_NoYieldSignal(char *event)
1549 {
1550     struct event *ev;
1551     debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1552     if (event == NULL)
1553         return LWP_EBADEVENT;
1554     ev = getevent(event);
1555     if (ev->refcount > 1) {
1556         ev->seq++;
1557         assert(pthread_cond_broadcast(&ev->cond) == 0);
1558     }
1559     relevent(ev);
1560     return LWP_SUCCESS;
1561 }
1562
1563 int
1564 LWP_SignalProcess(char *event)
1565 {
1566     struct event *ev;
1567     debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1568     if (event == NULL)
1569         return LWP_EBADEVENT;
1570     ev = getevent(event);
1571     if (ev->refcount > 1) {
1572         ev->seq++;
1573         assert(!pthread_mutex_unlock(&lwp_mutex));
1574         assert(!pthread_cond_broadcast(&ev->cond));
1575         pthread_yield();
1576         assert(!pthread_mutex_lock(&lwp_mutex));
1577     }
1578     relevent(ev);
1579     return LWP_SUCCESS;
1580 }
1581
1582 int
1583 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1584 {
1585     lwp_unimplemented("LWP_StackUsed");
1586 }
1587
1588 int
1589 LWP_NewRock(int Tag, char *Value)
1590 {
1591     lwp_unimplemented("LWP_NewRock");
1592 }
1593
1594 int
1595 LWP_GetRock(int Tag, char **Value)
1596 {
1597     lwp_unimplemented("LWP_GetRock");
1598 }
1599
1600 int
1601 LWP_GetProcessPriority(PROCESS pid, int *priority)
1602 {                               /* returns process priority */
1603     lwp_unimplemented("LWP_GetProcessPriority");
1604 }
1605
1606 #endif /* USE_PTHREADS */