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