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