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>
26 #include <afs/afsutil.h>
30 static struct lwp_ctl
*lwp_init
;
31 #define LWPANCHOR (*lwp_init)
44 #define Debug(level, msg)\
45 if (lwp_debug && lwp_debug >= level) {\
46 printf("***LWP (0x%p): ", lwp_cpptr);\
52 #define Debug(level, msg)
56 /* Forward declarations */
57 static void Dispatcher(void);
58 static void Abort_LWP(char *msg
);
59 static VOID WINAPI
Enter_LWP(PVOID fiberData
);
60 static void Initialize_PCB(PROCESS pcb
, int priority
, int stacksize
,
61 int (*funP
)(), void *argP
, char *name
);
63 static void Dispose_of_Dead_PCB();
64 static void Free_PCB();
65 static int Internal_Signal();
66 static void purge_dead_pcbs(void);
68 static void lwp_remove(PROCESS p
, struct QUEUE
*q
);
69 static void insert(PROCESS p
, struct QUEUE
*q
);
70 static void move(PROCESS p
, struct QUEUE
*from
, struct QUEUE
*to
);
72 /* biggest LWP stack created so far - used by IOMGR */
73 int lwp_MaxStackSeen
= 0;
76 static void Dump_One_Process(PROCESS pid
);
77 static void Dump_Processes(void);
82 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
84 /* Invariant for runnable queues: The head of each queue points to the
85 * currently running process if it is in that queue, or it points to the
86 * next process in that queue that should run.
91 } runnable
[MAX_PRIORITIES
], blocked
;
94 #define for_all_elts(var, q, body)\
98 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
99 _NEXT_ = var -> next;\
106 LPVOID
ConvertThreadToFiber(PROCESS x
)
110 LPVOID
CreateFiber(DWORD x
,LPVOID y
,PROCESS z
)
115 VOID
SwitchToFiber(LPVOID p
)
119 VOID
DeleteFiber(LPVOID p
)
125 int lwp_MinStackSize
= 0;
127 /* LWP_InitializeProcessSupport - setup base support for fibers.
130 * priority - priority of main thread.
133 * pid - return this process
135 * LWP_SUCCESS (else aborts)
139 int LWP_InitializeProcessSupport(int priority
, PROCESS
*pid
)
145 Debug(0, ("Entered LWP_InitializeProcessSupport"))
146 if (lwp_init
!= NULL
) return LWP_SUCCESS
;
148 if (priority
>= MAX_PRIORITIES
) return LWP_EBADPRI
;
150 pcb
= malloc(sizeof(*pcb
));
152 Abort_LWP("Insufficient Storage to Initialize LWP PCB");
153 (void) memset((void*)pcb
, 0, sizeof(*pcb
));
154 pcb
->fiber
= ConvertThreadToFiber(pcb
);
156 Abort_LWP("Cannot convert main thread to LWP fiber");
158 lwp_init
= malloc(sizeof(struct lwp_ctl
));
159 if (lwp_init
== NULL
)
160 Abort_LWP("Insufficient Storage to Initialize LWP CTL");
161 (void) memset((void*)lwp_init
, 0, sizeof(struct lwp_ctl
));
163 for (i
=0; i
<MAX_PRIORITIES
; i
++) {
164 runnable
[i
].head
= NULL
;
165 runnable
[i
].count
= 0;
170 LWPANCHOR
.processcnt
= 1;
171 LWPANCHOR
.outerpid
= pcb
;
172 LWPANCHOR
.outersp
= NULL
;
175 Initialize_PCB(pcb
, priority
, 0, NULL
, NULL
,
176 "Main Process [created by LWP]");
179 Debug(10, ("Init: Insert 0x%p into runnable at priority %d\n", pcb
, priority
))
180 insert(pcb
, &runnable
[priority
]);
182 if ( ( value
= getenv("AFS_LWP_STACK_SIZE")) == NULL
)
183 lwp_MinStackSize
= AFS_LWP_MINSTACKSIZE
;
185 lwp_MinStackSize
= (AFS_LWP_MINSTACKSIZE
>atoi(value
)?
186 AFS_LWP_MINSTACKSIZE
: atoi(value
));
193 /* LWP_CreateProcess - create a new fiber and start executing it.
196 * funP - start function
197 * stacksize - size of
198 * priority - LWP priority
199 * argP - initial parameter for start function
203 * pid - handle of created LWP
206 * LWP_EINIT - error in intialization.
209 int LWP_CreateProcess(int (*funP
)(), int stacksize
, int priority
, void *argP
,
210 char *name
, PROCESS
*pid
)
216 pcb
= malloc(sizeof(*pcb
));
219 (void) memset((void*)pcb
, 0, sizeof(*pcb
));
222 * on some systems (e.g. hpux), a minimum usable stack size has
225 if (stacksize
< lwp_MinStackSize
) {
226 stacksize
= lwp_MinStackSize
;
228 /* more stack size computations; keep track of for IOMGR */
229 if (lwp_MaxStackSeen
< stacksize
)
230 lwp_MaxStackSeen
= stacksize
;
232 pcb
->fiber
= CreateFiber(stacksize
, Enter_LWP
, pcb
);
233 if (pcb
->fiber
== NULL
) {
237 Debug(0, ("Create: pcb=0x%p, funP=0x%p, argP=0x%p\n", pcb
, funP
, argP
))
238 /* Fiber is now created, so fill in PCB */
239 Initialize_PCB(pcb
, priority
, stacksize
, funP
, argP
, name
);
240 Debug(10, ("Create: Insert 0x%p into runnable at priority %d\n", pcb
, priority
))
241 insert(pcb
, &runnable
[priority
]);
243 LWPANCHOR
.processcnt
++;
245 /* And hand off execution. */
246 SwitchToFiber(pcb
->fiber
);
253 int LWP_DestroyProcess(PROCESS pid
)
255 Debug(0, ("Entered Destroy_Process"))
260 if (lwp_cpptr
!= pid
) {
261 Dispose_of_Dead_PCB(pid
);
263 pid
->status
= DESTROYED
;
264 move(pid
, &runnable
[pid
->priority
], &blocked
);
275 (tp
=lwp_cpptr
) -> status
= QWAITING
;
276 lwp_remove(tp
, &runnable
[tp
->priority
]);
281 int LWP_QSignal(PROCESS pid
)
283 if (pid
->status
== QWAITING
) {
285 Debug(10, ("QSignal: Insert 0x%p into runnable at priority %d\n", pid
, pid
->priority
))
286 insert(pid
, &runnable
[pid
->priority
]);
289 else return LWP_ENOWAIT
;
292 int LWP_CurrentProcess(PROCESS
*pid
)
294 Debug(0, ("Entered Current_Process"))
302 PROCESS
LWP_ThreadId()
304 Debug(0, ("Entered ThreadId"))
311 int LWP_DispatchProcess(void) /* explicit voluntary preemption */
313 Debug(2, ("Entered Dispatch_Process"))
323 static void Dump_Processes(void)
327 for (i
=0; i
<MAX_PRIORITIES
; i
++)
328 for_all_elts(x
, runnable
[i
], {
329 printf("[Priority %d]\n", i
);
332 for_all_elts(x
, blocked
, { Dump_One_Process(x
); })
334 printf("***LWP: LWP support not initialized\n");
339 int LWP_GetProcessPriority(pid
, priority
) /* returns process priority */
343 Debug(0, ("Entered Get_Process_Priority"))
345 *priority
= pid
->priority
;
351 static int Internal_Signal(char *event
)
353 int rc
= LWP_ENOWAIT
;
356 Debug(0, ("Entered Internal_Signal [event id 0x%p]", event
))
357 if (!lwp_init
) return LWP_EINIT
;
358 if (event
== NULL
) return LWP_EBADEVENT
;
359 for_all_elts(temp
, blocked
, {
360 if (temp
->status
== WAITING
)
361 for (i
=0; i
< temp
->eventcnt
; i
++) {
362 if (temp
-> eventlist
[i
] == event
) {
363 temp
-> eventlist
[i
] = NULL
;
365 Debug(0, ("Signal satisfied for PCB 0x%p", temp
))
366 if (--temp
->waitcnt
== 0) {
367 temp
-> status
= READY
;
368 temp
-> wakevent
= i
+1;
369 move(temp
, &blocked
, &runnable
[temp
->priority
]);
378 /* signal the occurence of an event */
379 int LWP_INTERNALSIGNAL(void *event
, int yield
)
381 Debug(2, ("Entered LWP_SignalProcess"))
384 rc
= Internal_Signal(event
);
392 int LWP_TerminateProcessSupport() /* terminate all LWP support */
396 Debug(0, ("Entered Terminate_Process_Support"))
397 if (lwp_init
== NULL
) return LWP_EINIT
;
398 if (lwp_cpptr
!= LWPANCHOR
.outerpid
)
399 Abort_LWP("Terminate_Process_Support invoked from wrong process!");
400 /* Is this safe??? @@@ */
401 for (i
=0; i
<MAX_PRIORITIES
; i
++)
402 for_all_elts(cur
, runnable
[i
], { Free_PCB(cur
); })
403 for_all_elts(cur
, blocked
, { Free_PCB(cur
); })
409 int LWP_MwaitProcess(int wcount
, void **evlist
)
413 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount
))
414 if (evlist
== NULL
) {
416 return LWP_EBADCOUNT
;
419 for (ecount
= 0; evlist
[ecount
] != NULL
; ecount
++) ;
423 return LWP_EBADCOUNT
;
429 if (wcount
>ecount
|| wcount
<0) {
431 return LWP_EBADCOUNT
;
433 if (ecount
> lwp_cpptr
->eventlistsize
) {
435 void **save_eventlist
= lwp_cpptr
->eventlist
;
436 lwp_cpptr
->eventlist
= realloc(lwp_cpptr
->eventlist
,
437 ecount
*sizeof(char *));
438 if (lwp_cpptr
->eventlist
== NULL
) {
439 lwp_cpptr
->eventlist
= save_eventlist
;
443 lwp_cpptr
->eventlistsize
= ecount
;
445 for (i
=0; i
<ecount
; i
++) lwp_cpptr
-> eventlist
[i
] = evlist
[i
];
447 lwp_cpptr
->status
= WAITING
;
449 move(lwp_cpptr
, &runnable
[lwp_cpptr
->priority
], &blocked
);
452 lwp_cpptr
->wakevent
= 0;
453 lwp_cpptr
->waitcnt
= wcount
;
454 lwp_cpptr
->eventcnt
= ecount
;
461 int LWP_WaitProcess(void *event
) /* wait on a single event */
465 Debug(2, ("Entered Wait_Process"))
466 if (event
== NULL
) return LWP_EBADEVENT
;
469 return LWP_MwaitProcess(1, tempev
);
473 /* Internal Support Routines */
474 static void Initialize_PCB(PROCESS pcb
, int priority
, int stacksize
,
475 int (*funP
)(), void *argP
, char *name
)
479 Debug(4, ("Entered Initialize_PCB"))
481 while (((pcb
->name
[i
] = name
[i
]) != '\0') && (i
< 31)) i
++;
482 pcb
->name
[31] = '\0';
483 pcb
->priority
= priority
;
484 pcb
->stacksize
= stacksize
;
488 pcb
->eventlist
= malloc(EVINITSIZE
*sizeof(void*));
489 pcb
->eventlistsize
= pcb
->eventlist
? EVINITSIZE
: 0;
493 pcb
->next
= pcb
->prev
= (PROCESS
)NULL
;
494 pcb
->iomgrRequest
= NULL
;
495 pcb
->index
= lwp_nextindex
++;
499 static VOID WINAPI
Enter_LWP(PVOID fiberData
)
501 PROCESS pcb
= (PROCESS
)fiberData
;
503 /* next lines are new..... */
506 Debug(2, ("Enter_LWP: pcb=0x%p, funP=0x%p, argP=0x%p\n", pcb
, pcb
->funP
, pcb
->argP
))
508 (*pcb
->funP
)(pcb
->argP
);
510 LWP_DestroyProcess(pcb
);
514 static void Abort_LWP(char *msg
)
516 Debug(0, ("Entered Abort_LWP"))
517 printf("***LWP: %s\n",msg
);
519 printf("***LWP: Abort --- dumping PCBs ...\n");
526 static void Dump_One_Process(PROCESS pid
)
530 printf("***LWP: Process Control Block at 0x%p\n", pid
);
531 printf("***LWP: Name: %s\n", pid
->name
);
532 if (pid
->funP
!= NULL
)
533 printf("***LWP: Initial entry point: 0x%p\n", pid
->funP
);
534 switch (pid
->status
) {
535 case READY
: printf("READY"); break;
536 case WAITING
: printf("WAITING"); break;
537 case DESTROYED
: printf("DESTROYED"); break;
538 default: printf("unknown");
541 printf("***LWP: Priority: %d \tInitial parameter: 0x%p\n",
542 pid
->priority
, pid
->argP
);
543 if (pid
->stacksize
!= 0) {
544 printf("***LWP: Stacksize: %d\n", pid
->stacksize
);
546 if (pid
->eventcnt
> 0) {
547 printf("***LWP: Number of events outstanding: %d\n", pid
->waitcnt
);
548 printf("***LWP: Event id list:");
549 for (i
=0;i
<pid
->eventcnt
;i
++)
550 printf(" 0x%p", pid
->eventlist
[i
]);
554 printf("***LWP: Number of last wakeup event: %d\n", pid
->wakevent
);
559 static void purge_dead_pcbs(void)
561 for_all_elts(cur
, blocked
, { if (cur
->status
== DESTROYED
) Dispose_of_Dead_PCB(cur
); })
564 int LWP_TraceProcesses
= 0;
566 static void Dispatcher(void)
570 static int dispatch_count
= 0;
572 if (LWP_TraceProcesses
> 0) {
573 for (i
=0; i
<MAX_PRIORITIES
; i
++) {
574 printf("[Priority %d, runnable (%d):", i
, runnable
[i
].count
);
575 for_all_elts(p
, runnable
[i
], {
576 printf(" \"%s\"", p
->name
);
580 printf("[Blocked (%d):", blocked
.count
);
581 for_all_elts(p
, blocked
, {
582 printf(" \"%s\"", p
->name
);
587 /* Move head of current runnable queue forward if current LWP is still
590 if (lwp_cpptr
!= NULL
&& lwp_cpptr
== runnable
[lwp_cpptr
->priority
].head
)
591 runnable
[lwp_cpptr
->priority
].head
=
592 runnable
[lwp_cpptr
->priority
].head
-> next
;
593 /* Find highest priority with runnable processes. */
594 for (i
=MAX_PRIORITIES
-1; i
>=0; i
--)
595 if (runnable
[i
].head
!= NULL
) break;
597 if (i
< 0) Abort_LWP("No READY processes");
600 if (LWP_TraceProcesses
> 0)
601 printf("Dispatch %d [PCB at 0x%p] \"%s\"\n", ++dispatch_count
,
602 runnable
[i
].head
, runnable
[i
].head
->name
);
605 lwp_cpptr
= runnable
[i
].head
;
606 SwitchToFiber(lwp_cpptr
->fiber
);
609 static void Delete_PCB(PROCESS pid
)
611 Debug(4, ("Entered Delete_PCB"))
612 lwp_remove(pid
, (pid
->status
==WAITING
|| pid
->status
==DESTROYED
614 : &runnable
[pid
->priority
]));
615 LWPANCHOR
.processcnt
--;
619 static void Free_PCB(PROCESS pid
)
621 Debug(4, ("Entered Free_PCB"))
622 if (pid
->fiber
!= NULL
) {
623 DeleteFiber(pid
->fiber
);
625 if (pid
->eventlist
!= NULL
) free(pid
->eventlist
);
629 static void Dispose_of_Dead_PCB(PROCESS cur
)
631 Debug(4, ("Entered Dispose_of_Dead_PCB"))
636 /* Queue manipulation. */
637 static void lwp_remove(PROCESS p
, struct QUEUE
*q
)
639 /* Special test for only element on queue */
643 /* Not only element, do normal remove */
644 p
-> next
-> prev
= p
-> prev
;
645 p
-> prev
-> next
= p
-> next
;
647 /* See if head pointing to this element */
648 if (q
->head
== p
) q
-> head
= p
-> next
;
650 p
-> next
= p
-> prev
= NULL
;
653 static void insert(PROCESS p
, struct QUEUE
*q
)
655 if (q
->head
== NULL
) { /* Queue is empty */
657 p
-> next
= p
-> prev
= p
;
658 } else { /* Regular insert */
659 p
-> prev
= q
-> head
-> prev
;
660 q
-> head
-> prev
-> next
= p
;
661 q
-> head
-> prev
= p
;
662 p
-> next
= q
-> head
;
667 static void move(PROCESS p
, struct QUEUE
*from
, struct QUEUE
*to
)
672 #endif /* AFS_NT40_ENV */