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