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 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
51 extern int PRE_Block; /* from preempt.c */
53 extern char PRE_Block; /* from preempt.c */
64 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
67 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
78 #elif defined(AFS_DARWIN_ENV)
79 #define STACK_ALIGN 16
88 #define Debug(level, msg) do { \
89 if (lwp_debug && lwp_debug >= level) { \
90 printf("***LWP (0x%x): ", lwp_cpptr); \
96 #define Debug(level, msg) do { \
101 static int Dispatcher();
102 static int Create_Process_Part2();
103 static int Exit_LWP();
104 static afs_int32 Initialize_Stack();
105 static int Stack_Used();
106 char (*RC_to_ASCII());
108 static void Abort_LWP();
109 static void Overflow_Complain();
110 static void Initialize_PCB();
111 static void Dispose_of_Dead_PCB();
112 static void Free_PCB();
113 static int Internal_Signal();
114 static purge_dead_pcbs();
116 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
121 } runnable[MAX_PRIORITIES], blocked, qwaiting;
122 /* 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. */
124 /* Offset of stack field within pcb -- used by stack checking stuff */
127 /* special user-tweakable option for AIX */
128 int lwp_MaxStackSize = 32768;
130 /* biggest LWP stack created so far */
131 int lwp_MaxStackSeen = 0;
133 /* Stack checking action */
134 int lwp_overflowAction = LWP_SOABORT;
136 /* Controls stack size counting. */
137 int lwp_stackUseEnabled = TRUE; /* pay the price */
141 /* Minimum stack size */
142 int lwp_MinStackSize = 0;
145 lwp_remove(register PROCESS p, register struct QUEUE *q)
147 /* Special test for only element on queue */
151 /* Not only element, do normal remove */
152 p->next->prev = p->prev;
153 p->prev->next = p->next;
155 /* See if head pointing to this element */
159 p->next = p->prev = NULL;
164 insert(register PROCESS p, register struct QUEUE *q)
166 if (q->head == NULL) { /* Queue is empty */
168 p->next = p->prev = p;
169 } else { /* Regular insert */
170 p->prev = q->head->prev;
171 q->head->prev->next = p;
180 move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
190 #define for_all_elts(var, q, body)\
192 register PROCESS var, _NEXT_;\
194 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
195 _NEXT_ = var -> next;\
201 /*****************************************************************************\
203 * Following section documents the Assembler interfaces used by LWP code *
205 \*****************************************************************************/
208 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
210 Stub for Assembler routine that will
211 save the current SP value in the passed
212 context savearea and call the function
213 whose entry point is in ep. If the sp
214 parameter is NULL, the current stack is
215 used, otherwise sp becomes the new stack
218 returnto(struct lwp_context *savearea);
220 Stub for Assembler routine that will
221 restore context from a passed savearea
222 and return to the restored C frame.
226 /* Macro to force a re-schedule. Strange name is historical */
227 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
229 static struct lwp_ctl *lwp_init = 0;
235 (tp = lwp_cpptr)->status = QWAITING;
236 move(tp, &runnable[tp->priority], &qwaiting);
242 LWP_QSignal(register PROCESS pid)
244 if (pid->status == QWAITING) {
246 move(pid, &qwaiting, &runnable[pid->priority]);
254 reserveFromStack(register afs_int32 size)
263 LWP_CreateProcess(int (*ep) (), int stacksize, int priority, void *parm,
264 char *name, PROCESS * pid)
268 static char *stackptr = 0;
274 #if defined(AFS_LWP_MINSTACKSIZE)
276 * on some systems (e.g. hpux), a minimum usable stack size has
279 if (stacksize < lwp_MinStackSize) {
280 stacksize = lwp_MinStackSize;
282 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
283 /* more stack size computations; keep track of for IOMGR */
284 if (lwp_MaxStackSeen < stacksize)
285 lwp_MaxStackSeen = stacksize;
287 Debug(0, ("Entered LWP_CreateProcess"));
288 /* Throw away all dead process control blocks */
291 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
296 if (stacksize < MINSTACK)
297 #ifdef AFS_DARWIN_ENV
299 #else /* !AFS_DARWIN_ENV */
301 #endif /* !AFS_DARWIN_ENV */
304 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
308 * The following signal action for AIX is necessary so that in case of a
309 * crash (i.e. core is generated) we can include the user's data section
310 * in the core dump. Unfortunately, by default, only a partial core is
311 * generated which, in many cases, isn't too useful.
313 * We also do it here in case the main program forgets to do it.
315 struct sigaction nsa;
316 extern uid_t geteuid();
318 sigemptyset(&nsa.sa_mask);
319 nsa.sa_handler = SIG_DFL;
320 nsa.sa_flags = SA_FULLDUMP;
321 sigaction(SIGABRT, &nsa, NULL);
322 sigaction(SIGSEGV, &nsa, NULL);
325 * First we need to increase the default resource limits,
326 * if necessary, so that we can guarantee that we have the
327 * resources to create the core file, but we can't always
328 * do it as an ordinary user.
331 /* vos dump causes problems */
332 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
333 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
334 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
337 * Now reserve in one scoop all the stack space that will be used
338 * by the particular application's main (i.e. non-lwp) body. This
339 * is plenty space for any of our applications.
341 stackptr = reserveFromStack(lwp_MaxStackSize);
343 stackptr -= stacksize;
344 stackmemory = stackptr;
346 #ifdef AFS_DARWIN_ENV
347 if ((stackmemory = (char *)malloc(stacksize + STACK_ALIGN - 1)) == NULL)
348 #else /* !AFS_DARWIN_ENV */
349 if ((stackmemory = (char *)malloc(stacksize + 7)) == NULL)
350 #endif /* !AFS_DARWIN_ENV */
355 /* Round stack pointer to byte boundary */
356 #ifdef AFS_DARWIN_ENV
357 stackptr = (char *)(STACK_ALIGN * (((long)stackmemory + STACK_ALIGN - 1) / STACK_ALIGN));
358 #else /* !AFS_DARWIN_ENV */
359 stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
360 #endif /* !AFS_DARWIN_ENV */
362 if (priority < 0 || priority >= MAX_PRIORITIES) {
366 Initialize_Stack(stackptr, stacksize);
367 Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
368 insert(temp, &runnable[priority]);
371 Abort_LWP("PRE_Block not 0");
373 /* Gross hack: beware! */
376 #if defined(AFS_PARISC_LINUX24_ENV)
377 savecontext(Create_Process_Part2, &temp2->context,
378 stackptr + MINFRAME);
381 savecontext(Create_Process_Part2, &temp2->context,
382 stackptr + MINFRAME);
384 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
385 #ifdef sys_x86_darwin_80
386 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16 - sizeof(void *)); /* 16 = 2 * jmp_buf_type */
387 #else /* !sys_x86_darwin_80 */
388 /* Need to have the sp on an 8-byte boundary for storing doubles. */
389 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16); /* 16 = 2 * jmp_buf_type */
390 #endif /* !sys_x86_darwin_80 */
392 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
393 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40); /* lomgjmp does something
396 #if defined(AFS_S390_LINUX20_ENV)
397 savecontext(Create_Process_Part2, &temp2->context,
398 stackptr + stacksize - MINFRAME);
399 #else /* !AFS_S390_LINUX20_ENV */
400 savecontext(Create_Process_Part2, &temp2->context,
401 stackptr + stacksize - sizeof(void *));
402 #endif /* AFS_S390_LINUX20_ENV */
403 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
404 #endif /* AFS_SGI62_ENV */
407 /* End of gross hack */
418 LWP_CreateProcess2(int (*ep) (), int stacksize, int priority, void *parm,
419 char *name, PROCESS * pid)
424 #if defined(AFS_LWP_MINSTACKSIZE)
426 * on some systems (e.g. hpux), a minimum usable stack size has
429 if (stacksize < lwp_MinStackSize) {
430 stacksize = lwp_MinStackSize;
432 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
433 /* more stack size computations; keep track of for IOMGR */
434 if (lwp_MaxStackSeen < stacksize)
435 lwp_MaxStackSeen = stacksize;
437 Debug(0, ("Entered LWP_CreateProcess"));
438 /* Throw away all dead process control blocks */
441 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
446 if (stacksize < MINSTACK)
450 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
451 if ((stackptr = (char *)malloc(stacksize)) == NULL) {
455 if (priority < 0 || priority >= MAX_PRIORITIES) {
459 Initialize_Stack(stackptr, stacksize);
460 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
461 insert(temp, &runnable[priority]);
464 Abort_LWP("PRE_Block not 0");
466 /* Gross hack: beware! */
469 savecontext(Create_Process_Part2, &temp2->context,
470 stackptr + stacksize - sizeof(void *));
471 /* End of gross hack */
482 LWP_CurrentProcess(PROCESS * pid)
483 { /* returns pid of current process */
484 Debug(0, ("Entered Current_Process"));
495 Debug(0, ("Entered ThreadId"));
502 #define LWPANCHOR (*lwp_init)
505 LWP_DestroyProcess(PROCESS pid)
506 { /* destroy a lightweight process */
509 Debug(0, ("Entered Destroy_Process"));
511 if (lwp_cpptr != pid) {
512 Dispose_of_Dead_PCB(pid);
515 pid->status = DESTROYED;
516 move(pid, &runnable[pid->priority], &blocked);
518 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
519 savecontext(Dispatcher, &(temp->context),
520 &(LWPANCHOR.dsptchstack[MINFRAME]));
521 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
522 savecontext(Dispatcher, &(temp->context),
524 dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
525 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
526 savecontext(Dispatcher, &(temp->context),
528 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
530 #elif defined(AFS_S390_LINUX20_ENV)
531 savecontext(Dispatcher, &(temp->context),
533 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
536 savecontext(Dispatcher, &(temp->context),
538 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
548 LWP_DispatchProcess(void)
549 { /* explicit voluntary preemption */
550 Debug(2, ("Entered Dispatch_Process"));
564 for (i = 0; i < MAX_PRIORITIES; i++)
565 for_all_elts(x, runnable[i], {
566 printf("[Priority %d]\n", i);
570 for_all_elts(x, blocked, {
571 Dump_One_Process(x);}
573 for_all_elts(x, qwaiting, {
574 Dump_One_Process(x);}
577 printf("***LWP: LWP support not initialized\n");
583 LWP_GetProcessPriority(PROCESS pid, int *priority)
584 { /* returns process priority */
585 Debug(0, ("Entered Get_Process_Priority"));
587 *priority = pid->priority;
594 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
597 struct lwp_pcb dummy;
601 Debug(0, ("Entered LWP_InitializeProcessSupport"));
602 if (lwp_init != NULL)
605 /* Set up offset for stack checking -- do this as soon as possible */
606 stack_offset = (char *)&dummy.stack - (char *)&dummy;
608 if (priority >= MAX_PRIORITIES)
610 for (i = 0; i < MAX_PRIORITIES; i++) {
611 runnable[i].head = NULL;
612 runnable[i].count = 0;
616 qwaiting.head = NULL;
618 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
619 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
620 if (lwp_init == NULL || temp == NULL)
621 Abort_LWP("Insufficient Storage to Initialize LWP Support");
622 LWPANCHOR.processcnt = 1;
623 LWPANCHOR.outerpid = temp;
624 LWPANCHOR.outersp = NULL;
625 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
626 "Main Process [created by LWP]");
627 insert(temp, &runnable[priority]);
628 savecontext(Dispatcher, &temp->context, NULL);
629 LWPANCHOR.outersp = temp->context.topstack;
633 /* get minimum stack size from the environment. this allows the administrator
634 * to change the lwp stack dynamically without getting a new binary version.
636 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
637 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
640 (AFS_LWP_MINSTACKSIZE >
641 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
647 LWP_INTERNALSIGNAL(char *event, int yield)
648 { /* signal the occurence of an event */
649 Debug(2, ("Entered LWP_SignalProcess"));
652 rc = Internal_Signal(event);
661 LWP_TerminateProcessSupport(void)
662 { /* terminate all LWP support */
665 Debug(0, ("Entered Terminate_Process_Support"));
666 if (lwp_init == NULL)
668 if (lwp_cpptr != LWPANCHOR.outerpid)
669 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
670 for (i = 0; i < MAX_PRIORITIES; i++)
671 for_all_elts(cur, runnable[i], {
674 for_all_elts(cur, blocked, {
677 for_all_elts(cur, qwaiting, {
686 LWP_WaitProcess(char *event)
687 { /* wait on a single event */
690 Debug(2, ("Entered Wait_Process"));
692 return LWP_EBADEVENT;
695 return LWP_MwaitProcess(1, tempev);
699 LWP_MwaitProcess(int wcount, char *evlist[])
700 { /* wait on m of n events */
701 register int ecount, i;
704 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
706 if (evlist == NULL) {
708 return LWP_EBADCOUNT;
711 for (ecount = 0; evlist[ecount] != NULL; ecount++);
715 return LWP_EBADCOUNT;
720 if (wcount > ecount || wcount < 0) {
722 return LWP_EBADCOUNT;
724 if (ecount > lwp_cpptr->eventlistsize) {
726 lwp_cpptr->eventlist =
727 (char **)realloc(lwp_cpptr->eventlist,
728 ecount * sizeof(char *));
729 lwp_cpptr->eventlistsize = ecount;
731 for (i = 0; i < ecount; i++)
732 lwp_cpptr->eventlist[i] = evlist[i];
734 lwp_cpptr->status = WAITING;
736 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
739 lwp_cpptr->wakevent = 0;
740 lwp_cpptr->waitcnt = wcount;
741 lwp_cpptr->eventcnt = ecount;
752 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
754 *maxa = pid->stacksize;
755 *used = Stack_Used(pid->stack, *maxa);
762 * The following functions are strictly
763 * INTERNAL to the LWP support package.
769 struct lwp_context tempcontext;
771 Debug(0, ("Entered Abort_LWP"));
772 printf("***LWP: %s\n", msg);
773 printf("***LWP: Abort --- dumping PCBs ...\n");
777 if (LWPANCHOR.outersp == NULL)
780 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
785 Create_Process_Part2(void)
786 { /* creates a context for the new process */
789 Debug(2, ("Entered Create_Process_Part2"));
790 temp = lwp_cpptr; /* Get current process id */
791 savecontext(Dispatcher, &temp->context, NULL);
792 (*temp->ep) (temp->parm);
793 LWP_DestroyProcess(temp);
798 Delete_PCB(register PROCESS pid)
799 { /* remove a PCB from the process list */
800 Debug(4, ("Entered Delete_PCB"));
802 (pid->blockflag || pid->status == WAITING
804 DESTROYED ? &blocked :
805 (pid->status == QWAITING) ? &qwaiting :
806 &runnable[pid->priority]));
807 LWPANCHOR.processcnt--;
813 Dump_One_Process(PROCESS pid)
817 printf("***LWP: Process Control Block at 0x%x\n", pid);
818 printf("***LWP: Name: %s\n", pid->name);
820 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
822 printf("BLOCKED and ");
823 switch (pid->status) {
840 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
842 if (pid->stacksize != 0) {
843 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
844 pid->stacksize, pid->stack);
845 printf("***LWP: HWM stack usage: ");
846 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
848 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
849 if (pid->eventcnt > 0) {
850 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
851 printf("***LWP: Event id list:");
852 for (i = 0; i < pid->eventcnt; i++)
853 printf(" 0x%x", pid->eventlist[i]);
856 if (pid->wakevent > 0)
857 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
863 purge_dead_pcbs(void)
865 for_all_elts(cur, blocked, {
866 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
871 int LWP_TraceProcesses = 0;
875 { /* Lightweight process dispatcher */
878 static int dispatch_count = 0;
880 if (LWP_TraceProcesses > 0) {
881 for (i = 0; i < MAX_PRIORITIES; i++) {
882 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
883 for_all_elts(p, runnable[i], {
884 printf(" \"%s\"", p->name);
889 printf("[Blocked (%d):", blocked.count);
890 for_all_elts(p, blocked, {
891 printf(" \"%s\"", p->name);
895 printf("[Qwaiting (%d):", qwaiting.count);
896 for_all_elts(p, qwaiting, {
897 printf(" \"%s\"", p->name);
904 /* Check for stack overflowif this lwp has a stack. Check for
905 * the guard word at the front of the stack being damaged and
906 * for the stack pointer being below the front of the stack.
907 * WARNING! This code assumes that stacks grow downward. */
908 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
909 /* Fix this (stackcheck at other end of stack?) */
910 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
911 && (lwp_cpptr->stackcheck !=
912 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
913 || lwp_cpptr->context.topstack >
914 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
916 if (lwp_cpptr && lwp_cpptr->stack
917 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
918 || lwp_cpptr->context.topstack < lwp_cpptr->stack
919 || lwp_cpptr->context.topstack >
920 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
922 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
923 *(int *)lwp_cpptr->stack);
924 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
925 lwp_cpptr->context.topstack, lwp_cpptr->stack,
926 lwp_cpptr->stacksize);
928 switch (lwp_overflowAction) {
937 lwp_overflowAction = LWP_SOQUIET;
942 /* Move head of current runnable queue forward if current LWP is still in it. */
943 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
944 runnable[lwp_cpptr->priority].head =
945 runnable[lwp_cpptr->priority].head->next;
946 /* Find highest priority with runnable processes. */
947 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
948 if (runnable[i].head != NULL)
952 Abort_LWP("No READY processes");
955 if (LWP_TraceProcesses > 0)
956 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
957 runnable[i].head, runnable[i].head->name);
960 Abort_LWP("PRE_Block not 1");
961 lwp_cpptr = runnable[i].head;
963 returnto(&lwp_cpptr->context);
966 /* Complain of a stack overflow to stderr without using stdio. */
968 Overflow_Complain(void)
972 char *msg1 = " LWP: stack overflow in process ";
975 currenttime = time(0);
976 timeStamp = ctime(¤ttime);
978 write(2, timeStamp, strlen(timeStamp));
980 write(2, msg1, strlen(msg1));
981 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
982 write(2, msg2, strlen(msg2));
986 Dispose_of_Dead_PCB(PROCESS cur)
988 Debug(4, ("Entered Dispose_of_Dead_PCB"));
992 Internal_Signal(cur);
1003 Free_PCB(PROCESS pid)
1005 Debug(4, ("Entered Free_PCB"));
1006 if (pid->stack != NULL) {
1008 ("HWM stack usage: %d, [PCB at 0x%x]",
1009 Stack_Used(pid->stack, pid->stacksize), pid));
1010 #ifndef AFS_AIX32_ENV
1014 if (pid->eventlist != NULL)
1015 free(pid->eventlist);
1020 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1021 int (*ep) (), void *parm, char *name)
1025 Debug(4, ("Entered Initialize_PCB"));
1027 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1029 temp->name[31] = '\0';
1030 temp->status = READY;
1031 temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
1032 temp->eventlistsize = EVINITSIZE;
1036 temp->blockflag = 0;
1037 temp->iomgrRequest = 0;
1038 temp->priority = priority;
1039 temp->index = lwp_nextindex++;
1040 temp->stack = stack;
1041 temp->stacksize = stacksize;
1042 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1043 if (temp->stack != NULL)
1044 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1046 if (temp->stack != NULL)
1047 temp->stackcheck = *(int *)(temp->stack);
1051 temp->misc = NULL; /* currently unused */
1054 temp->lwp_rused = 0;
1055 temp->level = 1; /* non-preemptable */
1059 Internal_Signal(register char *event)
1061 int rc = LWP_ENOWAIT;
1064 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1068 return LWP_EBADEVENT;
1069 for_all_elts(temp, blocked, {
1070 if (temp->status == WAITING)
1071 for (i = 0; i < temp->eventcnt; i++) {
1072 if (temp->eventlist[i] == event) {
1073 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1074 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1075 if (--temp->waitcnt == 0) {
1076 temp->status = READY; temp->wakevent = i + 1;
1077 move(temp, &blocked, &runnable[temp->priority]); break;}
1085 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1086 #define STACKMAGIC 0xBADBADBA
1088 Initialize_Stack(char *stackptr, int stacksize)
1092 Debug(4, ("Entered Initialize_Stack"));
1093 if (lwp_stackUseEnabled)
1094 for (i = 0; i < stacksize; i++)
1095 stackptr[i] = i & 0xff;
1097 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1098 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1100 *(afs_int32 *) stackptr = STACKMAGIC;
1106 Stack_Used(register char *stackptr, int stacksize)
1110 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1111 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1114 for (i = stacksize - 1; i >= 0; i--)
1115 if ((unsigned char)stackptr[i] != (i & 0xff))
1120 if (*(afs_int32 *) stackptr == STACKMAGIC)
1123 for (i = 0; i < stacksize; i++)
1124 if ((unsigned char)stackptr[i] != (i & 0xff))
1125 return (stacksize - i);
1133 LWP_NewRock(int Tag, char *Value)
1134 /* Finds a free rock and sets its value to Value.
1136 * LWP_SUCCESS Rock did not exist and a new one was used
1137 * LWP_EBADROCK Rock already exists.
1138 * LWP_ENOROCKS All rocks are in use.
1140 * From the above semantics, you can only set a rock value once. This is specifically
1141 * to prevent multiple users of the LWP package from accidentally using the same Tag
1142 * value and clobbering others. You can always use one level of indirection to obtain
1143 * a rock whose contents can change.
1147 register struct rock *ra; /* rock array */
1149 ra = lwp_cpptr->lwp_rlist;
1151 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1152 if (ra[i].tag == Tag)
1153 return (LWP_EBADROCK);
1155 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1156 ra[lwp_cpptr->lwp_rused].tag = Tag;
1157 ra[lwp_cpptr->lwp_rused].value = Value;
1158 lwp_cpptr->lwp_rused++;
1159 return (LWP_SUCCESS);
1161 return (LWP_ENOROCKS);
1166 LWP_GetRock(int Tag, char **Value)
1167 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1169 * LWP_SUCCESS if specified rock exists and Value has been filled
1170 * LWP_EBADROCK rock specified does not exist
1174 register struct rock *ra;
1176 ra = lwp_cpptr->lwp_rlist;
1178 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1179 if (ra[i].tag == Tag) {
1180 *Value = ra[i].value;
1181 return (LWP_SUCCESS);
1183 return (LWP_EBADROCK);
1187 #ifdef AFS_AIX32_ENV
1189 setlim(int limcon, uchar_t hard, int limit)
1193 (void)getrlimit(limcon, &rlim);
1195 limit = limit * 1024;
1197 rlim.rlim_max = limit;
1198 else if (limit == RLIM_INFINITY && geteuid() != 0)
1199 rlim.rlim_cur = rlim.rlim_max;
1201 rlim.rlim_cur = limit;
1203 /* Must use ulimit() due to Posix constraints */
1204 if (limcon == RLIMIT_FSIZE) {
1207 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1208 printf("Can't %s%s limit\n",
1209 limit == RLIM_INFINITY ? "remove" : "set",
1210 hard ? " hard" : "");
1214 if (setrlimit(limcon, &rlim) < 0) {
1216 printf("Can't %s%s limit\n",
1217 limit == RLIM_INFINITY ? "remove" : "set",
1218 hard ? " hard" : "");
1228 * Print the specific limit out
1231 plim(char *name, afs_int32 lc, uchar_t hard)
1236 printf("%s \t", name);
1237 (void)getrlimit(lc, &rlim);
1238 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1239 if (lim == RLIM_INFINITY)
1240 printf("unlimited");
1241 printf("%d %s", lim / 1024, "kbytes");
1249 LWP_NoYieldSignal(char *event)
1251 return (LWP_INTERNALSIGNAL(event, 0));
1255 LWP_SignalProcess(char *event)
1257 return (LWP_INTERNALSIGNAL(event, 1));
1262 #ifdef USE_SOLARIS_THREADS
1265 #include "pthread.h"
1270 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1272 PROCESS lwp_process_list; /* List of LWP initiated threads */
1274 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1276 #define CHECK check(__LINE__);
1278 typedef struct event {
1279 struct event *next; /* next in hash chain */
1280 char *event; /* lwp event: an address */
1281 int refcount; /* Is it in use? */
1282 pthread_cond_t cond; /* Currently associated condition variable */
1283 int seq; /* Sequence number: this is incremented
1284 * by wakeup calls; wait will not return until
1288 #define HASHSIZE 127
1289 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1290 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1292 #if CMA_DEBUG || DEBUGF
1294 lwp_process_string(void)
1296 static char id[200];
1298 LWP_CurrentProcess(&p);
1299 sprintf(id, "PID %x <%s>", p, p->name);
1305 lwp_unimplemented(char *interface)
1308 "cmalwp: %s is not currently implemented: program aborted\n",
1314 lwpabort(char *interface)
1316 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1323 lwp_unimplemented("LWP_QWait");
1327 LWP_QSignal(int pid)
1329 lwp_unimplemented("LWP_QSignal");
1332 /* Allocate and initialize an LWP process handle. The associated pthread handle
1333 * must be added by the caller, and the structure threaded onto the LWP active
1334 * process list by lwp_thread_process */
1336 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1339 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1340 memset((char *)lp, 0, sizeof(*lp));
1344 sprintf(temp, "unnamed_process_%04d", ++procnum);
1345 assert(name = (char *)malloc(strlen(temp) + 1));
1354 /* Thread the LWP process descriptor *lp onto the lwp active process list
1355 * and associate a back pointer to the process descriptor from the associated
1358 lwp_thread_process(PROCESS lp)
1360 lp->next = lwp_process_list;
1361 lwp_process_list = lp;
1362 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1365 /* The top-level routine used as entry point to explicitly created LWP
1366 * processes. This completes a few details of process creation left
1367 * out by LWP_CreateProcess and calls the user-specified entry point */
1369 lwp_top_level(pthread_addr_t argp)
1371 PROCESS lp = (PROCESS) argp;
1373 assert(!pthread_mutex_lock(&lwp_mutex));
1374 lwp_thread_process(lp);
1376 assert(!pthread_mutex_unlock(&lwp_mutex));
1377 /* Should cleanup state */
1381 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1382 void *parm, char *name, PROCESS * pid)
1385 pthread_attr_t attr;
1389 #ifndef LWP_NO_PRIORITIES
1390 if (!cmalwp_pri_inrange(priority))
1393 assert(!pthread_attr_create(&attr));
1394 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1396 assert(!pthread_attr_setstacksize(&attr, stacksize));
1398 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1399 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1400 #ifndef LWP_NO_PRIORITIES
1401 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1404 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1405 (pthread_addr_t) parm);
1407 /* allow new thread to run if higher priority */
1408 assert(!pthread_mutex_unlock(&lwp_mutex));
1409 /* process is only added to active list after first time it runs (it adds itself) */
1411 pthread_create(&lp->handle, attr,
1412 (pthread_startroutine_t) lwp_top_level,
1413 (pthread_addr_t) lp);
1414 assert(!pthread_attr_delete(&attr));
1415 assert(!pthread_mutex_lock(&lwp_mutex));
1425 LWP_ActiveProcess(void)
1426 { /* returns pid of current process */
1428 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1433 LWP_CurrentProcess(PROCESS * pid)
1434 { /* get pid of current process */
1435 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1440 LWP_DestroyProcess(PROCESS pid)
1441 { /* destroy a lightweight process */
1442 lwp_unimplemented("LWP_DestroyProcess");
1446 LWP_DispatchProcess(void)
1447 { /* explicit voluntary preemption */
1448 assert(!pthread_mutex_unlock(&lwp_mutex));
1450 assert(!pthread_mutex_lock(&lwp_mutex));
1455 lwp_process_key_destructor(void)
1460 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1462 static int initialized = 0;
1472 #ifndef LWP_NO_PRIORITIES
1473 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1477 /* Create pthread key to associate LWP process descriptor with each
1478 * LWP-created thread */
1479 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1480 lwp_process_key_destructor));
1482 lp = lwp_alloc_process("main process", main, 0);
1483 lp->handle = pthread_self();
1484 lwp_thread_process(lp);
1485 #ifndef LWP_NO_PRIORITIES
1486 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1487 cmalwp_lwppri_to_cmapri(priority));
1490 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1491 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1498 LWP_TerminateProcessSupport(void)
1499 { /* terminate all LWP support */
1500 lwp_unimplemented("LWP_TerminateProcessSupport");
1503 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1505 getevent(char *event)
1507 event_t *evp, *newp;
1510 hashcode = hash(event);
1511 evp = hashtable[hashcode];
1514 if (evp->event == event) {
1518 if (evp->refcount == 0)
1523 newp = (event_t *) malloc(sizeof(event_t));
1525 newp->next = hashtable[hashcode];
1526 hashtable[hashcode] = newp;
1527 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1530 newp->event = event;
1535 /* Release the specified event */
1536 #define relevent(evp) ((evp)->refcount--)
1539 LWP_WaitProcess(char *event)
1540 { /* wait on a single event */
1543 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1545 return LWP_EBADEVENT;
1546 ev = getevent(event);
1548 while (seq == ev->seq) {
1549 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1551 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1557 LWP_MwaitProcess(int wcount, char *evlist[])
1558 { /* wait on m of n events */
1559 lwp_unimplemented("LWP_MWaitProcess");
1563 LWP_NoYieldSignal(char *event)
1566 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1568 return LWP_EBADEVENT;
1569 ev = getevent(event);
1570 if (ev->refcount > 1) {
1572 assert(pthread_cond_broadcast(&ev->cond) == 0);
1579 LWP_SignalProcess(char *event)
1582 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1584 return LWP_EBADEVENT;
1585 ev = getevent(event);
1586 if (ev->refcount > 1) {
1588 assert(!pthread_mutex_unlock(&lwp_mutex));
1589 assert(!pthread_cond_broadcast(&ev->cond));
1591 assert(!pthread_mutex_lock(&lwp_mutex));
1598 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1600 lwp_unimplemented("LWP_StackUsed");
1604 LWP_NewRock(int Tag, char *Value)
1606 lwp_unimplemented("LWP_NewRock");
1610 LWP_GetRock(int Tag, char **Value)
1612 lwp_unimplemented("LWP_GetRock");
1616 LWP_GetProcessPriority(PROCESS pid, int *priority)
1617 { /* returns process priority */
1618 lwp_unimplemented("LWP_GetProcessPriority");
1621 #endif /* USE_PTHREADS */