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 *
16 \*******************************************************************/
19 /* allocate externs here */
20 #include <afsconfig.h>
21 #include <afs/param.h>
35 #define WAITING (1<<2)
36 #define DESTROYED (1<<3)
37 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
42 #define Debug(level, msg)\
43 if (lwp_debug && lwp_debug >= level) {\
44 printf("***LWP (0x%x): ", lwp_cpptr);\
50 #define Debug(level, msg)
55 int Create_Process_Part2();
57 int Initialize_Stack(), Stack_Used();
58 char (*RC_to_ASCII());
60 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
65 } runnable[MAX_PRIORITIES], blocked;
67 /* Offset of stack field within pcb -- used by stack checking stuff */
72 register struct QUEUE *q;
74 /* Special test for only element on queue */
78 /* Not only element, do normal remove */
79 p -> next -> prev = p -> prev;
80 p -> prev -> next = p -> next;
82 /* See if head pointing to this element */
83 if (q->head == p) q -> head = p -> next;
85 p -> next = p -> prev = NULL;
90 register struct QUEUE *q;
92 if (q->head == NULL) { /* Queue is empty */
94 p -> next = p -> prev = p;
95 } else { /* Regular insert */
96 p -> prev = q -> head -> prev;
97 q -> head -> prev -> next = p;
98 q -> head -> prev = p;
99 p -> next = q -> head;
104 static move(p, from, to)
106 struct QUEUE *from, *to;
113 #define for_all_elts(var, q, body)\
115 register PROCESS var, _NEXT_;\
117 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
118 _NEXT_ = var -> next;\
124 /*****************************************************************************\
126 * Following section documents the Assembler interfaces used by LWP code *
128 \*****************************************************************************/
131 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
133 Stub for Assembler routine that will
134 save the current SP value in the passed
135 context savearea and call the function
136 whose entry point is in ep. If the sp
137 parameter is NULL, the current stack is
138 used, otherwise sp becomes the new stack
141 returnto(struct lwp_context *savearea);
143 Stub for Assembler routine that will
144 restore context from a passed savearea
145 and return to the restored C frame.
149 /* Macro to force a re-schedule. Strange name is historical */
151 #define Set_LWP_RC(dummy) savecontext(Dispatcher, &lwp_cpptr->context, NULL)
153 static struct lwp_ctl *lwp_init;
155 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
157 int stacksize, priority;
165 Debug(0, ("Entered LWP_CreateProcess"))
166 /* Throw away all dead process control blocks */
169 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
174 if (stacksize < MINSTACK)
177 stacksize = 4 * ((stacksize+3) / 4);
178 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
182 if (priority < 0 || priority >= MAX_PRIORITIES) {
188 Initialize_Stack(stackptr, stacksize);
191 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
192 insert(temp, &runnable[priority]);
195 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-4);
203 int LWP_CurrentProcess(pid) /* returns pid of current process */
206 Debug(0, ("Entered Current_Process"))
214 #define LWPANCHOR (*lwp_init)
216 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
221 Debug(0, ("Entered Destroy_Process"))
223 if (lwp_cpptr != pid) {
224 Dispose_of_Dead_PCB(pid);
227 pid -> status = DESTROYED;
228 move(pid, &runnable[pid->priority], &blocked);
230 savecontext(Dispatcher, &(temp -> context),
231 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-4]));
238 int LWP_DispatchProcess() /* explicit voluntary preemption */
240 Debug(2, ("Entered Dispatch_Process"))
253 for (i=0; i<MAX_PRIORITIES; i++)
254 for_all_elts(x, runnable[i], {
255 printf("[Priority %d]\n", i);
258 for_all_elts(x, blocked, { Dump_One_Process(x); })
260 printf("***LWP: LWP support not initialized\n");
264 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
268 Debug(0, ("Entered Get_Process_Priority"))
270 *priority = pid -> priority;
276 int LWP_InitializeProcessSupport(priority, pid)
281 struct lwp_pcb dummy;
284 Debug(0, ("Entered LWP_InitializeProcessSupport"))
285 if (lwp_init != NULL) return LWP_EINIT;
287 /* Set up offset for stack checking -- do this as soon as possible */
288 stack_offset = (char *) &dummy.stack - (char *) &dummy;
290 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
291 for (i=0; i<MAX_PRIORITIES; i++) {
292 runnable[i].head = NULL;
293 runnable[i].count = 0;
297 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
298 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
299 if (lwp_init == NULL || temp == NULL)
300 Abort_LWP("Insufficient Storage to Initialize LWP Support");
301 LWPANCHOR.processcnt = 1;
302 LWPANCHOR.outerpid = temp;
303 LWPANCHOR.outersp = NULL;
304 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
305 insert(temp, &runnable[priority]);
306 savecontext(Dispatcher, &temp->context, NULL);
307 LWPANCHOR.outersp = temp -> context.topstack;
313 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
317 Debug(2, ("Entered LWP_SignalProcess"))
320 rc = Internal_Signal(event);
321 if (yield) Set_LWP_RC();
327 int LWP_TerminateProcessSupport() /* terminate all LWP support */
332 Debug(0, ("Entered Terminate_Process_Support"))
333 if (lwp_init == NULL) return LWP_EINIT;
334 if (lwp_cpptr != LWPANCHOR.outerpid)
335 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
336 pc = LWPANCHOR.processcnt-1;
337 for (i=0; i<MAX_PRIORITIES; i++)
338 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
339 for_all_elts(cur, blocked, { Free_PCB(cur); })
345 int LWP_WaitProcess(event) /* wait on a single event */
350 Debug(2, ("Entered Wait_Process"))
351 if (event == NULL) return LWP_EBADEVENT;
354 return LWP_MwaitProcess(1, tempev);
357 int LWP_MwaitProcess(wcount, evlist, ecount) /* wait on m of n events */
358 register int wcount, ecount;
359 register char *evlist[];
361 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
365 return LWP_EBADCOUNT;
368 if (wcount>ecount || wcount<0) {
370 return LWP_EBADCOUNT;
372 if (ecount > LWP_MAX_EVENTS) {
374 return LWP_EBADCOUNT;
377 lwp_cpptr->eventlist[0] = evlist[0];
379 memcpy(lwp_cpptr->eventlist, evlist, ecount*sizeof(char *));
381 lwp_cpptr -> status = WAITING;
382 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
384 lwp_cpptr -> wakevent = 0;
385 lwp_cpptr -> waitcnt = wcount;
386 lwp_cpptr -> eventcnt = ecount;
393 int LWP_StackUsed(pid, max, used)
397 #define NO_STACK_STUFF
400 #undef NO_STACK_STUFF
404 #ifdef NO_STACK_STUFF
407 *max = pid -> stacksize;
408 *used = Stack_Used(pid->stack, *max);
414 * The following functions are strictly
415 * INTERNAL to the LWP support package.
418 static Abort_LWP(msg)
421 struct lwp_context tempcontext;
423 Debug(0, ("Entered Abort_LWP"))
424 printf("***LWP: %s\n",msg);
425 printf("***LWP: Abort --- dumping PCBs ...\n");
429 if (LWPANCHOR.outersp == NULL)
432 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
435 static Create_Process_Part2 () /* creates a context for the new process */
439 Debug(2, ("Entered Create_Process_Part2"))
440 temp = lwp_cpptr; /* Get current process id */
441 savecontext(Dispatcher, &temp->context, NULL);
442 (*temp->ep)(temp->parm);
443 LWP_DestroyProcess(temp);
446 static Delete_PCB(pid) /* remove a PCB from the process list */
447 register PROCESS pid;
449 Debug(4, ("Entered Delete_PCB"))
450 remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
452 : &runnable[pid->priority]));
453 LWPANCHOR.processcnt--;
457 static Dump_One_Process(pid)
462 printf("***LWP: Process Control Block at 0x%x\n", pid);
463 printf("***LWP: Name: %s\n", pid->name);
465 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
466 if (pid->blockflag) printf("BLOCKED and ");
467 switch (pid->status) {
468 case READY: printf("READY"); break;
469 case WAITING: printf("WAITING"); break;
470 case DESTROYED: printf("DESTROYED"); break;
471 default: printf("unknown");
474 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
475 pid->priority, pid->parm);
476 if (pid->stacksize != 0) {
477 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
478 pid->stacksize, pid->stack);
479 printf("***LWP: HWM stack usage: ");
480 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
483 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
484 if (pid->eventcnt > 0) {
485 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
486 printf("***LWP: Event id list:");
487 for (i=0;i<pid->eventcnt;i++)
488 printf(" 0x%x", pid->eventlist[i]);
492 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
496 static purge_dead_pcbs()
498 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
501 int LWP_TraceProcesses = 0;
503 static Dispatcher() /* Lightweight process dispatcher */
507 static int dispatch_count = 0;
509 if (LWP_TraceProcesses > 0) {
510 for (i=0; i<MAX_PRIORITIES; i++) {
511 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
512 for_all_elts(p, runnable[i], {
513 printf(" \"%s\"", p->name);
517 printf("[Blocked (%d):", blocked.count);
518 for_all_elts(p, blocked, {
519 printf(" \"%s\"", p->name);
525 for (i=MAX_PRIORITIES-1; i>=0; i--)
526 if (runnable[i].head != NULL) break;
528 if (i < 0) Abort_LWP("No READY processes");
531 if (LWP_TraceProcesses > 0)
532 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
534 lwp_cpptr = runnable[i].head;
535 runnable[i].head = runnable[i].head -> next;
536 returnto(&lwp_cpptr->context);
539 static Dispose_of_Dead_PCB (cur)
542 Debug(4, ("Entered Dispose_of_Dead_PCB"))
546 Internal_Signal(cur);
558 Debug(4, ("Entered Free_PCB"))
559 if (pid -> stack != NULL) {
560 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
561 Stack_Used(pid->stack,pid->stacksize), pid))
567 static Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
570 int stacksize, priority;
576 Debug(4, ("Entered Initialize_PCB"))
578 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
579 temp -> name[31] = '\0';
580 temp -> status = READY;
581 temp -> eventcnt = 0;
582 temp -> wakevent = 0;
584 temp -> blockflag = 0;
585 temp -> priority = priority;
586 temp -> stack = stack;
587 temp -> stacksize = stacksize;
590 temp -> misc = NULL; /* currently unused */
595 static int Internal_Signal(event)
596 register char *event;
598 int rc = LWP_ENOWAIT;
601 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
602 if (!lwp_init) return LWP_EINIT;
603 if (event == NULL) return LWP_EBADEVENT;
604 for_all_elts(temp, blocked, {
605 if (temp->status == WAITING)
606 for (i=0; i < temp->eventcnt; i++) {
607 if (temp -> eventlist[i] == event) {
608 temp -> eventlist[i] = NULL;
610 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
611 if (--temp->waitcnt == 0) {
612 temp -> status = READY;
613 temp -> wakevent = i+1;
614 move(temp, &blocked, &runnable[temp->priority]);
625 static Initialize_Stack(stackptr, stacksize)
631 Debug(4, ("Entered Initialize_Stack"))
632 for (i=0; i<stacksize; i++) stackptr[i] = i & 0xff;
635 static int Stack_Used(stackptr, stacksize)
636 register char *stackptr;
641 for (i=0;i<stacksize;i++)
642 if ((unsigned char) stackptr[i] != (i & 0xff))
643 return (stacksize-i);