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>
34 #define WAITING (1<<2)
35 #define DESTROYED (1<<3)
36 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
41 #define Debug(level, msg)\
42 if (lwp_debug && lwp_debug >= level) {\
43 printf("***LWP (0x%x): ", lwp_cpptr);\
49 #define Debug(level, msg)
54 int Create_Process_Part2();
56 int Initialize_Stack(), Stack_Used();
57 char (*RC_to_ASCII());
59 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
64 } runnable[MAX_PRIORITIES], blocked;
66 /* Offset of stack field within pcb -- used by stack checking stuff */
73 /* Special test for only element on queue */
77 /* Not only element, do normal remove */
78 p -> next -> prev = p -> prev;
79 p -> prev -> next = p -> next;
81 /* See if head pointing to this element */
82 if (q->head == p) q -> head = p -> next;
84 p -> next = p -> prev = NULL;
91 if (q->head == NULL) { /* Queue is empty */
93 p -> next = p -> prev = p;
94 } else { /* Regular insert */
95 p -> prev = q -> head -> prev;
96 q -> head -> prev -> next = p;
97 q -> head -> prev = p;
98 p -> next = q -> head;
103 static move(p, from, to)
105 struct QUEUE *from, *to;
112 #define for_all_elts(var, q, body)\
114 PROCESS var, _NEXT_;\
116 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
117 _NEXT_ = var -> next;\
123 /*****************************************************************************\
125 * Following section documents the Assembler interfaces used by LWP code *
127 \*****************************************************************************/
130 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
132 Stub for Assembler routine that will
133 save the current SP value in the passed
134 context savearea and call the function
135 whose entry point is in ep. If the sp
136 parameter is NULL, the current stack is
137 used, otherwise sp becomes the new stack
140 returnto(struct lwp_context *savearea);
142 Stub for Assembler routine that will
143 restore context from a passed savearea
144 and return to the restored C frame.
148 /* Macro to force a re-schedule. Strange name is historical */
150 #define Set_LWP_RC(dummy) savecontext(Dispatcher, &lwp_cpptr->context, NULL)
152 static struct lwp_ctl *lwp_init;
154 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
156 int stacksize, priority;
164 Debug(0, ("Entered LWP_CreateProcess"))
165 /* Throw away all dead process control blocks */
168 temp = (PROCESS) malloc (sizeof (struct lwp_pcb));
173 if (stacksize < MINSTACK)
176 stacksize = 4 * ((stacksize+3) / 4);
177 if ((stackptr = (char *) malloc(stacksize)) == NULL) {
181 if (priority < 0 || priority >= MAX_PRIORITIES) {
187 Initialize_Stack(stackptr, stacksize);
190 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
191 insert(temp, &runnable[priority]);
194 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-4);
202 int LWP_CurrentProcess(pid) /* returns pid of current process */
205 Debug(0, ("Entered Current_Process"))
213 #define LWPANCHOR (*lwp_init)
215 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
220 Debug(0, ("Entered Destroy_Process"))
222 if (lwp_cpptr != pid) {
223 Dispose_of_Dead_PCB(pid);
226 pid -> status = DESTROYED;
227 move(pid, &runnable[pid->priority], &blocked);
229 savecontext(Dispatcher, &(temp -> context),
230 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-4]));
237 int LWP_DispatchProcess() /* explicit voluntary preemption */
239 Debug(2, ("Entered Dispatch_Process"))
252 for (i=0; i<MAX_PRIORITIES; i++)
253 for_all_elts(x, runnable[i], {
254 printf("[Priority %d]\n", i);
257 for_all_elts(x, blocked, { Dump_One_Process(x); })
259 printf("***LWP: LWP support not initialized\n");
263 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
267 Debug(0, ("Entered Get_Process_Priority"))
269 *priority = pid -> priority;
275 int LWP_InitializeProcessSupport(priority, pid)
280 struct lwp_pcb dummy;
283 Debug(0, ("Entered LWP_InitializeProcessSupport"))
284 if (lwp_init != NULL) return LWP_EINIT;
286 /* Set up offset for stack checking -- do this as soon as possible */
287 stack_offset = (char *) &dummy.stack - (char *) &dummy;
289 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
290 for (i=0; i<MAX_PRIORITIES; i++) {
291 runnable[i].head = NULL;
292 runnable[i].count = 0;
296 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
297 temp = (PROCESS) malloc(sizeof(struct lwp_pcb));
298 if (lwp_init == NULL || temp == NULL)
299 Abort_LWP("Insufficient Storage to Initialize LWP Support");
300 LWPANCHOR.processcnt = 1;
301 LWPANCHOR.outerpid = temp;
302 LWPANCHOR.outersp = NULL;
303 Initialize_PCB(temp, priority, NULL, 0, NULL, NULL, "Main Process [created by LWP]");
304 insert(temp, &runnable[priority]);
305 savecontext(Dispatcher, &temp->context, NULL);
306 LWPANCHOR.outersp = temp -> context.topstack;
312 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
316 Debug(2, ("Entered LWP_SignalProcess"))
319 rc = Internal_Signal(event);
320 if (yield) Set_LWP_RC();
326 int LWP_TerminateProcessSupport() /* terminate all LWP support */
331 Debug(0, ("Entered Terminate_Process_Support"))
332 if (lwp_init == NULL) return LWP_EINIT;
333 if (lwp_cpptr != LWPANCHOR.outerpid)
334 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
335 pc = LWPANCHOR.processcnt-1;
336 for (i=0; i<MAX_PRIORITIES; i++)
337 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
338 for_all_elts(cur, blocked, { Free_PCB(cur); })
344 int LWP_WaitProcess(event) /* wait on a single event */
349 Debug(2, ("Entered Wait_Process"))
350 if (event == NULL) return LWP_EBADEVENT;
353 return LWP_MwaitProcess(1, tempev);
356 int LWP_MwaitProcess(wcount, evlist, ecount) /* wait on m of n events */
360 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
364 return LWP_EBADCOUNT;
367 if (wcount>ecount || wcount<0) {
369 return LWP_EBADCOUNT;
371 if (ecount > LWP_MAX_EVENTS) {
373 return LWP_EBADCOUNT;
376 lwp_cpptr->eventlist[0] = evlist[0];
378 memcpy(lwp_cpptr->eventlist, evlist, ecount*sizeof(char *));
380 lwp_cpptr -> status = WAITING;
381 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
383 lwp_cpptr -> wakevent = 0;
384 lwp_cpptr -> waitcnt = wcount;
385 lwp_cpptr -> eventcnt = ecount;
392 int LWP_StackUsed(pid, max, used)
396 #define NO_STACK_STUFF
399 #undef NO_STACK_STUFF
403 #ifdef NO_STACK_STUFF
406 *max = pid -> stacksize;
407 *used = Stack_Used(pid->stack, *max);
413 * The following functions are strictly
414 * INTERNAL to the LWP support package.
417 static Abort_LWP(msg)
420 struct lwp_context tempcontext;
422 Debug(0, ("Entered Abort_LWP"))
423 printf("***LWP: %s\n",msg);
424 printf("***LWP: Abort --- dumping PCBs ...\n");
428 if (LWPANCHOR.outersp == NULL)
431 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
434 static Create_Process_Part2 () /* creates a context for the new process */
438 Debug(2, ("Entered Create_Process_Part2"))
439 temp = lwp_cpptr; /* Get current process id */
440 savecontext(Dispatcher, &temp->context, NULL);
441 (*temp->ep)(temp->parm);
442 LWP_DestroyProcess(temp);
445 static Delete_PCB(pid) /* remove a PCB from the process list */
448 Debug(4, ("Entered Delete_PCB"))
449 remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
451 : &runnable[pid->priority]));
452 LWPANCHOR.processcnt--;
456 static Dump_One_Process(pid)
461 printf("***LWP: Process Control Block at 0x%x\n", pid);
462 printf("***LWP: Name: %s\n", pid->name);
464 printf("***LWP: Initial entry point: 0x%x\n", pid->ep);
465 if (pid->blockflag) printf("BLOCKED and ");
466 switch (pid->status) {
467 case READY: printf("READY"); break;
468 case WAITING: printf("WAITING"); break;
469 case DESTROYED: printf("DESTROYED"); break;
470 default: printf("unknown");
473 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
474 pid->priority, pid->parm);
475 if (pid->stacksize != 0) {
476 printf("***LWP: Stacksize: %d \tStack base address: 0x%x\n",
477 pid->stacksize, pid->stack);
478 printf("***LWP: HWM stack usage: ");
479 printf("%d\n", Stack_Used(pid->stack,pid->stacksize));
482 printf("***LWP: Current Stack Pointer: 0x%x\n", pid->context.topstack);
483 if (pid->eventcnt > 0) {
484 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
485 printf("***LWP: Event id list:");
486 for (i=0;i<pid->eventcnt;i++)
487 printf(" 0x%x", pid->eventlist[i]);
491 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
495 static purge_dead_pcbs()
497 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
500 int LWP_TraceProcesses = 0;
502 static Dispatcher() /* Lightweight process dispatcher */
506 static int dispatch_count = 0;
508 if (LWP_TraceProcesses > 0) {
509 for (i=0; i<MAX_PRIORITIES; i++) {
510 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
511 for_all_elts(p, runnable[i], {
512 printf(" \"%s\"", p->name);
516 printf("[Blocked (%d):", blocked.count);
517 for_all_elts(p, blocked, {
518 printf(" \"%s\"", p->name);
524 for (i=MAX_PRIORITIES-1; i>=0; i--)
525 if (runnable[i].head != NULL) break;
527 if (i < 0) Abort_LWP("No READY processes");
530 if (LWP_TraceProcesses > 0)
531 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
533 lwp_cpptr = runnable[i].head;
534 runnable[i].head = runnable[i].head -> next;
535 returnto(&lwp_cpptr->context);
538 static Dispose_of_Dead_PCB (cur)
541 Debug(4, ("Entered Dispose_of_Dead_PCB"))
545 Internal_Signal(cur);
557 Debug(4, ("Entered Free_PCB"))
558 if (pid -> stack != NULL) {
559 Debug(0, ("HWM stack usage: %d, [PCB at 0x%x]",
560 Stack_Used(pid->stack,pid->stacksize), pid))
566 static Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
569 int stacksize, priority;
575 Debug(4, ("Entered Initialize_PCB"))
577 while (((temp -> name[i] = name[i]) != '\0') && (i < 31)) i++;
578 temp -> name[31] = '\0';
579 temp -> status = READY;
580 temp -> eventcnt = 0;
581 temp -> wakevent = 0;
583 temp -> blockflag = 0;
584 temp -> priority = priority;
585 temp -> stack = stack;
586 temp -> stacksize = stacksize;
589 temp -> misc = NULL; /* currently unused */
594 static int Internal_Signal(event)
597 int rc = LWP_ENOWAIT;
600 Debug(0, ("Entered Internal_Signal [event id 0x%x]", event))
601 if (!lwp_init) return LWP_EINIT;
602 if (event == NULL) return LWP_EBADEVENT;
603 for_all_elts(temp, blocked, {
604 if (temp->status == WAITING)
605 for (i=0; i < temp->eventcnt; i++) {
606 if (temp -> eventlist[i] == event) {
607 temp -> eventlist[i] = NULL;
609 Debug(0, ("Signal satisfied for PCB 0x%x", temp))
610 if (--temp->waitcnt == 0) {
611 temp -> status = READY;
612 temp -> wakevent = i+1;
613 move(temp, &blocked, &runnable[temp->priority]);
624 static Initialize_Stack(stackptr, stacksize)
630 Debug(4, ("Entered Initialize_Stack"))
631 for (i=0; i<stacksize; i++) stackptr[i] = i & 0xff;
634 static int Stack_Used(stackptr, stacksize)
640 for (i=0;i<stacksize;i++)
641 if ((unsigned char) stackptr[i] != (i & 0xff))
642 return (stacksize-i);