2 ****************************************************************************
3 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
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. *
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 /*******************************************************************\
24 * Information Technology Center *
25 * Carnegie-Mellon University *
27 \*******************************************************************/
33 /* allocate externs here */
38 #include <sys/errno.h>
45 extern char* getenv();
48 #if !defined(USE_PTHREADS) && !defined(USE_SOLARIS_THREADS)
51 extern void *malloc(int size);
52 extern void *realloc(void *ptr, int size);
53 extern int PRE_Block; /* from preempt.c */
55 extern char PRE_Block; /* from preempt.c */
66 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
75 #define Debug(level, msg)\
76 if (lwp_debug && lwp_debug >= level) {\
77 printf("***LWP (0x%x): ", lwp_cpptr);\
83 #define Debug(level, msg)
87 static int Dispatcher();
88 static int Create_Process_Part2();
89 static int Exit_LWP();
90 static afs_int32 Initialize_Stack();
91 static int Stack_Used();
92 char (*RC_to_ASCII());
94 static void Abort_LWP();
95 static void Overflow_Complain();
96 static void Initialize_PCB();
97 static void Dispose_of_Dead_PCB();
98 static void Free_PCB();
99 static int Internal_Signal();
100 static purge_dead_pcbs();
102 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
107 } runnable[MAX_PRIORITIES], blocked;
108 /* Invariant for runnable queues: The head of each queue points to the currently running process if it is in that queue, or it points to the next process in that queue that should run. */
110 /* Offset of stack field within pcb -- used by stack checking stuff */
113 /* special user-tweakable option for AIX */
114 int lwp_MaxStackSize = 32768;
116 /* biggest LWP stack created so far */
117 int lwp_MaxStackSeen = 0;
119 /* Stack checking action */
120 int lwp_overflowAction = LWP_SOABORT;
122 /* Controls stack size counting. */
123 int lwp_stackUseEnabled = TRUE; /* pay the price */
127 /* Minimum stack size */
128 int lwp_MinStackSize=0;
130 static lwp_remove(p, q)
132 register struct QUEUE *q;
134 /* Special test for only element on queue */
138 /* Not only element, do normal remove */
139 p -> next -> prev = p -> prev;
140 p -> prev -> next = p -> next;
142 /* See if head pointing to this element */
143 if (q->head == p) q -> head = p -> next;
145 p -> next = p -> prev = NULL;
150 register struct QUEUE *q;
152 if (q->head == NULL) { /* Queue is empty */
154 p -> next = p -> prev = p;
155 } else { /* Regular insert */
156 p -> prev = q -> head -> prev;
157 q -> head -> prev -> next = p;
158 q -> head -> prev = p;
159 p -> next = q -> head;
164 static move(p, from, to)
166 struct QUEUE *from, *to;
176 #define for_all_elts(var, q, body)\
178 register PROCESS var, _NEXT_;\
180 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
181 _NEXT_ = var -> next;\
187 /*****************************************************************************\
189 * Following section documents the Assembler interfaces used by LWP code *
191 \*****************************************************************************/
194 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
196 Stub for Assembler routine that will
197 save the current SP value in the passed
198 context savearea and call the function
199 whose entry point is in ep. If the sp
200 parameter is NULL, the current stack is
201 used, otherwise sp becomes the new stack
204 returnto(struct lwp_context *savearea);
206 Stub for Assembler routine that will
207 restore context from a passed savearea
208 and return to the restored C frame.
212 /* Macro to force a re-schedule. Strange name is historical */
213 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
215 static struct lwp_ctl *lwp_init = 0;
218 {register PROCESS tp;
219 (tp=lwp_cpptr) -> status = QWAITING;
220 lwp_remove(tp, &runnable[tp->priority]);
226 register PROCESS pid; {
227 if (pid->status == QWAITING) {
229 insert(pid, &runnable[pid->priority]);
232 else return LWP_ENOWAIT;
236 char *reserveFromStack(size)
237 register afs_int32 size;
245 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
247 int stacksize, priority;
254 static char *stackptr = 0;
259 #if defined(AFS_LWP_MINSTACKSIZE)
261 * on some systems (e.g. hpux), a minimum usable stack size has
264 if (stacksize < lwp_MinStackSize) {
265 stacksize = lwp_MinStackSize;
267 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
268 /* more stack size computations; keep track of for IOMGR */
269 if (lwp_MaxStackSeen < stacksize)
270 lwp_MaxStackSeen = stacksize;
272 Debug(0, ("Entered LWP_CreateProcess"))
273 /* Throw away all dead process control blocks */
276 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
281 if (stacksize < MINSTACK)
285 stacksize = 8 * ((stacksize+7) / 8);
287 stacksize = 4 * ((stacksize+3) / 4);
292 * The following signal action for AIX is necessary so that in case of a
293 * crash (i.e. core is generated) we can include the user's data section
294 * in the core dump. Unfortunately, by default, only a partial core is
295 * generated which, in many cases, isn't too useful.
297 * We also do it here in case the main program forgets to do it.
299 struct sigaction nsa;
300 extern uid_t geteuid();
302 sigemptyset(&nsa.sa_mask);
303 nsa.sa_handler = SIG_DFL;
304 nsa.sa_flags = SA_FULLDUMP;
305 sigaction(SIGABRT, &nsa, NULL);
306 sigaction(SIGSEGV, &nsa, NULL);
309 * First we need to increase the default resource limits,
310 * if necessary, so that we can guarantee that we have the
311 * resources to create the core file, but we can't always
312 * do it as an ordinary user.
315 /* vos dump causes problems */
316 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
317 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
318 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
321 * Now reserve in one scoop all the stack space that will be used
322 * by the particular application's main (i.e. non-lwp) body. This
323 * is plenty space for any of our applications.
325 stackptr = reserveFromStack(lwp_MaxStackSize);
327 stackptr -= stacksize;
329 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
333 /* Round stack pointer to byte boundary */
334 stackptr = (char *)(8 * (((long)stackptr+7) / 8));
336 if (priority < 0 || priority >= MAX_PRIORITIES) {
340 Initialize_Stack(stackptr, stacksize);
341 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
342 insert(temp, &runnable[priority]);
344 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
346 /* Gross hack: beware! */
350 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
353 /* Need to have the sp on an 8-byte boundary for storing doubles. */
354 savecontext(Create_Process_Part2, &temp2->context,
355 stackptr+stacksize-16); /* 16 = 2 * jmp_buf_type*/
357 savecontext(Create_Process_Part2, &temp2->context,
358 stackptr+stacksize-sizeof(void *));
361 /* End of gross hack */
371 int LWP_CreateProcess2(ep, stacksize, priority, parm, name, pid)
373 int stacksize, priority;
381 #if defined(AFS_LWP_MINSTACKSIZE)
383 * on some systems (e.g. hpux), a minimum usable stack size has
386 if (stacksize < lwp_MinStackSize) {
387 stacksize = lwp_MinStackSize;
389 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
390 /* more stack size computations; keep track of for IOMGR */
391 if (lwp_MaxStackSeen < stacksize)
392 lwp_MaxStackSeen = stacksize;
394 Debug(0, ("Entered LWP_CreateProcess"))
395 /* Throw away all dead process control blocks */
398 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
403 if (stacksize < MINSTACK)
407 stacksize = 8 * ((stacksize+7) / 8);
409 stacksize = 4 * ((stacksize+3) / 4);
411 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
415 if (priority < 0 || priority >= MAX_PRIORITIES) {
419 Initialize_Stack(stackptr, stacksize);
420 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
421 insert(temp, &runnable[priority]);
423 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
425 /* Gross hack: beware! */
429 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
431 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-sizeof(void *));
433 /* End of gross hack */
443 int LWP_CurrentProcess(pid) /* returns pid of current process */
446 Debug(0, ("Entered Current_Process"))
454 #define LWPANCHOR (*lwp_init)
456 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
461 Debug(0, ("Entered Destroy_Process"))
463 if (lwp_cpptr != pid) {
464 Dispose_of_Dead_PCB(pid);
467 pid -> status = DESTROYED;
468 move(pid, &runnable[pid->priority], &blocked);
471 savecontext(Dispatcher, &(temp -> context),
472 &(LWPANCHOR.dsptchstack[MINFRAME]));
475 savecontext(Dispatcher, &(temp -> context),
476 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-8]));
478 savecontext(Dispatcher, &(temp -> context),
479 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-sizeof(void *)]));
488 int LWP_DispatchProcess() /* explicit voluntary preemption */
490 Debug(2, ("Entered Dispatch_Process"))
503 for (i=0; i<MAX_PRIORITIES; i++)
504 for_all_elts(x, runnable[i], {
505 printf("[Priority %d]\n", i);
508 for_all_elts(x, blocked, { Dump_One_Process(x); })
510 printf("***LWP: LWP support not initialized\n");
514 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
518 Debug(0, ("Entered Get_Process_Priority"))
520 *priority = pid -> priority;
526 int LWP_InitializeProcessSupport(priority, pid)
531 struct lwp_pcb dummy;
535 Debug(0, ("Entered LWP_InitializeProcessSupport"))
536 if (lwp_init != NULL) return LWP_SUCCESS;
538 /* Set up offset for stack checking -- do this as soon as possible */
539 stack_offset = (char *) &dummy.stack - (char *) &dummy;
541 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
542 for (i=0; i<MAX_PRIORITIES; i++) {
543 runnable[i].head = NULL;
544 runnable[i].count = 0;
548 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
549 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
550 if (lwp_init == NULL || temp == NULL)
551 Abort_LWP("Insufficient Storage to Initialize LWP Support");
552 LWPANCHOR.processcnt = 1;
553 LWPANCHOR.outerpid = temp;
554 LWPANCHOR.outersp = NULL;
555 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
556 insert(temp, &runnable[priority]);
557 savecontext(Dispatcher, &temp->context, NULL);
558 LWPANCHOR.outersp = temp -> context.topstack;
562 /* get minimum stack size from the environment. this allows the administrator
563 * to change the lwp stack dynamically without getting a new binary version.
565 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
566 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
568 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
569 AFS_LWP_MINSTACKSIZE : atoi(value));
574 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
578 Debug(2, ("Entered LWP_SignalProcess"))
581 rc = Internal_Signal(event);
582 if (yield) Set_LWP_RC();
588 int LWP_TerminateProcessSupport() /* terminate all LWP support */
592 Debug(0, ("Entered Terminate_Process_Support"))
593 if (lwp_init == NULL) return LWP_EINIT;
594 if (lwp_cpptr != LWPANCHOR.outerpid)
595 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
596 for (i=0; i<MAX_PRIORITIES; i++)
597 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
598 for_all_elts(cur, blocked, { Free_PCB(cur); })
604 int LWP_WaitProcess(event) /* wait on a single event */
609 Debug(2, ("Entered Wait_Process"))
610 if (event == NULL) return LWP_EBADEVENT;
613 return LWP_MwaitProcess(1, tempev);
616 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
620 register int ecount, i;
623 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
625 if (evlist == NULL) {
627 return LWP_EBADCOUNT;
630 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
634 return LWP_EBADCOUNT;
639 if (wcount>ecount || wcount<0) {
641 return LWP_EBADCOUNT;
643 if (ecount > lwp_cpptr->eventlistsize) {
645 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *));
646 lwp_cpptr->eventlistsize = ecount;
648 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
650 lwp_cpptr -> status = WAITING;
652 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
655 lwp_cpptr -> wakevent = 0;
656 lwp_cpptr -> waitcnt = wcount;
657 lwp_cpptr -> eventcnt = ecount;
667 int LWP_StackUsed(pid, maxa, used)
671 *maxa = pid -> stacksize;
672 *used = Stack_Used(pid->stack, *maxa);
679 * The following functions are strictly
680 * INTERNAL to the LWP support package.
683 static void Abort_LWP(msg)
686 struct lwp_context tempcontext;
688 Debug(0, ("Entered Abort_LWP"))
689 printf("***LWP: %s\n",msg);
690 printf("***LWP: Abort --- dumping PCBs ...\n");
694 if (LWPANCHOR.outersp == NULL)
697 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
700 static int Create_Process_Part2 () /* creates a context for the new process */
704 Debug(2, ("Entered Create_Process_Part2"))
705 temp = lwp_cpptr; /* Get current process id */
706 savecontext(Dispatcher, &temp->context, NULL);
707 (*temp->ep)(temp->parm);
708 LWP_DestroyProcess(temp);
711 static Delete_PCB(pid) /* remove a PCB from the process list */
712 register PROCESS pid;
714 Debug(4, ("Entered Delete_PCB"))
715 lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
717 : &runnable[pid->priority]));
718 LWPANCHOR.processcnt--;
722 static Dump_One_Process(pid)
727 printf("***LWP: Process Control Block at 0x%x\n", pid);
728 printf("***LWP: Name: %s\n", pid->name);
730 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
731 if (pid->blockflag) printf("BLOCKED and ");
732 switch (pid->status) {
733 case READY: printf("READY"); break;
734 case WAITING: printf("WAITING"); break;
735 case DESTROYED: printf("DESTROYED"); break;
736 default: printf("unknown");
739 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
740 pid->priority, pid->parm);
741 if (pid->stacksize != 0) {
742 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
743 pid->stacksize, pid->stack);
744 printf("***LWP: HWM stack usage: ");
745 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
748 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
749 if (pid->eventcnt > 0) {
750 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
751 printf("***LWP: Event id list:");
752 for (i=0;i<pid->eventcnt;i++)
753 printf(" 0x%x", pid->eventlist[i]);
757 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
761 static purge_dead_pcbs()
763 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
766 int LWP_TraceProcesses = 0;
768 static Dispatcher() /* Lightweight process dispatcher */
772 static int dispatch_count = 0;
774 if (LWP_TraceProcesses > 0) {
775 for (i=0; i<MAX_PRIORITIES; i++) {
776 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
777 for_all_elts(p, runnable[i], {
778 printf(" \"%s\"", p->name);
782 printf("[Blocked (%d):", blocked.count);
783 for_all_elts(p, blocked, {
784 printf(" \"%s\"", p->name);
790 /* Check for stack overflowif this lwp has a stack. Check for
791 the guard word at the front of the stack being damaged and
792 for the stack pointer being below the front of the stack.
793 WARNING! This code assumes that stacks grow downward. */
795 /* Fix this (stackcheck at other end of stack?) */
796 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
797 && (lwp_cpptr->stackcheck !=
798 *(afs_int32 *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
799 || lwp_cpptr->context.topstack >
800 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
802 if (lwp_cpptr && lwp_cpptr->stack &&
803 (lwp_cpptr->stackcheck != *(afs_int32 *)(lwp_cpptr->stack) ||
804 lwp_cpptr->context.topstack < lwp_cpptr->stack ||
805 lwp_cpptr->context.topstack > (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
807 printf("stackcheck = %u: stack = %u \n",
808 lwp_cpptr->stackcheck, *(afs_int32 *)lwp_cpptr->stack);
809 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
810 lwp_cpptr->context.topstack, lwp_cpptr->stack, lwp_cpptr->stacksize);
812 switch (lwp_overflowAction) {
821 lwp_overflowAction = LWP_SOQUIET;
826 /* Move head of current runnable queue forward if current LWP is still in it. */
827 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
828 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head -> next;
829 /* Find highest priority with runnable processes. */
830 for (i=MAX_PRIORITIES-1; i>=0; i--)
831 if (runnable[i].head != NULL) break;
833 if (i < 0) Abort_LWP("No READY processes");
836 if (LWP_TraceProcesses > 0)
837 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
839 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
840 lwp_cpptr = runnable[i].head;
842 returnto(&lwp_cpptr->context);
845 /* Complain of a stack overflow to stderr without using stdio. */
846 static void Overflow_Complain ()
850 char *msg1 = " LWP: stack overflow in process ";
853 currenttime = time(0);
854 timeStamp = ctime(¤ttime);
856 write (2, timeStamp, strlen(timeStamp));
858 write (2, msg1, strlen(msg1));
859 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
860 write (2, msg2, strlen(msg2));
863 static void Dispose_of_Dead_PCB (cur)
866 Debug(4, ("Entered Dispose_of_Dead_PCB"))
870 Internal_Signal(cur);
879 static void Free_PCB(pid)
882 Debug(4, ("Entered Free_PCB"))
883 if (pid -> stack != NULL) {
884 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
885 Stack_Used(pid->stack,pid->stacksize), pid))
888 if (pid->eventlist != NULL) free(pid->eventlist);
892 static void Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
895 int stacksize, priority;
901 Debug(4, ("Entered Initialize_PCB"))
903 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
904 temp -> name[31] = '\0';
905 temp -> status = READY;
906 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
907 temp -> eventlistsize = EVINITSIZE;
908 temp -> eventcnt = 0;
909 temp -> wakevent = 0;
911 temp -> blockflag = 0;
912 temp -> iomgrRequest = 0;
913 temp -> priority = priority;
914 temp -> index = lwp_nextindex++;
915 temp -> stack = stack;
916 temp -> stacksize = stacksize;
918 if (temp -> stack != NULL)
919 temp -> stackcheck = *(afs_int32 *) ((temp -> stack) + stacksize - 4);
921 if (temp -> stack != NULL)
922 temp -> stackcheck = *(afs_int32 *) (temp -> stack);
926 temp -> misc = NULL; /* currently unused */
929 temp -> lwp_rused = NULL;
930 temp -> level = 1; /* non-preemptable */
933 static int Internal_Signal(event)
934 register char *event;
936 int rc = LWP_ENOWAIT;
939 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
940 if (!lwp_init) return LWP_EINIT;
941 if (event == NULL) return LWP_EBADEVENT;
942 for_all_elts(temp, blocked, {
943 if (temp->status == WAITING)
944 for (i=0; i < temp->eventcnt; i++) {
945 if (temp -> eventlist[i] == event) {
946 temp -> eventlist[i] = NULL;
948 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
949 if (--temp->waitcnt == 0) {
950 temp -> status = READY;
951 temp -> wakevent = i+1;
952 move(temp, &blocked, &runnable[temp->priority]);
961 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
962 #define STACKMAGIC 0xBADBADBA
963 static afs_int32 Initialize_Stack(stackptr, stacksize)
969 Debug(4, ("Entered Initialize_Stack"))
970 if (lwp_stackUseEnabled)
971 for (i=0; i<stacksize; i++)
972 stackptr[i] = i &0xff;
975 *(afs_int32 *)(stackptr + stacksize - 4) = STACKMAGIC;
977 *(afs_int32 *)stackptr = STACKMAGIC;
981 static int Stack_Used(stackptr, stacksize)
982 register char *stackptr;
988 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
991 for (i = stacksize - 1; i >= 0 ; i--)
992 if ((unsigned char) stackptr[i] != (i & 0xff))
997 if (*(afs_int32 *) stackptr == STACKMAGIC)
1000 for (i = 0; i < stacksize; i++)
1001 if ((unsigned char) stackptr[i] != (i & 0xff))
1002 return (stacksize - i);
1009 LWP_NewRock(Tag, Value)
1011 char *Value; /* IN */
1012 /* Finds a free rock and sets its value to Value.
1014 LWP_SUCCESS Rock did not exist and a new one was used
1015 LWP_EBADROCK Rock already exists.
1016 LWP_ENOROCKS All rocks are in use.
1018 From the above semantics, you can only set a rock value once. This is specifically
1019 to prevent multiple users of the LWP package from accidentally using the same Tag
1020 value and clobbering others. You can always use one level of indirection to obtain
1021 a rock whose contents can change.
1025 register struct rock *ra; /* rock array */
1027 ra = lwp_cpptr->lwp_rlist;
1029 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1030 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1032 if (lwp_cpptr->lwp_rused < MAXROCKS)
1034 ra[lwp_cpptr->lwp_rused].tag = Tag;
1035 ra[lwp_cpptr->lwp_rused].value = Value;
1036 lwp_cpptr->lwp_rused++;
1037 return(LWP_SUCCESS);
1039 else return(LWP_ENOROCKS);
1043 LWP_GetRock(Tag, Value)
1045 char **Value; /* OUT */
1047 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1049 LWP_SUCCESS if specified rock exists and Value has been filled
1050 LWP_EBADROCK rock specified does not exist
1054 register struct rock *ra;
1056 ra = lwp_cpptr->lwp_rlist;
1058 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1059 if (ra[i].tag == Tag)
1061 *Value = ra[i].value;
1062 return(LWP_SUCCESS);
1064 return(LWP_EBADROCK);
1068 #ifdef AFS_AIX32_ENV
1069 setlim(limcon, hard, limit)
1075 (void) getrlimit(limcon, &rlim);
1077 limit = limit * 1024;
1079 rlim.rlim_max = limit;
1080 else if (limit == RLIM_INFINITY && geteuid() != 0)
1081 rlim.rlim_cur = rlim.rlim_max;
1083 rlim.rlim_cur = limit;
1085 /* Must use ulimit() due to Posix constraints */
1086 if (limcon == RLIMIT_FSIZE) {
1087 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1088 printf("Can't %s%s limit\n",
1089 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1093 if (setrlimit(limcon, &rlim) < 0) {
1095 printf("Can't %s%s limit\n",
1096 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1106 * Print the specific limit out
1108 plim(name, lc, hard)
1116 printf("%s \t", name);
1117 (void) getrlimit(lc, &rlim);
1118 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1119 if (lim == RLIM_INFINITY)
1120 printf("unlimited");
1121 printf("%d %s", lim / 1024, "kbytes");
1128 int LWP_NoYieldSignal(event)
1131 return (LWP_INTERNALSIGNAL(event, 0));
1134 int LWP_SignalProcess(event)
1137 return (LWP_INTERNALSIGNAL(event, 1));
1142 #ifdef USE_SOLARIS_THREADS
1145 #include "pthread.h"
1150 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1152 PROCESS lwp_process_list; /* List of LWP initiated threads */
1154 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1156 #define CHECK check(__LINE__);
1158 typedef struct event {
1159 struct event *next; /* next in hash chain */
1160 char *event; /* lwp event: an address */
1161 int refcount; /* Is it in use? */
1162 pthread_cond_t cond; /* Currently associated condition variable */
1163 int seq; /* Sequence number: this is incremented
1164 by wakeup calls; wait will not return until
1168 #define HASHSIZE 127
1169 event_t *hashtable[HASHSIZE];/* Hash table for events */
1170 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1172 #if CMA_DEBUG || DEBUGF
1173 char *lwp_process_string() {
1174 static char id[200];
1176 LWP_CurrentProcess(&p);
1177 sprintf(id, "PID %x <%s>", p, p->name);
1182 void lwp_unimplemented(interface)
1185 fprintf(stderr, "cmalwp: %s is not currently implemented: program aborted\n",
1190 static lwpabort(interface)
1193 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1199 lwp_unimplemented("LWP_QWait");
1202 int LWP_QSignal(pid)
1204 lwp_unimplemented("LWP_QSignal");
1207 /* Allocate and initialize an LWP process handle. The associated pthread handle
1208 * must be added by the caller, and the structure threaded onto the LWP active
1209 * process list by lwp_thread_process */
1210 static PROCESS lwp_alloc_process(name, ep, arg)
1212 pthread_startroutine_t ep;
1216 assert(lp = (PROCESS) malloc(sizeof (*lp)));
1217 bzero((char *) lp, sizeof(*lp));
1221 sprintf(temp, "unnamed_process_%04d", ++procnum);
1222 assert(name = (char *)malloc(strlen(temp) + 1));
1231 /* Thread the LWP process descriptor *lp onto the lwp active process list
1232 * and associate a back pointer to the process descriptor from the associated
1234 static lwp_thread_process(lp)
1237 lp->next = lwp_process_list;
1238 lwp_process_list = lp;
1239 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1242 /* The top-level routine used as entry point to explicitly created LWP
1243 * processes. This completes a few details of process creation left
1244 * out by LWP_CreateProcess and calls the user-specified entry point */
1245 static int lwp_top_level(argp)
1246 pthread_addr_t argp;
1248 PROCESS lp = (PROCESS) argp;
1250 assert(!pthread_mutex_lock(&lwp_mutex));
1251 lwp_thread_process(lp);
1253 assert(!pthread_mutex_unlock(&lwp_mutex));
1254 /* Should cleanup state */
1257 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
1259 int stacksize, priority;
1265 pthread_attr_t attr;
1269 #ifndef LWP_NO_PRIORITIES
1270 if (!cmalwp_pri_inrange(priority))
1273 assert(!pthread_attr_create(&attr));
1274 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1276 assert(!pthread_attr_setstacksize(&attr, stacksize));
1278 (void) pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1279 (void) pthread_attr_setsched(&attr, SCHED_FIFO);
1280 #ifndef LWP_NO_PRIORITIES
1281 (void) pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1284 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep, (pthread_addr_t) parm);
1286 /* allow new thread to run if higher priority */
1287 assert(!pthread_mutex_unlock(&lwp_mutex));
1288 /* process is only added to active list after first time it runs (it adds itself) */
1289 status = pthread_create(&lp->handle,
1291 (pthread_startroutine_t) lwp_top_level,
1292 (pthread_addr_t) lp);
1293 assert(!pthread_attr_delete(&attr));
1294 assert (!pthread_mutex_lock(&lwp_mutex));
1303 PROCESS LWP_ActiveProcess() { /* returns pid of current process */
1305 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) &pid));
1309 int LWP_CurrentProcess(pid) /* get pid of current process */
1312 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1316 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
1319 lwp_unimplemented("LWP_DestroyProcess");
1322 int LWP_DispatchProcess() /* explicit voluntary preemption */
1324 assert(!pthread_mutex_unlock(&lwp_mutex));
1326 assert(!pthread_mutex_lock(&lwp_mutex));
1330 static int lwp_process_key_destructor() {}
1332 int LWP_InitializeProcessSupport(priority, pid)
1336 static int initialized = 0;
1347 #ifndef LWP_NO_PRIORITIES
1348 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1352 /* Create pthread key to associate LWP process descriptor with each
1353 LWP-created thread */
1354 assert(!pthread_keycreate(&lwp_process_key,
1355 (pthread_destructor_t) lwp_process_key_destructor));
1357 lp = lwp_alloc_process("main process", main, 0);
1358 lp->handle = pthread_self();
1359 lwp_thread_process(lp);
1360 #ifndef LWP_NO_PRIORITIES
1361 (void) pthread_setscheduler(pthread_self(),
1363 cmalwp_lwppri_to_cmapri(priority));
1366 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1367 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1373 int LWP_TerminateProcessSupport() /* terminate all LWP support */
1375 lwp_unimplemented("LWP_TerminateProcessSupport");
1378 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1379 static event_t *getevent(event)
1382 event_t *evp, *newp;
1385 hashcode = hash(event);
1386 evp = hashtable[hashcode];
1389 if (evp->event == event) {
1393 if (evp->refcount == 0)
1398 newp = (event_t *) malloc(sizeof (event_t));
1400 newp->next = hashtable[hashcode];
1401 hashtable[hashcode] = newp;
1402 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t)0)));
1405 newp->event = event;
1410 /* Release the specified event */
1411 #define relevent(evp) ((evp)->refcount--)
1413 int LWP_WaitProcess(event) /* wait on a single event */
1418 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1419 if (event == NULL) return LWP_EBADEVENT;
1420 ev = getevent(event);
1422 while (seq == ev->seq) {
1423 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1425 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1430 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
1434 lwp_unimplemented("LWP_MWaitProcess");
1437 int LWP_NoYieldSignal(event)
1441 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1442 if (event == NULL) return LWP_EBADEVENT;
1443 ev = getevent(event);
1444 if (ev->refcount > 1) {
1446 assert(pthread_cond_broadcast(&ev->cond) == 0);
1452 int LWP_SignalProcess(event)
1456 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1457 if (event == NULL) return LWP_EBADEVENT;
1458 ev = getevent(event);
1459 if (ev->refcount > 1) {
1461 assert(!pthread_mutex_unlock(&lwp_mutex));
1462 assert(!pthread_cond_broadcast(&ev->cond));
1464 assert(!pthread_mutex_lock(&lwp_mutex));
1470 int LWP_StackUsed(pid, maxa, used)
1474 lwp_unimplemented("LWP_StackUsed");
1477 LWP_NewRock(Tag, Value)
1479 char *Value; /* IN */
1481 lwp_unimplemented("LWP_NewRock");
1484 LWP_GetRock(Tag, Value)
1486 char **Value; /* OUT */
1488 lwp_unimplemented("LWP_GetRock");
1491 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
1495 lwp_unimplemented("LWP_GetProcessPriority");
1498 #endif /* USE_PTHREADS */