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