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>
28 /* allocate externs here */
33 #include <sys/errno.h>
38 int setlim(int limcon, uchar_t hard, int limit);
41 extern char *getenv();
46 #if !defined(USE_PTHREADS) && !defined(USE_SOLARIS_THREADS)
49 extern void *malloc(int size);
50 extern void *realloc(void *ptr, int size);
52 #ifndef AFS_ARM_LINUX20_ENV
53 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
54 extern int PRE_Block; /* from preempt.c */
56 extern char PRE_Block; /* from preempt.c */
68 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
71 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
82 #elif defined(AFS_DARWIN_ENV)
83 #define STACK_ALIGN 16
92 #define Debug(level, msg) do { \
93 if (lwp_debug && lwp_debug >= level) { \
94 printf("***LWP (0x%x): ", lwp_cpptr); \
100 #define Debug(level, msg) do { \
105 static void Dispatcher(void);
106 static void Create_Process_Part2(void);
107 static void Exit_LWP(void);
108 static afs_int32 Initialize_Stack(char *stackptr, int stacksize);
109 static int Stack_Used(char *stackptr, int stacksize);
111 static void Abort_LWP(char *msg);
112 static void Overflow_Complain(void);
113 static void Initialize_PCB(PROCESS temp, int priority, char *stack,
114 int stacksize, void *(*ep)(void *), void *parm,
116 static void Dispose_of_Dead_PCB(PROCESS cur);
117 static void Free_PCB(PROCESS pid);
118 static int Internal_Signal(void *event);
119 static int purge_dead_pcbs(void);
120 static int LWP_MwaitProcess(int wcount, void *evlist[]);
123 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
128 } runnable[MAX_PRIORITIES], blocked, qwaiting;
129 /* Invariant for runnable queues: The head of each queue points to the
130 * currently running process if it is in that queue, or it points to the
131 * next process in that queue that should run. */
133 /* Offset of stack field within pcb -- used by stack checking stuff */
136 /* special user-tweakable option for AIX */
137 int lwp_MaxStackSize = 32768;
139 /* biggest LWP stack created so far */
140 int lwp_MaxStackSeen = 0;
142 /* Stack checking action */
143 int lwp_overflowAction = LWP_SOABORT;
145 /* Controls stack size counting. */
146 int lwp_stackUseEnabled = TRUE; /* pay the price */
150 /* Minimum stack size */
151 int lwp_MinStackSize = 0;
154 lwp_remove(PROCESS p, struct QUEUE *q)
156 /* Special test for only element on queue */
160 /* Not only element, do normal remove */
161 p->next->prev = p->prev;
162 p->prev->next = p->next;
164 /* See if head pointing to this element */
168 p->next = p->prev = NULL;
173 insert(PROCESS p, struct QUEUE *q)
175 if (q->head == NULL) { /* Queue is empty */
177 p->next = p->prev = p;
178 } else { /* Regular insert */
179 p->prev = q->head->prev;
180 q->head->prev->next = p;
189 move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
199 #define for_all_elts(var, q, body)\
201 PROCESS var, _NEXT_;\
203 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
204 _NEXT_ = var -> next;\
210 /*****************************************************************************\
212 * Following section documents the Assembler interfaces used by LWP code *
214 \*****************************************************************************/
217 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
219 Stub for Assembler routine that will
220 save the current SP value in the passed
221 context savearea and call the function
222 whose entry point is in ep. If the sp
223 parameter is NULL, the current stack is
224 used, otherwise sp becomes the new stack
227 returnto(struct lwp_context *savearea);
229 Stub for Assembler routine that will
230 restore context from a passed savearea
231 and return to the restored C frame.
235 /* Macro to force a re-schedule. Strange name is historical */
236 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
238 static struct lwp_ctl *lwp_init = 0;
244 (tp = lwp_cpptr)->status = QWAITING;
245 move(tp, &runnable[tp->priority], &qwaiting);
251 LWP_QSignal(PROCESS pid)
253 if (pid->status == QWAITING) {
255 move(pid, &qwaiting, &runnable[pid->priority]);
263 reserveFromStack(afs_int32 size)
272 LWP_CreateProcess(void *(*ep) (void *), int stacksize, int priority, void *parm,
273 char *name, PROCESS * pid)
277 static char *stackptr = 0;
283 #if defined(AFS_LWP_MINSTACKSIZE)
285 * on some systems (e.g. hpux), a minimum usable stack size has
288 if (stacksize < lwp_MinStackSize) {
289 stacksize = lwp_MinStackSize;
291 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
292 /* more stack size computations; keep track of for IOMGR */
293 if (lwp_MaxStackSeen < stacksize)
294 lwp_MaxStackSeen = stacksize;
296 Debug(0, ("Entered LWP_CreateProcess"));
297 /* Throw away all dead process control blocks */
300 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
305 if (stacksize < MINSTACK)
306 #ifdef AFS_DARWIN_ENV
308 #else /* !AFS_DARWIN_ENV */
310 #endif /* !AFS_DARWIN_ENV */
313 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
317 * The following signal action for AIX is necessary so that in case of a
318 * crash (i.e. core is generated) we can include the user's data section
319 * in the core dump. Unfortunately, by default, only a partial core is
320 * generated which, in many cases, isn't too useful.
322 * We also do it here in case the main program forgets to do it.
324 struct sigaction nsa;
325 extern uid_t geteuid();
327 sigemptyset(&nsa.sa_mask);
328 nsa.sa_handler = SIG_DFL;
329 nsa.sa_flags = SA_FULLDUMP;
330 sigaction(SIGABRT, &nsa, NULL);
331 sigaction(SIGSEGV, &nsa, NULL);
334 * First we need to increase the default resource limits,
335 * if necessary, so that we can guarantee that we have the
336 * resources to create the core file, but we can't always
337 * do it as an ordinary user.
340 /* vos dump causes problems */
341 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
342 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
343 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
346 * Now reserve in one scoop all the stack space that will be used
347 * by the particular application's main (i.e. non-lwp) body. This
348 * is plenty space for any of our applications.
350 stackptr = reserveFromStack(lwp_MaxStackSize);
352 stackptr -= stacksize;
353 stackmemory = stackptr;
355 #ifdef AFS_DARWIN_ENV
356 if ((stackmemory = (char *)malloc(stacksize + STACK_ALIGN - 1)) == NULL)
357 #else /* !AFS_DARWIN_ENV */
358 if ((stackmemory = (char *)malloc(stacksize + 7)) == NULL)
359 #endif /* !AFS_DARWIN_ENV */
364 /* Round stack pointer to byte boundary */
365 #ifdef AFS_DARWIN_ENV
366 stackptr = (char *)(STACK_ALIGN * (((long)stackmemory + STACK_ALIGN - 1) / STACK_ALIGN));
367 #else /* !AFS_DARWIN_ENV */
368 stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
369 #endif /* !AFS_DARWIN_ENV */
371 if (priority < 0 || priority >= MAX_PRIORITIES) {
375 Initialize_Stack(stackptr, stacksize);
376 Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
377 insert(temp, &runnable[priority]);
379 #ifndef AFS_ARM_LINUX20_ENV
381 Abort_LWP("PRE_Block not 0");
383 /* Gross hack: beware! */
387 #if defined(AFS_PARISC_LINUX24_ENV)
388 savecontext(Create_Process_Part2, &temp2->context,
389 stackptr + MINFRAME);
392 savecontext(Create_Process_Part2, &temp2->context,
393 stackptr + MINFRAME);
395 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
396 #ifdef sys_x86_darwin_80
397 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16 - sizeof(void *)); /* 16 = 2 * jmp_buf_type */
398 #else /* !sys_x86_darwin_80 */
399 /* Need to have the sp on an 8-byte boundary for storing doubles. */
400 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16); /* 16 = 2 * jmp_buf_type */
401 #endif /* !sys_x86_darwin_80 */
403 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
404 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40); /* lomgjmp does something
407 #if defined(AFS_S390_LINUX20_ENV)
408 savecontext(Create_Process_Part2, &temp2->context,
409 stackptr + stacksize - MINFRAME);
410 #else /* !AFS_S390_LINUX20_ENV */
411 savecontext(Create_Process_Part2, &temp2->context,
412 stackptr + stacksize - sizeof(void *));
413 #endif /* AFS_S390_LINUX20_ENV */
414 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
415 #endif /* AFS_SGI62_ENV */
418 /* End of gross hack */
429 LWP_CreateProcess2(void *(*ep) (void *), int stacksize, int priority, void *parm,
430 char *name, PROCESS * pid)
435 #if defined(AFS_LWP_MINSTACKSIZE)
437 * on some systems (e.g. hpux), a minimum usable stack size has
440 if (stacksize < lwp_MinStackSize) {
441 stacksize = lwp_MinStackSize;
443 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
444 /* more stack size computations; keep track of for IOMGR */
445 if (lwp_MaxStackSeen < stacksize)
446 lwp_MaxStackSeen = stacksize;
448 Debug(0, ("Entered LWP_CreateProcess"));
449 /* Throw away all dead process control blocks */
452 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
457 if (stacksize < MINSTACK)
461 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
462 if ((stackptr = (char *)malloc(stacksize)) == NULL) {
466 if (priority < 0 || priority >= MAX_PRIORITIES) {
470 Initialize_Stack(stackptr, stacksize);
471 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
472 insert(temp, &runnable[priority]);
474 #ifndef AFS_ARM_LINUX20_ENV
476 Abort_LWP("PRE_Block not 0");
478 /* Gross hack: beware! */
482 savecontext(Create_Process_Part2, &temp2->context,
483 stackptr + stacksize - sizeof(void *));
484 /* End of gross hack */
495 LWP_CurrentProcess(PROCESS * pid)
496 { /* returns pid of current process */
497 Debug(0, ("Entered Current_Process"));
508 Debug(0, ("Entered ThreadId"));
515 #define LWPANCHOR (*lwp_init)
518 LWP_DestroyProcess(PROCESS pid)
519 { /* destroy a lightweight process */
522 Debug(0, ("Entered Destroy_Process"));
524 if (lwp_cpptr != pid) {
525 Dispose_of_Dead_PCB(pid);
528 pid->status = DESTROYED;
529 move(pid, &runnable[pid->priority], &blocked);
531 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
532 savecontext(Dispatcher, &(temp->context),
533 &(LWPANCHOR.dsptchstack[MINFRAME]));
534 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
535 savecontext(Dispatcher, &(temp->context),
537 dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
538 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
539 savecontext(Dispatcher, &(temp->context),
541 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
543 #elif defined(AFS_S390_LINUX20_ENV)
544 savecontext(Dispatcher, &(temp->context),
546 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
549 savecontext(Dispatcher, &(temp->context),
551 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
561 LWP_DispatchProcess(void)
562 { /* explicit voluntary preemption */
563 Debug(2, ("Entered Dispatch_Process"));
577 for (i = 0; i < MAX_PRIORITIES; i++)
578 for_all_elts(x, runnable[i], {
579 printf("[Priority %d]\n", i);
583 for_all_elts(x, blocked, {
584 Dump_One_Process(x);}
586 for_all_elts(x, qwaiting, {
587 Dump_One_Process(x);}
590 printf("***LWP: LWP support not initialized\n");
596 LWP_GetProcessPriority(PROCESS pid, int *priority)
597 { /* returns process priority */
598 Debug(0, ("Entered Get_Process_Priority"));
600 *priority = pid->priority;
607 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
610 struct lwp_pcb dummy;
614 Debug(0, ("Entered LWP_InitializeProcessSupport"));
615 if (lwp_init != NULL)
618 /* Set up offset for stack checking -- do this as soon as possible */
619 stack_offset = (char *)&dummy.stack - (char *)&dummy;
621 if (priority >= MAX_PRIORITIES)
623 for (i = 0; i < MAX_PRIORITIES; i++) {
624 runnable[i].head = NULL;
625 runnable[i].count = 0;
629 qwaiting.head = NULL;
631 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
632 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
633 if (lwp_init == NULL || temp == NULL)
634 Abort_LWP("Insufficient Storage to Initialize LWP Support");
635 LWPANCHOR.processcnt = 1;
636 LWPANCHOR.outerpid = temp;
637 LWPANCHOR.outersp = NULL;
638 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
639 "Main Process [created by LWP]");
640 insert(temp, &runnable[priority]);
641 savecontext(Dispatcher, &temp->context, NULL);
642 LWPANCHOR.outersp = temp->context.topstack;
646 /* get minimum stack size from the environment. this allows the administrator
647 * to change the lwp stack dynamically without getting a new binary version.
649 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
650 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
653 (AFS_LWP_MINSTACKSIZE >
654 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
660 LWP_INTERNALSIGNAL(void *event, int yield)
661 { /* signal the occurence of an event */
662 Debug(2, ("Entered LWP_SignalProcess"));
665 rc = Internal_Signal(event);
674 LWP_TerminateProcessSupport(void)
675 { /* terminate all LWP support */
678 Debug(0, ("Entered Terminate_Process_Support"));
679 if (lwp_init == NULL)
681 if (lwp_cpptr != LWPANCHOR.outerpid)
682 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
683 for (i = 0; i < MAX_PRIORITIES; i++)
684 for_all_elts(cur, runnable[i], {
687 for_all_elts(cur, blocked, {
690 for_all_elts(cur, qwaiting, {
699 LWP_WaitProcess(void *event)
700 { /* wait on a single event */
703 Debug(2, ("Entered Wait_Process"));
705 return LWP_EBADEVENT;
708 return LWP_MwaitProcess(1, tempev);
712 LWP_MwaitProcess(int wcount, void *evlist[])
713 { /* wait on m of n events */
717 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
719 if (evlist == NULL) {
721 return LWP_EBADCOUNT;
724 for (ecount = 0; evlist[ecount] != NULL; ecount++);
728 return LWP_EBADCOUNT;
733 if (wcount > ecount || wcount < 0) {
735 return LWP_EBADCOUNT;
737 if (ecount > lwp_cpptr->eventlistsize) {
739 lwp_cpptr->eventlist =
740 (void **)realloc(lwp_cpptr->eventlist,
741 ecount * sizeof(void *));
742 lwp_cpptr->eventlistsize = ecount;
744 for (i = 0; i < ecount; i++)
745 lwp_cpptr->eventlist[i] = evlist[i];
747 lwp_cpptr->status = WAITING;
749 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
752 lwp_cpptr->wakevent = 0;
753 lwp_cpptr->waitcnt = wcount;
754 lwp_cpptr->eventcnt = ecount;
765 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
767 *maxa = pid->stacksize;
768 *used = Stack_Used(pid->stack, *maxa);
775 * The following functions are strictly
776 * INTERNAL to the LWP support package.
782 struct lwp_context tempcontext;
784 Debug(0, ("Entered Abort_LWP"));
785 printf("***LWP: %s\n", msg);
786 printf("***LWP: Abort --- dumping PCBs ...\n");
790 if (LWPANCHOR.outersp == NULL)
793 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
798 Create_Process_Part2(void)
799 { /* creates a context for the new process */
802 Debug(2, ("Entered Create_Process_Part2"));
803 temp = lwp_cpptr; /* Get current process id */
804 savecontext(Dispatcher, &temp->context, NULL);
805 (*temp->ep) (temp->parm);
806 LWP_DestroyProcess(temp);
811 Delete_PCB(PROCESS pid)
812 { /* remove a PCB from the process list */
813 Debug(4, ("Entered Delete_PCB"));
815 (pid->blockflag || pid->status == WAITING
817 DESTROYED ? &blocked :
818 (pid->status == QWAITING) ? &qwaiting :
819 &runnable[pid->priority]));
820 LWPANCHOR.processcnt--;
826 Dump_One_Process(PROCESS pid)
830 printf("***LWP: Process Control Block at 0x%x\n", pid);
831 printf("***LWP: Name: %s\n", pid->name);
833 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
835 printf("BLOCKED and ");
836 switch (pid->status) {
853 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
855 if (pid->stacksize != 0) {
856 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
857 pid->stacksize, pid->stack);
858 printf("***LWP: HWM stack usage: ");
859 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
861 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
862 if (pid->eventcnt > 0) {
863 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
864 printf("***LWP: Event id list:");
865 for (i = 0; i < pid->eventcnt; i++)
866 printf(" 0x%x", pid->eventlist[i]);
869 if (pid->wakevent > 0)
870 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
876 purge_dead_pcbs(void)
878 for_all_elts(cur, blocked, {
879 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
884 int LWP_TraceProcesses = 0;
888 { /* Lightweight process dispatcher */
891 static int dispatch_count = 0;
893 if (LWP_TraceProcesses > 0) {
894 for (i = 0; i < MAX_PRIORITIES; i++) {
895 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
896 for_all_elts(p, runnable[i], {
897 printf(" \"%s\"", p->name);
902 printf("[Blocked (%d):", blocked.count);
903 for_all_elts(p, blocked, {
904 printf(" \"%s\"", p->name);
908 printf("[Qwaiting (%d):", qwaiting.count);
909 for_all_elts(p, qwaiting, {
910 printf(" \"%s\"", p->name);
917 /* Check for stack overflowif this lwp has a stack. Check for
918 * the guard word at the front of the stack being damaged and
919 * for the stack pointer being below the front of the stack.
920 * WARNING! This code assumes that stacks grow downward. */
921 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
922 /* Fix this (stackcheck at other end of stack?) */
923 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
924 && (lwp_cpptr->stackcheck !=
925 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
926 || lwp_cpptr->context.topstack >
927 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
929 if (lwp_cpptr && lwp_cpptr->stack
930 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
931 || lwp_cpptr->context.topstack < lwp_cpptr->stack
932 || lwp_cpptr->context.topstack >
933 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
935 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
936 *(int *)lwp_cpptr->stack);
937 printf("topstack = 0x%" AFS_PTR_FMT ": stackptr = 0x%" AFS_PTR_FMT ": stacksize = 0x%x\n",
938 (void *)(uintptr_t)lwp_cpptr->context.topstack,
939 (void *)(uintptr_t)lwp_cpptr->stack,
940 lwp_cpptr->stacksize);
942 switch (lwp_overflowAction) {
951 lwp_overflowAction = LWP_SOQUIET;
956 /* Move head of current runnable queue forward if current LWP is still in it. */
957 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
958 runnable[lwp_cpptr->priority].head =
959 runnable[lwp_cpptr->priority].head->next;
960 /* Find highest priority with runnable processes. */
961 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
962 if (runnable[i].head != NULL)
966 Abort_LWP("No READY processes");
969 if (LWP_TraceProcesses > 0)
970 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
971 runnable[i].head, runnable[i].head->name);
973 #ifndef AFS_ARM_LINUX20_ENV
975 Abort_LWP("PRE_Block not 1");
977 lwp_cpptr = runnable[i].head;
979 returnto(&lwp_cpptr->context);
981 return; /* not reachable */
984 /* Complain of a stack overflow to stderr without using stdio. */
986 Overflow_Complain(void)
990 char *msg1 = " LWP: stack overflow in process ";
993 currenttime = time(0);
994 timeStamp = ctime(¤ttime);
996 write(2, timeStamp, strlen(timeStamp));
998 write(2, msg1, strlen(msg1));
999 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
1000 write(2, msg2, strlen(msg2));
1004 Dispose_of_Dead_PCB(PROCESS cur)
1006 Debug(4, ("Entered Dispose_of_Dead_PCB"));
1010 Internal_Signal(cur);
1021 Free_PCB(PROCESS pid)
1023 Debug(4, ("Entered Free_PCB"));
1024 if (pid->stack != NULL) {
1026 ("HWM stack usage: %d, [PCB at 0x%x]",
1027 Stack_Used(pid->stack, pid->stacksize), pid));
1028 #ifndef AFS_AIX32_ENV
1032 if (pid->eventlist != NULL)
1033 free(pid->eventlist);
1038 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1039 void *(*ep) (void *), void *parm, char *name)
1043 Debug(4, ("Entered Initialize_PCB"));
1045 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1047 temp->name[31] = '\0';
1048 temp->status = READY;
1049 temp->eventlist = (void **)malloc(EVINITSIZE * sizeof(void *));
1050 temp->eventlistsize = EVINITSIZE;
1054 temp->blockflag = 0;
1055 temp->iomgrRequest = 0;
1056 temp->priority = priority;
1057 temp->index = lwp_nextindex++;
1058 temp->stack = stack;
1059 temp->stacksize = stacksize;
1060 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1061 if (temp->stack != NULL)
1062 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1064 if (temp->stack != NULL)
1065 temp->stackcheck = *(int *)(temp->stack);
1069 temp->misc = NULL; /* currently unused */
1072 temp->lwp_rused = 0;
1073 temp->level = 1; /* non-preemptable */
1077 Internal_Signal(void *event)
1079 int rc = LWP_ENOWAIT;
1082 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1086 return LWP_EBADEVENT;
1087 for_all_elts(temp, blocked, {
1088 if (temp->status == WAITING)
1089 for (i = 0; i < temp->eventcnt; i++) {
1090 if (temp->eventlist[i] == event) {
1091 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1092 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1093 if (--temp->waitcnt == 0) {
1094 temp->status = READY; temp->wakevent = i + 1;
1095 move(temp, &blocked, &runnable[temp->priority]); break;}
1103 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1104 #define STACKMAGIC 0xBADBADBA
1106 Initialize_Stack(char *stackptr, int stacksize)
1110 Debug(4, ("Entered Initialize_Stack"));
1111 if (lwp_stackUseEnabled)
1112 for (i = 0; i < stacksize; i++)
1113 stackptr[i] = i & 0xff;
1115 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1116 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1118 *(afs_int32 *) stackptr = STACKMAGIC;
1124 Stack_Used(char *stackptr, int stacksize)
1128 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1129 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1132 for (i = stacksize - 1; i >= 0; i--)
1133 if ((unsigned char)stackptr[i] != (i & 0xff))
1138 if (*(afs_int32 *) stackptr == STACKMAGIC)
1141 for (i = 0; i < stacksize; i++)
1142 if ((unsigned char)stackptr[i] != (i & 0xff))
1143 return (stacksize - i);
1151 LWP_NewRock(int Tag, char *Value)
1152 /* Finds a free rock and sets its value to Value.
1154 * LWP_SUCCESS Rock did not exist and a new one was used
1155 * LWP_EBADROCK Rock already exists.
1156 * LWP_ENOROCKS All rocks are in use.
1158 * From the above semantics, you can only set a rock value once. This is specifically
1159 * to prevent multiple users of the LWP package from accidentally using the same Tag
1160 * value and clobbering others. You can always use one level of indirection to obtain
1161 * a rock whose contents can change.
1165 struct rock *ra; /* rock array */
1167 ra = lwp_cpptr->lwp_rlist;
1169 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1170 if (ra[i].tag == Tag)
1171 return (LWP_EBADROCK);
1173 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1174 ra[lwp_cpptr->lwp_rused].tag = Tag;
1175 ra[lwp_cpptr->lwp_rused].value = Value;
1176 lwp_cpptr->lwp_rused++;
1177 return (LWP_SUCCESS);
1179 return (LWP_ENOROCKS);
1184 LWP_GetRock(int Tag, char **Value)
1185 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1187 * LWP_SUCCESS if specified rock exists and Value has been filled
1188 * LWP_EBADROCK rock specified does not exist
1194 ra = lwp_cpptr->lwp_rlist;
1196 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1197 if (ra[i].tag == Tag) {
1198 *Value = ra[i].value;
1199 return (LWP_SUCCESS);
1201 return (LWP_EBADROCK);
1205 #ifdef AFS_AIX32_ENV
1207 setlim(int limcon, uchar_t hard, int limit)
1211 (void)getrlimit(limcon, &rlim);
1213 limit = limit * 1024;
1215 rlim.rlim_max = limit;
1216 else if (limit == RLIM_INFINITY && geteuid() != 0)
1217 rlim.rlim_cur = rlim.rlim_max;
1219 rlim.rlim_cur = limit;
1221 /* Must use ulimit() due to Posix constraints */
1222 if (limcon == RLIMIT_FSIZE) {
1225 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1226 printf("Can't %s%s limit\n",
1227 limit == RLIM_INFINITY ? "remove" : "set",
1228 hard ? " hard" : "");
1232 if (setrlimit(limcon, &rlim) < 0) {
1234 printf("Can't %s%s limit\n",
1235 limit == RLIM_INFINITY ? "remove" : "set",
1236 hard ? " hard" : "");
1246 * Print the specific limit out
1249 plim(char *name, afs_int32 lc, uchar_t hard)
1254 printf("%s \t", name);
1255 (void)getrlimit(lc, &rlim);
1256 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1257 if (lim == RLIM_INFINITY)
1258 printf("unlimited");
1259 printf("%d %s", lim / 1024, "kbytes");
1267 LWP_NoYieldSignal(void *event)
1269 return (LWP_INTERNALSIGNAL(event, 0));
1273 LWP_SignalProcess(void *event)
1275 return (LWP_INTERNALSIGNAL(event, 1));
1280 #ifdef USE_SOLARIS_THREADS
1283 #include "pthread.h"
1288 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1290 PROCESS lwp_process_list; /* List of LWP initiated threads */
1292 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1294 #define CHECK check(__LINE__);
1296 typedef struct event {
1297 struct event *next; /* next in hash chain */
1298 void *event; /* lwp event: an address */
1299 int refcount; /* Is it in use? */
1300 pthread_cond_t cond; /* Currently associated condition variable */
1301 int seq; /* Sequence number: this is incremented
1302 * by wakeup calls; wait will not return until
1306 #define HASHSIZE 127
1307 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1308 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1310 #if CMA_DEBUG || DEBUGF
1312 lwp_process_string(void)
1314 static char id[200];
1316 LWP_CurrentProcess(&p);
1317 sprintf(id, "PID %x <%s>", p, p->name);
1323 lwp_unimplemented(char *interface)
1326 "cmalwp: %s is not currently implemented: program aborted\n",
1332 lwpabort(char *interface)
1334 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1341 lwp_unimplemented("LWP_QWait");
1345 LWP_QSignal(int pid)
1347 lwp_unimplemented("LWP_QSignal");
1350 /* Allocate and initialize an LWP process handle. The associated pthread handle
1351 * must be added by the caller, and the structure threaded onto the LWP active
1352 * process list by lwp_thread_process */
1354 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1357 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1358 memset(lp, 0, sizeof(*lp));
1362 sprintf(temp, "unnamed_process_%04d", ++procnum);
1363 assert(name = (char *)malloc(strlen(temp) + 1));
1372 /* Thread the LWP process descriptor *lp onto the lwp active process list
1373 * and associate a back pointer to the process descriptor from the associated
1376 lwp_thread_process(PROCESS lp)
1378 lp->next = lwp_process_list;
1379 lwp_process_list = lp;
1380 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1383 /* The top-level routine used as entry point to explicitly created LWP
1384 * processes. This completes a few details of process creation left
1385 * out by LWP_CreateProcess and calls the user-specified entry point */
1387 lwp_top_level(pthread_addr_t argp)
1389 PROCESS lp = (PROCESS) argp;
1391 assert(!pthread_mutex_lock(&lwp_mutex));
1392 lwp_thread_process(lp);
1394 assert(!pthread_mutex_unlock(&lwp_mutex));
1395 /* Should cleanup state */
1399 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1400 void *parm, char *name, PROCESS * pid)
1403 pthread_attr_t attr;
1407 #ifndef LWP_NO_PRIORITIES
1408 if (!cmalwp_pri_inrange(priority))
1411 assert(!pthread_attr_create(&attr));
1412 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1414 assert(!pthread_attr_setstacksize(&attr, stacksize));
1416 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1417 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1418 #ifndef LWP_NO_PRIORITIES
1419 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1422 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1423 (pthread_addr_t) parm);
1425 /* allow new thread to run if higher priority */
1426 assert(!pthread_mutex_unlock(&lwp_mutex));
1427 /* process is only added to active list after first time it runs (it adds itself) */
1429 pthread_create(&lp->handle, attr,
1430 (pthread_startroutine_t) lwp_top_level,
1431 (pthread_addr_t) lp);
1432 assert(!pthread_attr_delete(&attr));
1433 assert(!pthread_mutex_lock(&lwp_mutex));
1443 LWP_ActiveProcess(void)
1444 { /* returns pid of current process */
1446 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1451 LWP_CurrentProcess(PROCESS * pid)
1452 { /* get pid of current process */
1453 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1458 LWP_DestroyProcess(PROCESS pid)
1459 { /* destroy a lightweight process */
1460 lwp_unimplemented("LWP_DestroyProcess");
1464 LWP_DispatchProcess(void)
1465 { /* explicit voluntary preemption */
1466 assert(!pthread_mutex_unlock(&lwp_mutex));
1468 assert(!pthread_mutex_lock(&lwp_mutex));
1473 lwp_process_key_destructor(void)
1478 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1480 static int initialized = 0;
1490 #ifndef LWP_NO_PRIORITIES
1491 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1495 /* Create pthread key to associate LWP process descriptor with each
1496 * LWP-created thread */
1497 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1498 lwp_process_key_destructor));
1500 lp = lwp_alloc_process("main process", main, 0);
1501 lp->handle = pthread_self();
1502 lwp_thread_process(lp);
1503 #ifndef LWP_NO_PRIORITIES
1504 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1505 cmalwp_lwppri_to_cmapri(priority));
1508 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1509 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1516 LWP_TerminateProcessSupport(void)
1517 { /* terminate all LWP support */
1518 lwp_unimplemented("LWP_TerminateProcessSupport");
1521 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1523 getevent(void *event)
1525 event_t *evp, *newp;
1528 hashcode = hash(event);
1529 evp = hashtable[hashcode];
1532 if (evp->event == event) {
1536 if (evp->refcount == 0)
1541 newp = (event_t *) malloc(sizeof(event_t));
1543 newp->next = hashtable[hashcode];
1544 hashtable[hashcode] = newp;
1545 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1548 newp->event = event;
1553 /* Release the specified event */
1554 #define relevent(evp) ((evp)->refcount--)
1557 LWP_WaitProcess(void *event)
1558 { /* wait on a single event */
1561 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1563 return LWP_EBADEVENT;
1564 ev = getevent(event);
1566 while (seq == ev->seq) {
1567 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1569 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1575 LWP_MwaitProcess(int wcount, char *evlist[])
1576 { /* wait on m of n events */
1577 lwp_unimplemented("LWP_MWaitProcess");
1581 LWP_NoYieldSignal(void *event)
1584 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1586 return LWP_EBADEVENT;
1587 ev = getevent(event);
1588 if (ev->refcount > 1) {
1590 assert(pthread_cond_broadcast(&ev->cond) == 0);
1597 LWP_SignalProcess(void *event)
1600 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1602 return LWP_EBADEVENT;
1603 ev = getevent(event);
1604 if (ev->refcount > 1) {
1606 assert(!pthread_mutex_unlock(&lwp_mutex));
1607 assert(!pthread_cond_broadcast(&ev->cond));
1609 assert(!pthread_mutex_lock(&lwp_mutex));
1616 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1618 lwp_unimplemented("LWP_StackUsed");
1622 LWP_NewRock(int Tag, char *Value)
1624 lwp_unimplemented("LWP_NewRock");
1628 LWP_GetRock(int Tag, char **Value)
1630 lwp_unimplemented("LWP_GetRock");
1634 LWP_GetProcessPriority(PROCESS pid, int *priority)
1635 { /* returns process priority */
1636 lwp_unimplemented("LWP_GetProcessPriority");
1639 #endif /* USE_PTHREADS */