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