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();
49 #if !defined(USE_PTHREADS) && !defined(USE_SOLARIS_THREADS)
52 extern void *malloc(int size);
53 extern void *realloc(void *ptr, int size);
55 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
56 extern int PRE_Block; /* from preempt.c */
58 extern char PRE_Block; /* from preempt.c */
69 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
72 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
86 #define Debug(level, msg) do { \
87 if (lwp_debug && lwp_debug >= level) { \
88 printf("***LWP (0x%x): ", lwp_cpptr); \
94 #define Debug(level, msg) do { \
99 static int Dispatcher();
100 static int Create_Process_Part2();
101 static int Exit_LWP();
102 static afs_int32 Initialize_Stack();
103 static int Stack_Used();
104 char (*RC_to_ASCII());
106 static void Abort_LWP();
107 static void Overflow_Complain();
108 static void Initialize_PCB();
109 static void Dispose_of_Dead_PCB();
110 static void Free_PCB();
111 static int Internal_Signal();
112 static purge_dead_pcbs();
114 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
119 } runnable[MAX_PRIORITIES], blocked, qwaiting;
120 /* 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. */
122 /* Offset of stack field within pcb -- used by stack checking stuff */
125 /* special user-tweakable option for AIX */
126 int lwp_MaxStackSize = 32768;
128 /* biggest LWP stack created so far */
129 int lwp_MaxStackSeen = 0;
131 /* Stack checking action */
132 int lwp_overflowAction = LWP_SOABORT;
134 /* Controls stack size counting. */
135 int lwp_stackUseEnabled = TRUE; /* pay the price */
139 /* Minimum stack size */
140 int lwp_MinStackSize = 0;
145 register struct QUEUE *q;
147 /* Special test for only element on queue */
151 /* Not only element, do normal remove */
152 p->next->prev = p->prev;
153 p->prev->next = p->next;
155 /* See if head pointing to this element */
159 p->next = p->prev = NULL;
166 register struct QUEUE *q;
168 if (q->head == NULL) { /* Queue is empty */
170 p->next = p->prev = p;
171 } else { /* Regular insert */
172 p->prev = q->head->prev;
173 q->head->prev->next = p;
184 struct QUEUE *from, *to;
194 #define for_all_elts(var, q, body)\
196 register PROCESS var, _NEXT_;\
198 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
199 _NEXT_ = var -> next;\
205 /*****************************************************************************\
207 * Following section documents the Assembler interfaces used by LWP code *
209 \*****************************************************************************/
212 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
214 Stub for Assembler routine that will
215 save the current SP value in the passed
216 context savearea and call the function
217 whose entry point is in ep. If the sp
218 parameter is NULL, the current stack is
219 used, otherwise sp becomes the new stack
222 returnto(struct lwp_context *savearea);
224 Stub for Assembler routine that will
225 restore context from a passed savearea
226 and return to the restored C frame.
230 /* Macro to force a re-schedule. Strange name is historical */
231 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
233 static struct lwp_ctl *lwp_init = 0;
239 (tp = lwp_cpptr)->status = QWAITING;
240 move(tp, &runnable[tp->priority], qwaiting);
247 register PROCESS pid;
249 if (pid->status == QWAITING) {
251 move(pid, qwaiting, &runnable[pid->priority]);
259 reserveFromStack(register afs_int32 size)
268 LWP_CreateProcess(int (*ep) (), int stacksize, int priority, void *parm,
269 char *name, PROCESS * pid)
273 static char *stackptr = 0;
278 #if defined(AFS_LWP_MINSTACKSIZE)
280 * on some systems (e.g. hpux), a minimum usable stack size has
283 if (stacksize < lwp_MinStackSize) {
284 stacksize = lwp_MinStackSize;
286 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
287 /* more stack size computations; keep track of for IOMGR */
288 if (lwp_MaxStackSeen < stacksize)
289 lwp_MaxStackSeen = stacksize;
291 Debug(0, ("Entered LWP_CreateProcess"));
292 /* Throw away all dead process control blocks */
295 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
300 if (stacksize < MINSTACK)
304 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
308 * The following signal action for AIX is necessary so that in case of a
309 * crash (i.e. core is generated) we can include the user's data section
310 * in the core dump. Unfortunately, by default, only a partial core is
311 * generated which, in many cases, isn't too useful.
313 * We also do it here in case the main program forgets to do it.
315 struct sigaction nsa;
316 extern uid_t geteuid();
318 sigemptyset(&nsa.sa_mask);
319 nsa.sa_handler = SIG_DFL;
320 nsa.sa_flags = SA_FULLDUMP;
321 sigaction(SIGABRT, &nsa, NULL);
322 sigaction(SIGSEGV, &nsa, NULL);
325 * First we need to increase the default resource limits,
326 * if necessary, so that we can guarantee that we have the
327 * resources to create the core file, but we can't always
328 * do it as an ordinary user.
331 /* vos dump causes problems */
332 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
333 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
334 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
337 * Now reserve in one scoop all the stack space that will be used
338 * by the particular application's main (i.e. non-lwp) body. This
339 * is plenty space for any of our applications.
341 stackptr = reserveFromStack(lwp_MaxStackSize);
343 stackptr -= stacksize;
345 if ((stackptr = (char *)malloc(stacksize + 7)) == NULL) {
349 /* Round stack pointer to byte boundary */
350 stackptr = (char *)(8 * (((long)stackptr + 7) / 8));
352 if (priority < 0 || priority >= MAX_PRIORITIES) {
356 Initialize_Stack(stackptr, stacksize);
357 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
358 insert(temp, &runnable[priority]);
361 Abort_LWP("PRE_Block not 0");
363 /* Gross hack: beware! */
366 #if defined(AFS_PARISC_LINUX24_ENV)
367 savecontext(Create_Process_Part2, &temp2->context,
368 stackptr + MINFRAME);
371 savecontext(Create_Process_Part2, &temp2->context,
372 stackptr + MINFRAME);
374 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
375 /* Need to have the sp on an 8-byte boundary for storing doubles. */
376 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16); /* 16 = 2 * jmp_buf_type */
378 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
379 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40); /* lomgjmp does something
382 #if defined(AFS_S390_LINUX20_ENV)
383 savecontext(Create_Process_Part2, &temp2->context,
384 stackptr + stacksize - MINFRAME);
385 #else /* !AFS_S390_LINUX20_ENV */
386 savecontext(Create_Process_Part2, &temp2->context,
387 stackptr + stacksize - sizeof(void *));
388 #endif /* AFS_S390_LINUX20_ENV */
389 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
390 #endif /* AFS_SGI62_ENV */
393 /* End of gross hack */
404 LWP_CreateProcess2(int (*ep) (), int stacksize, int priority, void *parm,
405 char *name, PROCESS * pid)
410 #if defined(AFS_LWP_MINSTACKSIZE)
412 * on some systems (e.g. hpux), a minimum usable stack size has
415 if (stacksize < lwp_MinStackSize) {
416 stacksize = lwp_MinStackSize;
418 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
419 /* more stack size computations; keep track of for IOMGR */
420 if (lwp_MaxStackSeen < stacksize)
421 lwp_MaxStackSeen = stacksize;
423 Debug(0, ("Entered LWP_CreateProcess"));
424 /* Throw away all dead process control blocks */
427 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
432 if (stacksize < MINSTACK)
436 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
437 if ((stackptr = (char *)malloc(stacksize)) == NULL) {
441 if (priority < 0 || priority >= MAX_PRIORITIES) {
445 Initialize_Stack(stackptr, stacksize);
446 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
447 insert(temp, &runnable[priority]);
450 Abort_LWP("PRE_Block not 0");
452 /* Gross hack: beware! */
455 savecontext(Create_Process_Part2, &temp2->context,
456 stackptr + stacksize - sizeof(void *));
457 /* End of gross hack */
468 LWP_CurrentProcess(PROCESS * pid)
469 { /* returns pid of current process */
470 Debug(0, ("Entered Current_Process"));
481 Debug(0, ("Entered ThreadId"));
488 #define LWPANCHOR (*lwp_init)
491 LWP_DestroyProcess(PROCESS pid)
492 { /* destroy a lightweight process */
495 Debug(0, ("Entered Destroy_Process"));
497 if (lwp_cpptr != pid) {
498 Dispose_of_Dead_PCB(pid);
501 pid->status = DESTROYED;
502 move(pid, &runnable[pid->priority], &blocked);
504 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
505 savecontext(Dispatcher, &(temp->context),
506 &(LWPANCHOR.dsptchstack[MINFRAME]));
507 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
508 savecontext(Dispatcher, &(temp->context),
510 dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
511 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
512 savecontext(Dispatcher, &(temp->context),
514 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
516 #elif defined(AFS_S390_LINUX20_ENV)
517 savecontext(Dispatcher, &(temp->context),
519 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
522 savecontext(Dispatcher, &(temp->context),
524 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
534 LWP_DispatchProcess(void)
535 { /* explicit voluntary preemption */
536 Debug(2, ("Entered Dispatch_Process"));
550 for (i = 0; i < MAX_PRIORITIES; i++)
551 for_all_elts(x, runnable[i], {
552 printf("[Priority %d]\n", i);
556 for_all_elts(x, blocked, {
557 Dump_One_Process(x);}
559 for_all_elts(x, qwaiting, {
560 Dump_One_Process(x);}
563 printf("***LWP: LWP support not initialized\n");
569 LWP_GetProcessPriority(PROCESS pid, int *priority)
570 { /* returns process priority */
571 Debug(0, ("Entered Get_Process_Priority"));
573 *priority = pid->priority;
580 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
583 struct lwp_pcb dummy;
587 Debug(0, ("Entered LWP_InitializeProcessSupport"));
588 if (lwp_init != NULL)
591 /* Set up offset for stack checking -- do this as soon as possible */
592 stack_offset = (char *)&dummy.stack - (char *)&dummy;
594 if (priority >= MAX_PRIORITIES)
596 for (i = 0; i < MAX_PRIORITIES; i++) {
597 runnable[i].head = NULL;
598 runnable[i].count = 0;
602 qwaiting.head = NULL;
604 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
605 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
606 if (lwp_init == NULL || temp == NULL)
607 Abort_LWP("Insufficient Storage to Initialize LWP Support");
608 LWPANCHOR.processcnt = 1;
609 LWPANCHOR.outerpid = temp;
610 LWPANCHOR.outersp = NULL;
611 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
612 "Main Process [created by LWP]");
613 insert(temp, &runnable[priority]);
614 savecontext(Dispatcher, &temp->context, NULL);
615 LWPANCHOR.outersp = temp->context.topstack;
619 /* get minimum stack size from the environment. this allows the administrator
620 * to change the lwp stack dynamically without getting a new binary version.
622 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
623 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
626 (AFS_LWP_MINSTACKSIZE >
627 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
633 LWP_INTERNALSIGNAL(char *event, int yield)
634 { /* signal the occurence of an event */
635 Debug(2, ("Entered LWP_SignalProcess"));
638 rc = Internal_Signal(event);
647 LWP_TerminateProcessSupport(void)
648 { /* terminate all LWP support */
651 Debug(0, ("Entered Terminate_Process_Support"));
652 if (lwp_init == NULL)
654 if (lwp_cpptr != LWPANCHOR.outerpid)
655 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
656 for (i = 0; i < MAX_PRIORITIES; i++)
657 for_all_elts(cur, runnable[i], {
660 for_all_elts(cur, blocked, {
663 for_all_elts(cur, qwaiting, {
672 LWP_WaitProcess(char *event)
673 { /* wait on a single event */
676 Debug(2, ("Entered Wait_Process"));
678 return LWP_EBADEVENT;
681 return LWP_MwaitProcess(1, tempev);
685 LWP_MwaitProcess(int wcount, char *evlist[])
686 { /* wait on m of n events */
687 register int ecount, i;
690 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
692 if (evlist == NULL) {
694 return LWP_EBADCOUNT;
697 for (ecount = 0; evlist[ecount] != NULL; ecount++);
701 return LWP_EBADCOUNT;
706 if (wcount > ecount || wcount < 0) {
708 return LWP_EBADCOUNT;
710 if (ecount > lwp_cpptr->eventlistsize) {
712 lwp_cpptr->eventlist =
713 (char **)realloc(lwp_cpptr->eventlist,
714 ecount * sizeof(char *));
715 lwp_cpptr->eventlistsize = ecount;
717 for (i = 0; i < ecount; i++)
718 lwp_cpptr->eventlist[i] = evlist[i];
720 lwp_cpptr->status = WAITING;
722 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
725 lwp_cpptr->wakevent = 0;
726 lwp_cpptr->waitcnt = wcount;
727 lwp_cpptr->eventcnt = ecount;
738 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
740 *maxa = pid->stacksize;
741 *used = Stack_Used(pid->stack, *maxa);
748 * The following functions are strictly
749 * INTERNAL to the LWP support package.
755 struct lwp_context tempcontext;
757 Debug(0, ("Entered Abort_LWP"));
758 printf("***LWP: %s\n", msg);
759 printf("***LWP: Abort --- dumping PCBs ...\n");
763 if (LWPANCHOR.outersp == NULL)
766 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
771 Create_Process_Part2(void)
772 { /* creates a context for the new process */
775 Debug(2, ("Entered Create_Process_Part2"));
776 temp = lwp_cpptr; /* Get current process id */
777 savecontext(Dispatcher, &temp->context, NULL);
778 (*temp->ep) (temp->parm);
779 LWP_DestroyProcess(temp);
784 Delete_PCB(register PROCESS pid)
785 { /* remove a PCB from the process list */
786 Debug(4, ("Entered Delete_PCB"));
788 (pid->blockflag || pid->status == WAITING
790 DESTROYED ? &blocked :
791 (pid->status == QWAITING) ? &qwaiting :
792 &runnable[pid->priority]));
793 LWPANCHOR.processcnt--;
799 Dump_One_Process(PROCESS pid)
803 printf("***LWP: Process Control Block at 0x%x\n", pid);
804 printf("***LWP: Name: %s\n", pid->name);
806 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
808 printf("BLOCKED and ");
809 switch (pid->status) {
826 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
828 if (pid->stacksize != 0) {
829 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
830 pid->stacksize, pid->stack);
831 printf("***LWP: HWM stack usage: ");
832 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
835 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
836 if (pid->eventcnt > 0) {
837 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
838 printf("***LWP: Event id list:");
839 for (i = 0; i < pid->eventcnt; i++)
840 printf(" 0x%x", pid->eventlist[i]);
843 if (pid->wakevent > 0)
844 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
850 purge_dead_pcbs(void)
852 for_all_elts(cur, blocked, {
853 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
858 int LWP_TraceProcesses = 0;
862 { /* Lightweight process dispatcher */
865 static int dispatch_count = 0;
867 if (LWP_TraceProcesses > 0) {
868 for (i = 0; i < MAX_PRIORITIES; i++) {
869 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
870 for_all_elts(p, runnable[i], {
871 printf(" \"%s\"", p->name);
876 printf("[Blocked (%d):", blocked.count);
877 for_all_elts(p, blocked, {
878 printf(" \"%s\"", p->name);
882 printf("[Qwaiting (%d):", qwaiting.count);
883 for_all_elts(p, qwaiting, {
884 printf(" \"%s\"", p->name);
891 /* Check for stack overflowif this lwp has a stack. Check for
892 * the guard word at the front of the stack being damaged and
893 * for the stack pointer being below the front of the stack.
894 * WARNING! This code assumes that stacks grow downward. */
895 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
896 /* Fix this (stackcheck at other end of stack?) */
897 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
898 && (lwp_cpptr->stackcheck !=
899 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
900 || lwp_cpptr->context.topstack >
901 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
903 if (lwp_cpptr && lwp_cpptr->stack
904 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
905 || lwp_cpptr->context.topstack < lwp_cpptr->stack
906 || lwp_cpptr->context.topstack >
907 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
909 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
910 *(int *)lwp_cpptr->stack);
911 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
912 lwp_cpptr->context.topstack, lwp_cpptr->stack,
913 lwp_cpptr->stacksize);
915 switch (lwp_overflowAction) {
924 lwp_overflowAction = LWP_SOQUIET;
929 /* Move head of current runnable queue forward if current LWP is still in it. */
930 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
931 runnable[lwp_cpptr->priority].head =
932 runnable[lwp_cpptr->priority].head->next;
933 /* Find highest priority with runnable processes. */
934 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
935 if (runnable[i].head != NULL)
939 Abort_LWP("No READY processes");
942 if (LWP_TraceProcesses > 0)
943 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
944 runnable[i].head, runnable[i].head->name);
947 Abort_LWP("PRE_Block not 1");
948 lwp_cpptr = runnable[i].head;
950 returnto(&lwp_cpptr->context);
953 /* Complain of a stack overflow to stderr without using stdio. */
955 Overflow_Complain(void)
959 char *msg1 = " LWP: stack overflow in process ";
962 currenttime = time(0);
963 timeStamp = ctime(¤ttime);
965 write(2, timeStamp, strlen(timeStamp));
967 write(2, msg1, strlen(msg1));
968 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
969 write(2, msg2, strlen(msg2));
973 Dispose_of_Dead_PCB(PROCESS cur)
975 Debug(4, ("Entered Dispose_of_Dead_PCB"));
979 Internal_Signal(cur);
990 Free_PCB(PROCESS pid)
992 Debug(4, ("Entered Free_PCB"));
993 if (pid->stack != NULL) {
995 ("HWM stack usage: %d, [PCB at 0x%x]",
996 Stack_Used(pid->stack, pid->stacksize), pid));
999 if (pid->eventlist != NULL)
1000 free(pid->eventlist);
1005 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1006 int (*ep) (), void *parm, char *name)
1010 Debug(4, ("Entered Initialize_PCB"));
1012 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1014 temp->name[31] = '\0';
1015 temp->status = READY;
1016 temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
1017 temp->eventlistsize = EVINITSIZE;
1021 temp->blockflag = 0;
1022 temp->iomgrRequest = 0;
1023 temp->priority = priority;
1024 temp->index = lwp_nextindex++;
1025 temp->stack = stack;
1026 temp->stacksize = stacksize;
1027 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1028 if (temp->stack != NULL)
1029 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1031 if (temp->stack != NULL)
1032 temp->stackcheck = *(int *)(temp->stack);
1036 temp->misc = NULL; /* currently unused */
1039 temp->lwp_rused = 0;
1040 temp->level = 1; /* non-preemptable */
1044 Internal_Signal(register char *event)
1046 int rc = LWP_ENOWAIT;
1049 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1053 return LWP_EBADEVENT;
1054 for_all_elts(temp, blocked, {
1055 if (temp->status == WAITING)
1056 for (i = 0; i < temp->eventcnt; i++) {
1057 if (temp->eventlist[i] == event) {
1058 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1059 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1060 if (--temp->waitcnt == 0) {
1061 temp->status = READY; temp->wakevent = i + 1;
1062 move(temp, &blocked, &runnable[temp->priority]); break;}
1070 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1071 #define STACKMAGIC 0xBADBADBA
1073 Initialize_Stack(char *stackptr, int stacksize)
1077 Debug(4, ("Entered Initialize_Stack"));
1078 if (lwp_stackUseEnabled)
1079 for (i = 0; i < stacksize; i++)
1080 stackptr[i] = i & 0xff;
1082 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1083 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1085 *(afs_int32 *) stackptr = STACKMAGIC;
1091 Stack_Used(register char *stackptr, int stacksize)
1095 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1096 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1099 for (i = stacksize - 1; i >= 0; i--)
1100 if ((unsigned char)stackptr[i] != (i & 0xff))
1105 if (*(afs_int32 *) stackptr == STACKMAGIC)
1108 for (i = 0; i < stacksize; i++)
1109 if ((unsigned char)stackptr[i] != (i & 0xff))
1110 return (stacksize - i);
1118 LWP_NewRock(int Tag, char *Value)
1119 /* Finds a free rock and sets its value to Value.
1121 * LWP_SUCCESS Rock did not exist and a new one was used
1122 * LWP_EBADROCK Rock already exists.
1123 * LWP_ENOROCKS All rocks are in use.
1125 * From the above semantics, you can only set a rock value once. This is specifically
1126 * to prevent multiple users of the LWP package from accidentally using the same Tag
1127 * value and clobbering others. You can always use one level of indirection to obtain
1128 * a rock whose contents can change.
1132 register struct rock *ra; /* rock array */
1134 ra = lwp_cpptr->lwp_rlist;
1136 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1137 if (ra[i].tag == Tag)
1138 return (LWP_EBADROCK);
1140 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1141 ra[lwp_cpptr->lwp_rused].tag = Tag;
1142 ra[lwp_cpptr->lwp_rused].value = Value;
1143 lwp_cpptr->lwp_rused++;
1144 return (LWP_SUCCESS);
1146 return (LWP_ENOROCKS);
1151 LWP_GetRock(int Tag, char **Value)
1152 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1154 * LWP_SUCCESS if specified rock exists and Value has been filled
1155 * LWP_EBADROCK rock specified does not exist
1159 register struct rock *ra;
1161 ra = lwp_cpptr->lwp_rlist;
1163 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1164 if (ra[i].tag == Tag) {
1165 *Value = ra[i].value;
1166 return (LWP_SUCCESS);
1168 return (LWP_EBADROCK);
1172 #ifdef AFS_AIX32_ENV
1174 setlim(int limcon, uchar_t hard, int limit)
1178 (void)getrlimit(limcon, &rlim);
1180 limit = limit * 1024;
1182 rlim.rlim_max = limit;
1183 else if (limit == RLIM_INFINITY && geteuid() != 0)
1184 rlim.rlim_cur = rlim.rlim_max;
1186 rlim.rlim_cur = limit;
1188 /* Must use ulimit() due to Posix constraints */
1189 if (limcon == RLIMIT_FSIZE) {
1192 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1193 printf("Can't %s%s limit\n",
1194 limit == RLIM_INFINITY ? "remove" : "set",
1195 hard ? " hard" : "");
1199 if (setrlimit(limcon, &rlim) < 0) {
1201 printf("Can't %s%s limit\n",
1202 limit == RLIM_INFINITY ? "remove" : "set",
1203 hard ? " hard" : "");
1213 * Print the specific limit out
1216 plim(char *name, afs_int32 lc, uchar_t hard)
1221 printf("%s \t", name);
1222 (void)getrlimit(lc, &rlim);
1223 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1224 if (lim == RLIM_INFINITY)
1225 printf("unlimited");
1226 printf("%d %s", lim / 1024, "kbytes");
1234 LWP_NoYieldSignal(char *event)
1236 return (LWP_INTERNALSIGNAL(event, 0));
1240 LWP_SignalProcess(char *event)
1242 return (LWP_INTERNALSIGNAL(event, 1));
1247 #ifdef USE_SOLARIS_THREADS
1250 #include "pthread.h"
1255 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1257 PROCESS lwp_process_list; /* List of LWP initiated threads */
1259 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1261 #define CHECK check(__LINE__);
1263 typedef struct event {
1264 struct event *next; /* next in hash chain */
1265 char *event; /* lwp event: an address */
1266 int refcount; /* Is it in use? */
1267 pthread_cond_t cond; /* Currently associated condition variable */
1268 int seq; /* Sequence number: this is incremented
1269 * by wakeup calls; wait will not return until
1273 #define HASHSIZE 127
1274 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1275 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1277 #if CMA_DEBUG || DEBUGF
1279 lwp_process_string(void)
1281 static char id[200];
1283 LWP_CurrentProcess(&p);
1284 sprintf(id, "PID %x <%s>", p, p->name);
1290 lwp_unimplemented(char *interface)
1293 "cmalwp: %s is not currently implemented: program aborted\n",
1299 lwpabort(char *interface)
1301 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1308 lwp_unimplemented("LWP_QWait");
1312 LWP_QSignal(int pid)
1314 lwp_unimplemented("LWP_QSignal");
1317 /* Allocate and initialize an LWP process handle. The associated pthread handle
1318 * must be added by the caller, and the structure threaded onto the LWP active
1319 * process list by lwp_thread_process */
1321 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1324 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1325 memset((char *)lp, 0, sizeof(*lp));
1329 sprintf(temp, "unnamed_process_%04d", ++procnum);
1330 assert(name = (char *)malloc(strlen(temp) + 1));
1339 /* Thread the LWP process descriptor *lp onto the lwp active process list
1340 * and associate a back pointer to the process descriptor from the associated
1343 lwp_thread_process(PROCESS lp)
1345 lp->next = lwp_process_list;
1346 lwp_process_list = lp;
1347 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1350 /* The top-level routine used as entry point to explicitly created LWP
1351 * processes. This completes a few details of process creation left
1352 * out by LWP_CreateProcess and calls the user-specified entry point */
1354 lwp_top_level(pthread_addr_t argp)
1356 PROCESS lp = (PROCESS) argp;
1358 assert(!pthread_mutex_lock(&lwp_mutex));
1359 lwp_thread_process(lp);
1361 assert(!pthread_mutex_unlock(&lwp_mutex));
1362 /* Should cleanup state */
1366 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1367 void *parm, char *name, PROCESS * pid)
1370 pthread_attr_t attr;
1374 #ifndef LWP_NO_PRIORITIES
1375 if (!cmalwp_pri_inrange(priority))
1378 assert(!pthread_attr_create(&attr));
1379 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1381 assert(!pthread_attr_setstacksize(&attr, stacksize));
1383 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1384 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1385 #ifndef LWP_NO_PRIORITIES
1386 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1389 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1390 (pthread_addr_t) parm);
1392 /* allow new thread to run if higher priority */
1393 assert(!pthread_mutex_unlock(&lwp_mutex));
1394 /* process is only added to active list after first time it runs (it adds itself) */
1396 pthread_create(&lp->handle, attr,
1397 (pthread_startroutine_t) lwp_top_level,
1398 (pthread_addr_t) lp);
1399 assert(!pthread_attr_delete(&attr));
1400 assert(!pthread_mutex_lock(&lwp_mutex));
1410 LWP_ActiveProcess(void)
1411 { /* returns pid of current process */
1413 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1418 LWP_CurrentProcess(PROCESS * pid)
1419 { /* get pid of current process */
1420 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1425 LWP_DestroyProcess(PROCESS pid)
1426 { /* destroy a lightweight process */
1427 lwp_unimplemented("LWP_DestroyProcess");
1431 LWP_DispatchProcess(void)
1432 { /* explicit voluntary preemption */
1433 assert(!pthread_mutex_unlock(&lwp_mutex));
1435 assert(!pthread_mutex_lock(&lwp_mutex));
1440 lwp_process_key_destructor(void)
1445 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1447 static int initialized = 0;
1457 #ifndef LWP_NO_PRIORITIES
1458 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1462 /* Create pthread key to associate LWP process descriptor with each
1463 * LWP-created thread */
1464 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1465 lwp_process_key_destructor));
1467 lp = lwp_alloc_process("main process", main, 0);
1468 lp->handle = pthread_self();
1469 lwp_thread_process(lp);
1470 #ifndef LWP_NO_PRIORITIES
1471 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1472 cmalwp_lwppri_to_cmapri(priority));
1475 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1476 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1483 LWP_TerminateProcessSupport(void)
1484 { /* terminate all LWP support */
1485 lwp_unimplemented("LWP_TerminateProcessSupport");
1488 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1490 getevent(char *event)
1492 event_t *evp, *newp;
1495 hashcode = hash(event);
1496 evp = hashtable[hashcode];
1499 if (evp->event == event) {
1503 if (evp->refcount == 0)
1508 newp = (event_t *) malloc(sizeof(event_t));
1510 newp->next = hashtable[hashcode];
1511 hashtable[hashcode] = newp;
1512 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1515 newp->event = event;
1520 /* Release the specified event */
1521 #define relevent(evp) ((evp)->refcount--)
1524 LWP_WaitProcess(char *event)
1525 { /* wait on a single event */
1528 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1530 return LWP_EBADEVENT;
1531 ev = getevent(event);
1533 while (seq == ev->seq) {
1534 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1536 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1542 LWP_MwaitProcess(int wcount, char *evlist[])
1543 { /* wait on m of n events */
1544 lwp_unimplemented("LWP_MWaitProcess");
1548 LWP_NoYieldSignal(char *event)
1551 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1553 return LWP_EBADEVENT;
1554 ev = getevent(event);
1555 if (ev->refcount > 1) {
1557 assert(pthread_cond_broadcast(&ev->cond) == 0);
1564 LWP_SignalProcess(char *event)
1567 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1569 return LWP_EBADEVENT;
1570 ev = getevent(event);
1571 if (ev->refcount > 1) {
1573 assert(!pthread_mutex_unlock(&lwp_mutex));
1574 assert(!pthread_cond_broadcast(&ev->cond));
1576 assert(!pthread_mutex_lock(&lwp_mutex));
1583 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1585 lwp_unimplemented("LWP_StackUsed");
1589 LWP_NewRock(int Tag, char *Value)
1591 lwp_unimplemented("LWP_NewRock");
1595 LWP_GetRock(int Tag, char **Value)
1597 lwp_unimplemented("LWP_GetRock");
1601 LWP_GetProcessPriority(PROCESS pid, int *priority)
1602 { /* returns process priority */
1603 lwp_unimplemented("LWP_GetProcessPriority");
1606 #endif /* USE_PTHREADS */