3ff9afc4bcdabb6562998b876950479b0bbb2cb7
[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 #include <roken.h>
21
22 /* allocate externs here */
23 #define  LWP_KERNEL
24 #include "lwp.h"
25
26 #ifdef  AFS_AIX32_ENV
27 #include <ulimit.h>
28 #include <sys/errno.h>
29 #include <sys/user.h>
30 #include <sys/pseg.h>
31 #include <sys/core.h>
32 #pragma alloca
33 int setlim(int limcon, uchar_t hard, int limit);
34 #endif
35
36 #ifndef AFS_ARM_LINUX20_ENV
37 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
38 int PRE_Block;  /* Remnants of preemption support. */
39 #else
40 char PRE_Block; /* Remnants of preemption support. */
41 #endif
42 #endif
43
44 #define ON              1
45 #define OFF             0
46 #define TRUE            1
47 #define FALSE           0
48 #define READY           2
49 #define WAITING         3
50 #define DESTROYED       4
51 #define QWAITING        5
52 #define MAXINT     (~(1<<((sizeof(int)*8)-1)))
53 #define MINSTACK   44
54
55 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
56 #define MINFRAME 128
57 #define STACK_ALIGN 8
58 #else
59 #ifdef __s390x__
60 #define MINFRAME    160
61 #define STACK_ALIGN 8
62 #else
63 #ifdef __s390__
64 #define MINFRAME    96
65 #define STACK_ALIGN 8
66 #elif defined(AFS_DARWIN_ENV)
67 #define STACK_ALIGN 16
68 #else
69 #define STACK_ALIGN 4
70 #endif
71 #endif
72 #endif
73
74 /* Debugging macro */
75 #ifdef DEBUG
76 #define Debug(level, msg) do {                                          \
77     if (lwp_debug && lwp_debug >= level) {                              \
78         printf("***LWP (0x%x): ", lwp_cpptr);                           \
79         printf msg;                                                     \
80         putchar('\n');                                                  \
81     }                                                                   \
82 } while (0)
83 #else
84 #define Debug(level, msg) do {                                          \
85     ;                                                                   \
86 } while (0)
87 #endif
88
89 static void Dispatcher(void);
90 static void Create_Process_Part2(void);
91 static void Exit_LWP(void);
92 static afs_int32 Initialize_Stack(char *stackptr, int stacksize);
93 static int Stack_Used(char *stackptr, int stacksize);
94
95 static void Abort_LWP(char *msg);
96 static void Overflow_Complain(void);
97 static void Initialize_PCB(PROCESS temp, int priority, char *stack,
98                            int stacksize, void *(*ep)(void *), void *parm,
99                            char *name);
100 static void Dispose_of_Dead_PCB(PROCESS cur);
101 static void Free_PCB(PROCESS pid);
102 static int Internal_Signal(void *event);
103 static int purge_dead_pcbs(void);
104 static int LWP_MwaitProcess(int wcount, void *evlist[]);
105
106
107 #define MAX_PRIORITIES  (LWP_MAX_PRIORITY+1)
108
109 struct QUEUE {
110     PROCESS head;
111     int count;
112 } runnable[MAX_PRIORITIES], blocked, qwaiting;
113 /* Invariant for runnable queues: The head of each queue points to the
114  * currently running process if it is in that queue, or it points to the
115  * next process in that queue that should run. */
116
117 /* Offset of stack field within pcb -- used by stack checking stuff */
118 int stack_offset;
119
120 /* special user-tweakable option for AIX */
121 int lwp_MaxStackSize = 32768;
122
123 /* biggest LWP stack created so far */
124 int lwp_MaxStackSeen = 0;
125
126 /* Stack checking action */
127 int lwp_overflowAction = LWP_SOABORT;
128
129 /* Controls stack size counting. */
130 int lwp_stackUseEnabled = TRUE; /* pay the price */
131
132 int lwp_nextindex;
133
134 /* Minimum stack size */
135 int lwp_MinStackSize = 0;
136
137 static int
138 lwp_remove(PROCESS p, struct QUEUE *q)
139 {
140     /* Special test for only element on queue */
141     if (q->count == 1)
142         q->head = NULL;
143     else {
144         /* Not only element, do normal remove */
145         p->next->prev = p->prev;
146         p->prev->next = p->next;
147     }
148     /* See if head pointing to this element */
149     if (q->head == p)
150         q->head = p->next;
151     q->count--;
152     p->next = p->prev = NULL;
153     return 0;
154 }
155
156 static int
157 insert(PROCESS p, struct QUEUE *q)
158 {
159     if (q->head == NULL) {      /* Queue is empty */
160         q->head = p;
161         p->next = p->prev = p;
162     } else {                    /* Regular insert */
163         p->prev = q->head->prev;
164         q->head->prev->next = p;
165         q->head->prev = p;
166         p->next = q->head;
167     }
168     q->count++;
169     return 0;
170 }
171
172 static int
173 move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
174 {
175
176     lwp_remove(p, from);
177
178     insert(p, to);
179     return 0;
180 }
181
182 /* Iterator macro */
183 #define for_all_elts(var, q, body)\
184         {\
185             PROCESS var, _NEXT_;\
186             int _I_;\
187             for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
188                 _NEXT_ = var -> next;\
189                 body\
190             }\
191         }
192
193 /*                                                                          */
194 /*****************************************************************************\
195 *                                                                             *
196 *  Following section documents the Assembler interfaces used by LWP code      *
197 *                                                                             *
198 \*****************************************************************************/
199
200 /*
201         savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
202
203 Stub for Assembler routine that will
204 save the current SP value in the passed
205 context savearea and call the function
206 whose entry point is in ep.  If the sp
207 parameter is NULL, the current stack is
208 used, otherwise sp becomes the new stack
209 pointer.
210
211         returnto(struct lwp_context *savearea);
212
213 Stub for Assembler routine that will
214 restore context from a passed savearea
215 and return to the restored C frame.
216
217 */
218
219 /* Macro to force a re-schedule.  Strange name is historical */
220 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
221
222 static struct lwp_ctl *lwp_init = 0;
223
224 int
225 LWP_QWait(void)
226 {
227     PROCESS tp;
228     (tp = lwp_cpptr)->status = QWAITING;
229     move(tp, &runnable[tp->priority], &qwaiting);
230     Set_LWP_RC();
231     return LWP_SUCCESS;
232 }
233
234 int
235 LWP_QSignal(PROCESS pid)
236 {
237     if (pid->status == QWAITING) {
238         pid->status = READY;
239         move(pid, &qwaiting, &runnable[pid->priority]);
240         return LWP_SUCCESS;
241     } else
242         return LWP_ENOWAIT;
243 }
244
245 #ifdef  AFS_AIX32_ENV
246 char *
247 reserveFromStack(afs_int32 size)
248 {
249     char *x;
250     x = alloca(size);
251     return x;
252 }
253 #endif
254
255 int
256 LWP_CreateProcess(void *(*ep) (void *), int stacksize, int priority, void *parm,
257                   char *name, PROCESS * pid)
258 {
259     PROCESS temp, temp2;
260 #ifdef  AFS_AIX32_ENV
261     static char *stackptr = 0;
262 #else
263     char *stackptr;
264 #endif
265     char *stackmemory;
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 = malloc(sizeof(struct lwp_pcb));
285         if (temp == NULL) {
286             Set_LWP_RC();
287             return LWP_ENOMEM;
288         }
289         if (stacksize < MINSTACK)
290 #ifdef AFS_DARWIN_ENV
291             stacksize = 1008;
292 #else /* !AFS_DARWIN_ENV */
293             stacksize = 1000;
294 #endif /* !AFS_DARWIN_ENV */
295         else
296             stacksize =
297                 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
298 #ifdef  AFS_AIX32_ENV
299         if (!stackptr) {
300             /*
301              * The following signal action for AIX is necessary so that in case of a
302              * crash (i.e. core is generated) we can include the user's data section
303              * in the core dump. Unfortunately, by default, only a partial core is
304              * generated which, in many cases, isn't too useful.
305              *
306              * We also do it here in case the main program forgets to do it.
307              */
308             struct sigaction nsa;
309             extern uid_t geteuid();
310
311             sigemptyset(&nsa.sa_mask);
312             nsa.sa_handler = SIG_DFL;
313             nsa.sa_flags = SA_FULLDUMP;
314             sigaction(SIGABRT, &nsa, NULL);
315             sigaction(SIGSEGV, &nsa, NULL);
316
317             /*
318              * First we need to increase the default resource limits,
319              * if necessary, so that we can guarantee that we have the
320              * resources to create the core file, but we can't always
321              * do it as an ordinary user.
322              */
323             if (!geteuid()) {
324                 /* vos dump causes problems */
325                 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
326                 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
327                 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
328             }
329             /*
330              * Now reserve in one scoop all the stack space that will be used
331              * by the particular application's main (i.e. non-lwp) body. This
332              * is plenty space for any of our applications.
333              */
334             stackptr = reserveFromStack(lwp_MaxStackSize);
335         }
336         stackptr -= stacksize;
337         stackmemory = stackptr;
338 #else
339 #ifdef AFS_DARWIN_ENV
340         if ((stackmemory = malloc(stacksize + STACK_ALIGN - 1)) == NULL)
341 #else /* !AFS_DARWIN_ENV */
342         if ((stackmemory = malloc(stacksize + 7)) == NULL)
343 #endif /* !AFS_DARWIN_ENV */
344         {
345             free(temp);
346             Set_LWP_RC();
347             return LWP_ENOMEM;
348         }
349         /* Round stack pointer to byte boundary */
350 #ifdef AFS_DARWIN_ENV
351         stackptr = (char *)(STACK_ALIGN * (((long)stackmemory + STACK_ALIGN - 1) / STACK_ALIGN));
352 #else /* !AFS_DARWIN_ENV */
353         stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
354 #endif /* !AFS_DARWIN_ENV */
355 #endif
356         if (priority < 0 || priority >= MAX_PRIORITIES) {
357             free(temp);
358             free(stackmemory);
359             Set_LWP_RC();
360             return LWP_EBADPRI;
361         }
362         Initialize_Stack(stackptr, stacksize);
363         Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
364         insert(temp, &runnable[priority]);
365         temp2 = lwp_cpptr;
366 #if !defined(AFS_ARM_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
367         if (PRE_Block != 0)
368             Abort_LWP("PRE_Block not 0");
369
370         /* Gross hack: beware! */
371         PRE_Block = 1;
372 #endif
373         lwp_cpptr = temp;
374 #if defined(AFS_PARISC_LINUX24_ENV)
375         savecontext(Create_Process_Part2, &temp2->context,
376                     stackptr + MINFRAME);
377 #else
378 #ifdef __hp9000s800
379         savecontext(Create_Process_Part2, &temp2->context,
380                     stackptr + MINFRAME);
381 #else
382 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
383 #ifdef sys_x86_darwin_80
384         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16 - sizeof(void *)); /* 16 = 2 * jmp_buf_type */
385 #else /* !sys_x86_darwin_80 */
386         /* Need to have the sp on an 8-byte boundary for storing doubles. */
387         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16);  /* 16 = 2 * jmp_buf_type */
388 #endif /* !sys_x86_darwin_80 */
389 #else
390 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
391         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40);        /* lomgjmp does something
392                                                                                                  * with %fp + 0x38 */
393 #else
394 #if defined(AFS_S390_LINUX20_ENV)
395         savecontext(Create_Process_Part2, &temp2->context,
396                     stackptr + stacksize - MINFRAME);
397 #else /* !AFS_S390_LINUX20_ENV */
398         savecontext(Create_Process_Part2, &temp2->context,
399                     stackptr + stacksize - sizeof(void *));
400 #endif /* AFS_S390_LINUX20_ENV */
401 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
402 #endif /* AFS_SGI62_ENV */
403 #endif
404 #endif
405         /* End of gross hack */
406
407         Set_LWP_RC();
408         if (pid)
409             *pid = temp;
410         return 0;
411     } else
412         return LWP_EINIT;
413 }
414
415 #ifdef  AFS_AIX32_ENV
416 int
417 LWP_CreateProcess2(void *(*ep) (void *), int stacksize, int priority, void *parm,
418                    char *name, PROCESS * pid)
419 {
420     PROCESS temp, temp2;
421     char *stackptr;
422
423 #if defined(AFS_LWP_MINSTACKSIZE)
424     /*
425      * on some systems (e.g. hpux), a minimum usable stack size has
426      * been discovered
427      */
428     if (stacksize < lwp_MinStackSize) {
429         stacksize = lwp_MinStackSize;
430     }
431 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
432     /* more stack size computations; keep track of for IOMGR */
433     if (lwp_MaxStackSeen < stacksize)
434         lwp_MaxStackSeen = stacksize;
435
436     Debug(0, ("Entered LWP_CreateProcess"));
437     /* Throw away all dead process control blocks */
438     purge_dead_pcbs();
439     if (lwp_init) {
440         temp = malloc(sizeof(struct lwp_pcb));
441         if (temp == NULL) {
442             Set_LWP_RC();
443             return LWP_ENOMEM;
444         }
445         if (stacksize < MINSTACK)
446             stacksize = 1000;
447         else
448             stacksize =
449                 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
450         if ((stackptr = malloc(stacksize)) == NULL) {
451             Set_LWP_RC();
452             return LWP_ENOMEM;
453         }
454         if (priority < 0 || priority >= MAX_PRIORITIES) {
455             Set_LWP_RC();
456             return LWP_EBADPRI;
457         }
458         Initialize_Stack(stackptr, stacksize);
459         Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
460         insert(temp, &runnable[priority]);
461         temp2 = lwp_cpptr;
462 #if !defined(AFS_ARM_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
463         if (PRE_Block != 0)
464             Abort_LWP("PRE_Block not 0");
465
466         /* Gross hack: beware! */
467         PRE_Block = 1;
468 #endif
469         lwp_cpptr = temp;
470         savecontext(Create_Process_Part2, &temp2->context,
471                     stackptr + stacksize - sizeof(void *));
472         /* End of gross hack */
473
474         Set_LWP_RC();
475         if (pid)
476             *pid = temp;
477         return 0;
478     } else
479         return LWP_EINIT;
480 }
481 #endif
482
483 int
484 LWP_CurrentProcess(PROCESS * pid)
485 {                               /* returns pid of current process */
486     Debug(0, ("Entered Current_Process"));
487     if (lwp_init) {
488         *pid = lwp_cpptr;
489         return LWP_SUCCESS;
490     } else
491         return LWP_EINIT;
492 }
493
494 PROCESS
495 LWP_ThreadId(void)
496 {
497     Debug(0, ("Entered ThreadId"));
498     if (lwp_init)
499         return lwp_cpptr;
500     else
501         return (PROCESS) 0;
502 }
503
504 #define LWPANCHOR (*lwp_init)
505
506 int
507 LWP_DestroyProcess(PROCESS pid)
508 {                               /* destroy a lightweight process */
509     PROCESS temp;
510
511     Debug(0, ("Entered Destroy_Process"));
512     if (lwp_init) {
513         if (lwp_cpptr != pid) {
514             Dispose_of_Dead_PCB(pid);
515             Set_LWP_RC();
516         } else {
517             pid->status = DESTROYED;
518             move(pid, &runnable[pid->priority], &blocked);
519             temp = lwp_cpptr;
520 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
521             savecontext(Dispatcher, &(temp->context),
522                         &(LWPANCHOR.dsptchstack[MINFRAME]));
523 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
524             savecontext(Dispatcher, &(temp->context),
525                         &(LWPANCHOR.
526                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
527 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
528             savecontext(Dispatcher, &(temp->context),
529                         &(LWPANCHOR.
530                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
531                                       0x40]));
532 #elif defined(AFS_S390_LINUX20_ENV)
533             savecontext(Dispatcher, &(temp->context),
534                         &(LWPANCHOR.
535                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
536                                       MINFRAME]));
537 #else
538             savecontext(Dispatcher, &(temp->context),
539                         &(LWPANCHOR.
540                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
541                                       sizeof(void *)]));
542 #endif
543         }
544         return LWP_SUCCESS;
545     } else
546         return LWP_EINIT;
547 }
548
549 int
550 LWP_DispatchProcess(void)
551 {                               /* explicit voluntary preemption */
552     Debug(2, ("Entered Dispatch_Process"));
553     if (lwp_init) {
554         Set_LWP_RC();
555         return LWP_SUCCESS;
556     } else
557         return LWP_EINIT;
558 }
559
560 #ifdef DEBUG
561 int
562 Dump_Processes(void)
563 {
564     if (lwp_init) {
565         int i;
566         for (i = 0; i < MAX_PRIORITIES; i++)
567             for_all_elts(x, runnable[i], {
568                          printf("[Priority %d]\n", i);
569                          Dump_One_Process(x);
570                          }
571         )
572             for_all_elts(x, blocked, {
573                          Dump_One_Process(x);}
574         )
575             for_all_elts(x, qwaiting, {
576                          Dump_One_Process(x);}
577         )
578     } else
579         printf("***LWP: LWP support not initialized\n");
580     return 0;
581 }
582 #endif
583
584 int
585 LWP_GetProcessPriority(PROCESS pid, int *priority)
586 {                               /* returns process priority */
587     Debug(0, ("Entered Get_Process_Priority"));
588     if (lwp_init) {
589         *priority = pid->priority;
590         return 0;
591     } else
592         return LWP_EINIT;
593 }
594
595 int
596 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
597 {
598     PROCESS temp;
599     struct lwp_pcb dummy;
600     int i;
601     char *value;
602
603     Debug(0, ("Entered LWP_InitializeProcessSupport"));
604     if (lwp_init != NULL)
605         return LWP_SUCCESS;
606
607     /* Set up offset for stack checking -- do this as soon as possible */
608     stack_offset = (char *)&dummy.stack - (char *)&dummy;
609
610     if (priority >= MAX_PRIORITIES)
611         return LWP_EBADPRI;
612     for (i = 0; i < MAX_PRIORITIES; i++) {
613         runnable[i].head = NULL;
614         runnable[i].count = 0;
615     }
616     blocked.head = NULL;
617     blocked.count = 0;
618     qwaiting.head = NULL;
619     qwaiting.count = 0;
620     lwp_init = malloc(sizeof(struct lwp_ctl));
621     temp = malloc(sizeof(struct lwp_pcb));
622     if (lwp_init == NULL || temp == NULL)
623         Abort_LWP("Insufficient Storage to Initialize LWP Support");
624     LWPANCHOR.processcnt = 1;
625     LWPANCHOR.outerpid = temp;
626     LWPANCHOR.outersp = NULL;
627     Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
628                    "Main Process [created by LWP]");
629     insert(temp, &runnable[priority]);
630     savecontext(Dispatcher, &temp->context, NULL);
631     LWPANCHOR.outersp = temp->context.topstack;
632     Set_LWP_RC();
633     if (pid)
634         *pid = temp;
635
636     /* get minimum stack size from the environment. this allows the  administrator
637      * to change the lwp stack dynamically without getting a new binary version.
638      */
639     if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
640         lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
641     else
642         lwp_MinStackSize =
643             (AFS_LWP_MINSTACKSIZE >
644              atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
645
646     return LWP_SUCCESS;
647 }
648
649 int
650 LWP_INTERNALSIGNAL(void *event, int yield)
651 {                               /* signal the occurence of an event */
652     Debug(2, ("Entered LWP_SignalProcess"));
653     if (lwp_init) {
654         int rc;
655         rc = Internal_Signal(event);
656         if (yield)
657             Set_LWP_RC();
658         return rc;
659     } else
660         return LWP_EINIT;
661 }
662
663 int
664 LWP_TerminateProcessSupport(void)
665 {                               /* terminate all LWP support */
666     int i;
667
668     Debug(0, ("Entered Terminate_Process_Support"));
669     if (lwp_init == NULL)
670         return LWP_EINIT;
671     if (lwp_cpptr != LWPANCHOR.outerpid)
672         Abort_LWP("Terminate_Process_Support invoked from wrong process!");
673     for (i = 0; i < MAX_PRIORITIES; i++)
674         for_all_elts(cur, runnable[i], {
675                      Free_PCB(cur);}
676     )
677         for_all_elts(cur, blocked, {
678                      Free_PCB(cur);}
679     )
680         for_all_elts(cur, qwaiting, {
681                      Free_PCB(cur);}
682     )
683         free(lwp_init);
684     lwp_init = NULL;
685     return LWP_SUCCESS;
686 }
687
688 int
689 LWP_WaitProcess(void *event)
690 {                               /* wait on a single event */
691     void *tempev[2];
692
693     Debug(2, ("Entered Wait_Process"));
694     if (event == NULL)
695         return LWP_EBADEVENT;
696     tempev[0] = event;
697     tempev[1] = NULL;
698     return LWP_MwaitProcess(1, tempev);
699 }
700
701 int
702 LWP_MwaitProcess(int wcount, void *evlist[])
703 {                               /* wait on m of n events */
704     int ecount, i;
705
706
707     Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
708
709     if (evlist == NULL) {
710         Set_LWP_RC();
711         return LWP_EBADCOUNT;
712     }
713
714     for (ecount = 0; evlist[ecount] != NULL; ecount++);
715
716     if (ecount == 0) {
717         Set_LWP_RC();
718         return LWP_EBADCOUNT;
719     }
720
721     if (lwp_init) {
722
723         if (wcount > ecount || wcount < 0) {
724             Set_LWP_RC();
725             return LWP_EBADCOUNT;
726         }
727         if (ecount > lwp_cpptr->eventlistsize) {
728
729             lwp_cpptr->eventlist = realloc(lwp_cpptr->eventlist,
730                                            ecount * sizeof(void *));
731             lwp_cpptr->eventlistsize = ecount;
732         }
733         for (i = 0; i < ecount; i++)
734             lwp_cpptr->eventlist[i] = evlist[i];
735         if (wcount > 0) {
736             lwp_cpptr->status = WAITING;
737
738             move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
739
740         }
741         lwp_cpptr->wakevent = 0;
742         lwp_cpptr->waitcnt = wcount;
743         lwp_cpptr->eventcnt = ecount;
744
745         Set_LWP_RC();
746
747         return LWP_SUCCESS;
748     }
749
750     return LWP_EINIT;
751 }
752
753 int
754 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
755 {
756     *maxa = pid->stacksize;
757     *used = Stack_Used(pid->stack, *maxa);
758     if (*used == 0)
759         return LWP_NO_STACK;
760     return LWP_SUCCESS;
761 }
762
763 /*
764  *  The following functions are strictly
765  *  INTERNAL to the LWP support package.
766  */
767
768 static void
769 Abort_LWP(char *msg)
770 {
771     struct lwp_context tempcontext;
772
773     Debug(0, ("Entered Abort_LWP"));
774     printf("***LWP: %s\n", msg);
775     printf("***LWP: Abort --- dumping PCBs ...\n");
776 #ifdef DEBUG
777     Dump_Processes();
778 #endif
779     if (LWPANCHOR.outersp == NULL)
780         Exit_LWP();
781     else
782         savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
783     return;
784 }
785
786 static void
787 Create_Process_Part2(void)
788 {                               /* creates a context for the new process */
789     PROCESS temp;
790
791     Debug(2, ("Entered Create_Process_Part2"));
792     temp = lwp_cpptr;           /* Get current process id */
793     savecontext(Dispatcher, &temp->context, NULL);
794     (*temp->ep) (temp->parm);
795     LWP_DestroyProcess(temp);
796     return;
797 }
798
799 static int
800 Delete_PCB(PROCESS pid)
801 {                               /* remove a PCB from the process list */
802     Debug(4, ("Entered Delete_PCB"));
803     lwp_remove(pid,
804                (pid->blockflag || pid->status == WAITING
805                 || pid->status ==
806                 DESTROYED ? &blocked :
807                 (pid->status == QWAITING) ? &qwaiting :
808                 &runnable[pid->priority]));
809     LWPANCHOR.processcnt--;
810     return 0;
811 }
812
813 #ifdef DEBUG
814 static int
815 Dump_One_Process(PROCESS pid)
816 {
817     int i;
818
819     printf("***LWP: Process Control Block at 0x%x\n", pid);
820     printf("***LWP: Name: %s\n", pid->name);
821     if (pid->ep != NULL)
822         printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
823     if (pid->blockflag)
824         printf("BLOCKED and ");
825     switch (pid->status) {
826     case READY:
827         printf("READY");
828         break;
829     case WAITING:
830         printf("WAITING");
831         break;
832     case DESTROYED:
833         printf("DESTROYED");
834         break;
835     case QWAITING:
836         printf("QWAITING");
837         break;
838     default:
839         printf("unknown");
840     }
841     putchar('\n');
842     printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
843            pid->parm);
844     if (pid->stacksize != 0) {
845         printf("***LWP:  Stacksize: %d \tStack base address: 0x%x\n",
846                pid->stacksize, pid->stack);
847         printf("***LWP: HWM stack usage: ");
848         printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
849     }
850     printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
851     if (pid->eventcnt > 0) {
852         printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
853         printf("***LWP: Event id list:");
854         for (i = 0; i < pid->eventcnt; i++)
855             printf(" 0x%x", pid->eventlist[i]);
856         putchar('\n');
857     }
858     if (pid->wakevent > 0)
859         printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
860     return 0;
861 }
862 #endif
863
864 static int
865 purge_dead_pcbs(void)
866 {
867     for_all_elts(cur, blocked, {
868                  if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
869     )
870         return 0;
871 }
872
873 int LWP_TraceProcesses = 0;
874
875 static void
876 Dispatcher(void)
877 {                               /* Lightweight process dispatcher */
878     int i;
879 #ifdef DEBUG
880     static int dispatch_count = 0;
881
882     if (LWP_TraceProcesses > 0) {
883         for (i = 0; i < MAX_PRIORITIES; i++) {
884             printf("[Priority %d, runnable (%d):", i, runnable[i].count);
885             for_all_elts(p, runnable[i], {
886                          printf(" \"%s\"", p->name);
887                          }
888             )
889                 puts("]");
890         }
891         printf("[Blocked (%d):", blocked.count);
892         for_all_elts(p, blocked, {
893                      printf(" \"%s\"", p->name);
894                      }
895         )
896         puts("]");
897         printf("[Qwaiting (%d):", qwaiting.count);
898         for_all_elts(p, qwaiting, {
899                      printf(" \"%s\"", p->name);
900                      }
901         )
902         puts("]");
903     }
904 #endif
905
906     /* Check for stack overflowif this lwp has a stack.  Check for
907      * the guard word at the front of the stack being damaged and
908      * for the stack pointer being below the front of the stack.
909      * WARNING!  This code assumes that stacks grow downward. */
910 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
911     /* Fix this (stackcheck at other end of stack?) */
912     if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
913         && (lwp_cpptr->stackcheck !=
914             *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
915             || lwp_cpptr->context.topstack >
916             lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
917 #else
918     if (lwp_cpptr && lwp_cpptr->stack
919         && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
920             || lwp_cpptr->context.topstack < lwp_cpptr->stack
921             || lwp_cpptr->context.topstack >
922             (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
923 #endif
924         printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
925                *(int *)lwp_cpptr->stack);
926         printf("topstack = 0x%" AFS_PTR_FMT ": stackptr = 0x%" AFS_PTR_FMT ": stacksize = 0x%x\n",
927                (void *)(uintptr_t)lwp_cpptr->context.topstack,
928                (void *)(uintptr_t)lwp_cpptr->stack,
929                lwp_cpptr->stacksize);
930
931         switch (lwp_overflowAction) {
932         case LWP_SOQUIET:
933             break;
934         case LWP_SOABORT:
935             Overflow_Complain();
936             abort();
937         case LWP_SOMESSAGE:
938         default:
939             Overflow_Complain();
940             lwp_overflowAction = LWP_SOQUIET;
941             break;
942         }
943     }
944
945     /* Move head of current runnable queue forward if current LWP is still in it. */
946     if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
947         runnable[lwp_cpptr->priority].head =
948             runnable[lwp_cpptr->priority].head->next;
949     /* Find highest priority with runnable processes. */
950     for (i = MAX_PRIORITIES - 1; i >= 0; i--)
951         if (runnable[i].head != NULL)
952             break;
953
954     if (i < 0)
955         Abort_LWP("No READY processes");
956
957 #ifdef DEBUG
958     if (LWP_TraceProcesses > 0)
959         printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
960                runnable[i].head, runnable[i].head->name);
961 #endif
962 #if !defined(AFS_ARM_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
963     if (PRE_Block != 1)
964         Abort_LWP("PRE_Block not 1");
965 #endif
966     lwp_cpptr = runnable[i].head;
967
968     returnto(&lwp_cpptr->context);
969
970     return; /* not reachable */
971 }
972
973 /* Complain of a stack overflow to stderr without using stdio. */
974 static void
975 Overflow_Complain(void)
976 {
977     time_t currenttime;
978     char *timeStamp;
979     char *msg1 = " LWP: stack overflow in process ";
980     char *msg2 = "!\n";
981
982     currenttime = time(0);
983     timeStamp = ctime(&currenttime);
984     timeStamp[24] = 0;
985     if (write(2, timeStamp, strlen(timeStamp)) < 0)
986         return;
987
988     if (write(2, msg1, strlen(msg1)) < 0)
989         return;
990     if (write(2, lwp_cpptr->name, strlen(lwp_cpptr->name)) < 0)
991         return;
992     if (write(2, msg2, strlen(msg2)) < 0)
993         return;
994 }
995
996 static void
997 Dispose_of_Dead_PCB(PROCESS cur)
998 {
999     Debug(4, ("Entered Dispose_of_Dead_PCB"));
1000     Delete_PCB(cur);
1001     Free_PCB(cur);
1002 /*
1003     Internal_Signal(cur);
1004 */
1005 }
1006
1007 static void
1008 Exit_LWP(void)
1009 {
1010     abort();
1011 }
1012
1013 static void
1014 Free_PCB(PROCESS pid)
1015 {
1016     Debug(4, ("Entered Free_PCB"));
1017     if (pid->stack != NULL) {
1018         Debug(0,
1019               ("HWM stack usage: %d, [PCB at 0x%x]",
1020                Stack_Used(pid->stack, pid->stacksize), pid));
1021 #ifndef AFS_AIX32_ENV
1022         free(pid->stack);
1023 #endif
1024     }
1025     if (pid->eventlist != NULL)
1026         free(pid->eventlist);
1027     free(pid);
1028 }
1029
1030 static void
1031 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1032                void *(*ep) (void *), void *parm, char *name)
1033 {
1034     int i = 0;
1035
1036     Debug(4, ("Entered Initialize_PCB"));
1037     if (name != NULL)
1038         while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1039             i++;
1040     temp->name[31] = '\0';
1041     temp->status = READY;
1042     temp->eventlist = malloc(EVINITSIZE * sizeof(void *));
1043     temp->eventlistsize = EVINITSIZE;
1044     temp->eventcnt = 0;
1045     temp->wakevent = 0;
1046     temp->waitcnt = 0;
1047     temp->blockflag = 0;
1048     temp->iomgrRequest = 0;
1049     temp->priority = priority;
1050     temp->index = lwp_nextindex++;
1051     temp->stack = stack;
1052     temp->stacksize = stacksize;
1053 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1054     if (temp->stack != NULL)
1055         temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1056 #else
1057     if (temp->stack != NULL)
1058         temp->stackcheck = *(int *)(temp->stack);
1059 #endif
1060     temp->ep = ep;
1061     temp->parm = parm;
1062     temp->misc = NULL;          /* currently unused */
1063     temp->next = NULL;
1064     temp->prev = NULL;
1065     temp->lwp_rused = 0;
1066     temp->level = 1;            /* non-preemptable */
1067 }
1068
1069 static int
1070 Internal_Signal(void *event)
1071 {
1072     int rc = LWP_ENOWAIT;
1073     int i;
1074
1075     Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1076     if (!lwp_init)
1077         return LWP_EINIT;
1078     if (event == NULL)
1079         return LWP_EBADEVENT;
1080     for_all_elts(temp, blocked, {
1081                  if (temp->status == WAITING)
1082                  for (i = 0; i < temp->eventcnt; i++) {
1083                  if (temp->eventlist[i] == event) {
1084                  temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1085                  Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1086                  if (--temp->waitcnt == 0) {
1087                  temp->status = READY; temp->wakevent = i + 1;
1088                  move(temp, &blocked, &runnable[temp->priority]); break;}
1089                  }
1090                  }
1091                  }
1092     )
1093         return rc;
1094 }
1095
1096 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1097 #define STACKMAGIC      0xBADBADBA
1098 static afs_int32
1099 Initialize_Stack(char *stackptr, int stacksize)
1100 {
1101     int i;
1102
1103     Debug(4, ("Entered Initialize_Stack"));
1104     if (lwp_stackUseEnabled)
1105         for (i = 0; i < stacksize; i++)
1106             stackptr[i] = i & 0xff;
1107     else
1108 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1109         *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1110 #else
1111         *(afs_int32 *) stackptr = STACKMAGIC;
1112 #endif
1113     return 0;
1114 }
1115
1116 static int
1117 Stack_Used(char *stackptr, int stacksize)
1118 {
1119     int i;
1120
1121 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1122     if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1123         return 0;
1124     else {
1125         for (i = stacksize - 1; i >= 0; i--)
1126             if ((unsigned char)stackptr[i] != (i & 0xff))
1127                 return (i);
1128         return 0;
1129     }
1130 #else
1131     if (*(afs_int32 *) stackptr == STACKMAGIC)
1132         return 0;
1133     else {
1134         for (i = 0; i < stacksize; i++)
1135             if ((unsigned char)stackptr[i] != (i & 0xff))
1136                 return (stacksize - i);
1137         return 0;
1138     }
1139 #endif
1140 }
1141
1142
1143 int
1144 LWP_NewRock(int Tag, char *Value)
1145     /* Finds a free rock and sets its value to Value.
1146      * Return codes:
1147      * LWP_SUCCESS      Rock did not exist and a new one was used
1148      * LWP_EBADROCK     Rock already exists.
1149      * LWP_ENOROCKS     All rocks are in use.
1150      *
1151      * From the above semantics, you can only set a rock value once.  This is specifically
1152      * to prevent multiple users of the LWP package from accidentally using the same Tag
1153      * value and clobbering others.  You can always use one level of indirection to obtain
1154      * a rock whose contents can change.
1155      */
1156 {
1157     int i;
1158     struct rock *ra;    /* rock array */
1159
1160     ra = lwp_cpptr->lwp_rlist;
1161
1162     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1163         if (ra[i].tag == Tag)
1164             return (LWP_EBADROCK);
1165
1166     if (lwp_cpptr->lwp_rused < MAXROCKS) {
1167         ra[lwp_cpptr->lwp_rused].tag = Tag;
1168         ra[lwp_cpptr->lwp_rused].value = Value;
1169         lwp_cpptr->lwp_rused++;
1170         return (LWP_SUCCESS);
1171     } else
1172         return (LWP_ENOROCKS);
1173 }
1174
1175
1176 int
1177 LWP_GetRock(int Tag, char **Value)
1178     /* Obtains the pointer Value associated with the rock Tag of this LWP.
1179      * Returns:
1180      * LWP_SUCCESS              if specified rock exists and Value has been filled
1181      * LWP_EBADROCK     rock specified does not exist
1182      */
1183 {
1184     int i;
1185     struct rock *ra;
1186
1187     ra = lwp_cpptr->lwp_rlist;
1188
1189     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1190         if (ra[i].tag == Tag) {
1191             *Value = ra[i].value;
1192             return (LWP_SUCCESS);
1193         }
1194     return (LWP_EBADROCK);
1195 }
1196
1197
1198 #ifdef  AFS_AIX32_ENV
1199 int
1200 setlim(int limcon, uchar_t hard, int limit)
1201 {
1202     struct rlimit rlim;
1203
1204     (void)getrlimit(limcon, &rlim);
1205
1206     limit = limit * 1024;
1207     if (hard)
1208         rlim.rlim_max = limit;
1209     else if (limit == RLIM_INFINITY && geteuid() != 0)
1210         rlim.rlim_cur = rlim.rlim_max;
1211     else
1212         rlim.rlim_cur = limit;
1213
1214     /* Must use ulimit() due to Posix constraints */
1215     if (limcon == RLIMIT_FSIZE) {
1216         if (ulimit
1217             (UL_SETFSIZE,
1218              ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1219             printf("Can't %s%s limit\n",
1220                    limit == RLIM_INFINITY ? "remove" : "set",
1221                    hard ? " hard" : "");
1222             return (-1);
1223         }
1224     } else {
1225         if (setrlimit(limcon, &rlim) < 0) {
1226             perror("");
1227             printf("Can't %s%s limit\n",
1228                    limit == RLIM_INFINITY ? "remove" : "set",
1229                    hard ? " hard" : "");
1230             return (-1);
1231         }
1232     }
1233     return (0);
1234 }
1235 #endif
1236
1237 #ifdef  AFS_SUN5_ENV
1238 int
1239 LWP_NoYieldSignal(void *event)
1240 {
1241     return (LWP_INTERNALSIGNAL(event, 0));
1242 }
1243
1244 int
1245 LWP_SignalProcess(void *event)
1246 {
1247     return (LWP_INTERNALSIGNAL(event, 1));
1248 }
1249
1250 #endif