lwp-elf-bsd-and-assembly-cleanup-20030924
[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;
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     lwp_remove(tp, &runnable[tp->priority]);
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         insert(pid, &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     } else
560         printf("***LWP: LWP support not initialized\n");
561     return 0;
562 }
563 #endif
564
565 int
566 LWP_GetProcessPriority(PROCESS pid, int *priority)
567 {                               /* returns process priority */
568     Debug(0, ("Entered Get_Process_Priority"));
569     if (lwp_init) {
570         *priority = pid->priority;
571         return 0;
572     } else
573         return LWP_EINIT;
574 }
575
576 int
577 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
578 {
579     PROCESS temp;
580     struct lwp_pcb dummy;
581     register int i;
582     char *value;
583
584     Debug(0, ("Entered LWP_InitializeProcessSupport"));
585     if (lwp_init != NULL)
586         return LWP_SUCCESS;
587
588     /* Set up offset for stack checking -- do this as soon as possible */
589     stack_offset = (char *)&dummy.stack - (char *)&dummy;
590
591     if (priority >= MAX_PRIORITIES)
592         return LWP_EBADPRI;
593     for (i = 0; i < MAX_PRIORITIES; i++) {
594         runnable[i].head = NULL;
595         runnable[i].count = 0;
596     }
597     blocked.head = NULL;
598     blocked.count = 0;
599     lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
600     temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
601     if (lwp_init == NULL || temp == NULL)
602         Abort_LWP("Insufficient Storage to Initialize LWP Support");
603     LWPANCHOR.processcnt = 1;
604     LWPANCHOR.outerpid = temp;
605     LWPANCHOR.outersp = NULL;
606     Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
607                    "Main Process [created by LWP]");
608     insert(temp, &runnable[priority]);
609     savecontext(Dispatcher, &temp->context, NULL);
610     LWPANCHOR.outersp = temp->context.topstack;
611     Set_LWP_RC();
612     *pid = temp;
613
614     /* get minimum stack size from the environment. this allows the  administrator
615      * to change the lwp stack dynamically without getting a new binary version.
616      */
617     if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
618         lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
619     else
620         lwp_MinStackSize =
621             (AFS_LWP_MINSTACKSIZE >
622              atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
623
624     return LWP_SUCCESS;
625 }
626
627 int
628 LWP_INTERNALSIGNAL(char *event, int yield)
629 {                               /* signal the occurence of an event */
630     Debug(2, ("Entered LWP_SignalProcess"));
631     if (lwp_init) {
632         int rc;
633         rc = Internal_Signal(event);
634         if (yield)
635             Set_LWP_RC();
636         return rc;
637     } else
638         return LWP_EINIT;
639 }
640
641 int
642 LWP_TerminateProcessSupport(void)
643 {                               /* terminate all LWP support */
644     register int i;
645
646     Debug(0, ("Entered Terminate_Process_Support"));
647     if (lwp_init == NULL)
648         return LWP_EINIT;
649     if (lwp_cpptr != LWPANCHOR.outerpid)
650         Abort_LWP("Terminate_Process_Support invoked from wrong process!");
651     for (i = 0; i < MAX_PRIORITIES; i++)
652         for_all_elts(cur, runnable[i], {
653                      Free_PCB(cur);}
654     )
655         for_all_elts(cur, blocked, {
656                      Free_PCB(cur);}
657     )
658         free(lwp_init);
659     lwp_init = NULL;
660     return LWP_SUCCESS;
661 }
662
663 int
664 LWP_WaitProcess(char *event)
665 {                               /* wait on a single event */
666     char *tempev[2];
667
668     Debug(2, ("Entered Wait_Process"));
669     if (event == NULL)
670         return LWP_EBADEVENT;
671     tempev[0] = event;
672     tempev[1] = NULL;
673     return LWP_MwaitProcess(1, tempev);
674 }
675
676 int
677 LWP_MwaitProcess(int wcount, char *evlist[])
678 {                               /* wait on m of n events */
679     register int ecount, i;
680
681
682     Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
683
684     if (evlist == NULL) {
685         Set_LWP_RC();
686         return LWP_EBADCOUNT;
687     }
688
689     for (ecount = 0; evlist[ecount] != NULL; ecount++);
690
691     if (ecount == 0) {
692         Set_LWP_RC();
693         return LWP_EBADCOUNT;
694     }
695
696     if (lwp_init) {
697
698         if (wcount > ecount || wcount < 0) {
699             Set_LWP_RC();
700             return LWP_EBADCOUNT;
701         }
702         if (ecount > lwp_cpptr->eventlistsize) {
703
704             lwp_cpptr->eventlist =
705                 (char **)realloc(lwp_cpptr->eventlist,
706                                  ecount * sizeof(char *));
707             lwp_cpptr->eventlistsize = ecount;
708         }
709         for (i = 0; i < ecount; i++)
710             lwp_cpptr->eventlist[i] = evlist[i];
711         if (wcount > 0) {
712             lwp_cpptr->status = WAITING;
713
714             move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
715
716         }
717         lwp_cpptr->wakevent = 0;
718         lwp_cpptr->waitcnt = wcount;
719         lwp_cpptr->eventcnt = ecount;
720
721         Set_LWP_RC();
722
723         return LWP_SUCCESS;
724     }
725
726     return LWP_EINIT;
727 }
728
729 int
730 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
731 {
732     *maxa = pid->stacksize;
733     *used = Stack_Used(pid->stack, *maxa);
734     if (*used == 0)
735         return LWP_NO_STACK;
736     return LWP_SUCCESS;
737 }
738 \f
739 /*
740  *  The following functions are strictly
741  *  INTERNAL to the LWP support package.
742  */
743
744 static void
745 Abort_LWP(char *msg)
746 {
747     struct lwp_context tempcontext;
748
749     Debug(0, ("Entered Abort_LWP"));
750     printf("***LWP: %s\n", msg);
751     printf("***LWP: Abort --- dumping PCBs ...\n");
752 #ifdef DEBUG
753     Dump_Processes();
754 #endif
755     if (LWPANCHOR.outersp == NULL)
756         Exit_LWP();
757     else
758         savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
759     return;
760 }
761
762 static int
763 Create_Process_Part2(void)
764 {                               /* creates a context for the new process */
765     PROCESS temp;
766
767     Debug(2, ("Entered Create_Process_Part2"));
768     temp = lwp_cpptr;           /* Get current process id */
769     savecontext(Dispatcher, &temp->context, NULL);
770     (*temp->ep) (temp->parm);
771     LWP_DestroyProcess(temp);
772     return 0;
773 }
774
775 static int
776 Delete_PCB(register PROCESS pid)
777 {                               /* remove a PCB from the process list */
778     Debug(4, ("Entered Delete_PCB"));
779     lwp_remove(pid,
780                (pid->blockflag || pid->status == WAITING
781                 || pid->status ==
782                 DESTROYED ? &blocked : &runnable[pid->priority]));
783     LWPANCHOR.processcnt--;
784     return 0;
785 }
786
787 #ifdef DEBUG
788 static int
789 Dump_One_Process(PROCESS pid)
790 {
791     int i;
792
793     printf("***LWP: Process Control Block at 0x%x\n", pid);
794     printf("***LWP: Name: %s\n", pid->name);
795     if (pid->ep != NULL)
796         printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
797     if (pid->blockflag)
798         printf("BLOCKED and ");
799     switch (pid->status) {
800     case READY:
801         printf("READY");
802         break;
803     case WAITING:
804         printf("WAITING");
805         break;
806     case DESTROYED:
807         printf("DESTROYED");
808         break;
809     default:
810         printf("unknown");
811     }
812     putchar('\n');
813     printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
814            pid->parm);
815     if (pid->stacksize != 0) {
816         printf("***LWP:  Stacksize: %d \tStack base address: 0x%x\n",
817                pid->stacksize, pid->stack);
818         printf("***LWP: HWM stack usage: ");
819         printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
820         free(pid->stack);
821     }
822     printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
823     if (pid->eventcnt > 0) {
824         printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
825         printf("***LWP: Event id list:");
826         for (i = 0; i < pid->eventcnt; i++)
827             printf(" 0x%x", pid->eventlist[i]);
828         putchar('\n');
829     }
830     if (pid->wakevent > 0)
831         printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
832     return 0;
833 }
834 #endif
835
836 static int
837 purge_dead_pcbs(void)
838 {
839     for_all_elts(cur, blocked, {
840                  if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
841     )
842         return 0;
843 }
844
845 int LWP_TraceProcesses = 0;
846
847 static int
848 Dispatcher(void)
849 {                               /* Lightweight process dispatcher */
850     register int i;
851 #ifdef DEBUG
852     static int dispatch_count = 0;
853
854     if (LWP_TraceProcesses > 0) {
855         for (i = 0; i < MAX_PRIORITIES; i++) {
856             printf("[Priority %d, runnable (%d):", i, runnable[i].count);
857             for_all_elts(p, runnable[i], {
858                          printf(" \"%s\"", p->name);
859                          }
860             )
861                 puts("]");
862         }
863         printf("[Blocked (%d):", blocked.count);
864         for_all_elts(p, blocked, {
865                      printf(" \"%s\"", p->name);
866                      }
867         )
868             puts("]");
869     }
870 #endif
871
872     /* Check for stack overflowif this lwp has a stack.  Check for
873      * the guard word at the front of the stack being damaged and
874      * for the stack pointer being below the front of the stack.
875      * WARNING!  This code assumes that stacks grow downward. */
876 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
877     /* Fix this (stackcheck at other end of stack?) */
878     if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
879         && (lwp_cpptr->stackcheck !=
880             *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
881             || lwp_cpptr->context.topstack >
882             lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
883 #else
884     if (lwp_cpptr && lwp_cpptr->stack
885         && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
886             || lwp_cpptr->context.topstack < lwp_cpptr->stack
887             || lwp_cpptr->context.topstack >
888             (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
889 #endif
890         printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
891                *(int *)lwp_cpptr->stack);
892         printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
893                lwp_cpptr->context.topstack, lwp_cpptr->stack,
894                lwp_cpptr->stacksize);
895
896         switch (lwp_overflowAction) {
897         case LWP_SOQUIET:
898             break;
899         case LWP_SOABORT:
900             Overflow_Complain();
901             abort();
902         case LWP_SOMESSAGE:
903         default:
904             Overflow_Complain();
905             lwp_overflowAction = LWP_SOQUIET;
906             break;
907         }
908     }
909
910     /* Move head of current runnable queue forward if current LWP is still in it. */
911     if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
912         runnable[lwp_cpptr->priority].head =
913             runnable[lwp_cpptr->priority].head->next;
914     /* Find highest priority with runnable processes. */
915     for (i = MAX_PRIORITIES - 1; i >= 0; i--)
916         if (runnable[i].head != NULL)
917             break;
918
919     if (i < 0)
920         Abort_LWP("No READY processes");
921
922 #ifdef DEBUG
923     if (LWP_TraceProcesses > 0)
924         printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
925                runnable[i].head, runnable[i].head->name);
926 #endif
927     if (PRE_Block != 1)
928         Abort_LWP("PRE_Block not 1");
929     lwp_cpptr = runnable[i].head;
930
931     returnto(&lwp_cpptr->context);
932 }
933
934 /* Complain of a stack overflow to stderr without using stdio. */
935 static void
936 Overflow_Complain(void)
937 {
938     time_t currenttime;
939     char *timeStamp;
940     char *msg1 = " LWP: stack overflow in process ";
941     char *msg2 = "!\n";
942
943     currenttime = time(0);
944     timeStamp = ctime(&currenttime);
945     timeStamp[24] = 0;
946     write(2, timeStamp, strlen(timeStamp));
947
948     write(2, msg1, strlen(msg1));
949     write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
950     write(2, msg2, strlen(msg2));
951 }
952
953 static void
954 Dispose_of_Dead_PCB(PROCESS cur)
955 {
956     Debug(4, ("Entered Dispose_of_Dead_PCB"));
957     Delete_PCB(cur);
958     Free_PCB(cur);
959 /*
960     Internal_Signal(cur);
961 */
962 }
963
964 static int
965 Exit_LWP(void)
966 {
967     abort();
968 }
969
970 static void
971 Free_PCB(PROCESS pid)
972 {
973     Debug(4, ("Entered Free_PCB"));
974     if (pid->stack != NULL) {
975         Debug(0,
976               ("HWM stack usage: %d, [PCB at 0x%x]",
977                Stack_Used(pid->stack, pid->stacksize), pid));
978         free(pid->stack);
979     }
980     if (pid->eventlist != NULL)
981         free(pid->eventlist);
982     free(pid);
983 }
984
985 static void
986 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
987                int (*ep) (), void *parm, char *name)
988 {
989     register int i = 0;
990
991     Debug(4, ("Entered Initialize_PCB"));
992     if (name != NULL)
993         while (((temp->name[i] = name[i]) != '\0') && (i < 31))
994             i++;
995     temp->name[31] = '\0';
996     temp->status = READY;
997     temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
998     temp->eventlistsize = EVINITSIZE;
999     temp->eventcnt = 0;
1000     temp->wakevent = 0;
1001     temp->waitcnt = 0;
1002     temp->blockflag = 0;
1003     temp->iomgrRequest = 0;
1004     temp->priority = priority;
1005     temp->index = lwp_nextindex++;
1006     temp->stack = stack;
1007     temp->stacksize = stacksize;
1008 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1009     if (temp->stack != NULL)
1010         temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1011 #else
1012     if (temp->stack != NULL)
1013         temp->stackcheck = *(int *)(temp->stack);
1014 #endif
1015     temp->ep = ep;
1016     temp->parm = parm;
1017     temp->misc = NULL;          /* currently unused */
1018     temp->next = NULL;
1019     temp->prev = NULL;
1020     temp->lwp_rused = 0;
1021     temp->level = 1;            /* non-preemptable */
1022 }
1023
1024 static int
1025 Internal_Signal(register char *event)
1026 {
1027     int rc = LWP_ENOWAIT;
1028     register int i;
1029
1030     Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1031     if (!lwp_init)
1032         return LWP_EINIT;
1033     if (event == NULL)
1034         return LWP_EBADEVENT;
1035     for_all_elts(temp, blocked, {
1036                  if (temp->status == WAITING)
1037                  for (i = 0; i < temp->eventcnt; i++) {
1038                  if (temp->eventlist[i] == event) {
1039                  temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1040                  Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1041                  if (--temp->waitcnt == 0) {
1042                  temp->status = READY; temp->wakevent = i + 1;
1043                  move(temp, &blocked, &runnable[temp->priority]); break;}
1044                  }
1045                  }
1046                  }
1047     )
1048         return rc;
1049 }
1050
1051 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1052 #define STACKMAGIC      0xBADBADBA
1053 static afs_int32
1054 Initialize_Stack(char *stackptr, int stacksize)
1055 {
1056     register int i;
1057
1058     Debug(4, ("Entered Initialize_Stack"));
1059     if (lwp_stackUseEnabled)
1060         for (i = 0; i < stacksize; i++)
1061             stackptr[i] = i & 0xff;
1062     else
1063 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1064         *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1065 #else
1066         *(afs_int32 *) stackptr = STACKMAGIC;
1067 #endif
1068     return 0;
1069 }
1070
1071 static int
1072 Stack_Used(register char *stackptr, int stacksize)
1073 {
1074     register int i;
1075
1076 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1077     if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1078         return 0;
1079     else {
1080         for (i = stacksize - 1; i >= 0; i--)
1081             if ((unsigned char)stackptr[i] != (i & 0xff))
1082                 return (i);
1083         return 0;
1084     }
1085 #else
1086     if (*(afs_int32 *) stackptr == STACKMAGIC)
1087         return 0;
1088     else {
1089         for (i = 0; i < stacksize; i++)
1090             if ((unsigned char)stackptr[i] != (i & 0xff))
1091                 return (stacksize - i);
1092         return 0;
1093     }
1094 #endif
1095 }
1096
1097
1098 int
1099 LWP_NewRock(int Tag, char *Value)
1100     /* Finds a free rock and sets its value to Value.
1101      * Return codes:
1102      * LWP_SUCCESS      Rock did not exist and a new one was used
1103      * LWP_EBADROCK     Rock already exists.
1104      * LWP_ENOROCKS     All rocks are in use.
1105      * 
1106      * From the above semantics, you can only set a rock value once.  This is specifically
1107      * to prevent multiple users of the LWP package from accidentally using the same Tag
1108      * value and clobbering others.  You can always use one level of indirection to obtain
1109      * a rock whose contents can change.
1110      */
1111 {
1112     register int i;
1113     register struct rock *ra;   /* rock array */
1114
1115     ra = lwp_cpptr->lwp_rlist;
1116
1117     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1118         if (ra[i].tag == Tag)
1119             return (LWP_EBADROCK);
1120
1121     if (lwp_cpptr->lwp_rused < MAXROCKS) {
1122         ra[lwp_cpptr->lwp_rused].tag = Tag;
1123         ra[lwp_cpptr->lwp_rused].value = Value;
1124         lwp_cpptr->lwp_rused++;
1125         return (LWP_SUCCESS);
1126     } else
1127         return (LWP_ENOROCKS);
1128 }
1129
1130
1131 int
1132 LWP_GetRock(int Tag, char **Value)
1133     /* Obtains the pointer Value associated with the rock Tag of this LWP.
1134      * Returns:
1135      * LWP_SUCCESS              if specified rock exists and Value has been filled
1136      * LWP_EBADROCK     rock specified does not exist
1137      */
1138 {
1139     register int i;
1140     register struct rock *ra;
1141
1142     ra = lwp_cpptr->lwp_rlist;
1143
1144     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1145         if (ra[i].tag == Tag) {
1146             *Value = ra[i].value;
1147             return (LWP_SUCCESS);
1148         }
1149     return (LWP_EBADROCK);
1150 }
1151
1152
1153 #ifdef  AFS_AIX32_ENV
1154 int
1155 setlim(int limcon, uchar_t hard, int limit)
1156 {
1157     struct rlimit rlim;
1158
1159     (void)getrlimit(limcon, &rlim);
1160
1161     limit = limit * 1024;
1162     if (hard)
1163         rlim.rlim_max = limit;
1164     else if (limit == RLIM_INFINITY && geteuid() != 0)
1165         rlim.rlim_cur = rlim.rlim_max;
1166     else
1167         rlim.rlim_cur = limit;
1168
1169     /* Must use ulimit() due to Posix constraints */
1170     if (limcon == RLIMIT_FSIZE) {
1171         if (ulimit
1172             (UL_SETFSIZE,
1173              ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1174             printf("Can't %s%s limit\n",
1175                    limit == RLIM_INFINITY ? "remove" : "set",
1176                    hard ? " hard" : "");
1177             return (-1);
1178         }
1179     } else {
1180         if (setrlimit(limcon, &rlim) < 0) {
1181             perror("");
1182             printf("Can't %s%s limit\n",
1183                    limit == RLIM_INFINITY ? "remove" : "set",
1184                    hard ? " hard" : "");
1185             return (-1);
1186         }
1187     }
1188     return (0);
1189 }
1190
1191
1192 #ifdef  notdef
1193 /*
1194  * Print the specific limit out
1195  */
1196 int
1197 plim(char *name, afs_int32 lc, uchar_t hard)
1198 {
1199     struct rlimit rlim;
1200     int lim;
1201
1202     printf("%s \t", name);
1203     (void)getrlimit(lc, &rlim);
1204     lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1205     if (lim == RLIM_INFINITY)
1206         printf("unlimited");
1207     printf("%d %s", lim / 1024, "kbytes");
1208     printf("\n");
1209 }
1210 #endif
1211 #endif
1212
1213 #ifdef  AFS_SUN5_ENV
1214 int
1215 LWP_NoYieldSignal(char *event)
1216 {
1217     return (LWP_INTERNALSIGNAL(event, 0));
1218 }
1219
1220 int
1221 LWP_SignalProcess(char *event)
1222 {
1223     return (LWP_INTERNALSIGNAL(event, 1));
1224 }
1225
1226 #endif
1227 #else
1228 #ifdef  USE_SOLARIS_THREADS
1229 #include <thread.h>
1230 #else
1231 #include "pthread.h"
1232 #endif
1233 #include <stdio.h>
1234 #include <assert.h>
1235
1236 pthread_mutex_t lwp_mutex;      /* Mutex to ensure mutual exclusion of all LWP threads */
1237
1238 PROCESS lwp_process_list;       /* List of LWP initiated threads */
1239
1240 pthread_key_t lwp_process_key;  /* Key associating lwp pid with thread */
1241
1242 #define CHECK check(__LINE__);
1243
1244 typedef struct event {
1245     struct event *next;         /* next in hash chain */
1246     char *event;                /* lwp event: an address */
1247     int refcount;               /* Is it in use? */
1248     pthread_cond_t cond;        /* Currently associated condition variable */
1249     int seq;                    /* Sequence number: this is incremented
1250                                  * by wakeup calls; wait will not return until
1251                                  * it changes */
1252 } event_t;
1253
1254 #define HASHSIZE 127
1255 event_t *hashtable[HASHSIZE];   /* Hash table for events */
1256 #define hash(event)     ((unsigned long) (event) % HASHSIZE);
1257
1258 #if CMA_DEBUG || DEBUGF
1259 char *
1260 lwp_process_string(void)
1261 {
1262     static char id[200];
1263     PROCESS p;
1264     LWP_CurrentProcess(&p);
1265     sprintf(id, "PID %x <%s>", p, p->name);
1266     return id;
1267 }
1268 #endif
1269
1270 void
1271 lwp_unimplemented(char *interface)
1272 {
1273     fprintf(stderr,
1274             "cmalwp: %s is not currently implemented: program aborted\n",
1275             interface);
1276     exit(1);
1277 }
1278
1279 static void
1280 lwpabort(char *interface)
1281 {
1282     fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1283     abort();
1284 }
1285
1286 int
1287 LWP_QWait(void)
1288 {
1289     lwp_unimplemented("LWP_QWait");
1290 }
1291
1292 int
1293 LWP_QSignal(int pid)
1294 {
1295     lwp_unimplemented("LWP_QSignal");
1296 }
1297
1298 /* Allocate and initialize an LWP process handle. The associated pthread handle
1299  * must be added by the caller, and the structure threaded onto the LWP active
1300  * process list by lwp_thread_process */
1301 static PROCESS
1302 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1303 {
1304     PROCESS lp;
1305     assert(lp = (PROCESS) malloc(sizeof(*lp)));
1306     memset((char *)lp, 0, sizeof(*lp));
1307     if (!name) {
1308         char temp[100];
1309         static procnum;
1310         sprintf(temp, "unnamed_process_%04d", ++procnum);
1311         assert(name = (char *)malloc(strlen(temp) + 1));
1312         strcpy(name, temp);
1313     }
1314     lp->name = name;
1315     lp->ep = ep;
1316     lp->arg = arg;
1317     return lp;
1318 }
1319
1320 /* Thread the LWP process descriptor *lp onto the lwp active process list
1321  * and associate a back pointer to the process descriptor from the associated
1322  * thread */
1323 static
1324 lwp_thread_process(PROCESS lp)
1325 {
1326     lp->next = lwp_process_list;
1327     lwp_process_list = lp;
1328     assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1329 }
1330
1331 /* The top-level routine used as entry point to explicitly created LWP
1332  * processes. This completes a few details of process creation left
1333  * out by LWP_CreateProcess and calls the user-specified entry point */
1334 static int
1335 lwp_top_level(pthread_addr_t argp)
1336 {
1337     PROCESS lp = (PROCESS) argp;
1338
1339     assert(!pthread_mutex_lock(&lwp_mutex));
1340     lwp_thread_process(lp);
1341     (lp->ep) (lp->arg);
1342     assert(!pthread_mutex_unlock(&lwp_mutex));
1343     /* Should cleanup state */
1344 }
1345
1346 int
1347 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1348                   void *parm, char *name, PROCESS * pid)
1349 {
1350     int status;
1351     pthread_attr_t attr;
1352     pthread_t handle;
1353     PROCESS lp;
1354
1355 #ifndef LWP_NO_PRIORITIES
1356     if (!cmalwp_pri_inrange(priority))
1357         return LWP_EBADPRI;
1358 #endif
1359     assert(!pthread_attr_create(&attr));
1360     assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1361     if (stacksize)
1362         assert(!pthread_attr_setstacksize(&attr, stacksize));
1363 #ifndef BDE_THREADS
1364     (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1365     (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1366 #ifndef LWP_NO_PRIORITIES
1367     (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1368 #endif
1369 #endif
1370     lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1371                            (pthread_addr_t) parm);
1372
1373     /* allow new thread to run if higher priority */
1374     assert(!pthread_mutex_unlock(&lwp_mutex));
1375     /* process is only added to active list after first time it runs (it adds itself) */
1376     status =
1377         pthread_create(&lp->handle, attr,
1378                        (pthread_startroutine_t) lwp_top_level,
1379                        (pthread_addr_t) lp);
1380     assert(!pthread_attr_delete(&attr));
1381     assert(!pthread_mutex_lock(&lwp_mutex));
1382     if (status != 0) {
1383         free(lp);
1384         return LWP_ENOMEM;
1385     }
1386     *pid = lp;
1387     return LWP_SUCCESS;
1388 }
1389
1390 PROCESS
1391 LWP_ActiveProcess(void)
1392 {                               /* returns pid of current process */
1393     PROCESS pid;
1394     assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1395     return pid;
1396 }
1397
1398 int
1399 LWP_CurrentProcess(PROCESS * pid)
1400 {                               /* get pid of current process */
1401     assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1402     return LWP_SUCCESS;
1403 }
1404
1405 int
1406 LWP_DestroyProcess(PROCESS pid)
1407 {                               /* destroy a lightweight process */
1408     lwp_unimplemented("LWP_DestroyProcess");
1409 }
1410
1411 int
1412 LWP_DispatchProcess(void)
1413 {                               /* explicit voluntary preemption */
1414     assert(!pthread_mutex_unlock(&lwp_mutex));
1415     pthread_yield();
1416     assert(!pthread_mutex_lock(&lwp_mutex));
1417     return LWP_SUCCESS;
1418 }
1419
1420 static int
1421 lwp_process_key_destructor(void)
1422 {
1423 }
1424
1425 int
1426 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1427 {
1428     static int initialized = 0;
1429     int status;
1430     static PROCESS lp;
1431     extern main;
1432     int state;
1433
1434     if (initialized) {
1435         *pid = lp;
1436         return LWP_SUCCESS;
1437     }
1438 #ifndef LWP_NO_PRIORITIES
1439     if (priority < 0 || priority > LWP_MAX_PRIORITY)
1440         return LWP_EBADPRI;
1441 #endif
1442
1443     /* Create pthread key to associate LWP process descriptor with each
1444      * LWP-created thread */
1445     assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1446                               lwp_process_key_destructor));
1447
1448     lp = lwp_alloc_process("main process", main, 0);
1449     lp->handle = pthread_self();
1450     lwp_thread_process(lp);
1451 #ifndef LWP_NO_PRIORITIES
1452     (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1453                                cmalwp_lwppri_to_cmapri(priority));
1454
1455 #endif
1456     assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1457     assert(pthread_mutex_lock(&lwp_mutex) == 0);
1458     initialized = 1;
1459     *pid = lp;
1460     return LWP_SUCCESS;
1461 }
1462
1463 int
1464 LWP_TerminateProcessSupport(void)
1465 {                               /* terminate all LWP support */
1466     lwp_unimplemented("LWP_TerminateProcessSupport");
1467 }
1468
1469 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1470 static event_t *
1471 getevent(char *event)
1472 {
1473     event_t *evp, *newp;
1474     int hashcode;
1475
1476     hashcode = hash(event);
1477     evp = hashtable[hashcode];
1478     newp = 0;
1479     while (evp) {
1480         if (evp->event == event) {
1481             evp->refcount++;
1482             return evp;
1483         }
1484         if (evp->refcount == 0)
1485             newp = evp;
1486         evp = evp->next;
1487     }
1488     if (!newp) {
1489         newp = (event_t *) malloc(sizeof(event_t));
1490         assert(newp);
1491         newp->next = hashtable[hashcode];
1492         hashtable[hashcode] = newp;
1493         assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1494         newp->seq = 0;
1495     }
1496     newp->event = event;
1497     newp->refcount = 1;
1498     return newp;
1499 }
1500
1501 /* Release the specified event */
1502 #define relevent(evp) ((evp)->refcount--)
1503
1504 int
1505 LWP_WaitProcess(char *event)
1506 {                               /* wait on a single event */
1507     struct event *ev;
1508     int seq;
1509     debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1510     if (event == NULL)
1511         return LWP_EBADEVENT;
1512     ev = getevent(event);
1513     seq = ev->seq;
1514     while (seq == ev->seq) {
1515         assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1516     }
1517     debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1518     relevent(ev);
1519     return LWP_SUCCESS;
1520 }
1521
1522 int
1523 LWP_MwaitProcess(int wcount, char *evlist[])
1524 {                               /* wait on m of n events */
1525     lwp_unimplemented("LWP_MWaitProcess");
1526 }
1527
1528 int
1529 LWP_NoYieldSignal(char *event)
1530 {
1531     struct event *ev;
1532     debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1533     if (event == NULL)
1534         return LWP_EBADEVENT;
1535     ev = getevent(event);
1536     if (ev->refcount > 1) {
1537         ev->seq++;
1538         assert(pthread_cond_broadcast(&ev->cond) == 0);
1539     }
1540     relevent(ev);
1541     return LWP_SUCCESS;
1542 }
1543
1544 int
1545 LWP_SignalProcess(char *event)
1546 {
1547     struct event *ev;
1548     debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1549     if (event == NULL)
1550         return LWP_EBADEVENT;
1551     ev = getevent(event);
1552     if (ev->refcount > 1) {
1553         ev->seq++;
1554         assert(!pthread_mutex_unlock(&lwp_mutex));
1555         assert(!pthread_cond_broadcast(&ev->cond));
1556         pthread_yield();
1557         assert(!pthread_mutex_lock(&lwp_mutex));
1558     }
1559     relevent(ev);
1560     return LWP_SUCCESS;
1561 }
1562
1563 int
1564 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1565 {
1566     lwp_unimplemented("LWP_StackUsed");
1567 }
1568
1569 int
1570 LWP_NewRock(int Tag, char *Value)
1571 {
1572     lwp_unimplemented("LWP_NewRock");
1573 }
1574
1575 int
1576 LWP_GetRock(int Tag, char **Value)
1577 {
1578     lwp_unimplemented("LWP_GetRock");
1579 }
1580
1581 int
1582 LWP_GetProcessPriority(PROCESS pid, int *priority)
1583 {                               /* returns process priority */
1584     lwp_unimplemented("LWP_GetProcessPriority");
1585 }
1586
1587 #endif /* USE_PTHREADS */