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