2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 /*******************************************************************\
12 * Information Technology Center *
13 * Carnegie-Mellon University *
15 \*******************************************************************/
17 #include <afsconfig.h>
18 #include <afs/param.h>
26 /* allocate externs here */
31 #include <sys/errno.h>
38 extern char *getenv();
49 #if !defined(USE_PTHREADS) && !defined(USE_SOLARIS_THREADS)
52 extern void *malloc(int size);
53 extern void *realloc(void *ptr, int size);
55 #if defined(AFS_OSF_ENV) || defined(AFS_S390_LINUX20_ENV)
56 extern int PRE_Block; /* from preempt.c */
58 extern char PRE_Block; /* from preempt.c */
69 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
72 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
91 #define Debug(level, msg) do { \
92 if (lwp_debug && lwp_debug >= level) { \
93 printf("***LWP (0x%x): ", lwp_cpptr); \
99 #define Debug(level, msg) do { \
104 static int Dispatcher();
105 static int Create_Process_Part2();
106 static int Exit_LWP();
107 static afs_int32 Initialize_Stack();
108 static int Stack_Used();
109 char (*RC_to_ASCII());
111 static void Abort_LWP();
112 static void Overflow_Complain();
113 static void Initialize_PCB();
114 static void Dispose_of_Dead_PCB();
115 static void Free_PCB();
116 static int Internal_Signal();
117 static purge_dead_pcbs();
119 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
124 } runnable[MAX_PRIORITIES], blocked, qwaiting;
125 /* 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. */
127 /* Offset of stack field within pcb -- used by stack checking stuff */
130 /* special user-tweakable option for AIX */
131 int lwp_MaxStackSize = 32768;
133 /* biggest LWP stack created so far */
134 int lwp_MaxStackSeen = 0;
136 /* Stack checking action */
137 int lwp_overflowAction = LWP_SOABORT;
139 /* Controls stack size counting. */
140 int lwp_stackUseEnabled = TRUE; /* pay the price */
144 /* Minimum stack size */
145 int lwp_MinStackSize = 0;
148 lwp_remove(register PROCESS p, register struct QUEUE *q)
150 /* Special test for only element on queue */
154 /* Not only element, do normal remove */
155 p->next->prev = p->prev;
156 p->prev->next = p->next;
158 /* See if head pointing to this element */
162 p->next = p->prev = NULL;
167 insert(register PROCESS p, register struct QUEUE *q)
169 if (q->head == NULL) { /* Queue is empty */
171 p->next = p->prev = p;
172 } else { /* Regular insert */
173 p->prev = q->head->prev;
174 q->head->prev->next = p;
183 move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
193 #define for_all_elts(var, q, body)\
195 register PROCESS var, _NEXT_;\
197 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
198 _NEXT_ = var -> next;\
204 /*****************************************************************************\
206 * Following section documents the Assembler interfaces used by LWP code *
208 \*****************************************************************************/
211 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
213 Stub for Assembler routine that will
214 save the current SP value in the passed
215 context savearea and call the function
216 whose entry point is in ep. If the sp
217 parameter is NULL, the current stack is
218 used, otherwise sp becomes the new stack
221 returnto(struct lwp_context *savearea);
223 Stub for Assembler routine that will
224 restore context from a passed savearea
225 and return to the restored C frame.
229 /* Macro to force a re-schedule. Strange name is historical */
230 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
232 static struct lwp_ctl *lwp_init = 0;
238 (tp = lwp_cpptr)->status = QWAITING;
239 move(tp, &runnable[tp->priority], &qwaiting);
245 LWP_QSignal(register PROCESS pid)
247 if (pid->status == QWAITING) {
249 move(pid, &qwaiting, &runnable[pid->priority]);
257 reserveFromStack(register afs_int32 size)
266 LWP_CreateProcess(int (*ep) (), int stacksize, int priority, void *parm,
267 char *name, PROCESS * pid)
271 static char *stackptr = 0;
277 #if defined(AFS_LWP_MINSTACKSIZE)
279 * on some systems (e.g. hpux), a minimum usable stack size has
282 if (stacksize < lwp_MinStackSize) {
283 stacksize = lwp_MinStackSize;
285 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
286 /* more stack size computations; keep track of for IOMGR */
287 if (lwp_MaxStackSeen < stacksize)
288 lwp_MaxStackSeen = stacksize;
290 Debug(0, ("Entered LWP_CreateProcess"));
291 /* Throw away all dead process control blocks */
294 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
299 if (stacksize < MINSTACK)
303 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
307 * The following signal action for AIX is necessary so that in case of a
308 * crash (i.e. core is generated) we can include the user's data section
309 * in the core dump. Unfortunately, by default, only a partial core is
310 * generated which, in many cases, isn't too useful.
312 * We also do it here in case the main program forgets to do it.
314 struct sigaction nsa;
315 extern uid_t geteuid();
317 sigemptyset(&nsa.sa_mask);
318 nsa.sa_handler = SIG_DFL;
319 nsa.sa_flags = SA_FULLDUMP;
320 sigaction(SIGABRT, &nsa, NULL);
321 sigaction(SIGSEGV, &nsa, NULL);
324 * First we need to increase the default resource limits,
325 * if necessary, so that we can guarantee that we have the
326 * resources to create the core file, but we can't always
327 * do it as an ordinary user.
330 /* vos dump causes problems */
331 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
332 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
333 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
336 * Now reserve in one scoop all the stack space that will be used
337 * by the particular application's main (i.e. non-lwp) body. This
338 * is plenty space for any of our applications.
340 stackptr = reserveFromStack(lwp_MaxStackSize);
342 stackptr -= stacksize;
343 stackmemory = stackptr;
345 if ((stackmemory = (char *)malloc(stacksize + 7)) == NULL) {
349 /* Round stack pointer to byte boundary */
350 stackptr = (char *)(8 * (((long)stackmemory + 7) / 8));
352 if (priority < 0 || priority >= MAX_PRIORITIES) {
356 Initialize_Stack(stackptr, stacksize);
357 Initialize_PCB(temp, priority, stackmemory, stacksize, ep, parm, name);
358 insert(temp, &runnable[priority]);
361 Abort_LWP("PRE_Block not 0");
363 /* Gross hack: beware! */
366 #if defined(AFS_PARISC_LINUX24_ENV)
367 savecontext(Create_Process_Part2, &temp2->context,
368 stackptr + MINFRAME);
371 savecontext(Create_Process_Part2, &temp2->context,
372 stackptr + MINFRAME);
374 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
375 /* Need to have the sp on an 8-byte boundary for storing doubles. */
376 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 16); /* 16 = 2 * jmp_buf_type */
378 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
379 savecontext(Create_Process_Part2, &temp2->context, stackptr + stacksize - 0x40); /* lomgjmp does something
382 #if defined(AFS_S390_LINUX20_ENV)
383 savecontext(Create_Process_Part2, &temp2->context,
384 stackptr + stacksize - MINFRAME);
385 #else /* !AFS_S390_LINUX20_ENV */
386 savecontext(Create_Process_Part2, &temp2->context,
387 stackptr + stacksize - sizeof(void *));
388 #endif /* AFS_S390_LINUX20_ENV */
389 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
390 #endif /* AFS_SGI62_ENV */
393 /* End of gross hack */
404 LWP_CreateProcess2(int (*ep) (), int stacksize, int priority, void *parm,
405 char *name, PROCESS * pid)
410 #if defined(AFS_LWP_MINSTACKSIZE)
412 * on some systems (e.g. hpux), a minimum usable stack size has
415 if (stacksize < lwp_MinStackSize) {
416 stacksize = lwp_MinStackSize;
418 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
419 /* more stack size computations; keep track of for IOMGR */
420 if (lwp_MaxStackSeen < stacksize)
421 lwp_MaxStackSeen = stacksize;
423 Debug(0, ("Entered LWP_CreateProcess"));
424 /* Throw away all dead process control blocks */
427 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
432 if (stacksize < MINSTACK)
436 STACK_ALIGN * ((stacksize + STACK_ALIGN - 1) / STACK_ALIGN);
437 if ((stackptr = (char *)malloc(stacksize)) == NULL) {
441 if (priority < 0 || priority >= MAX_PRIORITIES) {
445 Initialize_Stack(stackptr, stacksize);
446 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
447 insert(temp, &runnable[priority]);
450 Abort_LWP("PRE_Block not 0");
452 /* Gross hack: beware! */
455 savecontext(Create_Process_Part2, &temp2->context,
456 stackptr + stacksize - sizeof(void *));
457 /* End of gross hack */
468 LWP_CurrentProcess(PROCESS * pid)
469 { /* returns pid of current process */
470 Debug(0, ("Entered Current_Process"));
481 Debug(0, ("Entered ThreadId"));
488 #define LWPANCHOR (*lwp_init)
491 LWP_DestroyProcess(PROCESS pid)
492 { /* destroy a lightweight process */
495 Debug(0, ("Entered Destroy_Process"));
497 if (lwp_cpptr != pid) {
498 Dispose_of_Dead_PCB(pid);
501 pid->status = DESTROYED;
502 move(pid, &runnable[pid->priority], &blocked);
504 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
505 savecontext(Dispatcher, &(temp->context),
506 &(LWPANCHOR.dsptchstack[MINFRAME]));
507 #elif defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
508 savecontext(Dispatcher, &(temp->context),
510 dsptchstack[(sizeof LWPANCHOR.dsptchstack) - 8]));
511 #elif defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
512 savecontext(Dispatcher, &(temp->context),
514 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
516 #elif defined(AFS_S390_LINUX20_ENV)
517 savecontext(Dispatcher, &(temp->context),
519 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
522 savecontext(Dispatcher, &(temp->context),
524 dsptchstack[(sizeof LWPANCHOR.dsptchstack) -
534 LWP_DispatchProcess(void)
535 { /* explicit voluntary preemption */
536 Debug(2, ("Entered Dispatch_Process"));
550 for (i = 0; i < MAX_PRIORITIES; i++)
551 for_all_elts(x, runnable[i], {
552 printf("[Priority %d]\n", i);
556 for_all_elts(x, blocked, {
557 Dump_One_Process(x);}
559 for_all_elts(x, qwaiting, {
560 Dump_One_Process(x);}
563 printf("***LWP: LWP support not initialized\n");
569 LWP_GetProcessPriority(PROCESS pid, int *priority)
570 { /* returns process priority */
571 Debug(0, ("Entered Get_Process_Priority"));
573 *priority = pid->priority;
580 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
583 struct lwp_pcb dummy;
587 Debug(0, ("Entered LWP_InitializeProcessSupport"));
588 if (lwp_init != NULL)
591 /* Set up offset for stack checking -- do this as soon as possible */
592 stack_offset = (char *)&dummy.stack - (char *)&dummy;
594 if (priority >= MAX_PRIORITIES)
596 for (i = 0; i < MAX_PRIORITIES; i++) {
597 runnable[i].head = NULL;
598 runnable[i].count = 0;
602 qwaiting.head = NULL;
604 lwp_init = (struct lwp_ctl *)malloc(sizeof(struct lwp_ctl));
605 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
606 if (lwp_init == NULL || temp == NULL)
607 Abort_LWP("Insufficient Storage to Initialize LWP Support");
608 LWPANCHOR.processcnt = 1;
609 LWPANCHOR.outerpid = temp;
610 LWPANCHOR.outersp = NULL;
611 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL,
612 "Main Process [created by LWP]");
613 insert(temp, &runnable[priority]);
614 savecontext(Dispatcher, &temp->context, NULL);
615 LWPANCHOR.outersp = temp->context.topstack;
619 /* get minimum stack size from the environment. this allows the administrator
620 * to change the lwp stack dynamically without getting a new binary version.
622 if ((value = getenv("AFS_LWP_STACK_SIZE")) == NULL)
623 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
626 (AFS_LWP_MINSTACKSIZE >
627 atoi(value) ? AFS_LWP_MINSTACKSIZE : atoi(value));
633 LWP_INTERNALSIGNAL(char *event, int yield)
634 { /* signal the occurence of an event */
635 Debug(2, ("Entered LWP_SignalProcess"));
638 rc = Internal_Signal(event);
647 LWP_TerminateProcessSupport(void)
648 { /* terminate all LWP support */
651 Debug(0, ("Entered Terminate_Process_Support"));
652 if (lwp_init == NULL)
654 if (lwp_cpptr != LWPANCHOR.outerpid)
655 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
656 for (i = 0; i < MAX_PRIORITIES; i++)
657 for_all_elts(cur, runnable[i], {
660 for_all_elts(cur, blocked, {
663 for_all_elts(cur, qwaiting, {
672 LWP_WaitProcess(char *event)
673 { /* wait on a single event */
676 Debug(2, ("Entered Wait_Process"));
678 return LWP_EBADEVENT;
681 return LWP_MwaitProcess(1, tempev);
685 LWP_MwaitProcess(int wcount, char *evlist[])
686 { /* wait on m of n events */
687 register int ecount, i;
690 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
692 if (evlist == NULL) {
694 return LWP_EBADCOUNT;
697 for (ecount = 0; evlist[ecount] != NULL; ecount++);
701 return LWP_EBADCOUNT;
706 if (wcount > ecount || wcount < 0) {
708 return LWP_EBADCOUNT;
710 if (ecount > lwp_cpptr->eventlistsize) {
712 lwp_cpptr->eventlist =
713 (char **)realloc(lwp_cpptr->eventlist,
714 ecount * sizeof(char *));
715 lwp_cpptr->eventlistsize = ecount;
717 for (i = 0; i < ecount; i++)
718 lwp_cpptr->eventlist[i] = evlist[i];
720 lwp_cpptr->status = WAITING;
722 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
725 lwp_cpptr->wakevent = 0;
726 lwp_cpptr->waitcnt = wcount;
727 lwp_cpptr->eventcnt = ecount;
738 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
740 *maxa = pid->stacksize;
741 *used = Stack_Used(pid->stack, *maxa);
748 * The following functions are strictly
749 * INTERNAL to the LWP support package.
755 struct lwp_context tempcontext;
757 Debug(0, ("Entered Abort_LWP"));
758 printf("***LWP: %s\n", msg);
759 printf("***LWP: Abort --- dumping PCBs ...\n");
763 if (LWPANCHOR.outersp == NULL)
766 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
771 Create_Process_Part2(void)
772 { /* creates a context for the new process */
775 Debug(2, ("Entered Create_Process_Part2"));
776 temp = lwp_cpptr; /* Get current process id */
777 savecontext(Dispatcher, &temp->context, NULL);
778 (*temp->ep) (temp->parm);
779 LWP_DestroyProcess(temp);
784 Delete_PCB(register PROCESS pid)
785 { /* remove a PCB from the process list */
786 Debug(4, ("Entered Delete_PCB"));
788 (pid->blockflag || pid->status == WAITING
790 DESTROYED ? &blocked :
791 (pid->status == QWAITING) ? &qwaiting :
792 &runnable[pid->priority]));
793 LWPANCHOR.processcnt--;
799 Dump_One_Process(PROCESS pid)
803 printf("***LWP: Process Control Block at 0x%x\n", pid);
804 printf("***LWP: Name: %s\n", pid->name);
806 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
808 printf("BLOCKED and ");
809 switch (pid->status) {
826 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n", pid->priority,
828 if (pid->stacksize != 0) {
829 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
830 pid->stacksize, pid->stack);
831 printf("***LWP: HWM stack usage: ");
832 printf("%d\n", Stack_Used(pid->stack, pid->stacksize));
834 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
835 if (pid->eventcnt > 0) {
836 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
837 printf("***LWP: Event id list:");
838 for (i = 0; i < pid->eventcnt; i++)
839 printf(" 0x%x", pid->eventlist[i]);
842 if (pid->wakevent > 0)
843 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
849 purge_dead_pcbs(void)
851 for_all_elts(cur, blocked, {
852 if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur);}
857 int LWP_TraceProcesses = 0;
861 { /* Lightweight process dispatcher */
864 static int dispatch_count = 0;
866 if (LWP_TraceProcesses > 0) {
867 for (i = 0; i < MAX_PRIORITIES; i++) {
868 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
869 for_all_elts(p, runnable[i], {
870 printf(" \"%s\"", p->name);
875 printf("[Blocked (%d):", blocked.count);
876 for_all_elts(p, blocked, {
877 printf(" \"%s\"", p->name);
881 printf("[Qwaiting (%d):", qwaiting.count);
882 for_all_elts(p, qwaiting, {
883 printf(" \"%s\"", p->name);
890 /* Check for stack overflowif this lwp has a stack. Check for
891 * the guard word at the front of the stack being damaged and
892 * for the stack pointer being below the front of the stack.
893 * WARNING! This code assumes that stacks grow downward. */
894 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
895 /* Fix this (stackcheck at other end of stack?) */
896 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
897 && (lwp_cpptr->stackcheck !=
898 *(afs_int32 *) ((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
899 || lwp_cpptr->context.topstack >
900 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
902 if (lwp_cpptr && lwp_cpptr->stack
903 && (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack)
904 || lwp_cpptr->context.topstack < lwp_cpptr->stack
905 || lwp_cpptr->context.topstack >
906 (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
908 printf("stackcheck = %u: stack = %u \n", lwp_cpptr->stackcheck,
909 *(int *)lwp_cpptr->stack);
910 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
911 lwp_cpptr->context.topstack, lwp_cpptr->stack,
912 lwp_cpptr->stacksize);
914 switch (lwp_overflowAction) {
923 lwp_overflowAction = LWP_SOQUIET;
928 /* Move head of current runnable queue forward if current LWP is still in it. */
929 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
930 runnable[lwp_cpptr->priority].head =
931 runnable[lwp_cpptr->priority].head->next;
932 /* Find highest priority with runnable processes. */
933 for (i = MAX_PRIORITIES - 1; i >= 0; i--)
934 if (runnable[i].head != NULL)
938 Abort_LWP("No READY processes");
941 if (LWP_TraceProcesses > 0)
942 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count,
943 runnable[i].head, runnable[i].head->name);
946 Abort_LWP("PRE_Block not 1");
947 lwp_cpptr = runnable[i].head;
949 returnto(&lwp_cpptr->context);
952 /* Complain of a stack overflow to stderr without using stdio. */
954 Overflow_Complain(void)
958 char *msg1 = " LWP: stack overflow in process ";
961 currenttime = time(0);
962 timeStamp = ctime(¤ttime);
964 write(2, timeStamp, strlen(timeStamp));
966 write(2, msg1, strlen(msg1));
967 write(2, lwp_cpptr->name, strlen(lwp_cpptr->name));
968 write(2, msg2, strlen(msg2));
972 Dispose_of_Dead_PCB(PROCESS cur)
974 Debug(4, ("Entered Dispose_of_Dead_PCB"));
978 Internal_Signal(cur);
989 Free_PCB(PROCESS pid)
991 Debug(4, ("Entered Free_PCB"));
992 if (pid->stack != NULL) {
994 ("HWM stack usage: %d, [PCB at 0x%x]",
995 Stack_Used(pid->stack, pid->stacksize), pid));
996 #ifndef AFS_AIX32_ENV
1000 if (pid->eventlist != NULL)
1001 free(pid->eventlist);
1006 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1007 int (*ep) (), void *parm, char *name)
1011 Debug(4, ("Entered Initialize_PCB"));
1013 while (((temp->name[i] = name[i]) != '\0') && (i < 31))
1015 temp->name[31] = '\0';
1016 temp->status = READY;
1017 temp->eventlist = (char **)malloc(EVINITSIZE * sizeof(char *));
1018 temp->eventlistsize = EVINITSIZE;
1022 temp->blockflag = 0;
1023 temp->iomgrRequest = 0;
1024 temp->priority = priority;
1025 temp->index = lwp_nextindex++;
1026 temp->stack = stack;
1027 temp->stacksize = stacksize;
1028 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1029 if (temp->stack != NULL)
1030 temp->stackcheck = *(int *)((temp->stack) + stacksize - 4);
1032 if (temp->stack != NULL)
1033 temp->stackcheck = *(int *)(temp->stack);
1037 temp->misc = NULL; /* currently unused */
1040 temp->lwp_rused = 0;
1041 temp->level = 1; /* non-preemptable */
1045 Internal_Signal(register char *event)
1047 int rc = LWP_ENOWAIT;
1050 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event));
1054 return LWP_EBADEVENT;
1055 for_all_elts(temp, blocked, {
1056 if (temp->status == WAITING)
1057 for (i = 0; i < temp->eventcnt; i++) {
1058 if (temp->eventlist[i] == event) {
1059 temp->eventlist[i] = NULL; rc = LWP_SUCCESS;
1060 Debug(0, ("Signal satisfied for PCB 0x%x", temp));
1061 if (--temp->waitcnt == 0) {
1062 temp->status = READY; temp->wakevent = i + 1;
1063 move(temp, &blocked, &runnable[temp->priority]); break;}
1071 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
1072 #define STACKMAGIC 0xBADBADBA
1074 Initialize_Stack(char *stackptr, int stacksize)
1078 Debug(4, ("Entered Initialize_Stack"));
1079 if (lwp_stackUseEnabled)
1080 for (i = 0; i < stacksize; i++)
1081 stackptr[i] = i & 0xff;
1083 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1084 *(afs_int32 *) (stackptr + stacksize - 4) = STACKMAGIC;
1086 *(afs_int32 *) stackptr = STACKMAGIC;
1092 Stack_Used(register char *stackptr, int stacksize)
1096 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
1097 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1100 for (i = stacksize - 1; i >= 0; i--)
1101 if ((unsigned char)stackptr[i] != (i & 0xff))
1106 if (*(afs_int32 *) stackptr == STACKMAGIC)
1109 for (i = 0; i < stacksize; i++)
1110 if ((unsigned char)stackptr[i] != (i & 0xff))
1111 return (stacksize - i);
1119 LWP_NewRock(int Tag, char *Value)
1120 /* Finds a free rock and sets its value to Value.
1122 * LWP_SUCCESS Rock did not exist and a new one was used
1123 * LWP_EBADROCK Rock already exists.
1124 * LWP_ENOROCKS All rocks are in use.
1126 * From the above semantics, you can only set a rock value once. This is specifically
1127 * to prevent multiple users of the LWP package from accidentally using the same Tag
1128 * value and clobbering others. You can always use one level of indirection to obtain
1129 * a rock whose contents can change.
1133 register struct rock *ra; /* rock array */
1135 ra = lwp_cpptr->lwp_rlist;
1137 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1138 if (ra[i].tag == Tag)
1139 return (LWP_EBADROCK);
1141 if (lwp_cpptr->lwp_rused < MAXROCKS) {
1142 ra[lwp_cpptr->lwp_rused].tag = Tag;
1143 ra[lwp_cpptr->lwp_rused].value = Value;
1144 lwp_cpptr->lwp_rused++;
1145 return (LWP_SUCCESS);
1147 return (LWP_ENOROCKS);
1152 LWP_GetRock(int Tag, char **Value)
1153 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1155 * LWP_SUCCESS if specified rock exists and Value has been filled
1156 * LWP_EBADROCK rock specified does not exist
1160 register struct rock *ra;
1162 ra = lwp_cpptr->lwp_rlist;
1164 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1165 if (ra[i].tag == Tag) {
1166 *Value = ra[i].value;
1167 return (LWP_SUCCESS);
1169 return (LWP_EBADROCK);
1173 #ifdef AFS_AIX32_ENV
1175 setlim(int limcon, uchar_t hard, int limit)
1179 (void)getrlimit(limcon, &rlim);
1181 limit = limit * 1024;
1183 rlim.rlim_max = limit;
1184 else if (limit == RLIM_INFINITY && geteuid() != 0)
1185 rlim.rlim_cur = rlim.rlim_max;
1187 rlim.rlim_cur = limit;
1189 /* Must use ulimit() due to Posix constraints */
1190 if (limcon == RLIMIT_FSIZE) {
1193 ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1194 printf("Can't %s%s limit\n",
1195 limit == RLIM_INFINITY ? "remove" : "set",
1196 hard ? " hard" : "");
1200 if (setrlimit(limcon, &rlim) < 0) {
1202 printf("Can't %s%s limit\n",
1203 limit == RLIM_INFINITY ? "remove" : "set",
1204 hard ? " hard" : "");
1214 * Print the specific limit out
1217 plim(char *name, afs_int32 lc, uchar_t hard)
1222 printf("%s \t", name);
1223 (void)getrlimit(lc, &rlim);
1224 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1225 if (lim == RLIM_INFINITY)
1226 printf("unlimited");
1227 printf("%d %s", lim / 1024, "kbytes");
1235 LWP_NoYieldSignal(char *event)
1237 return (LWP_INTERNALSIGNAL(event, 0));
1241 LWP_SignalProcess(char *event)
1243 return (LWP_INTERNALSIGNAL(event, 1));
1248 #ifdef USE_SOLARIS_THREADS
1251 #include "pthread.h"
1256 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1258 PROCESS lwp_process_list; /* List of LWP initiated threads */
1260 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1262 #define CHECK check(__LINE__);
1264 typedef struct event {
1265 struct event *next; /* next in hash chain */
1266 char *event; /* lwp event: an address */
1267 int refcount; /* Is it in use? */
1268 pthread_cond_t cond; /* Currently associated condition variable */
1269 int seq; /* Sequence number: this is incremented
1270 * by wakeup calls; wait will not return until
1274 #define HASHSIZE 127
1275 event_t *hashtable[HASHSIZE]; /* Hash table for events */
1276 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1278 #if CMA_DEBUG || DEBUGF
1280 lwp_process_string(void)
1282 static char id[200];
1284 LWP_CurrentProcess(&p);
1285 sprintf(id, "PID %x <%s>", p, p->name);
1291 lwp_unimplemented(char *interface)
1294 "cmalwp: %s is not currently implemented: program aborted\n",
1300 lwpabort(char *interface)
1302 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1309 lwp_unimplemented("LWP_QWait");
1313 LWP_QSignal(int pid)
1315 lwp_unimplemented("LWP_QSignal");
1318 /* Allocate and initialize an LWP process handle. The associated pthread handle
1319 * must be added by the caller, and the structure threaded onto the LWP active
1320 * process list by lwp_thread_process */
1322 lwp_alloc_process(char *name, pthread_startroutine_t ep, pthread_addr_t arg)
1325 assert(lp = (PROCESS) malloc(sizeof(*lp)));
1326 memset((char *)lp, 0, sizeof(*lp));
1330 sprintf(temp, "unnamed_process_%04d", ++procnum);
1331 assert(name = (char *)malloc(strlen(temp) + 1));
1340 /* Thread the LWP process descriptor *lp onto the lwp active process list
1341 * and associate a back pointer to the process descriptor from the associated
1344 lwp_thread_process(PROCESS lp)
1346 lp->next = lwp_process_list;
1347 lwp_process_list = lp;
1348 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1351 /* The top-level routine used as entry point to explicitly created LWP
1352 * processes. This completes a few details of process creation left
1353 * out by LWP_CreateProcess and calls the user-specified entry point */
1355 lwp_top_level(pthread_addr_t argp)
1357 PROCESS lp = (PROCESS) argp;
1359 assert(!pthread_mutex_lock(&lwp_mutex));
1360 lwp_thread_process(lp);
1362 assert(!pthread_mutex_unlock(&lwp_mutex));
1363 /* Should cleanup state */
1367 LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1368 void *parm, char *name, PROCESS * pid)
1371 pthread_attr_t attr;
1375 #ifndef LWP_NO_PRIORITIES
1376 if (!cmalwp_pri_inrange(priority))
1379 assert(!pthread_attr_create(&attr));
1380 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1382 assert(!pthread_attr_setstacksize(&attr, stacksize));
1384 (void)pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1385 (void)pthread_attr_setsched(&attr, SCHED_FIFO);
1386 #ifndef LWP_NO_PRIORITIES
1387 (void)pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1390 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep,
1391 (pthread_addr_t) parm);
1393 /* allow new thread to run if higher priority */
1394 assert(!pthread_mutex_unlock(&lwp_mutex));
1395 /* process is only added to active list after first time it runs (it adds itself) */
1397 pthread_create(&lp->handle, attr,
1398 (pthread_startroutine_t) lwp_top_level,
1399 (pthread_addr_t) lp);
1400 assert(!pthread_attr_delete(&attr));
1401 assert(!pthread_mutex_lock(&lwp_mutex));
1411 LWP_ActiveProcess(void)
1412 { /* returns pid of current process */
1414 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) & pid));
1419 LWP_CurrentProcess(PROCESS * pid)
1420 { /* get pid of current process */
1421 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1426 LWP_DestroyProcess(PROCESS pid)
1427 { /* destroy a lightweight process */
1428 lwp_unimplemented("LWP_DestroyProcess");
1432 LWP_DispatchProcess(void)
1433 { /* explicit voluntary preemption */
1434 assert(!pthread_mutex_unlock(&lwp_mutex));
1436 assert(!pthread_mutex_lock(&lwp_mutex));
1441 lwp_process_key_destructor(void)
1446 LWP_InitializeProcessSupport(int priority, PROCESS * pid)
1448 static int initialized = 0;
1458 #ifndef LWP_NO_PRIORITIES
1459 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1463 /* Create pthread key to associate LWP process descriptor with each
1464 * LWP-created thread */
1465 assert(!pthread_keycreate(&lwp_process_key, (pthread_destructor_t)
1466 lwp_process_key_destructor));
1468 lp = lwp_alloc_process("main process", main, 0);
1469 lp->handle = pthread_self();
1470 lwp_thread_process(lp);
1471 #ifndef LWP_NO_PRIORITIES
1472 (void)pthread_setscheduler(pthread_self(), SCHED_FIFO,
1473 cmalwp_lwppri_to_cmapri(priority));
1476 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1477 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1484 LWP_TerminateProcessSupport(void)
1485 { /* terminate all LWP support */
1486 lwp_unimplemented("LWP_TerminateProcessSupport");
1489 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1491 getevent(char *event)
1493 event_t *evp, *newp;
1496 hashcode = hash(event);
1497 evp = hashtable[hashcode];
1500 if (evp->event == event) {
1504 if (evp->refcount == 0)
1509 newp = (event_t *) malloc(sizeof(event_t));
1511 newp->next = hashtable[hashcode];
1512 hashtable[hashcode] = newp;
1513 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t) 0)));
1516 newp->event = event;
1521 /* Release the specified event */
1522 #define relevent(evp) ((evp)->refcount--)
1525 LWP_WaitProcess(char *event)
1526 { /* wait on a single event */
1529 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1531 return LWP_EBADEVENT;
1532 ev = getevent(event);
1534 while (seq == ev->seq) {
1535 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1537 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1543 LWP_MwaitProcess(int wcount, char *evlist[])
1544 { /* wait on m of n events */
1545 lwp_unimplemented("LWP_MWaitProcess");
1549 LWP_NoYieldSignal(char *event)
1552 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1554 return LWP_EBADEVENT;
1555 ev = getevent(event);
1556 if (ev->refcount > 1) {
1558 assert(pthread_cond_broadcast(&ev->cond) == 0);
1565 LWP_SignalProcess(char *event)
1568 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1570 return LWP_EBADEVENT;
1571 ev = getevent(event);
1572 if (ev->refcount > 1) {
1574 assert(!pthread_mutex_unlock(&lwp_mutex));
1575 assert(!pthread_cond_broadcast(&ev->cond));
1577 assert(!pthread_mutex_lock(&lwp_mutex));
1584 LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1586 lwp_unimplemented("LWP_StackUsed");
1590 LWP_NewRock(int Tag, char *Value)
1592 lwp_unimplemented("LWP_NewRock");
1596 LWP_GetRock(int Tag, char **Value)
1598 lwp_unimplemented("LWP_GetRock");
1602 LWP_GetProcessPriority(PROCESS pid, int *priority)
1603 { /* returns process priority */
1604 lwp_unimplemented("LWP_GetProcessPriority");
1607 #endif /* USE_PTHREADS */