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 #define LWPANCHOR (*lwp_init)
450 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
455 Debug(0, ("Entered Destroy_Process"))
457 if (lwp_cpptr != pid) {
458 Dispose_of_Dead_PCB(pid);
461 pid -> status = DESTROYED;
462 move(pid, &runnable[pid->priority], &blocked);
465 savecontext(Dispatcher, &(temp -> context),
466 &(LWPANCHOR.dsptchstack[MINFRAME]));
469 savecontext(Dispatcher, &(temp -> context),
470 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-8]));
472 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
473 savecontext(Dispatcher, &(temp -> context),
474 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-0x40]));
476 savecontext(Dispatcher, &(temp -> context),
477 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-sizeof(void *)]));
487 int LWP_DispatchProcess() /* explicit voluntary preemption */
489 Debug(2, ("Entered Dispatch_Process"))
502 for (i=0; i<MAX_PRIORITIES; i++)
503 for_all_elts(x, runnable[i], {
504 printf("[Priority %d]\n", i);
507 for_all_elts(x, blocked, { Dump_One_Process(x); })
509 printf("***LWP: LWP support not initialized\n");
513 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
517 Debug(0, ("Entered Get_Process_Priority"))
519 *priority = pid -> priority;
525 int LWP_InitializeProcessSupport(priority, pid)
530 struct lwp_pcb dummy;
534 Debug(0, ("Entered LWP_InitializeProcessSupport"))
535 if (lwp_init != NULL) return LWP_SUCCESS;
537 /* Set up offset for stack checking -- do this as soon as possible */
538 stack_offset = (char *) &dummy.stack - (char *) &dummy;
540 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
541 for (i=0; i<MAX_PRIORITIES; i++) {
542 runnable[i].head = NULL;
543 runnable[i].count = 0;
547 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
548 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
549 if (lwp_init == NULL || temp == NULL)
550 Abort_LWP("Insufficient Storage to Initialize LWP Support");
551 LWPANCHOR.processcnt = 1;
552 LWPANCHOR.outerpid = temp;
553 LWPANCHOR.outersp = NULL;
554 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
555 insert(temp, &runnable[priority]);
556 savecontext(Dispatcher, &temp->context, NULL);
557 LWPANCHOR.outersp = temp -> context.topstack;
561 /* get minimum stack size from the environment. this allows the administrator
562 * to change the lwp stack dynamically without getting a new binary version.
564 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
565 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
567 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
568 AFS_LWP_MINSTACKSIZE : atoi(value));
573 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
577 Debug(2, ("Entered LWP_SignalProcess"))
580 rc = Internal_Signal(event);
581 if (yield) Set_LWP_RC();
587 int LWP_TerminateProcessSupport() /* terminate all LWP support */
591 Debug(0, ("Entered Terminate_Process_Support"))
592 if (lwp_init == NULL) return LWP_EINIT;
593 if (lwp_cpptr != LWPANCHOR.outerpid)
594 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
595 for (i=0; i<MAX_PRIORITIES; i++)
596 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
597 for_all_elts(cur, blocked, { Free_PCB(cur); })
603 int LWP_WaitProcess(event) /* wait on a single event */
608 Debug(2, ("Entered Wait_Process"))
609 if (event == NULL) return LWP_EBADEVENT;
612 return LWP_MwaitProcess(1, tempev);
615 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
619 register int ecount, i;
622 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
624 if (evlist == NULL) {
626 return LWP_EBADCOUNT;
629 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
633 return LWP_EBADCOUNT;
638 if (wcount>ecount || wcount<0) {
640 return LWP_EBADCOUNT;
642 if (ecount > lwp_cpptr->eventlistsize) {
644 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *));
645 lwp_cpptr->eventlistsize = ecount;
647 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
649 lwp_cpptr -> status = WAITING;
651 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
654 lwp_cpptr -> wakevent = 0;
655 lwp_cpptr -> waitcnt = wcount;
656 lwp_cpptr -> eventcnt = ecount;
666 int LWP_StackUsed(pid, maxa, used)
670 *maxa = pid -> stacksize;
671 *used = Stack_Used(pid->stack, *maxa);
678 * The following functions are strictly
679 * INTERNAL to the LWP support package.
682 static void Abort_LWP(msg)
685 struct lwp_context tempcontext;
687 Debug(0, ("Entered Abort_LWP"))
688 printf("***LWP: %s\n",msg);
689 printf("***LWP: Abort --- dumping PCBs ...\n");
693 if (LWPANCHOR.outersp == NULL)
696 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
699 static int Create_Process_Part2 () /* creates a context for the new process */
703 Debug(2, ("Entered Create_Process_Part2"))
704 temp = lwp_cpptr; /* Get current process id */
705 savecontext(Dispatcher, &temp->context, NULL);
706 (*temp->ep)(temp->parm);
707 LWP_DestroyProcess(temp);
710 static Delete_PCB(pid) /* remove a PCB from the process list */
711 register PROCESS pid;
713 Debug(4, ("Entered Delete_PCB"))
714 lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
716 : &runnable[pid->priority]));
717 LWPANCHOR.processcnt--;
721 static Dump_One_Process(pid)
726 printf("***LWP: Process Control Block at 0x%x\n", pid);
727 printf("***LWP: Name: %s\n", pid->name);
729 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
730 if (pid->blockflag) printf("BLOCKED and ");
731 switch (pid->status) {
732 case READY: printf("READY"); break;
733 case WAITING: printf("WAITING"); break;
734 case DESTROYED: printf("DESTROYED"); break;
735 default: printf("unknown");
738 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
739 pid->priority, pid->parm);
740 if (pid->stacksize != 0) {
741 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
742 pid->stacksize, pid->stack);
743 printf("***LWP: HWM stack usage: ");
744 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
747 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
748 if (pid->eventcnt > 0) {
749 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
750 printf("***LWP: Event id list:");
751 for (i=0;i<pid->eventcnt;i++)
752 printf(" 0x%x", pid->eventlist[i]);
756 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
760 static purge_dead_pcbs()
762 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
765 int LWP_TraceProcesses = 0;
767 static Dispatcher() /* Lightweight process dispatcher */
771 static int dispatch_count = 0;
773 if (LWP_TraceProcesses > 0) {
774 for (i=0; i<MAX_PRIORITIES; i++) {
775 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
776 for_all_elts(p, runnable[i], {
777 printf(" \"%s\"", p->name);
781 printf("[Blocked (%d):", blocked.count);
782 for_all_elts(p, blocked, {
783 printf(" \"%s\"", p->name);
789 /* Check for stack overflowif this lwp has a stack. Check for
790 the guard word at the front of the stack being damaged and
791 for the stack pointer being below the front of the stack.
792 WARNING! This code assumes that stacks grow downward. */
794 /* Fix this (stackcheck at other end of stack?) */
795 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
796 && (lwp_cpptr->stackcheck !=
797 *(afs_int32 *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
798 || lwp_cpptr->context.topstack >
799 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
801 if (lwp_cpptr && lwp_cpptr->stack &&
802 (lwp_cpptr->stackcheck != *(afs_int32 *)(lwp_cpptr->stack) ||
803 lwp_cpptr->context.topstack < lwp_cpptr->stack ||
804 lwp_cpptr->context.topstack > (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
806 printf("stackcheck = %u: stack = %u \n",
807 lwp_cpptr->stackcheck, *(afs_int32 *)lwp_cpptr->stack);
808 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
809 lwp_cpptr->context.topstack, lwp_cpptr->stack, lwp_cpptr->stacksize);
811 switch (lwp_overflowAction) {
820 lwp_overflowAction = LWP_SOQUIET;
825 /* Move head of current runnable queue forward if current LWP is still in it. */
826 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
827 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head -> next;
828 /* Find highest priority with runnable processes. */
829 for (i=MAX_PRIORITIES-1; i>=0; i--)
830 if (runnable[i].head != NULL) break;
832 if (i < 0) Abort_LWP("No READY processes");
835 if (LWP_TraceProcesses > 0)
836 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
838 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
839 lwp_cpptr = runnable[i].head;
841 returnto(&lwp_cpptr->context);
844 /* Complain of a stack overflow to stderr without using stdio. */
845 static void Overflow_Complain ()
849 char *msg1 = " LWP: stack overflow in process ";
852 currenttime = time(0);
853 timeStamp = ctime(¤ttime);
855 write (2, timeStamp, strlen(timeStamp));
857 write (2, msg1, strlen(msg1));
858 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
859 write (2, msg2, strlen(msg2));
862 static void Dispose_of_Dead_PCB (cur)
865 Debug(4, ("Entered Dispose_of_Dead_PCB"))
869 Internal_Signal(cur);
878 static void Free_PCB(pid)
881 Debug(4, ("Entered Free_PCB"))
882 if (pid -> stack != NULL) {
883 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
884 Stack_Used(pid->stack,pid->stacksize), pid))
887 if (pid->eventlist != NULL) free(pid->eventlist);
891 static void Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
894 int stacksize, priority;
900 Debug(4, ("Entered Initialize_PCB"))
902 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
903 temp -> name[31] = '\0';
904 temp -> status = READY;
905 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
906 temp -> eventlistsize = EVINITSIZE;
907 temp -> eventcnt = 0;
908 temp -> wakevent = 0;
910 temp -> blockflag = 0;
911 temp -> iomgrRequest = 0;
912 temp -> priority = priority;
913 temp -> index = lwp_nextindex++;
914 temp -> stack = stack;
915 temp -> stacksize = stacksize;
917 if (temp -> stack != NULL)
918 temp -> stackcheck = *(afs_int32 *) ((temp -> stack) + stacksize - 4);
920 if (temp -> stack != NULL)
921 temp -> stackcheck = *(afs_int32 *) (temp -> stack);
925 temp -> misc = NULL; /* currently unused */
928 temp -> lwp_rused = 0;
929 temp -> level = 1; /* non-preemptable */
932 static int Internal_Signal(event)
933 register char *event;
935 int rc = LWP_ENOWAIT;
938 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
939 if (!lwp_init) return LWP_EINIT;
940 if (event == NULL) return LWP_EBADEVENT;
941 for_all_elts(temp, blocked, {
942 if (temp->status == WAITING)
943 for (i=0; i < temp->eventcnt; i++) {
944 if (temp -> eventlist[i] == event) {
945 temp -> eventlist[i] = NULL;
947 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
948 if (--temp->waitcnt == 0) {
949 temp -> status = READY;
950 temp -> wakevent = i+1;
951 move(temp, &blocked, &runnable[temp->priority]);
960 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
961 #define STACKMAGIC 0xBADBADBA
962 static afs_int32 Initialize_Stack(stackptr, stacksize)
968 Debug(4, ("Entered Initialize_Stack"))
969 if (lwp_stackUseEnabled)
970 for (i=0; i<stacksize; i++)
971 stackptr[i] = i &0xff;
974 *(afs_int32 *)(stackptr + stacksize - 4) = STACKMAGIC;
976 *(afs_int32 *)stackptr = STACKMAGIC;
980 static int Stack_Used(stackptr, stacksize)
981 register char *stackptr;
987 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
990 for (i = stacksize - 1; i >= 0 ; i--)
991 if ((unsigned char) stackptr[i] != (i & 0xff))
996 if (*(afs_int32 *) stackptr == STACKMAGIC)
999 for (i = 0; i < stacksize; i++)
1000 if ((unsigned char) stackptr[i] != (i & 0xff))
1001 return (stacksize - i);
1008 LWP_NewRock(Tag, Value)
1010 char *Value; /* IN */
1011 /* Finds a free rock and sets its value to Value.
1013 LWP_SUCCESS Rock did not exist and a new one was used
1014 LWP_EBADROCK Rock already exists.
1015 LWP_ENOROCKS All rocks are in use.
1017 From the above semantics, you can only set a rock value once. This is specifically
1018 to prevent multiple users of the LWP package from accidentally using the same Tag
1019 value and clobbering others. You can always use one level of indirection to obtain
1020 a rock whose contents can change.
1024 register struct rock *ra; /* rock array */
1026 ra = lwp_cpptr->lwp_rlist;
1028 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1029 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1031 if (lwp_cpptr->lwp_rused < MAXROCKS)
1033 ra[lwp_cpptr->lwp_rused].tag = Tag;
1034 ra[lwp_cpptr->lwp_rused].value = Value;
1035 lwp_cpptr->lwp_rused++;
1036 return(LWP_SUCCESS);
1038 else return(LWP_ENOROCKS);
1042 LWP_GetRock(Tag, Value)
1044 char **Value; /* OUT */
1046 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1048 LWP_SUCCESS if specified rock exists and Value has been filled
1049 LWP_EBADROCK rock specified does not exist
1053 register struct rock *ra;
1055 ra = lwp_cpptr->lwp_rlist;
1057 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1058 if (ra[i].tag == Tag)
1060 *Value = ra[i].value;
1061 return(LWP_SUCCESS);
1063 return(LWP_EBADROCK);
1067 #ifdef AFS_AIX32_ENV
1068 setlim(limcon, hard, limit)
1074 (void) getrlimit(limcon, &rlim);
1076 limit = limit * 1024;
1078 rlim.rlim_max = limit;
1079 else if (limit == RLIM_INFINITY && geteuid() != 0)
1080 rlim.rlim_cur = rlim.rlim_max;
1082 rlim.rlim_cur = limit;
1084 /* Must use ulimit() due to Posix constraints */
1085 if (limcon == RLIMIT_FSIZE) {
1086 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1087 printf("Can't %s%s limit\n",
1088 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1092 if (setrlimit(limcon, &rlim) < 0) {
1094 printf("Can't %s%s limit\n",
1095 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1105 * Print the specific limit out
1107 plim(name, lc, hard)
1115 printf("%s \t", name);
1116 (void) getrlimit(lc, &rlim);
1117 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1118 if (lim == RLIM_INFINITY)
1119 printf("unlimited");
1120 printf("%d %s", lim / 1024, "kbytes");
1127 int LWP_NoYieldSignal(event)
1130 return (LWP_INTERNALSIGNAL(event, 0));
1133 int LWP_SignalProcess(event)
1136 return (LWP_INTERNALSIGNAL(event, 1));
1141 #ifdef USE_SOLARIS_THREADS
1144 #include "pthread.h"
1149 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1151 PROCESS lwp_process_list; /* List of LWP initiated threads */
1153 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1155 #define CHECK check(__LINE__);
1157 typedef struct event {
1158 struct event *next; /* next in hash chain */
1159 char *event; /* lwp event: an address */
1160 int refcount; /* Is it in use? */
1161 pthread_cond_t cond; /* Currently associated condition variable */
1162 int seq; /* Sequence number: this is incremented
1163 by wakeup calls; wait will not return until
1167 #define HASHSIZE 127
1168 event_t *hashtable[HASHSIZE];/* Hash table for events */
1169 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1171 #if CMA_DEBUG || DEBUGF
1172 char *lwp_process_string() {
1173 static char id[200];
1175 LWP_CurrentProcess(&p);
1176 sprintf(id, "PID %x <%s>", p, p->name);
1181 void lwp_unimplemented(interface)
1184 fprintf(stderr, "cmalwp: %s is not currently implemented: program aborted\n",
1189 static lwpabort(interface)
1192 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1198 lwp_unimplemented("LWP_QWait");
1201 int LWP_QSignal(pid)
1203 lwp_unimplemented("LWP_QSignal");
1206 /* Allocate and initialize an LWP process handle. The associated pthread handle
1207 * must be added by the caller, and the structure threaded onto the LWP active
1208 * process list by lwp_thread_process */
1209 static PROCESS lwp_alloc_process(name, ep, arg)
1211 pthread_startroutine_t ep;
1215 assert(lp = (PROCESS) malloc(sizeof (*lp)));
1216 bzero((char *) lp, sizeof(*lp));
1220 sprintf(temp, "unnamed_process_%04d", ++procnum);
1221 assert(name = (char *)malloc(strlen(temp) + 1));
1230 /* Thread the LWP process descriptor *lp onto the lwp active process list
1231 * and associate a back pointer to the process descriptor from the associated
1233 static lwp_thread_process(lp)
1236 lp->next = lwp_process_list;
1237 lwp_process_list = lp;
1238 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1241 /* The top-level routine used as entry point to explicitly created LWP
1242 * processes. This completes a few details of process creation left
1243 * out by LWP_CreateProcess and calls the user-specified entry point */
1244 static int lwp_top_level(argp)
1245 pthread_addr_t argp;
1247 PROCESS lp = (PROCESS) argp;
1249 assert(!pthread_mutex_lock(&lwp_mutex));
1250 lwp_thread_process(lp);
1252 assert(!pthread_mutex_unlock(&lwp_mutex));
1253 /* Should cleanup state */
1256 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
1258 int stacksize, priority;
1264 pthread_attr_t attr;
1268 #ifndef LWP_NO_PRIORITIES
1269 if (!cmalwp_pri_inrange(priority))
1272 assert(!pthread_attr_create(&attr));
1273 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1275 assert(!pthread_attr_setstacksize(&attr, stacksize));
1277 (void) pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1278 (void) pthread_attr_setsched(&attr, SCHED_FIFO);
1279 #ifndef LWP_NO_PRIORITIES
1280 (void) pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1283 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep, (pthread_addr_t) parm);
1285 /* allow new thread to run if higher priority */
1286 assert(!pthread_mutex_unlock(&lwp_mutex));
1287 /* process is only added to active list after first time it runs (it adds itself) */
1288 status = pthread_create(&lp->handle,
1290 (pthread_startroutine_t) lwp_top_level,
1291 (pthread_addr_t) lp);
1292 assert(!pthread_attr_delete(&attr));
1293 assert (!pthread_mutex_lock(&lwp_mutex));
1302 PROCESS LWP_ActiveProcess() { /* returns pid of current process */
1304 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) &pid));
1308 int LWP_CurrentProcess(pid) /* get pid of current process */
1311 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1315 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
1318 lwp_unimplemented("LWP_DestroyProcess");
1321 int LWP_DispatchProcess() /* explicit voluntary preemption */
1323 assert(!pthread_mutex_unlock(&lwp_mutex));
1325 assert(!pthread_mutex_lock(&lwp_mutex));
1329 static int lwp_process_key_destructor() {}
1331 int LWP_InitializeProcessSupport(priority, pid)
1335 static int initialized = 0;
1346 #ifndef LWP_NO_PRIORITIES
1347 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1351 /* Create pthread key to associate LWP process descriptor with each
1352 LWP-created thread */
1353 assert(!pthread_keycreate(&lwp_process_key,
1354 (pthread_destructor_t) lwp_process_key_destructor));
1356 lp = lwp_alloc_process("main process", main, 0);
1357 lp->handle = pthread_self();
1358 lwp_thread_process(lp);
1359 #ifndef LWP_NO_PRIORITIES
1360 (void) pthread_setscheduler(pthread_self(),
1362 cmalwp_lwppri_to_cmapri(priority));
1365 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1366 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1372 int LWP_TerminateProcessSupport() /* terminate all LWP support */
1374 lwp_unimplemented("LWP_TerminateProcessSupport");
1377 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1378 static event_t *getevent(event)
1381 event_t *evp, *newp;
1384 hashcode = hash(event);
1385 evp = hashtable[hashcode];
1388 if (evp->event == event) {
1392 if (evp->refcount == 0)
1397 newp = (event_t *) malloc(sizeof (event_t));
1399 newp->next = hashtable[hashcode];
1400 hashtable[hashcode] = newp;
1401 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t)0)));
1404 newp->event = event;
1409 /* Release the specified event */
1410 #define relevent(evp) ((evp)->refcount--)
1412 int LWP_WaitProcess(event) /* wait on a single event */
1417 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1418 if (event == NULL) return LWP_EBADEVENT;
1419 ev = getevent(event);
1421 while (seq == ev->seq) {
1422 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1424 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1429 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
1433 lwp_unimplemented("LWP_MWaitProcess");
1436 int LWP_NoYieldSignal(event)
1440 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1441 if (event == NULL) return LWP_EBADEVENT;
1442 ev = getevent(event);
1443 if (ev->refcount > 1) {
1445 assert(pthread_cond_broadcast(&ev->cond) == 0);
1451 int LWP_SignalProcess(event)
1455 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1456 if (event == NULL) return LWP_EBADEVENT;
1457 ev = getevent(event);
1458 if (ev->refcount > 1) {
1460 assert(!pthread_mutex_unlock(&lwp_mutex));
1461 assert(!pthread_cond_broadcast(&ev->cond));
1463 assert(!pthread_mutex_lock(&lwp_mutex));
1469 int LWP_StackUsed(pid, maxa, used)
1473 lwp_unimplemented("LWP_StackUsed");
1476 LWP_NewRock(Tag, Value)
1478 char *Value; /* IN */
1480 lwp_unimplemented("LWP_NewRock");
1483 LWP_GetRock(Tag, Value)
1485 char **Value; /* OUT */
1487 lwp_unimplemented("LWP_GetRock");
1490 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
1494 lwp_unimplemented("LWP_GetProcessPriority");
1497 #endif /* USE_PTHREADS */