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