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