1 /* This version of the code is derived from the Coda version of the LWP
2 * library, which can be compiled as a wrapper around Mach cthreads
4 * Windows Threads support was added by Love <lha@stacken.kth.se>
5 * and debugged by Magnus <map@stacken.kth.se> and Robert <rb@abc.se>.
6 * It provides a glue layer around the windows primitives to make
7 * it look like pthreads.
10 ****************************************************************************
11 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
13 * Permission to use, copy, modify, and distribute this software and its *
14 * documentation for any purpose and without fee is hereby granted, *
15 * provided that the above copyright notice appear in all copies and *
16 * that both that copyright notice and this permission notice appear in *
17 * supporting documentation, and that the name of IBM not be used in *
18 * advertising or publicity pertaining to distribution of the software *
19 * without specific, written prior permission. *
21 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
23 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
24 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
25 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
26 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
27 ****************************************************************************
39 /* allocate externs here */
49 #include <sys/errno.h>
57 #define MAX(a,b) (((a)>(b))?(a):(b))
69 #define Debug(level, msg) \
71 if (lwp_debug && lwp_debug >= level) { \
72 printf("***LWP(max=%d) (%p): ", \
73 Highest_runnable_priority, lwp_cpptr); \
80 #define Debug(level, msg) do {} while (0)
83 #define lwp_timerclear(t) (t)->tv_sec = (t)->tv_usec = 0
86 static void Abort_LWP(char *msg
, ...) ;
87 static void Dispatcher(void);
88 static void Create_Process_Part2(PROCESS temp
);
89 static void purge_dead_pcbs(void) ;
90 static void Dispose_of_Dead_PCB (PROCESS cur
) ;
91 static void Free_PCB(PROCESS pid
) ;
92 static void Exit_LWP();
93 static void Initialize_PCB(PROCESS temp
, int priority
, char *stack
,
94 int stacksize
, void (*ep
)() , char *parm
,
96 static int Internal_Signal(char *event
) ;
97 char (*RC_to_ASCII());
99 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
104 } runnable
[MAX_PRIORITIES
], blocked
;
106 * Invariant for runnable queues: The head of each queue points to the
107 * currently running process if it is in that queue, or it points to the
108 * next process in that queue that should run.
111 /* special user-tweakable option for AIX */
112 int lwp_MaxStackSize
= 32768;
113 int lwp_MaxStackSeen
= 0;
115 int lwp_nextindex
= 0;
118 #define for_all_elts(var, q, body)\
120 PROCESS var, _NEXT_;\
122 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
123 _NEXT_ = var -> next;\
128 static struct lwp_ctl
*lwp_init
= NULL
;
130 static void Dump_One_Process(PROCESS pid
);
131 static void Dump_Processes();
132 static void Delete_PCB(PROCESS pid
);
133 static void Free_PCB(PROCESS pid
);
134 static void Cal_Highest_runnable_priority(void);
135 static int InitializeProcessSupport(int, PROCESS
*);
139 /* The global Highest_runnable_priority is only needed in NEW lwp.
140 But it gets set within a for_all_elts() instance in
142 int Highest_runnable_priority
; /* global variable for max priority */
144 int Proc_Running
; /* indicates forked proc got control */
150 #if defined(PTHREADS_LWP)
151 pthread_mutex_t run_sem
, ct_mutex
;
153 #define LWP_INT_LOCK(sem) pthread_mutex_lock(sem)
154 #define LWP_INT_UNLOCK(sem) pthread_mutex_unlock(sem)
156 #define LWP_INT_WAIT(cond, mutex) pthread_cond_wait(cond, mutex)
157 #define LWP_INT_SIGNAL(cond) pthread_cond_signal(cond)
159 #define LWP_INT_EXIT(t) pthread_exit(t)
161 #elif defined(WINDOWS_THREADS_LWP)
163 HANDLE run_sem
, ct_mutex
;
166 #define LWP_INT_LOCK(sem) WaitForSingleObject (sem, INFINITE)
167 #define LWP_INT_UNLOCK(sem) ReleaseMutex (sem)
171 DWORD
LWP_INT_LOCK(HANDLE
*sem
)
174 Debug(0, ("LWP_INT_LOCK: sem = %p", *sem
));
175 ret
= WaitForSingleObject(*sem
, INFINITE
);
176 if (ret
== WAIT_FAILED
) {
177 DWORD err
= GetLastError();
178 Debug(0, ("LWP_INT_LOCK: h = %p, wait = %ld, %ld\n",
181 Debug(0, ("LWP_INT_LOCK: got %p", *sem
));
185 static DWORD
LWP_INT_UNLOCK(HANDLE
*sem
)
188 Debug(0, ("LWP_INT_UNLOCK: sem = %p", *sem
));
189 ret
= ReleaseMutex(*sem
);
191 DWORD err
= GetLastError();
192 Debug(0, ("LWP_INT_UNLOCK: h = %p, wait = %ld, %ld\n",
195 Debug(0, ("LWP_INT_UNLOCK: %p released", *sem
));
199 static DWORD
LWP_INT_WAIT(HANDLE
*cond
, HANDLE
*mutex
)
202 static int times
= 0;
203 int this_time
= times
++;
205 Debug(0, ("LWP_INT_WAIT(%d): cond: %p mutex: %p",
206 this_time
, *cond
, *mutex
));
207 ret
= ReleaseMutex (*mutex
);
209 DWORD err
= GetLastError();
210 Debug(0, ("LWP_INT_WAIT(%d): ReleaseMutex failed: %ld error: "
211 "%ld mutex\n", this_time
, err
, *mutex
));
214 Debug(0, ("LWP_INT_WAIT(%d): mutex released, waiting", this_time
));
215 ret
= WaitForSingleObject (*cond
, INFINITE
);
216 if (ret
!= WAIT_OBJECT_0
) {
217 Debug(0, ("LWP_INT_WAIT(%d): WaitForSingleObject(cond) failed: "
218 "%ld mutex: %p\n", this_time
, ret
, *mutex
));
221 Debug(0, ("LWP_INT_WAIT(%d): got sem, waiting for mutex", this_time
));
222 ret
= WaitForSingleObject (*mutex
, INFINITE
);
223 if (ret
!= WAIT_OBJECT_0
) {
224 Debug(0, ("LWP_INT_WAIT(%d): WaitForSingleObject(mutex) failed: "
225 "%ld mutex: %p\n", this_time
, ret
, *mutex
));
228 Debug(0, ("LWP_INT_WAIT(%d): got mutex: cond: %p mutex: %p",
229 this_time
, *cond
, *mutex
));
233 #define LWP_INT_SIGNAL(cond) do { \
234 Debug(0, ("LWP_INT_SIGNAL: cond: %p\n", *cond)); \
235 SetEvent (*cond); } while (0)
238 #define LWP_INT_EXIT(t) ExitThread ((int)t); /* XXX */
243 lwpremove(PROCESS p
, struct QUEUE
*q
)
245 /* Special test for only element on queue */
249 /* Not only element, do normal remove */
250 p
-> next
-> prev
= p
-> prev
;
251 p
-> prev
-> next
= p
-> next
;
253 /* See if head pointing to this element */
254 if (q
->head
== p
) q
-> head
= p
-> next
;
256 Debug(0, ("removing, count now %d", q
->count
));
257 p
-> next
= p
-> prev
= NULL
;
261 lwpinsert(PROCESS p
, struct QUEUE
*q
)
263 if (q
->head
== NULL
) { /* Queue is empty */
265 p
-> next
= p
-> prev
= p
;
266 } else { /* Regular insert */
267 p
-> prev
= q
-> head
-> prev
;
268 q
-> head
-> prev
-> next
= p
;
269 q
-> head
-> prev
= p
;
270 p
-> next
= q
-> head
;
273 Debug(0, ("inserting, count now %d", q
->count
));
277 lwpmove(PROCESS p
, struct QUEUE
*from
, struct QUEUE
*to
)
284 LWP_TerminateProcessSupport() /* terminate all LWP support */
288 Debug(0, ("Entered Terminate_Process_Support"));
289 if (lwp_init
== NULL
)
291 /* free all space allocated */
292 for (i
=0; i
<MAX_PRIORITIES
; i
++)
293 for_all_elts(cur
, runnable
[i
], { Free_PCB(cur
);});
294 for_all_elts(cur
, blocked
, { Free_PCB(cur
);});
295 free((char *)lwp_init
);
301 LWP_GetRock(int Tag
, char **Value
)
303 /* Obtains the pointer Value associated with the rock Tag of this LWP.
305 LWP_SUCCESS if specified rock exists and Value has been filled
306 LWP_EBADROCK rock specified does not exist
311 ra
= lwp_cpptr
->rlist
;
313 for (i
= 0; i
< lwp_cpptr
->rused
; i
++)
314 if (ra
[i
].tag
== Tag
) {
316 #ifdef PTHREAD_GETSPECIFIC_TWOARG
317 pthread_getspecific(ra
[i
].val
, Value
);
319 *Value
= pthread_getspecific(ra
[i
].val
);
321 #elif WINDOWS_THREADS_LWP
322 *Value
= TlsGetValue((unsigned long) ra
[i
].val
);
327 return(LWP_EBADROCK
);
332 LWP_NewRock(int Tag
, char *Value
)
334 /* Finds a free rock and sets its value to Value.
336 LWP_SUCCESS Rock did not exist and a new one was used
337 LWP_EBADROCK Rock already exists.
338 LWP_ENOROCKS All rocks are in use.
340 From the above semantics, you can only set a rock value once.
341 This is specifically to prevent multiple users of the LWP
342 package from accidentally using the same Tag value and
343 clobbering others. You can always use one level of
344 indirection to obtain a rock whose contents can change. */
347 struct rock
*ra
; /* rock array */
349 ra
= lwp_cpptr
->rlist
;
351 /* check if rock has been used before */
352 for (i
= 0; i
< lwp_cpptr
->rused
; i
++)
353 if (ra
[i
].tag
== Tag
) return(LWP_EBADROCK
);
355 /* insert new rock in rock list and increment count of rocks */
356 if (lwp_cpptr
->rused
< MAXROCKS
) {
357 ra
[lwp_cpptr
->rused
].tag
= Tag
;
359 #ifdef HAVE_PTHREAD_KEYCREATE
360 if (pthread_keycreate(&ra
[lwp_cpptr
->rused
].val
, NULL
))
362 if (pthread_key_create(&ra
[lwp_cpptr
->rused
].val
, NULL
))
364 return(LWP_EBADROCK
);
365 if (pthread_setspecific(ra
[lwp_cpptr
->rused
].val
, Value
))
366 return(LWP_EBADROCK
);
368 #elif WINDOWS_THREADS_LWP
369 ra
[lwp_cpptr
->rused
].val
= (LPVOID
) TlsAlloc();
370 if (ra
[lwp_cpptr
->rused
].val
== (LPVOID
) 0xFFFFFFFF)
371 return(LWP_EBADROCK
);
372 if (!TlsSetValue((unsigned long) ra
[lwp_cpptr
->rused
].val
, Value
))
373 return(LWP_EBADROCK
);
379 else return(LWP_ENOROCKS
);
383 Dispose_of_Dead_PCB(PROCESS cur
)
386 Debug(0, ("Entered Dispose_of_Dead_PCB"));
392 LWP_CurrentProcess(PROCESS
*pid
)
394 Debug(0, ("Entered Current_Process"));
404 LWP_GetProcessPriority(PROCESS pid
, int *priority
)
406 Debug(0, ("Entered Get_Process_Priority"));
408 *priority
= pid
-> priority
;
415 LWP_WaitProcess(void *event
)
419 Debug(0, ("Entered Wait_Process"));
420 if (event
== NULL
) return LWP_EBADEVENT
;
423 return LWP_MwaitProcess(1, tempev
);
427 Delete_PCB(PROCESS pid
)
429 Debug(0, ("Entered Delete_PCB"));
430 lwpremove(pid
, (pid
->blockflag
|| pid
->status
==WAITING
||
431 pid
->status
==DESTROYED
? &blocked
432 : &runnable
[pid
->priority
]));
438 for_all_elts(cur
, blocked
, { if (cur
->status
== DESTROYED
)
439 Dispose_of_Dead_PCB(cur
); });
453 for (i
=0; i
<MAX_PRIORITIES
; i
++)
454 for_all_elts(x
, runnable
[i
], {
455 printf("[Priority %d]\n", i
);
458 for_all_elts(x
, blocked
, { Dump_One_Process(x
); });
460 printf("***LWP: LWP support not initialized\n");
467 return(lwp_cpptr
->name
);
473 return(lwp_cpptr
->index
);
479 return(lwp_nextindex
-1);
482 /* A process calls this routine to wait until somebody signals it.
483 * LWP_QWait removes the calling process from the runnable queue
484 * and makes the process sleep until some other process signals via LWP_QSignal
491 Debug(0, ("LWP_QWait: %s is going to QWait", lwp_cpptr
->name
));
492 lwp_cpptr
->status
= QWAITING
;
493 if (runnable
[lwp_cpptr
->priority
].count
== 0)
494 Cal_Highest_runnable_priority();
496 old_cpptr
= lwp_cpptr
;
498 /* wake up next lwp */
499 lwp_cpptr
= runnable
[Highest_runnable_priority
].head
;
500 lwpremove(lwp_cpptr
, &runnable
[Highest_runnable_priority
]);
501 lwp_timerclear(&lwp_cpptr
->lastReady
);
502 LWP_INT_LOCK(&ct_mutex
);
503 Debug(0, ("LWP_QWait:%s going to wake up %s", old_cpptr
->name
,
505 LWP_INT_SIGNAL(&lwp_cpptr
->c
);
507 /* sleep on your own condition */
508 Debug(0, ("LWP_QWait:%s going to wait on own condition",
510 LWP_INT_WAIT(&old_cpptr
->c
, &ct_mutex
);
511 LWP_INT_UNLOCK(&ct_mutex
);
512 Debug(0, ("LWP_QWait:%s woke up",
515 lwp_cpptr
= old_cpptr
;
517 /* return only if calling process' priority is the highest */
518 if (lwp_cpptr
->priority
< Highest_runnable_priority
)
524 /* signal the PROCESS pid - by adding it to the runnable queue */
526 LWP_QSignal(PROCESS pid
)
528 if (pid
->status
== QWAITING
) {
529 Debug(0, ("LWP_Qsignal: %s is going to QSignal %s\n", lwp_cpptr
->name
,
532 lwpinsert(pid
, &runnable
[pid
->priority
]);
533 Debug(0, ("LWP_QSignal: Just inserted %s into runnable queue\n",
535 gettimeofday(&pid
->lastReady
, 0);
536 Highest_runnable_priority
=
537 MAX(Highest_runnable_priority
, pid
->priority
);
538 Debug(0, ("%s priority= %d; HRP = %d; Signalled process pri = %d",
539 lwp_cpptr
->name
, lwp_cpptr
->priority
,
540 Highest_runnable_priority
, pid
->priority
));
543 else return LWP_ENOWAIT
;
548 LWP_CreateProcess(void (*ep
)(), int stacksize
, int priority
,
549 char *parm
, char *name
, PROCESS
*pid
)
552 #if defined(PTHREADS_LWP)
556 #elif defined(WINDOWS_THREADS_LWP)
561 Debug(0, ("Entered LWP_CreateProcess to create %s at priority %d\n",
564 if (stacksize
< AFS_LWP_MINSTACKSIZE
)
565 stacksize
= AFS_LWP_MINSTACKSIZE
;
567 old_cpptr
= lwp_cpptr
;
568 /* Throw away all dead process control blocks */
571 if (lwp_init
== NULL
)
574 /* allocate the memory for the pcb - check for malloc errors */
575 temp
= (PROCESS
)malloc (sizeof (struct lwp_pcb
));
581 /* check priorities */
582 if (priority
< 0 || priority
>= MAX_PRIORITIES
) {
587 Initialize_PCB(temp
, priority
, NULL
, 0, ep
, parm
, name
);
589 /* make the process runnable by placing it in the runnable q */
590 lwpinsert(temp
, &runnable
[priority
]);
591 gettimeofday(&temp
->lastReady
, 0);
594 Abort_LWP("PRE_Block not 0");
597 Proc_Running
= FALSE
; /* sem set true by forked process */
599 #if defined(PTHREADS_LWP)
600 pthread_attr_init(&cta
);
601 #ifdef _POSIX_THREAD_ATTR_STACKSIZE
602 pthread_attr_setstacksize(&cta
, stacksize
);
604 retval
= pthread_create(&ct
, &cta
, (void *)Create_Process_Part2
, temp
);
606 Abort_LWP("pthread_create failed to create thread %d/%d",
611 #elif defined(WINDOWS_THREADS_LWP)
612 Debug(0,("Before CreateThread Create_Process_Part2"));
613 ct
= CreateThread (NULL
,
614 stacksize
, (LPTHREAD_START_ROUTINE
)Create_Process_Part2
,
616 Debug(0,("After CreateThread Create_Process_Part2"));
618 Abort_LWP("CreateThread failed to create thread: %d",
619 (int)GetLastError());
623 /* check if max priority has changed */
624 Highest_runnable_priority
= MAX(Highest_runnable_priority
, priority
);
626 LWP_INT_LOCK(&run_sem
);
627 Debug(0, ("Before creating process yields Proc_Running = %d\n",
629 while( !Proc_Running
){
630 LWP_INT_UNLOCK(&run_sem
);
631 #if defined(PTHREADS_LWP)
632 #if defined(HAVE_THR_YIELD)
634 #elif defined(HAVE_SCHED_YIELD)
639 #elif defined(WINDOWS_THREADS_LWP)
642 LWP_INT_LOCK(&run_sem
);
643 Debug(0,("After creating proc yields and gets back control Proc_Running = %d\n",
646 LWP_INT_UNLOCK(&run_sem
);
648 lwp_cpptr
= old_cpptr
;
656 LWP_DestroyProcess(PROCESS pid
)
660 Debug(0, ("Entered Destroy_Process"));
662 #if defined(PTHREADS_LWP)
663 pthread_attr_destroy(&pid
->a
);
664 #elif defined(WINDOWS_THREADS_LWP)
665 CloseHandle (pid
->t
);
667 if (lwp_cpptr
== pid
){
669 pid
->status
= DESTROYED
;
671 Cal_Highest_runnable_priority();
673 /* Calculate next runnable lwp and signal it */
674 lwp_cpptr
= runnable
[Highest_runnable_priority
].head
;
675 lwpremove(lwp_cpptr
, &runnable
[Highest_runnable_priority
]);
677 LWP_INT_LOCK(&ct_mutex
);
678 LWP_INT_SIGNAL(&lwp_cpptr
->c
);
679 LWP_INT_UNLOCK(&ct_mutex
);
682 /* kill some other process - mark status destroyed -
683 if process is blocked, it will be purged on next create proc;
684 if it is runnable the dispatcher will kill it */
685 pid
->status
= DESTROYED
;
694 LWP_DispatchProcess() /* explicit voluntary preemption */
696 Debug(0, ("Entered Dispatch_Process"));
706 LWP_Init(int version
, int priority
, PROCESS
*pid
)
709 if (version
!= LWP_VERSION
)
711 fprintf(stderr
, "**** FATAL ERROR: LWP VERSION MISMATCH ****\n");
714 else return(InitializeProcessSupport(priority
, pid
));
718 LWP_InitializeProcessSupport(int priority
, PROCESS
*pid
)
720 return(InitializeProcessSupport(priority
, pid
));
724 InitializeProcessSupport(int priority
, PROCESS
*pid
)
729 Debug(0, ("Entered InitializeProcessSupport"));
730 if (lwp_init
!= NULL
)
733 /* check priorities and set up running and blocked queues */
734 if (priority
>= MAX_PRIORITIES
) return LWP_EBADPRI
;
735 for (i
=0; i
<MAX_PRIORITIES
; i
++) {
736 runnable
[i
].head
= NULL
;
737 runnable
[i
].count
= 0;
741 lwp_init
= (struct lwp_ctl
*) malloc(sizeof(struct lwp_ctl
));
742 temp
= (PROCESS
) malloc(sizeof(struct lwp_pcb
));
743 if (lwp_init
== NULL
|| temp
== NULL
)
744 Abort_LWP("Insufficient Storage to Initialize LWP Support");
746 /* check parameters */
747 Initialize_PCB(temp
, priority
, NULL
, 0, NULL
, NULL
,"Main Process");
748 gettimeofday(&temp
->lastReady
, 0);
751 Highest_runnable_priority
= priority
;
754 /* initialize mutex and semaphore */
756 #if defined(PTHREADS_LWP)
757 pthread_mutex_init(&run_sem
, NULL
);
758 pthread_mutex_init(&ct_mutex
, NULL
);
759 #elif defined(WINDOWS_THREADS_LWP)
760 run_sem
= CreateMutex (NULL
, FALSE
, "run_sem");
761 if (run_sem
== NULL
) abort();
762 ct_mutex
= CreateMutex (NULL
, FALSE
, "ct_mutex");
763 if (ct_mutex
== NULL
) abort();
772 LWP_INTERNALSIGNAL(void *event
, int yield
)
774 Debug(0, ("Entered LWP_SignalProcess, yield=%d", yield
));
777 rc
= Internal_Signal(event
);
779 Cal_Highest_runnable_priority();
780 Debug(0, ("hipri=%d", Highest_runnable_priority
));
789 LWP_MwaitProcess(int wcount
, char *evlist
[]) /* wait on m of n events */
794 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount
));
795 if (evlist
== NULL
) {
797 return LWP_EBADCOUNT
;
800 /* count # of events in eventlist */
801 for (ecount
= 0; evlist
[ecount
] != NULL
; ecount
++) ;
804 return LWP_EBADCOUNT
;
808 /* check for illegal counts */
809 if (wcount
>ecount
|| wcount
<0) {
811 return LWP_EBADCOUNT
;
814 /* reallocate eventlist if new list has more elements than before */
815 if (ecount
> lwp_cpptr
->eventlistsize
) {
816 lwp_cpptr
->eventlist
=
817 (char **)realloc((char *)lwp_cpptr
->eventlist
,
818 ecount
*sizeof(char *));
819 lwp_cpptr
->eventlistsize
= ecount
;
822 /* place events in eventlist of the pcb */
823 for (i
=0; i
<ecount
; i
++) lwp_cpptr
-> eventlist
[i
] = evlist
[i
];
825 /* if there are any events to wait on then set status to
826 WAITING and place the pcb in blocked queue */
828 lwp_cpptr
-> status
= WAITING
;
829 lwpinsert(lwp_cpptr
, &blocked
);
831 lwp_cpptr
-> wakevent
= 0; /* index of eventid causing wakeup */
832 lwp_cpptr
-> waitcnt
= wcount
;
833 lwp_cpptr
-> eventcnt
= ecount
;
834 if (runnable
[lwp_cpptr
->priority
].count
== 0)
835 Cal_Highest_runnable_priority();
836 old_cpptr
= lwp_cpptr
;
838 /* wake up next lwp */
839 lwp_cpptr
= runnable
[Highest_runnable_priority
].head
;
840 lwpremove(lwp_cpptr
, &runnable
[Highest_runnable_priority
]);
841 lwp_timerclear(&lwp_cpptr
->lastReady
);
842 Debug(0, ("WaitProcess: %s Going to signal %s \n",
843 old_cpptr
->name
, lwp_cpptr
->name
));
844 LWP_INT_LOCK(&ct_mutex
);
845 LWP_INT_SIGNAL(&lwp_cpptr
->c
);
847 /* sleep on your own condition */
848 Debug(0, ("WaitProcess:%s going to wait \n", old_cpptr
->name
));
850 LWP_INT_WAIT(&old_cpptr
->c
, &ct_mutex
);
851 LWP_INT_UNLOCK(&ct_mutex
);
852 Debug(0, ("WaitProcess:%s woke up \n", old_cpptr
->name
));
854 /* update the global pointer */
855 lwp_cpptr
= old_cpptr
;
857 if (lwp_cpptr
->priority
< Highest_runnable_priority
)
866 LWP_StackUsed(PROCESS pid
, int *max
, int *used
)
868 /* just here for compatibility */
875 Abort_LWP(char *msg
, ...)
879 Debug(0, ("Entered Abort_LWP"));
881 printf("***LWP Abort ");
889 Create_Process_Part2(PROCESS temp
)
891 /* set the global Proc_Running to signal the parent */
892 LWP_INT_LOCK(&run_sem
);
894 LWP_INT_UNLOCK(&run_sem
);
896 LWP_INT_LOCK(&ct_mutex
);
897 LWP_INT_WAIT(&temp
->c
, &ct_mutex
);
898 LWP_INT_UNLOCK(&ct_mutex
);
902 (*temp
->ep
)(temp
->parm
);
903 LWP_DestroyProcess(temp
);
907 Dump_One_Process(PROCESS pid
)
911 printf("***LWP: Process Control Block at 0x%x\n", (int)pid
);
912 printf("***LWP: Name: %s\n", pid
->name
);
914 printf("***LWP: Initial entry point: 0x%x\n", (int)pid
->ep
);
915 if (pid
->blockflag
) printf("BLOCKED and ");
916 switch (pid
->status
) {
917 case READY
: printf("READY"); break;
918 case WAITING
: printf("WAITING"); break;
919 case DESTROYED
: printf("DESTROYED"); break;
920 default: printf("unknown");
923 printf("***LWP: Priority: %d \tInitial parameter: 0x%x\n",
924 pid
->priority
, (int)pid
->parm
);
926 if (pid
->eventcnt
> 0) {
927 printf("***LWP: Number of events outstanding: %d\n", pid
->waitcnt
);
928 printf("***LWP: Event id list:");
929 for (i
=0;i
<pid
->eventcnt
;i
++)
930 printf(" 0x%x", (int)pid
->eventlist
[i
]);
934 printf("***LWP: Number of last wakeup event: %d\n", pid
->wakevent
);
938 Dispatcher() /* Lightweight process dispatcher */
946 int i
= Highest_runnable_priority
;
948 Cal_Highest_runnable_priority();
949 if (Highest_runnable_priority
!= i
) {
950 printf("hipri was %d actually %d\n", i
, Highest_runnable_priority
);
955 Highest_runnable_priority
= i
;
957 my_priority
= lwp_cpptr
->priority
;
958 Debug(0, ("Dispatcher: %d runnable at pri %d hi %d blk %d",
959 runnable
[my_priority
].count
, my_priority
,
960 Highest_runnable_priority
, PRE_Block
));
962 if ((my_priority
< Highest_runnable_priority
) ||
963 (runnable
[my_priority
].count
> 0))
965 Debug(0, ("Dispatcher: %s is now yielding", lwp_cpptr
->name
));
967 old_cpptr
= lwp_cpptr
;
968 lwpinsert(old_cpptr
, &runnable
[my_priority
]);
969 gettimeofday(&old_cpptr
->lastReady
, 0);
970 lwp_cpptr
= runnable
[Highest_runnable_priority
].head
;
972 /* remove next process from runnable queue and signal it */
973 lwpremove(lwp_cpptr
, &runnable
[Highest_runnable_priority
]);
974 LWP_INT_LOCK(&ct_mutex
);
975 Debug(0, ("Dispatcher: %s going to signal %s condition",
976 old_cpptr
->name
, lwp_cpptr
->name
));
978 LWP_INT_SIGNAL(&lwp_cpptr
->c
);
980 /* now sleep until somebody wakes me */
981 Debug(0, ("Dispatcher: %s going to wait on own condition",
983 LWP_INT_WAIT(&old_cpptr
->c
, &ct_mutex
);
984 LWP_INT_UNLOCK(&ct_mutex
);
985 Debug(0, ("Dispatcher: %s woke up",
988 /* update global pointer */
989 lwp_cpptr
= old_cpptr
;
991 Debug(0, ("Dispatcher: %s still running", lwp_cpptr
->name
));
993 /* make sure HRP is set correct */
994 Highest_runnable_priority
= lwp_cpptr
->priority
;
995 if (lwp_cpptr
->status
== DESTROYED
){
996 /* the process was runnable but got destroyed by somebody */
998 Cal_Highest_runnable_priority();
999 lwp_cpptr
= runnable
[Highest_runnable_priority
].head
;
1000 lwpremove(lwp_cpptr
, &runnable
[Highest_runnable_priority
]);
1002 LWP_INT_LOCK(&ct_mutex
);
1003 LWP_INT_SIGNAL(&lwp_cpptr
->c
);
1004 LWP_INT_UNLOCK(&ct_mutex
);
1008 if (PRE_Block
!= 1) Abort_LWP("PRE_Block not 1");
1015 Free_PCB(PROCESS pid
)
1017 Debug(0, ("Entered Free_PCB"));
1019 if (pid
->eventlist
!= NULL
)
1020 free((char *)pid
->eventlist
);
1025 Initialize_PCB(PROCESS temp
, int priority
, char *stack
, int stacksize
,
1026 void (*ep
)(), char *parm
, char *name
)
1030 Debug(0, ("Entered Initialize_PCB"));
1032 while (((temp
-> name
[i
] = name
[i
]) != '\0') && (i
< 31))
1034 temp
-> name
[31] = '\0';
1035 temp
-> status
= READY
;
1036 temp
-> eventlist
= (char **)malloc(EVINITSIZE
*sizeof(char *));
1037 temp
-> eventlistsize
= EVINITSIZE
;
1038 temp
-> eventcnt
= 0;
1039 temp
-> wakevent
= 0;
1040 temp
-> waitcnt
= 0;
1041 temp
-> blockflag
= 0;
1042 temp
-> iomgrRequest
= 0;
1043 temp
-> priority
= priority
;
1044 temp
-> index
= lwp_nextindex
++;
1046 temp
-> parm
= parm
;
1047 temp
-> misc
= NULL
; /* currently unused */
1048 temp
-> next
= NULL
;
1049 temp
-> prev
= NULL
;
1051 temp
-> level
= 1; /* non-preemptable */
1052 temp
-> stacksize
= stacksize
;
1053 lwp_timerclear(&temp
->lastReady
);
1055 /* initialize the mutex and condition */
1056 #if defined(PTHREADS_LWP)
1057 pthread_mutex_init(&temp
->m
, NULL
);
1058 pthread_cond_init(&temp
->c
, NULL
);
1059 #elif defined(WINDOWS_THREADS_LWP)
1060 temp
->m
= CreateMutex (NULL
, FALSE
, NULL
);
1061 if (temp
->m
== NULL
) abort();
1062 temp
->c
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
1063 if (temp
->c
== NULL
) abort();
1064 Debug(0, ("Init_PCB: event = %p\n", temp
->c
));
1067 Debug(0, ("Leaving Initialize_PCB\n"));
1071 Internal_Signal(char *event
)
1073 int rc
= LWP_ENOWAIT
;
1076 Debug(0, ("Entered Internal_Signal [event id 0x%x]", (int)event
));
1077 if (lwp_init
== NULL
)
1080 return LWP_EBADEVENT
;
1082 for_all_elts(temp
, blocked
, { /* for all pcb's on the blocked q */
1083 if (temp
->status
== WAITING
)
1084 for (i
=0; i
< temp
->eventcnt
; i
++) { /* check each event in list */
1085 if (temp
-> eventlist
[i
] == event
) {
1086 temp
-> eventlist
[i
] = NULL
;
1088 Debug(0, ("decrementing %s to %d", temp
->name
,
1089 (temp
->waitcnt
-1)));
1090 /* reduce waitcnt by 1 for the signal */
1091 /* if wcount reaches 0 then make the process runnable */
1092 if (--temp
->waitcnt
== 0) {
1093 temp
-> status
= READY
;
1094 temp
-> wakevent
= i
+1;
1095 lwpmove(temp
, &blocked
, &runnable
[temp
->priority
]);
1096 gettimeofday(&temp
->lastReady
, 0);
1097 Highest_runnable_priority
=
1098 MAX(Highest_runnable_priority
, temp
->priority
);
1099 Debug(0, ("marked runnable. hi_pri %d, %d at %d",
1100 Highest_runnable_priority
,
1101 runnable
[temp
->priority
].count
,
1111 /* places the maximum of runnable task priorities in the global variable -
1112 * Highest_runnable_priority. No runnable process is an error */
1114 Cal_Highest_runnable_priority(void)
1122 for (i
= MAX_PRIORITIES
- 1; i
>= 0 ; i
--)
1123 if (runnable
[i
].count
!= 0)
1127 Abort_LWP("No ready processes");
1130 Highest_runnable_priority
= i
;