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