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