Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / lwp / test / testlwp.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 */
9
10 /*******************************************************************\
11 * *
12 * Information Technology Center *
13 * Carnegie-Mellon University *
14 * *
15 * *
16 \*******************************************************************/
17
18
19 /* allocate externs here */
20 #include <afsconfig.h>
21 #include <afs/param.h>
22
23
24 #define LWP_KERNEL
25 #include "lwp.h"
26
27 #define NULL 0
28
29 #define ON 1
30 #define OFF 0
31 #define TRUE 1
32 #define FALSE 0
33 #define READY (1<<1)
34 #define WAITING (1<<2)
35 #define DESTROYED (1<<3)
36 #define MAXINT (~(1<<((sizeof(int)*8)-1)))
37 #define MINSTACK 44
38
39 /* Debugging macro */
40 #ifdef DEBUG
41 #define Debug(level, msg)\
42 if (lwp_debug && lwp_debug >= level) {\
43 printf("***LWP (0x%x): ", lwp_cpptr);\
44 printf msg;\
45 putchar('\n');\
46 }
47
48 #else
49 #define Debug(level, msg)
50
51 #endif
52 \f
53 int Dispatcher();
54 int Create_Process_Part2();
55 int Exit_LWP();
56 int Initialize_Stack(), Stack_Used();
57 char (*RC_to_ASCII());
58
59 #define MAX_PRIORITIES (LWP_MAX_PRIORITY+1)
60
61 struct QUEUE {
62 PROCESS head;
63 int count;
64 } runnable[MAX_PRIORITIES], blocked;
65
66 /* Offset of stack field within pcb -- used by stack checking stuff */
67 int stack_offset;
68
69 static remove(p, q)
70 PROCESS p;
71 struct QUEUE *q;
72 {
73 /* Special test for only element on queue */
74 if (q->count == 1)
75 q -> head = NULL;
76 else {
77 /* Not only element, do normal remove */
78 p -> next -> prev = p -> prev;
79 p -> prev -> next = p -> next;
80 }
81 /* See if head pointing to this element */
82 if (q->head == p) q -> head = p -> next;
83 q->count--;
84 p -> next = p -> prev = NULL;
85 }
86
87 static insert(p, q)
88 PROCESS p;
89 struct QUEUE *q;
90 {
91 if (q->head == NULL) { /* Queue is empty */
92 q -> head = p;
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;
99 }
100 q->count++;
101 }
102
103 static move(p, from, to)
104 PROCESS p;
105 struct QUEUE *from, *to;
106 {
107 remove(p, from);
108 insert(p, to);
109 }
110
111 /* Iterator macro */
112 #define for_all_elts(var, q, body)\
113 {\
114 PROCESS var, _NEXT_;\
115 int _I_;\
116 for (_I_=q.count, var = q.head; _I_>0; _I_--, var=_NEXT_) {\
117 _NEXT_ = var -> next;\
118 body\
119 }\
120 }
121 \f
122 /* */
123 /*****************************************************************************\
124 * *
125 * Following section documents the Assembler interfaces used by LWP code *
126 * *
127 \*****************************************************************************/
128
129 /*
130 savecontext(int (*ep)(), struct lwp_context *savearea, char *sp);
131
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
138 pointer.
139
140 returnto(struct lwp_context *savearea);
141
142 Stub for Assembler routine that will
143 restore context from a passed savearea
144 and return to the restored C frame.
145
146 */
147
148 /* Macro to force a re-schedule. Strange name is historical */
149
150 #define Set_LWP_RC(dummy) savecontext(Dispatcher, &lwp_cpptr->context, NULL)
151
152 static struct lwp_ctl *lwp_init;
153
154 int LWP_CreateProcess(ep, stacksize, priority, parm, name, pid)
155 int (*ep)();
156 int stacksize, priority;
157 char *parm;
158 char *name;
159 PROCESS *pid;
160 {
161 PROCESS temp, temp2;
162 char *stackptr;
163
164 Debug(0, ("Entered LWP_CreateProcess"))
165 /* Throw away all dead process control blocks */
166 purge_dead_pcbs();
167 if (lwp_init) {
168 temp = malloc (sizeof (struct lwp_pcb));
169 if (temp == NULL) {
170 Set_LWP_RC();
171 return LWP_ENOMEM;
172 }
173 if (stacksize < MINSTACK)
174 stacksize = 1000;
175 else
176 stacksize = 4 * ((stacksize+3) / 4);
177 if ((stackptr = malloc(stacksize)) == NULL) {
178 Set_LWP_RC();
179 return LWP_ENOMEM;
180 }
181 if (priority < 0 || priority >= MAX_PRIORITIES) {
182 Set_LWP_RC();
183 return LWP_EBADPRI;
184 }
185 #ifdef DEBUG
186 #ifdef STACK_USED
187 Initialize_Stack(stackptr, stacksize);
188 #endif
189 #endif
190 Initialize_PCB(temp, priority, stackptr, stacksize, ep, parm, name);
191 insert(temp, &runnable[priority]);
192 temp2 = lwp_cpptr;
193 lwp_cpptr = temp;
194 savecontext(Create_Process_Part2, &temp2->context, stackptr+stacksize-4);
195 Set_LWP_RC();
196 *pid = temp;
197 return 0;
198 } else
199 return LWP_EINIT;
200 }
201
202 int LWP_CurrentProcess(pid) /* returns pid of current process */
203 PROCESS *pid;
204 {
205 Debug(0, ("Entered Current_Process"))
206 if (lwp_init) {
207 *pid = lwp_cpptr;
208 return LWP_SUCCESS;
209 } else
210 return LWP_EINIT;
211 }
212
213 #define LWPANCHOR (*lwp_init)
214
215 int LWP_DestroyProcess(pid) /* destroy a lightweight process */
216 PROCESS pid;
217 {
218 PROCESS temp;
219
220 Debug(0, ("Entered Destroy_Process"))
221 if (lwp_init) {
222 if (lwp_cpptr != pid) {
223 Dispose_of_Dead_PCB(pid);
224 Set_LWP_RC();
225 } else {
226 pid -> status = DESTROYED;
227 move(pid, &runnable[pid->priority], &blocked);
228 temp = lwp_cpptr;
229 savecontext(Dispatcher, &(temp -> context),
230 &(LWPANCHOR.dsptchstack[(sizeof LWPANCHOR.dsptchstack)-4]));
231 }
232 return LWP_SUCCESS;
233 } else
234 return LWP_EINIT;
235 }
236
237 int LWP_DispatchProcess() /* explicit voluntary preemption */
238 {
239 Debug(2, ("Entered Dispatch_Process"))
240 if (lwp_init) {
241 Set_LWP_RC();
242 return LWP_SUCCESS;
243 } else
244 return LWP_EINIT;
245 }
246
247 #ifdef DEBUG
248 Dump_Processes()
249 {
250 if (lwp_init) {
251 int i;
252 for (i=0; i<MAX_PRIORITIES; i++)
253 for_all_elts(x, runnable[i], {
254 printf("[Priority %d]\n", i);
255 Dump_One_Process(x);
256 })
257 for_all_elts(x, blocked, { Dump_One_Process(x); })
258 } else
259 printf("***LWP: LWP support not initialized\n");
260 }
261 #endif
262
263 int LWP_GetProcessPriority(pid, priority) /* returns process priority */
264 PROCESS pid;
265 int *priority;
266 {
267 Debug(0, ("Entered Get_Process_Priority"))
268 if (lwp_init) {
269 *priority = pid -> priority;
270 return 0;
271 } else
272 return LWP_EINIT;
273 }
274
275 int LWP_InitializeProcessSupport(priority, pid)
276 int priority;
277 PROCESS *pid;
278 {
279 PROCESS temp;
280 struct lwp_pcb dummy;
281 int i;
282
283 Debug(0, ("Entered LWP_InitializeProcessSupport"))
284 if (lwp_init != NULL) return LWP_EINIT;
285
286 /* Set up offset for stack checking -- do this as soon as possible */
287 stack_offset = (char *) &dummy.stack - (char *) &dummy;
288
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;
293 }
294 blocked.head = NULL;
295 blocked.count = 0;
296 lwp_init = malloc(sizeof(struct lwp_ctl));
297 temp = 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;
307 Set_LWP_RC();
308 *pid = temp;
309 return LWP_SUCCESS;
310 }
311
312 int LWP_INTERNALSIGNAL(event, yield) /* signal the occurence of an event */
313 char *event;
314 int yield;
315 {
316 Debug(2, ("Entered LWP_SignalProcess"))
317 if (lwp_init) {
318 int rc;
319 rc = Internal_Signal(event);
320 if (yield) Set_LWP_RC();
321 return rc;
322 } else
323 return LWP_EINIT;
324 }
325
326 int LWP_TerminateProcessSupport() /* terminate all LWP support */
327 {
328 int pc;
329 int i;
330
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); })
339 free(lwp_init);
340 lwp_init = NULL;
341 return LWP_SUCCESS;
342 }
343
344 int LWP_WaitProcess(event) /* wait on a single event */
345 char *event;
346 {
347 char *tempev[2];
348
349 Debug(2, ("Entered Wait_Process"))
350 if (event == NULL) return LWP_EBADEVENT;
351 tempev[0] = event;
352 tempev[1] = NULL;
353 return LWP_MwaitProcess(1, tempev);
354 }
355
356 int LWP_MwaitProcess(wcount, evlist, ecount) /* wait on m of n events */
357 int wcount, ecount;
358 char *evlist[];
359 {
360 Debug(0, ("Entered Mwait_Process [waitcnt = %d]", wcount))
361
362 if (ecount == 0) {
363 Set_LWP_RC();
364 return LWP_EBADCOUNT;
365 }
366 if (lwp_init) {
367 if (wcount>ecount || wcount<0) {
368 Set_LWP_RC();
369 return LWP_EBADCOUNT;
370 }
371 if (ecount > LWP_MAX_EVENTS) {
372 Set_LWP_RC();
373 return LWP_EBADCOUNT;
374 }
375 if (ecount == 1)
376 lwp_cpptr->eventlist[0] = evlist[0];
377 else
378 memcpy(lwp_cpptr->eventlist, evlist, ecount*sizeof(char *));
379 if (wcount > 0) {
380 lwp_cpptr -> status = WAITING;
381 move(lwp_cpptr, &runnable[lwp_cpptr->priority], &blocked);
382 }
383 lwp_cpptr -> wakevent = 0;
384 lwp_cpptr -> waitcnt = wcount;
385 lwp_cpptr -> eventcnt = ecount;
386 Set_LWP_RC();
387 return LWP_SUCCESS;
388 }
389 return LWP_EINIT;
390 }
391
392 int LWP_StackUsed(pid, max, used)
393 PROCESS pid;
394 int *max, *used;
395 {
396 #define NO_STACK_STUFF
397 #ifdef DEBUG
398 #ifdef STACK_USED
399 #undef NO_STACK_STUFF
400 #endif
401 #endif
402
403 #ifdef NO_STACK_STUFF
404 return LWP_NO_STACK;
405 #else
406 *max = pid -> stacksize;
407 *used = Stack_Used(pid->stack, *max);
408 return LWP_SUCCESS;
409 #endif
410 }
411 \f
412 /*
413 * The following functions are strictly
414 * INTERNAL to the LWP support package.
415 */
416
417 static Abort_LWP(msg)
418 char *msg;
419 {
420 struct lwp_context tempcontext;
421
422 Debug(0, ("Entered Abort_LWP"))
423 printf("***LWP: %s\n",msg);
424 printf("***LWP: Abort --- dumping PCBs ...\n");
425 #ifdef DEBUG
426 Dump_Processes();
427 #endif
428 if (LWPANCHOR.outersp == NULL)
429 Exit_LWP();
430 else
431 savecontext(Exit_LWP, &tempcontext, LWPANCHOR.outersp);
432 }
433
434 static Create_Process_Part2 () /* creates a context for the new process */
435 {
436 PROCESS temp;
437
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);
443 }
444
445 static Delete_PCB(pid) /* remove a PCB from the process list */
446 PROCESS pid;
447 {
448 Debug(4, ("Entered Delete_PCB"))
449 remove(pid, (pid->blockflag || pid->status==WAITING || pid->status==DESTROYED
450 ? &blocked
451 : &runnable[pid->priority]));
452 LWPANCHOR.processcnt--;
453 }
454
455 #ifdef DEBUG
456 static Dump_One_Process(pid)
457 PROCESS pid;
458 {
459 int i;
460
461 printf("***LWP: Process Control Block at 0x%x\n", pid);
462 printf("***LWP: Name: %s\n", pid->name);
463 if (pid->ep != NULL)
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");
471 }
472 putchar('\n');
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));
480 free (pid->stack);
481 }
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]);
488 putchar('\n');
489 }
490 if (pid->wakevent>0)
491 printf("***LWP: Number of last wakeup event: %d\n", pid->wakevent);
492 }
493 #endif
494
495 static purge_dead_pcbs()
496 {
497 for_all_elts(cur, blocked, { if (cur->status == DESTROYED) Dispose_of_Dead_PCB(cur); })
498 }
499
500 int LWP_TraceProcesses = 0;
501
502 static Dispatcher() /* Lightweight process dispatcher */
503 {
504 int i;
505 #ifdef DEBUG
506 static int dispatch_count = 0;
507
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);
513 })
514 puts("]");
515 }
516 printf("[Blocked (%d):", blocked.count);
517 for_all_elts(p, blocked, {
518 printf(" \"%s\"", p->name);
519 })
520 puts("]");
521 }
522 #endif
523
524 for (i=MAX_PRIORITIES-1; i>=0; i--)
525 if (runnable[i].head != NULL) break;
526
527 if (i < 0) Abort_LWP("No READY processes");
528
529 #ifdef DEBUG
530 if (LWP_TraceProcesses > 0)
531 printf("Dispatch %d [PCB at 0x%x] \"%s\"\n", ++dispatch_count, runnable[i].head, runnable[i].head->name);
532 #endif
533 lwp_cpptr = runnable[i].head;
534 runnable[i].head = runnable[i].head -> next;
535 returnto(&lwp_cpptr->context);
536 }
537
538 static Dispose_of_Dead_PCB (cur)
539 PROCESS cur;
540 {
541 Debug(4, ("Entered Dispose_of_Dead_PCB"))
542 Delete_PCB(cur);
543 Free_PCB(cur);
544 /*
545 Internal_Signal(cur);
546 */
547 }
548
549 static Exit_LWP()
550 {
551 abort();
552 }
553
554 static Free_PCB(pid)
555 PROCESS pid;
556 {
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))
561 free(pid -> stack);
562 }
563 free(pid);
564 }
565
566 static Initialize_PCB(temp, priority, stack, stacksize, ep, parm, name)
567 PROCESS temp;
568 int (*ep)();
569 int stacksize, priority;
570 char *parm;
571 char *name,*stack;
572 {
573 int i = 0;
574
575 Debug(4, ("Entered Initialize_PCB"))
576 if (name != NULL)
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;
582 temp -> waitcnt = 0;
583 temp -> blockflag = 0;
584 temp -> priority = priority;
585 temp -> stack = stack;
586 temp -> stacksize = stacksize;
587 temp -> ep = ep;
588 temp -> parm = parm;
589 temp -> misc = NULL; /* currently unused */
590 temp -> next = NULL;
591 temp -> prev = NULL;
592 }
593
594 static int Internal_Signal(event)
595 char *event;
596 {
597 int rc = LWP_ENOWAIT;
598 int i;
599
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;
608 rc = LWP_SUCCESS;
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]);
614 break;
615 }
616 }
617 }
618 })
619 return rc;
620 }
621
622 #ifdef DEBUG
623 #ifdef STACK_USED
624 static Initialize_Stack(stackptr, stacksize)
625 char *stackptr;
626 int stacksize;
627 {
628 int i;
629
630 Debug(4, ("Entered Initialize_Stack"))
631 for (i=0; i<stacksize; i++) stackptr[i] = i & 0xff;
632 }
633
634 static int Stack_Used(stackptr, stacksize)
635 char *stackptr;
636 int stacksize;
637 {
638 int i;
639
640 for (i=0;i<stacksize;i++)
641 if ((unsigned char) stackptr[i] != (i & 0xff))
642 return (stacksize-i);
643 return 0;
644 }
645 #endif
646 #endif