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 \*******************************************************************/
17 #include <afsconfig.h>
18 #include <afs/param.h>
26 /* allocate externs here */
31 #include <sys/errno.h>
38 extern char* getenv();
41 #if !defined(USE_PTHREADS) && !defined(USE_SOLARIS_THREADS)
44 extern void *malloc(int size);
45 extern void *realloc(void *ptr, int size);
47 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
48 extern int PRE_Block; /* from preempt.c */
50 extern char PRE_Block; /* from preempt.c */
61 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
78 #define Debug(level, msg)\
79 if (lwp_debug && lwp_debug >= level) {\
80 printf("***LWP (0x%x): ", lwp_cpptr);\
86 #define Debug(level, msg)
90 static int Dispatcher();
91 static int Create_Process_Part2();
92 static int Exit_LWP();
93 static afs_int32 Initialize_Stack();
94 static int Stack_Used();
95 char (*RC_to_ASCII());
97 static void Abort_LWP();
98 static void Overflow_Complain();
99 static void Initialize_PCB();
100 static void Dispose_of_Dead_PCB();
101 static void Free_PCB();
102 static int Internal_Signal();
103 static purge_dead_pcbs();
105 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
110 } runnable[MAX_PRIORITIES], blocked;
111 /* 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. */
113 /* Offset of stack field within pcb -- used by stack checking stuff */
116 /* special user-tweakable option for AIX */
117 int lwp_MaxStackSize = 32768;
119 /* biggest LWP stack created so far */
120 int lwp_MaxStackSeen = 0;
122 /* Stack checking action */
123 int lwp_overflowAction = LWP_SOABORT;
125 /* Controls stack size counting. */
126 int lwp_stackUseEnabled = TRUE; /* pay the price */
130 /* Minimum stack size */
131 int lwp_MinStackSize=0;
133 static int lwp_remove(p, q)
135 register struct QUEUE *q;
137 /* Special test for only element on queue */
141 /* Not only element, do normal remove */
142 p -> next -> prev = p -> prev;
143 p -> prev -> next = p -> next;
145 /* See if head pointing to this element */
146 if (q->head == p) q -> head = p -> next;
148 p -> next = p -> prev = NULL;
152 static int insert(p, q)
154 register struct QUEUE *q;
156 if (q->head == NULL) { /* Queue is empty */
158 p -> next = p -> prev = p;
159 } else { /* Regular insert */
160 p -> prev = q -> head -> prev;
161 q -> head -> prev -> next = p;
162 q -> head -> prev = p;
163 p -> next = q -> head;
169 static int move(p, from, to)
171 struct QUEUE *from, *to;
181 #define for_all_elts(var, q, body)\
183 register PROCESS var, _NEXT_;\
185 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
186 _NEXT_ = var -> next;\
192 /*****************************************************************************\
194 * Following section documents the Assembler interfaces used by LWP code *
196 \*****************************************************************************/
199 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
201 Stub for Assembler routine that will
202 save the current SP value in the passed
203 context savearea and call the function
204 whose entry point is in ep. If the sp
205 parameter is NULL, the current stack is
206 used, otherwise sp becomes the new stack
209 returnto(struct lwp_context *savearea);
211 Stub for Assembler routine that will
212 restore context from a passed savearea
213 and return to the restored C frame.
217 /* Macro to force a re-schedule. Strange name is historical */
218 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
220 static struct lwp_ctl *lwp_init = 0;
223 {register PROCESS tp;
224 (tp=lwp_cpptr) -> status = QWAITING;
225 lwp_remove(tp, &runnable[tp->priority]);
231 register PROCESS pid; {
232 if (pid->status == QWAITING) {
234 insert(pid, &runnable[pid->priority]);
237 else return LWP_ENOWAIT;
241 char *reserveFromStack(size)
242 register afs_int32 size;
250 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
252 int stacksize, priority;
259 static char *stackptr = 0;
264 #if defined(AFS_LWP_MINSTACKSIZE)
266 * on some systems (e.g. hpux), a minimum usable stack size has
269 if (stacksize < lwp_MinStackSize) {
270 stacksize = lwp_MinStackSize;
272 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
273 /* more stack size computations; keep track of for IOMGR */
274 if (lwp_MaxStackSeen < stacksize)
275 lwp_MaxStackSeen = stacksize;
277 Debug(0, ("Entered LWP_CreateProcess"))
278 /* Throw away all dead process control blocks */
281 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
286 if (stacksize < MINSTACK)
289 stacksize = STACK_ALIGN * ((stacksize+STACK_ALIGN-1) / STACK_ALIGN);
293 * The following signal action for AIX is necessary so that in case of a
294 * crash (i.e. core is generated) we can include the user's data section
295 * in the core dump. Unfortunately, by default, only a partial core is
296 * generated which, in many cases, isn't too useful.
298 * We also do it here in case the main program forgets to do it.
300 struct sigaction nsa;
301 extern uid_t geteuid();
303 sigemptyset(&nsa.sa_mask);
304 nsa.sa_handler = SIG_DFL;
305 nsa.sa_flags = SA_FULLDUMP;
306 sigaction(SIGABRT, &nsa, NULL);
307 sigaction(SIGSEGV, &nsa, NULL);
310 * First we need to increase the default resource limits,
311 * if necessary, so that we can guarantee that we have the
312 * resources to create the core file, but we can't always
313 * do it as an ordinary user.
316 /* vos dump causes problems */
317 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
318 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
319 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
322 * Now reserve in one scoop all the stack space that will be used
323 * by the particular application's main (i.e. non-lwp) body. This
324 * is plenty space for any of our applications.
326 stackptr = reserveFromStack(lwp_MaxStackSize);
328 stackptr -= stacksize;
330 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
334 /* Round stack pointer to byte boundary */
335 stackptr = (char *)(8 * (((long)stackptr+7) / 8));
337 if (priority < 0 || priority >= MAX_PRIORITIES) {
341 Initialize_Stack(stackptr, stacksize);
342 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
343 insert(temp, &runnable[priority]);
345 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
347 /* Gross hack: beware! */
351 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
353 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_PARISC_LINUX24_ENV)
354 /* Need to have the sp on an 8-byte boundary for storing doubles. */
355 savecontext(Create_Process_Part2, &temp2->context,
356 stackptr+stacksize-16); /* 16 = 2 * jmp_buf_type*/
358 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
359 savecontext(Create_Process_Part2, &temp2->context,
360 stackptr+stacksize-0x40); /* lomgjmp does something
363 #if defined(AFS_S390_LINUX20_ENV)
364 savecontext(Create_Process_Part2, &temp2->context,
365 stackptr+stacksize-MINFRAME);
366 #else /* !AFS_S390_LINUX20_ENV */
367 savecontext(Create_Process_Part2, &temp2->context,
368 stackptr+stacksize-sizeof(void *));
369 #endif /* AFS_S390_LINUX20_ENV */
370 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
371 #endif /* AFS_SGI62_ENV */
373 /* End of gross hack */
383 int LWP_CreateProcess2(ep, stacksize, priority, parm, name, pid)
385 int stacksize, priority;
393 #if defined(AFS_LWP_MINSTACKSIZE)
395 * on some systems (e.g. hpux), a minimum usable stack size has
398 if (stacksize < lwp_MinStackSize) {
399 stacksize = lwp_MinStackSize;
401 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
402 /* more stack size computations; keep track of for IOMGR */
403 if (lwp_MaxStackSeen < stacksize)
404 lwp_MaxStackSeen = stacksize;
406 Debug(0, ("Entered LWP_CreateProcess"))
407 /* Throw away all dead process control blocks */
410 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
415 if (stacksize < MINSTACK)
418 stacksize = STACK_ALIGN * ((stacksize+STACK_ALIGN-1) / STACK_ALIGN);
419 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
423 if (priority < 0 || priority >= MAX_PRIORITIES) {
427 Initialize_Stack(stackptr, stacksize);
428 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
429 insert(temp, &runnable[priority]);
431 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
433 /* Gross hack: beware! */
437 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
439 #if defined(AFS_S390_LINUX20_ENV)
440 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-MINFRAME);
442 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-sizeof(void *));
445 /* End of gross hack */
455 int LWP_CurrentProcess(pid) /* returns pid of current process */
458 Debug(0, ("Entered Current_Process"))
466 PROCESS LWP_ThreadId()
468 Debug(0, ("Entered ThreadId"))
475 #define LWPANCHOR (*lwp_init)
477 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
482 Debug(0, ("Entered Destroy_Process"))
484 if (lwp_cpptr != pid) {
485 Dispose_of_Dead_PCB(pid);
488 pid -> status = DESTROYED;
489 move(pid, &runnable[pid->priority], &blocked);
492 savecontext(Dispatcher, &(temp -> context),
493 &(LWPANCHOR.dsptchstack[MINFRAME]));
495 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_PARISC_LINUX24_ENV)
496 savecontext(Dispatcher, &(temp -> context),
497 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-8]));
499 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
500 savecontext(Dispatcher, &(temp -> context),
501 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-0x40]));
503 #if defined(AFS_S390_LINUX20_ENV)
504 savecontext(Dispatcher, &(temp -> context),
505 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-MINFRAME]));
507 savecontext(Dispatcher, &(temp -> context),
508 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-sizeof(void *)]));
519 int LWP_DispatchProcess() /* explicit voluntary preemption */
521 Debug(2, ("Entered Dispatch_Process"))
534 for (i=0; i<MAX_PRIORITIES; i++)
535 for_all_elts(x, runnable[i], {
536 printf("[Priority %d]\n", i);
539 for_all_elts(x, blocked, { Dump_One_Process(x); })
541 printf("***LWP: LWP support not initialized\n");
546 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
550 Debug(0, ("Entered Get_Process_Priority"))
552 *priority = pid -> priority;
558 int LWP_InitializeProcessSupport(priority, pid)
563 struct lwp_pcb dummy;
567 Debug(0, ("Entered LWP_InitializeProcessSupport"))
568 if (lwp_init != NULL) return LWP_SUCCESS;
570 /* Set up offset for stack checking -- do this as soon as possible */
571 stack_offset = (char *) &dummy.stack - (char *) &dummy;
573 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
574 for (i=0; i<MAX_PRIORITIES; i++) {
575 runnable[i].head = NULL;
576 runnable[i].count = 0;
580 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
581 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
582 if (lwp_init == NULL || temp == NULL)
583 Abort_LWP("Insufficient Storage to Initialize LWP Support");
584 LWPANCHOR.processcnt = 1;
585 LWPANCHOR.outerpid = temp;
586 LWPANCHOR.outersp = NULL;
587 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
588 insert(temp, &runnable[priority]);
589 savecontext(Dispatcher, &temp->context, NULL);
590 LWPANCHOR.outersp = temp -> context.topstack;
594 /* get minimum stack size from the environment. this allows the administrator
595 * to change the lwp stack dynamically without getting a new binary version.
597 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
598 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
600 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
601 AFS_LWP_MINSTACKSIZE : atoi(value));
606 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
610 Debug(2, ("Entered LWP_SignalProcess"))
613 rc = Internal_Signal(event);
614 if (yield) Set_LWP_RC();
620 int LWP_TerminateProcessSupport() /* terminate all LWP support */
624 Debug(0, ("Entered Terminate_Process_Support"))
625 if (lwp_init == NULL) return LWP_EINIT;
626 if (lwp_cpptr != LWPANCHOR.outerpid)
627 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
628 for (i=0; i<MAX_PRIORITIES; i++)
629 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
630 for_all_elts(cur, blocked, { Free_PCB(cur); })
636 int LWP_WaitProcess(event) /* wait on a single event */
641 Debug(2, ("Entered Wait_Process"))
642 if (event == NULL) return LWP_EBADEVENT;
645 return LWP_MwaitProcess(1, tempev);
648 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
652 register int ecount, i;
655 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
657 if (evlist == NULL) {
659 return LWP_EBADCOUNT;
662 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
666 return LWP_EBADCOUNT;
671 if (wcount>ecount || wcount<0) {
673 return LWP_EBADCOUNT;
675 if (ecount > lwp_cpptr->eventlistsize) {
677 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *));
678 lwp_cpptr->eventlistsize = ecount;
680 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
682 lwp_cpptr -> status = WAITING;
684 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
687 lwp_cpptr -> wakevent = 0;
688 lwp_cpptr -> waitcnt = wcount;
689 lwp_cpptr -> eventcnt = ecount;
699 int LWP_StackUsed(pid, maxa, used)
703 *maxa = pid -> stacksize;
704 *used = Stack_Used(pid->stack, *maxa);
711 * The following functions are strictly
712 * INTERNAL to the LWP support package.
715 static void Abort_LWP(msg)
718 struct lwp_context tempcontext;
720 Debug(0, ("Entered Abort_LWP"))
721 printf("***LWP: %s\n",msg);
722 printf("***LWP: Abort --- dumping PCBs ...\n");
726 if (LWPANCHOR.outersp == NULL)
729 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
733 static int Create_Process_Part2 () /* creates a context for the new process */
737 Debug(2, ("Entered Create_Process_Part2"))
738 temp = lwp_cpptr; /* Get current process id */
739 savecontext(Dispatcher, &temp->context, NULL);
740 (*temp->ep)(temp->parm);
741 LWP_DestroyProcess(temp);
745 static int Delete_PCB(pid) /* remove a PCB from the process list */
746 register PROCESS pid;
748 Debug(4, ("Entered Delete_PCB"))
749 lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
751 : &runnable[pid->priority]));
752 LWPANCHOR.processcnt--;
757 static int Dump_One_Process(pid)
762 printf("***LWP: Process Control Block at 0x%x\n", pid);
763 printf("***LWP: Name: %s\n", pid->name);
765 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
766 if (pid->blockflag) printf("BLOCKED and ");
767 switch (pid->status) {
768 case READY: printf("READY"); break;
769 case WAITING: printf("WAITING"); break;
770 case DESTROYED: printf("DESTROYED"); break;
771 default: printf("unknown");
774 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
775 pid->priority, pid->parm);
776 if (pid->stacksize != 0) {
777 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
778 pid->stacksize, pid->stack);
779 printf("***LWP: HWM stack usage: ");
780 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
783 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
784 if (pid->eventcnt > 0) {
785 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
786 printf("***LWP: Event id list:");
787 for (i=0;i<pid->eventcnt;i++)
788 printf(" 0x%x", pid->eventlist[i]);
792 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
797 static int purge_dead_pcbs()
799 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
803 int LWP_TraceProcesses = 0;
805 static int Dispatcher() /* Lightweight process dispatcher */
809 static int dispatch_count = 0;
811 if (LWP_TraceProcesses > 0) {
812 for (i=0; i<MAX_PRIORITIES; i++) {
813 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
814 for_all_elts(p, runnable[i], {
815 printf(" \"%s\"", p->name);
819 printf("[Blocked (%d):", blocked.count);
820 for_all_elts(p, blocked, {
821 printf(" \"%s\"", p->name);
827 /* Check for stack overflowif this lwp has a stack. Check for
828 the guard word at the front of the stack being damaged and
829 for the stack pointer being below the front of the stack.
830 WARNING! This code assumes that stacks grow downward. */
832 /* Fix this (stackcheck at other end of stack?) */
833 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
834 && (lwp_cpptr->stackcheck !=
835 *(afs_int32 *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
836 || lwp_cpptr->context.topstack >
837 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
839 if (lwp_cpptr && lwp_cpptr->stack &&
840 (lwp_cpptr->stackcheck != *(afs_int32 *)(lwp_cpptr->stack) ||
841 lwp_cpptr->context.topstack < lwp_cpptr->stack ||
842 lwp_cpptr->context.topstack > (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
844 printf("stackcheck = %u: stack = %u \n",
845 lwp_cpptr->stackcheck, *(afs_int32 *)lwp_cpptr->stack);
846 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
847 lwp_cpptr->context.topstack, lwp_cpptr->stack, lwp_cpptr->stacksize);
849 switch (lwp_overflowAction) {
858 lwp_overflowAction = LWP_SOQUIET;
863 /* Move head of current runnable queue forward if current LWP is still in it. */
864 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
865 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head -> next;
866 /* Find highest priority with runnable processes. */
867 for (i=MAX_PRIORITIES-1; i>=0; i--)
868 if (runnable[i].head != NULL) break;
870 if (i < 0) Abort_LWP("No READY processes");
873 if (LWP_TraceProcesses > 0)
874 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
876 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
877 lwp_cpptr = runnable[i].head;
879 returnto(&lwp_cpptr->context);
882 /* Complain of a stack overflow to stderr without using stdio. */
883 static void Overflow_Complain ()
887 char *msg1 = " LWP: stack overflow in process ";
890 currenttime = time(0);
891 timeStamp = ctime(¤ttime);
893 write (2, timeStamp, strlen(timeStamp));
895 write (2, msg1, strlen(msg1));
896 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
897 write (2, msg2, strlen(msg2));
900 static void Dispose_of_Dead_PCB (cur)
903 Debug(4, ("Entered Dispose_of_Dead_PCB"))
907 Internal_Signal(cur);
911 static int Exit_LWP()
916 static void Free_PCB(pid)
919 Debug(4, ("Entered Free_PCB"))
920 if (pid -> stack != NULL) {
921 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
922 Stack_Used(pid->stack,pid->stacksize), pid))
925 if (pid->eventlist != NULL) free(pid->eventlist);
929 static void Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
932 int stacksize, priority;
938 Debug(4, ("Entered Initialize_PCB"))
940 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
941 temp -> name[31] = '\0';
942 temp -> status = READY;
943 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
944 temp -> eventlistsize = EVINITSIZE;
945 temp -> eventcnt = 0;
946 temp -> wakevent = 0;
948 temp -> blockflag = 0;
949 temp -> iomgrRequest = 0;
950 temp -> priority = priority;
951 temp -> index = lwp_nextindex++;
952 temp -> stack = stack;
953 temp -> stacksize = stacksize;
955 if (temp -> stack != NULL)
956 temp -> stackcheck = *(afs_int32 *) ((temp -> stack) + stacksize - 4);
958 if (temp -> stack != NULL)
959 temp -> stackcheck = *(afs_int32 *) (temp -> stack);
963 temp -> misc = NULL; /* currently unused */
966 temp -> lwp_rused = 0;
967 temp -> level = 1; /* non-preemptable */
970 static int Internal_Signal(event)
971 register char *event;
973 int rc = LWP_ENOWAIT;
976 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
977 if (!lwp_init) return LWP_EINIT;
978 if (event == NULL) return LWP_EBADEVENT;
979 for_all_elts(temp, blocked, {
980 if (temp->status == WAITING)
981 for (i=0; i < temp->eventcnt; i++) {
982 if (temp -> eventlist[i] == event) {
983 temp -> eventlist[i] = NULL;
985 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
986 if (--temp->waitcnt == 0) {
987 temp -> status = READY;
988 temp -> wakevent = i+1;
989 move(temp, &blocked, &runnable[temp->priority]);
998 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
999 #define STACKMAGIC 0xBADBADBA
1000 static afs_int32 Initialize_Stack(stackptr, stacksize)
1006 Debug(4, ("Entered Initialize_Stack"))
1007 if (lwp_stackUseEnabled)
1008 for (i=0; i<stacksize; i++)
1009 stackptr[i] = i &0xff;
1012 *(afs_int32 *)(stackptr + stacksize - 4) = STACKMAGIC;
1014 *(afs_int32 *)stackptr = STACKMAGIC;
1019 static int Stack_Used(stackptr, stacksize)
1020 register char *stackptr;
1026 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1029 for (i = stacksize - 1; i >= 0 ; i--)
1030 if ((unsigned char) stackptr[i] != (i & 0xff))
1035 if (*(afs_int32 *) stackptr == STACKMAGIC)
1038 for (i = 0; i < stacksize; i++)
1039 if ((unsigned char) stackptr[i] != (i & 0xff))
1040 return (stacksize - i);
1047 LWP_NewRock(Tag, Value)
1049 char *Value; /* IN */
1050 /* Finds a free rock and sets its value to Value.
1052 LWP_SUCCESS Rock did not exist and a new one was used
1053 LWP_EBADROCK Rock already exists.
1054 LWP_ENOROCKS All rocks are in use.
1056 From the above semantics, you can only set a rock value once. This is specifically
1057 to prevent multiple users of the LWP package from accidentally using the same Tag
1058 value and clobbering others. You can always use one level of indirection to obtain
1059 a rock whose contents can change.
1063 register struct rock *ra; /* rock array */
1065 ra = lwp_cpptr->lwp_rlist;
1067 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1068 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1070 if (lwp_cpptr->lwp_rused < MAXROCKS)
1072 ra[lwp_cpptr->lwp_rused].tag = Tag;
1073 ra[lwp_cpptr->lwp_rused].value = Value;
1074 lwp_cpptr->lwp_rused++;
1075 return(LWP_SUCCESS);
1077 else return(LWP_ENOROCKS);
1081 LWP_GetRock(Tag, Value)
1083 char **Value; /* OUT */
1085 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1087 LWP_SUCCESS if specified rock exists and Value has been filled
1088 LWP_EBADROCK rock specified does not exist
1092 register struct rock *ra;
1094 ra = lwp_cpptr->lwp_rlist;
1096 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1097 if (ra[i].tag == Tag)
1099 *Value = ra[i].value;
1100 return(LWP_SUCCESS);
1102 return(LWP_EBADROCK);
1106 #ifdef AFS_AIX32_ENV
1107 setlim(limcon, hard, limit)
1113 (void) getrlimit(limcon, &rlim);
1115 limit = limit * 1024;
1117 rlim.rlim_max = limit;
1118 else if (limit == RLIM_INFINITY && geteuid() != 0)
1119 rlim.rlim_cur = rlim.rlim_max;
1121 rlim.rlim_cur = limit;
1123 /* Must use ulimit() due to Posix constraints */
1124 if (limcon == RLIMIT_FSIZE) {
1125 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1126 printf("Can't %s%s limit\n",
1127 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1131 if (setrlimit(limcon, &rlim) < 0) {
1133 printf("Can't %s%s limit\n",
1134 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1144 * Print the specific limit out
1146 plim(name, lc, hard)
1154 printf("%s \t", name);
1155 (void) getrlimit(lc, &rlim);
1156 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1157 if (lim == RLIM_INFINITY)
1158 printf("unlimited");
1159 printf("%d %s", lim / 1024, "kbytes");
1166 int LWP_NoYieldSignal(event)
1169 return (LWP_INTERNALSIGNAL(event, 0));
1172 int LWP_SignalProcess(event)
1175 return (LWP_INTERNALSIGNAL(event, 1));
1180 #ifdef USE_SOLARIS_THREADS
1183 #include "pthread.h"
1188 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1190 PROCESS lwp_process_list; /* List of LWP initiated threads */
1192 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1194 #define CHECK check(__LINE__);
1196 typedef struct event {
1197 struct event *next; /* next in hash chain */
1198 char *event; /* lwp event: an address */
1199 int refcount; /* Is it in use? */
1200 pthread_cond_t cond; /* Currently associated condition variable */
1201 int seq; /* Sequence number: this is incremented
1202 by wakeup calls; wait will not return until
1206 #define HASHSIZE 127
1207 event_t *hashtable[HASHSIZE];/* Hash table for events */
1208 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1210 #if CMA_DEBUG || DEBUGF
1211 char *lwp_process_string() {
1212 static char id[200];
1214 LWP_CurrentProcess(&p);
1215 sprintf(id, "PID %x <%s>", p, p->name);
1220 void lwp_unimplemented(interface)
1223 fprintf(stderr, "cmalwp: %s is not currently implemented: program aborted\n",
1228 static lwpabort(interface)
1231 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1237 lwp_unimplemented("LWP_QWait");
1240 int LWP_QSignal(pid)
1242 lwp_unimplemented("LWP_QSignal");
1245 /* Allocate and initialize an LWP process handle. The associated pthread handle
1246 * must be added by the caller, and the structure threaded onto the LWP active
1247 * process list by lwp_thread_process */
1248 static PROCESS lwp_alloc_process(name, ep, arg)
1250 pthread_startroutine_t ep;
1254 assert(lp = (PROCESS) malloc(sizeof (*lp)));
1255 memset((char *) lp, 0, sizeof(*lp));
1259 sprintf(temp, "unnamed_process_%04d", ++procnum);
1260 assert(name = (char *)malloc(strlen(temp) + 1));
1269 /* Thread the LWP process descriptor *lp onto the lwp active process list
1270 * and associate a back pointer to the process descriptor from the associated
1272 static lwp_thread_process(lp)
1275 lp->next = lwp_process_list;
1276 lwp_process_list = lp;
1277 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1280 /* The top-level routine used as entry point to explicitly created LWP
1281 * processes. This completes a few details of process creation left
1282 * out by LWP_CreateProcess and calls the user-specified entry point */
1283 static int lwp_top_level(argp)
1284 pthread_addr_t argp;
1286 PROCESS lp = (PROCESS) argp;
1288 assert(!pthread_mutex_lock(&lwp_mutex));
1289 lwp_thread_process(lp);
1291 assert(!pthread_mutex_unlock(&lwp_mutex));
1292 /* Should cleanup state */
1295 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
1297 int stacksize, priority;
1303 pthread_attr_t attr;
1307 #ifndef LWP_NO_PRIORITIES
1308 if (!cmalwp_pri_inrange(priority))
1311 assert(!pthread_attr_create(&attr));
1312 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1314 assert(!pthread_attr_setstacksize(&attr, stacksize));
1316 (void) pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1317 (void) pthread_attr_setsched(&attr, SCHED_FIFO);
1318 #ifndef LWP_NO_PRIORITIES
1319 (void) pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1322 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep, (pthread_addr_t) parm);
1324 /* allow new thread to run if higher priority */
1325 assert(!pthread_mutex_unlock(&lwp_mutex));
1326 /* process is only added to active list after first time it runs (it adds itself) */
1327 status = pthread_create(&lp->handle,
1329 (pthread_startroutine_t) lwp_top_level,
1330 (pthread_addr_t) lp);
1331 assert(!pthread_attr_delete(&attr));
1332 assert (!pthread_mutex_lock(&lwp_mutex));
1341 PROCESS LWP_ActiveProcess() { /* returns pid of current process */
1343 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) &pid));
1347 int LWP_CurrentProcess(pid) /* get pid of current process */
1350 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1354 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
1357 lwp_unimplemented("LWP_DestroyProcess");
1360 int LWP_DispatchProcess() /* explicit voluntary preemption */
1362 assert(!pthread_mutex_unlock(&lwp_mutex));
1364 assert(!pthread_mutex_lock(&lwp_mutex));
1368 static int lwp_process_key_destructor() {}
1370 int LWP_InitializeProcessSupport(priority, pid)
1374 static int initialized = 0;
1385 #ifndef LWP_NO_PRIORITIES
1386 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1390 /* Create pthread key to associate LWP process descriptor with each
1391 LWP-created thread */
1392 assert(!pthread_keycreate(&lwp_process_key,
1393 (pthread_destructor_t) lwp_process_key_destructor));
1395 lp = lwp_alloc_process("main process", main, 0);
1396 lp->handle = pthread_self();
1397 lwp_thread_process(lp);
1398 #ifndef LWP_NO_PRIORITIES
1399 (void) pthread_setscheduler(pthread_self(),
1401 cmalwp_lwppri_to_cmapri(priority));
1404 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1405 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1411 int LWP_TerminateProcessSupport() /* terminate all LWP support */
1413 lwp_unimplemented("LWP_TerminateProcessSupport");
1416 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1417 static event_t *getevent(event)
1420 event_t *evp, *newp;
1423 hashcode = hash(event);
1424 evp = hashtable[hashcode];
1427 if (evp->event == event) {
1431 if (evp->refcount == 0)
1436 newp = (event_t *) malloc(sizeof (event_t));
1438 newp->next = hashtable[hashcode];
1439 hashtable[hashcode] = newp;
1440 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t)0)));
1443 newp->event = event;
1448 /* Release the specified event */
1449 #define relevent(evp) ((evp)->refcount--)
1451 int LWP_WaitProcess(event) /* wait on a single event */
1456 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1457 if (event == NULL) return LWP_EBADEVENT;
1458 ev = getevent(event);
1460 while (seq == ev->seq) {
1461 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1463 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1468 int LWP_MwaitProcess(wcount, evlist) /* wait on m of n events */
1472 lwp_unimplemented("LWP_MWaitProcess");
1475 int LWP_NoYieldSignal(event)
1479 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1480 if (event == NULL) return LWP_EBADEVENT;
1481 ev = getevent(event);
1482 if (ev->refcount > 1) {
1484 assert(pthread_cond_broadcast(&ev->cond) == 0);
1490 int LWP_SignalProcess(event)
1494 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1495 if (event == NULL) return LWP_EBADEVENT;
1496 ev = getevent(event);
1497 if (ev->refcount > 1) {
1499 assert(!pthread_mutex_unlock(&lwp_mutex));
1500 assert(!pthread_cond_broadcast(&ev->cond));
1502 assert(!pthread_mutex_lock(&lwp_mutex));
1508 int LWP_StackUsed(pid, maxa, used)
1512 lwp_unimplemented("LWP_StackUsed");
1515 LWP_NewRock(Tag, Value)
1517 char *Value; /* IN */
1519 lwp_unimplemented("LWP_NewRock");
1522 LWP_GetRock(Tag, Value)
1524 char **Value; /* OUT */
1526 lwp_unimplemented("LWP_GetRock");
1529 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
1533 lwp_unimplemented("LWP_GetProcessPriority");
1536 #endif /* USE_PTHREADS */