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