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