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)
86 #define Debug(level, msg)\
87 if (lwp_debug && lwp_debug >= level) {\
88 printf("***LWP (0x%x): ", lwp_cpptr);\
94 #define Debug(level, msg)
98 static int Dispatcher();
99 static int Create_Process_Part2();
100 static int Exit_LWP();
101 static afs_int32 Initialize_Stack();
102 static int Stack_Used();
103 char (*RC_to_ASCII());
105 static void Abort_LWP();
106 static void Overflow_Complain();
107 static void Initialize_PCB();
108 static void Dispose_of_Dead_PCB();
109 static void Free_PCB();
110 static int Internal_Signal();
111 static purge_dead_pcbs();
113 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
118 } runnable[MAX_PRIORITIES], blocked;
119 /* 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. */
121 /* Offset of stack field within pcb -- used by stack checking stuff */
124 /* special user-tweakable option for AIX */
125 int lwp_MaxStackSize = 32768;
127 /* biggest LWP stack created so far */
128 int lwp_MaxStackSeen = 0;
130 /* Stack checking action */
131 int lwp_overflowAction = LWP_SOABORT;
133 /* Controls stack size counting. */
134 int lwp_stackUseEnabled = TRUE; /* pay the price */
138 /* Minimum stack size */
139 int lwp_MinStackSize=0;
141 static int lwp_remove(p, q)
143 register struct QUEUE *q;
145 /* Special test for only element on queue */
149 /* Not only element, do normal remove */
150 p -> next -> prev = p -> prev;
151 p -> prev -> next = p -> next;
153 /* See if head pointing to this element */
154 if (q->head == p) q -> head = p -> next;
156 p -> next = p -> prev = NULL;
160 static int insert(p, q)
162 register struct QUEUE *q;
164 if (q->head == NULL) { /* Queue is empty */
166 p -> next = p -> prev = p;
167 } else { /* Regular insert */
168 p -> prev = q -> head -> prev;
169 q -> head -> prev -> next = p;
170 q -> head -> prev = p;
171 p -> next = q -> head;
177 static int move(p, from, to)
179 struct QUEUE *from, *to;
189 #define for_all_elts(var, q, body)\
191 register PROCESS var, _NEXT_;\
193 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
194 _NEXT_ = var -> next;\
200 /*****************************************************************************\
202 * Following section documents the Assembler interfaces used by LWP code *
204 \*****************************************************************************/
207 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
209 Stub for Assembler routine that will
210 save the current SP value in the passed
211 context savearea and call the function
212 whose entry point is in ep. If the sp
213 parameter is NULL, the current stack is
214 used, otherwise sp becomes the new stack
217 returnto(struct lwp_context *savearea);
219 Stub for Assembler routine that will
220 restore context from a passed savearea
221 and return to the restored C frame.
225 /* Macro to force a re-schedule. Strange name is historical */
226 #define Set_LWP_RC() savecontext(Dispatcher, &lwp_cpptr->context, NULL)
228 static struct lwp_ctl *lwp_init = 0;
231 {register PROCESS tp;
232 (tp=lwp_cpptr) -> status = QWAITING;
233 lwp_remove(tp, &runnable[tp->priority]);
239 register PROCESS pid; {
240 if (pid->status == QWAITING) {
242 insert(pid, &runnable[pid->priority]);
245 else return LWP_ENOWAIT;
249 char *reserveFromStack(register afs_int32 size)
257 int LWP_CreateProcess(int (*ep)(), int stacksize, int priority,
258 void *parm, char *name, PROCESS *pid)
262 static char *stackptr = 0;
267 #if defined(AFS_LWP_MINSTACKSIZE)
269 * on some systems (e.g. hpux), a minimum usable stack size has
272 if (stacksize < lwp_MinStackSize) {
273 stacksize = lwp_MinStackSize;
275 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
276 /* more stack size computations; keep track of for IOMGR */
277 if (lwp_MaxStackSeen < stacksize)
278 lwp_MaxStackSeen = stacksize;
280 Debug(0, ("Entered LWP_CreateProcess"))
281 /* Throw away all dead process control blocks */
284 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
289 if (stacksize < MINSTACK)
292 stacksize = STACK_ALIGN * ((stacksize+STACK_ALIGN-1) / STACK_ALIGN);
296 * The following signal action for AIX is necessary so that in case of a
297 * crash (i.e. core is generated) we can include the user's data section
298 * in the core dump. Unfortunately, by default, only a partial core is
299 * generated which, in many cases, isn't too useful.
301 * We also do it here in case the main program forgets to do it.
303 struct sigaction nsa;
304 extern uid_t geteuid();
306 sigemptyset(&nsa.sa_mask);
307 nsa.sa_handler = SIG_DFL;
308 nsa.sa_flags = SA_FULLDUMP;
309 sigaction(SIGABRT, &nsa, NULL);
310 sigaction(SIGSEGV, &nsa, NULL);
313 * First we need to increase the default resource limits,
314 * if necessary, so that we can guarantee that we have the
315 * resources to create the core file, but we can't always
316 * do it as an ordinary user.
319 /* vos dump causes problems */
320 /* setlim(RLIMIT_FSIZE, 0, 1048575); * 1 Gig */
321 setlim(RLIMIT_STACK, 0, 65536); /* 65 Meg */
322 setlim(RLIMIT_CORE, 0, 131072); /* 131 Meg */
325 * Now reserve in one scoop all the stack space that will be used
326 * by the particular application's main (i.e. non-lwp) body. This
327 * is plenty space for any of our applications.
329 stackptr = reserveFromStack(lwp_MaxStackSize);
331 stackptr -= stacksize;
333 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
337 /* Round stack pointer to byte boundary */
338 stackptr = (char *)(8 * (((long)stackptr+7) / 8));
340 if (priority < 0 || priority >= MAX_PRIORITIES) {
344 Initialize_Stack(stackptr, stacksize);
345 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
346 insert(temp, &runnable[priority]);
348 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
350 /* Gross hack: beware! */
353 #if defined(AFS_PARISC_LINUX24_ENV)
354 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
357 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
359 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
360 /* Need to have the sp on an 8-byte boundary for storing doubles. */
361 savecontext(Create_Process_Part2, &temp2->context,
362 stackptr+stacksize-16); /* 16 = 2 * jmp_buf_type*/
364 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
365 savecontext(Create_Process_Part2, &temp2->context,
366 stackptr+stacksize-0x40); /* lomgjmp does something
369 #if defined(AFS_S390_LINUX20_ENV)
370 savecontext(Create_Process_Part2, &temp2->context,
371 stackptr+stacksize-MINFRAME);
372 #else /* !AFS_S390_LINUX20_ENV */
373 savecontext(Create_Process_Part2, &temp2->context,
374 stackptr+stacksize-sizeof(void *));
375 #endif /* AFS_S390_LINUX20_ENV */
376 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
377 #endif /* AFS_SGI62_ENV */
380 /* End of gross hack */
390 int LWP_CreateProcess2(int (*ep)(), int stacksize, int priority,
391 void *parm, char *name, PROCESS *pid)
396 #if defined(AFS_LWP_MINSTACKSIZE)
398 * on some systems (e.g. hpux), a minimum usable stack size has
401 if (stacksize < lwp_MinStackSize) {
402 stacksize = lwp_MinStackSize;
404 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
405 /* more stack size computations; keep track of for IOMGR */
406 if (lwp_MaxStackSeen < stacksize)
407 lwp_MaxStackSeen = stacksize;
409 Debug(0, ("Entered LWP_CreateProcess"))
410 /* Throw away all dead process control blocks */
413 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
418 if (stacksize < MINSTACK)
421 stacksize = STACK_ALIGN * ((stacksize+STACK_ALIGN-1) / STACK_ALIGN);
422 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
426 if (priority < 0 || priority >= MAX_PRIORITIES) {
430 Initialize_Stack(stackptr, stacksize);
431 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
432 insert(temp, &runnable[priority]);
434 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
436 /* Gross hack: beware! */
439 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-sizeof(void *));
440 /* End of gross hack */
450 int LWP_CurrentProcess(PROCESS *pid) /* returns pid of current process */
452 Debug(0, ("Entered Current_Process"))
460 PROCESS LWP_ThreadId(void)
462 Debug(0, ("Entered ThreadId"))
469 #define LWPANCHOR (*lwp_init)
471 int LWP_DestroyProcess(PROCESS pid) /* destroy a lightweight process */
475 Debug(0, ("Entered Destroy_Process"))
477 if (lwp_cpptr != pid) {
478 Dispose_of_Dead_PCB(pid);
481 pid -> status = DESTROYED;
482 move(pid, &runnable[pid->priority], &blocked);
484 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
485 savecontext(Dispatcher, &(temp -> context),
486 &(LWPANCHOR.dsptchstack[MINFRAME]));
488 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
489 savecontext(Dispatcher, &(temp -> context),
490 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-8]));
492 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
493 savecontext(Dispatcher, &(temp -> context),
494 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-0x40]));
496 #if defined(AFS_S390_LINUX20_ENV)
497 savecontext(Dispatcher, &(temp -> context),
498 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-MINFRAME]));
500 savecontext(Dispatcher, &(temp -> context),
501 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-sizeof(void *)]));
512 int LWP_DispatchProcess(void) /* explicit voluntary preemption */
514 Debug(2, ("Entered Dispatch_Process"))
523 int Dump_Processes(void)
527 for (i=0; i<MAX_PRIORITIES; i++)
528 for_all_elts(x, runnable[i], {
529 printf("[Priority %d]\n", i);
532 for_all_elts(x, blocked, { Dump_One_Process(x); })
534 printf("***LWP: LWP support not initialized\n");
539 int LWP_GetProcessPriority(PROCESS pid, int *priority) /* returns process priority */
541 Debug(0, ("Entered Get_Process_Priority"))
543 *priority = pid -> priority;
549 int LWP_InitializeProcessSupport(int priority, PROCESS *pid)
552 struct lwp_pcb dummy;
556 Debug(0, ("Entered LWP_InitializeProcessSupport"))
557 if (lwp_init != NULL) return LWP_SUCCESS;
559 /* Set up offset for stack checking -- do this as soon as possible */
560 stack_offset = (char *) &dummy.stack - (char *) &dummy;
562 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
563 for (i=0; i<MAX_PRIORITIES; i++) {
564 runnable[i].head = NULL;
565 runnable[i].count = 0;
569 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
570 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
571 if (lwp_init == NULL || temp == NULL)
572 Abort_LWP("Insufficient Storage to Initialize LWP Support");
573 LWPANCHOR.processcnt = 1;
574 LWPANCHOR.outerpid = temp;
575 LWPANCHOR.outersp = NULL;
576 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
577 insert(temp, &runnable[priority]);
578 savecontext(Dispatcher, &temp->context, NULL);
579 LWPANCHOR.outersp = temp -> context.topstack;
583 /* get minimum stack size from the environment. this allows the administrator
584 * to change the lwp stack dynamically without getting a new binary version.
586 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
587 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
589 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
590 AFS_LWP_MINSTACKSIZE : atoi(value));
595 int LWP_INTERNALSIGNAL(char *event, int yield) /* signal the occurence of an event */
597 Debug(2, ("Entered LWP_SignalProcess"))
600 rc = Internal_Signal(event);
601 if (yield) Set_LWP_RC();
607 int LWP_TerminateProcessSupport(void) /* terminate all LWP support */
611 Debug(0, ("Entered Terminate_Process_Support"))
612 if (lwp_init == NULL) return LWP_EINIT;
613 if (lwp_cpptr != LWPANCHOR.outerpid)
614 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
615 for (i=0; i<MAX_PRIORITIES; i++)
616 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
617 for_all_elts(cur, blocked, { Free_PCB(cur); })
623 int LWP_WaitProcess(char *event) /* wait on a single event */
627 Debug(2, ("Entered Wait_Process"))
628 if (event == NULL) return LWP_EBADEVENT;
631 return LWP_MwaitProcess(1, tempev);
634 int LWP_MwaitProcess(int wcount, char *evlist[]) /* wait on m of n events */
636 register int ecount, i;
639 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
641 if (evlist == NULL) {
643 return LWP_EBADCOUNT;
646 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
650 return LWP_EBADCOUNT;
655 if (wcount>ecount || wcount<0) {
657 return LWP_EBADCOUNT;
659 if (ecount > lwp_cpptr->eventlistsize) {
661 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *));
662 lwp_cpptr->eventlistsize = ecount;
664 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
666 lwp_cpptr -> status = WAITING;
668 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
671 lwp_cpptr -> wakevent = 0;
672 lwp_cpptr -> waitcnt = wcount;
673 lwp_cpptr -> eventcnt = ecount;
683 int LWP_StackUsed(PROCESS pid, int *maxa, int *used)
685 *maxa = pid -> stacksize;
686 *used = Stack_Used(pid->stack, *maxa);
693 * The following functions are strictly
694 * INTERNAL to the LWP support package.
697 static void Abort_LWP(char *msg)
699 struct lwp_context tempcontext;
701 Debug(0, ("Entered Abort_LWP"))
702 printf("***LWP: %s\n",msg);
703 printf("***LWP: Abort --- dumping PCBs ...\n");
707 if (LWPANCHOR.outersp == NULL)
710 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
714 static int Create_Process_Part2(void) /* creates a context for the new process */
718 Debug(2, ("Entered Create_Process_Part2"))
719 temp = lwp_cpptr; /* Get current process id */
720 savecontext(Dispatcher, &temp->context, NULL);
721 (*temp->ep)(temp->parm);
722 LWP_DestroyProcess(temp);
726 static int Delete_PCB(register PROCESS pid) /* remove a PCB from the process list */
728 Debug(4, ("Entered Delete_PCB"))
729 lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
731 : &runnable[pid->priority]));
732 LWPANCHOR.processcnt--;
737 static int Dump_One_Process(PROCESS pid)
741 printf("***LWP: Process Control Block at 0x%x\n", pid);
742 printf("***LWP: Name: %s\n", pid->name);
744 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
745 if (pid->blockflag) printf("BLOCKED and ");
746 switch (pid->status) {
747 case READY: printf("READY"); break;
748 case WAITING: printf("WAITING"); break;
749 case DESTROYED: printf("DESTROYED"); break;
750 default: printf("unknown");
753 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
754 pid->priority, pid->parm);
755 if (pid->stacksize != 0) {
756 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
757 pid->stacksize, pid->stack);
758 printf("***LWP: HWM stack usage: ");
759 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
762 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
763 if (pid->eventcnt > 0) {
764 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
765 printf("***LWP: Event id list:");
766 for (i=0;i<pid->eventcnt;i++)
767 printf(" 0x%x", pid->eventlist[i]);
771 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
776 static int purge_dead_pcbs(void)
778 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
782 int LWP_TraceProcesses = 0;
784 static int Dispatcher(void) /* Lightweight process dispatcher */
788 static int dispatch_count = 0;
790 if (LWP_TraceProcesses > 0) {
791 for (i=0; i<MAX_PRIORITIES; i++) {
792 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
793 for_all_elts(p, runnable[i], {
794 printf(" \"%s\"", p->name);
798 printf("[Blocked (%d):", blocked.count);
799 for_all_elts(p, blocked, {
800 printf(" \"%s\"", p->name);
806 /* Check for stack overflowif this lwp has a stack. Check for
807 the guard word at the front of the stack being damaged and
808 for the stack pointer being below the front of the stack.
809 WARNING! This code assumes that stacks grow downward. */
810 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
811 /* Fix this (stackcheck at other end of stack?) */
812 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
813 && (lwp_cpptr->stackcheck !=
814 *(afs_int32 *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
815 || lwp_cpptr->context.topstack >
816 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
818 if (lwp_cpptr && lwp_cpptr->stack &&
819 (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack) ||
820 lwp_cpptr->context.topstack < lwp_cpptr->stack ||
821 lwp_cpptr->context.topstack > (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
823 printf("stackcheck = %u: stack = %u \n",
824 lwp_cpptr->stackcheck, *(int *)lwp_cpptr->stack);
825 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
826 lwp_cpptr->context.topstack, lwp_cpptr->stack, lwp_cpptr->stacksize);
828 switch (lwp_overflowAction) {
837 lwp_overflowAction = LWP_SOQUIET;
842 /* Move head of current runnable queue forward if current LWP is still in it. */
843 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
844 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head -> next;
845 /* Find highest priority with runnable processes. */
846 for (i=MAX_PRIORITIES-1; i>=0; i--)
847 if (runnable[i].head != NULL) break;
849 if (i < 0) Abort_LWP("No READY processes");
852 if (LWP_TraceProcesses > 0)
853 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
855 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
856 lwp_cpptr = runnable[i].head;
858 returnto(&lwp_cpptr->context);
861 /* Complain of a stack overflow to stderr without using stdio. */
862 static void Overflow_Complain(void)
866 char *msg1 = " LWP: stack overflow in process ";
869 currenttime = time(0);
870 timeStamp = ctime(¤ttime);
872 write (2, timeStamp, strlen(timeStamp));
874 write (2, msg1, strlen(msg1));
875 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
876 write (2, msg2, strlen(msg2));
879 static void Dispose_of_Dead_PCB (PROCESS cur)
881 Debug(4, ("Entered Dispose_of_Dead_PCB"))
885 Internal_Signal(cur);
889 static int Exit_LWP(void)
894 static void Free_PCB(PROCESS pid)
896 Debug(4, ("Entered Free_PCB"))
897 if (pid -> stack != NULL) {
898 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
899 Stack_Used(pid->stack,pid->stacksize), pid))
902 if (pid->eventlist != NULL) free(pid->eventlist);
906 static void Initialize_PCB(PROCESS temp, int priority, char *stack,
907 int stacksize, int (*ep)(), void *parm, char *name)
911 Debug(4, ("Entered Initialize_PCB"))
913 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
914 temp -> name[31] = '\0';
915 temp -> status = READY;
916 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
917 temp -> eventlistsize = EVINITSIZE;
918 temp -> eventcnt = 0;
919 temp -> wakevent = 0;
921 temp -> blockflag = 0;
922 temp -> iomgrRequest = 0;
923 temp -> priority = priority;
924 temp -> index = lwp_nextindex++;
925 temp -> stack = stack;
926 temp -> stacksize = stacksize;
927 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
928 if (temp -> stack != NULL)
929 temp -> stackcheck = *(int *) ((temp -> stack) + stacksize - 4);
931 if (temp -> stack != NULL)
932 temp -> stackcheck = *(int *) (temp -> stack);
936 temp -> misc = NULL; /* currently unused */
939 temp -> lwp_rused = 0;
940 temp -> level = 1; /* non-preemptable */
943 static int Internal_Signal(register char *event)
945 int rc = LWP_ENOWAIT;
948 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
949 if (!lwp_init) return LWP_EINIT;
950 if (event == NULL) return LWP_EBADEVENT;
951 for_all_elts(temp, blocked, {
952 if (temp->status == WAITING)
953 for (i=0; i < temp->eventcnt; i++) {
954 if (temp -> eventlist[i] == event) {
955 temp -> eventlist[i] = NULL;
957 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
958 if (--temp->waitcnt == 0) {
959 temp -> status = READY;
960 temp -> wakevent = i+1;
961 move(temp, &blocked, &runnable[temp->priority]);
970 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
971 #define STACKMAGIC 0xBADBADBA
972 static afs_int32 Initialize_Stack(char *stackptr, int stacksize)
976 Debug(4, ("Entered Initialize_Stack"))
977 if (lwp_stackUseEnabled)
978 for (i=0; i<stacksize; i++)
979 stackptr[i] = i &0xff;
981 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
982 *(afs_int32 *)(stackptr + stacksize - 4) = STACKMAGIC;
984 *(afs_int32 *)stackptr = STACKMAGIC;
989 static int Stack_Used(register char *stackptr, int stacksize)
993 #if defined(__hp9000s800) || defined(AFS_PARISC_LINUX24_ENV)
994 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
997 for (i = stacksize - 1; i >= 0 ; i--)
998 if ((unsigned char) stackptr[i] != (i & 0xff))
1003 if (*(afs_int32 *) stackptr == STACKMAGIC)
1006 for (i = 0; i < stacksize; i++)
1007 if ((unsigned char) stackptr[i] != (i & 0xff))
1008 return (stacksize - i);
1015 int LWP_NewRock(int Tag, char *Value)
1016 /* Finds a free rock and sets its value to Value.
1018 LWP_SUCCESS Rock did not exist and a new one was used
1019 LWP_EBADROCK Rock already exists.
1020 LWP_ENOROCKS All rocks are in use.
1022 From the above semantics, you can only set a rock value once. This is specifically
1023 to prevent multiple users of the LWP package from accidentally using the same Tag
1024 value and clobbering others. You can always use one level of indirection to obtain
1025 a rock whose contents can change.
1029 register struct rock *ra; /* rock array */
1031 ra = lwp_cpptr->lwp_rlist;
1033 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1034 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1036 if (lwp_cpptr->lwp_rused < MAXROCKS)
1038 ra[lwp_cpptr->lwp_rused].tag = Tag;
1039 ra[lwp_cpptr->lwp_rused].value = Value;
1040 lwp_cpptr->lwp_rused++;
1041 return(LWP_SUCCESS);
1043 else return(LWP_ENOROCKS);
1047 int LWP_GetRock(int Tag, char **Value)
1048 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1050 LWP_SUCCESS if specified rock exists and Value has been filled
1051 LWP_EBADROCK rock specified does not exist
1055 register struct rock *ra;
1057 ra = lwp_cpptr->lwp_rlist;
1059 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1060 if (ra[i].tag == Tag)
1062 *Value = ra[i].value;
1063 return(LWP_SUCCESS);
1065 return(LWP_EBADROCK);
1069 #ifdef AFS_AIX32_ENV
1070 int setlim(int limcon, uchar_t hard, int limit)
1074 (void) getrlimit(limcon, &rlim);
1076 limit = limit * 1024;
1078 rlim.rlim_max = limit;
1079 else if (limit == RLIM_INFINITY && geteuid() != 0)
1080 rlim.rlim_cur = rlim.rlim_max;
1082 rlim.rlim_cur = limit;
1084 /* Must use ulimit() due to Posix constraints */
1085 if (limcon == RLIMIT_FSIZE) {
1086 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1087 printf("Can't %s%s limit\n",
1088 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1092 if (setrlimit(limcon, &rlim) < 0) {
1094 printf("Can't %s%s limit\n",
1095 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1105 * Print the specific limit out
1107 int plim(char *name, afs_int32 lc, uchar_t hard)
1112 printf("%s \t", name);
1113 (void) getrlimit(lc, &rlim);
1114 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1115 if (lim == RLIM_INFINITY)
1116 printf("unlimited");
1117 printf("%d %s", lim / 1024, "kbytes");
1124 int LWP_NoYieldSignal(char *event)
1126 return (LWP_INTERNALSIGNAL(event, 0));
1129 int LWP_SignalProcess(char *event)
1131 return (LWP_INTERNALSIGNAL(event, 1));
1136 #ifdef USE_SOLARIS_THREADS
1139 #include "pthread.h"
1144 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1146 PROCESS lwp_process_list; /* List of LWP initiated threads */
1148 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1150 #define CHECK check(__LINE__);
1152 typedef struct event {
1153 struct event *next; /* next in hash chain */
1154 char *event; /* lwp event: an address */
1155 int refcount; /* Is it in use? */
1156 pthread_cond_t cond; /* Currently associated condition variable */
1157 int seq; /* Sequence number: this is incremented
1158 by wakeup calls; wait will not return until
1162 #define HASHSIZE 127
1163 event_t *hashtable[HASHSIZE];/* Hash table for events */
1164 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1166 #if CMA_DEBUG || DEBUGF
1167 char *lwp_process_string(void)
1169 static char id[200];
1171 LWP_CurrentProcess(&p);
1172 sprintf(id, "PID %x <%s>", p, p->name);
1177 void lwp_unimplemented(char *interface)
1179 fprintf(stderr, "cmalwp: %s is not currently implemented: program aborted\n",
1184 static void lwpabort(char *interface)
1186 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1192 lwp_unimplemented("LWP_QWait");
1195 int LWP_QSignal(int pid)
1197 lwp_unimplemented("LWP_QSignal");
1200 /* Allocate and initialize an LWP process handle. The associated pthread handle
1201 * must be added by the caller, and the structure threaded onto the LWP active
1202 * process list by lwp_thread_process */
1203 static PROCESS lwp_alloc_process(char *name,
1204 pthread_startroutine_t ep, pthread_addr_t arg)
1207 assert(lp = (PROCESS) malloc(sizeof (*lp)));
1208 memset((char *) lp, 0, sizeof(*lp));
1212 sprintf(temp, "unnamed_process_%04d", ++procnum);
1213 assert(name = (char *)malloc(strlen(temp) + 1));
1222 /* Thread the LWP process descriptor *lp onto the lwp active process list
1223 * and associate a back pointer to the process descriptor from the associated
1225 static lwp_thread_process(PROCESS lp)
1227 lp->next = lwp_process_list;
1228 lwp_process_list = lp;
1229 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1232 /* The top-level routine used as entry point to explicitly created LWP
1233 * processes. This completes a few details of process creation left
1234 * out by LWP_CreateProcess and calls the user-specified entry point */
1235 static int lwp_top_level(pthread_addr_t argp)
1237 PROCESS lp = (PROCESS) argp;
1239 assert(!pthread_mutex_lock(&lwp_mutex));
1240 lwp_thread_process(lp);
1242 assert(!pthread_mutex_unlock(&lwp_mutex));
1243 /* Should cleanup state */
1246 int LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1247 void *parm, char *name, PROCESS *pid)
1250 pthread_attr_t attr;
1254 #ifndef LWP_NO_PRIORITIES
1255 if (!cmalwp_pri_inrange(priority))
1258 assert(!pthread_attr_create(&attr));
1259 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1261 assert(!pthread_attr_setstacksize(&attr, stacksize));
1263 (void) pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1264 (void) pthread_attr_setsched(&attr, SCHED_FIFO);
1265 #ifndef LWP_NO_PRIORITIES
1266 (void) pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1269 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep, (pthread_addr_t) parm);
1271 /* allow new thread to run if higher priority */
1272 assert(!pthread_mutex_unlock(&lwp_mutex));
1273 /* process is only added to active list after first time it runs (it adds itself) */
1274 status = pthread_create(&lp->handle,
1276 (pthread_startroutine_t) lwp_top_level,
1277 (pthread_addr_t) lp);
1278 assert(!pthread_attr_delete(&attr));
1279 assert (!pthread_mutex_lock(&lwp_mutex));
1288 PROCESS LWP_ActiveProcess(void)
1289 { /* returns pid of current process */
1291 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) &pid));
1295 int LWP_CurrentProcess(PROCESS *pid) /* get pid of current process */
1297 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1301 int LWP_DestroyProcess(PROCESS pid) /* destroy a lightweight process */
1303 lwp_unimplemented("LWP_DestroyProcess");
1306 int LWP_DispatchProcess(void) /* explicit voluntary preemption */
1308 assert(!pthread_mutex_unlock(&lwp_mutex));
1310 assert(!pthread_mutex_lock(&lwp_mutex));
1314 static int lwp_process_key_destructor(void)
1318 int LWP_InitializeProcessSupport(int priority, PROCESS *pid)
1320 static int initialized = 0;
1331 #ifndef LWP_NO_PRIORITIES
1332 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1336 /* Create pthread key to associate LWP process descriptor with each
1337 LWP-created thread */
1338 assert(!pthread_keycreate(&lwp_process_key,
1339 (pthread_destructor_t) lwp_process_key_destructor));
1341 lp = lwp_alloc_process("main process", main, 0);
1342 lp->handle = pthread_self();
1343 lwp_thread_process(lp);
1344 #ifndef LWP_NO_PRIORITIES
1345 (void) pthread_setscheduler(pthread_self(),
1347 cmalwp_lwppri_to_cmapri(priority));
1350 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1351 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1357 int LWP_TerminateProcessSupport(void) /* terminate all LWP support */
1359 lwp_unimplemented("LWP_TerminateProcessSupport");
1362 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1363 static event_t *getevent(char *event)
1365 event_t *evp, *newp;
1368 hashcode = hash(event);
1369 evp = hashtable[hashcode];
1372 if (evp->event == event) {
1376 if (evp->refcount == 0)
1381 newp = (event_t *) malloc(sizeof (event_t));
1383 newp->next = hashtable[hashcode];
1384 hashtable[hashcode] = newp;
1385 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t)0)));
1388 newp->event = event;
1393 /* Release the specified event */
1394 #define relevent(evp) ((evp)->refcount--)
1396 int LWP_WaitProcess(char *event) /* wait on a single event */
1400 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1401 if (event == NULL) return LWP_EBADEVENT;
1402 ev = getevent(event);
1404 while (seq == ev->seq) {
1405 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1407 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1412 int LWP_MwaitProcess(int wcount, char *evlist[]) /* wait on m of n events */
1414 lwp_unimplemented("LWP_MWaitProcess");
1417 int LWP_NoYieldSignal(char *event)
1420 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1421 if (event == NULL) return LWP_EBADEVENT;
1422 ev = getevent(event);
1423 if (ev->refcount > 1) {
1425 assert(pthread_cond_broadcast(&ev->cond) == 0);
1431 int LWP_SignalProcess(char *event)
1434 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1435 if (event == NULL) return LWP_EBADEVENT;
1436 ev = getevent(event);
1437 if (ev->refcount > 1) {
1439 assert(!pthread_mutex_unlock(&lwp_mutex));
1440 assert(!pthread_cond_broadcast(&ev->cond));
1442 assert(!pthread_mutex_lock(&lwp_mutex));
1448 int LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1450 lwp_unimplemented("LWP_StackUsed");
1453 int LWP_NewRock(int Tag, char *Value)
1455 lwp_unimplemented("LWP_NewRock");
1458 int LWP_GetRock(int Tag, char **Value)
1460 lwp_unimplemented("LWP_GetRock");
1463 int LWP_GetProcessPriority(PROCESS pid, int *priority) /* returns process priority */
1465 lwp_unimplemented("LWP_GetProcessPriority");
1468 #endif /* USE_PTHREADS */