Update to the newest upstream version.
[vlp.git] / int / cint.c
1  
2
3 #include "depend.h"
4 #include "genint.h"
5 #include "int.h"
6 #include "process.h"
7 #include "intproto.h"
8 #include "socu.h"
9 #include <fcntl.h>
10 #include <sys/stat.h>
11 #include <sys/time.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <errno.h>
15 #include <netdb.h>
16 #include <qthread.h>
17
18 #ifndef NO_PROTOTYPES
19 static void load(char *);
20 static void initiate(int,char **);
21 int main(int,char **);
22 #else
23 static void load();
24 static void initiate();
25 int main();
26 #endif
27
28
29
30 int internal_sock,graph_sock,net_sock,connected=0;
31 struct sockaddr_un svr;
32 int GraphRes=-1;
33 char ProgName[255],mygname[80], gname[80],mykname[80], nname[80], mynname[80];
34 fd_set DirSet;
35 int maxDirSet;
36
37 ctx_struct my_ctx;
38 ctx_struct parent_ctx;
39
40 int RInstance[255]; /* IDs of remote instances */
41 int DirConn[255];   /* Direct connection channels */
42
43 /* graphic vars */
44 int fcol, bcol, curx=0, cury=0;
45
46
47
48 /* Macro to decode addressing modes : */
49 #define getargument(a, argnr)                                       \
50     switch (eop->args[ argnr ])                                     \
51     {                                                               \
52         case GLOBAL     : a = M[ ic++ ];             break;         \
53         case LOCAL      : a = c1+M[ ic++ ];          break;         \
54         case TEMPLOCAL  : a = c2+M[ ic++ ];          break;         \
55         case REMOTE     : a = M[ M[ ic+1 ] ]+M[ ic ];  ic+=2; break;\
56         case INDIRECT   : a = M[ M[ ic++ ] ];                 break;\
57         case IMMEDIATE  : a = ic++;                           break;\
58         case CONSTANT  : a = M[ ic++ ];                       break;\
59         case DOTACCESS : a = M[ display+M[ ic+1 ] ]+M[ ic ];  ic += 2; break;\
60         case NOARGUMENT : return;                          \
61     }
62
63
64 static void load(_filename)     /* Load code and prototypes from file */
65    char *_filename;
66 {
67     FILE *fp;
68     char *cp;
69     word n, left;
70     char filename[100]; /* should suffice on all systems */
71
72     strcpy( filename, _filename );
73     M = mallocate(memorysize+1);        /* allocate main memory array */
74     if (M == NULL) abend("Memory size too large (use /m option)\n");
75
76     addext(filename, ".ccd");
77     if ((fp = fopen(filename, BINARYREAD)) == NULL)
78         {
79            fprintf(stderr,"Cannot open .ccd file\n");
80            endrun(10);
81          };
82
83     ic = 0;              /* read static data and code */
84     left = memorysize+1;               /* from .ccd file */
85     do
86     {
87         if (left == 0) abend("Memory size too small (use /m option)\n");
88         n = min(IOBLOCK/sizeof(word), left);
89         n = fread((char *) &M[ ic ], sizeof(word), (int) n, fp);
90         ic += n;
91         left -= n;
92     } while (n != 0);      /* now ic = number of words read */
93
94     fclose(fp);
95     /* Get various addresses passed by GENERATOR */
96     ipradr    = M[ ic-5 ];           /* primitive type desctriptions */
97     temporary = M[ ic-4 ];           /* global temporary variables */
98     strings   = M[ ic-3 ];           /* string constants */
99     lastprot  = M[ ic-2 ];           /* last prototype number */
100     freem     = M[ ic-1 ];           /* first free word in memory */
101
102     /* Read prototypes from .pcd file */
103     addext(filename, ".pcd");
104     if ((fp = fopen(filename, BINARYREAD)) == NULL)
105        {
106          fprintf(stderr,"Cannot open .pcd file\n");
107          endrun(10); 
108         }
109     for (n = MAINBLOCK;  n <= lastprot;  n++ )
110     {
111         cp = ballocate(sizeof(protdescr));
112         if (cp == NULL) abend("Memory size too large (use /m option)\n");
113         prototype[ n ] = (protdescr *) cp;
114         if (fread(cp, sizeof(protdescr), 1, fp) != 1)
115             abend("Cannot read .pcd file\n");
116     }
117     fclose(fp);
118
119     /* Open trace file */
120     if (debug)
121     {
122         addext(filename, ".trd");
123         if ((tracefile = fopen(filename, "w")) == NULL)
124             abend("Cannot open .trd file\n");
125     }
126 } /* end load */
127
128
129 static void initiate(argc, argv)        /* Establish configuration parameters */
130 int argc;
131 char **argv;
132 {
133     long m;
134     int len,i,on;
135     char filename[80];
136     int sock;
137     fd_set rset,wset;
138
139      ournode = 0;
140      network = TRUE;
141     if ( (argc==4) && (strcmp(argv[3],"r") == 0) ) remote = TRUE;else remote=FALSE;
142       for(i=0;i<255;i++)
143       {
144         RInstance[i] = -1;
145         DirConn[i] = -1;
146       }
147       
148     FD_ZERO(&DirSet);    
149     maxDirSet=0;
150  
151     strcpy(filename,argv[2]);
152     strcpy(ProgName,argv[2]);
153
154     strcpy(mynname,argv[1]);
155     strcat(mynname,".net");
156     unlink(mynname);
157     sock = socket(AF_UNIX,SOCK_STREAM,0); 
158     bzero(&svr, sizeof(svr));
159     svr.sun_family = AF_UNIX;
160     strcpy(svr.sun_path,mynname);
161     len = strlen(svr.sun_path)+sizeof(svr.sun_family);
162     bind(sock,(struct sockaddr*)&svr, len);
163     listen(sock,5);
164
165
166    /* socket for graphic requests */ 
167     strcpy(mygname,argv[1]);
168     strcat(mygname,".gr");
169     unlink(mygname);
170    
171
172    /* socket for KERNEL communication */  
173       internal_sock = socket(AF_UNIX,SOCK_STREAM,0);
174       bzero(&svr, sizeof(svr));
175       svr.sun_family = AF_UNIX;
176       strcpy(svr.sun_path,argv[1]);
177       strcpy(mykname,argv[1]);
178       len = strlen(svr.sun_path)+sizeof(svr.sun_family);
179       i=connect(internal_sock,(struct sockaddr*)&svr,len);
180      
181     if (i==0)
182        { 
183         fcntl(internal_sock,F_SETFL, O_NONBLOCK|fcntl(internal_sock,F_GETFL,0));
184         }
185     else
186      while (i!=0)
187     {
188       close(internal_sock);
189       internal_sock = socket(AF_UNIX,SOCK_STREAM,0);
190       fcntl(internal_sock,F_SETFL, O_NONBLOCK|fcntl(internal_sock,F_GETFL,0));
191       i=connect(internal_sock,(struct sockaddr*)&svr,len);     
192     }    
193     on=1;
194     setsockopt(internal_sock,IPPROTO_TCP,TCP_NODELAY,(char*)&on,sizeof(on));
195     
196     /* socket for network requests */
197      FD_ZERO(&rset);FD_ZERO(&wset);
198      FD_SET(sock,&rset);
199      if (select(sock+1,&rset,&wset,0,0))
200       net_sock = accept(sock,(struct sockaddr*)0,(int *)0);
201     if (net_sock>0)
202     {
203      fcntl(net_sock,F_SETFL,O_NONBLOCK|fcntl(net_sock,F_GETFL,0));
204      setsockopt(net_sock,IPPROTO_TCP,TCP_NODELAY,(char*)&on,sizeof(on));
205
206     }
207     close(sock);
208
209     if( filename!=NULL )
210        load(filename);                     /* load code and prototypes */
211     else
212        usage();
213 }
214
215
216 void decode(){
217     extopcode *eop;
218
219     eop = (extopcode *)(M+ic);   /* pointer to extended opcode in M */
220     lastic = ic;                     /* save ic for possible redecoding */
221     ic += APOPCODE;
222     opcode = ((int) eop->opcode ) & 0xFF ;
223     getargument(a1, 0);
224     getargument(a2, 1);
225     getargument(a3, 2);
226 }
227
228 /* -------------------------------------------------------------------- */
229
230
231 void send_to_graph(G_MESSAGE *msg)
232 {
233  write(graph_sock,msg,sizeof(G_MESSAGE));
234 }
235
236 int read_from_graph(G_MESSAGE *msg)
237 {
238  fd_set rset,wset;
239  struct timeval tout={0,0};
240  
241  FD_ZERO(&rset);FD_ZERO(&wset);
242  FD_SET(graph_sock,&rset);
243  
244   
245  if (select(graph_sock+1,&rset,&wset,0,(struct timeval *)&tout)>0)
246  {
247   if (FD_ISSET(graph_sock,&rset))
248    return(read(graph_sock,msg,sizeof(G_MESSAGE)));
249  }
250  return(0);  
251 }
252
253 int read_from_net(MESSAGE *msg)
254 {
255  fd_set rset,wset;
256  struct timeval tout={0,0};
257  
258  FD_ZERO(&rset);FD_ZERO(&wset);
259  FD_SET(net_sock,&rset);
260  
261   
262  if (select(net_sock+1,&rset,&wset,0,(struct timeval *)&tout)>0)
263  {
264   if (FD_ISSET(net_sock,&rset))
265    return(read(net_sock,msg,sizeof(MESSAGE)));
266  }
267  return(0);  
268 }
269
270
271 /* Get graphic resource number */
272 int get_graph_res()
273 {
274  MESSAGE msg;
275  int sock;
276  struct sockaddr_un svr;
277  int len,i,on;
278  fd_set rset,wset;
279
280  unlink(mygname);
281  sock = socket(AF_UNIX,SOCK_STREAM,0);
282  bzero(&svr,sizeof(svr));
283  svr.sun_family = AF_UNIX;
284  strcpy(svr.sun_path,mygname);
285  len = strlen(svr.sun_path)+sizeof(svr.sun_family);
286  bind(sock,(struct sockaddr*)&svr, len);      
287  listen(sock,5);
288
289
290  msg.msg_type = MSG_GRAPH;
291  msg.param.pword[0] = GRAPH_ALLOCATE;
292  strcpy(msg.param.pstr,mygname);
293  write(internal_sock,&msg,sizeof(MESSAGE));
294  bzero(&msg,sizeof(MESSAGE));
295  FD_ZERO(&rset);FD_ZERO(&wset);
296  FD_SET(sock,&rset);
297   if (select(sock+1,&rset,&wset,0,0))
298     graph_sock = accept(sock,(struct sockaddr*)0,(int*)0);
299  
300  if (graph_sock == -1)
301  {
302    graphics=FALSE;return(0);
303  }
304   on=1;
305   close(sock);
306   fcntl(graph_sock,F_SETFL, O_NONBLOCK|fcntl(graph_sock,F_GETFL,0));
307   setsockopt(graph_sock,IPPROTO_TCP,TCP_NODELAY,(char*)&on,sizeof(on));
308
309   return(1);
310    
311 } /* get_graph_res */
312
313
314 /* writeln string */
315 void writeln_str(char *s)
316 {
317  G_MESSAGE msg;
318  msg.msg_type = MSG_GRAPH;
319  msg.param.pword[1] = GraphRes;
320  msg.param.pword[2] = GRAPH_WRITE;
321  strcpy(msg.param.pstr,s);
322  
323  send_to_graph(&msg);
324  strcpy(msg.param.pstr,"\n");
325  send_to_graph(&msg);
326 }
327
328 /* write string */
329 void write_str(char *s)
330 {
331  G_MESSAGE msg;
332  msg.msg_type = MSG_GRAPH;
333  msg.param.pword[1] = GraphRes;
334  msg.param.pword[0] = GRAPH_WRITE;
335  strcpy(msg.param.pstr,s);
336  send_to_graph(&msg);
337 }
338
339 /* write char */
340 void write_char(char a)
341 {
342  G_MESSAGE msg;
343
344  msg.msg_type = MSG_GRAPH;
345  msg.param.pword[1] = GraphRes;
346  msg.param.pword[0] = GRAPH_PUTCHAR;
347  msg.param.pchar = a;
348  send_to_graph(&msg);
349 }
350
351
352 /* read char */
353 char read_char()
354 {
355  char ch;
356  G_MESSAGE msg;
357  int st;
358
359
360   msg.msg_type = MSG_GRAPH;
361   msg.param.pword[1] = GraphRes;
362   msg.param.pword[0] = GRAPH_READCHAR;
363   send_to_graph(&msg);
364   while(TRUE)
365       {
366        st = read_from_graph(&msg);
367        if (st>0)
368          {
369           if ((msg.msg_type == MSG_GRAPH) && 
370               (msg.param.pword[0]==GRAPH_READCHAR_RESPONSE)) 
371             {ch = msg.param.pchar;break;}
372          }
373        }
374  return(ch);
375
376 }
377
378 /* read line */
379 void read_line()
380 {
381  G_MESSAGE msg;
382  int st;
383
384
385   msg.msg_type = MSG_GRAPH;
386   msg.param.pword[1] = GraphRes;
387   msg.param.pword[0] = GRAPH_READLN;
388   send_to_graph(&msg);
389   while(TRUE)
390       {
391        st = read_from_graph(&msg);
392        if (st>0)
393          if ((msg.msg_type == MSG_GRAPH) && (msg.param.pword[0]== GRAPH_READLN_RESPONSE))
394           break;
395        }
396 }
397
398 /* read string */
399 void read_str(char *s)
400 {
401  char ss[255];
402  G_MESSAGE msg;
403  int st;
404
405   msg.msg_type = MSG_GRAPH;
406   msg.param.pword[1] = GraphRes;
407   msg.param.pword[0] = GRAPH_READSTR;
408   send_to_graph(&msg);
409   while(TRUE)
410       {
411        st = read_from_graph(&msg);
412        if (st>0)
413          {
414           if ((msg.msg_type == MSG_GRAPH) && 
415               (msg.param.pword[0]==GRAPH_READSTR_RESPONSE)) 
416             { strcpy(ss,msg.param.pstr);break;}
417          }
418        }
419  strcpy(s,ss);
420
421 }
422
423
424 /* send message to kernel */
425 void send_to_kernel(MESSAGE *msg)
426 {
427  write(internal_sock,msg,sizeof(MESSAGE));
428 }
429
430 /* send message to net */
431 /* 2010 returns 1 if ok and 0 if node desn't exists */
432 int send_to_net(MESSAGE *msg)
433 {
434  int k,len;
435  MESSAGE m;
436  struct sockaddr_in svr;
437  char addr[256];
438
439  
440  k = msg->int_msg.control.receiver.node; 
441
442  /* 2010 check if node exists */
443  m.msg_type = MSG_NET;
444  m.param.pword[0] = NET_NODE_EXIST;
445  m.param.pword[1] = k;
446  m.param.pword[2] = my_ctx.program_id;
447  write(net_sock,&m,sizeof(MESSAGE));
448  bzero(&m,sizeof(MESSAGE));
449  while( (m.msg_type!=MSG_NET) && (m.param.pword[0]!=NET_NODE_EXIST) )
450   read(net_sock,&m,sizeof(MESSAGE));
451  if (m.param.pword[1]!=1) return 0;
452  strcpy(addr,m.param.pstr);
453
454  if (RInstance[k]==-1)
455   { 
456    bzero(&m,sizeof(MESSAGE));
457    m.msg_type = MSG_VLP;
458    m.param.pword[0] = VLP_REMOTE_INSTANCE_PLEASE;
459    m.param.pword[1] = my_ctx.program_id;
460    m.param.pword[2] = k;
461    send_to_kernel(&m);
462    bzero(&m,sizeof(MESSAGE));
463    
464    while(1)
465      {
466        read(internal_sock,&m,sizeof(MESSAGE));
467        if ( (m.msg_type == MSG_VLP) && (m.param.pword[0]==VLP_REMOTE_INSTANCE_HERE)) break;
468       }
469       
470    /*printf("DEBUG: remote instance made with id: %d addr %s port %d\n",m.param.pword[1],addr, htons(m.param.pword[8]));*/
471    RInstance[k] = m.param.pword[1];
472    /* Make direct connection */
473    DirConn[k] = socket(AF_INET,SOCK_STREAM,0);
474    svr.sin_family = AF_INET;
475    svr.sin_addr.s_addr = inet_addr(addr);
476    svr.sin_port = htons(m.param.pword[8]);
477    len = connect(DirConn[k],(struct sockaddr*)&svr,sizeof(svr));
478    if (len!=0) 
479     {
480      RInstance[k]=-1;
481      
482      writeln_str("Cannot connect remote instance!");
483     }
484    else
485      {
486       fcntl(DirConn[k], F_SETFL,O_NONBLOCK | fcntl(DirConn[k], F_GETFL,0));
487      } 
488    }
489    if (RInstance[k]!=-1)
490    {
491       
492       write(DirConn[k],&(msg->int_msg),sizeof(message)); 
493    } 
494    return 1;
495 }
496
497
498
499 /* -------------------- Check for message on internal socket -------------*/
500
501
502 void get_internal()
503 {
504  MESSAGE m,m1;
505  message mx;
506  
507  int r,max,i;
508  char s[80];
509  fd_set rset;
510  struct timeval tout={0,0};
511  
512  
513
514  /* 2010 */
515  /* ----------- Direct connection messages -----
516  FD_ZERO(&DirSet);
517  maxDirSet=0;
518  for(i=0;i<255;i++)
519   if (DirConn[i]!=-1) 
520    {
521     FD_SET(DirConn[i],&DirSet);
522     if (maxDirSet<DirConn[i]) maxDirSet=DirConn[i];
523    }
524  
525  if (select(maxDirSet+1,&DirSet,0,0,(struct timeval *)&tout)>0)
526   {
527    for(i=0;i<255;i++)
528    {
529     if ( (DirConn[i]!=-1) && (FD_ISSET(DirConn[i],&DirSet)) )
530     {
531      r=read(DirConn[i],&mx,sizeof(mx));
532      if (r>0)
533      {
534       memcpy(globmsgqueue+msgtail,&mx,sizeof(message));
535       msgtail = (msgtail+1) % MAXMSGQUEUE;
536       msgready++;
537      } 
538     }
539    }
540    }
541  -----------------------------------------*/
542  
543  
544  FD_ZERO(&rset);
545  FD_SET(net_sock,&rset);
546  FD_SET(internal_sock,&rset); 
547  if (net_sock>internal_sock) max = net_sock; else max = internal_sock;
548  /* 2010 */
549  for(i=0;i<255;i++) {
550   if (DirConn[i]!=-1) 
551    {
552     FD_SET(DirConn[i],&rset);
553     if (max<DirConn[i]) max=DirConn[i];
554    }
555  } /* for */
556   
557  if (select(max+1,&rset,0,0,(struct timeval *)&tout)>0)
558  {
559  
560   /* 2010 */
561   for(i=0;i<255;i++)
562    {
563     if ( (DirConn[i]!=-1) && (FD_ISSET(DirConn[i],&rset)) )
564     {
565      /*printf("DEBUG: Interp has message on direct connection: type %d par %d\n",mx.control.type,mx.control.par);  */
566      r=read(DirConn[i],&mx,sizeof(mx));
567      if (r>0 && r==sizeof(mx))
568      {      
569       memcpy(globmsgqueue+msgtail,&mx,sizeof(message));
570       msgtail = (msgtail+1) % MAXMSGQUEUE;
571       msgready++;
572      } 
573     }
574    }
575
576
577
578
579  if (FD_ISSET(net_sock,&rset))
580  {
581  r = read(net_sock, &m, sizeof(MESSAGE));
582  if (r>0)
583  {
584    switch(m.msg_type)
585    {
586      case MSG_NET:
587                   switch(m.param.pword[0])
588                   {
589                    case NET_PROPAGATE:
590                     /*printf("DEBUG: cint net_sock MSG_NET NET_PROPAGATE cmd %d\n",m.param.pword[6]);*/
591                     memcpy(globmsgqueue+msgtail,&m.int_msg,sizeof(message));
592                     msgtail = (msgtail+1) % MAXMSGQUEUE;
593                     msgready++;
594                    break;
595                   }; break;
596     } /*switch */
597  }
598   } /* FD_ISSET */
599  
600  if (FD_ISSET(internal_sock,&rset))
601  {
602  r = read(internal_sock,&m,sizeof(MESSAGE));
603
604  if (r>0)
605  {
606   switch(m.msg_type)
607   {
608     case MSG_INT:
609                switch(m.param.pword[0])
610                { 
611                 case INT_CLOSE_INSTANCE: endrun(0);
612                 case INT_KILL: endrun(1);                     
613                 default:break;     
614                } /* switch int */
615     case MSG_NET: 
616             if (m.param.pword[0] == NET_PROPAGATE)
617             {
618              /*printf("DEBUG: cint internal_sock MSG_NET NET_PROPAGATE cmd %d\n",m.param.pword[6]);*/
619              memcpy(globmsgqueue+msgtail,&m.int_msg,sizeof(message));
620              msgtail = (msgtail+1) % MAXMSGQUEUE;
621              msgready++;
622             };break;           
623     
624     
625     
626   }/*switch type */
627  }
628  } /* FD_ISSET */
629  } /* select */
630
631 }
632
633
634 void request_id()
635 {
636  MESSAGE m;
637  G_MESSAGE m1; 
638  
639  m.msg_type = MSG_INT;
640  m.param.pword[0] = INT_CTX_REQ;
641  send_to_kernel(&m);
642  while ( (m.msg_type != MSG_INT) || (m.param.pword[0] != INT_CTX) )
643   read(internal_sock,&m,sizeof(MESSAGE));
644   
645     my_ctx.node = m.param.pword[1];
646     my_ctx.program_id = m.param.pword[2];
647     if (remote)
648             {
649               parent_ctx.node = m.param.pword[3];
650               parent_ctx.program_id = m.param.pword[4];
651               RInstance[parent_ctx.node] = parent_ctx.program_id;
652             }
653               else
654         {
655          parent_ctx.node = my_ctx.node;
656          parent_ctx.program_id = my_ctx.program_id;
657         } 
658   ournode = my_ctx.node;
659 //  strcpy(nname,m.param.pstr);
660 //  net_sock = open(nname,O_WRONLY);
661   m1.msg_type = MSG_GRAPH;
662   m1.param.pword[0] = GRAPH_SET_TITLE;
663   m1.param.pword[1] = GraphRes;
664   sprintf(m1.param.pstr,
665   "%s      ID: %d",ProgName,my_ctx.program_id);       
666   if (remote) strcat(m1.param.pstr,"  REMOTE instance");
667   send_to_graph(&m1);
668 }
669
670
671
672 void send_ready()
673 {
674  int sock,len;
675  struct sockaddr_in svr;
676  char name[255];
677  struct hostent *info;
678  
679
680  MESSAGE msg;
681  msg.msg_type = MSG_NET;
682  msg.param.pword[0] = NET_PROPAGATE;
683  msg.param.pword[1] = MSG_VLP;
684  msg.param.pword[2] = my_ctx.node;
685  msg.param.pword[4] = parent_ctx.node;
686  msg.param.pword[6] = VLP_REMOTE_INSTANCE_OK;
687  msg.param.pword[7] = my_ctx.program_id;
688  
689  sock = socket(AF_INET,SOCK_STREAM,0);
690  bzero(&svr,sizeof(svr));
691  svr.sin_family = AF_INET;
692  svr.sin_addr.s_addr = INADDR_ANY;
693  svr.sin_port = 0;
694  bind(sock, (struct sockaddr*)&svr, sizeof(svr));
695  listen(sock,5);
696  len=sizeof(svr);
697  getsockname(sock,(struct sockaddr*)&svr,&len);
698  msg.param.pword[8] = ntohs(svr.sin_port);
699  gethostname(name,&len);
700  info = (struct hostent*)gethostbyname(name);
701  bcopy((char*)info->h_addr,(char*)&svr.sin_addr,info->h_length);
702  sprintf(msg.param.pstr,"%s",inet_ntoa(svr.sin_addr));
703  send_to_kernel(&msg);
704  
705  bzero(&svr,sizeof(svr));
706  DirConn[parent_ctx.node] = accept(sock,(struct sockaddr*)&svr,&len);
707  fcntl(DirConn[parent_ctx.node], F_SETFL,O_NONBLOCK | fcntl(DirConn[parent_ctx.node], F_GETFL,0));
708 }
709
710 int main(argc, argv)
711 int argc;
712 char **argv;
713 {
714     initiate(argc, argv);             /* initialize executor */
715     runsys();              /* initialize running system */
716     init_scheduler();
717     GraphRes = get_graph_res();
718     if ( GraphRes < 0 ) exit(12); 
719      
720     request_id();
721     if (remote) send_ready(); 
722
723
724     setjmp(contenv);         /* set label for continue long jump */
725     while (TRUE)                     /* repeat until exit() is called */
726     {
727         get_internal();        
728         schedule();         /* reschedule current process */
729    if (ready != 0)
730     {   
731         decode();               /* fetch instruction */
732         execute();            /* and execute it */
733     } 
734        
735     }
736     return 0;
737 } /* end main */
738