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