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;
284 #if defined(AFS_LWP_MINSTACKSIZE)
286 * on some systems (e.g. hpux), a minimum usable stack size has
289 if (stacksize < lwp_MinStackSize) {
290 stacksize = lwp_MinStackSize;
292 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
293 /* more stack size computations; keep track of for IOMGR */
294 if (lwp_MaxStackSeen < stacksize)
295 lwp_MaxStackSeen = stacksize;
297 Debug(0, ("Entered LWP_CreateProcess"));
298 /* Throw away all dead process control blocks */
301 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
306 if (stacksize < MINSTACK)
310 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
314 * The following signal action for AIX is necessary so that in case of a
315 * crash (i.e. core is generated) we can include the user's data section
316 * in the core dump. Unfortunately, by default, only a partial core is
317 * generated which, in many cases, isn't too useful.
319 * We also do it here in case the main program forgets to do it.
321 struct sigaction nsa;
322 extern uid_t geteuid();
324 sigemptyset(&nsa.sa_mask);
325 nsa.sa_handler = SIG_DFL;
326 nsa.sa_flags = SA_FULLDUMP;
327 sigaction(SIGABRT, &nsa, NULL);
328 sigaction(SIGSEGV, &nsa, NULL);
331 * First we need to increase the default resource limits,
332 * if necessary, so that we can guarantee that we have the
333 * resources to create the core file, but we can't always
334 * do it as an ordinary user.
337 /* vos dump causes problems */
338 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
339 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
340 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
343 * Now reserve in one scoop all the stack space that will be used
344 * by the particular application's main (i.e. non-lwp) body. This
345 * is plenty space for any of our applications.
347 stackptr = reserveFromStack(lwp_MaxStackSize);
349 stackptr -= stacksize;
350 stackmemory = stackptr;
352 if ((stackmemory = (char *)malloc(stacksize + 7)) == NULL) {
356 /* Round stack pointer to byte boundary */
357 stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
359 if (priority < 0 || priority >= MAX_PRIORITIES) {
363 Initialize_Stack(stackptr, stacksize);
364 Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
365 insert(temp, &runnable[priority]);
368 Abort_LWP("PRE_Block not 0");
370 /* Gross hack: beware! */
373 #if defined(AFS_PARISC_LINUX24_ENV)
374 savecontext(Create_Process_Part2, &temp2->context,
375 stackptr + MINFRAME);
378 savecontext(Create_Process_Part2, &temp2->context,
379 stackptr + MINFRAME);
381 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
382 /* Need to have the sp on an 8-byte boundary for storing doubles. */
383 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16); /* 16 = 2 * jmp_buf_type */
385 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
386 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40); /* lomgjmp does something
389 #if defined(AFS_S390_LINUX20_ENV)
390 savecontext(Create_Process_Part2, &temp2->context,
391 stackptr + stacksize - MINFRAME);
392 #else /* !AFS_S390_LINUX20_ENV */
393 savecontext(Create_Process_Part2, &temp2->context,
394 stackptr + stacksize - sizeof(void *));
395 #endif /* AFS_S390_LINUX20_ENV */
396 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
397 #endif /* AFS_SGI62_ENV */
400 /* End of gross hack */
411 LWP_CreateProcess2(int (*ep) (), int stacksize, int priority, void *parm,
412 char *name, PROCESS * pid)
417 #if defined(AFS_LWP_MINSTACKSIZE)
419 * on some systems (e.g. hpux), a minimum usable stack size has
422 if (stacksize < lwp_MinStackSize) {
423 stacksize = lwp_MinStackSize;
425 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
426 /* more stack size computations; keep track of for IOMGR */
427 if (lwp_MaxStackSeen < stacksize)
428 lwp_MaxStackSeen = stacksize;
430 Debug(0, ("Entered LWP_CreateProcess"));
431 /* Throw away all dead process control blocks */
434 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
439 if (stacksize < MINSTACK)
443 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
444 if ((stackptr = (char *)malloc(stacksize)) == NULL) {
448 if (priority < 0 || priority >= MAX_PRIORITIES) {
452 Initialize_Stack(stackptr, stacksize);
453 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
454 insert(temp, &runnable[priority]);
457 Abort_LWP("PRE_Block not 0");
459 /* Gross hack: beware! */
462 savecontext(Create_Process_Part2, &temp2->context,
463 stackptr + stacksize - sizeof(void *));
464 /* End of gross hack */
475 LWP_CurrentProcess(PROCESS * pid)
476 { /* returns pid of current process */
477 Debug(0, ("Entered Current_Process"));
488 Debug(0, ("Entered ThreadId"));
495 #define LWPANCHOR (*lwp_init)
498 LWP_DestroyProcess(PROCESS pid)
499 { /* destroy a lightweight process */
502 Debug(0, ("Entered Destroy_Process"));
504 if (lwp_cpptr != pid) {
505 Dispose_of_Dead_PCB(pid);
508 pid->status = DESTROYED;
509 move(pid, &runnable[pid->priority], &blocked);
511 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
512 savecontext(Dispatcher, &(temp->context),
513 &(LWPANCHOR.dsptchstack[MINFRAME]));
514 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
515 savecontext(Dispatcher, &(temp->context),
517 dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
518 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
519 savecontext(Dispatcher, &(temp->context),
521 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
523 #elif defined(AFS_S390_LINUX20_ENV)
524 savecontext(Dispatcher, &(temp->context),
526 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
529 savecontext(Dispatcher, &(temp->context),
531 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
541 LWP_DispatchProcess(void)
542 { /* explicit voluntary preemption */
543 Debug(2, ("Entered Dispatch_Process"));
557 for (i = 0; i < MAX_PRIORITIES; i++)
558 for_all_elts(x, runnable[i], {
559 printf("[Priority %d]\n", i);
563 for_all_elts(x, blocked, {
564 Dump_One_Process(x);}
566 for_all_elts(x, qwaiting, {
567 Dump_One_Process(x);}
570 printf("***LWP: LWP support not initialized\n");
576 LWP_GetProcessPriority(PROCESS pid, int *priority)
577 { /* returns process priority */
578 Debug(0, ("Entered Get_Process_Priority"));
580 *priority = pid->priority;
587 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
590 struct lwp_pcb dummy;
594 Debug(0, ("Entered LWP_InitializeProcessSupport"));
595 if (lwp_init != NULL)
598 /* Set up offset for stack checking -- do this as soon as possible */
599 stack_offset = (char *)&dummy.stack - (char *)&dummy;
601 if (priority >= MAX_PRIORITIES)
603 for (i = 0; i < MAX_PRIORITIES; i++) {
604 runnable[i].head = NULL;
605 runnable[i].count = 0;
609 qwaiting.head = NULL;
611 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
612 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
613 if (lwp_init == NULL || temp == NULL)
614 Abort_LWP("Insufficient Storage to Initialize LWP Support");
615 LWPANCHOR.processcnt = 1;
616 LWPANCHOR.outerpid = temp;
617 LWPANCHOR.outersp = NULL;
618 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
619 "Main Process [created by LWP]");
620 insert(temp, &runnable[priority]);
621 savecontext(Dispatcher, &temp->context, NULL);
622 LWPANCHOR.outersp = temp->context.topstack;
626 /* get minimum stack size from the environment. this allows the administrator
627 * to change the lwp stack dynamically without getting a new binary version.
629 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
630 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
633 (AFS_LWP_MINSTACKSIZE >
634 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
640 LWP_INTERNALSIGNAL(char *event, int yield)
641 { /* signal the occurence of an event */
642 Debug(2, ("Entered LWP_SignalProcess"));
645 rc = Internal_Signal(event);
654 LWP_TerminateProcessSupport(void)
655 { /* terminate all LWP support */
658 Debug(0, ("Entered Terminate_Process_Support"));
659 if (lwp_init == NULL)
661 if (lwp_cpptr != LWPANCHOR.outerpid)
662 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
663 for (i = 0; i < MAX_PRIORITIES; i++)
664 for_all_elts(cur, runnable[i], {
667 for_all_elts(cur, blocked, {
670 for_all_elts(cur, qwaiting, {
679 LWP_WaitProcess(char *event)
680 { /* wait on a single event */
683 Debug(2, ("Entered Wait_Process"));
685 return LWP_EBADEVENT;
688 return LWP_MwaitProcess(1, tempev);
692 LWP_MwaitProcess(int wcount, char *evlist[])
693 { /* wait on m of n events */
694 register int ecount, i;
697 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
699 if (evlist == NULL) {
701 return LWP_EBADCOUNT;
704 for (ecount = 0; evlist[ecount] != NULL; ecount++);
708 return LWP_EBADCOUNT;
713 if (wcount > ecount || wcount < 0) {
715 return LWP_EBADCOUNT;
717 if (ecount > lwp_cpptr->eventlistsize) {
719 lwp_cpptr->eventlist =
720 (char **)realloc(lwp_cpptr->eventlist,
721 ecount * sizeof(char *));
722 lwp_cpptr->eventlistsize = ecount;
724 for (i = 0; i < ecount; i++)
725 lwp_cpptr->eventlist[i] = evlist[i];
727 lwp_cpptr->status = WAITING;
729 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
732 lwp_cpptr->wakevent = 0;
733 lwp_cpptr->waitcnt = wcount;
734 lwp_cpptr->eventcnt = ecount;
745 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
747 *maxa = pid->stacksize;
748 *used = Stack_Used(pid->stack, *maxa);
755 * The following functions are strictly
756 * INTERNAL to the LWP support package.
762 struct lwp_context tempcontext;
764 Debug(0, ("Entered Abort_LWP"));
765 printf("***LWP: %s\n", msg);
766 printf("***LWP: Abort --- dumping PCBs ...\n");
770 if (LWPANCHOR.outersp == NULL)
773 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
778 Create_Process_Part2(void)
779 { /* creates a context for the new process */
782 Debug(2, ("Entered Create_Process_Part2"));
783 temp = lwp_cpptr; /* Get current process id */
784 savecontext(Dispatcher, &temp->context, NULL);
785 (*temp->ep) (temp->parm);
786 LWP_DestroyProcess(temp);
791 Delete_PCB(register PROCESS pid)
792 { /* remove a PCB from the process list */
793 Debug(4, ("Entered Delete_PCB"));
795 (pid->blockflag || pid->status == WAITING
797 DESTROYED ? &blocked :
798 (pid->status == QWAITING) ? &qwaiting :
799 &runnable[pid->priority]));
800 LWPANCHOR.processcnt--;
806 Dump_One_Process(PROCESS pid)
810 printf("***LWP: Process Control Block at 0x%x\n", pid);
811 printf("***LWP: Name: %s\n", pid->name);
813 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
815 printf("BLOCKED and ");
816 switch (pid->status) {
833 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
835 if (pid->stacksize != 0) {
836 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
837 pid->stacksize, pid->stack);
838 printf("***LWP: HWM stack usage: ");
839 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
841 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
842 if (pid->eventcnt > 0) {
843 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
844 printf("***LWP: Event id list:");
845 for (i = 0; i < pid->eventcnt; i++)
846 printf(" 0x%x", pid->eventlist[i]);
849 if (pid->wakevent > 0)
850 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
856 purge_dead_pcbs(void)
858 for_all_elts(cur, blocked, {
859 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
864 int LWP_TraceProcesses = 0;
868 { /* Lightweight process dispatcher */
871 static int dispatch_count = 0;
873 if (LWP_TraceProcesses > 0) {
874 for (i = 0; i < MAX_PRIORITIES; i++) {
875 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
876 for_all_elts(p, runnable[i], {
877 printf(" \"%s\"", p->name);
882 printf("[Blocked (%d):", blocked.count);
883 for_all_elts(p, blocked, {
884 printf(" \"%s\"", p->name);
888 printf("[Qwaiting (%d):", qwaiting.count);
889 for_all_elts(p, qwaiting, {
890 printf(" \"%s\"", p->name);
897 /* Check for stack overflowif this lwp has a stack. Check for
898 * the guard word at the front of the stack being damaged and
899 * for the stack pointer being below the front of the stack.
900 * WARNING! This code assumes that stacks grow downward. */
901 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
902 /* Fix this (stackcheck at other end of stack?) */
903 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
904 && (lwp_cpptr->stackcheck !=
905 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
906 || lwp_cpptr->context.topstack >
907 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
909 if (lwp_cpptr && lwp_cpptr->stack
910 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
911 || lwp_cpptr->context.topstack < lwp_cpptr->stack
912 || lwp_cpptr->context.topstack >
913 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
915 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
916 *(int *)lwp_cpptr->stack);
917 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
918 lwp_cpptr->context.topstack, lwp_cpptr->stack,
919 lwp_cpptr->stacksize);
921 switch (lwp_overflowAction) {
930 lwp_overflowAction = LWP_SOQUIET;
935 /* Move head of current runnable queue forward if current LWP is still in it. */
936 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
937 runnable[lwp_cpptr->priority].head =
938 runnable[lwp_cpptr->priority].head->next;
939 /* Find highest priority with runnable processes. */
940 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
941 if (runnable[i].head != NULL)
945 Abort_LWP("No READY processes");
948 if (LWP_TraceProcesses > 0)
949 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
950 runnable[i].head, runnable[i].head->name);
953 Abort_LWP("PRE_Block not 1");
954 lwp_cpptr = runnable[i].head;
956 returnto(&lwp_cpptr->context);
959 /* Complain of a stack overflow to stderr without using stdio. */
961 Overflow_Complain(void)
965 char *msg1 = " LWP: stack overflow in process ";
968 currenttime = time(0);
969 timeStamp = ctime(¤ttime);
971 write(2, timeStamp, strlen(timeStamp));
973 write(2, msg1, strlen(msg1));
974 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
975 write(2, msg2, strlen(msg2));
979 Dispose_of_Dead_PCB(PROCESS cur)
981 Debug(4, ("Entered Dispose_of_Dead_PCB"));
985 Internal_Signal(cur);
996 Free_PCB(PROCESS pid)
998 Debug(4, ("Entered Free_PCB"));
999 if (pid->stack != NULL) {
1001 ("HWM stack usage: %d, [PCB at 0x%x]",
1002 Stack_Used(pid->stack, pid->stacksize), pid));
1003 #ifndef AFS_AIX32_ENV
1007 if (pid->eventlist != NULL)
1008 free(pid->eventlist);
1013 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1014 int (*ep) (), void *parm, char *name)
1018 Debug(4, ("Entered Initialize_PCB"));
1020 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1022 temp->name[31] = '\0';
1023 temp->status = READY;
1024 temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
1025 temp->eventlistsize = EVINITSIZE;
1029 temp->blockflag = 0;
1030 temp->iomgrRequest = 0;
1031 temp->priority = priority;
1032 temp->index = lwp_nextindex++;
1033 temp->stack = stack;
1034 temp->stacksize = stacksize;
1035 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1036 if (temp->stack != NULL)
1037 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1039 if (temp->stack != NULL)
1040 temp->stackcheck = *(int *)(temp->stack);
1044 temp->misc = NULL; /* currently unused */
1047 temp->lwp_rused = 0;
1048 temp->level = 1; /* non-preemptable */
1052 Internal_Signal(register char *event)
1054 int rc = LWP_ENOWAIT;
1057 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1061 return LWP_EBADEVENT;
1062 for_all_elts(temp, blocked, {
1063 if (temp->status == WAITING)
1064 for (i = 0; i < temp->eventcnt; i++) {
1065 if (temp->eventlist[i] == event) {
1066 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1067 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1068 if (--temp->waitcnt == 0) {
1069 temp->status = READY; temp->wakevent = i + 1;
1070 move(temp, &blocked, &runnable[temp->priority]); break;}
1078 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1079 #define STACKMAGIC 0xBADBADBA
1081 Initialize_Stack(char *stackptr, int stacksize)
1085 Debug(4, ("Entered Initialize_Stack"));
1086 if (lwp_stackUseEnabled)
1087 for (i = 0; i < stacksize; i++)
1088 stackptr[i] = i & 0xff;
1090 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1091 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1093 *(afs_int32 *) stackptr = STACKMAGIC;
1099 Stack_Used(register char *stackptr, int stacksize)
1103 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1104 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1107 for (i = stacksize - 1; i >= 0; i--)
1108 if ((unsigned char)stackptr[i] != (i & 0xff))
1113 if (*(afs_int32 *) stackptr == STACKMAGIC)
1116 for (i = 0; i < stacksize; i++)
1117 if ((unsigned char)stackptr[i] != (i & 0xff))
1118 return (stacksize - i);
1126 LWP_NewRock(int Tag, char *Value)
1127 /* Finds a free rock and sets its value to Value.
1129 * LWP_SUCCESS Rock did not exist and a new one was used
1130 * LWP_EBADROCK Rock already exists.
1131 * LWP_ENOROCKS All rocks are in use.
1133 * From the above semantics, you can only set a rock value once. This is specifically
1134 * to prevent multiple users of the LWP package from accidentally using the same Tag
1135 * value and clobbering others. You can always use one level of indirection to obtain
1136 * a rock whose contents can change.
1140 register struct rock *ra; /* rock array */
1142 ra = lwp_cpptr->lwp_rlist;
1144 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1145 if (ra[i].tag == Tag)
1146 return (LWP_EBADROCK);
1148 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1149 ra[lwp_cpptr->lwp_rused].tag = Tag;
1150 ra[lwp_cpptr->lwp_rused].value = Value;
1151 lwp_cpptr->lwp_rused++;
1152 return (LWP_SUCCESS);
1154 return (LWP_ENOROCKS);
1159 LWP_GetRock(int Tag, char **Value)
1160 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1162 * LWP_SUCCESS if specified rock exists and Value has been filled
1163 * LWP_EBADROCK rock specified does not exist
1167 register struct rock *ra;
1169 ra = lwp_cpptr->lwp_rlist;
1171 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1172 if (ra[i].tag == Tag) {
1173 *Value = ra[i].value;
1174 return (LWP_SUCCESS);
1176 return (LWP_EBADROCK);
1180 #ifdef AFS_AIX32_ENV
1182 setlim(int limcon, uchar_t hard, int limit)
1186 (void)getrlimit(limcon, &rlim);
1188 limit = limit * 1024;
1190 rlim.rlim_max = limit;
1191 else if (limit == RLIM_INFINITY && geteuid() != 0)
1192 rlim.rlim_cur = rlim.rlim_max;
1194 rlim.rlim_cur = limit;
1196 /* Must use ulimit() due to Posix constraints */
1197 if (limcon == RLIMIT_FSIZE) {
1200 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1201 printf("Can't %s%s limit\n",
1202 limit == RLIM_INFINITY ? "remove" : "set",
1203 hard ? " hard" : "");
1207 if (setrlimit(limcon, &rlim) < 0) {
1209 printf("Can't %s%s limit\n",
1210 limit == RLIM_INFINITY ? "remove" : "set",
1211 hard ? " hard" : "");
1221 * Print the specific limit out
1224 plim(char *name, afs_int32 lc, uchar_t hard)
1229 printf("%s \t", name);
1230 (void)getrlimit(lc, &rlim);
1231 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1232 if (lim == RLIM_INFINITY)
1233 printf("unlimited");
1234 printf("%d %s", lim / 1024, "kbytes");
1242 LWP_NoYieldSignal(char *event)
1244 return (LWP_INTERNALSIGNAL(event, 0));
1248 LWP_SignalProcess(char *event)
1250 return (LWP_INTERNALSIGNAL(event, 1));
1255 #ifdef USE_SOLARIS_THREADS
1258 #include "pthread.h"
1263 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1265 PROCESS lwp_process_list; /* List of LWP initiated threads */
1267 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1269 #define CHECK check(__LINE__);
1271 typedef struct event {
1272 struct event *next; /* next in hash chain */
1273 char *event; /* lwp event: an address */
1274 int refcount; /* Is it in use? */
1275 pthread_cond_t cond; /* Currently associated condition variable */
1276 int seq; /* Sequence number: this is incremented
1277 * by wakeup calls; wait will not return until
1281 #define HASHSIZE 127
1282 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1283 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1285 #if CMA_DEBUG || DEBUGF
1287 lwp_process_string(void)
1289 static char id[200];
1291 LWP_CurrentProcess(&p);
1292 sprintf(id, "PID %x <%s>", p, p->name);
1298 lwp_unimplemented(char *interface)
1301 "cmalwp: %s is not currently implemented: program aborted\n",
1307 lwpabort(char *interface)
1309 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1316 lwp_unimplemented("LWP_QWait");
1320 LWP_QSignal(int pid)
1322 lwp_unimplemented("LWP_QSignal");
1325 /* Allocate and initialize an LWP process handle. The associated pthread handle
1326 * must be added by the caller, and the structure threaded onto the LWP active
1327 * process list by lwp_thread_process */
1329 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1332 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1333 memset((char *)lp, 0, sizeof(*lp));
1337 sprintf(temp, "unnamed_process_%04d", ++procnum);
1338 assert(name = (char *)malloc(strlen(temp) + 1));
1347 /* Thread the LWP process descriptor *lp onto the lwp active process list
1348 * and associate a back pointer to the process descriptor from the associated
1351 lwp_thread_process(PROCESS lp)
1353 lp->next = lwp_process_list;
1354 lwp_process_list = lp;
1355 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1358 /* The top-level routine used as entry point to explicitly created LWP
1359 * processes. This completes a few details of process creation left
1360 * out by LWP_CreateProcess and calls the user-specified entry point */
1362 lwp_top_level(pthread_addr_t argp)
1364 PROCESS lp = (PROCESS) argp;
1366 assert(!pthread_mutex_lock(&lwp_mutex));
1367 lwp_thread_process(lp);
1369 assert(!pthread_mutex_unlock(&lwp_mutex));
1370 /* Should cleanup state */
1374 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1375 void *parm, char *name, PROCESS * pid)
1378 pthread_attr_t attr;
1382 #ifndef LWP_NO_PRIORITIES
1383 if (!cmalwp_pri_inrange(priority))
1386 assert(!pthread_attr_create(&attr));
1387 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1389 assert(!pthread_attr_setstacksize(&attr, stacksize));
1391 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1392 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1393 #ifndef LWP_NO_PRIORITIES
1394 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1397 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1398 (pthread_addr_t) parm);
1400 /* allow new thread to run if higher priority */
1401 assert(!pthread_mutex_unlock(&lwp_mutex));
1402 /* process is only added to active list after first time it runs (it adds itself) */
1404 pthread_create(&lp->handle, attr,
1405 (pthread_startroutine_t) lwp_top_level,
1406 (pthread_addr_t) lp);
1407 assert(!pthread_attr_delete(&attr));
1408 assert(!pthread_mutex_lock(&lwp_mutex));
1418 LWP_ActiveProcess(void)
1419 { /* returns pid of current process */
1421 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1426 LWP_CurrentProcess(PROCESS * pid)
1427 { /* get pid of current process */
1428 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1433 LWP_DestroyProcess(PROCESS pid)
1434 { /* destroy a lightweight process */
1435 lwp_unimplemented("LWP_DestroyProcess");
1439 LWP_DispatchProcess(void)
1440 { /* explicit voluntary preemption */
1441 assert(!pthread_mutex_unlock(&lwp_mutex));
1443 assert(!pthread_mutex_lock(&lwp_mutex));
1448 lwp_process_key_destructor(void)
1453 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1455 static int initialized = 0;
1465 #ifndef LWP_NO_PRIORITIES
1466 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1470 /* Create pthread key to associate LWP process descriptor with each
1471 * LWP-created thread */
1472 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1473 lwp_process_key_destructor));
1475 lp = lwp_alloc_process("main process", main, 0);
1476 lp->handle = pthread_self();
1477 lwp_thread_process(lp);
1478 #ifndef LWP_NO_PRIORITIES
1479 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1480 cmalwp_lwppri_to_cmapri(priority));
1483 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1484 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1491 LWP_TerminateProcessSupport(void)
1492 { /* terminate all LWP support */
1493 lwp_unimplemented("LWP_TerminateProcessSupport");
1496 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1498 getevent(char *event)
1500 event_t *evp, *newp;
1503 hashcode = hash(event);
1504 evp = hashtable[hashcode];
1507 if (evp->event == event) {
1511 if (evp->refcount == 0)
1516 newp = (event_t *) malloc(sizeof(event_t));
1518 newp->next = hashtable[hashcode];
1519 hashtable[hashcode] = newp;
1520 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1523 newp->event = event;
1528 /* Release the specified event */
1529 #define relevent(evp) ((evp)->refcount--)
1532 LWP_WaitProcess(char *event)
1533 { /* wait on a single event */
1536 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1538 return LWP_EBADEVENT;
1539 ev = getevent(event);
1541 while (seq == ev->seq) {
1542 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1544 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1550 LWP_MwaitProcess(int wcount, char *evlist[])
1551 { /* wait on m of n events */
1552 lwp_unimplemented("LWP_MWaitProcess");
1556 LWP_NoYieldSignal(char *event)
1559 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1561 return LWP_EBADEVENT;
1562 ev = getevent(event);
1563 if (ev->refcount > 1) {
1565 assert(pthread_cond_broadcast(&ev->cond) == 0);
1572 LWP_SignalProcess(char *event)
1575 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1577 return LWP_EBADEVENT;
1578 ev = getevent(event);
1579 if (ev->refcount > 1) {
1581 assert(!pthread_mutex_unlock(&lwp_mutex));
1582 assert(!pthread_cond_broadcast(&ev->cond));
1584 assert(!pthread_mutex_lock(&lwp_mutex));
1591 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1593 lwp_unimplemented("LWP_StackUsed");
1597 LWP_NewRock(int Tag, char *Value)
1599 lwp_unimplemented("LWP_NewRock");
1603 LWP_GetRock(int Tag, char **Value)
1605 lwp_unimplemented("LWP_GetRock");
1609 LWP_GetProcessPriority(PROCESS pid, int *priority)
1610 { /* returns process priority */
1611 lwp_unimplemented("LWP_GetProcessPriority");
1614 #endif /* USE_PTHREADS */