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);
42 #if defined(AFS_OSF_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV)
43 extern int PRE_Block; /* from preempt.c */
45 extern char PRE_Block; /* from preempt.c */
56 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
73 #define Debug(level, msg)\
74 if (lwp_debug && lwp_debug >= level) {\
75 printf("***LWP (0x%x): ", lwp_cpptr);\
81 #define Debug(level, msg)
85 static int Dispatcher();
86 static int Create_Process_Part2();
87 static int Exit_LWP();
88 static afs_int32 Initialize_Stack();
89 static int Stack_Used();
90 char (*RC_to_ASCII());
92 static void Abort_LWP();
93 static void Overflow_Complain();
94 static void Initialize_PCB();
95 static void Dispose_of_Dead_PCB();
96 static void Free_PCB();
97 static int Internal_Signal();
98 static purge_dead_pcbs();
100 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
105 } runnable[MAX_PRIORITIES], blocked;
106 /* 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. */
108 /* Offset of stack field within pcb -- used by stack checking stuff */
111 /* special user-tweakable option for AIX */
112 int lwp_MaxStackSize = 32768;
114 /* biggest LWP stack created so far */
115 int lwp_MaxStackSeen = 0;
117 /* Stack checking action */
118 int lwp_overflowAction = LWP_SOABORT;
120 /* Controls stack size counting. */
121 int lwp_stackUseEnabled = TRUE; /* pay the price */
125 /* Minimum stack size */
126 int lwp_MinStackSize=0;
128 static lwp_remove(p, q)
130 register struct QUEUE *q;
132 /* Special test for only element on queue */
136 /* Not only element, do normal remove */
137 p -> next -> prev = p -> prev;
138 p -> prev -> next = p -> next;
140 /* See if head pointing to this element */
141 if (q->head == p) q -> head = p -> next;
143 p -> next = p -> prev = NULL;
148 register struct QUEUE *q;
150 if (q->head == NULL) { /* Queue is empty */
152 p -> next = p -> prev = p;
153 } else { /* Regular insert */
154 p -> prev = q -> head -> prev;
155 q -> head -> prev -> next = p;
156 q -> head -> prev = p;
157 p -> next = q -> head;
162 static move(p, from, to)
164 struct QUEUE *from, *to;
174 #define for_all_elts(var, q, body)\
176 register PROCESS var, _NEXT_;\
178 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
179 _NEXT_ = var -> next;\
185 /*****************************************************************************\
187 * Following section documents the Assembler interfaces used by LWP code *
189 \*****************************************************************************/
192 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
194 Stub for Assembler routine that will
195 save the current SP value in the passed
196 context savearea and call the function
197 whose entry point is in ep. If the sp
198 parameter is NULL, the current stack is
199 used, otherwise sp becomes the new stack
202 returnto(struct lwp_context *savearea);
204 Stub for Assembler routine that will
205 restore context from a passed savearea
206 and return to the restored C frame.
210 /* Macro to force a re-schedule. Strange name is historical */
211 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
213 static struct lwp_ctl *lwp_init = 0;
216 {register PROCESS tp;
217 (tp=lwp_cpptr) -> status = QWAITING;
218 lwp_remove(tp, &runnable[tp->priority]);
224 register PROCESS pid; {
225 if (pid->status == QWAITING) {
227 insert(pid, &runnable[pid->priority]);
230 else return LWP_ENOWAIT;
234 char *reserveFromStack(size)
235 register afs_int32 size;
243 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
245 int stacksize, priority;
252 static char *stackptr = 0;
257 #if defined(AFS_LWP_MINSTACKSIZE)
259 * on some systems (e.g. hpux), a minimum usable stack size has
262 if (stacksize < lwp_MinStackSize) {
263 stacksize = lwp_MinStackSize;
265 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
266 /* more stack size computations; keep track of for IOMGR */
267 if (lwp_MaxStackSeen < stacksize)
268 lwp_MaxStackSeen = stacksize;
270 Debug(0, ("Entered LWP_CreateProcess"))
271 /* Throw away all dead process control blocks */
274 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
279 if (stacksize < MINSTACK)
282 stacksize = STACK_ALIGN * ((stacksize+STACK_ALIGN-1) / STACK_ALIGN);
286 * The following signal action for AIX is necessary so that in case of a
287 * crash (i.e. core is generated) we can include the user's data section
288 * in the core dump. Unfortunately, by default, only a partial core is
289 * generated which, in many cases, isn't too useful.
291 * We also do it here in case the main program forgets to do it.
293 struct sigaction nsa;
294 extern uid_t geteuid();
296 sigemptyset(&nsa.sa_mask);
297 nsa.sa_handler = SIG_DFL;
298 nsa.sa_flags = SA_FULLDUMP;
299 sigaction(SIGABRT, &nsa, NULL);
300 sigaction(SIGSEGV, &nsa, NULL);
303 * First we need to increase the default resource limits,
304 * if necessary, so that we can guarantee that we have the
305 * resources to create the core file, but we can't always
306 * do it as an ordinary user.
309 /* vos dump causes problems */
310 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
311 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
312 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
315 * Now reserve in one scoop all the stack space that will be used
316 * by the particular application's main (i.e. non-lwp) body. This
317 * is plenty space for any of our applications.
319 stackptr = reserveFromStack(lwp_MaxStackSize);
321 stackptr -= stacksize;
323 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
327 /* Round stack pointer to byte boundary */
328 stackptr = (char *)(8 * (((long)stackptr+7) / 8));
330 if (priority < 0 || priority >= MAX_PRIORITIES) {
334 Initialize_Stack(stackptr, stacksize);
335 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
336 insert(temp, &runnable[priority]);
338 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
340 /* Gross hack: beware! */
344 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
346 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV)
347 /* Need to have the sp on an 8-byte boundary for storing doubles. */
348 savecontext(Create_Process_Part2, &temp2->context,
349 stackptr+stacksize-16); /* 16 = 2 * jmp_buf_type*/
351 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
352 savecontext(Create_Process_Part2, &temp2->context,
353 stackptr+stacksize-0x40); /* lomgjmp does something
356 #if defined(AFS_S390_LINUX20_ENV)
357 savecontext(Create_Process_Part2, &temp2->context,
358 stackptr+stacksize-MINFRAME);
359 #else /* !AFS_S390_LINUX20_ENV */
360 savecontext(Create_Process_Part2, &temp2->context,
361 stackptr+stacksize-sizeof(void *));
362 #endif /* AFS_S390_LINUX20_ENV */
363 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
364 #endif /* AFS_SGI62_ENV */
366 /* End of gross hack */
376 int LWP_CreateProcess2(ep, stacksize, priority, parm, name, pid)
378 int stacksize, priority;
386 #if defined(AFS_LWP_MINSTACKSIZE)
388 * on some systems (e.g. hpux), a minimum usable stack size has
391 if (stacksize < lwp_MinStackSize) {
392 stacksize = lwp_MinStackSize;
394 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
395 /* more stack size computations; keep track of for IOMGR */
396 if (lwp_MaxStackSeen < stacksize)
397 lwp_MaxStackSeen = stacksize;
399 Debug(0, ("Entered LWP_CreateProcess"))
400 /* Throw away all dead process control blocks */
403 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
408 if (stacksize < MINSTACK)
411 stacksize = STACK_ALIGN * ((stacksize+STACK_ALIGN-1) / STACK_ALIGN);
412 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
416 if (priority < 0 || priority >= MAX_PRIORITIES) {
420 Initialize_Stack(stackptr, stacksize);
421 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
422 insert(temp, &runnable[priority]);
424 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
426 /* Gross hack: beware! */
430 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
432 #if defined(AFS_S390_LINUX20_ENV)
433 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-MINFRAME);
435 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-sizeof(void *));
438 /* End of gross hack */
448 int LWP_CurrentProcess(pid) /* returns pid of current process */
451 Debug(0, ("Entered Current_Process"))
459 PROCESS LWP_ThreadId()
461 Debug(0, ("Entered ThreadId"))
468 #define LWPANCHOR (*lwp_init)
470 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
475 Debug(0, ("Entered Destroy_Process"))
477 if (lwp_cpptr != pid) {
478 Dispose_of_Dead_PCB(pid);
481 pid -> status = DESTROYED;
482 move(pid, &runnable[pid->priority], &blocked);
485 savecontext(Dispatcher, &(temp -> context),
486 &(LWPANCHOR.dsptchstack[MINFRAME]));
488 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV)
489 savecontext(Dispatcher, &(temp -> context),
490 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-8]));
492 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
493 savecontext(Dispatcher, &(temp -> context),
494 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-0x40]));
496 #if defined(AFS_S390_LINUX20_ENV)
497 savecontext(Dispatcher, &(temp -> context),
498 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-MINFRAME]));
500 savecontext(Dispatcher, &(temp -> context),
501 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-sizeof(void *)]));
512 int LWP_DispatchProcess() /* explicit voluntary preemption */
514 Debug(2, ("Entered Dispatch_Process"))
527 for (i=0; i<MAX_PRIORITIES; i++)
528 for_all_elts(x, runnable[i], {
529 printf("[Priority %d]\n", i);
532 for_all_elts(x, blocked, { Dump_One_Process(x); })
534 printf("***LWP: LWP support not initialized\n");
538 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
542 Debug(0, ("Entered Get_Process_Priority"))
544 *priority = pid -> priority;
550 int LWP_InitializeProcessSupport(priority, pid)
555 struct lwp_pcb dummy;
559 Debug(0, ("Entered LWP_InitializeProcessSupport"))
560 if (lwp_init != NULL) return LWP_SUCCESS;
562 /* Set up offset for stack checking -- do this as soon as possible */
563 stack_offset = (char *) &dummy.stack - (char *) &dummy;
565 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
566 for (i=0; i<MAX_PRIORITIES; i++) {
567 runnable[i].head = NULL;
568 runnable[i].count = 0;
572 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
573 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
574 if (lwp_init == NULL || temp == NULL)
575 Abort_LWP("Insufficient Storage to Initialize LWP Support");
576 LWPANCHOR.processcnt = 1;
577 LWPANCHOR.outerpid = temp;
578 LWPANCHOR.outersp = NULL;
579 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
580 insert(temp, &runnable[priority]);
581 savecontext(Dispatcher, &temp->context, NULL);
582 LWPANCHOR.outersp = temp -> context.topstack;
586 /* get minimum stack size from the environment. this allows the administrator
587 * to change the lwp stack dynamically without getting a new binary version.
589 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
590 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
592 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
593 AFS_LWP_MINSTACKSIZE : atoi(value));
598 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
602 Debug(2, ("Entered LWP_SignalProcess"))
605 rc = Internal_Signal(event);
606 if (yield) Set_LWP_RC();
612 int LWP_TerminateProcessSupport() /* terminate all LWP support */
616 Debug(0, ("Entered Terminate_Process_Support"))
617 if (lwp_init == NULL) return LWP_EINIT;
618 if (lwp_cpptr != LWPANCHOR.outerpid)
619 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
620 for (i=0; i<MAX_PRIORITIES; i++)
621 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
622 for_all_elts(cur, blocked, { Free_PCB(cur); })
628 int LWP_WaitProcess(event) /* wait on a single event */
633 Debug(2, ("Entered Wait_Process"))
634 if (event == NULL) return LWP_EBADEVENT;
637 return LWP_MwaitProcess(1, tempev);
640 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
644 register int ecount, i;
647 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
649 if (evlist == NULL) {
651 return LWP_EBADCOUNT;
654 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
658 return LWP_EBADCOUNT;
663 if (wcount>ecount || wcount<0) {
665 return LWP_EBADCOUNT;
667 if (ecount > lwp_cpptr->eventlistsize) {
669 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *));
670 lwp_cpptr->eventlistsize = ecount;
672 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
674 lwp_cpptr -> status = WAITING;
676 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
679 lwp_cpptr -> wakevent = 0;
680 lwp_cpptr -> waitcnt = wcount;
681 lwp_cpptr -> eventcnt = ecount;
691 int LWP_StackUsed(pid, maxa, used)
695 *maxa = pid -> stacksize;
696 *used = Stack_Used(pid->stack, *maxa);
703 * The following functions are strictly
704 * INTERNAL to the LWP support package.
707 static void Abort_LWP(msg)
710 struct lwp_context tempcontext;
712 Debug(0, ("Entered Abort_LWP"))
713 printf("***LWP: %s\n",msg);
714 printf("***LWP: Abort --- dumping PCBs ...\n");
718 if (LWPANCHOR.outersp == NULL)
721 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
724 static int Create_Process_Part2 () /* creates a context for the new process */
728 Debug(2, ("Entered Create_Process_Part2"))
729 temp = lwp_cpptr; /* Get current process id */
730 savecontext(Dispatcher, &temp->context, NULL);
731 (*temp->ep)(temp->parm);
732 LWP_DestroyProcess(temp);
735 static Delete_PCB(pid) /* remove a PCB from the process list */
736 register PROCESS pid;
738 Debug(4, ("Entered Delete_PCB"))
739 lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
741 : &runnable[pid->priority]));
742 LWPANCHOR.processcnt--;
746 static Dump_One_Process(pid)
751 printf("***LWP: Process Control Block at 0x%x\n", pid);
752 printf("***LWP: Name: %s\n", pid->name);
754 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
755 if (pid->blockflag) printf("BLOCKED and ");
756 switch (pid->status) {
757 case READY: printf("READY"); break;
758 case WAITING: printf("WAITING"); break;
759 case DESTROYED: printf("DESTROYED"); break;
760 default: printf("unknown");
763 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
764 pid->priority, pid->parm);
765 if (pid->stacksize != 0) {
766 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
767 pid->stacksize, pid->stack);
768 printf("***LWP: HWM stack usage: ");
769 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
772 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
773 if (pid->eventcnt > 0) {
774 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
775 printf("***LWP: Event id list:");
776 for (i=0;i<pid->eventcnt;i++)
777 printf(" 0x%x", pid->eventlist[i]);
781 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
785 static purge_dead_pcbs()
787 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
790 int LWP_TraceProcesses = 0;
792 static Dispatcher() /* Lightweight process dispatcher */
796 static int dispatch_count = 0;
798 if (LWP_TraceProcesses > 0) {
799 for (i=0; i<MAX_PRIORITIES; i++) {
800 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
801 for_all_elts(p, runnable[i], {
802 printf(" \"%s\"", p->name);
806 printf("[Blocked (%d):", blocked.count);
807 for_all_elts(p, blocked, {
808 printf(" \"%s\"", p->name);
814 /* Check for stack overflowif this lwp has a stack. Check for
815 the guard word at the front of the stack being damaged and
816 for the stack pointer being below the front of the stack.
817 WARNING! This code assumes that stacks grow downward. */
819 /* Fix this (stackcheck at other end of stack?) */
820 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
821 && (lwp_cpptr->stackcheck !=
822 *(afs_int32 *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
823 || lwp_cpptr->context.topstack >
824 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
826 if (lwp_cpptr && lwp_cpptr->stack &&
827 (lwp_cpptr->stackcheck != *(afs_int32 *)(lwp_cpptr->stack) ||
828 lwp_cpptr->context.topstack < lwp_cpptr->stack ||
829 lwp_cpptr->context.topstack > (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
831 printf("stackcheck = %u: stack = %u \n",
832 lwp_cpptr->stackcheck, *(afs_int32 *)lwp_cpptr->stack);
833 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
834 lwp_cpptr->context.topstack, lwp_cpptr->stack, lwp_cpptr->stacksize);
836 switch (lwp_overflowAction) {
845 lwp_overflowAction = LWP_SOQUIET;
850 /* Move head of current runnable queue forward if current LWP is still in it. */
851 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
852 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head -> next;
853 /* Find highest priority with runnable processes. */
854 for (i=MAX_PRIORITIES-1; i>=0; i--)
855 if (runnable[i].head != NULL) break;
857 if (i < 0) Abort_LWP("No READY processes");
860 if (LWP_TraceProcesses > 0)
861 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
863 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
864 lwp_cpptr = runnable[i].head;
866 returnto(&lwp_cpptr->context);
869 /* Complain of a stack overflow to stderr without using stdio. */
870 static void Overflow_Complain ()
874 char *msg1 = " LWP: stack overflow in process ";
877 currenttime = time(0);
878 timeStamp = ctime(¤ttime);
880 write (2, timeStamp, strlen(timeStamp));
882 write (2, msg1, strlen(msg1));
883 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
884 write (2, msg2, strlen(msg2));
887 static void Dispose_of_Dead_PCB (cur)
890 Debug(4, ("Entered Dispose_of_Dead_PCB"))
894 Internal_Signal(cur);
903 static void Free_PCB(pid)
906 Debug(4, ("Entered Free_PCB"))
907 if (pid -> stack != NULL) {
908 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
909 Stack_Used(pid->stack,pid->stacksize), pid))
912 if (pid->eventlist != NULL) free(pid->eventlist);
916 static void Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
919 int stacksize, priority;
925 Debug(4, ("Entered Initialize_PCB"))
927 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
928 temp -> name[31] = '\0';
929 temp -> status = READY;
930 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
931 temp -> eventlistsize = EVINITSIZE;
932 temp -> eventcnt = 0;
933 temp -> wakevent = 0;
935 temp -> blockflag = 0;
936 temp -> iomgrRequest = 0;
937 temp -> priority = priority;
938 temp -> index = lwp_nextindex++;
939 temp -> stack = stack;
940 temp -> stacksize = stacksize;
942 if (temp -> stack != NULL)
943 temp -> stackcheck = *(afs_int32 *) ((temp -> stack) + stacksize - 4);
945 if (temp -> stack != NULL)
946 temp -> stackcheck = *(afs_int32 *) (temp -> stack);
950 temp -> misc = NULL; /* currently unused */
953 temp -> lwp_rused = 0;
954 temp -> level = 1; /* non-preemptable */
957 static int Internal_Signal(event)
958 register char *event;
960 int rc = LWP_ENOWAIT;
963 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
964 if (!lwp_init) return LWP_EINIT;
965 if (event == NULL) return LWP_EBADEVENT;
966 for_all_elts(temp, blocked, {
967 if (temp->status == WAITING)
968 for (i=0; i < temp->eventcnt; i++) {
969 if (temp -> eventlist[i] == event) {
970 temp -> eventlist[i] = NULL;
972 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
973 if (--temp->waitcnt == 0) {
974 temp -> status = READY;
975 temp -> wakevent = i+1;
976 move(temp, &blocked, &runnable[temp->priority]);
985 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
986 #define STACKMAGIC 0xBADBADBA
987 static afs_int32 Initialize_Stack(stackptr, stacksize)
993 Debug(4, ("Entered Initialize_Stack"))
994 if (lwp_stackUseEnabled)
995 for (i=0; i<stacksize; i++)
996 stackptr[i] = i &0xff;
999 *(afs_int32 *)(stackptr + stacksize - 4) = STACKMAGIC;
1001 *(afs_int32 *)stackptr = STACKMAGIC;
1005 static int Stack_Used(stackptr, stacksize)
1006 register char *stackptr;
1012 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1015 for (i = stacksize - 1; i >= 0 ; i--)
1016 if ((unsigned char) stackptr[i] != (i & 0xff))
1021 if (*(afs_int32 *) stackptr == STACKMAGIC)
1024 for (i = 0; i < stacksize; i++)
1025 if ((unsigned char) stackptr[i] != (i & 0xff))
1026 return (stacksize - i);
1033 LWP_NewRock(Tag, Value)
1035 char *Value; /* IN */
1036 /* Finds a free rock and sets its value to Value.
1038 LWP_SUCCESS Rock did not exist and a new one was used
1039 LWP_EBADROCK Rock already exists.
1040 LWP_ENOROCKS All rocks are in use.
1042 From the above semantics, you can only set a rock value once. This is specifically
1043 to prevent multiple users of the LWP package from accidentally using the same Tag
1044 value and clobbering others. You can always use one level of indirection to obtain
1045 a rock whose contents can change.
1049 register struct rock *ra; /* rock array */
1051 ra = lwp_cpptr->lwp_rlist;
1053 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1054 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1056 if (lwp_cpptr->lwp_rused < MAXROCKS)
1058 ra[lwp_cpptr->lwp_rused].tag = Tag;
1059 ra[lwp_cpptr->lwp_rused].value = Value;
1060 lwp_cpptr->lwp_rused++;
1061 return(LWP_SUCCESS);
1063 else return(LWP_ENOROCKS);
1067 LWP_GetRock(Tag, Value)
1069 char **Value; /* OUT */
1071 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1073 LWP_SUCCESS if specified rock exists and Value has been filled
1074 LWP_EBADROCK rock specified does not exist
1078 register struct rock *ra;
1080 ra = lwp_cpptr->lwp_rlist;
1082 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1083 if (ra[i].tag == Tag)
1085 *Value = ra[i].value;
1086 return(LWP_SUCCESS);
1088 return(LWP_EBADROCK);
1092 #ifdef AFS_AIX32_ENV
1093 setlim(limcon, hard, limit)
1099 (void) getrlimit(limcon, &rlim);
1101 limit = limit * 1024;
1103 rlim.rlim_max = limit;
1104 else if (limit == RLIM_INFINITY && geteuid() != 0)
1105 rlim.rlim_cur = rlim.rlim_max;
1107 rlim.rlim_cur = limit;
1109 /* Must use ulimit() due to Posix constraints */
1110 if (limcon == RLIMIT_FSIZE) {
1111 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1112 printf("Can't %s%s limit\n",
1113 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1117 if (setrlimit(limcon, &rlim) < 0) {
1119 printf("Can't %s%s limit\n",
1120 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1130 * Print the specific limit out
1132 plim(name, lc, hard)
1140 printf("%s \t", name);
1141 (void) getrlimit(lc, &rlim);
1142 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1143 if (lim == RLIM_INFINITY)
1144 printf("unlimited");
1145 printf("%d %s", lim / 1024, "kbytes");
1152 int LWP_NoYieldSignal(event)
1155 return (LWP_INTERNALSIGNAL(event, 0));
1158 int LWP_SignalProcess(event)
1161 return (LWP_INTERNALSIGNAL(event, 1));
1166 #ifdef USE_SOLARIS_THREADS
1169 #include "pthread.h"
1174 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1176 PROCESS lwp_process_list; /* List of LWP initiated threads */
1178 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1180 #define CHECK check(__LINE__);
1182 typedef struct event {
1183 struct event *next; /* next in hash chain */
1184 char *event; /* lwp event: an address */
1185 int refcount; /* Is it in use? */
1186 pthread_cond_t cond; /* Currently associated condition variable */
1187 int seq; /* Sequence number: this is incremented
1188 by wakeup calls; wait will not return until
1192 #define HASHSIZE 127
1193 event_t *hashtable[HASHSIZE];/* Hash table for events */
1194 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1196 #if CMA_DEBUG || DEBUGF
1197 char *lwp_process_string() {
1198 static char id[200];
1200 LWP_CurrentProcess(&p);
1201 sprintf(id, "PID %x <%s>", p, p->name);
1206 void lwp_unimplemented(interface)
1209 fprintf(stderr, "cmalwp: %s is not currently implemented: program aborted\n",
1214 static lwpabort(interface)
1217 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1223 lwp_unimplemented("LWP_QWait");
1226 int LWP_QSignal(pid)
1228 lwp_unimplemented("LWP_QSignal");
1231 /* Allocate and initialize an LWP process handle. The associated pthread handle
1232 * must be added by the caller, and the structure threaded onto the LWP active
1233 * process list by lwp_thread_process */
1234 static PROCESS lwp_alloc_process(name, ep, arg)
1236 pthread_startroutine_t ep;
1240 assert(lp = (PROCESS) malloc(sizeof (*lp)));
1241 bzero((char *) lp, sizeof(*lp));
1245 sprintf(temp, "unnamed_process_%04d", ++procnum);
1246 assert(name = (char *)malloc(strlen(temp) + 1));
1255 /* Thread the LWP process descriptor *lp onto the lwp active process list
1256 * and associate a back pointer to the process descriptor from the associated
1258 static lwp_thread_process(lp)
1261 lp->next = lwp_process_list;
1262 lwp_process_list = lp;
1263 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1266 /* The top-level routine used as entry point to explicitly created LWP
1267 * processes. This completes a few details of process creation left
1268 * out by LWP_CreateProcess and calls the user-specified entry point */
1269 static int lwp_top_level(argp)
1270 pthread_addr_t argp;
1272 PROCESS lp = (PROCESS) argp;
1274 assert(!pthread_mutex_lock(&lwp_mutex));
1275 lwp_thread_process(lp);
1277 assert(!pthread_mutex_unlock(&lwp_mutex));
1278 /* Should cleanup state */
1281 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
1283 int stacksize, priority;
1289 pthread_attr_t attr;
1293 #ifndef LWP_NO_PRIORITIES
1294 if (!cmalwp_pri_inrange(priority))
1297 assert(!pthread_attr_create(&attr));
1298 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1300 assert(!pthread_attr_setstacksize(&attr, stacksize));
1302 (void) pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1303 (void) pthread_attr_setsched(&attr, SCHED_FIFO);
1304 #ifndef LWP_NO_PRIORITIES
1305 (void) pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1308 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep, (pthread_addr_t) parm);
1310 /* allow new thread to run if higher priority */
1311 assert(!pthread_mutex_unlock(&lwp_mutex));
1312 /* process is only added to active list after first time it runs (it adds itself) */
1313 status = pthread_create(&lp->handle,
1315 (pthread_startroutine_t) lwp_top_level,
1316 (pthread_addr_t) lp);
1317 assert(!pthread_attr_delete(&attr));
1318 assert (!pthread_mutex_lock(&lwp_mutex));
1327 PROCESS LWP_ActiveProcess() { /* returns pid of current process */
1329 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) &pid));
1333 int LWP_CurrentProcess(pid) /* get pid of current process */
1336 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1340 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
1343 lwp_unimplemented("LWP_DestroyProcess");
1346 int LWP_DispatchProcess() /* explicit voluntary preemption */
1348 assert(!pthread_mutex_unlock(&lwp_mutex));
1350 assert(!pthread_mutex_lock(&lwp_mutex));
1354 static int lwp_process_key_destructor() {}
1356 int LWP_InitializeProcessSupport(priority, pid)
1360 static int initialized = 0;
1371 #ifndef LWP_NO_PRIORITIES
1372 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1376 /* Create pthread key to associate LWP process descriptor with each
1377 LWP-created thread */
1378 assert(!pthread_keycreate(&lwp_process_key,
1379 (pthread_destructor_t) lwp_process_key_destructor));
1381 lp = lwp_alloc_process("main process", main, 0);
1382 lp->handle = pthread_self();
1383 lwp_thread_process(lp);
1384 #ifndef LWP_NO_PRIORITIES
1385 (void) pthread_setscheduler(pthread_self(),
1387 cmalwp_lwppri_to_cmapri(priority));
1390 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1391 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1397 int LWP_TerminateProcessSupport() /* terminate all LWP support */
1399 lwp_unimplemented("LWP_TerminateProcessSupport");
1402 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1403 static event_t *getevent(event)
1406 event_t *evp, *newp;
1409 hashcode = hash(event);
1410 evp = hashtable[hashcode];
1413 if (evp->event == event) {
1417 if (evp->refcount == 0)
1422 newp = (event_t *) malloc(sizeof (event_t));
1424 newp->next = hashtable[hashcode];
1425 hashtable[hashcode] = newp;
1426 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t)0)));
1429 newp->event = event;
1434 /* Release the specified event */
1435 #define relevent(evp) ((evp)->refcount--)
1437 int LWP_WaitProcess(event) /* wait on a single event */
1442 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1443 if (event == NULL) return LWP_EBADEVENT;
1444 ev = getevent(event);
1446 while (seq == ev->seq) {
1447 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1449 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1454 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
1458 lwp_unimplemented("LWP_MWaitProcess");
1461 int LWP_NoYieldSignal(event)
1465 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1466 if (event == NULL) return LWP_EBADEVENT;
1467 ev = getevent(event);
1468 if (ev->refcount > 1) {
1470 assert(pthread_cond_broadcast(&ev->cond) == 0);
1476 int LWP_SignalProcess(event)
1480 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1481 if (event == NULL) return LWP_EBADEVENT;
1482 ev = getevent(event);
1483 if (ev->refcount > 1) {
1485 assert(!pthread_mutex_unlock(&lwp_mutex));
1486 assert(!pthread_cond_broadcast(&ev->cond));
1488 assert(!pthread_mutex_lock(&lwp_mutex));
1494 int LWP_StackUsed(pid, maxa, used)
1498 lwp_unimplemented("LWP_StackUsed");
1501 LWP_NewRock(Tag, Value)
1503 char *Value; /* IN */
1505 lwp_unimplemented("LWP_NewRock");
1508 LWP_GetRock(Tag, Value)
1510 char **Value; /* OUT */
1512 lwp_unimplemented("LWP_GetRock");
1515 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
1519 lwp_unimplemented("LWP_GetProcessPriority");
1522 #endif /* USE_PTHREADS */