1 e˙builtin.c
\0\0\0\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0p
\ 5/* $Id: builtin.c,v 1.5 1994/06/24 12:27:56 ceriel Exp $ */
3 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4 * See the copyright notice in the ACK home directory, in the file "Copyright".
7 /* builtin.c - built in named processes */
15 static void nullterm(s) register char *s;
16 /* Change Occam string to C string */
18 register len= (*s & 0377);
28 static void lenterm(s) register char *s;
29 /* Change C string to Occam string */
43 void b_open(mode, name, index) register char *mode, *name; long *index;
44 /* PROC open(VAR index, VALUE name[], mode[])= */
60 /* Find free file channel, there must be one free! */
62 for (i=0; (file[i].f.flgs&C_F_INUSE)!=0; i++) ;
64 file[i].f.flgs|=C_F_INUSE;
70 void b_close(index) long index;
71 /* PROC close(VALUE index)= */
73 fclose(unix_file[index]);
74 file[index].f.flgs&= ~C_F_INUSE;
77 void b_exit(code) long code;
78 /* PROC exit(VALUE code)= */
82 chan_strct.c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0\11\ 3/* $Id: chan_strct.c,v 1.3 1994/06/24 12:28:01 ceriel Exp $ */
83 /* chan_struct.c - channel routines for more structured objects */
86 void cbyte_in(b, c) char *b; chan *c;
93 void c_wa_in(a, z, c) register long *a; register unsigned z; register chan *c;
100 void c_ba_in(a, z, c) register char *a; register unsigned z; register chan *c;
109 void c_wa_out(a, z, c) register long *a; register unsigned z; register chan *c;
116 void c_ba_out(a, z, c) register char *a; register unsigned z; register chan *c;
119 chan_out((long) (*a++ &0377), c);
122 dchannel.c
\0.c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0¬
\ f/* $Id: channel.c,v 1.12 1994/06/24 12:28:06 ceriel Exp $ */
123 /* channel.c - basic channel handling routines */
129 #include "ocm_chan.h"
131 static void disaster();
133 void c_init(c, z) register chan *c; register unsigned z;
134 /* Initialise an array of interprocess channels declared as: CHAN c[z]. */
138 (c++)->c.synch=C_S_FREE;
142 void chan_in(v, c) long *v; register chan *c;
143 /* Reads a value from channel c and returns it through v. */
147 if ((c->f.flgs&C_F_READAHEAD)!=0) {
148 *v=(c->f.preread&0377);
149 c->f.flgs&= ~C_F_READAHEAD;
151 register FILE *fp= unix_file[c->f.index];
153 *v= feof(fp) ? C_F_EOF : getc(fp);
157 deadlock=0; /* Wait for value to arrive */
158 while (c->c.synch!=C_S_ANY) resumenext();
161 c->c.synch=C_S_ACK; /* Acknowledge receipt */
168 void chan_out(v, c) long v; register chan *c;
169 /* Send value v through channel c. */
173 register FILE *fp= unix_file[c->f.index];
176 if ((v& ~0xff)==0) /* Plain character */
180 gtty(fileno(fp), &tty);
181 tty.sg_flags&= ~CBREAK;
182 tty.sg_flags|= ECHO|CRMOD;
183 stty(fileno(fp), &tty);
186 gtty(fileno(fp),&tty);
187 tty.sg_flags|= CBREAK;
188 tty.sg_flags&= ~(ECHO|CRMOD);
189 stty(fileno(fp), &tty);
193 deadlock=0; /* Wait until channel is free */
194 while (c->c.synch!=C_S_FREE) resumenext();
197 c->c.synch=C_S_ANY; /* Channel has data */
199 deadlock=0; /* Wait for acknowledgement */
200 while (c->c.synch!=C_S_ACK) resumenext();
202 c->c.synch=C_S_FREE; /* Back to normal */
210 static void timeout();
213 int chan_any(c) register chan *c;
221 if ((c->f.flgs&C_F_READAHEAD)!=0)
224 register FILE *fp= unix_file[c->f.index];
233 /* No deadlock while waiting for key */
235 /* Unfortunately, the mechanism that was used
236 here does not work on all Unix systems.
237 On BSD 4.2 and newer, the "read" is
238 automatically restarted. Therefore, on
239 these systems, we try it with non-blocking
243 flags = fcntl(fileno(fp), F_GETFL, 0);
244 fcntl(fileno(fp), F_SETFL, flags | O_NDELAY);
247 fcntl(fileno(fp), F_SETFL, flags);
248 if (errno == EWOULDBLOCK) {
253 signal(SIGALRM, timeout);
259 signal(SIGALRM, SIG_IGN);
269 c->f.flgs|=C_F_READAHEAD;
277 return c->c.synch==C_S_ANY;
284 /* The ch=getc(fp) in the above function calls read(2) to do its task, but if
285 * there's no input on the file (pipe or terminal) then the read will block.
286 * To stop this read from blocking, we use the fact that if the read is
287 * interrupted by a signal that is caught by the program, then the read returns
288 * error EINTR after the signal is processed. Thus we use a one second alarm
289 * to interrupt the read with a trap to timeout(). But since the alarm signal
290 * may occur *before* the read is called, it is continuously restarted in
291 * timeout() to prevent it from getting lost.
294 static void timeout(sig)
296 signal(SIGALRM, timeout);
301 static void disaster()
303 write(2, "Fatal error: Channel variable corrupted\n", 40);
306 co.c
\0el.c
\0.c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0+ /* $Id: co.c,v 1.4 1994/06/24 12:28:11 ceriel Exp $ */
307 /* co.c - Routines to handle coroutines */
308 #include "ocm_proc.h"
310 static void search(), RESUMERR();
312 void resume(id) identification id;
313 /* Stops the current process, by saving its stack, and searches for the
314 * process with identification 'id' in the group the running process
315 * belongs to. If 'id' cannot be found then repeat these actions with
316 * the running process' parent. If 'id' is found it is activated. It
317 * is a fatal error if 'id' cannot be found.
321 register wordsize size;
323 size=top_size(group->s_brk);
324 (*group->active)->stack=alloc((unsigned) size);
326 if (top_save(size, (*group->active)->stack))
329 free((*group->active)->stack);
336 static void search(id) identification id;
337 /* Searches for the process with identification 'id'.
338 * If the process is found it is activated and its process tree is
339 * traversed to find the running process.
342 register struct process **aproc, *proc;
345 aproc= &group->first;
347 while (*aproc!=nil && (*aproc)->id!=id)
348 aproc= &(*aproc)->next;
350 if (*aproc!=nil) break;
354 if ((group=group->up)==nil)
361 while (proc->down!=nil) {
363 proc= *group->active;
365 top_load(proc->stack);
368 static void delete_group(group) struct procgroup *group;
369 /* Removes the whole group and sub-groups recursively from the running
373 register struct process *proc, *next;
379 delete_group(proc->down);
383 free( (void *) proc);
386 delete_between(group);
387 free( (void *) group);
392 register struct process *proc, *next;
393 register struct procgroup *junk;
398 if (proc!= *group->active) {
400 delete_group(proc->down);
405 free( (void *) proc);
408 delete_between(group);
411 free( (void *) junk);
414 (*group->active)->down=nil;
417 static void RESUMERR()
419 write(2, "RESUMERR\n", 9);
422 now.c
\0l.c
\0.c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0\95\0/* $Id: now.c,v 1.3 1994/06/24 12:28:16 ceriel Exp $ */
429 return time((long *) 0);
431 Rpar.c
\0l.c
\0.c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0;
\b/* $Id: par.c,v 1.4 1994/06/24 12:28:26 ceriel Exp $ */
432 /* par.c - Routines to simulate parallelism */
433 #include "ocm_proc.h"
435 static void search_next(), DEADLOCK();
438 /* Stops the current process, by saving its stack, and determines a new one
439 * to restart. In case the root of the process tree is passed more then once,
440 * without a process having done something useful, we'll have a deadlock.
444 register struct process *proc= *group->active;
445 register wordsize size;
447 size=top_size(group->s_brk);
448 proc->stack=alloc((unsigned) size);
450 if (top_save(size, proc->stack)) {
451 group->active= &proc->next;
458 if (++deadlock>1) DEADLOCK();
461 static void search_next()
462 /* Tries to resume the active process, if this is not possible, the process
463 * tree will be searched for another process. If the process tree is fully
464 * traversed, search will restart at the root of the tree.
467 while (*group->active==nil && group->up!=nil) {
472 group->active= &(*group->active)->next;
475 if (*group->active==nil) {
476 if (++deadlock>1) DEADLOCK();
477 group->active= &group->first;
482 while ((*group->active)->down!=nil) {
483 group=(*group->active)->down;
484 group->active= &group->first;
486 top_load((*group->active)->stack);
490 /* Deletes the current process from its process group and searches for a new
491 * process to run. The entire group is removed if this is the last process in
492 * the group, execution then continues with the process that set up this group
493 * in the first place.
496 register struct process *junk;
498 junk= *group->active;
499 *group->active=junk->next;
502 if (group->first==nil) {
503 register struct procgroup *junk;
505 delete_between(group);
512 (*group->active)->down=nil;
519 static void DEADLOCK()
521 write(2, "DEADLOCK\n", 9);
524 nparco.c
\0c
\0.c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0E
\v/* $Id: parco.c,v 1.4 1994/06/24 12:28:31 ceriel Exp $ */
525 /* parco.c - Common routines for simulating parallelism or coroutines on
526 * machines with downward growing stacks
528 #include "ocm_proc.h"
530 struct procgroup *group=nil, *highest_group;
534 void pc_begin(s_brk, id)
535 register void *s_brk;
537 /* Sets up a group of processes and puts the current process in it */
539 register struct procgroup *pg;
540 register struct process *p;
542 pg= (struct procgroup *) alloc(sizeof *pg);
543 p= (struct process *) alloc(sizeof *p);
545 pg->s_brk= s_brk==nil ? (void *) (&id +1) : s_brk;
548 pg->active= &pg->first;
555 (*group->active)->down=pg;
561 int pc_fork(id) identification id;
562 /* Makes a copy of the stack top of the calling function and creates an
563 * entry for it in the current process group. Pc_fork() returns 1 in the
564 * current process, 0 in the copied process. The current process runs first.
567 register struct process *newp;
568 register wordsize size;
570 newp= (struct process *) alloc(sizeof *newp);
575 newp->next= *group->active;
576 *group->active= newp;
577 group->active= &newp->next;
579 size=top_size(group->s_brk);
580 newp->stack=alloc((unsigned) size);
582 if (top_save(size, newp->stack))
591 void init_between(group) register struct procgroup *group;
592 /* Allocates memory to hold the stack space between s_brk and up->s_brk. */
594 register wordsize size;
597 || (size= (wordsize) group->up->s_brk - (wordsize) group->s_brk)==0)
600 group->between=alloc((unsigned) size);
605 void save_between(group) register struct procgroup *group;
606 /* Saves the stack space between s_brk and up->s_brk. */
608 register wordsize size;
610 if (group->between!=nil) {
611 size= (wordsize) group->up->s_brk - (wordsize) group->s_brk;
612 block_move(size, group->s_brk, group->between);
617 /* All stack pieces between s_brk and up->s_brk from the current group
618 * upto the 'highest_group' are loaded onto the stack at the right
619 * place (i.e. s_brk).
622 register struct procgroup *gr=group, *up;
623 register wordsize size;
625 while (gr!=highest_group) {
627 if (gr->between!=nil) {
628 size= (wordsize) up->s_brk - (wordsize) gr->s_brk;
630 block_move(size, gr->between, gr->s_brk);
636 void delete_between(group) register struct procgroup *group;
637 /* Deallocates the stack space between s_brk and up->s_brk. */
639 if (group->between!=nil)
640 free(group->between);
645 void *alloc(size) unsigned size;
649 if ((mem=malloc(size))==nil) {
650 write(2, "Heap error\n", 14);
655 ;misc.e
\0\0c
\0.c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0ü
\ 1#
656 mes 2,EM_WSIZE,EM_PSIZE
683 asp 2*EM_WSIZE+EM_PSIZE
704 ocrt.c
\0\0c
\0.c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0«
\ 3/* $Id: ocrt.c,v 1.4 1994/06/24 12:28:21 ceriel Exp $ */
705 /* ocrt.c - Occam runtime support */
706 #include "ocm_chan.h"
708 int chandes[]= { 0, 0, sizeof(int)+sizeof(long) };
709 int worddes[]= { 0, 0, sizeof(long) };
710 int bytedes[]= { 0, 0, 1 };
713 void catch(sig, file, line) int sig; char *file; int line;
714 /* Catches traps in the occam program */
720 mes="array bound error";
723 mes="division by zero";
726 mes="undefined variable";
731 fprintf(stderr, "%s (%d) F: %s\n", file, line, mes);
741 register chan *c=file;
743 for (i=0; i<20; i++) {
748 file[0].f.flgs|=C_F_INUSE;
751 file[1].f.flgs|=C_F_INUSE;
754 file[2].f.flgs|=C_F_INUSE;
757 Ppar_misc.e
\0c
\0\0\0\0\0\0\ 2\ 2¤
\ 1\0\0\93\b#
758 mes 2,EM_WSIZE,EM_PSIZE
772 pro $top_size2, 3*EM_WSIZE+3*EM_PSIZE
774 pro $top_size, 3*EM_WSIZE+3*EM_PSIZE
780 sbs EM_PSIZE ; s_brk-SP
781 ret EM_PSIZE ; return size of block to be saved
782 end 3*EM_WSIZE+3*EM_PSIZE
802 lae 4 ; load line number and file name
807 loi EM_PSIZE ; size of block
812 stl 0 ; push & store size in 2 bytes
813 lor 1 ; SP (the SP BEFORE pushing)
814 lor 1 ; SP (address of stack top to save)
818 bls EM_WSIZE ; move whole block
819 asp 3*EM_PSIZE+3*EM_WSIZE ; remove the lot from the stack
821 ret EM_WSIZE ; return 1
853 loi EM_PSIZE ; compare target SP with current LB to see if we must
855 cmp ; find another LB first
857 dch ; just follow dynamic chain to make sure we find
870 lor 1 ; SP (the SP AFTER, see above)
874 lof EM_PSIZE ; size of block
875 bls EM_WSIZE ; move block back (SP becomes the SP BEFORE again!)
876 asp EM_WSIZE+EM_PSIZE ; drop size + SP
881 ste 0 ; line and file
883 ret EM_WSIZE ; return 0