2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /*******************************************************************\
12 * Information Technology Center *
13 * Carnegie-Mellon University *
15 \*******************************************************************/
21 /* allocate externs here */
26 #include <sys/errno.h>
33 extern char* getenv();
36 #if !defined(USE_PTHREADS) && !defined(USE_SOLARIS_THREADS)
39 extern void *malloc(int size);
40 extern void *realloc(void *ptr, int size);
41 extern int PRE_Block; /* from preempt.c */
43 extern char PRE_Block; /* from preempt.c */
54 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
63 #define Debug(level, msg)\
64 if (lwp_debug && lwp_debug >= level) {\
65 printf("***LWP (0x%x): ", lwp_cpptr);\
71 #define Debug(level, msg)
75 static int Dispatcher();
76 static int Create_Process_Part2();
77 static int Exit_LWP();
78 static afs_int32 Initialize_Stack();
79 static int Stack_Used();
80 char (*RC_to_ASCII());
82 static void Abort_LWP();
83 static void Overflow_Complain();
84 static void Initialize_PCB();
85 static void Dispose_of_Dead_PCB();
86 static void Free_PCB();
87 static int Internal_Signal();
88 static purge_dead_pcbs();
90 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
95 } runnable[MAX_PRIORITIES], blocked;
96 /* 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. */
98 /* Offset of stack field within pcb -- used by stack checking stuff */
101 /* special user-tweakable option for AIX */
102 int lwp_MaxStackSize = 32768;
104 /* biggest LWP stack created so far */
105 int lwp_MaxStackSeen = 0;
107 /* Stack checking action */
108 int lwp_overflowAction = LWP_SOABORT;
110 /* Controls stack size counting. */
111 int lwp_stackUseEnabled = TRUE; /* pay the price */
115 /* Minimum stack size */
116 int lwp_MinStackSize=0;
118 static lwp_remove(p, q)
120 register struct QUEUE *q;
122 /* Special test for only element on queue */
126 /* Not only element, do normal remove */
127 p -> next -> prev = p -> prev;
128 p -> prev -> next = p -> next;
130 /* See if head pointing to this element */
131 if (q->head == p) q -> head = p -> next;
133 p -> next = p -> prev = NULL;
138 register struct QUEUE *q;
140 if (q->head == NULL) { /* Queue is empty */
142 p -> next = p -> prev = p;
143 } else { /* Regular insert */
144 p -> prev = q -> head -> prev;
145 q -> head -> prev -> next = p;
146 q -> head -> prev = p;
147 p -> next = q -> head;
152 static move(p, from, to)
154 struct QUEUE *from, *to;
164 #define for_all_elts(var, q, body)\
166 register PROCESS var, _NEXT_;\
168 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
169 _NEXT_ = var -> next;\
175 /*****************************************************************************\
177 * Following section documents the Assembler interfaces used by LWP code *
179 \*****************************************************************************/
182 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
184 Stub for Assembler routine that will
185 save the current SP value in the passed
186 context savearea and call the function
187 whose entry point is in ep. If the sp
188 parameter is NULL, the current stack is
189 used, otherwise sp becomes the new stack
192 returnto(struct lwp_context *savearea);
194 Stub for Assembler routine that will
195 restore context from a passed savearea
196 and return to the restored C frame.
200 /* Macro to force a re-schedule. Strange name is historical */
201 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
203 static struct lwp_ctl *lwp_init = 0;
206 {register PROCESS tp;
207 (tp=lwp_cpptr) -> status = QWAITING;
208 lwp_remove(tp, &runnable[tp->priority]);
214 register PROCESS pid; {
215 if (pid->status == QWAITING) {
217 insert(pid, &runnable[pid->priority]);
220 else return LWP_ENOWAIT;
224 char *reserveFromStack(size)
225 register afs_int32 size;
233 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
235 int stacksize, priority;
242 static char *stackptr = 0;
247 #if defined(AFS_LWP_MINSTACKSIZE)
249 * on some systems (e.g. hpux), a minimum usable stack size has
252 if (stacksize < lwp_MinStackSize) {
253 stacksize = lwp_MinStackSize;
255 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
256 /* more stack size computations; keep track of for IOMGR */
257 if (lwp_MaxStackSeen < stacksize)
258 lwp_MaxStackSeen = stacksize;
260 Debug(0, ("Entered LWP_CreateProcess"))
261 /* Throw away all dead process control blocks */
264 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
269 if (stacksize < MINSTACK)
273 stacksize = 8 * ((stacksize+7) / 8);
275 stacksize = 4 * ((stacksize+3) / 4);
280 * The following signal action for AIX is necessary so that in case of a
281 * crash (i.e. core is generated) we can include the user's data section
282 * in the core dump. Unfortunately, by default, only a partial core is
283 * generated which, in many cases, isn't too useful.
285 * We also do it here in case the main program forgets to do it.
287 struct sigaction nsa;
288 extern uid_t geteuid();
290 sigemptyset(&nsa.sa_mask);
291 nsa.sa_handler = SIG_DFL;
292 nsa.sa_flags = SA_FULLDUMP;
293 sigaction(SIGABRT, &nsa, NULL);
294 sigaction(SIGSEGV, &nsa, NULL);
297 * First we need to increase the default resource limits,
298 * if necessary, so that we can guarantee that we have the
299 * resources to create the core file, but we can't always
300 * do it as an ordinary user.
303 /* vos dump causes problems */
304 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
305 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
306 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
309 * Now reserve in one scoop all the stack space that will be used
310 * by the particular application's main (i.e. non-lwp) body. This
311 * is plenty space for any of our applications.
313 stackptr = reserveFromStack(lwp_MaxStackSize);
315 stackptr -= stacksize;
317 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
321 /* Round stack pointer to byte boundary */
322 stackptr = (char *)(8 * (((long)stackptr+7) / 8));
324 if (priority < 0 || priority >= MAX_PRIORITIES) {
328 Initialize_Stack(stackptr, stacksize);
329 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
330 insert(temp, &runnable[priority]);
332 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
334 /* Gross hack: beware! */
338 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
341 /* Need to have the sp on an 8-byte boundary for storing doubles. */
342 savecontext(Create_Process_Part2, &temp2->context,
343 stackptr+stacksize-16); /* 16 = 2 * jmp_buf_type*/
345 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
346 savecontext(Create_Process_Part2, &temp2->context,
347 stackptr+stacksize-0x40); /* lomgjmp does something
350 savecontext(Create_Process_Part2, &temp2->context,
351 stackptr+stacksize-sizeof(void *));
355 /* End of gross hack */
365 int LWP_CreateProcess2(ep, stacksize, priority, parm, name, pid)
367 int stacksize, priority;
375 #if defined(AFS_LWP_MINSTACKSIZE)
377 * on some systems (e.g. hpux), a minimum usable stack size has
380 if (stacksize < lwp_MinStackSize) {
381 stacksize = lwp_MinStackSize;
383 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
384 /* more stack size computations; keep track of for IOMGR */
385 if (lwp_MaxStackSeen < stacksize)
386 lwp_MaxStackSeen = stacksize;
388 Debug(0, ("Entered LWP_CreateProcess"))
389 /* Throw away all dead process control blocks */
392 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
397 if (stacksize < MINSTACK)
401 stacksize = 8 * ((stacksize+7) / 8);
403 stacksize = 4 * ((stacksize+3) / 4);
405 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
409 if (priority < 0 || priority >= MAX_PRIORITIES) {
413 Initialize_Stack(stackptr, stacksize);
414 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
415 insert(temp, &runnable[priority]);
417 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
419 /* Gross hack: beware! */
423 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
425 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-sizeof(void *));
427 /* End of gross hack */
437 int LWP_CurrentProcess(pid) /* returns pid of current process */
440 Debug(0, ("Entered Current_Process"))
448 PROCESS LWP_ThreadId()
450 Debug(0, ("Entered ThreadId"))
457 #define LWPANCHOR (*lwp_init)
459 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
464 Debug(0, ("Entered Destroy_Process"))
466 if (lwp_cpptr != pid) {
467 Dispose_of_Dead_PCB(pid);
470 pid -> status = DESTROYED;
471 move(pid, &runnable[pid->priority], &blocked);
474 savecontext(Dispatcher, &(temp -> context),
475 &(LWPANCHOR.dsptchstack[MINFRAME]));
478 savecontext(Dispatcher, &(temp -> context),
479 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-8]));
481 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
482 savecontext(Dispatcher, &(temp -> context),
483 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-0x40]));
485 savecontext(Dispatcher, &(temp -> context),
486 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-sizeof(void *)]));
496 int LWP_DispatchProcess() /* explicit voluntary preemption */
498 Debug(2, ("Entered Dispatch_Process"))
511 for (i=0; i<MAX_PRIORITIES; i++)
512 for_all_elts(x, runnable[i], {
513 printf("[Priority %d]\n", i);
516 for_all_elts(x, blocked, { Dump_One_Process(x); })
518 printf("***LWP: LWP support not initialized\n");
522 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
526 Debug(0, ("Entered Get_Process_Priority"))
528 *priority = pid -> priority;
534 int LWP_InitializeProcessSupport(priority, pid)
539 struct lwp_pcb dummy;
543 Debug(0, ("Entered LWP_InitializeProcessSupport"))
544 if (lwp_init != NULL) return LWP_SUCCESS;
546 /* Set up offset for stack checking -- do this as soon as possible */
547 stack_offset = (char *) &dummy.stack - (char *) &dummy;
549 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
550 for (i=0; i<MAX_PRIORITIES; i++) {
551 runnable[i].head = NULL;
552 runnable[i].count = 0;
556 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
557 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
558 if (lwp_init == NULL || temp == NULL)
559 Abort_LWP("Insufficient Storage to Initialize LWP Support");
560 LWPANCHOR.processcnt = 1;
561 LWPANCHOR.outerpid = temp;
562 LWPANCHOR.outersp = NULL;
563 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
564 insert(temp, &runnable[priority]);
565 savecontext(Dispatcher, &temp->context, NULL);
566 LWPANCHOR.outersp = temp -> context.topstack;
570 /* get minimum stack size from the environment. this allows the administrator
571 * to change the lwp stack dynamically without getting a new binary version.
573 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
574 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
576 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
577 AFS_LWP_MINSTACKSIZE : atoi(value));
582 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
586 Debug(2, ("Entered LWP_SignalProcess"))
589 rc = Internal_Signal(event);
590 if (yield) Set_LWP_RC();
596 int LWP_TerminateProcessSupport() /* terminate all LWP support */
600 Debug(0, ("Entered Terminate_Process_Support"))
601 if (lwp_init == NULL) return LWP_EINIT;
602 if (lwp_cpptr != LWPANCHOR.outerpid)
603 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
604 for (i=0; i<MAX_PRIORITIES; i++)
605 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
606 for_all_elts(cur, blocked, { Free_PCB(cur); })
612 int LWP_WaitProcess(event) /* wait on a single event */
617 Debug(2, ("Entered Wait_Process"))
618 if (event == NULL) return LWP_EBADEVENT;
621 return LWP_MwaitProcess(1, tempev);
624 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
628 register int ecount, i;
631 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
633 if (evlist == NULL) {
635 return LWP_EBADCOUNT;
638 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
642 return LWP_EBADCOUNT;
647 if (wcount>ecount || wcount<0) {
649 return LWP_EBADCOUNT;
651 if (ecount > lwp_cpptr->eventlistsize) {
653 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *));
654 lwp_cpptr->eventlistsize = ecount;
656 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
658 lwp_cpptr -> status = WAITING;
660 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
663 lwp_cpptr -> wakevent = 0;
664 lwp_cpptr -> waitcnt = wcount;
665 lwp_cpptr -> eventcnt = ecount;
675 int LWP_StackUsed(pid, maxa, used)
679 *maxa = pid -> stacksize;
680 *used = Stack_Used(pid->stack, *maxa);
687 * The following functions are strictly
688 * INTERNAL to the LWP support package.
691 static void Abort_LWP(msg)
694 struct lwp_context tempcontext;
696 Debug(0, ("Entered Abort_LWP"))
697 printf("***LWP: %s\n",msg);
698 printf("***LWP: Abort --- dumping PCBs ...\n");
702 if (LWPANCHOR.outersp == NULL)
705 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
708 static int Create_Process_Part2 () /* creates a context for the new process */
712 Debug(2, ("Entered Create_Process_Part2"))
713 temp = lwp_cpptr; /* Get current process id */
714 savecontext(Dispatcher, &temp->context, NULL);
715 (*temp->ep)(temp->parm);
716 LWP_DestroyProcess(temp);
719 static Delete_PCB(pid) /* remove a PCB from the process list */
720 register PROCESS pid;
722 Debug(4, ("Entered Delete_PCB"))
723 lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
725 : &runnable[pid->priority]));
726 LWPANCHOR.processcnt--;
730 static Dump_One_Process(pid)
735 printf("***LWP: Process Control Block at 0x%x\n", pid);
736 printf("***LWP: Name: %s\n", pid->name);
738 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
739 if (pid->blockflag) printf("BLOCKED and ");
740 switch (pid->status) {
741 case READY: printf("READY"); break;
742 case WAITING: printf("WAITING"); break;
743 case DESTROYED: printf("DESTROYED"); break;
744 default: printf("unknown");
747 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
748 pid->priority, pid->parm);
749 if (pid->stacksize != 0) {
750 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
751 pid->stacksize, pid->stack);
752 printf("***LWP: HWM stack usage: ");
753 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
756 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
757 if (pid->eventcnt > 0) {
758 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
759 printf("***LWP: Event id list:");
760 for (i=0;i<pid->eventcnt;i++)
761 printf(" 0x%x", pid->eventlist[i]);
765 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
769 static purge_dead_pcbs()
771 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
774 int LWP_TraceProcesses = 0;
776 static Dispatcher() /* Lightweight process dispatcher */
780 static int dispatch_count = 0;
782 if (LWP_TraceProcesses > 0) {
783 for (i=0; i<MAX_PRIORITIES; i++) {
784 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
785 for_all_elts(p, runnable[i], {
786 printf(" \"%s\"", p->name);
790 printf("[Blocked (%d):", blocked.count);
791 for_all_elts(p, blocked, {
792 printf(" \"%s\"", p->name);
798 /* Check for stack overflowif this lwp has a stack. Check for
799 the guard word at the front of the stack being damaged and
800 for the stack pointer being below the front of the stack.
801 WARNING! This code assumes that stacks grow downward. */
803 /* Fix this (stackcheck at other end of stack?) */
804 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
805 && (lwp_cpptr->stackcheck !=
806 *(afs_int32 *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
807 || lwp_cpptr->context.topstack >
808 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
810 if (lwp_cpptr && lwp_cpptr->stack &&
811 (lwp_cpptr->stackcheck != *(afs_int32 *)(lwp_cpptr->stack) ||
812 lwp_cpptr->context.topstack < lwp_cpptr->stack ||
813 lwp_cpptr->context.topstack > (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
815 printf("stackcheck = %u: stack = %u \n",
816 lwp_cpptr->stackcheck, *(afs_int32 *)lwp_cpptr->stack);
817 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
818 lwp_cpptr->context.topstack, lwp_cpptr->stack, lwp_cpptr->stacksize);
820 switch (lwp_overflowAction) {
829 lwp_overflowAction = LWP_SOQUIET;
834 /* Move head of current runnable queue forward if current LWP is still in it. */
835 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
836 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head -> next;
837 /* Find highest priority with runnable processes. */
838 for (i=MAX_PRIORITIES-1; i>=0; i--)
839 if (runnable[i].head != NULL) break;
841 if (i < 0) Abort_LWP("No READY processes");
844 if (LWP_TraceProcesses > 0)
845 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
847 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
848 lwp_cpptr = runnable[i].head;
850 returnto(&lwp_cpptr->context);
853 /* Complain of a stack overflow to stderr without using stdio. */
854 static void Overflow_Complain ()
858 char *msg1 = " LWP: stack overflow in process ";
861 currenttime = time(0);
862 timeStamp = ctime(¤ttime);
864 write (2, timeStamp, strlen(timeStamp));
866 write (2, msg1, strlen(msg1));
867 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
868 write (2, msg2, strlen(msg2));
871 static void Dispose_of_Dead_PCB (cur)
874 Debug(4, ("Entered Dispose_of_Dead_PCB"))
878 Internal_Signal(cur);
887 static void Free_PCB(pid)
890 Debug(4, ("Entered Free_PCB"))
891 if (pid -> stack != NULL) {
892 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
893 Stack_Used(pid->stack,pid->stacksize), pid))
896 if (pid->eventlist != NULL) free(pid->eventlist);
900 static void Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
903 int stacksize, priority;
909 Debug(4, ("Entered Initialize_PCB"))
911 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
912 temp -> name[31] = '\0';
913 temp -> status = READY;
914 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
915 temp -> eventlistsize = EVINITSIZE;
916 temp -> eventcnt = 0;
917 temp -> wakevent = 0;
919 temp -> blockflag = 0;
920 temp -> iomgrRequest = 0;
921 temp -> priority = priority;
922 temp -> index = lwp_nextindex++;
923 temp -> stack = stack;
924 temp -> stacksize = stacksize;
926 if (temp -> stack != NULL)
927 temp -> stackcheck = *(afs_int32 *) ((temp -> stack) + stacksize - 4);
929 if (temp -> stack != NULL)
930 temp -> stackcheck = *(afs_int32 *) (temp -> stack);
934 temp -> misc = NULL; /* currently unused */
937 temp -> lwp_rused = 0;
938 temp -> level = 1; /* non-preemptable */
941 static int Internal_Signal(event)
942 register char *event;
944 int rc = LWP_ENOWAIT;
947 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
948 if (!lwp_init) return LWP_EINIT;
949 if (event == NULL) return LWP_EBADEVENT;
950 for_all_elts(temp, blocked, {
951 if (temp->status == WAITING)
952 for (i=0; i < temp->eventcnt; i++) {
953 if (temp -> eventlist[i] == event) {
954 temp -> eventlist[i] = NULL;
956 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
957 if (--temp->waitcnt == 0) {
958 temp -> status = READY;
959 temp -> wakevent = i+1;
960 move(temp, &blocked, &runnable[temp->priority]);
969 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
970 #define STACKMAGIC 0xBADBADBA
971 static afs_int32 Initialize_Stack(stackptr, stacksize)
977 Debug(4, ("Entered Initialize_Stack"))
978 if (lwp_stackUseEnabled)
979 for (i=0; i<stacksize; i++)
980 stackptr[i] = i &0xff;
983 *(afs_int32 *)(stackptr + stacksize - 4) = STACKMAGIC;
985 *(afs_int32 *)stackptr = STACKMAGIC;
989 static int Stack_Used(stackptr, stacksize)
990 register char *stackptr;
996 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
999 for (i = stacksize - 1; i >= 0 ; i--)
1000 if ((unsigned char) stackptr[i] != (i & 0xff))
1005 if (*(afs_int32 *) stackptr == STACKMAGIC)
1008 for (i = 0; i < stacksize; i++)
1009 if ((unsigned char) stackptr[i] != (i & 0xff))
1010 return (stacksize - i);
1017 LWP_NewRock(Tag, Value)
1019 char *Value; /* IN */
1020 /* Finds a free rock and sets its value to Value.
1022 LWP_SUCCESS Rock did not exist and a new one was used
1023 LWP_EBADROCK Rock already exists.
1024 LWP_ENOROCKS All rocks are in use.
1026 From the above semantics, you can only set a rock value once. This is specifically
1027 to prevent multiple users of the LWP package from accidentally using the same Tag
1028 value and clobbering others. You can always use one level of indirection to obtain
1029 a rock whose contents can change.
1033 register struct rock *ra; /* rock array */
1035 ra = lwp_cpptr->lwp_rlist;
1037 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1038 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1040 if (lwp_cpptr->lwp_rused < MAXROCKS)
1042 ra[lwp_cpptr->lwp_rused].tag = Tag;
1043 ra[lwp_cpptr->lwp_rused].value = Value;
1044 lwp_cpptr->lwp_rused++;
1045 return(LWP_SUCCESS);
1047 else return(LWP_ENOROCKS);
1051 LWP_GetRock(Tag, Value)
1053 char **Value; /* OUT */
1055 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1057 LWP_SUCCESS if specified rock exists and Value has been filled
1058 LWP_EBADROCK rock specified does not exist
1062 register struct rock *ra;
1064 ra = lwp_cpptr->lwp_rlist;
1066 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1067 if (ra[i].tag == Tag)
1069 *Value = ra[i].value;
1070 return(LWP_SUCCESS);
1072 return(LWP_EBADROCK);
1076 #ifdef AFS_AIX32_ENV
1077 setlim(limcon, hard, limit)
1083 (void) getrlimit(limcon, &rlim);
1085 limit = limit * 1024;
1087 rlim.rlim_max = limit;
1088 else if (limit == RLIM_INFINITY && geteuid() != 0)
1089 rlim.rlim_cur = rlim.rlim_max;
1091 rlim.rlim_cur = limit;
1093 /* Must use ulimit() due to Posix constraints */
1094 if (limcon == RLIMIT_FSIZE) {
1095 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1096 printf("Can't %s%s limit\n",
1097 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1101 if (setrlimit(limcon, &rlim) < 0) {
1103 printf("Can't %s%s limit\n",
1104 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1114 * Print the specific limit out
1116 plim(name, lc, hard)
1124 printf("%s \t", name);
1125 (void) getrlimit(lc, &rlim);
1126 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1127 if (lim == RLIM_INFINITY)
1128 printf("unlimited");
1129 printf("%d %s", lim / 1024, "kbytes");
1136 int LWP_NoYieldSignal(event)
1139 return (LWP_INTERNALSIGNAL(event, 0));
1142 int LWP_SignalProcess(event)
1145 return (LWP_INTERNALSIGNAL(event, 1));
1150 #ifdef USE_SOLARIS_THREADS
1153 #include "pthread.h"
1158 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1160 PROCESS lwp_process_list; /* List of LWP initiated threads */
1162 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1164 #define CHECK check(__LINE__);
1166 typedef struct event {
1167 struct event *next; /* next in hash chain */
1168 char *event; /* lwp event: an address */
1169 int refcount; /* Is it in use? */
1170 pthread_cond_t cond; /* Currently associated condition variable */
1171 int seq; /* Sequence number: this is incremented
1172 by wakeup calls; wait will not return until
1176 #define HASHSIZE 127
1177 event_t *hashtable[HASHSIZE];/* Hash table for events */
1178 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1180 #if CMA_DEBUG || DEBUGF
1181 char *lwp_process_string() {
1182 static char id[200];
1184 LWP_CurrentProcess(&p);
1185 sprintf(id, "PID %x <%s>", p, p->name);
1190 void lwp_unimplemented(interface)
1193 fprintf(stderr, "cmalwp: %s is not currently implemented: program aborted\n",
1198 static lwpabort(interface)
1201 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1207 lwp_unimplemented("LWP_QWait");
1210 int LWP_QSignal(pid)
1212 lwp_unimplemented("LWP_QSignal");
1215 /* Allocate and initialize an LWP process handle. The associated pthread handle
1216 * must be added by the caller, and the structure threaded onto the LWP active
1217 * process list by lwp_thread_process */
1218 static PROCESS lwp_alloc_process(name, ep, arg)
1220 pthread_startroutine_t ep;
1224 assert(lp = (PROCESS) malloc(sizeof (*lp)));
1225 bzero((char *) lp, sizeof(*lp));
1229 sprintf(temp, "unnamed_process_%04d", ++procnum);
1230 assert(name = (char *)malloc(strlen(temp) + 1));
1239 /* Thread the LWP process descriptor *lp onto the lwp active process list
1240 * and associate a back pointer to the process descriptor from the associated
1242 static lwp_thread_process(lp)
1245 lp->next = lwp_process_list;
1246 lwp_process_list = lp;
1247 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1250 /* The top-level routine used as entry point to explicitly created LWP
1251 * processes. This completes a few details of process creation left
1252 * out by LWP_CreateProcess and calls the user-specified entry point */
1253 static int lwp_top_level(argp)
1254 pthread_addr_t argp;
1256 PROCESS lp = (PROCESS) argp;
1258 assert(!pthread_mutex_lock(&lwp_mutex));
1259 lwp_thread_process(lp);
1261 assert(!pthread_mutex_unlock(&lwp_mutex));
1262 /* Should cleanup state */
1265 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
1267 int stacksize, priority;
1273 pthread_attr_t attr;
1277 #ifndef LWP_NO_PRIORITIES
1278 if (!cmalwp_pri_inrange(priority))
1281 assert(!pthread_attr_create(&attr));
1282 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1284 assert(!pthread_attr_setstacksize(&attr, stacksize));
1286 (void) pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1287 (void) pthread_attr_setsched(&attr, SCHED_FIFO);
1288 #ifndef LWP_NO_PRIORITIES
1289 (void) pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1292 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep, (pthread_addr_t) parm);
1294 /* allow new thread to run if higher priority */
1295 assert(!pthread_mutex_unlock(&lwp_mutex));
1296 /* process is only added to active list after first time it runs (it adds itself) */
1297 status = pthread_create(&lp->handle,
1299 (pthread_startroutine_t) lwp_top_level,
1300 (pthread_addr_t) lp);
1301 assert(!pthread_attr_delete(&attr));
1302 assert (!pthread_mutex_lock(&lwp_mutex));
1311 PROCESS LWP_ActiveProcess() { /* returns pid of current process */
1313 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) &pid));
1317 int LWP_CurrentProcess(pid) /* get pid of current process */
1320 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1324 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
1327 lwp_unimplemented("LWP_DestroyProcess");
1330 int LWP_DispatchProcess() /* explicit voluntary preemption */
1332 assert(!pthread_mutex_unlock(&lwp_mutex));
1334 assert(!pthread_mutex_lock(&lwp_mutex));
1338 static int lwp_process_key_destructor() {}
1340 int LWP_InitializeProcessSupport(priority, pid)
1344 static int initialized = 0;
1355 #ifndef LWP_NO_PRIORITIES
1356 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1360 /* Create pthread key to associate LWP process descriptor with each
1361 LWP-created thread */
1362 assert(!pthread_keycreate(&lwp_process_key,
1363 (pthread_destructor_t) lwp_process_key_destructor));
1365 lp = lwp_alloc_process("main process", main, 0);
1366 lp->handle = pthread_self();
1367 lwp_thread_process(lp);
1368 #ifndef LWP_NO_PRIORITIES
1369 (void) pthread_setscheduler(pthread_self(),
1371 cmalwp_lwppri_to_cmapri(priority));
1374 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1375 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1381 int LWP_TerminateProcessSupport() /* terminate all LWP support */
1383 lwp_unimplemented("LWP_TerminateProcessSupport");
1386 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1387 static event_t *getevent(event)
1390 event_t *evp, *newp;
1393 hashcode = hash(event);
1394 evp = hashtable[hashcode];
1397 if (evp->event == event) {
1401 if (evp->refcount == 0)
1406 newp = (event_t *) malloc(sizeof (event_t));
1408 newp->next = hashtable[hashcode];
1409 hashtable[hashcode] = newp;
1410 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t)0)));
1413 newp->event = event;
1418 /* Release the specified event */
1419 #define relevent(evp) ((evp)->refcount--)
1421 int LWP_WaitProcess(event) /* wait on a single event */
1426 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1427 if (event == NULL) return LWP_EBADEVENT;
1428 ev = getevent(event);
1430 while (seq == ev->seq) {
1431 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1433 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1438 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
1442 lwp_unimplemented("LWP_MWaitProcess");
1445 int LWP_NoYieldSignal(event)
1449 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1450 if (event == NULL) return LWP_EBADEVENT;
1451 ev = getevent(event);
1452 if (ev->refcount > 1) {
1454 assert(pthread_cond_broadcast(&ev->cond) == 0);
1460 int LWP_SignalProcess(event)
1464 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1465 if (event == NULL) return LWP_EBADEVENT;
1466 ev = getevent(event);
1467 if (ev->refcount > 1) {
1469 assert(!pthread_mutex_unlock(&lwp_mutex));
1470 assert(!pthread_cond_broadcast(&ev->cond));
1472 assert(!pthread_mutex_lock(&lwp_mutex));
1478 int LWP_StackUsed(pid, maxa, used)
1482 lwp_unimplemented("LWP_StackUsed");
1485 LWP_NewRock(Tag, Value)
1487 char *Value; /* IN */
1489 lwp_unimplemented("LWP_NewRock");
1492 LWP_GetRock(Tag, Value)
1494 char **Value; /* OUT */
1496 lwp_unimplemented("LWP_GetRock");
1499 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
1503 lwp_unimplemented("LWP_GetProcessPriority");
1506 #endif /* USE_PTHREADS */