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