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