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 /* For NT, LWP is implemented on top of fibers. The design attempts to
11 * follow the current LWP implementation so that we are not using 2 LWP
12 * models. The parts of the Unix LWP model that are not actually used in
13 * AFS have not been implemented at all. With the exception of preemption,
14 * adding those parts to this NT base would be a matter of adding routines.
16 * required lib is kernel32.lib, header is winbase.h
19 #include <afsconfig.h>
20 #include <afs/param.h>
27 #include <afs/afsutil.h>
31 static struct lwp_ctl *lwp_init;
32 #define LWPANCHOR (*lwp_init)
45 #define Debug(level, msg)\
46 if (lwp_debug && lwp_debug >= level) {\
47 printf("***LWP (0x%p): ", lwp_cpptr);\
53 #define Debug(level, msg)
57 /* Forward declarations */
58 static void Dispatcher(void);
59 static void Exit_LWP(void);
60 static void Abort_LWP(char *msg);
61 static VOID WINAPI Enter_LWP(PVOID fiberData);
62 static void Initialize_PCB(PROCESS pcb, int priority, int stacksize,
63 int (*funP)(), void *argP, char *name);
65 static void Dispose_of_Dead_PCB();
66 static void Free_PCB();
67 static int Internal_Signal();
68 static void purge_dead_pcbs(void);
70 static void lwp_remove(PROCESS p, struct QUEUE *q);
71 static void insert(PROCESS p, struct QUEUE *q);
72 static void move(PROCESS p, struct QUEUE *from, struct QUEUE *to);
74 /* biggest LWP stack created so far - used by IOMGR */
75 int lwp_MaxStackSeen = 0;
78 static void Dump_One_Process(PROCESS pid);
79 static void Dump_Processes(void);
84 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
86 /* Invariant for runnable queues: The head of each queue points to the
87 * currently running process if it is in that queue, or it points to the
88 * next process in that queue that should run.
93 } runnable[MAX_PRIORITIES], blocked;
96 #define for_all_elts(var, q, body)\
98 register PROCESS var, _NEXT_;\
100 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
101 _NEXT_ = var -> next;\
108 LPVOID ConvertThreadToFiber(PROCESS x)
112 LPVOID CreateFiber(DWORD x ,LPVOID y,PROCESS z)
117 VOID SwitchToFiber(LPVOID p)
121 VOID DeleteFiber(LPVOID p)
127 int lwp_MinStackSize = 0;
129 /* LWP_InitializeProcessSupport - setup base support for fibers.
132 * priority - priority of main thread.
135 * pid - return this process
137 * LWP_SUCCESS (else aborts)
141 int LWP_InitializeProcessSupport(int priority, PROCESS *pid)
147 Debug(0, ("Entered LWP_InitializeProcessSupport"))
148 if (lwp_init != NULL) return LWP_SUCCESS;
150 if (priority >= MAX_PRIORITIES) return LWP_EBADPRI;
152 pcb = (PROCESS)malloc(sizeof(*pcb));
154 Abort_LWP("Insufficient Storage to Initialize LWP PCB");
155 (void) memset((void*)pcb, 0, sizeof(*pcb));
156 pcb->fiber = ConvertThreadToFiber(pcb);
158 Abort_LWP("Cannot convert main thread to LWP fiber");
160 lwp_init = (struct lwp_ctl *) malloc(sizeof(struct lwp_ctl));
161 if (lwp_init == NULL)
162 Abort_LWP("Insufficient Storage to Initialize LWP CTL");
163 (void) memset((void*)lwp_init, 0, sizeof(struct lwp_ctl));
165 for (i=0; i<MAX_PRIORITIES; i++) {
166 runnable[i].head = NULL;
167 runnable[i].count = 0;
172 LWPANCHOR.processcnt = 1;
173 LWPANCHOR.outerpid = pcb;
174 LWPANCHOR.outersp = NULL;
177 Initialize_PCB(pcb, priority, 0, NULL, NULL,
178 "Main Process [created by LWP]");
181 Debug(10, ("Init: Insert 0x%p into runnable at priority %d\n", pcb, priority))
182 insert(pcb, &runnable[priority]);
184 if ( ( value = getenv("AFS_LWP_STACK_SIZE")) == NULL )
185 lwp_MinStackSize = AFS_LWP_MINSTACKSIZE;
187 lwp_MinStackSize = (AFS_LWP_MINSTACKSIZE>atoi(value)?
188 AFS_LWP_MINSTACKSIZE : atoi(value));
195 /* LWP_CreateProcess - create a new fiber and start executing it.
198 * funP - start function
199 * stacksize - size of
200 * priority - LWP priority
201 * argP - initial parameter for start function
205 * pid - handle of created LWP
208 * LWP_EINIT - error in intialization.
211 int LWP_CreateProcess(int (*funP)(), int stacksize, int priority, void *argP,
212 char *name, PROCESS *pid)
218 pcb = (PROCESS)malloc(sizeof(*pcb));
221 (void) memset((void*)pcb, 0, sizeof(*pcb));
224 * on some systems (e.g. hpux), a minimum usable stack size has
227 if (stacksize < lwp_MinStackSize) {
228 stacksize = lwp_MinStackSize;
230 /* more stack size computations; keep track of for IOMGR */
231 if (lwp_MaxStackSeen < stacksize)
232 lwp_MaxStackSeen = stacksize;
234 pcb->fiber = CreateFiber(stacksize, Enter_LWP, pcb);
235 if (pcb->fiber == NULL) {
239 Debug(0, ("Create: pcb=0x%p, funP=0x%p, argP=0x%p\n", pcb, funP, argP))
240 /* Fiber is now created, so fill in PCB */
241 Initialize_PCB(pcb, priority, stacksize, funP, argP, name);
242 Debug(10, ("Create: Insert 0x%p into runnable at priority %d\n", pcb, priority))
243 insert(pcb, &runnable[priority]);
245 LWPANCHOR.processcnt++;
247 /* And hand off execution. */
248 SwitchToFiber(pcb->fiber);
255 int LWP_DestroyProcess(PROCESS pid)
257 Debug(0, ("Entered Destroy_Process"))
262 if (lwp_cpptr != pid) {
263 Dispose_of_Dead_PCB(pid);
265 pid->status = DESTROYED;
266 move(pid, &runnable[pid->priority], &blocked);
277 (tp=lwp_cpptr) -> status = QWAITING;
278 lwp_remove(tp, &runnable[tp->priority]);
283 int LWP_QSignal(PROCESS pid)
285 if (pid->status == QWAITING) {
287 Debug(10, ("QSignal: Insert 0x%p into runnable at priority %d\n", pid, pid->priority))
288 insert(pid, &runnable[pid->priority]);
291 else return LWP_ENOWAIT;
294 int LWP_CurrentProcess(PROCESS *pid)
296 Debug(0, ("Entered Current_Process"))
304 PROCESS LWP_ThreadId()
306 Debug(0, ("Entered ThreadId"))
313 int LWP_DispatchProcess(void) /* explicit voluntary preemption */
315 Debug(2, ("Entered Dispatch_Process"))
325 static void Dump_Processes(void)
329 for (i=0; i<MAX_PRIORITIES; i++)
330 for_all_elts(x, runnable[i], {
331 printf("[Priority %d]\n", i);
334 for_all_elts(x, blocked, { Dump_One_Process(x); })
336 printf("***LWP: LWP support not initialized\n");
341 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
345 Debug(0, ("Entered Get_Process_Priority"))
347 *priority = pid->priority;
353 static int Internal_Signal(char *event)
355 int rc = LWP_ENOWAIT;
358 Debug(0, ("Entered Internal_Signal [event id 0x%p]", event))
359 if (!lwp_init) return LWP_EINIT;
360 if (event == NULL) return LWP_EBADEVENT;
361 for_all_elts(temp, blocked, {
362 if (temp->status == WAITING)
363 for (i=0; i < temp->eventcnt; i++) {
364 if (temp -> eventlist[i] == event) {
365 temp -> eventlist[i] = NULL;
367 Debug(0, ("Signal satisfied for PCB 0x%p", temp))
368 if (--temp->waitcnt == 0) {
369 temp -> status = READY;
370 temp -> wakevent = i+1;
371 move(temp, &blocked, &runnable[temp->priority]);
380 /* signal the occurence of an event */
381 int LWP_INTERNALSIGNAL(void *event, int yield)
383 Debug(2, ("Entered LWP_SignalProcess"))
386 rc = Internal_Signal(event);
394 int LWP_TerminateProcessSupport() /* terminate all LWP support */
398 Debug(0, ("Entered Terminate_Process_Support"))
399 if (lwp_init == NULL) return LWP_EINIT;
400 if (lwp_cpptr != LWPANCHOR.outerpid)
401 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
402 /* Is this safe??? @@@ */
403 for (i=0; i<MAX_PRIORITIES; i++)
404 for_all_elts(cur, runnable[i], { Free_PCB(cur); })
405 for_all_elts(cur, blocked, { Free_PCB(cur); })
411 int LWP_MwaitProcess(int wcount, void **evlist)
415 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
416 if (evlist == NULL) {
418 return LWP_EBADCOUNT;
421 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
425 return LWP_EBADCOUNT;
431 if (wcount>ecount || wcount<0) {
433 return LWP_EBADCOUNT;
435 if (ecount > lwp_cpptr->eventlistsize) {
437 void **save_eventlist = lwp_cpptr->eventlist;
438 lwp_cpptr->eventlist = (char **)realloc(lwp_cpptr->eventlist,
439 ecount*sizeof(char *));
440 if (lwp_cpptr->eventlist == NULL) {
441 lwp_cpptr->eventlist = save_eventlist;
445 lwp_cpptr->eventlistsize = ecount;
447 for (i=0; i<ecount; i++) lwp_cpptr -> eventlist[i] = evlist[i];
449 lwp_cpptr->status = WAITING;
451 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
454 lwp_cpptr->wakevent = 0;
455 lwp_cpptr->waitcnt = wcount;
456 lwp_cpptr->eventcnt = ecount;
463 int LWP_WaitProcess(void *event) /* wait on a single event */
467 Debug(2, ("Entered Wait_Process"))
468 if (event == NULL) return LWP_EBADEVENT;
471 return LWP_MwaitProcess(1, tempev);
475 /* Internal Support Routines */
476 static void Initialize_PCB(PROCESS pcb, int priority, int stacksize,
477 int (*funP)(), void *argP, char *name)
481 Debug(4, ("Entered Initialize_PCB"))
483 while (((pcb->name[i] = name[i]) != '\0') && (i < 31)) i++;
484 pcb->name[31] = '\0';
485 pcb->priority = priority;
486 pcb->stacksize = stacksize;
490 pcb->eventlist = (void**)malloc(EVINITSIZE*sizeof(void*));
491 pcb->eventlistsize = pcb->eventlist ? EVINITSIZE : 0;
495 pcb->next = pcb->prev = (PROCESS)NULL;
496 pcb->iomgrRequest = (struct IoRequest*)NULL;
497 pcb->index = lwp_nextindex ++;
501 static VOID WINAPI Enter_LWP(PVOID fiberData)
503 PROCESS pcb = (PROCESS)fiberData;
505 /* next lines are new..... */
508 Debug(2, ("Enter_LWP: pcb=0x%p, funP=0x%p, argP=0x%p\n", pcb, pcb->funP, pcb->argP))
510 (*pcb->funP)(pcb->argP);
512 LWP_DestroyProcess(pcb);
516 static void Abort_LWP(char *msg)
518 Debug(0, ("Entered Abort_LWP"))
519 printf("***LWP: %s\n",msg);
521 printf("***LWP: Abort --- dumping PCBs ...\n");
528 static void Dump_One_Process(PROCESS pid)
532 printf("***LWP: Process Control Block at 0x%p\n", pid);
533 printf("***LWP: Name: %s\n", pid->name);
534 if (pid->funP != NULL)
535 printf("***LWP: Initial entry point: 0x%p\n", pid->funP);
536 switch (pid->status) {
537 case READY: printf("READY"); break;
538 case WAITING: printf("WAITING"); break;
539 case DESTROYED: printf("DESTROYED"); break;
540 default: printf("unknown");
543 printf("***LWP: Priority: %d \tInitial parameter: 0x%p\n",
544 pid->priority, pid->argP);
545 if (pid->stacksize != 0) {
546 printf("***LWP: Stacksize: %d\n", pid->stacksize);
548 if (pid->eventcnt > 0) {
549 printf("***LWP: Number of events outstanding: %d\n", pid->waitcnt);
550 printf("***LWP: Event id list:");
551 for (i=0;i<pid->eventcnt;i++)
552 printf(" 0x%p", pid->eventlist[i]);
556 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
561 static void purge_dead_pcbs(void)
563 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
566 int LWP_TraceProcesses = 0;
568 static void Dispatcher(void)
572 static int dispatch_count = 0;
574 if (LWP_TraceProcesses > 0) {
575 for (i=0; i<MAX_PRIORITIES; i++) {
576 printf("[Priority %d, runnable (%d):", i, runnable[i].count);
577 for_all_elts(p, runnable[i], {
578 printf(" \"%s\"", p->name);
582 printf("[Blocked (%d):", blocked.count);
583 for_all_elts(p, blocked, {
584 printf(" \"%s\"", p->name);
589 /* Move head of current runnable queue forward if current LWP is still
592 if (lwp_cpptr != NULL && lwp_cpptr == runnable[lwp_cpptr->priority].head)
593 runnable[lwp_cpptr->priority].head =
594 runnable[lwp_cpptr->priority].head -> next;
595 /* Find highest priority with runnable processes. */
596 for (i=MAX_PRIORITIES-1; i>=0; i--)
597 if (runnable[i].head != NULL) break;
599 if (i < 0) Abort_LWP("No READY processes");
602 if (LWP_TraceProcesses > 0)
603 printf("Dispatch %d [PCB at 0x%p] \"%s\"\n", ++dispatch_count,
604 runnable[i].head, runnable[i].head->name);
607 lwp_cpptr = runnable[i].head;
608 SwitchToFiber(lwp_cpptr->fiber);
616 static void Exit_LWP(void)
622 static void Delete_PCB(PROCESS pid)
624 Debug(4, ("Entered Delete_PCB"))
625 lwp_remove(pid, (pid->status==WAITING || pid->status==DESTROYED
627 : &runnable[pid->priority]));
628 LWPANCHOR.processcnt--;
632 static void Free_PCB(PROCESS pid)
634 Debug(4, ("Entered Free_PCB"))
635 if (pid->fiber != NULL) {
636 DeleteFiber(pid->fiber);
638 if (pid->eventlist != NULL) free((void*)pid->eventlist);
642 static void Dispose_of_Dead_PCB(PROCESS cur)
644 Debug(4, ("Entered Dispose_of_Dead_PCB"))
649 /* Queue manipulation. */
650 static void lwp_remove(PROCESS p, struct QUEUE *q)
652 /* Special test for only element on queue */
656 /* Not only element, do normal remove */
657 p -> next -> prev = p -> prev;
658 p -> prev -> next = p -> next;
660 /* See if head pointing to this element */
661 if (q->head == p) q -> head = p -> next;
663 p -> next = p -> prev = NULL;
666 static void insert(PROCESS p, struct QUEUE *q)
668 if (q->head == NULL) { /* Queue is empty */
670 p -> next = p -> prev = p;
671 } else { /* Regular insert */
672 p -> prev = q -> head -> prev;
673 q -> head -> prev -> next = p;
674 q -> head -> prev = p;
675 p -> next = q -> head;
680 static void move(PROCESS p, struct QUEUE *from, struct QUEUE *to)
685 #endif /* AFS_NT40_ENV */