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)))
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! */
354 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
356 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_PARISC_LINUX24_ENV)
357 /* Need to have the sp on an 8-byte boundary for storing doubles. */
358 savecontext(Create_Process_Part2, &temp2->context,
359 stackptr+stacksize-16); /* 16 = 2 * jmp_buf_type*/
361 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
362 savecontext(Create_Process_Part2, &temp2->context,
363 stackptr+stacksize-0x40); /* lomgjmp does something
366 #if defined(AFS_S390_LINUX20_ENV)
367 savecontext(Create_Process_Part2, &temp2->context,
368 stackptr+stacksize-MINFRAME);
369 #else /* !AFS_S390_LINUX20_ENV */
370 savecontext(Create_Process_Part2, &temp2->context,
371 stackptr+stacksize-sizeof(void *));
372 #endif /* AFS_S390_LINUX20_ENV */
373 #endif /* AFS_SPARC64_LINUX20_ENV || AFS_SPARC_LINUX20_ENV */
374 #endif /* AFS_SGI62_ENV */
376 /* End of gross hack */
386 int LWP_CreateProcess2(int (*ep)(), int stacksize, int priority,
387 void *parm, char *name, PROCESS *pid)
392 #if defined(AFS_LWP_MINSTACKSIZE)
394 * on some systems (e.g. hpux), a minimum usable stack size has
397 if (stacksize < lwp_MinStackSize) {
398 stacksize = lwp_MinStackSize;
400 #endif /* defined(AFS_LWP_MINSTACKSIZE) */
401 /* more stack size computations; keep track of for IOMGR */
402 if (lwp_MaxStackSeen < stacksize)
403 lwp_MaxStackSeen = stacksize;
405 Debug(0, ("Entered LWP_CreateProcess"))
406 /* Throw away all dead process control blocks */
409 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
414 if (stacksize < MINSTACK)
417 stacksize = STACK_ALIGN * ((stacksize+STACK_ALIGN-1) / STACK_ALIGN);
418 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
422 if (priority < 0 || priority >= MAX_PRIORITIES) {
426 Initialize_Stack(stackptr, stacksize);
427 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
428 insert(temp, &runnable[priority]);
430 if (PRE_Block != 0) Abort_LWP("PRE_Block not 0");
432 /* Gross hack: beware! */
436 savecontext(Create_Process_Part2, &temp2->context, stackptr+MINFRAME);
438 #if defined(AFS_S390_LINUX20_ENV)
439 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-MINFRAME);
441 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-sizeof(void *));
444 /* End of gross hack */
454 int LWP_CurrentProcess(PROCESS *pid) /* returns pid of current process */
456 Debug(0, ("Entered Current_Process"))
464 PROCESS LWP_ThreadId(void)
466 Debug(0, ("Entered ThreadId"))
473 #define LWPANCHOR (*lwp_init)
475 int LWP_DestroyProcess(PROCESS pid) /* destroy a lightweight process */
479 Debug(0, ("Entered Destroy_Process"))
481 if (lwp_cpptr != pid) {
482 Dispose_of_Dead_PCB(pid);
485 pid -> status = DESTROYED;
486 move(pid, &runnable[pid->priority], &blocked);
489 savecontext(Dispatcher, &(temp -> context),
490 &(LWPANCHOR.dsptchstack[MINFRAME]));
492 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_PARISC_LINUX24_ENV)
493 savecontext(Dispatcher, &(temp -> context),
494 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-8]));
496 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
497 savecontext(Dispatcher, &(temp -> context),
498 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-0x40]));
500 #if defined(AFS_S390_LINUX20_ENV)
501 savecontext(Dispatcher, &(temp -> context),
502 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-MINFRAME]));
504 savecontext(Dispatcher, &(temp -> context),
505 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-sizeof(void *)]));
516 int LWP_DispatchProcess(void) /* explicit voluntary preemption */
518 Debug(2, ("Entered Dispatch_Process"))
527 int Dump_Processes(void)
531 for (i=0; i<MAX_PRIORITIES; i++)
532 for_all_elts(x, runnable[i], {
533 printf("[Priority %d]\n", i);
536 for_all_elts(x, blocked, { Dump_One_Process(x); })
538 printf("***LWP: LWP support not initialized\n");
543 int LWP_GetProcessPriority(PROCESS pid, int *priority) /* returns process priority */
545 Debug(0, ("Entered Get_Process_Priority"))
547 *priority = pid -> priority;
553 int LWP_InitializeProcessSupport(int priority, PROCESS *pid)
556 struct lwp_pcb dummy;
560 Debug(0, ("Entered LWP_InitializeProcessSupport"))
561 if (lwp_init != NULL) return LWP_SUCCESS;
563 /* Set up offset for stack checking -- do this as soon as possible */
564 stack_offset = (char *) &dummy.stack - (char *) &dummy;
566 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
567 for (i=0; i<MAX_PRIORITIES; i++) {
568 runnable[i].head = NULL;
569 runnable[i].count = 0;
573 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
574 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
575 if (lwp_init == NULL || temp == NULL)
576 Abort_LWP("Insufficient Storage to Initialize LWP Support");
577 LWPANCHOR.processcnt = 1;
578 LWPANCHOR.outerpid = temp;
579 LWPANCHOR.outersp = NULL;
580 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
581 insert(temp, &runnable[priority]);
582 savecontext(Dispatcher, &temp->context, NULL);
583 LWPANCHOR.outersp = temp -> context.topstack;
587 /* get minimum stack size from the environment. this allows the administrator
588 * to change the lwp stack dynamically without getting a new binary version.
590 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
591 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
593 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
594 AFS_LWP_MINSTACKSIZE : atoi(value));
599 int LWP_INTERNALSIGNAL(char *event, int yield) /* signal the occurence of an event */
601 Debug(2, ("Entered LWP_SignalProcess"))
604 rc = Internal_Signal(event);
605 if (yield) Set_LWP_RC();
611 int LWP_TerminateProcessSupport(void) /* terminate all LWP support */
615 Debug(0, ("Entered Terminate_Process_Support"))
616 if (lwp_init == NULL) return LWP_EINIT;
617 if (lwp_cpptr != LWPANCHOR.outerpid)
618 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
619 for (i=0; i<MAX_PRIORITIES; i++)
620 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
621 for_all_elts(cur, blocked, { Free_PCB(cur); })
627 int LWP_WaitProcess(char *event) /* wait on a single event */
631 Debug(2, ("Entered Wait_Process"))
632 if (event == NULL) return LWP_EBADEVENT;
635 return LWP_MwaitProcess(1, tempev);
638 int LWP_MwaitProcess(int wcount, char *evlist[]) /* wait on m of n events */
640 register int ecount, i;
643 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
645 if (evlist == NULL) {
647 return LWP_EBADCOUNT;
650 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
654 return LWP_EBADCOUNT;
659 if (wcount>ecount || wcount<0) {
661 return LWP_EBADCOUNT;
663 if (ecount > lwp_cpptr->eventlistsize) {
665 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist, ecount*sizeof(char *));
666 lwp_cpptr->eventlistsize = ecount;
668 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
670 lwp_cpptr -> status = WAITING;
672 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
675 lwp_cpptr -> wakevent = 0;
676 lwp_cpptr -> waitcnt = wcount;
677 lwp_cpptr -> eventcnt = ecount;
687 int LWP_StackUsed(PROCESS pid, int *maxa, int *used)
689 *maxa = pid -> stacksize;
690 *used = Stack_Used(pid->stack, *maxa);
697 * The following functions are strictly
698 * INTERNAL to the LWP support package.
701 static void Abort_LWP(char *msg)
703 struct lwp_context tempcontext;
705 Debug(0, ("Entered Abort_LWP"))
706 printf("***LWP: %s\n",msg);
707 printf("***LWP: Abort --- dumping PCBs ...\n");
711 if (LWPANCHOR.outersp == NULL)
714 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
718 static int Create_Process_Part2(void) /* creates a context for the new process */
722 Debug(2, ("Entered Create_Process_Part2"))
723 temp = lwp_cpptr; /* Get current process id */
724 savecontext(Dispatcher, &temp->context, NULL);
725 (*temp->ep)(temp->parm);
726 LWP_DestroyProcess(temp);
730 static int Delete_PCB(register PROCESS pid) /* remove a PCB from the process list */
732 Debug(4, ("Entered Delete_PCB"))
733 lwp_remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
735 : &runnable[pid->priority]));
736 LWPANCHOR.processcnt--;
741 static int Dump_One_Process(PROCESS pid)
745 printf("***LWP: Process Control Block at 0x%x\n", pid);
746 printf("***LWP: Name: %s\n", pid->name);
748 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
749 if (pid->blockflag) printf("BLOCKED and ");
750 switch (pid->status) {
751 case READY: printf("READY"); break;
752 case WAITING: printf("WAITING"); break;
753 case DESTROYED: printf("DESTROYED"); break;
754 default: printf("unknown");
757 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
758 pid->priority, pid->parm);
759 if (pid->stacksize != 0) {
760 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
761 pid->stacksize, pid->stack);
762 printf("***LWP: HWM stack usage: ");
763 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
766 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
767 if (pid->eventcnt > 0) {
768 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
769 printf("***LWP: Event id list:");
770 for (i=0;i<pid->eventcnt;i++)
771 printf(" 0x%x", pid->eventlist[i]);
775 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
780 static int purge_dead_pcbs(void)
782 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
786 int LWP_TraceProcesses = 0;
788 static int Dispatcher(void) /* Lightweight process dispatcher */
792 static int dispatch_count = 0;
794 if (LWP_TraceProcesses > 0) {
795 for (i=0; i<MAX_PRIORITIES; i++) {
796 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
797 for_all_elts(p, runnable[i], {
798 printf(" \"%s\"", p->name);
802 printf("[Blocked (%d):", blocked.count);
803 for_all_elts(p, blocked, {
804 printf(" \"%s\"", p->name);
810 /* Check for stack overflowif this lwp has a stack. Check for
811 the guard word at the front of the stack being damaged and
812 for the stack pointer being below the front of the stack.
813 WARNING! This code assumes that stacks grow downward. */
815 /* Fix this (stackcheck at other end of stack?) */
816 if (lwp_cpptr != NULL && lwp_cpptr->stack != NULL
817 && (lwp_cpptr->stackcheck !=
818 *(afs_int32 *)((lwp_cpptr->stack) + lwp_cpptr->stacksize - 4)
819 || lwp_cpptr->context.topstack >
820 lwp_cpptr->stack + lwp_cpptr->stacksize - 4)) {
822 if (lwp_cpptr && lwp_cpptr->stack &&
823 (lwp_cpptr->stackcheck != *(int *)(lwp_cpptr->stack) ||
824 lwp_cpptr->context.topstack < lwp_cpptr->stack ||
825 lwp_cpptr->context.topstack > (lwp_cpptr->stack + lwp_cpptr->stacksize))) {
827 printf("stackcheck = %u: stack = %u \n",
828 lwp_cpptr->stackcheck, *(int *)lwp_cpptr->stack);
829 printf("topstack = 0x%x: stackptr = 0x%x: stacksize = 0x%x\n",
830 lwp_cpptr->context.topstack, lwp_cpptr->stack, lwp_cpptr->stacksize);
832 switch (lwp_overflowAction) {
841 lwp_overflowAction = LWP_SOQUIET;
846 /* Move head of current runnable queue forward if current LWP is still in it. */
847 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
848 runnable[lwp_cpptr->priority].head = runnable[lwp_cpptr->priority].head -> next;
849 /* Find highest priority with runnable processes. */
850 for (i=MAX_PRIORITIES-1; i>=0; i--)
851 if (runnable[i].head != NULL) break;
853 if (i < 0) Abort_LWP("No READY processes");
856 if (LWP_TraceProcesses > 0)
857 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
859 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
860 lwp_cpptr = runnable[i].head;
862 returnto(&lwp_cpptr->context);
865 /* Complain of a stack overflow to stderr without using stdio. */
866 static void Overflow_Complain(void)
870 char *msg1 = " LWP: stack overflow in process ";
873 currenttime = time(0);
874 timeStamp = ctime(¤ttime);
876 write (2, timeStamp, strlen(timeStamp));
878 write (2, msg1, strlen(msg1));
879 write (2, lwp_cpptr->name, strlen(lwp_cpptr->name));
880 write (2, msg2, strlen(msg2));
883 static void Dispose_of_Dead_PCB (PROCESS cur)
885 Debug(4, ("Entered Dispose_of_Dead_PCB"))
889 Internal_Signal(cur);
893 static int Exit_LWP(void)
898 static void Free_PCB(PROCESS pid)
900 Debug(4, ("Entered Free_PCB"))
901 if (pid -> stack != NULL) {
902 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
903 Stack_Used(pid->stack,pid->stacksize), pid))
906 if (pid->eventlist != NULL) free(pid->eventlist);
910 static void Initialize_PCB(PROCESS temp, int priority, char *stack,
911 int stacksize, int (*ep)(), void *parm, char *name)
915 Debug(4, ("Entered Initialize_PCB"))
917 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
918 temp -> name[31] = '\0';
919 temp -> status = READY;
920 temp -> eventlist = (char **)malloc(EVINITSIZE*sizeof(char *));
921 temp -> eventlistsize = EVINITSIZE;
922 temp -> eventcnt = 0;
923 temp -> wakevent = 0;
925 temp -> blockflag = 0;
926 temp -> iomgrRequest = 0;
927 temp -> priority = priority;
928 temp -> index = lwp_nextindex++;
929 temp -> stack = stack;
930 temp -> stacksize = stacksize;
932 if (temp -> stack != NULL)
933 temp -> stackcheck = *(int *) ((temp -> stack) + stacksize - 4);
935 if (temp -> stack != NULL)
936 temp -> stackcheck = *(int *) (temp -> stack);
940 temp -> misc = NULL; /* currently unused */
943 temp -> lwp_rused = 0;
944 temp -> level = 1; /* non-preemptable */
947 static int Internal_Signal(register char *event)
949 int rc = LWP_ENOWAIT;
952 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
953 if (!lwp_init) return LWP_EINIT;
954 if (event == NULL) return LWP_EBADEVENT;
955 for_all_elts(temp, blocked, {
956 if (temp->status == WAITING)
957 for (i=0; i < temp->eventcnt; i++) {
958 if (temp -> eventlist[i] == event) {
959 temp -> eventlist[i] = NULL;
961 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
962 if (--temp->waitcnt == 0) {
963 temp -> status = READY;
964 temp -> wakevent = i+1;
965 move(temp, &blocked, &runnable[temp->priority]);
974 /* This can be any unlikely pattern except 0x00010203 or the reverse. */
975 #define STACKMAGIC 0xBADBADBA
976 static afs_int32 Initialize_Stack(char *stackptr, int stacksize)
980 Debug(4, ("Entered Initialize_Stack"))
981 if (lwp_stackUseEnabled)
982 for (i=0; i<stacksize; i++)
983 stackptr[i] = i &0xff;
986 *(afs_int32 *)(stackptr + stacksize - 4) = STACKMAGIC;
988 *(afs_int32 *)stackptr = STACKMAGIC;
993 static int Stack_Used(register char *stackptr, int stacksize)
998 if (*(afs_int32 *) (stackptr + stacksize - 4) == STACKMAGIC)
1001 for (i = stacksize - 1; i >= 0 ; i--)
1002 if ((unsigned char) stackptr[i] != (i & 0xff))
1007 if (*(afs_int32 *) stackptr == STACKMAGIC)
1010 for (i = 0; i < stacksize; i++)
1011 if ((unsigned char) stackptr[i] != (i & 0xff))
1012 return (stacksize - i);
1019 int LWP_NewRock(int Tag, char *Value)
1020 /* Finds a free rock and sets its value to Value.
1022 LWP_SUCCESS Rock did not exist and a new one was used
1023 LWP_EBADROCK Rock already exists.
1024 LWP_ENOROCKS All rocks are in use.
1026 From the above semantics, you can only set a rock value once. This is specifically
1027 to prevent multiple users of the LWP package from accidentally using the same Tag
1028 value and clobbering others. You can always use one level of indirection to obtain
1029 a rock whose contents can change.
1033 register struct rock *ra; /* rock array */
1035 ra = lwp_cpptr->lwp_rlist;
1037 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1038 if (ra[i].tag == Tag) return(LWP_EBADROCK);
1040 if (lwp_cpptr->lwp_rused < MAXROCKS)
1042 ra[lwp_cpptr->lwp_rused].tag = Tag;
1043 ra[lwp_cpptr->lwp_rused].value = Value;
1044 lwp_cpptr->lwp_rused++;
1045 return(LWP_SUCCESS);
1047 else return(LWP_ENOROCKS);
1051 int LWP_GetRock(int Tag, char **Value)
1052 /* Obtains the pointer Value associated with the rock Tag of this LWP.
1054 LWP_SUCCESS if specified rock exists and Value has been filled
1055 LWP_EBADROCK rock specified does not exist
1059 register struct rock *ra;
1061 ra = lwp_cpptr->lwp_rlist;
1063 for (i = 0; i < lwp_cpptr->lwp_rused; i++)
1064 if (ra[i].tag == Tag)
1066 *Value = ra[i].value;
1067 return(LWP_SUCCESS);
1069 return(LWP_EBADROCK);
1073 #ifdef AFS_AIX32_ENV
1074 int setlim(int limcon, uchar_t hard, int limit)
1078 (void) getrlimit(limcon, &rlim);
1080 limit = limit * 1024;
1082 rlim.rlim_max = limit;
1083 else if (limit == RLIM_INFINITY && geteuid() != 0)
1084 rlim.rlim_cur = rlim.rlim_max;
1086 rlim.rlim_cur = limit;
1088 /* Must use ulimit() due to Posix constraints */
1089 if (limcon == RLIMIT_FSIZE) {
1090 if (ulimit(UL_SETFSIZE, ((hard ? rlim.rlim_max : rlim.rlim_cur) / 512)) < 0) {
1091 printf("Can't %s%s limit\n",
1092 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1096 if (setrlimit(limcon, &rlim) < 0) {
1098 printf("Can't %s%s limit\n",
1099 limit == RLIM_INFINITY ? "remove" : "set", hard ? " hard" : "");
1109 * Print the specific limit out
1111 int plim(char *name, afs_int32 lc, uchar_t hard)
1116 printf("%s \t", name);
1117 (void) getrlimit(lc, &rlim);
1118 lim = hard ? rlim.rlim_max : rlim.rlim_cur;
1119 if (lim == RLIM_INFINITY)
1120 printf("unlimited");
1121 printf("%d %s", lim / 1024, "kbytes");
1128 int LWP_NoYieldSignal(char *event)
1130 return (LWP_INTERNALSIGNAL(event, 0));
1133 int LWP_SignalProcess(char *event)
1135 return (LWP_INTERNALSIGNAL(event, 1));
1140 #ifdef USE_SOLARIS_THREADS
1143 #include "pthread.h"
1148 pthread_mutex_t lwp_mutex; /* Mutex to ensure mutual exclusion of all LWP threads */
1150 PROCESS lwp_process_list; /* List of LWP initiated threads */
1152 pthread_key_t lwp_process_key; /* Key associating lwp pid with thread */
1154 #define CHECK check(__LINE__);
1156 typedef struct event {
1157 struct event *next; /* next in hash chain */
1158 char *event; /* lwp event: an address */
1159 int refcount; /* Is it in use? */
1160 pthread_cond_t cond; /* Currently associated condition variable */
1161 int seq; /* Sequence number: this is incremented
1162 by wakeup calls; wait will not return until
1166 #define HASHSIZE 127
1167 event_t *hashtable[HASHSIZE];/* Hash table for events */
1168 #define hash(event) ((unsigned long) (event) % HASHSIZE);
1170 #if CMA_DEBUG || DEBUGF
1171 char *lwp_process_string(void)
1173 static char id[200];
1175 LWP_CurrentProcess(&p);
1176 sprintf(id, "PID %x <%s>", p, p->name);
1181 void lwp_unimplemented(char *interface)
1183 fprintf(stderr, "cmalwp: %s is not currently implemented: program aborted\n",
1188 static void lwpabort(char *interface)
1190 fprintf(stderr, "cmalwp: %s failed unexpectedly\n", interface);
1196 lwp_unimplemented("LWP_QWait");
1199 int LWP_QSignal(int pid)
1201 lwp_unimplemented("LWP_QSignal");
1204 /* Allocate and initialize an LWP process handle. The associated pthread handle
1205 * must be added by the caller, and the structure threaded onto the LWP active
1206 * process list by lwp_thread_process */
1207 static PROCESS lwp_alloc_process(char *name,
1208 pthread_startroutine_t ep, pthread_addr_t arg)
1211 assert(lp = (PROCESS) malloc(sizeof (*lp)));
1212 memset((char *) lp, 0, sizeof(*lp));
1216 sprintf(temp, "unnamed_process_%04d", ++procnum);
1217 assert(name = (char *)malloc(strlen(temp) + 1));
1226 /* Thread the LWP process descriptor *lp onto the lwp active process list
1227 * and associate a back pointer to the process descriptor from the associated
1229 static lwp_thread_process(PROCESS lp)
1231 lp->next = lwp_process_list;
1232 lwp_process_list = lp;
1233 assert(!pthread_setspecific(lwp_process_key, (pthread_addr_t) lp));
1236 /* The top-level routine used as entry point to explicitly created LWP
1237 * processes. This completes a few details of process creation left
1238 * out by LWP_CreateProcess and calls the user-specified entry point */
1239 static int lwp_top_level(pthread_addr_t argp)
1241 PROCESS lp = (PROCESS) argp;
1243 assert(!pthread_mutex_lock(&lwp_mutex));
1244 lwp_thread_process(lp);
1246 assert(!pthread_mutex_unlock(&lwp_mutex));
1247 /* Should cleanup state */
1250 int LWP_CreateProcess(pthread_startroutine_t ep, int stacksize, int priority,
1251 void *parm, char *name, PROCESS *pid)
1254 pthread_attr_t attr;
1258 #ifndef LWP_NO_PRIORITIES
1259 if (!cmalwp_pri_inrange(priority))
1262 assert(!pthread_attr_create(&attr));
1263 assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
1265 assert(!pthread_attr_setstacksize(&attr, stacksize));
1267 (void) pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
1268 (void) pthread_attr_setsched(&attr, SCHED_FIFO);
1269 #ifndef LWP_NO_PRIORITIES
1270 (void) pthread_attr_setprio(&attr, cmalwp_lwppri_to_cmapri(priority));
1273 lp = lwp_alloc_process(name, (pthread_startroutine_t) ep, (pthread_addr_t) parm);
1275 /* allow new thread to run if higher priority */
1276 assert(!pthread_mutex_unlock(&lwp_mutex));
1277 /* process is only added to active list after first time it runs (it adds itself) */
1278 status = pthread_create(&lp->handle,
1280 (pthread_startroutine_t) lwp_top_level,
1281 (pthread_addr_t) lp);
1282 assert(!pthread_attr_delete(&attr));
1283 assert (!pthread_mutex_lock(&lwp_mutex));
1292 PROCESS LWP_ActiveProcess(void)
1293 { /* returns pid of current process */
1295 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) &pid));
1299 int LWP_CurrentProcess(PROCESS *pid) /* get pid of current process */
1301 assert(!pthread_getspecific(lwp_process_key, (pthread_addr_t *) pid));
1305 int LWP_DestroyProcess(PROCESS pid) /* destroy a lightweight process */
1307 lwp_unimplemented("LWP_DestroyProcess");
1310 int LWP_DispatchProcess(void) /* explicit voluntary preemption */
1312 assert(!pthread_mutex_unlock(&lwp_mutex));
1314 assert(!pthread_mutex_lock(&lwp_mutex));
1318 static int lwp_process_key_destructor(void)
1322 int LWP_InitializeProcessSupport(int priority, PROCESS *pid)
1324 static int initialized = 0;
1335 #ifndef LWP_NO_PRIORITIES
1336 if (priority < 0 || priority > LWP_MAX_PRIORITY)
1340 /* Create pthread key to associate LWP process descriptor with each
1341 LWP-created thread */
1342 assert(!pthread_keycreate(&lwp_process_key,
1343 (pthread_destructor_t) lwp_process_key_destructor));
1345 lp = lwp_alloc_process("main process", main, 0);
1346 lp->handle = pthread_self();
1347 lwp_thread_process(lp);
1348 #ifndef LWP_NO_PRIORITIES
1349 (void) pthread_setscheduler(pthread_self(),
1351 cmalwp_lwppri_to_cmapri(priority));
1354 assert(pthread_mutex_init(&lwp_mutex, MUTEX_FAST_NP) == 0);
1355 assert(pthread_mutex_lock(&lwp_mutex) == 0);
1361 int LWP_TerminateProcessSupport(void) /* terminate all LWP support */
1363 lwp_unimplemented("LWP_TerminateProcessSupport");
1366 /* Get and initialize event structure corresponding to lwp event (i.e. address) */
1367 static event_t *getevent(char *event)
1369 event_t *evp, *newp;
1372 hashcode = hash(event);
1373 evp = hashtable[hashcode];
1376 if (evp->event == event) {
1380 if (evp->refcount == 0)
1385 newp = (event_t *) malloc(sizeof (event_t));
1387 newp->next = hashtable[hashcode];
1388 hashtable[hashcode] = newp;
1389 assert(!pthread_cond_init(&newp->cond, ((pthread_condattr_t)0)));
1392 newp->event = event;
1397 /* Release the specified event */
1398 #define relevent(evp) ((evp)->refcount--)
1400 int LWP_WaitProcess(char *event) /* wait on a single event */
1404 debugf(("%s: wait process (%x)\n", lwp_process_string(), event));
1405 if (event == NULL) return LWP_EBADEVENT;
1406 ev = getevent(event);
1408 while (seq == ev->seq) {
1409 assert(pthread_cond_wait(&ev->cond, &lwp_mutex) == 0);
1411 debugf(("%s: Woken up (%x)\n", lwp_process_string(), event));
1416 int LWP_MwaitProcess(int wcount, char *evlist[]) /* wait on m of n events */
1418 lwp_unimplemented("LWP_MWaitProcess");
1421 int LWP_NoYieldSignal(char *event)
1424 debugf(("%s: no yield signal (%x)\n", lwp_process_string(), event));
1425 if (event == NULL) return LWP_EBADEVENT;
1426 ev = getevent(event);
1427 if (ev->refcount > 1) {
1429 assert(pthread_cond_broadcast(&ev->cond) == 0);
1435 int LWP_SignalProcess(char *event)
1438 debugf(("%s: signal process (%x)\n", lwp_process_string(), event));
1439 if (event == NULL) return LWP_EBADEVENT;
1440 ev = getevent(event);
1441 if (ev->refcount > 1) {
1443 assert(!pthread_mutex_unlock(&lwp_mutex));
1444 assert(!pthread_cond_broadcast(&ev->cond));
1446 assert(!pthread_mutex_lock(&lwp_mutex));
1452 int LWP_StackUsed(PROCESS pid, int *maxa, int *used)
1454 lwp_unimplemented("LWP_StackUsed");
1457 int LWP_NewRock(int Tag, char *Value)
1459 lwp_unimplemented("LWP_NewRock");
1462 int LWP_GetRock(int Tag, char **Value)
1464 lwp_unimplemented("LWP_GetRock");
1467 int LWP_GetProcessPriority(PROCESS pid, int *priority) /* returns process priority */
1469 lwp_unimplemented("LWP_GetProcessPriority");
1472 #endif /* USE_PTHREADS */