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