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 savecontext(Create_Process_Part2, &temp2->context,
346 stackptr+stacksize-sizeof(void *));
349 /* End of gross hack */
359 int LWP_CreateProcess2(ep, stacksize, priority, parm, name, pid)
361 int stacksize, priority;
369 #if defined(AFS_LWP_MINSTACKSIZE)
371 * on some systems (e.g. hpux), a minimum usable stack size has
374 if (stacksize < lwp_MinStackSize) {
375 stacksize = lwp_MinStackSize;
377 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
378 /* more stack size computations; keep track of for IOMGR */
379 if (lwp_MaxStackSeen < stacksize)
380 lwp_MaxStackSeen = stacksize;
382 Debug(0, ("Entered LWP_CreateProcess"))
383 /* Throw away all dead process control blocks */
386 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
391 if (stacksize < MINSTACK)
395 stacksize = 8 * ((stacksize+7) / 8);
397 stacksize = 4 * ((stacksize+3) / 4);
399 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
403 if (priority < 0 || priority >= MAX_PRIORITIES) {
407 Initialize_Stack(stackptr, stacksize);
408 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
409 insert(temp, &runnable[priority]);
411 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
413 /* Gross hack: beware! */
417 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
419 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-sizeof(void *));
421 /* End of gross hack */
431 int LWP_CurrentProcess(pid) /* returns pid of current process */
434 Debug(0, ("Entered Current_Process"))
442 #define LWPANCHOR (*lwp_init)
444 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
449 Debug(0, ("Entered Destroy_Process"))
451 if (lwp_cpptr != pid) {
452 Dispose_of_Dead_PCB(pid);
455 pid -> status = DESTROYED;
456 move(pid, &runnable[pid->priority], &blocked);
459 savecontext(Dispatcher, &(temp -> context),
460 &(LWPANCHOR.dsptchstack[MINFRAME]));
463 savecontext(Dispatcher, &(temp -> context),
464 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-8]));
466 savecontext(Dispatcher, &(temp -> context),
467 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-sizeof(void *)]));
476 int LWP_DispatchProcess() /* explicit voluntary preemption */
478 Debug(2, ("Entered Dispatch_Process"))
491 for (i=0; i<MAX_PRIORITIES; i++)
492 for_all_elts(x, runnable[i], {
493 printf("[Priority %d]\n", i);
496 for_all_elts(x, blocked, { Dump_One_Process(x); })
498 printf("***LWP: LWP support not initialized\n");
502 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
506 Debug(0, ("Entered Get_Process_Priority"))
508 *priority = pid -> priority;
514 int LWP_InitializeProcessSupport(priority, pid)
519 struct lwp_pcb dummy;
523 Debug(0, ("Entered LWP_InitializeProcessSupport"))
524 if (lwp_init != NULL) return LWP_SUCCESS;
526 /* Set up offset for stack checking -- do this as soon as possible */
527 stack_offset = (char *) &dummy.stack - (char *) &dummy;
529 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
530 for (i=0; i<MAX_PRIORITIES; i++) {
531 runnable[i].head = NULL;
532 runnable[i].count = 0;
536 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
537 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
538 if (lwp_init == NULL || temp == NULL)
539 Abort_LWP("Insufficient Storage to Initialize LWP Support");
540 LWPANCHOR.processcnt = 1;
541 LWPANCHOR.outerpid = temp;
542 LWPANCHOR.outersp = NULL;
543 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
544 insert(temp, &runnable[priority]);
545 savecontext(Dispatcher, &temp->context, NULL);
546 LWPANCHOR.outersp = temp -> context.topstack;
550 /* get minimum stack size from the environment. this allows the administrator
551 * to change the lwp stack dynamically without getting a new binary version.
553 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
554 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
556 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
557 AFS_LWP_MINSTACKSIZE : atoi(value));
562 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
566 Debug(2, ("Entered LWP_SignalProcess"))
569 rc = Internal_Signal(event);
570 if (yield) Set_LWP_RC();
576 int LWP_TerminateProcessSupport() /* terminate all LWP support */
580 Debug(0, ("Entered Terminate_Process_Support"))
581 if (lwp_init == NULL) return LWP_EINIT;
582 if (lwp_cpptr != LWPANCHOR.outerpid)
583 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
584 for (i=0; i<MAX_PRIORITIES; i++)
585 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
586 for_all_elts(cur, blocked, { Free_PCB(cur); })
592 int LWP_WaitProcess(event) /* wait on a single event */
597 Debug(2, ("Entered Wait_Process"))
598 if (event == NULL) return LWP_EBADEVENT;
601 return LWP_MwaitProcess(1, tempev);
604 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
608 register int ecount, i;
611 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
613 if (evlist == NULL) {
615 return LWP_EBADCOUNT;
618 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
622 return LWP_EBADCOUNT;
627 if (wcount>ecount || wcount<0) {
629 return LWP_EBADCOUNT;
631 if (ecount > lwp_cpptr->eventlistsize) {
633 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *));
634 lwp_cpptr->eventlistsize = ecount;
636 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
638 lwp_cpptr -> status = WAITING;
640 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
643 lwp_cpptr -> wakevent = 0;
644 lwp_cpptr -> waitcnt = wcount;
645 lwp_cpptr -> eventcnt = ecount;
655 int LWP_StackUsed(pid, maxa, used)
659 *maxa = pid -> stacksize;
660 *used = Stack_Used(pid->stack, *maxa);
667 * The following functions are strictly
668 * INTERNAL to the LWP support package.
671 static void Abort_LWP(msg)
674 struct lwp_context tempcontext;
676 Debug(0, ("Entered Abort_LWP"))
677 printf("***LWP: %s\n",msg);
678 printf("***LWP: Abort --- dumping PCBs ...\n");
682 if (LWPANCHOR.outersp == NULL)
685 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
688 static int Create_Process_Part2 () /* creates a context for the new process */
692 Debug(2, ("Entered Create_Process_Part2"))
693 temp = lwp_cpptr; /* Get current process id */
694 savecontext(Dispatcher, &temp->context, NULL);
695 (*temp->ep)(temp->parm);
696 LWP_DestroyProcess(temp);
699 static Delete_PCB(pid) /* remove a PCB from the process list */
700 register PROCESS pid;
702 Debug(4, ("Entered Delete_PCB"))
703 lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
705 : &runnable[pid->priority]));
706 LWPANCHOR.processcnt--;
710 static Dump_One_Process(pid)
715 printf("***LWP: Process Control Block at 0x%x\n", pid);
716 printf("***LWP: Name: %s\n", pid->name);
718 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
719 if (pid->blockflag) printf("BLOCKED and ");
720 switch (pid->status) {
721 case READY: printf("READY"); break;
722 case WAITING: printf("WAITING"); break;
723 case DESTROYED: printf("DESTROYED"); break;
724 default: printf("unknown");
727 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
728 pid->priority, pid->parm);
729 if (pid->stacksize != 0) {
730 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
731 pid->stacksize, pid->stack);
732 printf("***LWP: HWM stack usage: ");
733 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
736 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
737 if (pid->eventcnt > 0) {
738 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
739 printf("***LWP: Event id list:");
740 for (i=0;i<pid->eventcnt;i++)
741 printf(" 0x%x", pid->eventlist[i]);
745 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
749 static purge_dead_pcbs()
751 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
754 int LWP_TraceProcesses = 0;
756 static Dispatcher() /* Lightweight process dispatcher */
760 static int dispatch_count = 0;
762 if (LWP_TraceProcesses > 0) {
763 for (i=0; i<MAX_PRIORITIES; i++) {
764 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
765 for_all_elts(p, runnable[i], {
766 printf(" \"%s\"", p->name);
770 printf("[Blocked (%d):", blocked.count);
771 for_all_elts(p, blocked, {
772 printf(" \"%s\"", p->name);
778 /* Check for stack overflowif this lwp has a stack. Check for
779 the guard word at the front of the stack being damaged and
780 for the stack pointer being below the front of the stack.
781 WARNING! This code assumes that stacks grow downward. */
783 /* Fix this (stackcheck at other end of stack?) */
784 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
785 && (lwp_cpptr->stackcheck !=
786 *(afs_int32 *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
787 || lwp_cpptr->context.topstack >
788 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
790 if (lwp_cpptr && lwp_cpptr->stack &&
791 (lwp_cpptr->stackcheck != *(afs_int32 *)(lwp_cpptr->stack) ||
792 lwp_cpptr->context.topstack < lwp_cpptr->stack ||
793 lwp_cpptr->context.topstack > (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
795 printf("stackcheck = %u: stack = %u \n",
796 lwp_cpptr->stackcheck, *(afs_int32 *)lwp_cpptr->stack);
797 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
798 lwp_cpptr->context.topstack, lwp_cpptr->stack, lwp_cpptr->stacksize);
800 switch (lwp_overflowAction) {
809 lwp_overflowAction = LWP_SOQUIET;
814 /* Move head of current runnable queue forward if current LWP is still in it. */
815 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
816 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head -> next;
817 /* Find highest priority with runnable processes. */
818 for (i=MAX_PRIORITIES-1; i>=0; i--)
819 if (runnable[i].head != NULL) break;
821 if (i < 0) Abort_LWP("No READY processes");
824 if (LWP_TraceProcesses > 0)
825 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
827 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
828 lwp_cpptr = runnable[i].head;
830 returnto(&lwp_cpptr->context);
833 /* Complain of a stack overflow to stderr without using stdio. */
834 static void Overflow_Complain ()
838 char *msg1 = " LWP: stack overflow in process ";
841 currenttime = time(0);
842 timeStamp = ctime(¤ttime);
844 write (2, timeStamp, strlen(timeStamp));
846 write (2, msg1, strlen(msg1));
847 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
848 write (2, msg2, strlen(msg2));
851 static void Dispose_of_Dead_PCB (cur)
854 Debug(4, ("Entered Dispose_of_Dead_PCB"))
858 Internal_Signal(cur);
867 static void Free_PCB(pid)
870 Debug(4, ("Entered Free_PCB"))
871 if (pid -> stack != NULL) {
872 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
873 Stack_Used(pid->stack,pid->stacksize), pid))
876 if (pid->eventlist != NULL) free(pid->eventlist);
880 static void Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
883 int stacksize, priority;
889 Debug(4, ("Entered Initialize_PCB"))
891 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
892 temp -> name[31] = '\0';
893 temp -> status = READY;
894 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
895 temp -> eventlistsize = EVINITSIZE;
896 temp -> eventcnt = 0;
897 temp -> wakevent = 0;
899 temp -> blockflag = 0;
900 temp -> iomgrRequest = 0;
901 temp -> priority = priority;
902 temp -> index = lwp_nextindex++;
903 temp -> stack = stack;
904 temp -> stacksize = stacksize;
906 if (temp -> stack != NULL)
907 temp -> stackcheck = *(afs_int32 *) ((temp -> stack) + stacksize - 4);
909 if (temp -> stack != NULL)
910 temp -> stackcheck = *(afs_int32 *) (temp -> stack);
914 temp -> misc = NULL; /* currently unused */
917 temp -> lwp_rused = NULL;
918 temp -> level = 1; /* non-preemptable */
921 static int Internal_Signal(event)
922 register char *event;
924 int rc = LWP_ENOWAIT;
927 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
928 if (!lwp_init) return LWP_EINIT;
929 if (event == NULL) return LWP_EBADEVENT;
930 for_all_elts(temp, blocked, {
931 if (temp->status == WAITING)
932 for (i=0; i < temp->eventcnt; i++) {
933 if (temp -> eventlist[i] == event) {
934 temp -> eventlist[i] = NULL;
936 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
937 if (--temp->waitcnt == 0) {
938 temp -> status = READY;
939 temp -> wakevent = i+1;
940 move(temp, &blocked, &runnable[temp->priority]);
949 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
950 #define STACKMAGIC 0xBADBADBA
951 static afs_int32 Initialize_Stack(stackptr, stacksize)
957 Debug(4, ("Entered Initialize_Stack"))
958 if (lwp_stackUseEnabled)
959 for (i=0; i<stacksize; i++)
960 stackptr[i] = i &0xff;
963 *(afs_int32 *)(stackptr + stacksize - 4) = STACKMAGIC;
965 *(afs_int32 *)stackptr = STACKMAGIC;
969 static int Stack_Used(stackptr, stacksize)
970 register char *stackptr;
976 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
979 for (i = stacksize - 1; i >= 0 ; i--)
980 if ((unsigned char) stackptr[i] != (i & 0xff))
985 if (*(afs_int32 *) stackptr == STACKMAGIC)
988 for (i = 0; i < stacksize; i++)
989 if ((unsigned char) stackptr[i] != (i & 0xff))
990 return (stacksize - i);
997 LWP_NewRock(Tag, Value)
999 char *Value; /* IN */
1000 /* Finds a free rock and sets its value to Value.
1002 LWP_SUCCESS Rock did not exist and a new one was used
1003 LWP_EBADROCK Rock already exists.
1004 LWP_ENOROCKS All rocks are in use.
1006 From the above semantics, you can only set a rock value once. This is specifically
1007 to prevent multiple users of the LWP package from accidentally using the same Tag
1008 value and clobbering others. You can always use one level of indirection to obtain
1009 a rock whose contents can change.
1013 register struct rock *ra; /* rock array */
1015 ra = lwp_cpptr->lwp_rlist;
1017 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1018 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1020 if (lwp_cpptr->lwp_rused < MAXROCKS)
1022 ra[lwp_cpptr->lwp_rused].tag = Tag;
1023 ra[lwp_cpptr->lwp_rused].value = Value;
1024 lwp_cpptr->lwp_rused++;
1025 return(LWP_SUCCESS);
1027 else return(LWP_ENOROCKS);
1031 LWP_GetRock(Tag, Value)
1033 char **Value; /* OUT */
1035 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1037 LWP_SUCCESS if specified rock exists and Value has been filled
1038 LWP_EBADROCK rock specified does not exist
1042 register struct rock *ra;
1044 ra = lwp_cpptr->lwp_rlist;
1046 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1047 if (ra[i].tag == Tag)
1049 *Value = ra[i].value;
1050 return(LWP_SUCCESS);
1052 return(LWP_EBADROCK);
1056 #ifdef AFS_AIX32_ENV
1057 setlim(limcon, hard, limit)
1063 (void) getrlimit(limcon, &rlim);
1065 limit = limit * 1024;
1067 rlim.rlim_max = limit;
1068 else if (limit == RLIM_INFINITY && geteuid() != 0)
1069 rlim.rlim_cur = rlim.rlim_max;
1071 rlim.rlim_cur = limit;
1073 /* Must use ulimit() due to Posix constraints */
1074 if (limcon == RLIMIT_FSIZE) {
1075 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1076 printf("Can't %s%s limit\n",
1077 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1081 if (setrlimit(limcon, &rlim) < 0) {
1083 printf("Can't %s%s limit\n",
1084 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1094 * Print the specific limit out
1096 plim(name, lc, hard)
1104 printf("%s \t", name);
1105 (void) getrlimit(lc, &rlim);
1106 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1107 if (lim == RLIM_INFINITY)
1108 printf("unlimited");
1109 printf("%d %s", lim / 1024, "kbytes");
1116 int LWP_NoYieldSignal(event)
1119 return (LWP_INTERNALSIGNAL(event, 0));
1122 int LWP_SignalProcess(event)
1125 return (LWP_INTERNALSIGNAL(event, 1));
1130 #ifdef USE_SOLARIS_THREADS
1133 #include "pthread.h"
1138 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1140 PROCESS lwp_process_list; /* List of LWP initiated threads */
1142 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1144 #define CHECK check(__LINE__);
1146 typedef struct event {
1147 struct event *next; /* next in hash chain */
1148 char *event; /* lwp event: an address */
1149 int refcount; /* Is it in use? */
1150 pthread_cond_t cond; /* Currently associated condition variable */
1151 int seq; /* Sequence number: this is incremented
1152 by wakeup calls; wait will not return until
1156 #define HASHSIZE 127
1157 event_t *hashtable[HASHSIZE];/* Hash table for events */
1158 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1160 #if CMA_DEBUG || DEBUGF
1161 char *lwp_process_string() {
1162 static char id[200];
1164 LWP_CurrentProcess(&p);
1165 sprintf(id, "PID %x <%s>", p, p->name);
1170 void lwp_unimplemented(interface)
1173 fprintf(stderr, "cmalwp: %s is not currently implemented: program aborted\n",
1178 static lwpabort(interface)
1181 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1187 lwp_unimplemented("LWP_QWait");
1190 int LWP_QSignal(pid)
1192 lwp_unimplemented("LWP_QSignal");
1195 /* Allocate and initialize an LWP process handle. The associated pthread handle
1196 * must be added by the caller, and the structure threaded onto the LWP active
1197 * process list by lwp_thread_process */
1198 static PROCESS lwp_alloc_process(name, ep, arg)
1200 pthread_startroutine_t ep;
1204 assert(lp = (PROCESS) malloc(sizeof (*lp)));
1205 bzero((char *) lp, sizeof(*lp));
1209 sprintf(temp, "unnamed_process_%04d", ++procnum);
1210 assert(name = (char *)malloc(strlen(temp) + 1));
1219 /* Thread the LWP process descriptor *lp onto the lwp active process list
1220 * and associate a back pointer to the process descriptor from the associated
1222 static lwp_thread_process(lp)
1225 lp->next = lwp_process_list;
1226 lwp_process_list = lp;
1227 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1230 /* The top-level routine used as entry point to explicitly created LWP
1231 * processes. This completes a few details of process creation left
1232 * out by LWP_CreateProcess and calls the user-specified entry point */
1233 static int lwp_top_level(argp)
1234 pthread_addr_t argp;
1236 PROCESS lp = (PROCESS) argp;
1238 assert(!pthread_mutex_lock(&lwp_mutex));
1239 lwp_thread_process(lp);
1241 assert(!pthread_mutex_unlock(&lwp_mutex));
1242 /* Should cleanup state */
1245 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
1247 int stacksize, priority;
1253 pthread_attr_t attr;
1257 #ifndef LWP_NO_PRIORITIES
1258 if (!cmalwp_pri_inrange(priority))
1261 assert(!pthread_attr_create(&attr));
1262 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1264 assert(!pthread_attr_setstacksize(&attr, stacksize));
1266 (void) pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1267 (void) pthread_attr_setsched(&attr, SCHED_FIFO);
1268 #ifndef LWP_NO_PRIORITIES
1269 (void) pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1272 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep, (pthread_addr_t) parm);
1274 /* allow new thread to run if higher priority */
1275 assert(!pthread_mutex_unlock(&lwp_mutex));
1276 /* process is only added to active list after first time it runs (it adds itself) */
1277 status = pthread_create(&lp->handle,
1279 (pthread_startroutine_t) lwp_top_level,
1280 (pthread_addr_t) lp);
1281 assert(!pthread_attr_delete(&attr));
1282 assert (!pthread_mutex_lock(&lwp_mutex));
1291 PROCESS LWP_ActiveProcess() { /* returns pid of current process */
1293 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) &pid));
1297 int LWP_CurrentProcess(pid) /* get pid of current process */
1300 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1304 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
1307 lwp_unimplemented("LWP_DestroyProcess");
1310 int LWP_DispatchProcess() /* explicit voluntary preemption */
1312 assert(!pthread_mutex_unlock(&lwp_mutex));
1314 assert(!pthread_mutex_lock(&lwp_mutex));
1318 static int lwp_process_key_destructor() {}
1320 int LWP_InitializeProcessSupport(priority, pid)
1324 static int initialized = 0;
1335 #ifndef LWP_NO_PRIORITIES
1336 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1340 /* Create pthread key to associate LWP process descriptor with each
1341 LWP-created thread */
1342 assert(!pthread_keycreate(&lwp_process_key,
1343 (pthread_destructor_t) lwp_process_key_destructor));
1345 lp = lwp_alloc_process("main process", main, 0);
1346 lp->handle = pthread_self();
1347 lwp_thread_process(lp);
1348 #ifndef LWP_NO_PRIORITIES
1349 (void) pthread_setscheduler(pthread_self(),
1351 cmalwp_lwppri_to_cmapri(priority));
1354 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1355 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1361 int LWP_TerminateProcessSupport() /* terminate all LWP support */
1363 lwp_unimplemented("LWP_TerminateProcessSupport");
1366 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1367 static event_t *getevent(event)
1370 event_t *evp, *newp;
1373 hashcode = hash(event);
1374 evp = hashtable[hashcode];
1377 if (evp->event == event) {
1381 if (evp->refcount == 0)
1386 newp = (event_t *) malloc(sizeof (event_t));
1388 newp->next = hashtable[hashcode];
1389 hashtable[hashcode] = newp;
1390 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t)0)));
1393 newp->event = event;
1398 /* Release the specified event */
1399 #define relevent(evp) ((evp)->refcount--)
1401 int LWP_WaitProcess(event) /* wait on a single event */
1406 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1407 if (event == NULL) return LWP_EBADEVENT;
1408 ev = getevent(event);
1410 while (seq == ev->seq) {
1411 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1413 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1418 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
1422 lwp_unimplemented("LWP_MWaitProcess");
1425 int LWP_NoYieldSignal(event)
1429 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1430 if (event == NULL) return LWP_EBADEVENT;
1431 ev = getevent(event);
1432 if (ev->refcount > 1) {
1434 assert(pthread_cond_broadcast(&ev->cond) == 0);
1440 int LWP_SignalProcess(event)
1444 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1445 if (event == NULL) return LWP_EBADEVENT;
1446 ev = getevent(event);
1447 if (ev->refcount > 1) {
1449 assert(!pthread_mutex_unlock(&lwp_mutex));
1450 assert(!pthread_cond_broadcast(&ev->cond));
1452 assert(!pthread_mutex_lock(&lwp_mutex));
1458 int LWP_StackUsed(pid, maxa, used)
1462 lwp_unimplemented("LWP_StackUsed");
1465 LWP_NewRock(Tag, Value)
1467 char *Value; /* IN */
1469 lwp_unimplemented("LWP_NewRock");
1472 LWP_GetRock(Tag, Value)
1474 char **Value; /* OUT */
1476 lwp_unimplemented("LWP_GetRock");
1479 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
1483 lwp_unimplemented("LWP_GetProcessPriority");
1486 #endif /* USE_PTHREADS */