Added upstream version.
[vlp.git] / int / process.c
1 #include "depend.h"
2 #include "genint.h"
3 #include "int.h"
4 #include "process.h"
5 #include "intproto.h"
6
7 #if DLINK
8 #  include "dlink.h"
9 #elif TCPIP
10 #  include "tcpip.h"
11 #endif
12
13 #include <assert.h>
14
15
16 /* Process management */
17
18 procdescr process[ MAXPROCESS ];     /* process descriptor table         */
19 procdescr *thisp;                    /* pointer to current process descr */
20 word thispix;                        /* current process index            */
21 queue ready;                         /* Round-Robin queue                */
22 bool network;                        /* TRUE if operating in network     */
23 message globmsgqueue[ MAXMSGQUEUE ]; /* queue of waiting messages        */
24 int msgready = 0;                    /* number of waiting messages       */
25 int msghead = 0, msgtail = 0;        /* pointers to message queue        */
26 word ournode;                        /* this machine node number         */
27 word console;                        /* console node number              */
28 bool remote = FALSE;                 /* TRUE if remote node              */
29 bool reschedule = TRUE;              /* TRUE if must re-schedule         */
30
31
32
33 #ifndef NO_PROTOTYPES
34 static void ansprot(message *);
35 static void localkill(message *);
36 void transfer(word);
37 static void backcreate(message *);
38 static void createprocess(message *);
39 static void localerror(message *);
40 static void killprocess(word);
41 static void mkglobal(word);
42 word pix, ref;
43 #else
44 static void ansprot();
45 static void localkill();
46 void transfer();
47 static void backcreate();
48 static void createprocess();
49 static void localerror();
50 static void killprocess();
51 static void mkglobal();
52 #endif
53
54
55
56 #if OS2
57 PGINFOSEG ginf;                         /* pointer to Global Info Segment */
58 #endif
59
60
61 #if USE_ALARM
62 #  include <signal.h>
63 #  ifndef NO_PROTOTYPES
64       static void signal_catch( void );
65 #  else
66       static void signal_catch();
67 #  endif
68    static void signal_catch(){   reschedule=TRUE;   }
69 #endif
70
71
72 void init_scheduler(){
73 #if USE_ALARM
74    signal(SIGALRM,signal_catch);
75    alarm(1);
76 #endif
77 }
78
79 void schedule()                      /* Choose next ready process to exec */
80
81   trapmsg();                                   /* STRONGLY machine dependent        */
82 #if USE_ALARM
83     if(reschedule){
84         alarm(0);
85         signal(SIGALRM,signal_catch);
86         alarm(1);
87 #elif USE_CLOCK
88     static char last;
89     char c;
90     c = clock() >> 5;                   /* the most expensive method */
91     if (reschedule || c != last)        /* context switch is needed  */
92     {
93         last = c;
94 #elif MSDOS && ( WORD_16BIT || DWORD_16BIT ) /* DOS real memory model */
95     static char last;
96     char c;
97     static char *clk = (char *) 0x0040006CL;
98     c = *clk >> 1;
99     if (reschedule || c != last)        /* context switch is needed */
100     {
101         last = c;
102 #elif OS2
103     static char last;
104     char c;
105     c = ginf->hundredths >> 3;
106     if (reschedule || c != last)        /* context switch is needed */
107     {
108         last = c;
109 #else
110 #error Scheduler time counting method not implemented !
111 #endif
112         
113         if (!(qempty(ready)))     /* wait for event if no processes  */
114          {  
115         ready = qrotate(ready);        /* find another ready process */
116         transfer(pfront(ready));       /* transfer control to it     */
117         reschedule = FALSE;
118           }
119     }
120 }
121
122
123 void transfer(pix)           /* Context switch to another process */
124 word pix;
125 {
126     word apt;
127     if (pix == thispix) return;         /* optimized for case of one process */
128
129     if( thisp != NULL )            /* previous process is alive */
130     {
131         thisp->ic = ic;            /* store previous context */
132         thisp->c1 = c1;
133         thisp->c2 = c2;
134     }
135     thispix = pix;               /* and load new context */
136     thisp = &process[ thispix ];
137     ic = thisp->ic;
138     c1 = thisp->c1;
139     c2 = thisp->c2;
140     M = thisp->M;
141     param = thisp->param;
142     apt = thisp->prochead+M[ thisp->prochead ];
143     display = apt+dispoff;
144     display2 = apt+disp2off;
145 }
146
147
148 void activate(pix)               /* Resume process on this node */
149 word pix;
150 {
151     process[ pix ].status = EXECUTING;  /* flag process as ready to execute */
152     ready = pinsert(ready, pix);        /* insert into ready queue */
153     reschedule = TRUE;           /* force context switch */
154 #   ifdef RPCDBG
155     fprintf(stderr,"activate process %d\n",pix);
156 #   endif
157 }
158
159
160 void passivate(newstatus)             /* Passivate process */
161 int newstatus;
162 {
163
164     thisp->status = newstatus;   /* change to some wait status */
165     ready = qremove(ready);         /* remove from ready queue */
166     reschedule = TRUE;           /* force context switch */
167 #   ifdef RPCDBG
168     fprintf(stderr,"passivate process %d to state %d\n",thispix,newstatus);
169 #   endif
170 }
171
172
173 /* Copy parameters from object to message or vice versa. */
174
175
176 void moveparams(pix, am, msg, par1, dir)
177    word pix, am;
178    message *msg;
179    int par1, dir;
180 {
181    protdescr *ptr;
182    procdescr *p;
183    word i, tpd, ap, pd, prim, offset;
184    char *cp;
185    bool cflag, convert;
186
187    p = &process[ pix ];
188    ptr = prototype[ p->M[ am+PROTNUM ] ];
189    cp = (char *) msg->params;
190
191    for (i = 0;  i < ptr->lthparlist;  i++)      /* loop through parameters */
192    {
193
194       offset = M[ ptr->parlist+i ];
195       tpd = M[ ptr->pfdescr+i ];        /* type description of param */
196       pd = M[ tpd ];
197
198       if (par1 == PARIN)
199          cflag = ( pd==PARIN || pd==PARINOUT || pd==FORMFUNC || pd==FORMPROC );
200       else
201          cflag = ( pd==PAROUT || pd==PARINOUT );
202
203       if (cflag)
204       {
205          if (pd == FORMFUNC || pd == FORMPROC)
206          {
207             ap = APFMPROC;
208             convert = TRUE;
209          }
210          else
211             if (M[ M[ tpd+2 ] ] == CLASSTYPE)
212             {
213                ap = APREF;
214                convert = TRUE;
215             }
216             else
217             {
218                prim = M[ tpd+2 ]-ipradr;
219                ap = primapet[ prim ];
220                convert = (prim == 4 || prim == 5); /* process or coroutine */
221             }
222
223          ap *= sizeof(word);       /* param appetite in bytes */
224
225          switch (dir)           /* copy parameter in right direction */
226          {
227
228             case LOADPAR :
229
230                /* we always load parameters from OUR process */
231                assert(pix==thispix);
232
233                if (convert){
234                   procaddr pa;
235                   {
236                      word ah=M[am+offset];
237                      if( !isprocess((virtaddr*)(M+am+offset)) &&
238                          M[ ah+1 ] == M[ am+offset+1 ]
239                         )
240                         if (prototype[ M[ M[ ah ]+PROTNUM ] ]->kind == PROCESS)
241                         {
242                            pa.node = ournode;
243                            pa.pix  = pix;
244                            pa.mark = thisp->mark;
245                         }
246                        else
247                          /*pat  errsignal(RTENONGL); */ /* only process may be global */
248                     /*pat*/ obj2mess(p->M,(virtaddr*)(p->M+am+offset),&pa);
249                      else
250                         obj2mess(M,(virtaddr*)(M+am+offset),&pa);
251                   }
252 /*
253                   mkglobal(am+offset);
254                   obj2mess(p->M,(virtaddr*)(p->M+am+offset),&pa);
255 */
256                   moveblock((char *)&pa, cp, ap=sizeof(procaddr));
257                }else
258                   moveblock((char *) &p->M[ am+offset ], cp, ap);
259                break;
260
261
262             case SAVEPAR :
263
264                if (convert){
265                   procaddr pa;
266                   ap=sizeof(procaddr);
267                   moveblock(cp,(char *)&pa, ap);
268                   mess2obj(p,&pa,(virtaddr*)(p->M+am+offset));
269                }else
270                   moveblock(cp, (char *) &p->M[ am+offset ], ap);
271                break;
272
273          }
274
275          cp += ap;
276          assert(cp-msg->params <= sizeof(msg->params));
277       }
278    }
279 }
280
281
282 word getnode(am)                     /* Determine node number for process */
283 word am;
284 {
285     protdescr *ptr;
286     word p;
287     int i;
288
289     p = prototype[ M[ am+PROTNUM ] ]->preflist;
290     while (prototype[ M[ p ] ]->kind != PROCESS)  p++;
291     ptr = prototype[ M[ p ] ];
292     if (ptr->lthpreflist == 1) i = 0;
293     else i = prototype[ M[ p-1 ] ]->lthparlist;
294     return (M[ am+M[ ptr->parlist+i ] ]);
295 }
296
297
298 void resume(virt)                  /* Perform RESUME instruction */
299 virtaddr *virt;
300 {
301     message msg;
302
303     if (isprocess(virt))               /* is it process realy ? */
304     {
305         msg.control.type = RESUME;
306         obj2mess( M, virt, &msg.control.receiver );
307         sendmsg1( &msg);  /* request remote resume */
308     }
309     else errsignal(RTEILLRS);     /* illegal RESUME */
310 }
311
312
313 static void createprocess(msg)           /* Create new process */
314 message *msg;
315 {
316     word i, prot;
317     for (i = 0;  i < MAXPROCESS;  i++)  /* find unused process descr. */
318         if (!process[ i ].used && process[ i ].mark != -MAXMARKER) break;
319     if (i == MAXPROCESS) senderr(RTETMPRC, &(msg->control.sender) );
320     if (process[ i ].M == NULL)         /* memory not allocated yet */
321     {
322         process[ i ].M = mallocate(memorysize+1);
323         if (process[ i ].M == NULL) senderr(RTEMEMOV, &msg->control.sender);
324         moveblock((char *) process[ 0 ].M, (char *) process[ i ].M,
325                   freem * sizeof(word));
326     }
327     prot = msg->control.par;       /* process prototype number */
328     initprocess(i, prot, &msg->control.sender);
329     moveparams(i, process[ i ].prochead, msg, PARIN, SAVEPAR);
330     process[ i ].status = GENERATING;   /* execute process until RETURN */
331     ready = pinsert(ready, i);
332     reschedule = TRUE;
333     if ((remote) && (i==0)) { thispix=1;thisp=NULL;transfer(i); }
334 }
335
336
337 static void killprocess(pix)         /* Release process descriptor */
338 word pix;
339 {
340     qfree(process[ pix ].msgqueue);
341     qfree(process[ pix ].rpcwait);
342     sfree(process[ pix ].rpcmask);
343
344     process[ pix ].used = FALSE;        /* mark descriptor as unused */
345     process[ pix ].mark--;           /* decrement marker */
346
347     if( pix == thispix )
348     {
349         thispix = -1;
350         thisp = NULL;
351     }
352 }
353
354
355 static void localkill(msg)
356 message *msg;
357 {
358     word pix;
359
360     pix = msg->control.receiver.pix;
361
362 #   if RPCDBG
363     fprintf( stderr, "kill process %d\n", pix );
364 #   endif
365
366     if (process[ pix ].mark == msg->control.receiver.mark)      /* not none */
367     {
368         if (process[ pix ].status != STOPPED)  /* is process suspended ? */
369             senderr(RTEILLKL, &msg->control.sender);
370         killprocess(pix);
371     }
372 }
373
374
375 void endprocess(status)                /* Terminate current process */
376 int status;
377 {
378     int i;
379
380     passivate(STOPPED);
381 #   if RPCDBG
382     fprintf( stderr, "terminate process %d\n", thispix );
383 #   endif
384     killprocess(thispix);
385     if  (remote)  longjmp(contenv, 1);
386     for (i = 0;  i < MAXPROCESS;  i++)
387         if (process[ i ].used) longjmp(contenv, 1);
388     endrun(status);
389 }
390
391
392 static void backcreate(msg)
393 message *msg;
394 {
395     word pix, am;
396     procdescr *p;
397
398     pix = msg->control.receiver.pix;
399     p = &process[ pix ];
400
401     am = p->M[ p->template.addr ];      /* template physical address */
402     p->M[ temporary ] = am;
403     moveparams(pix, am, msg, PAROUT, SAVEPAR);
404
405                                                /*store new process address */
406     mess2obj(p,&(msg->control.sender),&(p->backobj));
407     activate(pix);               /* end of waiting for NEW */
408 }
409
410
411 void senderr(exception, virt)
412 int exception;
413 procaddr *virt;
414 {
415     message msg;
416
417     msg.control.type = ERRSIG;
418     msg.control.receiver=*virt;
419     msg.control.par = exception;
420     sendmsg1(&msg);           /* send error message */
421     longjmp(contenv, 1);        /* continue from next instruction */
422 }
423
424
425 static void localerror(msg)
426 message *msg;
427 {
428     word pix;
429     int s;
430
431     pix = msg->control.receiver.pix;
432     s = process[ pix ].status;
433     if (process[ pix ].mark == msg->control.receiver.mark && s != STOPPED)
434     {
435         if (s == WAITFORNEW || s == WAITFORRPC) activate(pix);
436         while (pfront(ready) != pix)
437             ready = qrotate(ready);
438         transfer(pfront(ready));
439         errsignal(msg->control.par);
440     }
441 }
442
443
444 void askprot(virt)               /* Ask for prototype of object */
445 virtaddr *virt;
446 {
447     word am;
448     message msg;
449
450     if (isprocess(virt))               /* send question to remote process */
451     {
452         obj2mess( M, virt, &msg.control.receiver );
453         msg.control.type = ASKPRO;
454         sendmsg1( &msg );
455         passivate(WAITASKPRO);
456     }
457     else
458     {
459         if (member(virt, &am))
460             M[ temporary ] = M[ am+PROTNUM ];
461         else errsignal(RTEREFTN);
462     }
463 }
464
465
466 static void ansprot(msg)               /* Answer with prototype of process */
467 message *msg;
468 {
469     message msg1;
470     word pix;
471
472     pix = msg->control.receiver.pix;
473     if (process[ pix ].mark == msg->control.receiver.mark)      /* not none */
474     {
475         msg1.control.receiver = msg->control.sender;
476         msg1.control.type = PROACK;
477         msg1.control.par = process[ pix ].prot;
478         sendmsg1( &msg1 );
479     }
480     else senderr(RTEREFTN, &msg->control.sender);
481 }
482
483
484 /* Message send/receive handling : */
485
486 void msginterrupt(msg)           /* Receive message interrupt handler */
487    message *msg;
488 {
489    moveblock((char *)msg, (char *)&globmsgqueue[ msgtail ],
490              (word) sizeof(message));
491    msgtail = (msgtail+1) % MAXMSGQUEUE;
492    msgready++;
493
494 }
495
496
497 void sendmsg1(msg)                  /* Send message via net */
498 message *msg;
499 {
500  MESSAGE m;
501
502     msg->control.sender.node = ournode;
503     msg->control.sender.pix  = thispix;
504     msg->control.sender.mark = thisp->mark;
505     if(
506        msg->control.receiver.node == ournode
507        ||
508        msg->control.receiver.node == 0
509       )
510                         /* simulate receive message interrupt */
511     {
512
513         msg->control.receiver.node == ournode;
514         msginterrupt(msg);         /* call directly interrupt handler */
515     }
516     else /* send message to kernel and then to NET module */
517     {
518      m.msg_type = MSG_NET; 
519      m.param.pword[0] = NET_PROPAGATE;
520      m.param.pword[1] = MSG_INT;
521      m.param.pword[2] = my_ctx.node;
522      m.param.pword[3] = my_ctx.program_id;     
523      memcpy(&m.int_msg,msg,sizeof(message));
524      send_to_net(&m);
525
526     }
527 }
528
529
530 void trapmsg()                  /* Check for waiting message */
531 {
532     message *msg;
533     procdescr *p;
534     word pix;
535
536     if (msgready > 0)      /* at least one message is waiting */
537     {
538         msg = &globmsgqueue[ msghead ];    /* get first message from queue */
539         msghead = (msghead+1) % MAXMSGQUEUE;
540      
541         switch(msg->control.type)
542         {
543             case ERRSIG :
544                localerror(msg);
545                break;
546
547             case RESUME :
548                pix = msg->control.receiver.pix;
549                if (process[ pix ].mark != msg->control.receiver.mark)
550                    senderr(RTEREFTN, &msg->control.sender);
551                if (process[ pix ].status != STOPPED)
552                    senderr(RTEILLRS, &msg->control.sender);
553                activate(pix);
554                break;
555
556             case CREATE :
557                createprocess(msg);
558                break;
559
560             case CREACK :
561                backcreate(msg);
562                break;
563
564             case KILLPR :
565                localkill(msg);
566                break;
567
568             case RPCALL :
569                rpc1(msg);
570                break;
571
572             case RPCACK :
573                rpcend(msg);
574                break;
575
576             case ASKPRO :
577                ansprot(msg);
578                break;
579
580             case PROACK :
581                pix = msg->control.receiver.pix;
582                p = &process[ pix ];
583                p->M[ temporary ] = msg->control.par;
584                activate(pix);
585                break;
586
587             default     :
588                fprintf( stderr, " Invalid message\n" );
589                senderr(RTESYSER, &msg->control.sender);
590         }
591         msgready--;
592
593     }
594 }
595
596
597 static void mkglobal(ref)            /* Make global a process reference */
598     word ref;
599 {
600     word ah;
601     ah = M[ ref ];
602     if (!isprocess((virtaddr*)(M+ref)) && M[ ah+1 ] == M[ ref+1 ])
603         if (prototype[ M[ M[ ah ]+PROTNUM ] ]->kind == PROCESS)
604         {
605             virtaddr va;
606             procaddr pa;
607             pa.node = ournode;
608             pa.pix  = pix;
609             pa.mark = thisp->mark;
610             mess2obj(thisp,&pa,&va);
611             M[ ref ]   = va.addr;
612             M[ ref+1 ] = va.mark;
613 #ifdef RPCDBG
614 fprintf(stderr,"mkglobal REAL (thisp=%d) isprocess:node=%d pix=%d mark=%d\n",thispix,pa.node,pa.pix,pa.mark);fflush(stderr);
615 #endif
616         }
617         else errsignal(RTENONGL);        /* only process may be global */
618 }
619
620
621
622 /*
623 void show_m( char *s, message *msg ){
624    char *n;
625    switch(msg->control.type)
626    {
627        case ERRSIG : n = "ERRSIG"; break;
628        case RESUME : n = "RESUME"; break;
629        case CREATE : n = "CREATE"; break;
630        case CREACK : n = "CREACK"; break;
631        case KILLPR : n = "KILLPR"; break;
632        case RPCALL : n = "RPCALL"; break;
633        case RPCACK : n = "RPCACK"; break;
634        case ASKPRO : n = "ASKPRO"; break;
635        case PROACK : n = "PROACK"; break;
636        default     : n = "??????"; break;
637    }
638 #ifdef RPCDBG
639    printf( "message %s type %s from %d:%d:%d to %d:%d:%d\n",
640            s, n,
641            msg->control.sender.node,
642            msg->control.sender.pix,
643            msg->control.sender.mark,
644            msg->control.receiver.node,
645            msg->control.receiver.pix,
646            msg->control.receiver.mark
647          );
648    fflush( stdout );
649 #endif
650 }
651 */
652