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)
91 #define Debug(level, msg) do { \
92 if (lwp_debug && lwp_debug >= level) { \
93 printf("***LWP (0x%x): ", lwp_cpptr); \
99 #define Debug(level, msg) do { \
104 static int Dispatcher();
105 static int Create_Process_Part2();
106 static int Exit_LWP();
107 static afs_int32 Initialize_Stack();
108 static int Stack_Used();
109 char (*RC_to_ASCII());
111 static void Abort_LWP();
112 static void Overflow_Complain();
113 static void Initialize_PCB();
114 static void Dispose_of_Dead_PCB();
115 static void Free_PCB();
116 static int Internal_Signal();
117 static purge_dead_pcbs();
119 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
124 } runnable[MAX_PRIORITIES], blocked, qwaiting;
125 /* 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. */
127 /* Offset of stack field within pcb -- used by stack checking stuff */
130 /* special user-tweakable option for AIX */
131 int lwp_MaxStackSize = 32768;
133 /* biggest LWP stack created so far */
134 int lwp_MaxStackSeen = 0;
136 /* Stack checking action */
137 int lwp_overflowAction = LWP_SOABORT;
139 /* Controls stack size counting. */
140 int lwp_stackUseEnabled = TRUE; /* pay the price */
144 /* Minimum stack size */
145 int lwp_MinStackSize = 0;
150 register struct QUEUE *q;
152 /* Special test for only element on queue */
156 /* Not only element, do normal remove */
157 p->next->prev = p->prev;
158 p->prev->next = p->next;
160 /* See if head pointing to this element */
164 p->next = p->prev = NULL;
171 register struct QUEUE *q;
173 if (q->head == NULL) { /* Queue is empty */
175 p->next = p->prev = p;
176 } else { /* Regular insert */
177 p->prev = q->head->prev;
178 q->head->prev->next = p;
189 struct QUEUE *from, *to;
199 #define for_all_elts(var, q, body)\
201 register PROCESS var, _NEXT_;\
203 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
204 _NEXT_ = var -> next;\
210 /*****************************************************************************\
212 * Following section documents the Assembler interfaces used by LWP code *
214 \*****************************************************************************/
217 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
219 Stub for Assembler routine that will
220 save the current SP value in the passed
221 context savearea and call the function
222 whose entry point is in ep. If the sp
223 parameter is NULL, the current stack is
224 used, otherwise sp becomes the new stack
227 returnto(struct lwp_context *savearea);
229 Stub for Assembler routine that will
230 restore context from a passed savearea
231 and return to the restored C frame.
235 /* Macro to force a re-schedule. Strange name is historical */
236 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
238 static struct lwp_ctl *lwp_init = 0;
244 (tp = lwp_cpptr)->status = QWAITING;
245 move(tp, &runnable[tp->priority], &qwaiting);
252 register PROCESS pid;
254 if (pid->status == QWAITING) {
256 move(pid, &qwaiting, &runnable[pid->priority]);
264 reserveFromStack(register afs_int32 size)
273 LWP_CreateProcess(int (*ep) (), int stacksize, int priority, void *parm,
274 char *name, PROCESS * pid)
278 static char *stackptr = 0;
283 #if defined(AFS_LWP_MINSTACKSIZE)
285 * on some systems (e.g. hpux), a minimum usable stack size has
288 if (stacksize < lwp_MinStackSize) {
289 stacksize = lwp_MinStackSize;
291 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
292 /* more stack size computations; keep track of for IOMGR */
293 if (lwp_MaxStackSeen < stacksize)
294 lwp_MaxStackSeen = stacksize;
296 Debug(0, ("Entered LWP_CreateProcess"));
297 /* Throw away all dead process control blocks */
300 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
305 if (stacksize < MINSTACK)
309 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
313 * The following signal action for AIX is necessary so that in case of a
314 * crash (i.e. core is generated) we can include the user's data section
315 * in the core dump. Unfortunately, by default, only a partial core is
316 * generated which, in many cases, isn't too useful.
318 * We also do it here in case the main program forgets to do it.
320 struct sigaction nsa;
321 extern uid_t geteuid();
323 sigemptyset(&nsa.sa_mask);
324 nsa.sa_handler = SIG_DFL;
325 nsa.sa_flags = SA_FULLDUMP;
326 sigaction(SIGABRT, &nsa, NULL);
327 sigaction(SIGSEGV, &nsa, NULL);
330 * First we need to increase the default resource limits,
331 * if necessary, so that we can guarantee that we have the
332 * resources to create the core file, but we can't always
333 * do it as an ordinary user.
336 /* vos dump causes problems */
337 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
338 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
339 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
342 * Now reserve in one scoop all the stack space that will be used
343 * by the particular application's main (i.e. non-lwp) body. This
344 * is plenty space for any of our applications.
346 stackptr = reserveFromStack(lwp_MaxStackSize);
348 stackptr -= stacksize;
350 if ((stackptr = (char *)malloc(stacksize + 7)) == NULL) {
354 /* Round stack pointer to byte boundary */
355 stackptr = (char *)(8 * (((long)stackptr + 7) / 8));
357 if (priority < 0 || priority >= MAX_PRIORITIES) {
361 Initialize_Stack(stackptr, stacksize);
362 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
363 insert(temp, &runnable[priority]);
366 Abort_LWP("PRE_Block not 0");
368 /* Gross hack: beware! */
371 #if defined(AFS_PARISC_LINUX24_ENV)
372 savecontext(Create_Process_Part2, &temp2->context,
373 stackptr + MINFRAME);
376 savecontext(Create_Process_Part2, &temp2->context,
377 stackptr + MINFRAME);
379 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
380 /* Need to have the sp on an 8-byte boundary for storing doubles. */
381 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16); /* 16 = 2 * jmp_buf_type */
383 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
384 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40); /* lomgjmp does something
387 #if defined(AFS_S390_LINUX20_ENV)
388 savecontext(Create_Process_Part2, &temp2->context,
389 stackptr + stacksize - MINFRAME);
390 #else /* !AFS_S390_LINUX20_ENV */
391 savecontext(Create_Process_Part2, &temp2->context,
392 stackptr + stacksize - sizeof(void *));
393 #endif /* AFS_S390_LINUX20_ENV */
394 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
395 #endif /* AFS_SGI62_ENV */
398 /* End of gross hack */
409 LWP_CreateProcess2(int (*ep) (), int stacksize, int priority, void *parm,
410 char *name, PROCESS * pid)
415 #if defined(AFS_LWP_MINSTACKSIZE)
417 * on some systems (e.g. hpux), a minimum usable stack size has
420 if (stacksize < lwp_MinStackSize) {
421 stacksize = lwp_MinStackSize;
423 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
424 /* more stack size computations; keep track of for IOMGR */
425 if (lwp_MaxStackSeen < stacksize)
426 lwp_MaxStackSeen = stacksize;
428 Debug(0, ("Entered LWP_CreateProcess"));
429 /* Throw away all dead process control blocks */
432 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
437 if (stacksize < MINSTACK)
441 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
442 if ((stackptr = (char *)malloc(stacksize)) == NULL) {
446 if (priority < 0 || priority >= MAX_PRIORITIES) {
450 Initialize_Stack(stackptr, stacksize);
451 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
452 insert(temp, &runnable[priority]);
455 Abort_LWP("PRE_Block not 0");
457 /* Gross hack: beware! */
460 savecontext(Create_Process_Part2, &temp2->context,
461 stackptr + stacksize - sizeof(void *));
462 /* End of gross hack */
473 LWP_CurrentProcess(PROCESS * pid)
474 { /* returns pid of current process */
475 Debug(0, ("Entered Current_Process"));
486 Debug(0, ("Entered ThreadId"));
493 #define LWPANCHOR (*lwp_init)
496 LWP_DestroyProcess(PROCESS pid)
497 { /* destroy a lightweight process */
500 Debug(0, ("Entered Destroy_Process"));
502 if (lwp_cpptr != pid) {
503 Dispose_of_Dead_PCB(pid);
506 pid->status = DESTROYED;
507 move(pid, &runnable[pid->priority], &blocked);
509 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
510 savecontext(Dispatcher, &(temp->context),
511 &(LWPANCHOR.dsptchstack[MINFRAME]));
512 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
513 savecontext(Dispatcher, &(temp->context),
515 dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
516 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
517 savecontext(Dispatcher, &(temp->context),
519 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
521 #elif defined(AFS_S390_LINUX20_ENV)
522 savecontext(Dispatcher, &(temp->context),
524 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
527 savecontext(Dispatcher, &(temp->context),
529 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
539 LWP_DispatchProcess(void)
540 { /* explicit voluntary preemption */
541 Debug(2, ("Entered Dispatch_Process"));
555 for (i = 0; i < MAX_PRIORITIES; i++)
556 for_all_elts(x, runnable[i], {
557 printf("[Priority %d]\n", i);
561 for_all_elts(x, blocked, {
562 Dump_One_Process(x);}
564 for_all_elts(x, qwaiting, {
565 Dump_One_Process(x);}
568 printf("***LWP: LWP support not initialized\n");
574 LWP_GetProcessPriority(PROCESS pid, int *priority)
575 { /* returns process priority */
576 Debug(0, ("Entered Get_Process_Priority"));
578 *priority = pid->priority;
585 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
588 struct lwp_pcb dummy;
592 Debug(0, ("Entered LWP_InitializeProcessSupport"));
593 if (lwp_init != NULL)
596 /* Set up offset for stack checking -- do this as soon as possible */
597 stack_offset = (char *)&dummy.stack - (char *)&dummy;
599 if (priority >= MAX_PRIORITIES)
601 for (i = 0; i < MAX_PRIORITIES; i++) {
602 runnable[i].head = NULL;
603 runnable[i].count = 0;
607 qwaiting.head = NULL;
609 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
610 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
611 if (lwp_init == NULL || temp == NULL)
612 Abort_LWP("Insufficient Storage to Initialize LWP Support");
613 LWPANCHOR.processcnt = 1;
614 LWPANCHOR.outerpid = temp;
615 LWPANCHOR.outersp = NULL;
616 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
617 "Main Process [created by LWP]");
618 insert(temp, &runnable[priority]);
619 savecontext(Dispatcher, &temp->context, NULL);
620 LWPANCHOR.outersp = temp->context.topstack;
624 /* get minimum stack size from the environment. this allows the administrator
625 * to change the lwp stack dynamically without getting a new binary version.
627 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
628 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
631 (AFS_LWP_MINSTACKSIZE >
632 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
638 LWP_INTERNALSIGNAL(char *event, int yield)
639 { /* signal the occurence of an event */
640 Debug(2, ("Entered LWP_SignalProcess"));
643 rc = Internal_Signal(event);
652 LWP_TerminateProcessSupport(void)
653 { /* terminate all LWP support */
656 Debug(0, ("Entered Terminate_Process_Support"));
657 if (lwp_init == NULL)
659 if (lwp_cpptr != LWPANCHOR.outerpid)
660 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
661 for (i = 0; i < MAX_PRIORITIES; i++)
662 for_all_elts(cur, runnable[i], {
665 for_all_elts(cur, blocked, {
668 for_all_elts(cur, qwaiting, {
677 LWP_WaitProcess(char *event)
678 { /* wait on a single event */
681 Debug(2, ("Entered Wait_Process"));
683 return LWP_EBADEVENT;
686 return LWP_MwaitProcess(1, tempev);
690 LWP_MwaitProcess(int wcount, char *evlist[])
691 { /* wait on m of n events */
692 register int ecount, i;
695 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
697 if (evlist == NULL) {
699 return LWP_EBADCOUNT;
702 for (ecount = 0; evlist[ecount] != NULL; ecount++);
706 return LWP_EBADCOUNT;
711 if (wcount > ecount || wcount < 0) {
713 return LWP_EBADCOUNT;
715 if (ecount > lwp_cpptr->eventlistsize) {
717 lwp_cpptr->eventlist =
718 (char **)realloc(lwp_cpptr->eventlist,
719 ecount * sizeof(char *));
720 lwp_cpptr->eventlistsize = ecount;
722 for (i = 0; i < ecount; i++)
723 lwp_cpptr->eventlist[i] = evlist[i];
725 lwp_cpptr->status = WAITING;
727 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
730 lwp_cpptr->wakevent = 0;
731 lwp_cpptr->waitcnt = wcount;
732 lwp_cpptr->eventcnt = ecount;
743 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
745 *maxa = pid->stacksize;
746 *used = Stack_Used(pid->stack, *maxa);
753 * The following functions are strictly
754 * INTERNAL to the LWP support package.
760 struct lwp_context tempcontext;
762 Debug(0, ("Entered Abort_LWP"));
763 printf("***LWP: %s\n", msg);
764 printf("***LWP: Abort --- dumping PCBs ...\n");
768 if (LWPANCHOR.outersp == NULL)
771 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
776 Create_Process_Part2(void)
777 { /* creates a context for the new process */
780 Debug(2, ("Entered Create_Process_Part2"));
781 temp = lwp_cpptr; /* Get current process id */
782 savecontext(Dispatcher, &temp->context, NULL);
783 (*temp->ep) (temp->parm);
784 LWP_DestroyProcess(temp);
789 Delete_PCB(register PROCESS pid)
790 { /* remove a PCB from the process list */
791 Debug(4, ("Entered Delete_PCB"));
793 (pid->blockflag || pid->status == WAITING
795 DESTROYED ? &blocked :
796 (pid->status == QWAITING) ? &qwaiting :
797 &runnable[pid->priority]));
798 LWPANCHOR.processcnt--;
804 Dump_One_Process(PROCESS pid)
808 printf("***LWP: Process Control Block at 0x%x\n", pid);
809 printf("***LWP: Name: %s\n", pid->name);
811 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
813 printf("BLOCKED and ");
814 switch (pid->status) {
831 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
833 if (pid->stacksize != 0) {
834 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
835 pid->stacksize, pid->stack);
836 printf("***LWP: HWM stack usage: ");
837 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
840 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
841 if (pid->eventcnt > 0) {
842 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
843 printf("***LWP: Event id list:");
844 for (i = 0; i < pid->eventcnt; i++)
845 printf(" 0x%x", pid->eventlist[i]);
848 if (pid->wakevent > 0)
849 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
855 purge_dead_pcbs(void)
857 for_all_elts(cur, blocked, {
858 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
863 int LWP_TraceProcesses = 0;
867 { /* Lightweight process dispatcher */
870 static int dispatch_count = 0;
872 if (LWP_TraceProcesses > 0) {
873 for (i = 0; i < MAX_PRIORITIES; i++) {
874 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
875 for_all_elts(p, runnable[i], {
876 printf(" \"%s\"", p->name);
881 printf("[Blocked (%d):", blocked.count);
882 for_all_elts(p, blocked, {
883 printf(" \"%s\"", p->name);
887 printf("[Qwaiting (%d):", qwaiting.count);
888 for_all_elts(p, qwaiting, {
889 printf(" \"%s\"", p->name);
896 /* Check for stack overflowif this lwp has a stack. Check for
897 * the guard word at the front of the stack being damaged and
898 * for the stack pointer being below the front of the stack.
899 * WARNING! This code assumes that stacks grow downward. */
900 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
901 /* Fix this (stackcheck at other end of stack?) */
902 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
903 && (lwp_cpptr->stackcheck !=
904 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
905 || lwp_cpptr->context.topstack >
906 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
908 if (lwp_cpptr && lwp_cpptr->stack
909 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
910 || lwp_cpptr->context.topstack < lwp_cpptr->stack
911 || lwp_cpptr->context.topstack >
912 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
914 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
915 *(int *)lwp_cpptr->stack);
916 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
917 lwp_cpptr->context.topstack, lwp_cpptr->stack,
918 lwp_cpptr->stacksize);
920 switch (lwp_overflowAction) {
929 lwp_overflowAction = LWP_SOQUIET;
934 /* Move head of current runnable queue forward if current LWP is still in it. */
935 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
936 runnable[lwp_cpptr->priority].head =
937 runnable[lwp_cpptr->priority].head->next;
938 /* Find highest priority with runnable processes. */
939 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
940 if (runnable[i].head != NULL)
944 Abort_LWP("No READY processes");
947 if (LWP_TraceProcesses > 0)
948 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
949 runnable[i].head, runnable[i].head->name);
952 Abort_LWP("PRE_Block not 1");
953 lwp_cpptr = runnable[i].head;
955 returnto(&lwp_cpptr->context);
958 /* Complain of a stack overflow to stderr without using stdio. */
960 Overflow_Complain(void)
964 char *msg1 = " LWP: stack overflow in process ";
967 currenttime = time(0);
968 timeStamp = ctime(¤ttime);
970 write(2, timeStamp, strlen(timeStamp));
972 write(2, msg1, strlen(msg1));
973 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
974 write(2, msg2, strlen(msg2));
978 Dispose_of_Dead_PCB(PROCESS cur)
980 Debug(4, ("Entered Dispose_of_Dead_PCB"));
984 Internal_Signal(cur);
995 Free_PCB(PROCESS pid)
997 Debug(4, ("Entered Free_PCB"));
998 if (pid->stack != NULL) {
1000 ("HWM stack usage: %d, [PCB at 0x%x]",
1001 Stack_Used(pid->stack, pid->stacksize), pid));
1004 if (pid->eventlist != NULL)
1005 free(pid->eventlist);
1010 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1011 int (*ep) (), void *parm, char *name)
1015 Debug(4, ("Entered Initialize_PCB"));
1017 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1019 temp->name[31] = '\0';
1020 temp->status = READY;
1021 temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
1022 temp->eventlistsize = EVINITSIZE;
1026 temp->blockflag = 0;
1027 temp->iomgrRequest = 0;
1028 temp->priority = priority;
1029 temp->index = lwp_nextindex++;
1030 temp->stack = stack;
1031 temp->stacksize = stacksize;
1032 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1033 if (temp->stack != NULL)
1034 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1036 if (temp->stack != NULL)
1037 temp->stackcheck = *(int *)(temp->stack);
1041 temp->misc = NULL; /* currently unused */
1044 temp->lwp_rused = 0;
1045 temp->level = 1; /* non-preemptable */
1049 Internal_Signal(register char *event)
1051 int rc = LWP_ENOWAIT;
1054 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1058 return LWP_EBADEVENT;
1059 for_all_elts(temp, blocked, {
1060 if (temp->status == WAITING)
1061 for (i = 0; i < temp->eventcnt; i++) {
1062 if (temp->eventlist[i] == event) {
1063 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1064 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1065 if (--temp->waitcnt == 0) {
1066 temp->status = READY; temp->wakevent = i + 1;
1067 move(temp, &blocked, &runnable[temp->priority]); break;}
1075 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1076 #define STACKMAGIC 0xBADBADBA
1078 Initialize_Stack(char *stackptr, int stacksize)
1082 Debug(4, ("Entered Initialize_Stack"));
1083 if (lwp_stackUseEnabled)
1084 for (i = 0; i < stacksize; i++)
1085 stackptr[i] = i & 0xff;
1087 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1088 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1090 *(afs_int32 *) stackptr = STACKMAGIC;
1096 Stack_Used(register char *stackptr, int stacksize)
1100 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1101 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1104 for (i = stacksize - 1; i >= 0; i--)
1105 if ((unsigned char)stackptr[i] != (i & 0xff))
1110 if (*(afs_int32 *) stackptr == STACKMAGIC)
1113 for (i = 0; i < stacksize; i++)
1114 if ((unsigned char)stackptr[i] != (i & 0xff))
1115 return (stacksize - i);
1123 LWP_NewRock(int Tag, char *Value)
1124 /* Finds a free rock and sets its value to Value.
1126 * LWP_SUCCESS Rock did not exist and a new one was used
1127 * LWP_EBADROCK Rock already exists.
1128 * LWP_ENOROCKS All rocks are in use.
1130 * From the above semantics, you can only set a rock value once. This is specifically
1131 * to prevent multiple users of the LWP package from accidentally using the same Tag
1132 * value and clobbering others. You can always use one level of indirection to obtain
1133 * a rock whose contents can change.
1137 register struct rock *ra; /* rock array */
1139 ra = lwp_cpptr->lwp_rlist;
1141 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1142 if (ra[i].tag == Tag)
1143 return (LWP_EBADROCK);
1145 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1146 ra[lwp_cpptr->lwp_rused].tag = Tag;
1147 ra[lwp_cpptr->lwp_rused].value = Value;
1148 lwp_cpptr->lwp_rused++;
1149 return (LWP_SUCCESS);
1151 return (LWP_ENOROCKS);
1156 LWP_GetRock(int Tag, char **Value)
1157 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1159 * LWP_SUCCESS if specified rock exists and Value has been filled
1160 * LWP_EBADROCK rock specified does not exist
1164 register struct rock *ra;
1166 ra = lwp_cpptr->lwp_rlist;
1168 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1169 if (ra[i].tag == Tag) {
1170 *Value = ra[i].value;
1171 return (LWP_SUCCESS);
1173 return (LWP_EBADROCK);
1177 #ifdef AFS_AIX32_ENV
1179 setlim(int limcon, uchar_t hard, int limit)
1183 (void)getrlimit(limcon, &rlim);
1185 limit = limit * 1024;
1187 rlim.rlim_max = limit;
1188 else if (limit == RLIM_INFINITY && geteuid() != 0)
1189 rlim.rlim_cur = rlim.rlim_max;
1191 rlim.rlim_cur = limit;
1193 /* Must use ulimit() due to Posix constraints */
1194 if (limcon == RLIMIT_FSIZE) {
1197 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1198 printf("Can't %s%s limit\n",
1199 limit == RLIM_INFINITY ? "remove" : "set",
1200 hard ? " hard" : "");
1204 if (setrlimit(limcon, &rlim) < 0) {
1206 printf("Can't %s%s limit\n",
1207 limit == RLIM_INFINITY ? "remove" : "set",
1208 hard ? " hard" : "");
1218 * Print the specific limit out
1221 plim(char *name, afs_int32 lc, uchar_t hard)
1226 printf("%s \t", name);
1227 (void)getrlimit(lc, &rlim);
1228 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1229 if (lim == RLIM_INFINITY)
1230 printf("unlimited");
1231 printf("%d %s", lim / 1024, "kbytes");
1239 LWP_NoYieldSignal(char *event)
1241 return (LWP_INTERNALSIGNAL(event, 0));
1245 LWP_SignalProcess(char *event)
1247 return (LWP_INTERNALSIGNAL(event, 1));
1252 #ifdef USE_SOLARIS_THREADS
1255 #include "pthread.h"
1260 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1262 PROCESS lwp_process_list; /* List of LWP initiated threads */
1264 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1266 #define CHECK check(__LINE__);
1268 typedef struct event {
1269 struct event *next; /* next in hash chain */
1270 char *event; /* lwp event: an address */
1271 int refcount; /* Is it in use? */
1272 pthread_cond_t cond; /* Currently associated condition variable */
1273 int seq; /* Sequence number: this is incremented
1274 * by wakeup calls; wait will not return until
1278 #define HASHSIZE 127
1279 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1280 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1282 #if CMA_DEBUG || DEBUGF
1284 lwp_process_string(void)
1286 static char id[200];
1288 LWP_CurrentProcess(&p);
1289 sprintf(id, "PID %x <%s>", p, p->name);
1295 lwp_unimplemented(char *interface)
1298 "cmalwp: %s is not currently implemented: program aborted\n",
1304 lwpabort(char *interface)
1306 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1313 lwp_unimplemented("LWP_QWait");
1317 LWP_QSignal(int pid)
1319 lwp_unimplemented("LWP_QSignal");
1322 /* Allocate and initialize an LWP process handle. The associated pthread handle
1323 * must be added by the caller, and the structure threaded onto the LWP active
1324 * process list by lwp_thread_process */
1326 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1329 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1330 memset((char *)lp, 0, sizeof(*lp));
1334 sprintf(temp, "unnamed_process_%04d", ++procnum);
1335 assert(name = (char *)malloc(strlen(temp) + 1));
1344 /* Thread the LWP process descriptor *lp onto the lwp active process list
1345 * and associate a back pointer to the process descriptor from the associated
1348 lwp_thread_process(PROCESS lp)
1350 lp->next = lwp_process_list;
1351 lwp_process_list = lp;
1352 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1355 /* The top-level routine used as entry point to explicitly created LWP
1356 * processes. This completes a few details of process creation left
1357 * out by LWP_CreateProcess and calls the user-specified entry point */
1359 lwp_top_level(pthread_addr_t argp)
1361 PROCESS lp = (PROCESS) argp;
1363 assert(!pthread_mutex_lock(&lwp_mutex));
1364 lwp_thread_process(lp);
1366 assert(!pthread_mutex_unlock(&lwp_mutex));
1367 /* Should cleanup state */
1371 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1372 void *parm, char *name, PROCESS * pid)
1375 pthread_attr_t attr;
1379 #ifndef LWP_NO_PRIORITIES
1380 if (!cmalwp_pri_inrange(priority))
1383 assert(!pthread_attr_create(&attr));
1384 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1386 assert(!pthread_attr_setstacksize(&attr, stacksize));
1388 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1389 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1390 #ifndef LWP_NO_PRIORITIES
1391 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1394 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1395 (pthread_addr_t) parm);
1397 /* allow new thread to run if higher priority */
1398 assert(!pthread_mutex_unlock(&lwp_mutex));
1399 /* process is only added to active list after first time it runs (it adds itself) */
1401 pthread_create(&lp->handle, attr,
1402 (pthread_startroutine_t) lwp_top_level,
1403 (pthread_addr_t) lp);
1404 assert(!pthread_attr_delete(&attr));
1405 assert(!pthread_mutex_lock(&lwp_mutex));
1415 LWP_ActiveProcess(void)
1416 { /* returns pid of current process */
1418 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1423 LWP_CurrentProcess(PROCESS * pid)
1424 { /* get pid of current process */
1425 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1430 LWP_DestroyProcess(PROCESS pid)
1431 { /* destroy a lightweight process */
1432 lwp_unimplemented("LWP_DestroyProcess");
1436 LWP_DispatchProcess(void)
1437 { /* explicit voluntary preemption */
1438 assert(!pthread_mutex_unlock(&lwp_mutex));
1440 assert(!pthread_mutex_lock(&lwp_mutex));
1445 lwp_process_key_destructor(void)
1450 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1452 static int initialized = 0;
1462 #ifndef LWP_NO_PRIORITIES
1463 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1467 /* Create pthread key to associate LWP process descriptor with each
1468 * LWP-created thread */
1469 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1470 lwp_process_key_destructor));
1472 lp = lwp_alloc_process("main process", main, 0);
1473 lp->handle = pthread_self();
1474 lwp_thread_process(lp);
1475 #ifndef LWP_NO_PRIORITIES
1476 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1477 cmalwp_lwppri_to_cmapri(priority));
1480 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1481 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1488 LWP_TerminateProcessSupport(void)
1489 { /* terminate all LWP support */
1490 lwp_unimplemented("LWP_TerminateProcessSupport");
1493 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1495 getevent(char *event)
1497 event_t *evp, *newp;
1500 hashcode = hash(event);
1501 evp = hashtable[hashcode];
1504 if (evp->event == event) {
1508 if (evp->refcount == 0)
1513 newp = (event_t *) malloc(sizeof(event_t));
1515 newp->next = hashtable[hashcode];
1516 hashtable[hashcode] = newp;
1517 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1520 newp->event = event;
1525 /* Release the specified event */
1526 #define relevent(evp) ((evp)->refcount--)
1529 LWP_WaitProcess(char *event)
1530 { /* wait on a single event */
1533 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1535 return LWP_EBADEVENT;
1536 ev = getevent(event);
1538 while (seq == ev->seq) {
1539 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1541 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1547 LWP_MwaitProcess(int wcount, char *evlist[])
1548 { /* wait on m of n events */
1549 lwp_unimplemented("LWP_MWaitProcess");
1553 LWP_NoYieldSignal(char *event)
1556 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1558 return LWP_EBADEVENT;
1559 ev = getevent(event);
1560 if (ev->refcount > 1) {
1562 assert(pthread_cond_broadcast(&ev->cond) == 0);
1569 LWP_SignalProcess(char *event)
1572 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1574 return LWP_EBADEVENT;
1575 ev = getevent(event);
1576 if (ev->refcount > 1) {
1578 assert(!pthread_mutex_unlock(&lwp_mutex));
1579 assert(!pthread_cond_broadcast(&ev->cond));
1581 assert(!pthread_mutex_lock(&lwp_mutex));
1588 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1590 lwp_unimplemented("LWP_StackUsed");
1594 LWP_NewRock(int Tag, char *Value)
1596 lwp_unimplemented("LWP_NewRock");
1600 LWP_GetRock(int Tag, char **Value)
1602 lwp_unimplemented("LWP_GetRock");
1606 LWP_GetProcessPriority(PROCESS pid, int *priority)
1607 { /* returns process priority */
1608 lwp_unimplemented("LWP_GetProcessPriority");
1611 #endif /* USE_PTHREADS */