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