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