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