*** empty log message ***
[arla.git] / lwp / plwp.c
blob0b81923ab00f993fd79f41295d186d574c9c4d7a
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.
8 */
9 /*
10 ****************************************************************************
11 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
12 * *
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. *
20 * *
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 ****************************************************************************
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
39 /* allocate externs here */
40 #define LWP_KERNEL
42 #include <lwp.h>
43 #include "preempt.h"
45 RCSID("$Id$");
47 #ifdef AFS_AIX32_ENV
48 #include <ulimit.h>
49 #include <sys/errno.h>
50 #include <sys/user.h>
51 #include <sys/pseg.h>
52 #include <sys/core.h>
53 #pragma alloca
54 #endif
56 #ifndef MAX
57 #define MAX(a,b) (((a)>(b))?(a):(b))
58 #endif
60 #define TRUE 1
61 #define FALSE 0
62 #define READY 2
63 #define WAITING 3
64 #define DESTROYED 4
65 #define QWAITING 5
67 /* Debugging macro */
68 #ifdef DEBUG
69 #define Debug(level, msg) \
70 do { \
71 if (lwp_debug && lwp_debug >= level) { \
72 printf("***LWP(max=%d) (%p): ", \
73 Highest_runnable_priority, lwp_cpptr); \
74 printf msg; \
75 putchar('\n'); \
76 } \
77 } while(0)
79 #else
80 #define Debug(level, msg) do {} while (0)
81 #endif
83 #define lwp_timerclear(t) (t)->tv_sec = (t)->tv_usec = 0
85 /* Prototypes */
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,
95 char *name) ;
96 static int Internal_Signal(char *event) ;
97 char (*RC_to_ASCII());
99 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
101 struct QUEUE {
102 PROCESS head;
103 int count;
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;
117 /* Iterator macro */
118 #define for_all_elts(var, q, body)\
120 PROCESS var, _NEXT_;\
121 int _I_;\
122 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
123 _NEXT_ = var -> next;\
124 body\
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 *);
137 PROCESS lwp_cpptr;
139 /* The global Highest_runnable_priority is only needed in NEW lwp.
140 But it gets set within a for_all_elts() instance in
141 InternalSignal(). */
142 int Highest_runnable_priority; /* global variable for max priority */
144 int Proc_Running; /* indicates forked proc got control */
147 * Glue for
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;
165 #if 0
166 #define LWP_INT_LOCK(sem) WaitForSingleObject (sem, INFINITE)
167 #define LWP_INT_UNLOCK(sem) ReleaseMutex (sem)
168 #endif
170 static
171 DWORD LWP_INT_LOCK(HANDLE *sem)
173 DWORD ret;
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",
179 *sem, ret, err));
181 Debug(0, ("LWP_INT_LOCK: got %p", *sem));
182 return ret;
185 static DWORD LWP_INT_UNLOCK(HANDLE *sem)
187 DWORD ret;
188 Debug(0, ("LWP_INT_UNLOCK: sem = %p", *sem));
189 ret = ReleaseMutex(*sem);
190 if (!ret) {
191 DWORD err = GetLastError();
192 Debug(0, ("LWP_INT_UNLOCK: h = %p, wait = %ld, %ld\n",
193 *sem, ret, err));
195 Debug(0, ("LWP_INT_UNLOCK: %p released", *sem));
196 return ret;
199 static DWORD LWP_INT_WAIT(HANDLE *cond, HANDLE *mutex)
201 DWORD ret;
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);
208 if (!ret) {
209 DWORD err = GetLastError();
210 Debug(0, ("LWP_INT_WAIT(%d): ReleaseMutex failed: %ld error: "
211 "%ld mutex\n", this_time, err, *mutex));
212 abort();
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));
219 abort();
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));
226 abort();
228 Debug(0, ("LWP_INT_WAIT(%d): got mutex: cond: %p mutex: %p",
229 this_time, *cond, *mutex));
230 return 0;
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 */
240 #endif
242 static void
243 lwpremove(PROCESS p, struct QUEUE *q)
245 /* Special test for only element on queue */
246 if (q->count == 1)
247 q -> head = NULL;
248 else {
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;
255 q->count--;
256 Debug(0, ("removing, count now %d", q->count));
257 p -> next = p -> prev = NULL;
260 static void
261 lwpinsert(PROCESS p, struct QUEUE *q)
263 if (q->head == NULL) { /* Queue is empty */
264 q -> head = p;
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;
272 q->count++;
273 Debug(0, ("inserting, count now %d", q->count));
276 static void
277 lwpmove(PROCESS p, struct QUEUE *from, struct QUEUE *to)
279 lwpremove(p, from);
280 lwpinsert(p, to);
283 int
284 LWP_TerminateProcessSupport() /* terminate all LWP support */
286 int i;
288 Debug(0, ("Entered Terminate_Process_Support"));
289 if (lwp_init == NULL)
290 return LWP_EINIT;
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);
296 lwp_init = NULL;
297 return LWP_SUCCESS;
300 int
301 LWP_GetRock(int Tag, char **Value)
303 /* Obtains the pointer Value associated with the rock Tag of this LWP.
304 Returns:
305 LWP_SUCCESS if specified rock exists and Value has been filled
306 LWP_EBADROCK rock specified does not exist
308 int i;
309 struct rock *ra;
311 ra = lwp_cpptr->rlist;
313 for (i = 0; i < lwp_cpptr->rused; i++)
314 if (ra[i].tag == Tag) {
315 #ifdef PTHREADS_LWP
316 #ifdef PTHREAD_GETSPECIFIC_TWOARG
317 pthread_getspecific(ra[i].val, Value);
318 #else
319 *Value = pthread_getspecific(ra[i].val);
320 #endif
321 #elif WINDOWS_THREADS_LWP
322 *Value = TlsGetValue((unsigned long) ra[i].val);
323 #endif
324 if (*Value != NULL)
325 return(LWP_SUCCESS);
327 return(LWP_EBADROCK);
331 int
332 LWP_NewRock(int Tag, char *Value)
334 /* Finds a free rock and sets its value to Value.
335 Return codes:
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. */
346 int i;
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;
358 #ifdef PTHREADS_LWP
359 #ifdef HAVE_PTHREAD_KEYCREATE
360 if (pthread_keycreate(&ra[lwp_cpptr->rused].val, NULL))
361 #else
362 if (pthread_key_create(&ra[lwp_cpptr->rused].val, NULL))
363 #endif
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);
374 #endif
376 lwp_cpptr->rused++;
377 return(LWP_SUCCESS);
379 else return(LWP_ENOROCKS);
382 static void
383 Dispose_of_Dead_PCB(PROCESS cur)
386 Debug(0, ("Entered Dispose_of_Dead_PCB"));
387 Delete_PCB(cur);
388 Free_PCB(cur);
391 int
392 LWP_CurrentProcess(PROCESS *pid)
394 Debug(0, ("Entered Current_Process"));
395 if (lwp_init) {
396 *pid = lwp_cpptr;
397 return LWP_SUCCESS;
398 } else
399 return LWP_EINIT;
403 int
404 LWP_GetProcessPriority(PROCESS pid, int *priority)
406 Debug(0, ("Entered Get_Process_Priority"));
407 if (lwp_init) {
408 *priority = pid -> priority;
409 return 0;
410 } else
411 return LWP_EINIT;
414 int
415 LWP_WaitProcess(void *event)
417 char *tempev[2];
419 Debug(0, ("Entered Wait_Process"));
420 if (event == NULL) return LWP_EBADEVENT;
421 tempev[0] = event;
422 tempev[1] = NULL;
423 return LWP_MwaitProcess(1, tempev);
426 static void
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]));
435 static void
436 purge_dead_pcbs()
438 for_all_elts(cur, blocked, { if (cur->status == DESTROYED)
439 Dispose_of_Dead_PCB(cur); });
442 static void
443 Exit_LWP()
445 exit (-1);
448 static void
449 Dump_Processes()
451 if (lwp_init) {
452 int i;
453 for (i=0; i<MAX_PRIORITIES; i++)
454 for_all_elts(x, runnable[i], {
455 printf("[Priority %d]\n", i);
456 Dump_One_Process(x);
458 for_all_elts(x, blocked, { Dump_One_Process(x); });
459 } else {
460 printf("***LWP: LWP support not initialized\n");
464 char *
465 LWP_Name()
467 return(lwp_cpptr->name);
470 int
471 LWP_Index()
473 return(lwp_cpptr->index);
476 int
477 LWP_HighestIndex()
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
486 int
487 LWP_QWait()
489 PROCESS old_cpptr;
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,
504 lwp_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",
509 old_cpptr->name));
510 LWP_INT_WAIT(&old_cpptr->c, &ct_mutex);
511 LWP_INT_UNLOCK(&ct_mutex);
512 Debug(0, ("LWP_QWait:%s woke up",
513 old_cpptr->name));
515 lwp_cpptr = old_cpptr;
517 /* return only if calling process' priority is the highest */
518 if (lwp_cpptr->priority < Highest_runnable_priority)
519 Dispatcher();
520 return LWP_SUCCESS;
524 /* signal the PROCESS pid - by adding it to the runnable queue */
525 int
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,
530 pid->name));
531 pid->status = READY;
532 lwpinsert(pid, &runnable[pid->priority]);
533 Debug(0, ("LWP_QSignal: Just inserted %s into runnable queue\n",
534 pid->name));
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));
541 return LWP_SUCCESS;
543 else return LWP_ENOWAIT;
548 LWP_CreateProcess(void (*ep)(), int stacksize, int priority,
549 char *parm, char *name, PROCESS *pid)
551 PROCESS temp;
552 #if defined(PTHREADS_LWP)
553 pthread_t ct;
554 pthread_attr_t cta;
555 int retval;
556 #elif defined(WINDOWS_THREADS_LWP)
557 HANDLE ct;
558 #endif
559 PROCESS old_cpptr;
561 Debug(0, ("Entered LWP_CreateProcess to create %s at priority %d\n",
562 name, priority));
564 if (stacksize < AFS_LWP_MINSTACKSIZE)
565 stacksize = AFS_LWP_MINSTACKSIZE;
567 old_cpptr = lwp_cpptr;
568 /* Throw away all dead process control blocks */
569 purge_dead_pcbs();
571 if (lwp_init == NULL)
572 return LWP_EINIT;
574 /* allocate the memory for the pcb - check for malloc errors */
575 temp = (PROCESS)malloc (sizeof (struct lwp_pcb));
576 if (temp == NULL) {
577 Dispatcher();
578 return LWP_ENOMEM;
581 /* check priorities */
582 if (priority < 0 || priority >= MAX_PRIORITIES) {
583 Dispatcher();
584 return LWP_EBADPRI;
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);
593 if (PRE_Block != 0)
594 Abort_LWP("PRE_Block not 0");
596 PRE_Block = 1;
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);
603 #endif
604 retval = pthread_create(&ct, &cta, (void *)Create_Process_Part2, temp);
605 if (retval != 0)
606 Abort_LWP("pthread_create failed to create thread %d/%d",
607 retval, errno);
609 pthread_detach(ct);
610 temp->a = cta;
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,
615 temp, 0, NULL);
616 Debug(0,("After CreateThread Create_Process_Part2"));
617 if (ct == NULL)
618 Abort_LWP("CreateThread failed to create thread: %d",
619 (int)GetLastError());
620 temp->t = ct;
621 #endif
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",
628 Proc_Running));
629 while( !Proc_Running ){
630 LWP_INT_UNLOCK(&run_sem);
631 #if defined(PTHREADS_LWP)
632 #if defined(HAVE_THR_YIELD)
633 thr_yield();
634 #elif defined(HAVE_SCHED_YIELD)
635 sched_yield();
636 #else
637 pthread_yield();
638 #endif
639 #elif defined(WINDOWS_THREADS_LWP)
640 Sleep(0); /* XXX */
641 #endif
642 LWP_INT_LOCK(&run_sem);
643 Debug(0,("After creating proc yields and gets back control Proc_Running = %d\n",
644 Proc_Running));
646 LWP_INT_UNLOCK(&run_sem);
648 lwp_cpptr = old_cpptr;
650 Dispatcher();
651 *pid = temp;
652 return LWP_SUCCESS;
655 int
656 LWP_DestroyProcess(PROCESS pid)
658 void *t;
660 Debug(0, ("Entered Destroy_Process"));
661 if (lwp_init) {
662 #if defined(PTHREADS_LWP)
663 pthread_attr_destroy(&pid->a);
664 #elif defined(WINDOWS_THREADS_LWP)
665 CloseHandle (pid->t);
666 #endif
667 if (lwp_cpptr == pid){
668 /* kill myself */
669 pid->status = DESTROYED;
670 Free_PCB(pid);
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);
680 LWP_INT_EXIT(t);
681 } else {
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 ;
686 Dispatcher();
688 return LWP_SUCCESS ;
689 } else
690 return LWP_EINIT;
693 int
694 LWP_DispatchProcess() /* explicit voluntary preemption */
696 Debug(0, ("Entered Dispatch_Process"));
697 if (lwp_init) {
698 Dispatcher();
699 return LWP_SUCCESS;
700 } else {
701 return LWP_EINIT;
705 int
706 LWP_Init(int version, int priority, PROCESS *pid)
708 lwp_debug = 0;
709 if (version != LWP_VERSION)
711 fprintf(stderr, "**** FATAL ERROR: LWP VERSION MISMATCH ****\n");
712 exit(-1);
714 else return(InitializeProcessSupport(priority, pid));
717 int
718 LWP_InitializeProcessSupport(int priority, PROCESS *pid)
720 return(InitializeProcessSupport(priority, pid));
723 static int
724 InitializeProcessSupport(int priority, PROCESS *pid)
726 PROCESS temp;
727 int i;
729 Debug(0, ("Entered InitializeProcessSupport"));
730 if (lwp_init != NULL)
731 return LWP_SUCCESS;
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;
739 blocked.head = NULL;
740 blocked.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);
750 #if 0
751 Highest_runnable_priority = priority;
752 #endif
754 /* initialize mutex and semaphore */
755 Proc_Running = TRUE;
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();
764 #endif
765 lwp_cpptr = temp;
766 Dispatcher();
767 *pid = temp;
768 return LWP_SUCCESS;
771 int
772 LWP_INTERNALSIGNAL(void *event, int yield)
774 Debug(0, ("Entered LWP_SignalProcess, yield=%d", yield));
775 if (lwp_init) {
776 int rc;
777 rc = Internal_Signal(event);
778 if (yield) {
779 Cal_Highest_runnable_priority();
780 Debug(0, ("hipri=%d", Highest_runnable_priority));
781 Dispatcher();
783 return rc;
784 } else
785 return LWP_EINIT;
788 int
789 LWP_MwaitProcess(int wcount, char *evlist[]) /* wait on m of n events */
791 int ecount, i;
792 PROCESS old_cpptr;
794 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount));
795 if (evlist == NULL) {
796 Dispatcher();
797 return LWP_EBADCOUNT;
800 /* count # of events in eventlist */
801 for (ecount = 0; evlist[ecount] != NULL; ecount++) ;
802 if (ecount == 0) {
803 Dispatcher();
804 return LWP_EBADCOUNT;
807 if (lwp_init) {
808 /* check for illegal counts */
809 if (wcount>ecount || wcount<0) {
810 Dispatcher();
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 */
827 if (wcount > 0) {
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)
858 Dispatcher();
859 return LWP_SUCCESS ;
861 return LWP_EINIT ;
865 int
866 LWP_StackUsed(PROCESS pid, int *max, int *used)
868 /* just here for compatibility */
869 *max = -1;
870 *used = -1;
871 return LWP_SUCCESS;
874 static void
875 Abort_LWP(char *msg, ...)
877 va_list ap;
879 Debug(0, ("Entered Abort_LWP"));
880 va_start(ap, msg);
881 printf("***LWP Abort ");
882 vprintf(msg, ap);
883 va_end(ap);
884 Dump_Processes();
885 Exit_LWP();
888 static void
889 Create_Process_Part2(PROCESS temp)
891 /* set the global Proc_Running to signal the parent */
892 LWP_INT_LOCK(&run_sem);
893 Proc_Running = TRUE;
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);
900 lwp_cpptr = temp;
902 (*temp->ep)(temp->parm);
903 LWP_DestroyProcess(temp);
906 static void
907 Dump_One_Process(PROCESS pid)
909 int i;
911 printf("***LWP: Process Control Block at 0x%x\n", (int)pid);
912 printf("***LWP: Name: %s\n", pid->name);
913 if (pid->ep != NULL)
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");
922 putchar('\n');
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]);
931 putchar('\n');
933 if (pid->wakevent>0)
934 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
937 static void
938 Dispatcher() /* Lightweight process dispatcher */
940 void *t;
941 int my_priority;
942 PROCESS old_cpptr;
945 #if 1
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);
951 #if 0
952 Dump_Processes();
953 #endif
955 Highest_runnable_priority = i;
956 #endif
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));
961 PRE_Block = 1;
962 if ((my_priority < Highest_runnable_priority) ||
963 (runnable[my_priority].count > 0))
965 Debug(0, ("Dispatcher: %s is now yielding", lwp_cpptr->name));
966 /* I have to quit */
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",
982 old_cpptr->name));
983 LWP_INT_WAIT(&old_cpptr->c, &ct_mutex);
984 LWP_INT_UNLOCK(&ct_mutex);
985 Debug(0, ("Dispatcher: %s woke up",
986 old_cpptr->name));
988 /* update global pointer */
989 lwp_cpptr = old_cpptr;
990 } else {
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 */
997 Free_PCB(lwp_cpptr);
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);
1005 LWP_INT_EXIT(t);
1007 #if 0
1008 if (PRE_Block != 1) Abort_LWP("PRE_Block not 1");
1009 #endif
1010 PRE_Block = 0;
1014 static void
1015 Free_PCB(PROCESS pid)
1017 Debug(0, ("Entered Free_PCB"));
1019 if (pid->eventlist != NULL)
1020 free((char *)pid->eventlist);
1021 free((char *)pid);
1024 static void
1025 Initialize_PCB(PROCESS temp, int priority, char *stack, int stacksize,
1026 void (*ep)(), char *parm, char *name)
1028 int i = 0;
1030 Debug(0, ("Entered Initialize_PCB"));
1031 if (name != NULL)
1032 while (((temp -> name[i] = name[i]) != '\0') && (i < 31))
1033 i++;
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++;
1045 temp -> ep = ep;
1046 temp -> parm = parm;
1047 temp -> misc = NULL; /* currently unused */
1048 temp -> next = NULL;
1049 temp -> prev = NULL;
1050 temp -> rused = 0;
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));
1065 #endif
1067 Debug(0, ("Leaving Initialize_PCB\n"));
1070 static int
1071 Internal_Signal(char *event)
1073 int rc = LWP_ENOWAIT;
1074 int i;
1076 Debug(0, ("Entered Internal_Signal [event id 0x%x]", (int)event));
1077 if (lwp_init == NULL)
1078 return LWP_EINIT;
1079 if (event == 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;
1087 rc = LWP_SUCCESS;
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,
1102 temp->priority));
1103 break;
1108 return rc;
1111 /* places the maximum of runnable task priorities in the global variable -
1112 * Highest_runnable_priority. No runnable process is an error */
1113 static void
1114 Cal_Highest_runnable_priority(void)
1116 int i;
1118 #if 0
1119 Dump_Processes();
1120 #endif
1122 for (i = MAX_PRIORITIES - 1; i >= 0 ; i--)
1123 if (runnable[i].count != 0)
1124 break;
1125 #if 0
1126 if (i < 0)
1127 Abort_LWP("No ready processes");
1128 #endif
1129 if (i >= 0)
1130 Highest_runnable_priority = i;
1131 #if 0
1132 else
1133 abort();
1134 #endif