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