16 /* Process management */
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 */
34 static void ansprot(message *);
35 static void localkill(message *);
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);
44 static void ansprot();
45 static void localkill();
47 static void backcreate();
48 static void createprocess();
49 static void localerror();
50 static void killprocess();
51 static void mkglobal();
57 PGINFOSEG ginf; /* pointer to Global Info Segment */
63 # ifndef NO_PROTOTYPES
64 static void signal_catch( void );
66 static void signal_catch();
68 static void signal_catch(){ reschedule=TRUE; }
72 void init_scheduler(){
74 signal(SIGALRM,signal_catch);
79 void schedule() /* Choose next ready process to exec */
80 { /* STRONGLY machine dependent */
84 signal(SIGALRM,signal_catch);
89 c = clock() >> 5; /* the most expensive method */
90 if (reschedule || c != last) /* context switch is needed */
93 #elif MSDOS && ( WORD_16BIT || DWORD_16BIT ) /* DOS real memory model */
96 static char *clk = (char *) 0x0040006CL;
98 if (reschedule || c != last) /* context switch is needed */
104 c = ginf->hundredths >> 3;
105 if (reschedule || c != last) /* context switch is needed */
109 #error Scheduler time counting method not implemented !
113 while (qempty(ready)){ /* wait for event if no processes */
114 tcpip_poll( -1 ); /* wait for message until arrives */
118 while (qempty(ready)) /* wait for event if no processes */
121 ready = qrotate(ready); /* find another ready process */
122 transfer(pfront(ready)); /* transfer control to it */
128 void transfer(pix) /* Context switch to another process */
132 if (pix == thispix) return; /* optimized for case of one process */
134 if( thisp != NULL ) /* previous process is alive */
136 thisp->ic = ic; /* store previous context */
140 thispix = pix; /* and load new context */
141 thisp = &process[ thispix ];
146 param = thisp->param;
147 apt = thisp->prochead+M[ thisp->prochead ];
148 display = apt+dispoff;
149 display2 = apt+disp2off;
153 void activate(pix) /* Resume process on this node */
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 */
160 fprintf(stderr,"activate process %d\n",pix);
165 void passivate(newstatus) /* Passivate process */
168 thisp->status = newstatus; /* change to some wait status */
169 ready = qremove(ready); /* remove from ready queue */
170 reschedule = TRUE; /* force context switch */
172 fprintf(stderr,"passivate process %d to state %d\n",thispix,newstatus);
177 /* Copy parameters from object to message or vice versa. */
180 void moveparams(pix, am, msg, par1, dir)
187 word i, tpd, ap, pd, prim, offset;
192 ptr = prototype[ p->M[ am+PROTNUM ] ];
193 cp = (char *) msg->params;
195 for (i = 0; i < ptr->lthparlist; i++) /* loop through parameters */
198 offset = M[ ptr->parlist+i ];
199 tpd = M[ ptr->pfdescr+i ]; /* type description of param */
203 cflag = ( pd==PARIN || pd==PARINOUT || pd==FORMFUNC || pd==FORMPROC );
205 cflag = ( pd==PAROUT || pd==PARINOUT );
209 if (pd == FORMFUNC || pd == FORMPROC)
215 if (M[ M[ tpd+2 ] ] == CLASSTYPE)
222 prim = M[ tpd+2 ]-ipradr;
223 ap = primapet[ prim ];
224 convert = (prim == 4 || prim == 5); /* process or coroutine */
227 ap *= sizeof(word); /* param appetite in bytes */
229 switch (dir) /* copy parameter in right direction */
234 /* we always load parameters from OUR process */
235 assert(pix==thispix);
240 word ah=M[am+offset];
241 if( !isprocess((virtaddr*)(M+am+offset)) &&
242 M[ ah+1 ] == M[ am+offset+1 ]
244 if (prototype[ M[ M[ ah ]+PROTNUM ] ]->kind == PROCESS)
248 pa.mark = thisp->mark;
251 /*pat errsignal(RTENONGL); */ /* only process may be global */
252 /*pat*/ obj2mess(p->M,(virtaddr*)(p->M+am+offset),&pa);
254 obj2mess(M,(virtaddr*)(M+am+offset),&pa);
258 obj2mess(p->M,(virtaddr*)(p->M+am+offset),&pa);
260 moveblock((char *)&pa, cp, ap=sizeof(procaddr));
262 moveblock((char *) &p->M[ am+offset ], cp, ap);
271 moveblock(cp,(char *)&pa, ap);
272 mess2obj(p,&pa,(virtaddr*)(p->M+am+offset));
274 moveblock(cp, (char *) &p->M[ am+offset ], ap);
280 assert(cp-msg->params <= sizeof(msg->params));
286 word getnode(am) /* Determine node number for process */
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 ] ]);
302 void resume(virt) /* Perform RESUME instruction */
307 if (isprocess(virt)) /* is it process realy ? */
309 msg.control.type = RESUME;
310 obj2mess( M, virt, &msg.control.receiver );
311 sendmsg1( &msg); /* request remote resume */
313 else errsignal(RTEILLRS); /* illegal RESUME */
317 static void createprocess(msg) /* Create new process */
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 */
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));
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);
340 static void killprocess(pix) /* Release process descriptor */
343 qfree(process[ pix ].msgqueue);
344 qfree(process[ pix ].rpcwait);
345 sfree(process[ pix ].rpcmask);
347 process[ pix ].used = FALSE; /* mark descriptor as unused */
348 process[ pix ].mark--; /* decrement marker */
358 static void localkill(msg)
363 pix = msg->control.receiver.pix;
366 fprintf( stderr, "kill process %d\n", pix );
369 if (process[ pix ].mark == msg->control.receiver.mark) /* not none */
371 if (process[ pix ].status != STOPPED) /* is process suspended ? */
372 senderr(RTEILLKL, &msg->control.sender);
378 void endprocess(status) /* Terminate current process */
385 fprintf( stderr, "terminate process %d\n", thispix );
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);
395 static void backcreate(msg)
401 pix = msg->control.receiver.pix;
404 am = p->M[ p->template.addr ]; /* template physical address */
405 p->M[ temporary ] = am;
406 moveparams(pix, am, msg, PAROUT, SAVEPAR);
408 /*store new process address */
409 mess2obj(p,&(msg->control.sender),&(p->backobj));
411 activate(pix); /* end of waiting for NEW */
415 void senderr(exception, virt)
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 */
429 static void localerror(msg)
435 pix = msg->control.receiver.pix;
436 s = process[ pix ].status;
437 if (process[ pix ].mark == msg->control.receiver.mark && s != STOPPED)
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);
448 void askprot(virt) /* Ask for prototype of object */
454 if (isprocess(virt)) /* send question to remote process */
456 obj2mess( M, virt, &msg.control.receiver );
457 msg.control.type = ASKPRO;
459 passivate(WAITASKPRO);
463 if (member(virt, &am))
464 M[ temporary ] = M[ am+PROTNUM ];
465 else errsignal(RTEREFTN);
470 static void ansprot(msg) /* Answer with prototype of process */
476 pix = msg->control.receiver.pix;
477 if (process[ pix ].mark == msg->control.receiver.mark) /* not none */
479 msg1.control.receiver = msg->control.sender;
480 msg1.control.type = PROACK;
481 msg1.control.par = process[ pix ].prot;
484 else senderr(RTEREFTN, &msg->control.sender);
488 /* Message send/receive handling : */
490 void msginterrupt(msg) /* Receive message interrupt handler */
493 moveblock((char *)msg, (char *)&globmsgqueue[ msgtail ],
494 (word) sizeof(message));
495 msgtail = (msgtail+1) % MAXMSGQUEUE;
498 if (msgready < MAXMSGQUEUE-1) /* leave one place for own message */
504 void sendmsg1(msg) /* Send message via net */
507 msg->control.sender.node = ournode;
508 msg->control.sender.pix = thispix;
509 msg->control.sender.mark = thisp->mark;
511 msg->control.receiver.node == ournode
513 msg->control.receiver.node == 0
515 /* simulate receive message interrupt */
518 net_ignore(); /* disable attention */
520 msg->control.receiver.node == ournode;
521 msginterrupt(msg); /* call directly interrupt handler */
526 if (!network) errsignal(RTEINVND); /* send message by net */
527 while (net_send((int) msg->control.receiver.node, msg)) ;
529 if (!network) errsignal(RTEINVND); /* send message by net */
538 void trapmsg() /* Check for waiting message */
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;
554 if (msgready > 0) /* at least one message is waiting */
557 net_ignore(); /* disable attention for a moment */
559 msg = &globmsgqueue[ msghead ]; /* get first message from queue */
560 msghead = (msghead+1) % MAXMSGQUEUE;
562 printf("Received message %d\n",msg->control.type);
565 switch(msg->control.type)
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);
605 pix = msg->control.receiver.pix;
607 p->M[ temporary ] = msg->control.par;
612 fprintf( stderr, " Invalid message\n" );
613 senderr(RTESYSER, &msg->control.sender);
617 if (msgready < MAXMSGQUEUE-1) /* leave one place for own message */
618 net_attention(); /* attention back on */
624 static void mkglobal(ref) /* Make global a process reference */
629 if (!isprocess((virtaddr*)(M+ref)) && M[ ah+1 ] == M[ ref+1 ])
630 if (prototype[ M[ M[ ah ]+PROTNUM ] ]->kind == PROCESS)
636 pa.mark = thisp->mark;
637 mess2obj(thisp,&pa,&va);
639 M[ ref+1 ] = va.mark;
641 fprintf(stderr,"mkglobal REAL (thisp=%d) isprocess:node=%d pix=%d mark=%d\n",thispix,pa.node,pa.pix,pa.mark);fflush(stderr);
644 else errsignal(RTENONGL); /* only process may be global */
650 void show_m( char *s, message *msg ){
652 switch(msg->control.type)
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;
666 printf( "message %s type %s from %d:%d:%d to %d:%d:%d\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