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 void Dispatcher(void);
104 static void Create_Process_Part2(void);
105 static void Exit_LWP(void);
106 static afs_int32 Initialize_Stack(char *stackptr, int stacksize);
107 static int Stack_Used(register char *stackptr, int stacksize);
109 static void Abort_LWP(char *msg);
110 static void Overflow_Complain(void);
111 static void Initialize_PCB(PROCESS temp, int priority, char *stack,
112 int stacksize, void *(*ep)(void *), void *parm,
114 static void Dispose_of_Dead_PCB(PROCESS cur);
115 static void Free_PCB(PROCESS pid);
116 static int Internal_Signal(void *event);
117 static int purge_dead_pcbs(void);
118 static int LWP_MwaitProcess(int wcount, void *evlist[]);
121 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
126 } runnable[MAX_PRIORITIES], blocked, qwaiting;
127 /* Invariant for runnable queues: The head of each queue points to the
128 * currently running process if it is in that queue, or it points to the
129 * next process in that queue that should run. */
131 /* Offset of stack field within pcb -- used by stack checking stuff */
134 /* special user-tweakable option for AIX */
135 int lwp_MaxStackSize = 32768;
137 /* biggest LWP stack created so far */
138 int lwp_MaxStackSeen = 0;
140 /* Stack checking action */
141 int lwp_overflowAction = LWP_SOABORT;
143 /* Controls stack size counting. */
144 int lwp_stackUseEnabled = TRUE; /* pay the price */
148 /* Minimum stack size */
149 int lwp_MinStackSize = 0;
152 lwp_remove(register PROCESS p, register struct QUEUE *q)
154 /* Special test for only element on queue */
158 /* Not only element, do normal remove */
159 p->next->prev = p->prev;
160 p->prev->next = p->next;
162 /* See if head pointing to this element */
166 p->next = p->prev = NULL;
171 insert(register PROCESS p, 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;
187 move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
197 #define for_all_elts(var, q, body)\
199 register PROCESS var, _NEXT_;\
201 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
202 _NEXT_ = var -> next;\
208 /*****************************************************************************\
210 * Following section documents the Assembler interfaces used by LWP code *
212 \*****************************************************************************/
215 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
217 Stub for Assembler routine that will
218 save the current SP value in the passed
219 context savearea and call the function
220 whose entry point is in ep. If the sp
221 parameter is NULL, the current stack is
222 used, otherwise sp becomes the new stack
225 returnto(struct lwp_context *savearea);
227 Stub for Assembler routine that will
228 restore context from a passed savearea
229 and return to the restored C frame.
233 /* Macro to force a re-schedule. Strange name is historical */
234 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
236 static struct lwp_ctl *lwp_init = 0;
242 (tp = lwp_cpptr)->status = QWAITING;
243 move(tp, &runnable[tp->priority], &qwaiting);
249 LWP_QSignal(register PROCESS pid)
251 if (pid->status == QWAITING) {
253 move(pid, &qwaiting, &runnable[pid->priority]);
261 reserveFromStack(register afs_int32 size)
270 LWP_CreateProcess(void *(*ep) (void *), int stacksize, int priority, void *parm,
271 char *name, PROCESS * pid)
275 static char *stackptr = 0;
281 #if defined(AFS_LWP_MINSTACKSIZE)
283 * on some systems (e.g. hpux), a minimum usable stack size has
286 if (stacksize < lwp_MinStackSize) {
287 stacksize = lwp_MinStackSize;
289 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
290 /* more stack size computations; keep track of for IOMGR */
291 if (lwp_MaxStackSeen < stacksize)
292 lwp_MaxStackSeen = stacksize;
294 Debug(0, ("Entered LWP_CreateProcess"));
295 /* Throw away all dead process control blocks */
298 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
303 if (stacksize < MINSTACK)
304 #ifdef AFS_DARWIN_ENV
306 #else /* !AFS_DARWIN_ENV */
308 #endif /* !AFS_DARWIN_ENV */
311 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
315 * The following signal action for AIX is necessary so that in case of a
316 * crash (i.e. core is generated) we can include the user's data section
317 * in the core dump. Unfortunately, by default, only a partial core is
318 * generated which, in many cases, isn't too useful.
320 * We also do it here in case the main program forgets to do it.
322 struct sigaction nsa;
323 extern uid_t geteuid();
325 sigemptyset(&nsa.sa_mask);
326 nsa.sa_handler = SIG_DFL;
327 nsa.sa_flags = SA_FULLDUMP;
328 sigaction(SIGABRT, &nsa, NULL);
329 sigaction(SIGSEGV, &nsa, NULL);
332 * First we need to increase the default resource limits,
333 * if necessary, so that we can guarantee that we have the
334 * resources to create the core file, but we can't always
335 * do it as an ordinary user.
338 /* vos dump causes problems */
339 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
340 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
341 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
344 * Now reserve in one scoop all the stack space that will be used
345 * by the particular application's main (i.e. non-lwp) body. This
346 * is plenty space for any of our applications.
348 stackptr = reserveFromStack(lwp_MaxStackSize);
350 stackptr -= stacksize;
351 stackmemory = stackptr;
353 #ifdef AFS_DARWIN_ENV
354 if ((stackmemory = (char *)malloc(stacksize + STACK_ALIGN - 1)) == NULL)
355 #else /* !AFS_DARWIN_ENV */
356 if ((stackmemory = (char *)malloc(stacksize + 7)) == NULL)
357 #endif /* !AFS_DARWIN_ENV */
362 /* Round stack pointer to byte boundary */
363 #ifdef AFS_DARWIN_ENV
364 stackptr = (char *)(STACK_ALIGN * (((long)stackmemory + STACK_ALIGN - 1) / STACK_ALIGN));
365 #else /* !AFS_DARWIN_ENV */
366 stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
367 #endif /* !AFS_DARWIN_ENV */
369 if (priority < 0 || priority >= MAX_PRIORITIES) {
373 Initialize_Stack(stackptr, stacksize);
374 Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
375 insert(temp, &runnable[priority]);
377 #ifndef AFS_ARM_LINUX20_ENV
379 Abort_LWP("PRE_Block not 0");
381 /* Gross hack: beware! */
385 #if defined(AFS_PARISC_LINUX24_ENV)
386 savecontext(Create_Process_Part2, &temp2->context,
387 stackptr + MINFRAME);
390 savecontext(Create_Process_Part2, &temp2->context,
391 stackptr + MINFRAME);
393 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
394 #ifdef sys_x86_darwin_80
395 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16 - sizeof(void *)); /* 16 = 2 * jmp_buf_type */
396 #else /* !sys_x86_darwin_80 */
397 /* Need to have the sp on an 8-byte boundary for storing doubles. */
398 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16); /* 16 = 2 * jmp_buf_type */
399 #endif /* !sys_x86_darwin_80 */
401 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
402 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40); /* lomgjmp does something
405 #if defined(AFS_S390_LINUX20_ENV)
406 savecontext(Create_Process_Part2, &temp2->context,
407 stackptr + stacksize - MINFRAME);
408 #else /* !AFS_S390_LINUX20_ENV */
409 savecontext(Create_Process_Part2, &temp2->context,
410 stackptr + stacksize - sizeof(void *));
411 #endif /* AFS_S390_LINUX20_ENV */
412 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
413 #endif /* AFS_SGI62_ENV */
416 /* End of gross hack */
427 LWP_CreateProcess2(void *(*ep) (void *), int stacksize, int priority, void *parm,
428 char *name, PROCESS * pid)
433 #if defined(AFS_LWP_MINSTACKSIZE)
435 * on some systems (e.g. hpux), a minimum usable stack size has
438 if (stacksize < lwp_MinStackSize) {
439 stacksize = lwp_MinStackSize;
441 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
442 /* more stack size computations; keep track of for IOMGR */
443 if (lwp_MaxStackSeen < stacksize)
444 lwp_MaxStackSeen = stacksize;
446 Debug(0, ("Entered LWP_CreateProcess"));
447 /* Throw away all dead process control blocks */
450 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
455 if (stacksize < MINSTACK)
459 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
460 if ((stackptr = (char *)malloc(stacksize)) == NULL) {
464 if (priority < 0 || priority >= MAX_PRIORITIES) {
468 Initialize_Stack(stackptr, stacksize);
469 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
470 insert(temp, &runnable[priority]);
472 #ifndef AFS_ARM_LINUX20_ENV
474 Abort_LWP("PRE_Block not 0");
476 /* Gross hack: beware! */
480 savecontext(Create_Process_Part2, &temp2->context,
481 stackptr + stacksize - sizeof(void *));
482 /* End of gross hack */
493 LWP_CurrentProcess(PROCESS * pid)
494 { /* returns pid of current process */
495 Debug(0, ("Entered Current_Process"));
506 Debug(0, ("Entered ThreadId"));
513 #define LWPANCHOR (*lwp_init)
516 LWP_DestroyProcess(PROCESS pid)
517 { /* destroy a lightweight process */
520 Debug(0, ("Entered Destroy_Process"));
522 if (lwp_cpptr != pid) {
523 Dispose_of_Dead_PCB(pid);
526 pid->status = DESTROYED;
527 move(pid, &runnable[pid->priority], &blocked);
529 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
530 savecontext(Dispatcher, &(temp->context),
531 &(LWPANCHOR.dsptchstack[MINFRAME]));
532 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
533 savecontext(Dispatcher, &(temp->context),
535 dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
536 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
537 savecontext(Dispatcher, &(temp->context),
539 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
541 #elif defined(AFS_S390_LINUX20_ENV)
542 savecontext(Dispatcher, &(temp->context),
544 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
547 savecontext(Dispatcher, &(temp->context),
549 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
559 LWP_DispatchProcess(void)
560 { /* explicit voluntary preemption */
561 Debug(2, ("Entered Dispatch_Process"));
575 for (i = 0; i < MAX_PRIORITIES; i++)
576 for_all_elts(x, runnable[i], {
577 printf("[Priority %d]\n", i);
581 for_all_elts(x, blocked, {
582 Dump_One_Process(x);}
584 for_all_elts(x, qwaiting, {
585 Dump_One_Process(x);}
588 printf("***LWP: LWP support not initialized\n");
594 LWP_GetProcessPriority(PROCESS pid, int *priority)
595 { /* returns process priority */
596 Debug(0, ("Entered Get_Process_Priority"));
598 *priority = pid->priority;
605 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
608 struct lwp_pcb dummy;
612 Debug(0, ("Entered LWP_InitializeProcessSupport"));
613 if (lwp_init != NULL)
616 /* Set up offset for stack checking -- do this as soon as possible */
617 stack_offset = (char *)&dummy.stack - (char *)&dummy;
619 if (priority >= MAX_PRIORITIES)
621 for (i = 0; i < MAX_PRIORITIES; i++) {
622 runnable[i].head = NULL;
623 runnable[i].count = 0;
627 qwaiting.head = NULL;
629 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
630 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
631 if (lwp_init == NULL || temp == NULL)
632 Abort_LWP("Insufficient Storage to Initialize LWP Support");
633 LWPANCHOR.processcnt = 1;
634 LWPANCHOR.outerpid = temp;
635 LWPANCHOR.outersp = NULL;
636 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
637 "Main Process [created by LWP]");
638 insert(temp, &runnable[priority]);
639 savecontext(Dispatcher, &temp->context, NULL);
640 LWPANCHOR.outersp = temp->context.topstack;
644 /* get minimum stack size from the environment. this allows the administrator
645 * to change the lwp stack dynamically without getting a new binary version.
647 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
648 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
651 (AFS_LWP_MINSTACKSIZE >
652 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
658 LWP_INTERNALSIGNAL(void *event, int yield)
659 { /* signal the occurence of an event */
660 Debug(2, ("Entered LWP_SignalProcess"));
663 rc = Internal_Signal(event);
672 LWP_TerminateProcessSupport(void)
673 { /* terminate all LWP support */
676 Debug(0, ("Entered Terminate_Process_Support"));
677 if (lwp_init == NULL)
679 if (lwp_cpptr != LWPANCHOR.outerpid)
680 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
681 for (i = 0; i < MAX_PRIORITIES; i++)
682 for_all_elts(cur, runnable[i], {
685 for_all_elts(cur, blocked, {
688 for_all_elts(cur, qwaiting, {
697 LWP_WaitProcess(void *event)
698 { /* wait on a single event */
701 Debug(2, ("Entered Wait_Process"));
703 return LWP_EBADEVENT;
706 return LWP_MwaitProcess(1, tempev);
710 LWP_MwaitProcess(int wcount, void *evlist[])
711 { /* wait on m of n events */
712 register int ecount, i;
715 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
717 if (evlist == NULL) {
719 return LWP_EBADCOUNT;
722 for (ecount = 0; evlist[ecount] != NULL; ecount++);
726 return LWP_EBADCOUNT;
731 if (wcount > ecount || wcount < 0) {
733 return LWP_EBADCOUNT;
735 if (ecount > lwp_cpptr->eventlistsize) {
737 lwp_cpptr->eventlist =
738 (void **)realloc(lwp_cpptr->eventlist,
739 ecount * sizeof(void *));
740 lwp_cpptr->eventlistsize = ecount;
742 for (i = 0; i < ecount; i++)
743 lwp_cpptr->eventlist[i] = evlist[i];
745 lwp_cpptr->status = WAITING;
747 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
750 lwp_cpptr->wakevent = 0;
751 lwp_cpptr->waitcnt = wcount;
752 lwp_cpptr->eventcnt = ecount;
763 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
765 *maxa = pid->stacksize;
766 *used = Stack_Used(pid->stack, *maxa);
773 * The following functions are strictly
774 * INTERNAL to the LWP support package.
780 struct lwp_context tempcontext;
782 Debug(0, ("Entered Abort_LWP"));
783 printf("***LWP: %s\n", msg);
784 printf("***LWP: Abort --- dumping PCBs ...\n");
788 if (LWPANCHOR.outersp == NULL)
791 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
796 Create_Process_Part2(void)
797 { /* creates a context for the new process */
800 Debug(2, ("Entered Create_Process_Part2"));
801 temp = lwp_cpptr; /* Get current process id */
802 savecontext(Dispatcher, &temp->context, NULL);
803 (*temp->ep) (temp->parm);
804 LWP_DestroyProcess(temp);
809 Delete_PCB(register PROCESS pid)
810 { /* remove a PCB from the process list */
811 Debug(4, ("Entered Delete_PCB"));
813 (pid->blockflag || pid->status == WAITING
815 DESTROYED ? &blocked :
816 (pid->status == QWAITING) ? &qwaiting :
817 &runnable[pid->priority]));
818 LWPANCHOR.processcnt--;
824 Dump_One_Process(PROCESS pid)
828 printf("***LWP: Process Control Block at 0x%x\n", pid);
829 printf("***LWP: Name: %s\n", pid->name);
831 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
833 printf("BLOCKED and ");
834 switch (pid->status) {
851 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
853 if (pid->stacksize != 0) {
854 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
855 pid->stacksize, pid->stack);
856 printf("***LWP: HWM stack usage: ");
857 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
859 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
860 if (pid->eventcnt > 0) {
861 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
862 printf("***LWP: Event id list:");
863 for (i = 0; i < pid->eventcnt; i++)
864 printf(" 0x%x", pid->eventlist[i]);
867 if (pid->wakevent > 0)
868 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
874 purge_dead_pcbs(void)
876 for_all_elts(cur, blocked, {
877 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
882 int LWP_TraceProcesses = 0;
886 { /* Lightweight process dispatcher */
889 static int dispatch_count = 0;
891 if (LWP_TraceProcesses > 0) {
892 for (i = 0; i < MAX_PRIORITIES; i++) {
893 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
894 for_all_elts(p, runnable[i], {
895 printf(" \"%s\"", p->name);
900 printf("[Blocked (%d):", blocked.count);
901 for_all_elts(p, blocked, {
902 printf(" \"%s\"", p->name);
906 printf("[Qwaiting (%d):", qwaiting.count);
907 for_all_elts(p, qwaiting, {
908 printf(" \"%s\"", p->name);
915 /* Check for stack overflowif this lwp has a stack. Check for
916 * the guard word at the front of the stack being damaged and
917 * for the stack pointer being below the front of the stack.
918 * WARNING! This code assumes that stacks grow downward. */
919 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
920 /* Fix this (stackcheck at other end of stack?) */
921 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
922 && (lwp_cpptr->stackcheck !=
923 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
924 || lwp_cpptr->context.topstack >
925 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
927 if (lwp_cpptr && lwp_cpptr->stack
928 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
929 || lwp_cpptr->context.topstack < lwp_cpptr->stack
930 || lwp_cpptr->context.topstack >
931 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
933 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
934 *(int *)lwp_cpptr->stack);
935 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
936 (uintptr_t)lwp_cpptr->context.topstack,
937 (uintptr_t)lwp_cpptr->stack,
938 lwp_cpptr->stacksize);
940 switch (lwp_overflowAction) {
949 lwp_overflowAction = LWP_SOQUIET;
954 /* Move head of current runnable queue forward if current LWP is still in it. */
955 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
956 runnable[lwp_cpptr->priority].head =
957 runnable[lwp_cpptr->priority].head->next;
958 /* Find highest priority with runnable processes. */
959 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
960 if (runnable[i].head != NULL)
964 Abort_LWP("No READY processes");
967 if (LWP_TraceProcesses > 0)
968 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
969 runnable[i].head, runnable[i].head->name);
971 #ifndef AFS_ARM_LINUX20_ENV
973 Abort_LWP("PRE_Block not 1");
975 lwp_cpptr = runnable[i].head;
977 returnto(&lwp_cpptr->context);
979 return; /* not reachable */
982 /* Complain of a stack overflow to stderr without using stdio. */
984 Overflow_Complain(void)
988 char *msg1 = " LWP: stack overflow in process ";
991 currenttime = time(0);
992 timeStamp = ctime(¤ttime);
994 write(2, timeStamp, strlen(timeStamp));
996 write(2, msg1, strlen(msg1));
997 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
998 write(2, msg2, strlen(msg2));
1002 Dispose_of_Dead_PCB(PROCESS cur)
1004 Debug(4, ("Entered Dispose_of_Dead_PCB"));
1008 Internal_Signal(cur);
1019 Free_PCB(PROCESS pid)
1021 Debug(4, ("Entered Free_PCB"));
1022 if (pid->stack != NULL) {
1024 ("HWM stack usage: %d, [PCB at 0x%x]",
1025 Stack_Used(pid->stack, pid->stacksize), pid));
1026 #ifndef AFS_AIX32_ENV
1030 if (pid->eventlist != NULL)
1031 free(pid->eventlist);
1036 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1037 void *(*ep) (void *), void *parm, char *name)
1041 Debug(4, ("Entered Initialize_PCB"));
1043 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1045 temp->name[31] = '\0';
1046 temp->status = READY;
1047 temp->eventlist = (void **)malloc(EVINITSIZE * sizeof(void *));
1048 temp->eventlistsize = EVINITSIZE;
1052 temp->blockflag = 0;
1053 temp->iomgrRequest = 0;
1054 temp->priority = priority;
1055 temp->index = lwp_nextindex++;
1056 temp->stack = stack;
1057 temp->stacksize = stacksize;
1058 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1059 if (temp->stack != NULL)
1060 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1062 if (temp->stack != NULL)
1063 temp->stackcheck = *(int *)(temp->stack);
1067 temp->misc = NULL; /* currently unused */
1070 temp->lwp_rused = 0;
1071 temp->level = 1; /* non-preemptable */
1075 Internal_Signal(register void *event)
1077 int rc = LWP_ENOWAIT;
1080 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1084 return LWP_EBADEVENT;
1085 for_all_elts(temp, blocked, {
1086 if (temp->status == WAITING)
1087 for (i = 0; i < temp->eventcnt; i++) {
1088 if (temp->eventlist[i] == event) {
1089 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1090 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1091 if (--temp->waitcnt == 0) {
1092 temp->status = READY; temp->wakevent = i + 1;
1093 move(temp, &blocked, &runnable[temp->priority]); break;}
1101 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1102 #define STACKMAGIC 0xBADBADBA
1104 Initialize_Stack(char *stackptr, int stacksize)
1108 Debug(4, ("Entered Initialize_Stack"));
1109 if (lwp_stackUseEnabled)
1110 for (i = 0; i < stacksize; i++)
1111 stackptr[i] = i & 0xff;
1113 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1114 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1116 *(afs_int32 *) stackptr = STACKMAGIC;
1122 Stack_Used(register char *stackptr, int stacksize)
1126 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1127 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1130 for (i = stacksize - 1; i >= 0; i--)
1131 if ((unsigned char)stackptr[i] != (i & 0xff))
1136 if (*(afs_int32 *) stackptr == STACKMAGIC)
1139 for (i = 0; i < stacksize; i++)
1140 if ((unsigned char)stackptr[i] != (i & 0xff))
1141 return (stacksize - i);
1149 LWP_NewRock(int Tag, char *Value)
1150 /* Finds a free rock and sets its value to Value.
1152 * LWP_SUCCESS Rock did not exist and a new one was used
1153 * LWP_EBADROCK Rock already exists.
1154 * LWP_ENOROCKS All rocks are in use.
1156 * From the above semantics, you can only set a rock value once. This is specifically
1157 * to prevent multiple users of the LWP package from accidentally using the same Tag
1158 * value and clobbering others. You can always use one level of indirection to obtain
1159 * a rock whose contents can change.
1163 register struct rock *ra; /* rock array */
1165 ra = lwp_cpptr->lwp_rlist;
1167 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1168 if (ra[i].tag == Tag)
1169 return (LWP_EBADROCK);
1171 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1172 ra[lwp_cpptr->lwp_rused].tag = Tag;
1173 ra[lwp_cpptr->lwp_rused].value = Value;
1174 lwp_cpptr->lwp_rused++;
1175 return (LWP_SUCCESS);
1177 return (LWP_ENOROCKS);
1182 LWP_GetRock(int Tag, char **Value)
1183 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1185 * LWP_SUCCESS if specified rock exists and Value has been filled
1186 * LWP_EBADROCK rock specified does not exist
1190 register struct rock *ra;
1192 ra = lwp_cpptr->lwp_rlist;
1194 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1195 if (ra[i].tag == Tag) {
1196 *Value = ra[i].value;
1197 return (LWP_SUCCESS);
1199 return (LWP_EBADROCK);
1203 #ifdef AFS_AIX32_ENV
1205 setlim(int limcon, uchar_t hard, int limit)
1209 (void)getrlimit(limcon, &rlim);
1211 limit = limit * 1024;
1213 rlim.rlim_max = limit;
1214 else if (limit == RLIM_INFINITY && geteuid() != 0)
1215 rlim.rlim_cur = rlim.rlim_max;
1217 rlim.rlim_cur = limit;
1219 /* Must use ulimit() due to Posix constraints */
1220 if (limcon == RLIMIT_FSIZE) {
1223 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1224 printf("Can't %s%s limit\n",
1225 limit == RLIM_INFINITY ? "remove" : "set",
1226 hard ? " hard" : "");
1230 if (setrlimit(limcon, &rlim) < 0) {
1232 printf("Can't %s%s limit\n",
1233 limit == RLIM_INFINITY ? "remove" : "set",
1234 hard ? " hard" : "");
1244 * Print the specific limit out
1247 plim(char *name, afs_int32 lc, uchar_t hard)
1252 printf("%s \t", name);
1253 (void)getrlimit(lc, &rlim);
1254 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1255 if (lim == RLIM_INFINITY)
1256 printf("unlimited");
1257 printf("%d %s", lim / 1024, "kbytes");
1265 LWP_NoYieldSignal(void *event)
1267 return (LWP_INTERNALSIGNAL(event, 0));
1271 LWP_SignalProcess(void *event)
1273 return (LWP_INTERNALSIGNAL(event, 1));
1278 #ifdef USE_SOLARIS_THREADS
1281 #include "pthread.h"
1286 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1288 PROCESS lwp_process_list; /* List of LWP initiated threads */
1290 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1292 #define CHECK check(__LINE__);
1294 typedef struct event {
1295 struct event *next; /* next in hash chain */
1296 void *event; /* lwp event: an address */
1297 int refcount; /* Is it in use? */
1298 pthread_cond_t cond; /* Currently associated condition variable */
1299 int seq; /* Sequence number: this is incremented
1300 * by wakeup calls; wait will not return until
1304 #define HASHSIZE 127
1305 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1306 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1308 #if CMA_DEBUG || DEBUGF
1310 lwp_process_string(void)
1312 static char id[200];
1314 LWP_CurrentProcess(&p);
1315 sprintf(id, "PID %x <%s>", p, p->name);
1321 lwp_unimplemented(char *interface)
1324 "cmalwp: %s is not currently implemented: program aborted\n",
1330 lwpabort(char *interface)
1332 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1339 lwp_unimplemented("LWP_QWait");
1343 LWP_QSignal(int pid)
1345 lwp_unimplemented("LWP_QSignal");
1348 /* Allocate and initialize an LWP process handle. The associated pthread handle
1349 * must be added by the caller, and the structure threaded onto the LWP active
1350 * process list by lwp_thread_process */
1352 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1355 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1356 memset((char *)lp, 0, sizeof(*lp));
1360 sprintf(temp, "unnamed_process_%04d", ++procnum);
1361 assert(name = (char *)malloc(strlen(temp) + 1));
1370 /* Thread the LWP process descriptor *lp onto the lwp active process list
1371 * and associate a back pointer to the process descriptor from the associated
1374 lwp_thread_process(PROCESS lp)
1376 lp->next = lwp_process_list;
1377 lwp_process_list = lp;
1378 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1381 /* The top-level routine used as entry point to explicitly created LWP
1382 * processes. This completes a few details of process creation left
1383 * out by LWP_CreateProcess and calls the user-specified entry point */
1385 lwp_top_level(pthread_addr_t argp)
1387 PROCESS lp = (PROCESS) argp;
1389 assert(!pthread_mutex_lock(&lwp_mutex));
1390 lwp_thread_process(lp);
1392 assert(!pthread_mutex_unlock(&lwp_mutex));
1393 /* Should cleanup state */
1397 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1398 void *parm, char *name, PROCESS * pid)
1401 pthread_attr_t attr;
1405 #ifndef LWP_NO_PRIORITIES
1406 if (!cmalwp_pri_inrange(priority))
1409 assert(!pthread_attr_create(&attr));
1410 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1412 assert(!pthread_attr_setstacksize(&attr, stacksize));
1414 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1415 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1416 #ifndef LWP_NO_PRIORITIES
1417 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1420 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1421 (pthread_addr_t) parm);
1423 /* allow new thread to run if higher priority */
1424 assert(!pthread_mutex_unlock(&lwp_mutex));
1425 /* process is only added to active list after first time it runs (it adds itself) */
1427 pthread_create(&lp->handle, attr,
1428 (pthread_startroutine_t) lwp_top_level,
1429 (pthread_addr_t) lp);
1430 assert(!pthread_attr_delete(&attr));
1431 assert(!pthread_mutex_lock(&lwp_mutex));
1441 LWP_ActiveProcess(void)
1442 { /* returns pid of current process */
1444 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1449 LWP_CurrentProcess(PROCESS * pid)
1450 { /* get pid of current process */
1451 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1456 LWP_DestroyProcess(PROCESS pid)
1457 { /* destroy a lightweight process */
1458 lwp_unimplemented("LWP_DestroyProcess");
1462 LWP_DispatchProcess(void)
1463 { /* explicit voluntary preemption */
1464 assert(!pthread_mutex_unlock(&lwp_mutex));
1466 assert(!pthread_mutex_lock(&lwp_mutex));
1471 lwp_process_key_destructor(void)
1476 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1478 static int initialized = 0;
1488 #ifndef LWP_NO_PRIORITIES
1489 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1493 /* Create pthread key to associate LWP process descriptor with each
1494 * LWP-created thread */
1495 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1496 lwp_process_key_destructor));
1498 lp = lwp_alloc_process("main process", main, 0);
1499 lp->handle = pthread_self();
1500 lwp_thread_process(lp);
1501 #ifndef LWP_NO_PRIORITIES
1502 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1503 cmalwp_lwppri_to_cmapri(priority));
1506 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1507 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1514 LWP_TerminateProcessSupport(void)
1515 { /* terminate all LWP support */
1516 lwp_unimplemented("LWP_TerminateProcessSupport");
1519 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1521 getevent(void *event)
1523 event_t *evp, *newp;
1526 hashcode = hash(event);
1527 evp = hashtable[hashcode];
1530 if (evp->event == event) {
1534 if (evp->refcount == 0)
1539 newp = (event_t *) malloc(sizeof(event_t));
1541 newp->next = hashtable[hashcode];
1542 hashtable[hashcode] = newp;
1543 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1546 newp->event = event;
1551 /* Release the specified event */
1552 #define relevent(evp) ((evp)->refcount--)
1555 LWP_WaitProcess(void *event)
1556 { /* wait on a single event */
1559 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1561 return LWP_EBADEVENT;
1562 ev = getevent(event);
1564 while (seq == ev->seq) {
1565 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1567 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1573 LWP_MwaitProcess(int wcount, char *evlist[])
1574 { /* wait on m of n events */
1575 lwp_unimplemented("LWP_MWaitProcess");
1579 LWP_NoYieldSignal(void *event)
1582 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1584 return LWP_EBADEVENT;
1585 ev = getevent(event);
1586 if (ev->refcount > 1) {
1588 assert(pthread_cond_broadcast(&ev->cond) == 0);
1595 LWP_SignalProcess(void *event)
1598 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1600 return LWP_EBADEVENT;
1601 ev = getevent(event);
1602 if (ev->refcount > 1) {
1604 assert(!pthread_mutex_unlock(&lwp_mutex));
1605 assert(!pthread_cond_broadcast(&ev->cond));
1607 assert(!pthread_mutex_lock(&lwp_mutex));
1614 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1616 lwp_unimplemented("LWP_StackUsed");
1620 LWP_NewRock(int Tag, char *Value)
1622 lwp_unimplemented("LWP_NewRock");
1626 LWP_GetRock(int Tag, char **Value)
1628 lwp_unimplemented("LWP_GetRock");
1632 LWP_GetProcessPriority(PROCESS pid, int *priority)
1633 { /* returns process priority */
1634 lwp_unimplemented("LWP_GetProcessPriority");
1637 #endif /* USE_PTHREADS */