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;
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 lwp_remove(tp, &runnable[tp->priority]);
247 register PROCESS pid;
249 if (pid->status == QWAITING) {
251 insert(pid, &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);}
560 printf("***LWP: LWP support not initialized\n");
566 LWP_GetProcessPriority(PROCESS pid, int *priority)
567 { /* returns process priority */
568 Debug(0, ("Entered Get_Process_Priority"));
570 *priority = pid->priority;
577 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
580 struct lwp_pcb dummy;
584 Debug(0, ("Entered LWP_InitializeProcessSupport"));
585 if (lwp_init != NULL)
588 /* Set up offset for stack checking -- do this as soon as possible */
589 stack_offset = (char *)&dummy.stack - (char *)&dummy;
591 if (priority >= MAX_PRIORITIES)
593 for (i = 0; i < MAX_PRIORITIES; i++) {
594 runnable[i].head = NULL;
595 runnable[i].count = 0;
599 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
600 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
601 if (lwp_init == NULL || temp == NULL)
602 Abort_LWP("Insufficient Storage to Initialize LWP Support");
603 LWPANCHOR.processcnt = 1;
604 LWPANCHOR.outerpid = temp;
605 LWPANCHOR.outersp = NULL;
606 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
607 "Main Process [created by LWP]");
608 insert(temp, &runnable[priority]);
609 savecontext(Dispatcher, &temp->context, NULL);
610 LWPANCHOR.outersp = temp->context.topstack;
614 /* get minimum stack size from the environment. this allows the administrator
615 * to change the lwp stack dynamically without getting a new binary version.
617 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
618 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
621 (AFS_LWP_MINSTACKSIZE >
622 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
628 LWP_INTERNALSIGNAL(char *event, int yield)
629 { /* signal the occurence of an event */
630 Debug(2, ("Entered LWP_SignalProcess"));
633 rc = Internal_Signal(event);
642 LWP_TerminateProcessSupport(void)
643 { /* terminate all LWP support */
646 Debug(0, ("Entered Terminate_Process_Support"));
647 if (lwp_init == NULL)
649 if (lwp_cpptr != LWPANCHOR.outerpid)
650 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
651 for (i = 0; i < MAX_PRIORITIES; i++)
652 for_all_elts(cur, runnable[i], {
655 for_all_elts(cur, blocked, {
664 LWP_WaitProcess(char *event)
665 { /* wait on a single event */
668 Debug(2, ("Entered Wait_Process"));
670 return LWP_EBADEVENT;
673 return LWP_MwaitProcess(1, tempev);
677 LWP_MwaitProcess(int wcount, char *evlist[])
678 { /* wait on m of n events */
679 register int ecount, i;
682 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
684 if (evlist == NULL) {
686 return LWP_EBADCOUNT;
689 for (ecount = 0; evlist[ecount] != NULL; ecount++);
693 return LWP_EBADCOUNT;
698 if (wcount > ecount || wcount < 0) {
700 return LWP_EBADCOUNT;
702 if (ecount > lwp_cpptr->eventlistsize) {
704 lwp_cpptr->eventlist =
705 (char **)realloc(lwp_cpptr->eventlist,
706 ecount * sizeof(char *));
707 lwp_cpptr->eventlistsize = ecount;
709 for (i = 0; i < ecount; i++)
710 lwp_cpptr->eventlist[i] = evlist[i];
712 lwp_cpptr->status = WAITING;
714 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
717 lwp_cpptr->wakevent = 0;
718 lwp_cpptr->waitcnt = wcount;
719 lwp_cpptr->eventcnt = ecount;
730 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
732 *maxa = pid->stacksize;
733 *used = Stack_Used(pid->stack, *maxa);
740 * The following functions are strictly
741 * INTERNAL to the LWP support package.
747 struct lwp_context tempcontext;
749 Debug(0, ("Entered Abort_LWP"));
750 printf("***LWP: %s\n", msg);
751 printf("***LWP: Abort --- dumping PCBs ...\n");
755 if (LWPANCHOR.outersp == NULL)
758 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
763 Create_Process_Part2(void)
764 { /* creates a context for the new process */
767 Debug(2, ("Entered Create_Process_Part2"));
768 temp = lwp_cpptr; /* Get current process id */
769 savecontext(Dispatcher, &temp->context, NULL);
770 (*temp->ep) (temp->parm);
771 LWP_DestroyProcess(temp);
776 Delete_PCB(register PROCESS pid)
777 { /* remove a PCB from the process list */
778 Debug(4, ("Entered Delete_PCB"));
780 (pid->blockflag || pid->status == WAITING
782 DESTROYED ? &blocked : &runnable[pid->priority]));
783 LWPANCHOR.processcnt--;
789 Dump_One_Process(PROCESS pid)
793 printf("***LWP: Process Control Block at 0x%x\n", pid);
794 printf("***LWP: Name: %s\n", pid->name);
796 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
798 printf("BLOCKED and ");
799 switch (pid->status) {
813 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
815 if (pid->stacksize != 0) {
816 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
817 pid->stacksize, pid->stack);
818 printf("***LWP: HWM stack usage: ");
819 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
822 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
823 if (pid->eventcnt > 0) {
824 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
825 printf("***LWP: Event id list:");
826 for (i = 0; i < pid->eventcnt; i++)
827 printf(" 0x%x", pid->eventlist[i]);
830 if (pid->wakevent > 0)
831 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
837 purge_dead_pcbs(void)
839 for_all_elts(cur, blocked, {
840 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
845 int LWP_TraceProcesses = 0;
849 { /* Lightweight process dispatcher */
852 static int dispatch_count = 0;
854 if (LWP_TraceProcesses > 0) {
855 for (i = 0; i < MAX_PRIORITIES; i++) {
856 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
857 for_all_elts(p, runnable[i], {
858 printf(" \"%s\"", p->name);
863 printf("[Blocked (%d):", blocked.count);
864 for_all_elts(p, blocked, {
865 printf(" \"%s\"", p->name);
872 /* Check for stack overflowif this lwp has a stack. Check for
873 * the guard word at the front of the stack being damaged and
874 * for the stack pointer being below the front of the stack.
875 * WARNING! This code assumes that stacks grow downward. */
876 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
877 /* Fix this (stackcheck at other end of stack?) */
878 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
879 && (lwp_cpptr->stackcheck !=
880 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
881 || lwp_cpptr->context.topstack >
882 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
884 if (lwp_cpptr && lwp_cpptr->stack
885 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
886 || lwp_cpptr->context.topstack < lwp_cpptr->stack
887 || lwp_cpptr->context.topstack >
888 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
890 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
891 *(int *)lwp_cpptr->stack);
892 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
893 lwp_cpptr->context.topstack, lwp_cpptr->stack,
894 lwp_cpptr->stacksize);
896 switch (lwp_overflowAction) {
905 lwp_overflowAction = LWP_SOQUIET;
910 /* Move head of current runnable queue forward if current LWP is still in it. */
911 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
912 runnable[lwp_cpptr->priority].head =
913 runnable[lwp_cpptr->priority].head->next;
914 /* Find highest priority with runnable processes. */
915 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
916 if (runnable[i].head != NULL)
920 Abort_LWP("No READY processes");
923 if (LWP_TraceProcesses > 0)
924 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
925 runnable[i].head, runnable[i].head->name);
928 Abort_LWP("PRE_Block not 1");
929 lwp_cpptr = runnable[i].head;
931 returnto(&lwp_cpptr->context);
934 /* Complain of a stack overflow to stderr without using stdio. */
936 Overflow_Complain(void)
940 char *msg1 = " LWP: stack overflow in process ";
943 currenttime = time(0);
944 timeStamp = ctime(¤ttime);
946 write(2, timeStamp, strlen(timeStamp));
948 write(2, msg1, strlen(msg1));
949 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
950 write(2, msg2, strlen(msg2));
954 Dispose_of_Dead_PCB(PROCESS cur)
956 Debug(4, ("Entered Dispose_of_Dead_PCB"));
960 Internal_Signal(cur);
971 Free_PCB(PROCESS pid)
973 Debug(4, ("Entered Free_PCB"));
974 if (pid->stack != NULL) {
976 ("HWM stack usage: %d, [PCB at 0x%x]",
977 Stack_Used(pid->stack, pid->stacksize), pid));
980 if (pid->eventlist != NULL)
981 free(pid->eventlist);
986 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
987 int (*ep) (), void *parm, char *name)
991 Debug(4, ("Entered Initialize_PCB"));
993 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
995 temp->name[31] = '\0';
996 temp->status = READY;
997 temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
998 temp->eventlistsize = EVINITSIZE;
1002 temp->blockflag = 0;
1003 temp->iomgrRequest = 0;
1004 temp->priority = priority;
1005 temp->index = lwp_nextindex++;
1006 temp->stack = stack;
1007 temp->stacksize = stacksize;
1008 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1009 if (temp->stack != NULL)
1010 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1012 if (temp->stack != NULL)
1013 temp->stackcheck = *(int *)(temp->stack);
1017 temp->misc = NULL; /* currently unused */
1020 temp->lwp_rused = 0;
1021 temp->level = 1; /* non-preemptable */
1025 Internal_Signal(register char *event)
1027 int rc = LWP_ENOWAIT;
1030 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1034 return LWP_EBADEVENT;
1035 for_all_elts(temp, blocked, {
1036 if (temp->status == WAITING)
1037 for (i = 0; i < temp->eventcnt; i++) {
1038 if (temp->eventlist[i] == event) {
1039 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1040 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1041 if (--temp->waitcnt == 0) {
1042 temp->status = READY; temp->wakevent = i + 1;
1043 move(temp, &blocked, &runnable[temp->priority]); break;}
1051 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1052 #define STACKMAGIC 0xBADBADBA
1054 Initialize_Stack(char *stackptr, int stacksize)
1058 Debug(4, ("Entered Initialize_Stack"));
1059 if (lwp_stackUseEnabled)
1060 for (i = 0; i < stacksize; i++)
1061 stackptr[i] = i & 0xff;
1063 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1064 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1066 *(afs_int32 *) stackptr = STACKMAGIC;
1072 Stack_Used(register char *stackptr, int stacksize)
1076 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1077 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1080 for (i = stacksize - 1; i >= 0; i--)
1081 if ((unsigned char)stackptr[i] != (i & 0xff))
1086 if (*(afs_int32 *) stackptr == STACKMAGIC)
1089 for (i = 0; i < stacksize; i++)
1090 if ((unsigned char)stackptr[i] != (i & 0xff))
1091 return (stacksize - i);
1099 LWP_NewRock(int Tag, char *Value)
1100 /* Finds a free rock and sets its value to Value.
1102 * LWP_SUCCESS Rock did not exist and a new one was used
1103 * LWP_EBADROCK Rock already exists.
1104 * LWP_ENOROCKS All rocks are in use.
1106 * From the above semantics, you can only set a rock value once. This is specifically
1107 * to prevent multiple users of the LWP package from accidentally using the same Tag
1108 * value and clobbering others. You can always use one level of indirection to obtain
1109 * a rock whose contents can change.
1113 register struct rock *ra; /* rock array */
1115 ra = lwp_cpptr->lwp_rlist;
1117 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1118 if (ra[i].tag == Tag)
1119 return (LWP_EBADROCK);
1121 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1122 ra[lwp_cpptr->lwp_rused].tag = Tag;
1123 ra[lwp_cpptr->lwp_rused].value = Value;
1124 lwp_cpptr->lwp_rused++;
1125 return (LWP_SUCCESS);
1127 return (LWP_ENOROCKS);
1132 LWP_GetRock(int Tag, char **Value)
1133 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1135 * LWP_SUCCESS if specified rock exists and Value has been filled
1136 * LWP_EBADROCK rock specified does not exist
1140 register struct rock *ra;
1142 ra = lwp_cpptr->lwp_rlist;
1144 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1145 if (ra[i].tag == Tag) {
1146 *Value = ra[i].value;
1147 return (LWP_SUCCESS);
1149 return (LWP_EBADROCK);
1153 #ifdef AFS_AIX32_ENV
1155 setlim(int limcon, uchar_t hard, int limit)
1159 (void)getrlimit(limcon, &rlim);
1161 limit = limit * 1024;
1163 rlim.rlim_max = limit;
1164 else if (limit == RLIM_INFINITY && geteuid() != 0)
1165 rlim.rlim_cur = rlim.rlim_max;
1167 rlim.rlim_cur = limit;
1169 /* Must use ulimit() due to Posix constraints */
1170 if (limcon == RLIMIT_FSIZE) {
1173 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1174 printf("Can't %s%s limit\n",
1175 limit == RLIM_INFINITY ? "remove" : "set",
1176 hard ? " hard" : "");
1180 if (setrlimit(limcon, &rlim) < 0) {
1182 printf("Can't %s%s limit\n",
1183 limit == RLIM_INFINITY ? "remove" : "set",
1184 hard ? " hard" : "");
1194 * Print the specific limit out
1197 plim(char *name, afs_int32 lc, uchar_t hard)
1202 printf("%s \t", name);
1203 (void)getrlimit(lc, &rlim);
1204 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1205 if (lim == RLIM_INFINITY)
1206 printf("unlimited");
1207 printf("%d %s", lim / 1024, "kbytes");
1215 LWP_NoYieldSignal(char *event)
1217 return (LWP_INTERNALSIGNAL(event, 0));
1221 LWP_SignalProcess(char *event)
1223 return (LWP_INTERNALSIGNAL(event, 1));
1228 #ifdef USE_SOLARIS_THREADS
1231 #include "pthread.h"
1236 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1238 PROCESS lwp_process_list; /* List of LWP initiated threads */
1240 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1242 #define CHECK check(__LINE__);
1244 typedef struct event {
1245 struct event *next; /* next in hash chain */
1246 char *event; /* lwp event: an address */
1247 int refcount; /* Is it in use? */
1248 pthread_cond_t cond; /* Currently associated condition variable */
1249 int seq; /* Sequence number: this is incremented
1250 * by wakeup calls; wait will not return until
1254 #define HASHSIZE 127
1255 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1256 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1258 #if CMA_DEBUG || DEBUGF
1260 lwp_process_string(void)
1262 static char id[200];
1264 LWP_CurrentProcess(&p);
1265 sprintf(id, "PID %x <%s>", p, p->name);
1271 lwp_unimplemented(char *interface)
1274 "cmalwp: %s is not currently implemented: program aborted\n",
1280 lwpabort(char *interface)
1282 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1289 lwp_unimplemented("LWP_QWait");
1293 LWP_QSignal(int pid)
1295 lwp_unimplemented("LWP_QSignal");
1298 /* Allocate and initialize an LWP process handle. The associated pthread handle
1299 * must be added by the caller, and the structure threaded onto the LWP active
1300 * process list by lwp_thread_process */
1302 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1305 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1306 memset((char *)lp, 0, sizeof(*lp));
1310 sprintf(temp, "unnamed_process_%04d", ++procnum);
1311 assert(name = (char *)malloc(strlen(temp) + 1));
1320 /* Thread the LWP process descriptor *lp onto the lwp active process list
1321 * and associate a back pointer to the process descriptor from the associated
1324 lwp_thread_process(PROCESS lp)
1326 lp->next = lwp_process_list;
1327 lwp_process_list = lp;
1328 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1331 /* The top-level routine used as entry point to explicitly created LWP
1332 * processes. This completes a few details of process creation left
1333 * out by LWP_CreateProcess and calls the user-specified entry point */
1335 lwp_top_level(pthread_addr_t argp)
1337 PROCESS lp = (PROCESS) argp;
1339 assert(!pthread_mutex_lock(&lwp_mutex));
1340 lwp_thread_process(lp);
1342 assert(!pthread_mutex_unlock(&lwp_mutex));
1343 /* Should cleanup state */
1347 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1348 void *parm, char *name, PROCESS * pid)
1351 pthread_attr_t attr;
1355 #ifndef LWP_NO_PRIORITIES
1356 if (!cmalwp_pri_inrange(priority))
1359 assert(!pthread_attr_create(&attr));
1360 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1362 assert(!pthread_attr_setstacksize(&attr, stacksize));
1364 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1365 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1366 #ifndef LWP_NO_PRIORITIES
1367 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1370 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1371 (pthread_addr_t) parm);
1373 /* allow new thread to run if higher priority */
1374 assert(!pthread_mutex_unlock(&lwp_mutex));
1375 /* process is only added to active list after first time it runs (it adds itself) */
1377 pthread_create(&lp->handle, attr,
1378 (pthread_startroutine_t) lwp_top_level,
1379 (pthread_addr_t) lp);
1380 assert(!pthread_attr_delete(&attr));
1381 assert(!pthread_mutex_lock(&lwp_mutex));
1391 LWP_ActiveProcess(void)
1392 { /* returns pid of current process */
1394 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1399 LWP_CurrentProcess(PROCESS * pid)
1400 { /* get pid of current process */
1401 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1406 LWP_DestroyProcess(PROCESS pid)
1407 { /* destroy a lightweight process */
1408 lwp_unimplemented("LWP_DestroyProcess");
1412 LWP_DispatchProcess(void)
1413 { /* explicit voluntary preemption */
1414 assert(!pthread_mutex_unlock(&lwp_mutex));
1416 assert(!pthread_mutex_lock(&lwp_mutex));
1421 lwp_process_key_destructor(void)
1426 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1428 static int initialized = 0;
1438 #ifndef LWP_NO_PRIORITIES
1439 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1443 /* Create pthread key to associate LWP process descriptor with each
1444 * LWP-created thread */
1445 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1446 lwp_process_key_destructor));
1448 lp = lwp_alloc_process("main process", main, 0);
1449 lp->handle = pthread_self();
1450 lwp_thread_process(lp);
1451 #ifndef LWP_NO_PRIORITIES
1452 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1453 cmalwp_lwppri_to_cmapri(priority));
1456 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1457 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1464 LWP_TerminateProcessSupport(void)
1465 { /* terminate all LWP support */
1466 lwp_unimplemented("LWP_TerminateProcessSupport");
1469 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1471 getevent(char *event)
1473 event_t *evp, *newp;
1476 hashcode = hash(event);
1477 evp = hashtable[hashcode];
1480 if (evp->event == event) {
1484 if (evp->refcount == 0)
1489 newp = (event_t *) malloc(sizeof(event_t));
1491 newp->next = hashtable[hashcode];
1492 hashtable[hashcode] = newp;
1493 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1496 newp->event = event;
1501 /* Release the specified event */
1502 #define relevent(evp) ((evp)->refcount--)
1505 LWP_WaitProcess(char *event)
1506 { /* wait on a single event */
1509 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1511 return LWP_EBADEVENT;
1512 ev = getevent(event);
1514 while (seq == ev->seq) {
1515 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1517 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1523 LWP_MwaitProcess(int wcount, char *evlist[])
1524 { /* wait on m of n events */
1525 lwp_unimplemented("LWP_MWaitProcess");
1529 LWP_NoYieldSignal(char *event)
1532 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1534 return LWP_EBADEVENT;
1535 ev = getevent(event);
1536 if (ev->refcount > 1) {
1538 assert(pthread_cond_broadcast(&ev->cond) == 0);
1545 LWP_SignalProcess(char *event)
1548 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1550 return LWP_EBADEVENT;
1551 ev = getevent(event);
1552 if (ev->refcount > 1) {
1554 assert(!pthread_mutex_unlock(&lwp_mutex));
1555 assert(!pthread_cond_broadcast(&ev->cond));
1557 assert(!pthread_mutex_lock(&lwp_mutex));
1564 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1566 lwp_unimplemented("LWP_StackUsed");
1570 LWP_NewRock(int Tag, char *Value)
1572 lwp_unimplemented("LWP_NewRock");
1576 LWP_GetRock(int Tag, char **Value)
1578 lwp_unimplemented("LWP_GetRock");
1582 LWP_GetProcessPriority(PROCESS pid, int *priority)
1583 { /* returns process priority */
1584 lwp_unimplemented("LWP_GetProcessPriority");
1587 #endif /* USE_PTHREADS */