clean up headers, obsd socket.h needs types.h
[arla.git] / lwp / lwp_asm.c
blobae14bc87ecfed52f6f315dc6e052f5985f29991b
1 /*
2 ****************************************************************************
3 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
4 * *
5 * Permission to use, copy, modify, and distribute this software and its *
6 * documentation for any purpose and without fee is hereby granted, *
7 * provided that the above copyright notice appear in all copies and *
8 * that both that copyright notice and this permission notice appear in *
9 * supporting documentation, and that the name of IBM not be used in *
10 * advertising or publicity pertaining to distribution of the software *
11 * without specific, written prior permission. *
12 * *
13 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
15 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
16 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
17 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
18 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
19 ****************************************************************************
22 /*******************************************************************\
23 * *
24 * Information Technology Center *
25 * Carnegie-Mellon University *
26 * *
27 * *
28 \*******************************************************************/
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
36 #endif
37 #ifdef HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #ifdef HAVE_FCNTL_H
45 #include <fcntl.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
51 /* allocate externs here */
52 #define LWP_KERNEL
54 #include <lwp.h>
55 #include "preempt.h"
57 RCSID("$Id$");
59 #ifdef AFS_AIX32_ENV
60 #include <ulimit.h>
61 #include <sys/errno.h>
62 #include <sys/user.h>
63 #include <sys/pseg.h>
64 #include <sys/core.h>
65 #pragma alloca
66 #endif
68 #define READY 2
69 #define WAITING 3
70 #define DESTROYED 4
71 #define QWAITING 5
75 * Make sure that alignment and saving of data is right
78 #if defined(__alpha) || defined(__uxpv__) || defined(__sparcv9) || defined(__x86_64__)
79 #define REGSIZE 8
80 #else
81 #define REGSIZE 4
82 #endif
85 * Space before first stack frame expressed in registers.
87 * This should maybe be a ABI specific value defined somewhere else.
90 #ifdef __hp9000s800
91 #define STACK_HEADROOM 16
92 #elif defined(__s390__)
93 #define STACK_HEADROOM 24
94 #else
95 #define STACK_HEADROOM 5
96 #endif
98 /* Debugging macro */
99 #ifdef DEBUG
100 #define Debug(level, msg)\
101 if (lwp_debug && lwp_debug >= level) {\
102 printf("***LWP (%p): ", lwp_cpptr);\
103 printf msg;\
104 putchar('\n');\
107 #else
108 #define Debug(level, msg)
110 #endif
112 /* Prototypes */
113 static void Abort_LWP(char *msg) ;
114 static void Dispatcher(void);
115 static void Create_Process_Part2(void);
116 static void purge_dead_pcbs(void) ;
117 static void Overflow_Complain (void) ;
118 static void Dispose_of_Dead_PCB (PROCESS cur) ;
119 static void Free_PCB(PROCESS pid) ;
120 static void Exit_LWP(void);
121 static void Initialize_PCB(PROCESS temp, int priority, char *stack,
122 int stacksize, void (*ep)() , char *parm,
123 const char *name) ;
124 static long Initialize_Stack(char *stackptr,int stacksize) ;
125 static int Stack_Used(char *stackptr, int stacksize) ;
126 static int Internal_Signal(char *event) ;
127 char (*RC_to_ASCII());
129 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
131 struct QUEUE {
132 PROCESS head;
133 int count;
134 } runnable[MAX_PRIORITIES], blocked;
136 * Invariant for runnable queues: The head of each queue points to the
137 * currently running process if it is in that queue, or it points to the
138 * next process in that queue that should run.
141 /* Offset of stack field within pcb -- used by stack checking stuff */
142 int stack_offset;
144 /* special user-tweakable option for AIX */
145 int lwp_MaxStackSize = 32768;
147 /* biggest LWP stack created so far */
148 int lwp_MaxStackSeen = 0;
150 /* Stack checking action */
151 int lwp_overflowAction = LWP_SOABORT;
153 /* Controls stack size counting. */
154 int lwp_stackUseEnabled = 1;
156 int lwp_nextindex;
158 static void
159 lwp_remove(PROCESS p, struct QUEUE *q)
161 /* Special test for only element on queue */
162 if (q->count == 1)
163 q -> head = NULL;
164 else {
165 /* Not only element, do normal remove */
166 p -> next -> prev = p -> prev;
167 p -> prev -> next = p -> next;
169 /* See if head pointing to this element */
170 if (q->head == p) q -> head = p -> next;
171 q->count--;
172 p -> next = p -> prev = NULL;
175 static void
176 insert(PROCESS p, struct QUEUE *q)
178 if (q->head == NULL) { /* Queue is empty */
179 q -> head = p;
180 p -> next = p -> prev = p;
181 } else { /* Regular insert */
182 p -> prev = q -> head -> prev;
183 q -> head -> prev -> next = p;
184 q -> head -> prev = p;
185 p -> next = q -> head;
187 q->count++;
190 static void
191 move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
193 lwp_remove(p, from);
195 insert(p, to);
198 /* Iterator macro */
199 #define for_all_elts(var, q, body)\
201 PROCESS var, _NEXT_;\
202 int _I_;\
203 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
204 _NEXT_ = var -> next;\
205 body\
209 /* */
210 /*****************************************************************************\
212 * Following section documents the Assembler interfaces used by LWP code *
214 \*****************************************************************************/
217 * savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
218 * XXX - the above prototype is a lie.
219 * Stub for Assembler routine that will
220 * save the current SP value in the passed
221 * context savearea and call the function
222 * whose entry point is in ep. If the sp
223 * parameter is NULL, the current stack is
224 * used, otherwise sp becomes the new stack
225 * pointer.
227 * returnto(struct lwp_context *savearea);
229 * Stub for Assembler routine that will
230 * restore context from a passed savearea
231 * and return to the restored C frame.
235 void savecontext(void (*)(), struct lwp_context *, char *);
236 void returnto(struct lwp_context *);
238 /* Macro to force a re-schedule. Strange name is historical */
239 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
241 static struct lwp_ctl *lwp_init = 0;
243 int
244 LWP_QWait(void)
246 PROCESS tp;
247 (tp=lwp_cpptr) -> status = QWAITING;
248 lwp_remove(tp, &runnable[tp->priority]);
249 Set_LWP_RC();
250 return LWP_SUCCESS;
254 LWP_QSignal(PROCESS pid)
256 if (pid->status == QWAITING) {
257 pid->status = READY;
258 insert(pid, &runnable[pid->priority]);
259 return LWP_SUCCESS;
261 else return LWP_ENOWAIT;
264 #ifdef AFS_AIX32_ENV
265 char *
266 reserveFromStack(size)
267 long size;
269 char *x;
270 x = alloca(size);
271 return x;
273 #endif
275 #if defined(LWP_REDZONE) && defined(HAVE_MMAP)
278 * Redzone protection of stack
280 * We protect one page before and one after the stack to make sure
281 * none over/under runs the stack. The size of the stack is saved one
282 * the first page together with a magic number to make sure we free
283 * the right pages.
285 * If the operating system doesn't support mmap, turn redzone off in
286 * the autoconf glue.
289 #define P_SIZE_OFFSET 16
290 #define P_MAGIC 0x7442e938
292 static void *
293 lwp_stackmalloc(size_t size)
295 char *p, *p_after, *p_before;
296 size_t pagesize = getpagesize();
297 int pages = (size - 1) / pagesize + 1;
298 int fd = -1;
300 #ifndef MAP_ANON
301 #define MAP_ANON 0
302 #ifndef _PATH_DEV_ZERO
303 #define _PATH_DEV_ZERO "/dev/zero"
304 #endif
305 fd = open(_PATH_DEV_ZERO, O_RDWR, 0644);
306 #endif
308 p = mmap(0, (pages + 2) * pagesize, PROT_READ | PROT_WRITE,
309 MAP_PRIVATE | MAP_ANON, fd, 0);
310 if (p == MAP_FAILED) {
311 perror("mmap");
312 abort();
315 p_before = p;
316 p += pagesize;
317 p_after = p + pages * pagesize;
319 /* store the magic and the length in the first page */
321 *((unsigned long *)p_before) = P_MAGIC;
322 *((unsigned long *)(p_before + P_SIZE_OFFSET)) = (pages + 2) * pagesize;
324 /* protect pages */
326 if (mprotect(p_before, pagesize, PROT_NONE) < 0) {
327 perror("mprotect before");
328 abort();
330 if (mprotect(p_after, pagesize, PROT_NONE) < 0) {
331 perror("mprotect after");
332 abort();
334 return p;
337 static void
338 lwp_stackfree(void *ptr, size_t len)
340 size_t pagesize = getpagesize();
341 char *realptr;
342 unsigned long magic;
343 size_t length;
345 if (((size_t)ptr) % pagesize != 0)
346 abort();
348 realptr = ((char *)ptr) - pagesize;
350 if (mprotect(realptr, pagesize, PROT_READ) < 0) {
351 perror("mprotect");
352 abort();
355 magic = *((unsigned long *)realptr);
356 if (magic != P_MAGIC)
357 abort();
358 length = *((unsigned long *)(realptr + P_SIZE_OFFSET));
359 if (len != length - 2 * pagesize)
360 abort();
362 if (munmap(realptr, length) < 0) {
363 perror("munmap");
364 exit(1);
368 #else
370 static void *
371 lwp_stackmalloc(size_t size)
373 return malloc(size);
376 static void
377 lwp_stackfree(void *ptr, size_t len)
379 free(ptr);
381 #endif
384 LWP_CreateProcess(void (*ep)(), int stacksize, int priority,
385 char *parm, const char *name, PROCESS *pid)
387 PROCESS temp, temp2;
388 #ifdef AFS_AIX32_ENV
389 static char *stackptr = 0;
390 #else
391 char *stackptr;
392 #endif
395 * on some systems (e.g. hpux), a minimum usable stack size has
396 * been discovered
398 if (stacksize < AFS_LWP_MINSTACKSIZE)
399 stacksize = AFS_LWP_MINSTACKSIZE;
401 /* more stack size computations; keep track of for IOMGR */
402 if (lwp_MaxStackSeen < stacksize)
403 lwp_MaxStackSeen = stacksize;
405 Debug(0, ("Entered LWP_CreateProcess"))
406 /* Throw away all dead process control blocks */
407 purge_dead_pcbs();
408 if (!lwp_init)
409 return LWP_EINIT;
412 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
413 if (temp == NULL) {
414 Set_LWP_RC();
415 return LWP_ENOMEM;
418 /* align stacksize */
419 stacksize = REGSIZE * ((stacksize+REGSIZE-1) / REGSIZE);
421 #ifdef AFS_AIX32_ENV
422 if (!stackptr) {
424 * The following signal action for AIX is necessary so that in case of a
425 * crash (i.e. core is generated) we can include the user's data section
426 * in the core dump. Unfortunately, by default, only a partial core is
427 * generated which, in many cases, isn't too useful.
429 * We also do it here in case the main program forgets to do it.
431 struct sigaction nsa;
432 extern int geteuid();
434 sigemptyset(&nsa.sa_mask);
435 nsa.sa_handler = SIG_DFL;
436 nsa.sa_flags = SA_FULLDUMP;
437 sigaction(SIGSEGV, &nsa, NULL);
440 * First we need to increase the default resource limits,
441 * if necessary, so that we can guarantee that we have the
442 * resources to create the core file, but we can't always
443 * do it as an ordinary user.
445 if (!geteuid()) {
446 setlim(RLIMIT_FSIZE, 0, 1048575); /* 1 Gig */
447 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
448 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
451 * Now reserve in one scoop all the stack space that will be used
452 * by the particular application's main (i.e. non-lwp) body. This
453 * is plenty space for any of our applications.
455 stackptr = reserveFromStack(lwp_MaxStackSize);
457 stackptr -= stacksize;
458 #else /* !AFS_AIX32_ENV */
459 if ((stackptr = (char *) lwp_stackmalloc(stacksize)) == NULL) {
460 Set_LWP_RC();
461 return LWP_ENOMEM;
463 #endif /* AFS_AIX32_ENV */
464 if (priority < 0 || priority >= MAX_PRIORITIES) {
465 Set_LWP_RC();
466 return LWP_EBADPRI;
468 Initialize_Stack(stackptr, stacksize);
469 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
470 insert(temp, &runnable[priority]);
471 temp2 = lwp_cpptr;
473 if (PRE_Block != 0)
474 Abort_LWP("PRE_Block not 0");
476 /* Gross hack: beware! */
477 PRE_Block = 1;
478 lwp_cpptr = temp;
479 #ifdef __hp9000s800
480 savecontext(Create_Process_Part2, &temp2->context,
481 stackptr + (REGSIZE * STACK_HEADROOM));
482 #else
483 savecontext(Create_Process_Part2, &temp2->context,
484 stackptr + stacksize - (REGSIZE * STACK_HEADROOM));
485 #endif
486 /* End of gross hack */
488 Set_LWP_RC();
489 *pid = temp;
490 return 0;
493 /* returns pid of current process */
495 LWP_CurrentProcess(PROCESS *pid)
497 Debug(0, ("Entered Current_Process"))
498 if (lwp_init) {
499 *pid = lwp_cpptr;
500 return LWP_SUCCESS;
501 } else
502 return LWP_EINIT;
505 #define LWPANCHOR (*lwp_init)
507 /* destroy a lightweight process */
509 LWP_DestroyProcess(PROCESS pid)
511 PROCESS temp;
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 #ifdef __hp9000s800
523 savecontext(Dispatcher, &(temp -> context),
524 &(LWPANCHOR.dsptchstack[(REGSIZE * STACK_HEADROOM)]));
525 #else
526 savecontext(Dispatcher, &(temp -> context),
527 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)
528 - (REGSIZE * STACK_HEADROOM)]));
529 #endif
531 return LWP_SUCCESS;
532 } else
533 return LWP_EINIT;
536 /* explicit voluntary preemption */
537 int
538 LWP_DispatchProcess(void)
540 Debug(2, ("Entered Dispatch_Process"))
541 if (lwp_init) {
542 Set_LWP_RC();
543 return LWP_SUCCESS;
544 } else
545 return LWP_EINIT;
548 #ifdef DEBUG
549 static void Dump_One_Process(PROCESS pid);
551 static void
552 Dump_Processes(void)
554 if (lwp_init) {
555 int i;
556 for (i=0; i<MAX_PRIORITIES; i++)
557 for_all_elts(x, runnable[i], {
558 printf("[Priority %d]\n", i);
559 Dump_One_Process(x);
561 for_all_elts(x, blocked, { Dump_One_Process(x); })
562 } else
563 printf("***LWP: LWP support not initialized\n");
565 #endif
567 /* returns process priority */
569 LWP_GetProcessPriority(PROCESS pid, int *priority)
571 Debug(0, ("Entered Get_Process_Priority"))
572 if (lwp_init) {
573 *priority = pid -> priority;
574 return 0;
575 } else
576 return LWP_EINIT;
580 LWP_InitializeProcessSupport(int priority, PROCESS *pid)
582 PROCESS temp;
583 struct lwp_pcb dummy;
584 int i;
586 Debug(0, ("Entered LWP_InitializeProcessSupport"))
587 if (lwp_init != NULL) return LWP_SUCCESS;
589 /* Set up offset for stack checking -- do this as soon as possible */
590 stack_offset = (char *) &dummy.stack - (char *) &dummy;
592 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
593 for (i=0; i<MAX_PRIORITIES; i++) {
594 runnable[i].head = NULL;
595 runnable[i].count = 0;
597 blocked.head = NULL;
598 blocked.count = 0;
599 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
600 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
601 if (lwp_init == NULL || temp == NULL)
602 Abort_LWP("Insufficient Storage to Initialize LWP Support");
603 LWPANCHOR.processcnt = 1;
604 LWPANCHOR.outerpid = temp;
605 LWPANCHOR.outersp = NULL;
606 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
607 "Main Process [created by LWP]");
608 insert(temp, &runnable[priority]);
609 savecontext(Dispatcher, &temp->context, NULL);
610 LWPANCHOR.outersp = temp -> context.topstack;
611 Set_LWP_RC();
612 *pid = temp;
613 return LWP_SUCCESS;
616 /* signal the occurence of an event */
618 LWP_INTERNALSIGNAL(void *event, int yield)
620 Debug(2, ("Entered LWP_SignalProcess"))
621 if (lwp_init) {
622 int rc;
623 rc = Internal_Signal(event);
624 if (yield) Set_LWP_RC();
625 return rc;
626 } else
627 return LWP_EINIT;
630 /* terminate all LWP support */
632 LWP_TerminateProcessSupport(void)
634 int i;
636 Debug(0, ("Entered Terminate_Process_Support"))
637 if (lwp_init == NULL) return LWP_EINIT;
638 if (lwp_cpptr != LWPANCHOR.outerpid)
639 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
640 for (i=0; i<MAX_PRIORITIES; i++)
641 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
642 for_all_elts(cur, blocked, { Free_PCB(cur); })
643 free(lwp_init);
644 lwp_init = NULL;
645 return LWP_SUCCESS;
648 /* wait on m of n events */
650 LWP_MwaitProcess(int wcount, char *evlist[])
652 int ecount, i;
655 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
657 if (evlist == NULL) {
658 Set_LWP_RC();
659 return LWP_EBADCOUNT;
662 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
664 if (ecount == 0) {
665 Set_LWP_RC();
666 return LWP_EBADCOUNT;
669 if (lwp_init) {
671 if (wcount>ecount || wcount<0) {
672 Set_LWP_RC();
673 return LWP_EBADCOUNT;
675 if (ecount > lwp_cpptr->eventlistsize) {
677 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist,
678 ecount*sizeof(char *));
679 lwp_cpptr->eventlistsize = ecount;
681 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
682 if (wcount > 0) {
683 lwp_cpptr -> status = WAITING;
685 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
687 lwp_cpptr -> wakevent = 0;
688 lwp_cpptr -> waitcnt = wcount;
689 lwp_cpptr -> eventcnt = ecount;
691 Set_LWP_RC();
693 return LWP_SUCCESS;
696 return LWP_EINIT;
699 /* wait on a single event */
701 LWP_WaitProcess(void *event)
703 char *tempev[2];
705 Debug(2, ("Entered Wait_Process"))
706 if (event == NULL) return LWP_EBADEVENT;
707 tempev[0] = event;
708 tempev[1] = NULL;
709 return LWP_MwaitProcess(1, tempev);
713 LWP_StackUsed(PROCESS pid, int *max, int *used)
715 *max = pid -> stacksize;
716 *used = Stack_Used(pid->stack, *max);
717 if (*used == 0)
718 return LWP_NO_STACK;
719 return LWP_SUCCESS;
723 * The following functions are strictly
724 * INTERNAL to the LWP support package.
727 static void
728 Abort_LWP(char *msg)
730 struct lwp_context tempcontext;
732 Debug(0, ("Entered Abort_LWP"))
733 printf("***LWP: %s\n",msg);
734 printf("***LWP: Abort --- dumping PCBs ...\n");
735 #ifdef DEBUG
736 Dump_Processes();
737 #endif
738 if (LWPANCHOR.outersp == NULL)
739 Exit_LWP();
740 else
741 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
744 /* creates a context for the new process */
745 static void
746 Create_Process_Part2(void)
748 PROCESS temp;
750 Debug(2, ("Entered Create_Process_Part2"))
751 temp = lwp_cpptr; /* Get current process id */
752 savecontext(Dispatcher, &temp->context, NULL);
753 (*temp->ep)(temp->parm);
754 LWP_DestroyProcess(temp);
757 /* remove a PCB from the process list */
758 static void
759 Delete_PCB(PROCESS pid)
761 Debug(4, ("Entered Delete_PCB"))
762 lwp_remove(pid, (pid->blockflag ||
763 pid->status==WAITING ||
764 pid->status==DESTROYED
765 ? &blocked
766 : &runnable[pid->priority]));
767 LWPANCHOR.processcnt--;
770 #ifdef DEBUG
771 static void
772 Dump_One_Process(PROCESS pid)
774 int i;
776 printf("***LWP: Process Control Block at %p\n", pid);
777 printf("***LWP: Name: %s\n", pid->name);
778 if (pid->ep != NULL)
779 printf("***LWP: Initial entry point: %p\n", pid->ep);
780 if (pid->blockflag) printf("BLOCKED and ");
781 switch (pid->status) {
782 case READY: printf("READY"); break;
783 case WAITING: printf("WAITING"); break;
784 case DESTROYED: printf("DESTROYED"); break;
785 default: printf("unknown");
787 putchar('\n');
788 printf("***LWP: Priority: %d \tInitial parameter: %p\n",
789 pid->priority, pid->parm);
790 if (pid->stacksize != 0) {
791 printf("***LWP: Stacksize: %d \tStack base address: %p\n",
792 pid->stacksize, pid->stack);
793 printf("***LWP: HWM stack usage: ");
794 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
796 printf("***LWP: Current Stack Pointer: %p\n", pid->context.topstack);
797 if (pid->eventcnt > 0) {
798 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
799 printf("***LWP: Event id list:");
800 for (i=0;i<pid->eventcnt;i++)
801 printf(" %p", pid->eventlist[i]);
802 putchar('\n');
804 if (pid->wakevent>0)
805 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
807 #endif
809 static void
810 purge_dead_pcbs(void)
812 for_all_elts(cur, blocked, {
813 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);
817 int LWP_TraceProcesses = 0;
819 /* Lightweight process dispatcher */
820 static void
821 Dispatcher(void)
823 int i;
824 #ifdef DEBUG
825 static int dispatch_count = 0;
827 if (LWP_TraceProcesses > 0) {
828 for (i=0; i<MAX_PRIORITIES; i++) {
829 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
830 for_all_elts(p, runnable[i], {
831 printf(" \"%s\"", p->name);
833 puts("]");
835 printf("[Blocked (%d):", blocked.count);
836 for_all_elts(p, blocked, {
837 printf(" \"%s\"", p->name);
839 puts("]");
841 #endif
844 * Check for stack overflow if this lwp has a stack. Check for
845 * the guard word at the front of the stack being damaged and
846 * for the stack pointer being below the front of the stack.
847 * WARNING! This code assumes that stacks grow downward.
849 #ifdef __hp9000s800
850 /* Fix this (stackcheck at other end of stack???) */
851 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
852 && (lwp_cpptr->stackcheck !=
853 *(long *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
854 || lwp_cpptr->context.topstack >
855 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
856 #else
857 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
858 && (lwp_cpptr->stackcheck != *(long *)(lwp_cpptr->stack)
859 || lwp_cpptr->context.topstack < lwp_cpptr->stack)) {
860 #endif
862 printf("stackcheck = %lul: stack = %lul\n",
863 lwp_cpptr->stackcheck,
864 *(long *)lwp_cpptr->stack);
865 printf("topstack = %lul\n", *(long *)lwp_cpptr->context.topstack);
867 switch (lwp_overflowAction) {
868 case LWP_SOQUIET:
869 break;
870 case LWP_SOABORT:
871 Overflow_Complain();
872 abort ();
873 case LWP_SOMESSAGE:
874 default:
875 Overflow_Complain();
876 lwp_overflowAction = LWP_SOQUIET;
877 break;
883 * Move head of current runnable queue forward if current LWP
884 * is still in it.
886 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
887 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head->next;
889 /* Find highest priority with runnable processes. */
890 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
891 if (runnable[i].head != NULL)
892 break;
894 if (i < 0)
895 Abort_LWP("No READY processes");
897 #ifdef DEBUG
898 if (LWP_TraceProcesses > 0)
899 printf("Dispatch %d [PCB at %p] \"%s\"\n",
900 ++dispatch_count,
901 runnable[i].head,
902 runnable[i].head->name);
903 #endif
904 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
905 lwp_cpptr = runnable[i].head;
907 returnto(&lwp_cpptr->context);
910 /* Complain of a stack overflow to stderr without using stdio. */
911 static void
912 Overflow_Complain (void)
914 static char msg1[] = "LWP: stack overflow in process ";
915 static char msg2[] = "!\n";
917 write (2, msg1, sizeof(msg1) - 1);
918 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
919 write (2, msg2, sizeof(msg2) - 1);
922 static void
923 Dispose_of_Dead_PCB (PROCESS cur)
925 Debug(4, ("Entered Dispose_of_Dead_PCB"))
926 Delete_PCB(cur);
927 Free_PCB(cur);
929 Internal_Signal(cur);
933 static void
934 Exit_LWP(void)
936 abort();
939 static void
940 Free_PCB(PROCESS pid)
942 Debug(4, ("Entered Free_PCB"))
943 if (pid -> stack != NULL) {
944 Debug(0, ("HWM stack usage: %d, [PCB at %p]",
945 Stack_Used(pid->stack,pid->stacksize), pid))
946 lwp_stackfree(pid -> stack, pid->stacksize);
948 if (pid->eventlist != NULL) free(pid->eventlist);
949 free(pid);
952 static void
953 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
954 void (*ep)(), char *parm, const char *name)
956 Debug(4, ("Entered Initialize_PCB"))
957 if (name != NULL) {
958 strncpy(temp -> name, name, sizeof(temp -> name));
959 temp -> name[sizeof(temp -> name) - 1] = '\0';
960 } else
961 temp -> name[0] = '\0';
962 temp -> status = READY;
963 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
964 temp -> eventlistsize = EVINITSIZE;
965 temp -> eventcnt = 0;
966 temp -> wakevent = 0;
967 temp -> waitcnt = 0;
968 temp -> blockflag = 0;
969 temp -> iomgrRequest = 0;
970 temp -> priority = priority;
971 temp -> index = lwp_nextindex++;
972 temp -> stack = stack;
973 temp -> stacksize = stacksize;
974 #ifdef __hp9000s800
975 if (temp -> stack != NULL)
976 temp -> stackcheck = *(long *) ((temp -> stack) + stacksize - REGSIZE);
977 #else
978 if (temp -> stack != NULL)
979 temp -> stackcheck = *(long *) (temp -> stack);
980 #endif
981 temp -> ep = ep;
982 temp -> parm = parm;
983 temp -> misc = NULL; /* currently unused */
984 temp -> next = NULL;
985 temp -> prev = NULL;
986 temp -> rused = 0;
987 temp -> level = 1; /* non-preemptable */
990 static int
991 Internal_Signal(char *event)
993 int rc = LWP_ENOWAIT;
994 int i;
996 Debug(0, ("Entered Internal_Signal [event id %p]", event))
997 if (!lwp_init) return LWP_EINIT;
998 if (event == NULL) return LWP_EBADEVENT;
999 for_all_elts(temp, blocked, {
1000 if (temp->status == WAITING)
1001 for (i=0; i < temp->eventcnt; i++) {
1002 if (temp -> eventlist[i] == event) {
1003 temp -> eventlist[i] = NULL;
1004 rc = LWP_SUCCESS;
1005 Debug(0, ("Signal satisfied for PCB %p", temp))
1006 if (--temp->waitcnt == 0) {
1007 temp -> status = READY;
1008 temp -> wakevent = i+1;
1009 move(temp, &blocked, &runnable[temp->priority]);
1010 break;
1015 return rc;
1018 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1019 #define STACKMAGIC 0xBADBADBA
1020 static long
1021 Initialize_Stack(char *stackptr, int stacksize)
1023 int i;
1025 Debug(4, ("Entered Initialize_Stack"))
1026 if (lwp_stackUseEnabled)
1027 for (i=0; i<stacksize; i++)
1028 stackptr[i] = i &0xff;
1029 else
1030 #ifdef __hp9000s800
1031 *(long *)(stackptr + stacksize - 4) = STACKMAGIC;
1032 #else
1033 *(long *)stackptr = STACKMAGIC;
1034 #endif
1035 return 0; /* XXX - added. No clue what it should be */
1038 static int
1039 Stack_Used(char *stackptr, int stacksize)
1041 int i;
1043 #ifdef __hp9000s800
1044 if (*(long *) (stackptr + stacksize - 4) == STACKMAGIC)
1045 return 0;
1046 else {
1047 for (i = stacksize - 1; i >= 0 ; i--)
1048 if ((unsigned char) stackptr[i] != (i & 0xff))
1049 return (i);
1050 return 0;
1052 #else
1053 if (*(long *) stackptr == STACKMAGIC)
1054 return 0;
1055 else {
1056 for (i = 0; i < stacksize; i++)
1057 if ((unsigned char) stackptr[i] != (i & 0xff))
1058 return (stacksize - i);
1059 return 0;
1061 #endif
1066 * Finds a free rock and sets its value to Value.
1067 * Return codes:
1068 * LWP_SUCCESS Rock did not exist and a new one was used
1069 * LWP_EBADROCK Rock already exists.
1070 * LWP_ENOROCKS All rocks are in use.
1072 * From the above semantics, you can only set a rock value once.
1073 * This is specificallY to prevent multiple users of the LWP package from
1074 * accidentally using the same Tag value and clobbering others. You can always
1075 * use one level of indirection to obtain a rock whose contents can change.
1079 LWP_NewRock(int Tag, char *Value)
1081 int i;
1082 struct rock *ra; /* rock array */
1084 ra = lwp_cpptr->rlist;
1086 for (i = 0; i < lwp_cpptr->rused; i++)
1087 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1089 if (lwp_cpptr->rused < MAXROCKS)
1091 ra[lwp_cpptr->rused].tag = Tag;
1092 ra[lwp_cpptr->rused].value = Value;
1093 lwp_cpptr->rused++;
1094 return(LWP_SUCCESS);
1096 else return(LWP_ENOROCKS);
1100 * Obtains the pointer Value associated with the rock Tag of this LWP.
1101 * Returns:
1102 * LWP_SUCCESS if specified rock exists and Value has been filled
1103 * LWP_EBADROCK rock specified does not exist
1106 LWP_GetRock(int Tag, char **Value)
1108 int i;
1109 struct rock *ra;
1111 ra = lwp_cpptr->rlist;
1113 for (i = 0; i < lwp_cpptr->rused; i++) {
1114 if (ra[i].tag == Tag) {
1115 *Value = ra[i].value;
1116 return(LWP_SUCCESS);
1119 return(LWP_EBADROCK);
1123 #ifdef AFS_AIX32_ENV
1124 setlim(limcon, hard, limit)
1125 int limcon;
1126 uchar_t hard;
1128 struct rlimit rlim;
1130 (void) getrlimit(limcon, &rlim);
1132 limit = limit * 1024;
1133 if (hard)
1134 rlim.rlim_max = limit;
1135 else if (limit == RLIM_INFINITY && geteuid() != 0)
1136 rlim.rlim_cur = rlim.rlim_max;
1137 else
1138 rlim.rlim_cur = limit;
1140 /* Must use ulimit() due to Posix constraints */
1141 if (limcon == RLIMIT_FSIZE) {
1142 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1143 printf("Can't %s%s limit\n",
1144 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1145 return (-1);
1147 } else {
1148 if (setrlimit(limcon, &rlim) < 0) {
1149 perror("");
1150 printf("Can't %s%s limit\n",
1151 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1152 return (-1);
1155 return (0);
1159 #ifdef notdef
1161 * Print the specific limit out
1163 plim(name, lc, hard)
1164 char *name;
1165 long lc;
1166 uchar_t hard;
1168 struct rlimit rlim;
1169 int lim;
1171 printf("%s \t", name);
1172 (void) getrlimit(lc, &rlim);
1173 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1174 if (lim == RLIM_INFINITY)
1175 printf("unlimited");
1176 printf("%d %s", lim / 1024, "kbytes");
1177 printf("\n");
1179 #endif
1180 #endif