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