Import Debian changes 1.8.5-1
[hcoop/debian/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 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 = 0x%" AFS_PTR_FMT ": stackptr = 0x%" AFS_PTR_FMT ": 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