Remove AFS_PARISC_LINUX24_ENV references
[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_S390_LINUX20_ENV)
38 int PRE_Block;  /* Remnants of preemption support. */
39 #else
40 char PRE_Block; /* Remnants of preemption support. */
41 #endif
42 #endif
43
44 #define ON              1
45 #define OFF             0
46 #define TRUE            1
47 #define FALSE           0
48 #define READY           2
49 #define WAITING         3
50 #define DESTROYED       4
51 #define QWAITING        5
52 #define MAXINT     (~(1<<((sizeof(int)*8)-1)))
53 #define MINSTACK   44
54
55 #if defined(__hp9000s800)
56 #define MINFRAME 128
57 #define STACK_ALIGN 8
58 #else
59 #ifdef __s390x__
60 #define MINFRAME    160
61 #define STACK_ALIGN 8
62 #else
63 #ifdef __s390__
64 #define MINFRAME    96
65 #define STACK_ALIGN 8
66 #elif defined(AFS_DARWIN_ENV)
67 #define STACK_ALIGN 16
68 #else
69 #define STACK_ALIGN 4
70 #endif
71 #endif
72 #endif
73
74 /* Debugging macro */
75 #ifdef DEBUG
76 #define Debug(level, msg) do {                                          \
77     if (lwp_debug && lwp_debug >= level) {                              \
78         printf("***LWP (0x%x): ", lwp_cpptr);                           \
79         printf msg;                                                     \
80         putchar('\n');                                                  \
81     }                                                                   \
82 } while (0)
83 #else
84 #define Debug(level, msg) do {                                          \
85     ;                                                                   \
86 } while (0)
87 #endif
88
89 static void Dispatcher(void);
90 static void Create_Process_Part2(void);
91 static void Exit_LWP(void);
92 static afs_int32 Initialize_Stack(char *stackptr, int stacksize);
93 static int Stack_Used(char *stackptr, int stacksize);
94
95 static void Abort_LWP(char *msg);
96 static void Overflow_Complain(void);
97 static void Initialize_PCB(PROCESS temp, int priority, char *stack,
98                            int stacksize, void *(*ep)(void *), void *parm,
99                            char *name);
100 static void Dispose_of_Dead_PCB(PROCESS cur);
101 static void Free_PCB(PROCESS pid);
102 static int Internal_Signal(void *event);
103 static int purge_dead_pcbs(void);
104 static int LWP_MwaitProcess(int wcount, void *evlist[]);
105
106
107 #define MAX_PRIORITIES  (LWP_MAX_PRIORITY+1)
108
109 struct QUEUE {
110     PROCESS head;
111     int count;
112 } runnable[MAX_PRIORITIES], blocked, qwaiting;
113 /* Invariant for runnable queues: The head of each queue points to the
114  * currently running process if it is in that queue, or it points to the
115  * next process in that queue that should run. */
116
117 /* Offset of stack field within pcb -- used by stack checking stuff */
118 int stack_offset;
119
120 /* special user-tweakable option for AIX */
121 int lwp_MaxStackSize = 32768;
122
123 /* biggest LWP stack created so far */
124 int lwp_MaxStackSeen = 0;
125
126 /* Stack checking action */
127 int lwp_overflowAction = LWP_SOABORT;
128
129 /* Controls stack size counting. */
130 int lwp_stackUseEnabled = TRUE; /* pay the price */
131
132 int lwp_nextindex;
133
134 /* Minimum stack size */
135 int lwp_MinStackSize = 0;
136
137 static int
138 lwp_remove(PROCESS p, struct QUEUE *q)
139 {
140     /* Special test for only element on queue */
141     if (q->count == 1)
142         q->head = NULL;
143     else {
144         /* Not only element, do normal remove */
145         p->next->prev = p->prev;
146         p->prev->next = p->next;
147     }
148     /* See if head pointing to this element */
149     if (q->head == p)
150         q->head = p->next;
151     q->count--;
152     p->next = p->prev = NULL;
153     return 0;
154 }
155
156 static int
157 insert(PROCESS p, struct QUEUE *q)
158 {
159     if (q->head == NULL) {      /* Queue is empty */
160         q->head = p;
161         p->next = p->prev = p;
162     } else {                    /* Regular insert */
163         p->prev = q->head->prev;
164         q->head->prev->next = p;
165         q->head->prev = p;
166         p->next = q->head;
167     }
168     q->count++;
169     return 0;
170 }
171
172 static int
173 move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
174 {
175
176     lwp_remove(p, from);
177
178     insert(p, to);
179     return 0;
180 }
181
182 /* Iterator macro */
183 #define for_all_elts(var, q, body)\
184         {\
185             PROCESS var, _NEXT_;\
186             int _I_;\
187             for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
188                 _NEXT_ = var -> next;\
189                 body\
190             }\
191         }
192
193 /*                                                                          */
194 /*****************************************************************************\
195 *                                                                             *
196 *  Following section documents the Assembler interfaces used by LWP code      *
197 *                                                                             *
198 \*****************************************************************************/
199
200 /*
201         savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
202
203 Stub for Assembler routine that will
204 save the current SP value in the passed
205 context savearea and call the function
206 whose entry point is in ep.  If the sp
207 parameter is NULL, the current stack is
208 used, otherwise sp becomes the new stack
209 pointer.
210
211         returnto(struct lwp_context *savearea);
212
213 Stub for Assembler routine that will
214 restore context from a passed savearea
215 and return to the restored C frame.
216
217 */
218
219 /* Macro to force a re-schedule.  Strange name is historical */
220 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
221
222 static struct lwp_ctl *lwp_init = 0;
223
224 int
225 LWP_QWait(void)
226 {
227     PROCESS tp;
228     (tp = lwp_cpptr)->status = QWAITING;
229     move(tp, &runnable[tp->priority], &qwaiting);
230     Set_LWP_RC();
231     return LWP_SUCCESS;
232 }
233
234 int
235 LWP_QSignal(PROCESS pid)
236 {
237     if (pid->status == QWAITING) {
238         pid->status = READY;
239         move(pid, &qwaiting, &runnable[pid->priority]);
240         return LWP_SUCCESS;
241     } else
242         return LWP_ENOWAIT;
243 }
244
245 #ifdef  AFS_AIX32_ENV
246 char *
247 reserveFromStack(afs_int32 size)
248 {
249     char *x;
250     x = alloca(size);
251     return x;
252 }
253 #endif
254
255 int
256 LWP_CreateProcess(void *(*ep) (void *), int stacksize, int priority, void *parm,
257                   char *name, PROCESS * pid)
258 {
259     PROCESS temp, temp2;
260 #ifdef  AFS_AIX32_ENV
261     static char *stackptr = 0;
262 #else
263     char *stackptr;
264 #endif
265     char *stackmemory;
266
267 #if defined(AFS_LWP_MINSTACKSIZE)
268     /*
269      * on some systems (e.g. hpux), a minimum usable stack size has
270      * been discovered
271      */
272     if (stacksize < lwp_MinStackSize) {
273         stacksize = lwp_MinStackSize;
274     }
275 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
276     /* more stack size computations; keep track of for IOMGR */
277     if (lwp_MaxStackSeen < stacksize)
278         lwp_MaxStackSeen = stacksize;
279
280     Debug(0, ("Entered LWP_CreateProcess"));
281     /* Throw away all dead process control blocks */
282     purge_dead_pcbs();
283     if (lwp_init) {
284         temp = malloc(sizeof(struct lwp_pcb));
285         if (temp == NULL) {
286             Set_LWP_RC();
287             return LWP_ENOMEM;
288         }
289         if (stacksize < MINSTACK)
290 #ifdef AFS_DARWIN_ENV
291             stacksize = 1008;
292 #else /* !AFS_DARWIN_ENV */
293             stacksize = 1000;
294 #endif /* !AFS_DARWIN_ENV */
295         else
296             stacksize =
297                 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
298 #ifdef  AFS_AIX32_ENV
299         if (!stackptr) {
300             /*
301              * The following signal action for AIX is necessary so that in case of a
302              * crash (i.e. core is generated) we can include the user's data section
303              * in the core dump. Unfortunately, by default, only a partial core is
304              * generated which, in many cases, isn't too useful.
305              *
306              * We also do it here in case the main program forgets to do it.
307              */
308             struct sigaction nsa;
309             extern uid_t geteuid();
310
311             sigemptyset(&nsa.sa_mask);
312             nsa.sa_handler = SIG_DFL;
313             nsa.sa_flags = SA_FULLDUMP;
314             sigaction(SIGABRT, &nsa, NULL);
315             sigaction(SIGSEGV, &nsa, NULL);
316
317             /*
318              * First we need to increase the default resource limits,
319              * if necessary, so that we can guarantee that we have the
320              * resources to create the core file, but we can't always
321              * do it as an ordinary user.
322              */
323             if (!geteuid()) {
324                 /* vos dump causes problems */
325                 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
326                 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
327                 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
328             }
329             /*
330              * Now reserve in one scoop all the stack space that will be used
331              * by the particular application's main (i.e. non-lwp) body. This
332              * is plenty space for any of our applications.
333              */
334             stackptr = reserveFromStack(lwp_MaxStackSize);
335         }
336         stackptr -= stacksize;
337         stackmemory = stackptr;
338 #else
339 #ifdef AFS_DARWIN_ENV
340         if ((stackmemory = malloc(stacksize + STACK_ALIGN - 1)) == NULL)
341 #else /* !AFS_DARWIN_ENV */
342         if ((stackmemory = malloc(stacksize + 7)) == NULL)
343 #endif /* !AFS_DARWIN_ENV */
344         {
345             free(temp);
346             Set_LWP_RC();
347             return LWP_ENOMEM;
348         }
349         /* Round stack pointer to byte boundary */
350 #ifdef AFS_DARWIN_ENV
351         stackptr = (char *)(STACK_ALIGN * (((long)stackmemory + STACK_ALIGN - 1) / STACK_ALIGN));
352 #else /* !AFS_DARWIN_ENV */
353         stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
354 #endif /* !AFS_DARWIN_ENV */
355 #endif
356         if (priority < 0 || priority >= MAX_PRIORITIES) {
357             free(temp);
358 #ifndef AFS_AIX32_ENV
359             free(stackmemory);
360 #endif
361             Set_LWP_RC();
362             return LWP_EBADPRI;
363         }
364         Initialize_Stack(stackptr, stacksize);
365         Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
366         insert(temp, &runnable[priority]);
367         temp2 = lwp_cpptr;
368 #if !defined(AFS_ARM_LINUX20_ENV) && !defined(AFS_ARM_DARWIN_ENV)
369         if (PRE_Block != 0)
370             Abort_LWP("PRE_Block not 0");
371
372         /* Gross hack: beware! */
373         PRE_Block = 1;
374 #endif
375         lwp_cpptr = temp;
376 #ifdef __hp9000s800
377         savecontext(Create_Process_Part2, &temp2->context,
378                     stackptr + MINFRAME);
379 #else
380 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
381 #ifdef sys_x86_darwin_80
382         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16 - sizeof(void *)); /* 16 = 2 * jmp_buf_type */
383 #else /* !sys_x86_darwin_80 */
384         /* Need to have the sp on an 8-byte boundary for storing doubles. */
385         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16);  /* 16 = 2 * jmp_buf_type */
386 #endif /* !sys_x86_darwin_80 */
387 #else
388 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
389         savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40);        /* lomgjmp does something
390                                                                                                  * with %fp + 0x38 */
391 #else
392 #if defined(AFS_S390_LINUX20_ENV)
393         savecontext(Create_Process_Part2, &temp2->context,
394                     stackptr + stacksize - MINFRAME);
395 #else /* !AFS_S390_LINUX20_ENV */
396         savecontext(Create_Process_Part2, &temp2->context,
397                     stackptr + stacksize - sizeof(void *));
398 #endif /* AFS_S390_LINUX20_ENV */
399 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
400 #endif /* AFS_SGI62_ENV */
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 = 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 = 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)
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 = malloc(sizeof(struct lwp_ctl));
618     temp = 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)
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 = %p: stackptr = %p: 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     if (write(2, timeStamp, strlen(timeStamp)) < 0)
983         return;
984
985     if (write(2, msg1, strlen(msg1)) < 0)
986         return;
987     if (write(2, lwp_cpptr->name, strlen(lwp_cpptr->name)) < 0)
988         return;
989     if (write(2, msg2, strlen(msg2)) < 0)
990         return;
991 }
992
993 static void
994 Dispose_of_Dead_PCB(PROCESS cur)
995 {
996     Debug(4, ("Entered Dispose_of_Dead_PCB"));
997     Delete_PCB(cur);
998     Free_PCB(cur);
999 /*
1000     Internal_Signal(cur);
1001 */
1002 }
1003
1004 static void
1005 Exit_LWP(void)
1006 {
1007     abort();
1008 }
1009
1010 static void
1011 Free_PCB(PROCESS pid)
1012 {
1013     Debug(4, ("Entered Free_PCB"));
1014     if (pid->stack != NULL) {
1015         Debug(0,
1016               ("HWM stack usage: %d, [PCB at 0x%x]",
1017                Stack_Used(pid->stack, pid->stacksize), pid));
1018 #ifndef AFS_AIX32_ENV
1019         free(pid->stack);
1020 #endif
1021     }
1022     if (pid->eventlist != NULL)
1023         free(pid->eventlist);
1024     free(pid);
1025 }
1026
1027 static void
1028 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1029                void *(*ep) (void *), void *parm, char *name)
1030 {
1031     int i = 0;
1032
1033     Debug(4, ("Entered Initialize_PCB"));
1034     if (name != NULL)
1035         while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1036             i++;
1037     temp->name[31] = '\0';
1038     temp->status = READY;
1039     temp->eventlist = malloc(EVINITSIZE * sizeof(void *));
1040     temp->eventlistsize = EVINITSIZE;
1041     temp->eventcnt = 0;
1042     temp->wakevent = 0;
1043     temp->waitcnt = 0;
1044     temp->blockflag = 0;
1045     temp->iomgrRequest = 0;
1046     temp->priority = priority;
1047     temp->index = lwp_nextindex++;
1048     temp->stack = stack;
1049     temp->stacksize = stacksize;
1050 #if defined(__hp9000s800)
1051     if (temp->stack != NULL)
1052         temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1053 #else
1054     if (temp->stack != NULL)
1055         temp->stackcheck = *(int *)(temp->stack);
1056 #endif
1057     temp->ep = ep;
1058     temp->parm = parm;
1059     temp->misc = NULL;          /* currently unused */
1060     temp->next = NULL;
1061     temp->prev = NULL;
1062     temp->lwp_rused = 0;
1063     temp->level = 1;            /* non-preemptable */
1064 }
1065
1066 static int
1067 Internal_Signal(void *event)
1068 {
1069     int rc = LWP_ENOWAIT;
1070     int i;
1071
1072     Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1073     if (!lwp_init)
1074         return LWP_EINIT;
1075     if (event == NULL)
1076         return LWP_EBADEVENT;
1077     for_all_elts(temp, blocked, {
1078                  if (temp->status == WAITING)
1079                  for (i = 0; i < temp->eventcnt; i++) {
1080                  if (temp->eventlist[i] == event) {
1081                  temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1082                  Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1083                  if (--temp->waitcnt == 0) {
1084                  temp->status = READY; temp->wakevent = i + 1;
1085                  move(temp, &blocked, &runnable[temp->priority]); break;}
1086                  }
1087                  }
1088                  }
1089     )
1090         return rc;
1091 }
1092
1093 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1094 #define STACKMAGIC      0xBADBADBA
1095 static afs_int32
1096 Initialize_Stack(char *stackptr, int stacksize)
1097 {
1098     int i;
1099
1100     Debug(4, ("Entered Initialize_Stack"));
1101     if (lwp_stackUseEnabled)
1102         for (i = 0; i < stacksize; i++)
1103             stackptr[i] = i & 0xff;
1104     else
1105 #if defined(__hp9000s800)
1106         *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1107 #else
1108         *(afs_int32 *) stackptr = STACKMAGIC;
1109 #endif
1110     return 0;
1111 }
1112
1113 static int
1114 Stack_Used(char *stackptr, int stacksize)
1115 {
1116     int i;
1117
1118 #if defined(__hp9000s800)
1119     if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1120         return 0;
1121     else {
1122         for (i = stacksize - 1; i >= 0; i--)
1123             if ((unsigned char)stackptr[i] != (i & 0xff))
1124                 return (i);
1125         return 0;
1126     }
1127 #else
1128     if (*(afs_int32 *) stackptr == STACKMAGIC)
1129         return 0;
1130     else {
1131         for (i = 0; i < stacksize; i++)
1132             if ((unsigned char)stackptr[i] != (i & 0xff))
1133                 return (stacksize - i);
1134         return 0;
1135     }
1136 #endif
1137 }
1138
1139
1140 int
1141 LWP_NewRock(int Tag, char *Value)
1142     /* Finds a free rock and sets its value to Value.
1143      * Return codes:
1144      * LWP_SUCCESS      Rock did not exist and a new one was used
1145      * LWP_EBADROCK     Rock already exists.
1146      * LWP_ENOROCKS     All rocks are in use.
1147      *
1148      * From the above semantics, you can only set a rock value once.  This is specifically
1149      * to prevent multiple users of the LWP package from accidentally using the same Tag
1150      * value and clobbering others.  You can always use one level of indirection to obtain
1151      * a rock whose contents can change.
1152      */
1153 {
1154     int i;
1155     struct rock *ra;    /* rock array */
1156
1157     ra = lwp_cpptr->lwp_rlist;
1158
1159     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1160         if (ra[i].tag == Tag)
1161             return (LWP_EBADROCK);
1162
1163     if (lwp_cpptr->lwp_rused < MAXROCKS) {
1164         ra[lwp_cpptr->lwp_rused].tag = Tag;
1165         ra[lwp_cpptr->lwp_rused].value = Value;
1166         lwp_cpptr->lwp_rused++;
1167         return (LWP_SUCCESS);
1168     } else
1169         return (LWP_ENOROCKS);
1170 }
1171
1172
1173 int
1174 LWP_GetRock(int Tag, char **Value)
1175     /* Obtains the pointer Value associated with the rock Tag of this LWP.
1176      * Returns:
1177      * LWP_SUCCESS              if specified rock exists and Value has been filled
1178      * LWP_EBADROCK     rock specified does not exist
1179      */
1180 {
1181     int i;
1182     struct rock *ra;
1183
1184     ra = lwp_cpptr->lwp_rlist;
1185
1186     for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1187         if (ra[i].tag == Tag) {
1188             *Value = ra[i].value;
1189             return (LWP_SUCCESS);
1190         }
1191     return (LWP_EBADROCK);
1192 }
1193
1194
1195 #ifdef  AFS_AIX32_ENV
1196 int
1197 setlim(int limcon, uchar_t hard, int limit)
1198 {
1199     struct rlimit rlim;
1200
1201     (void)getrlimit(limcon, &rlim);
1202
1203     limit = limit * 1024;
1204     if (hard)
1205         rlim.rlim_max = limit;
1206     else if (limit == RLIM_INFINITY && geteuid() != 0)
1207         rlim.rlim_cur = rlim.rlim_max;
1208     else
1209         rlim.rlim_cur = limit;
1210
1211     /* Must use ulimit() due to Posix constraints */
1212     if (limcon == RLIMIT_FSIZE) {
1213         if (ulimit
1214             (UL_SETFSIZE,
1215              ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1216             printf("Can't %s%s limit\n",
1217                    limit == RLIM_INFINITY ? "remove" : "set",
1218                    hard ? " hard" : "");
1219             return (-1);
1220         }
1221     } else {
1222         if (setrlimit(limcon, &rlim) < 0) {
1223             perror("");
1224             printf("Can't %s%s limit\n",
1225                    limit == RLIM_INFINITY ? "remove" : "set",
1226                    hard ? " hard" : "");
1227             return (-1);
1228         }
1229     }
1230     return (0);
1231 }
1232 #endif
1233
1234 #ifdef  AFS_SUN5_ENV
1235 int
1236 LWP_NoYieldSignal(void *event)
1237 {
1238     return (LWP_INTERNALSIGNAL(event, 0));
1239 }
1240
1241 int
1242 LWP_SignalProcess(void *event)
1243 {
1244     return (LWP_INTERNALSIGNAL(event, 1));
1245 }
1246
1247 #endif