libwp: Tidy header includes
[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 extern int PRE_Block;           /* from preempt.c */
39 #else
40 extern char PRE_Block;          /* from preempt.c */
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 = (PROCESS) 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 = (char *)malloc(stacksize + STACK_ALIGN - 1)) == NULL)
341 #else /* !AFS_DARWIN_ENV */
342         if ((stackmemory = (char *)malloc(stacksize + 7)) == NULL)
343 #endif /* !AFS_DARWIN_ENV */
344         {
345             Set_LWP_RC();
346             return LWP_ENOMEM;
347         }
348         /* Round stack pointer to byte boundary */
349 #ifdef AFS_DARWIN_ENV
350         stackptr = (char *)(STACK_ALIGN * (((long)stackmemory + STACK_ALIGN - 1) / STACK_ALIGN));
351 #else /* !AFS_DARWIN_ENV */
352         stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
353 #endif /* !AFS_DARWIN_ENV */
354 #endif
355         if (priority < 0 || priority >= MAX_PRIORITIES) {
356             Set_LWP_RC();
357             return LWP_EBADPRI;
358         }
359         Initialize_Stack(stackptr, stacksize);
360         Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
361         insert(temp, &runnable[priority]);
362         temp2 = lwp_cpptr;
363 #if !defined(AFS_ARM_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
364         if (PRE_Block != 0)
365             Abort_LWP("PRE_Block not 0");
366
367         /* Gross hack: beware! */
368         PRE_Block = 1;
369 #endif
370         lwp_cpptr = temp;
371 #if defined(AFS_PARISC_LINUX24_ENV)
372         savecontext(Create_Process_Part2, &temp2->context,
373                     stackptr + MINFRAME);
374 #else
375 #ifdef __hp9000s800
376         savecontext(Create_Process_Part2, &temp2->context,
377                     stackptr + MINFRAME);
378 #else
379 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
380 #ifdef sys_x86_darwin_80
381         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16 - sizeof(void *)); /* 16 = 2 * jmp_buf_type */
382 #else /* !sys_x86_darwin_80 */
383         /* Need to have the sp on an 8-byte boundary for storing doubles. */
384         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16);  /* 16 = 2 * jmp_buf_type */
385 #endif /* !sys_x86_darwin_80 */
386 #else
387 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
388         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40);        /* lomgjmp does something
389                                                                                                  * with %fp + 0x38 */
390 #else
391 #if defined(AFS_S390_LINUX20_ENV)
392         savecontext(Create_Process_Part2, &temp2->context,
393                     stackptr + stacksize - MINFRAME);
394 #else /* !AFS_S390_LINUX20_ENV */
395         savecontext(Create_Process_Part2, &temp2->context,
396                     stackptr + stacksize - sizeof(void *));
397 #endif /* AFS_S390_LINUX20_ENV */
398 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
399 #endif /* AFS_SGI62_ENV */
400 #endif
401 #endif
402         /* End of gross hack */
403
404         Set_LWP_RC();
405         if (pid)
406             *pid = temp;
407         return 0;
408     } else
409         return LWP_EINIT;
410 }
411
412 #ifdef  AFS_AIX32_ENV
413 int
414 LWP_CreateProcess2(void *(*ep) (void *), int stacksize, int priority, void *parm,
415                    char *name, PROCESS * pid)
416 {
417     PROCESS temp, temp2;
418     char *stackptr;
419
420 #if defined(AFS_LWP_MINSTACKSIZE)
421     /*
422      * on some systems (e.g. hpux), a minimum usable stack size has
423      * been discovered
424      */
425     if (stacksize < lwp_MinStackSize) {
426         stacksize = lwp_MinStackSize;
427     }
428 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
429     /* more stack size computations; keep track of for IOMGR */
430     if (lwp_MaxStackSeen < stacksize)
431         lwp_MaxStackSeen = stacksize;
432
433     Debug(0, ("Entered LWP_CreateProcess"));
434     /* Throw away all dead process control blocks */
435     purge_dead_pcbs();
436     if (lwp_init) {
437         temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
438         if (temp == NULL) {
439             Set_LWP_RC();
440             return LWP_ENOMEM;
441         }
442         if (stacksize < MINSTACK)
443             stacksize = 1000;
444         else
445             stacksize =
446                 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
447         if ((stackptr = (char *)malloc(stacksize)) == NULL) {
448             Set_LWP_RC();
449             return LWP_ENOMEM;
450         }
451         if (priority < 0 || priority >= MAX_PRIORITIES) {
452             Set_LWP_RC();
453             return LWP_EBADPRI;
454         }
455         Initialize_Stack(stackptr, stacksize);
456         Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
457         insert(temp, &runnable[priority]);
458         temp2 = lwp_cpptr;
459 #if !defined(AFS_ARM_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
460         if (PRE_Block != 0)
461             Abort_LWP("PRE_Block not 0");
462
463         /* Gross hack: beware! */
464         PRE_Block = 1;
465 #endif
466         lwp_cpptr = temp;
467         savecontext(Create_Process_Part2, &temp2->context,
468                     stackptr + stacksize - sizeof(void *));
469         /* End of gross hack */
470
471         Set_LWP_RC();
472         if (pid)
473             *pid = temp;
474         return 0;
475     } else
476         return LWP_EINIT;
477 }
478 #endif
479
480 int
481 LWP_CurrentProcess(PROCESS * pid)
482 {                               /* returns pid of current process */
483     Debug(0, ("Entered Current_Process"));
484     if (lwp_init) {
485         *pid = lwp_cpptr;
486         return LWP_SUCCESS;
487     } else
488         return LWP_EINIT;
489 }
490
491 PROCESS
492 LWP_ThreadId(void)
493 {
494     Debug(0, ("Entered ThreadId"));
495     if (lwp_init)
496         return lwp_cpptr;
497     else
498         return (PROCESS) 0;
499 }
500
501 #define LWPANCHOR (*lwp_init)
502
503 int
504 LWP_DestroyProcess(PROCESS pid)
505 {                               /* destroy a lightweight process */
506     PROCESS temp;
507
508     Debug(0, ("Entered Destroy_Process"));
509     if (lwp_init) {
510         if (lwp_cpptr != pid) {
511             Dispose_of_Dead_PCB(pid);
512             Set_LWP_RC();
513         } else {
514             pid->status = DESTROYED;
515             move(pid, &runnable[pid->priority], &blocked);
516             temp = lwp_cpptr;
517 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
518             savecontext(Dispatcher, &(temp->context),
519                         &(LWPANCHOR.dsptchstack[MINFRAME]));
520 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
521             savecontext(Dispatcher, &(temp->context),
522                         &(LWPANCHOR.
523                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
524 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
525             savecontext(Dispatcher, &(temp->context),
526                         &(LWPANCHOR.
527                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
528                                       0x40]));
529 #elif defined(AFS_S390_LINUX20_ENV)
530             savecontext(Dispatcher, &(temp->context),
531                         &(LWPANCHOR.
532                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
533                                       MINFRAME]));
534 #else
535             savecontext(Dispatcher, &(temp->context),
536                         &(LWPANCHOR.
537                           dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
538                                       sizeof(void *)]));
539 #endif
540         }
541         return LWP_SUCCESS;
542     } else
543         return LWP_EINIT;
544 }
545
546 int
547 LWP_DispatchProcess(void)
548 {                               /* explicit voluntary preemption */
549     Debug(2, ("Entered Dispatch_Process"));
550     if (lwp_init) {
551         Set_LWP_RC();
552         return LWP_SUCCESS;
553     } else
554         return LWP_EINIT;
555 }
556
557 #ifdef DEBUG
558 int
559 Dump_Processes(void)
560 {
561     if (lwp_init) {
562         int i;
563         for (i = 0; i < MAX_PRIORITIES; i++)
564             for_all_elts(x, runnable[i], {
565                          printf("[Priority %d]\n", i);
566                          Dump_One_Process(x);
567                          }
568         )
569             for_all_elts(x, blocked, {
570                          Dump_One_Process(x);}
571         )
572             for_all_elts(x, qwaiting, {
573                          Dump_One_Process(x);}
574         )
575     } else
576         printf("***LWP: LWP support not initialized\n");
577     return 0;
578 }
579 #endif
580
581 int
582 LWP_GetProcessPriority(PROCESS pid, int *priority)
583 {                               /* returns process priority */
584     Debug(0, ("Entered Get_Process_Priority"));
585     if (lwp_init) {
586         *priority = pid->priority;
587         return 0;
588     } else
589         return LWP_EINIT;
590 }
591
592 int
593 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
594 {
595     PROCESS temp;
596     struct lwp_pcb dummy;
597     int i;
598     char *value;
599
600     Debug(0, ("Entered LWP_InitializeProcessSupport"));
601     if (lwp_init != NULL)
602         return LWP_SUCCESS;
603
604     /* Set up offset for stack checking -- do this as soon as possible */
605     stack_offset = (char *)&dummy.stack - (char *)&dummy;
606
607     if (priority >= MAX_PRIORITIES)
608         return LWP_EBADPRI;
609     for (i = 0; i < MAX_PRIORITIES; i++) {
610         runnable[i].head = NULL;
611         runnable[i].count = 0;
612     }
613     blocked.head = NULL;
614     blocked.count = 0;
615     qwaiting.head = NULL;
616     qwaiting.count = 0;
617     lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
618     temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
619     if (lwp_init == NULL || temp == NULL)
620         Abort_LWP("Insufficient Storage to Initialize LWP Support");
621     LWPANCHOR.processcnt = 1;
622     LWPANCHOR.outerpid = temp;
623     LWPANCHOR.outersp = NULL;
624     Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
625                    "Main Process [created by LWP]");
626     insert(temp, &runnable[priority]);
627     savecontext(Dispatcher, &temp->context, NULL);
628     LWPANCHOR.outersp = temp->context.topstack;
629     Set_LWP_RC();
630     if (pid)
631         *pid = temp;
632
633     /* get minimum stack size from the environment. this allows the  administrator
634      * to change the lwp stack dynamically without getting a new binary version.
635      */
636     if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
637         lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
638     else
639         lwp_MinStackSize =
640             (AFS_LWP_MINSTACKSIZE >
641              atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
642
643     return LWP_SUCCESS;
644 }
645
646 int
647 LWP_INTERNALSIGNAL(void *event, int yield)
648 {                               /* signal the occurence of an event */
649     Debug(2, ("Entered LWP_SignalProcess"));
650     if (lwp_init) {
651         int rc;
652         rc = Internal_Signal(event);
653         if (yield)
654             Set_LWP_RC();
655         return rc;
656     } else
657         return LWP_EINIT;
658 }
659
660 int
661 LWP_TerminateProcessSupport(void)
662 {                               /* terminate all LWP support */
663     int i;
664
665     Debug(0, ("Entered Terminate_Process_Support"));
666     if (lwp_init == NULL)
667         return LWP_EINIT;
668     if (lwp_cpptr != LWPANCHOR.outerpid)
669         Abort_LWP("Terminate_Process_Support invoked from wrong process!");
670     for (i = 0; i < MAX_PRIORITIES; i++)
671         for_all_elts(cur, runnable[i], {
672                      Free_PCB(cur);}
673     )
674         for_all_elts(cur, blocked, {
675                      Free_PCB(cur);}
676     )
677         for_all_elts(cur, qwaiting, {
678                      Free_PCB(cur);}
679     )
680         free(lwp_init);
681     lwp_init = NULL;
682     return LWP_SUCCESS;
683 }
684
685 int
686 LWP_WaitProcess(void *event)
687 {                               /* wait on a single event */
688     void *tempev[2];
689
690     Debug(2, ("Entered Wait_Process"));
691     if (event == NULL)
692         return LWP_EBADEVENT;
693     tempev[0] = event;
694     tempev[1] = NULL;
695     return LWP_MwaitProcess(1, tempev);
696 }
697
698 int
699 LWP_MwaitProcess(int wcount, void *evlist[])
700 {                               /* wait on m of n events */
701     int ecount, i;
702
703
704     Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
705
706     if (evlist == NULL) {
707         Set_LWP_RC();
708         return LWP_EBADCOUNT;
709     }
710
711     for (ecount = 0; evlist[ecount] != NULL; ecount++);
712
713     if (ecount == 0) {
714         Set_LWP_RC();
715         return LWP_EBADCOUNT;
716     }
717
718     if (lwp_init) {
719
720         if (wcount > ecount || wcount < 0) {
721             Set_LWP_RC();
722             return LWP_EBADCOUNT;
723         }
724         if (ecount > lwp_cpptr->eventlistsize) {
725
726             lwp_cpptr->eventlist =
727                 (void **)realloc(lwp_cpptr->eventlist,
728                                  ecount * sizeof(void *));
729             lwp_cpptr->eventlistsize = ecount;
730         }
731         for (i = 0; i < ecount; i++)
732             lwp_cpptr->eventlist[i] = evlist[i];
733         if (wcount > 0) {
734             lwp_cpptr->status = WAITING;
735
736             move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
737
738         }
739         lwp_cpptr->wakevent = 0;
740         lwp_cpptr->waitcnt = wcount;
741         lwp_cpptr->eventcnt = ecount;
742
743         Set_LWP_RC();
744
745         return LWP_SUCCESS;
746     }
747
748     return LWP_EINIT;
749 }
750
751 int
752 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
753 {
754     *maxa = pid->stacksize;
755     *used = Stack_Used(pid->stack, *maxa);
756     if (*used == 0)
757         return LWP_NO_STACK;
758     return LWP_SUCCESS;
759 }
760
761 /*
762  *  The following functions are strictly
763  *  INTERNAL to the LWP support package.
764  */
765
766 static void
767 Abort_LWP(char *msg)
768 {
769     struct lwp_context tempcontext;
770
771     Debug(0, ("Entered Abort_LWP"));
772     printf("***LWP: %s\n", msg);
773     printf("***LWP: Abort --- dumping PCBs ...\n");
774 #ifdef DEBUG
775     Dump_Processes();
776 #endif
777     if (LWPANCHOR.outersp == NULL)
778         Exit_LWP();
779     else
780         savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
781     return;
782 }
783
784 static void
785 Create_Process_Part2(void)
786 {                               /* creates a context for the new process */
787     PROCESS temp;
788
789     Debug(2, ("Entered Create_Process_Part2"));
790     temp = lwp_cpptr;           /* Get current process id */
791     savecontext(Dispatcher, &temp->context, NULL);
792     (*temp->ep) (temp->parm);
793     LWP_DestroyProcess(temp);
794     return;
795 }
796
797 static int
798 Delete_PCB(PROCESS pid)
799 {                               /* remove a PCB from the process list */
800     Debug(4, ("Entered Delete_PCB"));
801     lwp_remove(pid,
802                (pid->blockflag || pid->status == WAITING
803                 || pid->status ==
804                 DESTROYED ? &blocked :
805                 (pid->status == QWAITING) ? &qwaiting :
806                 &runnable[pid->priority]));
807     LWPANCHOR.processcnt--;
808     return 0;
809 }
810
811 #ifdef DEBUG
812 static int
813 Dump_One_Process(PROCESS pid)
814 {
815     int i;
816
817     printf("***LWP: Process Control Block at 0x%x\n", pid);
818     printf("***LWP: Name: %s\n", pid->name);
819     if (pid->ep != NULL)
820         printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
821     if (pid->blockflag)
822         printf("BLOCKED and ");
823     switch (pid->status) {
824     case READY:
825         printf("READY");
826         break;
827     case WAITING:
828         printf("WAITING");
829         break;
830     case DESTROYED:
831         printf("DESTROYED");
832         break;
833     case QWAITING:
834         printf("QWAITING");
835         break;
836     default:
837         printf("unknown");
838     }
839     putchar('\n');
840     printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
841            pid->parm);
842     if (pid->stacksize != 0) {
843         printf("***LWP:  Stacksize: %d \tStack base address: 0x%x\n",
844                pid->stacksize, pid->stack);
845         printf("***LWP: HWM stack usage: ");
846         printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
847     }
848     printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
849     if (pid->eventcnt > 0) {
850         printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
851         printf("***LWP: Event id list:");
852         for (i = 0; i < pid->eventcnt; i++)
853             printf(" 0x%x", pid->eventlist[i]);
854         putchar('\n');
855     }
856     if (pid->wakevent > 0)
857         printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
858     return 0;
859 }
860 #endif
861
862 static int
863 purge_dead_pcbs(void)
864 {
865     for_all_elts(cur, blocked, {
866                  if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
867     )
868         return 0;
869 }
870
871 int LWP_TraceProcesses = 0;
872
873 static void
874 Dispatcher(void)
875 {                               /* Lightweight process dispatcher */
876     int i;
877 #ifdef DEBUG
878     static int dispatch_count = 0;
879
880     if (LWP_TraceProcesses > 0) {
881         for (i = 0; i < MAX_PRIORITIES; i++) {
882             printf("[Priority %d, runnable (%d):", i, runnable[i].count);
883             for_all_elts(p, runnable[i], {
884                          printf(" \"%s\"", p->name);
885                          }
886             )
887                 puts("]");
888         }
889         printf("[Blocked (%d):", blocked.count);
890         for_all_elts(p, blocked, {
891                      printf(" \"%s\"", p->name);
892                      }
893         )
894         puts("]");
895         printf("[Qwaiting (%d):", qwaiting.count);
896         for_all_elts(p, qwaiting, {
897                      printf(" \"%s\"", p->name);
898                      }
899         )
900         puts("]");
901     }
902 #endif
903
904     /* Check for stack overflowif this lwp has a stack.  Check for
905      * the guard word at the front of the stack being damaged and
906      * for the stack pointer being below the front of the stack.
907      * WARNING!  This code assumes that stacks grow downward. */
908 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
909     /* Fix this (stackcheck at other end of stack?) */
910     if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
911         && (lwp_cpptr->stackcheck !=
912             *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
913             || lwp_cpptr->context.topstack >
914             lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
915 #else
916     if (lwp_cpptr && lwp_cpptr->stack
917         && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
918             || lwp_cpptr->context.topstack < lwp_cpptr->stack
919             || lwp_cpptr->context.topstack >
920             (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
921 #endif
922         printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
923                *(int *)lwp_cpptr->stack);
924         printf("topstack = 0x%" AFS_PTR_FMT ": stackptr = 0x%" AFS_PTR_FMT ": stacksize = 0x%x\n",
925                (void *)(uintptr_t)lwp_cpptr->context.topstack,
926                (void *)(uintptr_t)lwp_cpptr->stack,
927                lwp_cpptr->stacksize);
928
929         switch (lwp_overflowAction) {
930         case LWP_SOQUIET:
931             break;
932         case LWP_SOABORT:
933             Overflow_Complain();
934             abort();
935         case LWP_SOMESSAGE:
936         default:
937             Overflow_Complain();
938             lwp_overflowAction = LWP_SOQUIET;
939             break;
940         }
941     }
942
943     /* Move head of current runnable queue forward if current LWP is still in it. */
944     if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
945         runnable[lwp_cpptr->priority].head =
946             runnable[lwp_cpptr->priority].head->next;
947     /* Find highest priority with runnable processes. */
948     for (i = MAX_PRIORITIES - 1; i >= 0; i--)
949         if (runnable[i].head != NULL)
950             break;
951
952     if (i < 0)
953         Abort_LWP("No READY processes");
954
955 #ifdef DEBUG
956     if (LWP_TraceProcesses > 0)
957         printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
958                runnable[i].head, runnable[i].head->name);
959 #endif
960 #if !defined(AFS_ARM_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
961     if (PRE_Block != 1)
962         Abort_LWP("PRE_Block not 1");
963 #endif
964     lwp_cpptr = runnable[i].head;
965
966     returnto(&lwp_cpptr->context);
967
968     return; /* not reachable */
969 }
970
971 /* Complain of a stack overflow to stderr without using stdio. */
972 static void
973 Overflow_Complain(void)
974 {
975     time_t currenttime;
976     char *timeStamp;
977     char *msg1 = " LWP: stack overflow in process ";
978     char *msg2 = "!\n";
979
980     currenttime = time(0);
981     timeStamp = ctime(&currenttime);
982     timeStamp[24] = 0;
983     write(2, timeStamp, strlen(timeStamp));
984
985     write(2, msg1, strlen(msg1));
986     write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
987     write(2, msg2, strlen(msg2));
988 }
989
990 static void
991 Dispose_of_Dead_PCB(PROCESS cur)
992 {
993     Debug(4, ("Entered Dispose_of_Dead_PCB"));
994     Delete_PCB(cur);
995     Free_PCB(cur);
996 /*
997     Internal_Signal(cur);
998 */
999 }
1000
1001 static void
1002 Exit_LWP(void)
1003 {
1004     abort();
1005 }
1006
1007 static void
1008 Free_PCB(PROCESS pid)
1009 {
1010     Debug(4, ("Entered Free_PCB"));
1011     if (pid->stack != NULL) {
1012         Debug(0,
1013               ("HWM stack usage: %d, [PCB at 0x%x]",
1014                Stack_Used(pid->stack, pid->stacksize), pid));
1015 #ifndef AFS_AIX32_ENV
1016         free(pid->stack);
1017 #endif
1018     }
1019     if (pid->eventlist != NULL)
1020         free(pid->eventlist);
1021     free(pid);
1022 }
1023
1024 static void
1025 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1026                void *(*ep) (void *), void *parm, char *name)
1027 {
1028     int i = 0;
1029
1030     Debug(4, ("Entered Initialize_PCB"));
1031     if (name != NULL)
1032         while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1033             i++;
1034     temp->name[31] = '\0';
1035     temp->status = READY;
1036     temp->eventlist = (void **)malloc(EVINITSIZE * sizeof(void *));
1037     temp->eventlistsize = EVINITSIZE;
1038     temp->eventcnt = 0;
1039     temp->wakevent = 0;
1040     temp->waitcnt = 0;
1041     temp->blockflag = 0;
1042     temp->iomgrRequest = 0;
1043     temp->priority = priority;
1044     temp->index = lwp_nextindex++;
1045     temp->stack = stack;
1046     temp->stacksize = stacksize;
1047 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1048     if (temp->stack != NULL)
1049         temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1050 #else
1051     if (temp->stack != NULL)
1052         temp->stackcheck = *(int *)(temp->stack);
1053 #endif
1054     temp->ep = ep;
1055     temp->parm = parm;
1056     temp->misc = NULL;          /* currently unused */
1057     temp->next = NULL;
1058     temp->prev = NULL;
1059     temp->lwp_rused = 0;
1060     temp->level = 1;            /* non-preemptable */
1061 }
1062
1063 static int
1064 Internal_Signal(void *event)
1065 {
1066     int rc = LWP_ENOWAIT;
1067     int i;
1068
1069     Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1070     if (!lwp_init)
1071         return LWP_EINIT;
1072     if (event == NULL)
1073         return LWP_EBADEVENT;
1074     for_all_elts(temp, blocked, {
1075                  if (temp->status == WAITING)
1076                  for (i = 0; i < temp->eventcnt; i++) {
1077                  if (temp->eventlist[i] == event) {
1078                  temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1079                  Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1080                  if (--temp->waitcnt == 0) {
1081                  temp->status = READY; temp->wakevent = i + 1;
1082                  move(temp, &blocked, &runnable[temp->priority]); break;}
1083                  }
1084                  }
1085                  }
1086     )
1087         return rc;
1088 }
1089
1090 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1091 #define STACKMAGIC      0xBADBADBA
1092 static afs_int32
1093 Initialize_Stack(char *stackptr, int stacksize)
1094 {
1095     int i;
1096
1097     Debug(4, ("Entered Initialize_Stack"));
1098     if (lwp_stackUseEnabled)
1099         for (i = 0; i < stacksize; i++)
1100             stackptr[i] = i & 0xff;
1101     else
1102 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1103         *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1104 #else
1105         *(afs_int32 *) stackptr = STACKMAGIC;
1106 #endif
1107     return 0;
1108 }
1109
1110 static int
1111 Stack_Used(char *stackptr, int stacksize)
1112 {
1113     int i;
1114
1115 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1116     if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1117         return 0;
1118     else {
1119         for (i = stacksize - 1; i >= 0; i--)
1120             if ((unsigned char)stackptr[i] != (i & 0xff))
1121                 return (i);
1122         return 0;
1123     }
1124 #else
1125     if (*(afs_int32 *) stackptr == STACKMAGIC)
1126         return 0;
1127     else {
1128         for (i = 0; i < stacksize; i++)
1129             if ((unsigned char)stackptr[i] != (i & 0xff))
1130                 return (stacksize - i);
1131         return 0;
1132     }
1133 #endif
1134 }
1135
1136
1137 int
1138 LWP_NewRock(int Tag, char *Value)
1139     /* Finds a free rock and sets its value to Value.
1140      * Return codes:
1141      * LWP_SUCCESS      Rock did not exist and a new one was used
1142      * LWP_EBADROCK     Rock already exists.
1143      * LWP_ENOROCKS     All rocks are in use.
1144      *
1145      * From the above semantics, you can only set a rock value once.  This is specifically
1146      * to prevent multiple users of the LWP package from accidentally using the same Tag
1147      * value and clobbering others.  You can always use one level of indirection to obtain
1148      * a rock whose contents can change.
1149      */
1150 {
1151     int i;
1152     struct rock *ra;    /* rock array */
1153
1154     ra = lwp_cpptr->lwp_rlist;
1155
1156     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1157         if (ra[i].tag == Tag)
1158             return (LWP_EBADROCK);
1159
1160     if (lwp_cpptr->lwp_rused < MAXROCKS) {
1161         ra[lwp_cpptr->lwp_rused].tag = Tag;
1162         ra[lwp_cpptr->lwp_rused].value = Value;
1163         lwp_cpptr->lwp_rused++;
1164         return (LWP_SUCCESS);
1165     } else
1166         return (LWP_ENOROCKS);
1167 }
1168
1169
1170 int
1171 LWP_GetRock(int Tag, char **Value)
1172     /* Obtains the pointer Value associated with the rock Tag of this LWP.
1173      * Returns:
1174      * LWP_SUCCESS              if specified rock exists and Value has been filled
1175      * LWP_EBADROCK     rock specified does not exist
1176      */
1177 {
1178     int i;
1179     struct rock *ra;
1180
1181     ra = lwp_cpptr->lwp_rlist;
1182
1183     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1184         if (ra[i].tag == Tag) {
1185             *Value = ra[i].value;
1186             return (LWP_SUCCESS);
1187         }
1188     return (LWP_EBADROCK);
1189 }
1190
1191
1192 #ifdef  AFS_AIX32_ENV
1193 int
1194 setlim(int limcon, uchar_t hard, int limit)
1195 {
1196     struct rlimit rlim;
1197
1198     (void)getrlimit(limcon, &rlim);
1199
1200     limit = limit * 1024;
1201     if (hard)
1202         rlim.rlim_max = limit;
1203     else if (limit == RLIM_INFINITY && geteuid() != 0)
1204         rlim.rlim_cur = rlim.rlim_max;
1205     else
1206         rlim.rlim_cur = limit;
1207
1208     /* Must use ulimit() due to Posix constraints */
1209     if (limcon == RLIMIT_FSIZE) {
1210         if (ulimit
1211             (UL_SETFSIZE,
1212              ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1213             printf("Can't %s%s limit\n",
1214                    limit == RLIM_INFINITY ? "remove" : "set",
1215                    hard ? " hard" : "");
1216             return (-1);
1217         }
1218     } else {
1219         if (setrlimit(limcon, &rlim) < 0) {
1220             perror("");
1221             printf("Can't %s%s limit\n",
1222                    limit == RLIM_INFINITY ? "remove" : "set",
1223                    hard ? " hard" : "");
1224             return (-1);
1225         }
1226     }
1227     return (0);
1228 }
1229 #endif
1230
1231 #ifdef  AFS_SUN5_ENV
1232 int
1233 LWP_NoYieldSignal(void *event)
1234 {
1235     return (LWP_INTERNALSIGNAL(event, 0));
1236 }
1237
1238 int
1239 LWP_SignalProcess(void *event)
1240 {
1241     return (LWP_INTERNALSIGNAL(event, 1));
1242 }
1243
1244 #endif