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>
36 int setlim(int limcon, uchar_t hard, int limit);
39 extern char *getenv();
44 #if !defined(USE_PTHREADS) && !defined(USE_SOLARIS_THREADS)
47 extern void *malloc(int size);
48 extern void *realloc(void *ptr, int size);
50 #ifndef AFS_ARM_LINUX20_ENV
51 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
52 extern int PRE_Block; /* from preempt.c */
54 extern char PRE_Block; /* from preempt.c */
66 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
69 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
80 #elif defined(AFS_DARWIN_ENV)
81 #define STACK_ALIGN 16
90 #define Debug(level, msg) do { \
91 if (lwp_debug && lwp_debug >= level) { \
92 printf("***LWP (0x%x): ", lwp_cpptr); \
98 #define Debug(level, msg) do { \
103 static int Dispatcher();
104 static int Create_Process_Part2();
105 static int Exit_LWP();
106 static afs_int32 Initialize_Stack();
107 static int Stack_Used();
108 char (*RC_to_ASCII());
110 static void Abort_LWP();
111 static void Overflow_Complain();
112 static void Initialize_PCB();
113 static void Dispose_of_Dead_PCB();
114 static void Free_PCB();
115 static int Internal_Signal();
116 static purge_dead_pcbs();
118 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
123 } runnable[MAX_PRIORITIES], blocked, qwaiting;
124 /* 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. */
126 /* Offset of stack field within pcb -- used by stack checking stuff */
129 /* special user-tweakable option for AIX */
130 int lwp_MaxStackSize = 32768;
132 /* biggest LWP stack created so far */
133 int lwp_MaxStackSeen = 0;
135 /* Stack checking action */
136 int lwp_overflowAction = LWP_SOABORT;
138 /* Controls stack size counting. */
139 int lwp_stackUseEnabled = TRUE; /* pay the price */
143 /* Minimum stack size */
144 int lwp_MinStackSize = 0;
147 lwp_remove(register PROCESS p, register struct QUEUE *q)
149 /* Special test for only element on queue */
153 /* Not only element, do normal remove */
154 p->next->prev = p->prev;
155 p->prev->next = p->next;
157 /* See if head pointing to this element */
161 p->next = p->prev = NULL;
166 insert(register PROCESS p, 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;
182 move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
192 #define for_all_elts(var, q, body)\
194 register PROCESS var, _NEXT_;\
196 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
197 _NEXT_ = var -> next;\
203 /*****************************************************************************\
205 * Following section documents the Assembler interfaces used by LWP code *
207 \*****************************************************************************/
210 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
212 Stub for Assembler routine that will
213 save the current SP value in the passed
214 context savearea and call the function
215 whose entry point is in ep. If the sp
216 parameter is NULL, the current stack is
217 used, otherwise sp becomes the new stack
220 returnto(struct lwp_context *savearea);
222 Stub for Assembler routine that will
223 restore context from a passed savearea
224 and return to the restored C frame.
228 /* Macro to force a re-schedule. Strange name is historical */
229 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
231 static struct lwp_ctl *lwp_init = 0;
237 (tp = lwp_cpptr)->status = QWAITING;
238 move(tp, &runnable[tp->priority], &qwaiting);
244 LWP_QSignal(register PROCESS pid)
246 if (pid->status == QWAITING) {
248 move(pid, &qwaiting, &runnable[pid->priority]);
256 reserveFromStack(register afs_int32 size)
265 LWP_CreateProcess(int (*ep) (), int stacksize, int priority, void *parm,
266 char *name, PROCESS * pid)
270 static char *stackptr = 0;
276 #if defined(AFS_LWP_MINSTACKSIZE)
278 * on some systems (e.g. hpux), a minimum usable stack size has
281 if (stacksize < lwp_MinStackSize) {
282 stacksize = lwp_MinStackSize;
284 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
285 /* more stack size computations; keep track of for IOMGR */
286 if (lwp_MaxStackSeen < stacksize)
287 lwp_MaxStackSeen = stacksize;
289 Debug(0, ("Entered LWP_CreateProcess"));
290 /* Throw away all dead process control blocks */
293 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
298 if (stacksize < MINSTACK)
299 #ifdef AFS_DARWIN_ENV
301 #else /* !AFS_DARWIN_ENV */
303 #endif /* !AFS_DARWIN_ENV */
306 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
310 * The following signal action for AIX is necessary so that in case of a
311 * crash (i.e. core is generated) we can include the user's data section
312 * in the core dump. Unfortunately, by default, only a partial core is
313 * generated which, in many cases, isn't too useful.
315 * We also do it here in case the main program forgets to do it.
317 struct sigaction nsa;
318 extern uid_t geteuid();
320 sigemptyset(&nsa.sa_mask);
321 nsa.sa_handler = SIG_DFL;
322 nsa.sa_flags = SA_FULLDUMP;
323 sigaction(SIGABRT, &nsa, NULL);
324 sigaction(SIGSEGV, &nsa, NULL);
327 * First we need to increase the default resource limits,
328 * if necessary, so that we can guarantee that we have the
329 * resources to create the core file, but we can't always
330 * do it as an ordinary user.
333 /* vos dump causes problems */
334 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
335 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
336 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
339 * Now reserve in one scoop all the stack space that will be used
340 * by the particular application's main (i.e. non-lwp) body. This
341 * is plenty space for any of our applications.
343 stackptr = reserveFromStack(lwp_MaxStackSize);
345 stackptr -= stacksize;
346 stackmemory = stackptr;
348 #ifdef AFS_DARWIN_ENV
349 if ((stackmemory = (char *)malloc(stacksize + STACK_ALIGN - 1)) == NULL)
350 #else /* !AFS_DARWIN_ENV */
351 if ((stackmemory = (char *)malloc(stacksize + 7)) == NULL)
352 #endif /* !AFS_DARWIN_ENV */
357 /* Round stack pointer to byte boundary */
358 #ifdef AFS_DARWIN_ENV
359 stackptr = (char *)(STACK_ALIGN * (((long)stackmemory + STACK_ALIGN - 1) / STACK_ALIGN));
360 #else /* !AFS_DARWIN_ENV */
361 stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
362 #endif /* !AFS_DARWIN_ENV */
364 if (priority < 0 || priority >= MAX_PRIORITIES) {
368 Initialize_Stack(stackptr, stacksize);
369 Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
370 insert(temp, &runnable[priority]);
372 #ifndef AFS_ARM_LINUX20_ENV
374 Abort_LWP("PRE_Block not 0");
376 /* Gross hack: beware! */
380 #if defined(AFS_PARISC_LINUX24_ENV)
381 savecontext(Create_Process_Part2, &temp2->context,
382 stackptr + MINFRAME);
385 savecontext(Create_Process_Part2, &temp2->context,
386 stackptr + MINFRAME);
388 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
389 #ifdef sys_x86_darwin_80
390 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16 - sizeof(void *)); /* 16 = 2 * jmp_buf_type */
391 #else /* !sys_x86_darwin_80 */
392 /* Need to have the sp on an 8-byte boundary for storing doubles. */
393 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16); /* 16 = 2 * jmp_buf_type */
394 #endif /* !sys_x86_darwin_80 */
396 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
397 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40); /* lomgjmp does something
400 #if defined(AFS_S390_LINUX20_ENV)
401 savecontext(Create_Process_Part2, &temp2->context,
402 stackptr + stacksize - MINFRAME);
403 #else /* !AFS_S390_LINUX20_ENV */
404 savecontext(Create_Process_Part2, &temp2->context,
405 stackptr + stacksize - sizeof(void *));
406 #endif /* AFS_S390_LINUX20_ENV */
407 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
408 #endif /* AFS_SGI62_ENV */
411 /* End of gross hack */
422 LWP_CreateProcess2(int (*ep) (), int stacksize, int priority, void *parm,
423 char *name, PROCESS * pid)
428 #if defined(AFS_LWP_MINSTACKSIZE)
430 * on some systems (e.g. hpux), a minimum usable stack size has
433 if (stacksize < lwp_MinStackSize) {
434 stacksize = lwp_MinStackSize;
436 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
437 /* more stack size computations; keep track of for IOMGR */
438 if (lwp_MaxStackSeen < stacksize)
439 lwp_MaxStackSeen = stacksize;
441 Debug(0, ("Entered LWP_CreateProcess"));
442 /* Throw away all dead process control blocks */
445 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
450 if (stacksize < MINSTACK)
454 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
455 if ((stackptr = (char *)malloc(stacksize)) == NULL) {
459 if (priority < 0 || priority >= MAX_PRIORITIES) {
463 Initialize_Stack(stackptr, stacksize);
464 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
465 insert(temp, &runnable[priority]);
467 #ifndef AFS_ARM_LINUX20_ENV
469 Abort_LWP("PRE_Block not 0");
471 /* Gross hack: beware! */
475 savecontext(Create_Process_Part2, &temp2->context,
476 stackptr + stacksize - sizeof(void *));
477 /* End of gross hack */
488 LWP_CurrentProcess(PROCESS * pid)
489 { /* returns pid of current process */
490 Debug(0, ("Entered Current_Process"));
501 Debug(0, ("Entered ThreadId"));
508 #define LWPANCHOR (*lwp_init)
511 LWP_DestroyProcess(PROCESS pid)
512 { /* destroy a lightweight process */
515 Debug(0, ("Entered Destroy_Process"));
517 if (lwp_cpptr != pid) {
518 Dispose_of_Dead_PCB(pid);
521 pid->status = DESTROYED;
522 move(pid, &runnable[pid->priority], &blocked);
524 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
525 savecontext(Dispatcher, &(temp->context),
526 &(LWPANCHOR.dsptchstack[MINFRAME]));
527 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
528 savecontext(Dispatcher, &(temp->context),
530 dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
531 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
532 savecontext(Dispatcher, &(temp->context),
534 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
536 #elif defined(AFS_S390_LINUX20_ENV)
537 savecontext(Dispatcher, &(temp->context),
539 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
542 savecontext(Dispatcher, &(temp->context),
544 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
554 LWP_DispatchProcess(void)
555 { /* explicit voluntary preemption */
556 Debug(2, ("Entered Dispatch_Process"));
570 for (i = 0; i < MAX_PRIORITIES; i++)
571 for_all_elts(x, runnable[i], {
572 printf("[Priority %d]\n", i);
576 for_all_elts(x, blocked, {
577 Dump_One_Process(x);}
579 for_all_elts(x, qwaiting, {
580 Dump_One_Process(x);}
583 printf("***LWP: LWP support not initialized\n");
589 LWP_GetProcessPriority(PROCESS pid, int *priority)
590 { /* returns process priority */
591 Debug(0, ("Entered Get_Process_Priority"));
593 *priority = pid->priority;
600 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
603 struct lwp_pcb dummy;
607 Debug(0, ("Entered LWP_InitializeProcessSupport"));
608 if (lwp_init != NULL)
611 /* Set up offset for stack checking -- do this as soon as possible */
612 stack_offset = (char *)&dummy.stack - (char *)&dummy;
614 if (priority >= MAX_PRIORITIES)
616 for (i = 0; i < MAX_PRIORITIES; i++) {
617 runnable[i].head = NULL;
618 runnable[i].count = 0;
622 qwaiting.head = NULL;
624 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
625 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
626 if (lwp_init == NULL || temp == NULL)
627 Abort_LWP("Insufficient Storage to Initialize LWP Support");
628 LWPANCHOR.processcnt = 1;
629 LWPANCHOR.outerpid = temp;
630 LWPANCHOR.outersp = NULL;
631 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
632 "Main Process [created by LWP]");
633 insert(temp, &runnable[priority]);
634 savecontext(Dispatcher, &temp->context, NULL);
635 LWPANCHOR.outersp = temp->context.topstack;
639 /* get minimum stack size from the environment. this allows the administrator
640 * to change the lwp stack dynamically without getting a new binary version.
642 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
643 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
646 (AFS_LWP_MINSTACKSIZE >
647 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
653 LWP_INTERNALSIGNAL(char *event, int yield)
654 { /* signal the occurence of an event */
655 Debug(2, ("Entered LWP_SignalProcess"));
658 rc = Internal_Signal(event);
667 LWP_TerminateProcessSupport(void)
668 { /* terminate all LWP support */
671 Debug(0, ("Entered Terminate_Process_Support"));
672 if (lwp_init == NULL)
674 if (lwp_cpptr != LWPANCHOR.outerpid)
675 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
676 for (i = 0; i < MAX_PRIORITIES; i++)
677 for_all_elts(cur, runnable[i], {
680 for_all_elts(cur, blocked, {
683 for_all_elts(cur, qwaiting, {
692 LWP_WaitProcess(char *event)
693 { /* wait on a single event */
696 Debug(2, ("Entered Wait_Process"));
698 return LWP_EBADEVENT;
701 return LWP_MwaitProcess(1, tempev);
705 LWP_MwaitProcess(int wcount, char *evlist[])
706 { /* wait on m of n events */
707 register int ecount, i;
710 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
712 if (evlist == NULL) {
714 return LWP_EBADCOUNT;
717 for (ecount = 0; evlist[ecount] != NULL; ecount++);
721 return LWP_EBADCOUNT;
726 if (wcount > ecount || wcount < 0) {
728 return LWP_EBADCOUNT;
730 if (ecount > lwp_cpptr->eventlistsize) {
732 lwp_cpptr->eventlist =
733 (char **)realloc(lwp_cpptr->eventlist,
734 ecount * sizeof(char *));
735 lwp_cpptr->eventlistsize = ecount;
737 for (i = 0; i < ecount; i++)
738 lwp_cpptr->eventlist[i] = evlist[i];
740 lwp_cpptr->status = WAITING;
742 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
745 lwp_cpptr->wakevent = 0;
746 lwp_cpptr->waitcnt = wcount;
747 lwp_cpptr->eventcnt = ecount;
758 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
760 *maxa = pid->stacksize;
761 *used = Stack_Used(pid->stack, *maxa);
768 * The following functions are strictly
769 * INTERNAL to the LWP support package.
775 struct lwp_context tempcontext;
777 Debug(0, ("Entered Abort_LWP"));
778 printf("***LWP: %s\n", msg);
779 printf("***LWP: Abort --- dumping PCBs ...\n");
783 if (LWPANCHOR.outersp == NULL)
786 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
791 Create_Process_Part2(void)
792 { /* creates a context for the new process */
795 Debug(2, ("Entered Create_Process_Part2"));
796 temp = lwp_cpptr; /* Get current process id */
797 savecontext(Dispatcher, &temp->context, NULL);
798 (*temp->ep) (temp->parm);
799 LWP_DestroyProcess(temp);
804 Delete_PCB(register PROCESS pid)
805 { /* remove a PCB from the process list */
806 Debug(4, ("Entered Delete_PCB"));
808 (pid->blockflag || pid->status == WAITING
810 DESTROYED ? &blocked :
811 (pid->status == QWAITING) ? &qwaiting :
812 &runnable[pid->priority]));
813 LWPANCHOR.processcnt--;
819 Dump_One_Process(PROCESS pid)
823 printf("***LWP: Process Control Block at 0x%x\n", pid);
824 printf("***LWP: Name: %s\n", pid->name);
826 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
828 printf("BLOCKED and ");
829 switch (pid->status) {
846 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
848 if (pid->stacksize != 0) {
849 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
850 pid->stacksize, pid->stack);
851 printf("***LWP: HWM stack usage: ");
852 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
854 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
855 if (pid->eventcnt > 0) {
856 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
857 printf("***LWP: Event id list:");
858 for (i = 0; i < pid->eventcnt; i++)
859 printf(" 0x%x", pid->eventlist[i]);
862 if (pid->wakevent > 0)
863 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
869 purge_dead_pcbs(void)
871 for_all_elts(cur, blocked, {
872 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
877 int LWP_TraceProcesses = 0;
881 { /* Lightweight process dispatcher */
884 static int dispatch_count = 0;
886 if (LWP_TraceProcesses > 0) {
887 for (i = 0; i < MAX_PRIORITIES; i++) {
888 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
889 for_all_elts(p, runnable[i], {
890 printf(" \"%s\"", p->name);
895 printf("[Blocked (%d):", blocked.count);
896 for_all_elts(p, blocked, {
897 printf(" \"%s\"", p->name);
901 printf("[Qwaiting (%d):", qwaiting.count);
902 for_all_elts(p, qwaiting, {
903 printf(" \"%s\"", p->name);
910 /* Check for stack overflowif this lwp has a stack. Check for
911 * the guard word at the front of the stack being damaged and
912 * for the stack pointer being below the front of the stack.
913 * WARNING! This code assumes that stacks grow downward. */
914 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
915 /* Fix this (stackcheck at other end of stack?) */
916 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
917 && (lwp_cpptr->stackcheck !=
918 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
919 || lwp_cpptr->context.topstack >
920 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
922 if (lwp_cpptr && lwp_cpptr->stack
923 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
924 || lwp_cpptr->context.topstack < lwp_cpptr->stack
925 || lwp_cpptr->context.topstack >
926 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
928 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
929 *(int *)lwp_cpptr->stack);
930 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
931 lwp_cpptr->context.topstack, lwp_cpptr->stack,
932 lwp_cpptr->stacksize);
934 switch (lwp_overflowAction) {
943 lwp_overflowAction = LWP_SOQUIET;
948 /* Move head of current runnable queue forward if current LWP is still in it. */
949 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
950 runnable[lwp_cpptr->priority].head =
951 runnable[lwp_cpptr->priority].head->next;
952 /* Find highest priority with runnable processes. */
953 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
954 if (runnable[i].head != NULL)
958 Abort_LWP("No READY processes");
961 if (LWP_TraceProcesses > 0)
962 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
963 runnable[i].head, runnable[i].head->name);
965 #ifndef AFS_ARM_LINUX20_ENV
967 Abort_LWP("PRE_Block not 1");
969 lwp_cpptr = runnable[i].head;
971 returnto(&lwp_cpptr->context);
973 return 0; /* not reachable */
976 /* Complain of a stack overflow to stderr without using stdio. */
978 Overflow_Complain(void)
982 char *msg1 = " LWP: stack overflow in process ";
985 currenttime = time(0);
986 timeStamp = ctime(¤ttime);
988 write(2, timeStamp, strlen(timeStamp));
990 write(2, msg1, strlen(msg1));
991 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
992 write(2, msg2, strlen(msg2));
996 Dispose_of_Dead_PCB(PROCESS cur)
998 Debug(4, ("Entered Dispose_of_Dead_PCB"));
1002 Internal_Signal(cur);
1013 Free_PCB(PROCESS pid)
1015 Debug(4, ("Entered Free_PCB"));
1016 if (pid->stack != NULL) {
1018 ("HWM stack usage: %d, [PCB at 0x%x]",
1019 Stack_Used(pid->stack, pid->stacksize), pid));
1020 #ifndef AFS_AIX32_ENV
1024 if (pid->eventlist != NULL)
1025 free(pid->eventlist);
1030 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1031 int (*ep) (), void *parm, char *name)
1035 Debug(4, ("Entered Initialize_PCB"));
1037 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1039 temp->name[31] = '\0';
1040 temp->status = READY;
1041 temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
1042 temp->eventlistsize = EVINITSIZE;
1046 temp->blockflag = 0;
1047 temp->iomgrRequest = 0;
1048 temp->priority = priority;
1049 temp->index = lwp_nextindex++;
1050 temp->stack = stack;
1051 temp->stacksize = stacksize;
1052 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1053 if (temp->stack != NULL)
1054 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1056 if (temp->stack != NULL)
1057 temp->stackcheck = *(int *)(temp->stack);
1061 temp->misc = NULL; /* currently unused */
1064 temp->lwp_rused = 0;
1065 temp->level = 1; /* non-preemptable */
1069 Internal_Signal(register char *event)
1071 int rc = LWP_ENOWAIT;
1074 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1078 return LWP_EBADEVENT;
1079 for_all_elts(temp, blocked, {
1080 if (temp->status == WAITING)
1081 for (i = 0; i < temp->eventcnt; i++) {
1082 if (temp->eventlist[i] == event) {
1083 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1084 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1085 if (--temp->waitcnt == 0) {
1086 temp->status = READY; temp->wakevent = i + 1;
1087 move(temp, &blocked, &runnable[temp->priority]); break;}
1095 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1096 #define STACKMAGIC 0xBADBADBA
1098 Initialize_Stack(char *stackptr, int stacksize)
1102 Debug(4, ("Entered Initialize_Stack"));
1103 if (lwp_stackUseEnabled)
1104 for (i = 0; i < stacksize; i++)
1105 stackptr[i] = i & 0xff;
1107 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1108 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1110 *(afs_int32 *) stackptr = STACKMAGIC;
1116 Stack_Used(register char *stackptr, int stacksize)
1120 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1121 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1124 for (i = stacksize - 1; i >= 0; i--)
1125 if ((unsigned char)stackptr[i] != (i & 0xff))
1130 if (*(afs_int32 *) stackptr == STACKMAGIC)
1133 for (i = 0; i < stacksize; i++)
1134 if ((unsigned char)stackptr[i] != (i & 0xff))
1135 return (stacksize - i);
1143 LWP_NewRock(int Tag, char *Value)
1144 /* Finds a free rock and sets its value to Value.
1146 * LWP_SUCCESS Rock did not exist and a new one was used
1147 * LWP_EBADROCK Rock already exists.
1148 * LWP_ENOROCKS All rocks are in use.
1150 * From the above semantics, you can only set a rock value once. This is specifically
1151 * to prevent multiple users of the LWP package from accidentally using the same Tag
1152 * value and clobbering others. You can always use one level of indirection to obtain
1153 * a rock whose contents can change.
1157 register struct rock *ra; /* rock array */
1159 ra = lwp_cpptr->lwp_rlist;
1161 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1162 if (ra[i].tag == Tag)
1163 return (LWP_EBADROCK);
1165 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1166 ra[lwp_cpptr->lwp_rused].tag = Tag;
1167 ra[lwp_cpptr->lwp_rused].value = Value;
1168 lwp_cpptr->lwp_rused++;
1169 return (LWP_SUCCESS);
1171 return (LWP_ENOROCKS);
1176 LWP_GetRock(int Tag, char **Value)
1177 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1179 * LWP_SUCCESS if specified rock exists and Value has been filled
1180 * LWP_EBADROCK rock specified does not exist
1184 register struct rock *ra;
1186 ra = lwp_cpptr->lwp_rlist;
1188 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1189 if (ra[i].tag == Tag) {
1190 *Value = ra[i].value;
1191 return (LWP_SUCCESS);
1193 return (LWP_EBADROCK);
1197 #ifdef AFS_AIX32_ENV
1199 setlim(int limcon, uchar_t hard, int limit)
1203 (void)getrlimit(limcon, &rlim);
1205 limit = limit * 1024;
1207 rlim.rlim_max = limit;
1208 else if (limit == RLIM_INFINITY && geteuid() != 0)
1209 rlim.rlim_cur = rlim.rlim_max;
1211 rlim.rlim_cur = limit;
1213 /* Must use ulimit() due to Posix constraints */
1214 if (limcon == RLIMIT_FSIZE) {
1217 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1218 printf("Can't %s%s limit\n",
1219 limit == RLIM_INFINITY ? "remove" : "set",
1220 hard ? " hard" : "");
1224 if (setrlimit(limcon, &rlim) < 0) {
1226 printf("Can't %s%s limit\n",
1227 limit == RLIM_INFINITY ? "remove" : "set",
1228 hard ? " hard" : "");
1238 * Print the specific limit out
1241 plim(char *name, afs_int32 lc, uchar_t hard)
1246 printf("%s \t", name);
1247 (void)getrlimit(lc, &rlim);
1248 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1249 if (lim == RLIM_INFINITY)
1250 printf("unlimited");
1251 printf("%d %s", lim / 1024, "kbytes");
1259 LWP_NoYieldSignal(char *event)
1261 return (LWP_INTERNALSIGNAL(event, 0));
1265 LWP_SignalProcess(char *event)
1267 return (LWP_INTERNALSIGNAL(event, 1));
1272 #ifdef USE_SOLARIS_THREADS
1275 #include "pthread.h"
1280 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1282 PROCESS lwp_process_list; /* List of LWP initiated threads */
1284 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1286 #define CHECK check(__LINE__);
1288 typedef struct event {
1289 struct event *next; /* next in hash chain */
1290 char *event; /* lwp event: an address */
1291 int refcount; /* Is it in use? */
1292 pthread_cond_t cond; /* Currently associated condition variable */
1293 int seq; /* Sequence number: this is incremented
1294 * by wakeup calls; wait will not return until
1298 #define HASHSIZE 127
1299 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1300 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1302 #if CMA_DEBUG || DEBUGF
1304 lwp_process_string(void)
1306 static char id[200];
1308 LWP_CurrentProcess(&p);
1309 sprintf(id, "PID %x <%s>", p, p->name);
1315 lwp_unimplemented(char *interface)
1318 "cmalwp: %s is not currently implemented: program aborted\n",
1324 lwpabort(char *interface)
1326 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1333 lwp_unimplemented("LWP_QWait");
1337 LWP_QSignal(int pid)
1339 lwp_unimplemented("LWP_QSignal");
1342 /* Allocate and initialize an LWP process handle. The associated pthread handle
1343 * must be added by the caller, and the structure threaded onto the LWP active
1344 * process list by lwp_thread_process */
1346 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1349 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1350 memset((char *)lp, 0, sizeof(*lp));
1354 sprintf(temp, "unnamed_process_%04d", ++procnum);
1355 assert(name = (char *)malloc(strlen(temp) + 1));
1364 /* Thread the LWP process descriptor *lp onto the lwp active process list
1365 * and associate a back pointer to the process descriptor from the associated
1368 lwp_thread_process(PROCESS lp)
1370 lp->next = lwp_process_list;
1371 lwp_process_list = lp;
1372 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1375 /* The top-level routine used as entry point to explicitly created LWP
1376 * processes. This completes a few details of process creation left
1377 * out by LWP_CreateProcess and calls the user-specified entry point */
1379 lwp_top_level(pthread_addr_t argp)
1381 PROCESS lp = (PROCESS) argp;
1383 assert(!pthread_mutex_lock(&lwp_mutex));
1384 lwp_thread_process(lp);
1386 assert(!pthread_mutex_unlock(&lwp_mutex));
1387 /* Should cleanup state */
1391 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1392 void *parm, char *name, PROCESS * pid)
1395 pthread_attr_t attr;
1399 #ifndef LWP_NO_PRIORITIES
1400 if (!cmalwp_pri_inrange(priority))
1403 assert(!pthread_attr_create(&attr));
1404 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1406 assert(!pthread_attr_setstacksize(&attr, stacksize));
1408 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1409 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1410 #ifndef LWP_NO_PRIORITIES
1411 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1414 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1415 (pthread_addr_t) parm);
1417 /* allow new thread to run if higher priority */
1418 assert(!pthread_mutex_unlock(&lwp_mutex));
1419 /* process is only added to active list after first time it runs (it adds itself) */
1421 pthread_create(&lp->handle, attr,
1422 (pthread_startroutine_t) lwp_top_level,
1423 (pthread_addr_t) lp);
1424 assert(!pthread_attr_delete(&attr));
1425 assert(!pthread_mutex_lock(&lwp_mutex));
1435 LWP_ActiveProcess(void)
1436 { /* returns pid of current process */
1438 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1443 LWP_CurrentProcess(PROCESS * pid)
1444 { /* get pid of current process */
1445 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1450 LWP_DestroyProcess(PROCESS pid)
1451 { /* destroy a lightweight process */
1452 lwp_unimplemented("LWP_DestroyProcess");
1456 LWP_DispatchProcess(void)
1457 { /* explicit voluntary preemption */
1458 assert(!pthread_mutex_unlock(&lwp_mutex));
1460 assert(!pthread_mutex_lock(&lwp_mutex));
1465 lwp_process_key_destructor(void)
1470 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1472 static int initialized = 0;
1482 #ifndef LWP_NO_PRIORITIES
1483 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1487 /* Create pthread key to associate LWP process descriptor with each
1488 * LWP-created thread */
1489 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1490 lwp_process_key_destructor));
1492 lp = lwp_alloc_process("main process", main, 0);
1493 lp->handle = pthread_self();
1494 lwp_thread_process(lp);
1495 #ifndef LWP_NO_PRIORITIES
1496 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1497 cmalwp_lwppri_to_cmapri(priority));
1500 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1501 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1508 LWP_TerminateProcessSupport(void)
1509 { /* terminate all LWP support */
1510 lwp_unimplemented("LWP_TerminateProcessSupport");
1513 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1515 getevent(char *event)
1517 event_t *evp, *newp;
1520 hashcode = hash(event);
1521 evp = hashtable[hashcode];
1524 if (evp->event == event) {
1528 if (evp->refcount == 0)
1533 newp = (event_t *) malloc(sizeof(event_t));
1535 newp->next = hashtable[hashcode];
1536 hashtable[hashcode] = newp;
1537 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1540 newp->event = event;
1545 /* Release the specified event */
1546 #define relevent(evp) ((evp)->refcount--)
1549 LWP_WaitProcess(char *event)
1550 { /* wait on a single event */
1553 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1555 return LWP_EBADEVENT;
1556 ev = getevent(event);
1558 while (seq == ev->seq) {
1559 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1561 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1567 LWP_MwaitProcess(int wcount, char *evlist[])
1568 { /* wait on m of n events */
1569 lwp_unimplemented("LWP_MWaitProcess");
1573 LWP_NoYieldSignal(char *event)
1576 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1578 return LWP_EBADEVENT;
1579 ev = getevent(event);
1580 if (ev->refcount > 1) {
1582 assert(pthread_cond_broadcast(&ev->cond) == 0);
1589 LWP_SignalProcess(char *event)
1592 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1594 return LWP_EBADEVENT;
1595 ev = getevent(event);
1596 if (ev->refcount > 1) {
1598 assert(!pthread_mutex_unlock(&lwp_mutex));
1599 assert(!pthread_cond_broadcast(&ev->cond));
1601 assert(!pthread_mutex_lock(&lwp_mutex));
1608 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1610 lwp_unimplemented("LWP_StackUsed");
1614 LWP_NewRock(int Tag, char *Value)
1616 lwp_unimplemented("LWP_NewRock");
1620 LWP_GetRock(int Tag, char **Value)
1622 lwp_unimplemented("LWP_GetRock");
1626 LWP_GetProcessPriority(PROCESS pid, int *priority)
1627 { /* returns process priority */
1628 lwp_unimplemented("LWP_GetProcessPriority");
1631 #endif /* USE_PTHREADS */