2ee83a0bec55dd5161d4e0f9a7dc43688d23729d
[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 = realloc(lwp_cpptr->eventlist,
727                                            ecount * sizeof(void *));
728             lwp_cpptr->eventlistsize = ecount;
729         }
730         for (i = 0; i < ecount; i++)
731             lwp_cpptr->eventlist[i] = evlist[i];
732         if (wcount > 0) {
733             lwp_cpptr->status = WAITING;
734
735             move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
736
737         }
738         lwp_cpptr->wakevent = 0;
739         lwp_cpptr->waitcnt = wcount;
740         lwp_cpptr->eventcnt = ecount;
741
742         Set_LWP_RC();
743
744         return LWP_SUCCESS;
745     }
746
747     return LWP_EINIT;
748 }
749
750 int
751 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
752 {
753     *maxa = pid->stacksize;
754     *used = Stack_Used(pid->stack, *maxa);
755     if (*used == 0)
756         return LWP_NO_STACK;
757     return LWP_SUCCESS;
758 }
759
760 /*
761  *  The following functions are strictly
762  *  INTERNAL to the LWP support package.
763  */
764
765 static void
766 Abort_LWP(char *msg)
767 {
768     struct lwp_context tempcontext;
769
770     Debug(0, ("Entered Abort_LWP"));
771     printf("***LWP: %s\n", msg);
772     printf("***LWP: Abort --- dumping PCBs ...\n");
773 #ifdef DEBUG
774     Dump_Processes();
775 #endif
776     if (LWPANCHOR.outersp == NULL)
777         Exit_LWP();
778     else
779         savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
780     return;
781 }
782
783 static void
784 Create_Process_Part2(void)
785 {                               /* creates a context for the new process */
786     PROCESS temp;
787
788     Debug(2, ("Entered Create_Process_Part2"));
789     temp = lwp_cpptr;           /* Get current process id */
790     savecontext(Dispatcher, &temp->context, NULL);
791     (*temp->ep) (temp->parm);
792     LWP_DestroyProcess(temp);
793     return;
794 }
795
796 static int
797 Delete_PCB(PROCESS pid)
798 {                               /* remove a PCB from the process list */
799     Debug(4, ("Entered Delete_PCB"));
800     lwp_remove(pid,
801                (pid->blockflag || pid->status == WAITING
802                 || pid->status ==
803                 DESTROYED ? &blocked :
804                 (pid->status == QWAITING) ? &qwaiting :
805                 &runnable[pid->priority]));
806     LWPANCHOR.processcnt--;
807     return 0;
808 }
809
810 #ifdef DEBUG
811 static int
812 Dump_One_Process(PROCESS pid)
813 {
814     int i;
815
816     printf("***LWP: Process Control Block at 0x%x\n", pid);
817     printf("***LWP: Name: %s\n", pid->name);
818     if (pid->ep != NULL)
819         printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
820     if (pid->blockflag)
821         printf("BLOCKED and ");
822     switch (pid->status) {
823     case READY:
824         printf("READY");
825         break;
826     case WAITING:
827         printf("WAITING");
828         break;
829     case DESTROYED:
830         printf("DESTROYED");
831         break;
832     case QWAITING:
833         printf("QWAITING");
834         break;
835     default:
836         printf("unknown");
837     }
838     putchar('\n');
839     printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
840            pid->parm);
841     if (pid->stacksize != 0) {
842         printf("***LWP:  Stacksize: %d \tStack base address: 0x%x\n",
843                pid->stacksize, pid->stack);
844         printf("***LWP: HWM stack usage: ");
845         printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
846     }
847     printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
848     if (pid->eventcnt > 0) {
849         printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
850         printf("***LWP: Event id list:");
851         for (i = 0; i < pid->eventcnt; i++)
852             printf(" 0x%x", pid->eventlist[i]);
853         putchar('\n');
854     }
855     if (pid->wakevent > 0)
856         printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
857     return 0;
858 }
859 #endif
860
861 static int
862 purge_dead_pcbs(void)
863 {
864     for_all_elts(cur, blocked, {
865                  if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
866     )
867         return 0;
868 }
869
870 int LWP_TraceProcesses = 0;
871
872 static void
873 Dispatcher(void)
874 {                               /* Lightweight process dispatcher */
875     int i;
876 #ifdef DEBUG
877     static int dispatch_count = 0;
878
879     if (LWP_TraceProcesses > 0) {
880         for (i = 0; i < MAX_PRIORITIES; i++) {
881             printf("[Priority %d, runnable (%d):", i, runnable[i].count);
882             for_all_elts(p, runnable[i], {
883                          printf(" \"%s\"", p->name);
884                          }
885             )
886                 puts("]");
887         }
888         printf("[Blocked (%d):", blocked.count);
889         for_all_elts(p, blocked, {
890                      printf(" \"%s\"", p->name);
891                      }
892         )
893         puts("]");
894         printf("[Qwaiting (%d):", qwaiting.count);
895         for_all_elts(p, qwaiting, {
896                      printf(" \"%s\"", p->name);
897                      }
898         )
899         puts("]");
900     }
901 #endif
902
903     /* Check for stack overflowif this lwp has a stack.  Check for
904      * the guard word at the front of the stack being damaged and
905      * for the stack pointer being below the front of the stack.
906      * WARNING!  This code assumes that stacks grow downward. */
907 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
908     /* Fix this (stackcheck at other end of stack?) */
909     if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
910         && (lwp_cpptr->stackcheck !=
911             *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
912             || lwp_cpptr->context.topstack >
913             lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
914 #else
915     if (lwp_cpptr && lwp_cpptr->stack
916         && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
917             || lwp_cpptr->context.topstack < lwp_cpptr->stack
918             || lwp_cpptr->context.topstack >
919             (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
920 #endif
921         printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
922                *(int *)lwp_cpptr->stack);
923         printf("topstack = 0x%" AFS_PTR_FMT ": stackptr = 0x%" AFS_PTR_FMT ": stacksize = 0x%x\n",
924                (void *)(uintptr_t)lwp_cpptr->context.topstack,
925                (void *)(uintptr_t)lwp_cpptr->stack,
926                lwp_cpptr->stacksize);
927
928         switch (lwp_overflowAction) {
929         case LWP_SOQUIET:
930             break;
931         case LWP_SOABORT:
932             Overflow_Complain();
933             abort();
934         case LWP_SOMESSAGE:
935         default:
936             Overflow_Complain();
937             lwp_overflowAction = LWP_SOQUIET;
938             break;
939         }
940     }
941
942     /* Move head of current runnable queue forward if current LWP is still in it. */
943     if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
944         runnable[lwp_cpptr->priority].head =
945             runnable[lwp_cpptr->priority].head->next;
946     /* Find highest priority with runnable processes. */
947     for (i = MAX_PRIORITIES - 1; i >= 0; i--)
948         if (runnable[i].head != NULL)
949             break;
950
951     if (i < 0)
952         Abort_LWP("No READY processes");
953
954 #ifdef DEBUG
955     if (LWP_TraceProcesses > 0)
956         printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
957                runnable[i].head, runnable[i].head->name);
958 #endif
959 #if !defined(AFS_ARM_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
960     if (PRE_Block != 1)
961         Abort_LWP("PRE_Block not 1");
962 #endif
963     lwp_cpptr = runnable[i].head;
964
965     returnto(&lwp_cpptr->context);
966
967     return; /* not reachable */
968 }
969
970 /* Complain of a stack overflow to stderr without using stdio. */
971 static void
972 Overflow_Complain(void)
973 {
974     time_t currenttime;
975     char *timeStamp;
976     char *msg1 = " LWP: stack overflow in process ";
977     char *msg2 = "!\n";
978
979     currenttime = time(0);
980     timeStamp = ctime(&currenttime);
981     timeStamp[24] = 0;
982     write(2, timeStamp, strlen(timeStamp));
983
984     write(2, msg1, strlen(msg1));
985     write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
986     write(2, msg2, strlen(msg2));
987 }
988
989 static void
990 Dispose_of_Dead_PCB(PROCESS cur)
991 {
992     Debug(4, ("Entered Dispose_of_Dead_PCB"));
993     Delete_PCB(cur);
994     Free_PCB(cur);
995 /*
996     Internal_Signal(cur);
997 */
998 }
999
1000 static void
1001 Exit_LWP(void)
1002 {
1003     abort();
1004 }
1005
1006 static void
1007 Free_PCB(PROCESS pid)
1008 {
1009     Debug(4, ("Entered Free_PCB"));
1010     if (pid->stack != NULL) {
1011         Debug(0,
1012               ("HWM stack usage: %d, [PCB at 0x%x]",
1013                Stack_Used(pid->stack, pid->stacksize), pid));
1014 #ifndef AFS_AIX32_ENV
1015         free(pid->stack);
1016 #endif
1017     }
1018     if (pid->eventlist != NULL)
1019         free(pid->eventlist);
1020     free(pid);
1021 }
1022
1023 static void
1024 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1025                void *(*ep) (void *), void *parm, char *name)
1026 {
1027     int i = 0;
1028
1029     Debug(4, ("Entered Initialize_PCB"));
1030     if (name != NULL)
1031         while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1032             i++;
1033     temp->name[31] = '\0';
1034     temp->status = READY;
1035     temp->eventlist = (void **)malloc(EVINITSIZE * sizeof(void *));
1036     temp->eventlistsize = EVINITSIZE;
1037     temp->eventcnt = 0;
1038     temp->wakevent = 0;
1039     temp->waitcnt = 0;
1040     temp->blockflag = 0;
1041     temp->iomgrRequest = 0;
1042     temp->priority = priority;
1043     temp->index = lwp_nextindex++;
1044     temp->stack = stack;
1045     temp->stacksize = stacksize;
1046 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1047     if (temp->stack != NULL)
1048         temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1049 #else
1050     if (temp->stack != NULL)
1051         temp->stackcheck = *(int *)(temp->stack);
1052 #endif
1053     temp->ep = ep;
1054     temp->parm = parm;
1055     temp->misc = NULL;          /* currently unused */
1056     temp->next = NULL;
1057     temp->prev = NULL;
1058     temp->lwp_rused = 0;
1059     temp->level = 1;            /* non-preemptable */
1060 }
1061
1062 static int
1063 Internal_Signal(void *event)
1064 {
1065     int rc = LWP_ENOWAIT;
1066     int i;
1067
1068     Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1069     if (!lwp_init)
1070         return LWP_EINIT;
1071     if (event == NULL)
1072         return LWP_EBADEVENT;
1073     for_all_elts(temp, blocked, {
1074                  if (temp->status == WAITING)
1075                  for (i = 0; i < temp->eventcnt; i++) {
1076                  if (temp->eventlist[i] == event) {
1077                  temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1078                  Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1079                  if (--temp->waitcnt == 0) {
1080                  temp->status = READY; temp->wakevent = i + 1;
1081                  move(temp, &blocked, &runnable[temp->priority]); break;}
1082                  }
1083                  }
1084                  }
1085     )
1086         return rc;
1087 }
1088
1089 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1090 #define STACKMAGIC      0xBADBADBA
1091 static afs_int32
1092 Initialize_Stack(char *stackptr, int stacksize)
1093 {
1094     int i;
1095
1096     Debug(4, ("Entered Initialize_Stack"));
1097     if (lwp_stackUseEnabled)
1098         for (i = 0; i < stacksize; i++)
1099             stackptr[i] = i & 0xff;
1100     else
1101 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1102         *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1103 #else
1104         *(afs_int32 *) stackptr = STACKMAGIC;
1105 #endif
1106     return 0;
1107 }
1108
1109 static int
1110 Stack_Used(char *stackptr, int stacksize)
1111 {
1112     int i;
1113
1114 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1115     if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1116         return 0;
1117     else {
1118         for (i = stacksize - 1; i >= 0; i--)
1119             if ((unsigned char)stackptr[i] != (i & 0xff))
1120                 return (i);
1121         return 0;
1122     }
1123 #else
1124     if (*(afs_int32 *) stackptr == STACKMAGIC)
1125         return 0;
1126     else {
1127         for (i = 0; i < stacksize; i++)
1128             if ((unsigned char)stackptr[i] != (i & 0xff))
1129                 return (stacksize - i);
1130         return 0;
1131     }
1132 #endif
1133 }
1134
1135
1136 int
1137 LWP_NewRock(int Tag, char *Value)
1138     /* Finds a free rock and sets its value to Value.
1139      * Return codes:
1140      * LWP_SUCCESS      Rock did not exist and a new one was used
1141      * LWP_EBADROCK     Rock already exists.
1142      * LWP_ENOROCKS     All rocks are in use.
1143      *
1144      * From the above semantics, you can only set a rock value once.  This is specifically
1145      * to prevent multiple users of the LWP package from accidentally using the same Tag
1146      * value and clobbering others.  You can always use one level of indirection to obtain
1147      * a rock whose contents can change.
1148      */
1149 {
1150     int i;
1151     struct rock *ra;    /* rock array */
1152
1153     ra = lwp_cpptr->lwp_rlist;
1154
1155     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1156         if (ra[i].tag == Tag)
1157             return (LWP_EBADROCK);
1158
1159     if (lwp_cpptr->lwp_rused < MAXROCKS) {
1160         ra[lwp_cpptr->lwp_rused].tag = Tag;
1161         ra[lwp_cpptr->lwp_rused].value = Value;
1162         lwp_cpptr->lwp_rused++;
1163         return (LWP_SUCCESS);
1164     } else
1165         return (LWP_ENOROCKS);
1166 }
1167
1168
1169 int
1170 LWP_GetRock(int Tag, char **Value)
1171     /* Obtains the pointer Value associated with the rock Tag of this LWP.
1172      * Returns:
1173      * LWP_SUCCESS              if specified rock exists and Value has been filled
1174      * LWP_EBADROCK     rock specified does not exist
1175      */
1176 {
1177     int i;
1178     struct rock *ra;
1179
1180     ra = lwp_cpptr->lwp_rlist;
1181
1182     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1183         if (ra[i].tag == Tag) {
1184             *Value = ra[i].value;
1185             return (LWP_SUCCESS);
1186         }
1187     return (LWP_EBADROCK);
1188 }
1189
1190
1191 #ifdef  AFS_AIX32_ENV
1192 int
1193 setlim(int limcon, uchar_t hard, int limit)
1194 {
1195     struct rlimit rlim;
1196
1197     (void)getrlimit(limcon, &rlim);
1198
1199     limit = limit * 1024;
1200     if (hard)
1201         rlim.rlim_max = limit;
1202     else if (limit == RLIM_INFINITY && geteuid() != 0)
1203         rlim.rlim_cur = rlim.rlim_max;
1204     else
1205         rlim.rlim_cur = limit;
1206
1207     /* Must use ulimit() due to Posix constraints */
1208     if (limcon == RLIMIT_FSIZE) {
1209         if (ulimit
1210             (UL_SETFSIZE,
1211              ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1212             printf("Can't %s%s limit\n",
1213                    limit == RLIM_INFINITY ? "remove" : "set",
1214                    hard ? " hard" : "");
1215             return (-1);
1216         }
1217     } else {
1218         if (setrlimit(limcon, &rlim) < 0) {
1219             perror("");
1220             printf("Can't %s%s limit\n",
1221                    limit == RLIM_INFINITY ? "remove" : "set",
1222                    hard ? " hard" : "");
1223             return (-1);
1224         }
1225     }
1226     return (0);
1227 }
1228 #endif
1229
1230 #ifdef  AFS_SUN5_ENV
1231 int
1232 LWP_NoYieldSignal(void *event)
1233 {
1234     return (LWP_INTERNALSIGNAL(event, 0));
1235 }
1236
1237 int
1238 LWP_SignalProcess(void *event)
1239 {
1240     return (LWP_INTERNALSIGNAL(event, 1));
1241 }
1242
1243 #endif