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