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