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