5 #include "intproto.h"
\r
16 /* Process management */
\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
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
44 static void ansprot();
\r
45 static void localkill();
\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
57 PGINFOSEG ginf; /* pointer to Global Info Segment */
\r
62 # include <signal.h>
\r
63 # ifndef NO_PROTOTYPES
\r
64 static void signal_catch( void );
\r
66 static void signal_catch();
\r
68 static void signal_catch(){ reschedule=TRUE; }
\r
72 void init_scheduler(){
\r
74 signal(SIGALRM,signal_catch);
\r
79 void schedule() /* Choose next ready process to exec */
\r
80 { /* STRONGLY machine dependent */
\r
84 signal(SIGALRM,signal_catch);
\r
89 c = clock() >> 5; /* the most expensive method */
\r
90 if (reschedule || c != last) /* context switch is needed */
\r
93 #elif MSDOS && ( WORD_16BIT || DWORD_16BIT ) /* DOS real memory model */
\r
96 static char *clk = (char *) 0x0040006CL;
\r
98 if (reschedule || c != last) /* context switch is needed */
\r
104 c = ginf->hundredths >> 3;
\r
105 if (reschedule || c != last) /* context switch is needed */
\r
109 #error Scheduler time counting method not implemented !
\r
113 while (qempty(ready)){ /* wait for event if no processes */
\r
114 tcpip_poll( -1 ); /* wait for message until arrives */
\r
118 while (qempty(ready)) /* wait for event if no processes */
\r
121 ready = qrotate(ready); /* find another ready process */
\r
122 transfer(pfront(ready)); /* transfer control to it */
\r
123 reschedule = FALSE;
\r
128 void transfer(pix) /* Context switch to another process */
\r
133 if (pix == thispix) return; /* optimized for case of one process */
\r
135 if( thisp != NULL ) /* previous process is alive */
\r
137 thisp->ic = ic; /* store previous context */
\r
142 thispix = pix; /* and load new context */
\r
143 thisp = &process[ thispix ];
\r
148 param = thisp->param;
\r
149 apt = thisp->prochead+M[ thisp->prochead ];
\r
150 display = apt+dispoff;
\r
151 display2 = apt+disp2off;
\r
155 void activate(pix) /* Resume process on this node */
\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
162 fprintf(stderr,"activate process %d\n",pix);
\r
167 void passivate(newstatus) /* Passivate process */
\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
174 fprintf(stderr,"passivate process %d to state %d\n",thispix,newstatus);
\r
179 /* Copy parameters from object to message or vice versa. */
\r
182 void moveparams(pix, am, msg, par1, dir)
\r
189 word i, tpd, ap, pd, prim, offset;
\r
191 bool cflag, convert;
\r
193 p = &process[ pix ];
\r
194 ptr = prototype[ p->M[ am+PROTNUM ] ];
\r
195 cp = (char *) msg->params;
\r
197 for (i = 0; i < ptr->lthparlist; i++) /* loop through parameters */
\r
200 offset = M[ ptr->parlist+i ];
\r
201 tpd = M[ ptr->pfdescr+i ]; /* type description of param */
\r
205 cflag = ( pd==PARIN || pd==PARINOUT || pd==FORMFUNC || pd==FORMPROC );
\r
207 cflag = ( pd==PAROUT || pd==PARINOUT );
\r
211 if (pd == FORMFUNC || pd == FORMPROC)
\r
217 if (M[ M[ tpd+2 ] ] == CLASSTYPE)
\r
224 prim = M[ tpd+2 ]-ipradr;
\r
225 ap = primapet[ prim ];
\r
226 convert = (prim == 4 || prim == 5); /* process or coroutine */
\r
229 ap *= sizeof(word); /* param appetite in bytes */
\r
231 switch (dir) /* copy parameter in right direction */
\r
236 /* we always load parameters from OUR process */
\r
237 assert(pix==thispix);
\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
246 if (prototype[ M[ M[ ah ]+PROTNUM ] ]->kind == PROCESS)
\r
250 pa.mark = thisp->mark;
\r
253 /*pat errsignal(RTENONGL); */ /* only process may be global */
\r
254 /*pat*/ obj2mess(p->M,(virtaddr*)(p->M+am+offset),&pa);
\r
256 obj2mess(M,(virtaddr*)(M+am+offset),&pa);
\r
259 mkglobal(am+offset);
\r
260 obj2mess(p->M,(virtaddr*)(p->M+am+offset),&pa);
\r
262 moveblock((char *)&pa, cp, ap=sizeof(procaddr));
\r
264 moveblock((char *) &p->M[ am+offset ], cp, ap);
\r
272 ap=sizeof(procaddr);
\r
273 moveblock(cp,(char *)&pa, ap);
\r
274 mess2obj(p,&pa,(virtaddr*)(p->M+am+offset));
\r
276 moveblock(cp, (char *) &p->M[ am+offset ], ap);
\r
282 assert(cp-msg->params <= sizeof(msg->params));
\r
288 word getnode(am) /* Determine node number for process */
\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
304 void resume(virt) /* Perform RESUME instruction */
\r
309 if (isprocess(virt)) /* is it process realy ? */
\r
311 msg.control.type = RESUME;
\r
312 obj2mess( M, virt, &msg.control.receiver );
\r
313 sendmsg( &msg); /* request remote resume */
\r
315 else errsignal(RTEILLRS); /* illegal RESUME */
\r
319 static void createprocess(msg) /* Create new process */
\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
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
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
343 static void killprocess(pix) /* Release process descriptor */
\r
346 qfree(process[ pix ].msgqueue);
\r
347 qfree(process[ pix ].rpcwait);
\r
348 sfree(process[ pix ].rpcmask);
\r
350 process[ pix ].used = FALSE; /* mark descriptor as unused */
\r
351 process[ pix ].mark--; /* decrement marker */
\r
353 if( pix == thispix )
\r
361 static void localkill(msg)
\r
366 pix = msg->control.receiver.pix;
\r
369 fprintf( stderr, "kill process %d\n", pix );
\r
372 if (process[ pix ].mark == msg->control.receiver.mark) /* not none */
\r
374 if (process[ pix ].status != STOPPED) /* is process suspended ? */
\r
375 senderr(RTEILLKL, &msg->control.sender);
\r
381 void endprocess(status) /* Terminate current process */
\r
386 passivate(STOPPED);
\r
388 fprintf( stderr, "terminate process %d\n", thispix );
\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
398 static void backcreate(msg)
\r
404 pix = msg->control.receiver.pix;
\r
405 p = &process[ pix ];
\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
411 /*store new process address */
\r
412 mess2obj(p,&(msg->control.sender),&(p->backobj));
\r
414 activate(pix); /* end of waiting for NEW */
\r
418 void senderr(exception, virt)
\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
432 static void localerror(msg)
\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
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
451 void askprot(virt) /* Ask for prototype of object */
\r
457 if (isprocess(virt)) /* send question to remote process */
\r
459 obj2mess( M, virt, &msg.control.receiver );
\r
460 msg.control.type = ASKPRO;
\r
462 passivate(WAITASKPRO);
\r
466 if (member(virt, &am))
\r
467 M[ temporary ] = M[ am+PROTNUM ];
\r
468 else errsignal(RTEREFTN);
\r
473 static void ansprot(msg) /* Answer with prototype of process */
\r
479 pix = msg->control.receiver.pix;
\r
480 if (process[ pix ].mark == msg->control.receiver.mark) /* not none */
\r
482 msg1.control.receiver = msg->control.sender;
\r
483 msg1.control.type = PROACK;
\r
484 msg1.control.par = process[ pix ].prot;
\r
487 else senderr(RTEREFTN, &msg->control.sender);
\r
491 /* Message send/receive handling : */
\r
493 void msginterrupt(msg) /* Receive message interrupt handler */
\r
496 moveblock((char *)msg, (char *)&globmsgqueue[ msgtail ],
\r
497 (word) sizeof(message));
\r
498 msgtail = (msgtail+1) % MAXMSGQUEUE;
\r
501 if (msgready < MAXMSGQUEUE-1) /* leave one place for own message */
\r
507 void sendmsg(msg) /* Send message via net */
\r
510 msg->control.sender.node = ournode;
\r
511 msg->control.sender.pix = thispix;
\r
512 msg->control.sender.mark = thisp->mark;
\r
514 msg->control.receiver.node == ournode
\r
516 msg->control.receiver.node == 0
\r
518 /* simulate receive message interrupt */
\r
521 net_ignore(); /* disable attention */
\r
523 msg->control.receiver.node == ournode;
\r
524 msginterrupt(msg); /* call directly interrupt handler */
\r
529 if (!network) errsignal(RTEINVND); /* send message by net */
\r
530 while (net_send((int) msg->control.receiver.node, msg)) ;
\r
532 if (!network) errsignal(RTEINVND); /* send message by net */
\r
535 errsignal(RTEINVND);
\r
541 void trapmsg() /* Check for waiting message */
\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
557 if (msgready > 0) /* at least one message is waiting */
\r
560 net_ignore(); /* disable attention for a moment */
\r
562 msg = &globmsgqueue[ msghead ]; /* get first message from queue */
\r
563 msghead = (msghead+1) % MAXMSGQUEUE;
\r
564 switch(msg->control.type)
\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
580 createprocess(msg);
\r
604 pix = msg->control.receiver.pix;
\r
605 p = &process[ pix ];
\r
606 p->M[ temporary ] = msg->control.par;
\r
611 fprintf( stderr, " Invalid message\n" );
\r
612 senderr(RTESYSER, &msg->control.sender);
\r
616 if (msgready < MAXMSGQUEUE-1) /* leave one place for own message */
\r
617 net_attention(); /* attention back on */
\r
623 static void mkglobal(ref) /* Make global a process reference */
\r
628 if (!isprocess((virtaddr*)(M+ref)) && M[ ah+1 ] == M[ ref+1 ])
\r
629 if (prototype[ M[ M[ ah ]+PROTNUM ] ]->kind == PROCESS)
\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
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
643 else errsignal(RTENONGL); /* only process may be global */
\r
649 void show_m( char *s, message *msg ){
\r
651 switch(msg->control.type)
\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
664 printf( "message %s type %s from %d:%d:%d to %d:%d:%d\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