From: ceriel Date: Tue, 24 Feb 1987 18:36:02 +0000 (+0000) Subject: Initial revision X-Git-Tag: release-5-5~4605 X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=2eeacf071a11778cc715cab1069f3d11eb682bfc;p=ack.git Initial revision --- diff --git a/lang/occam/lib/AR2 b/lang/occam/lib/AR2 new file mode 100755 index 000000000..d249beb97 --- /dev/null +++ b/lang/occam/lib/AR2 @@ -0,0 +1,11 @@ +#!/bin/sh +case $# in + 0) ar ru /user0/bot/lib/lib2.a *.o + ranlib /user0/bot/lib/lib2.a + rm -f *.o + ;; + *) keys=$1 + shift + ar $keys /user0/bot/lib/lib2.a $* + ;; +esac diff --git a/lang/occam/lib/AR4 b/lang/occam/lib/AR4 new file mode 100755 index 000000000..0560c4a81 --- /dev/null +++ b/lang/occam/lib/AR4 @@ -0,0 +1,11 @@ +#!/bin/sh +case $# in + 0) ar ru /user0/bot/lib/lib4.a *.o + ranlib /user0/bot/lib/lib4.a + rm -f *.o + ;; + *) keys=$1 + shift + ar $keys /user0/bot/lib/lib4.a $* + ;; +esac diff --git a/lang/occam/lib/Makefile b/lang/occam/lib/Makefile new file mode 100644 index 000000000..357ab5fbf --- /dev/null +++ b/lang/occam/lib/Makefile @@ -0,0 +1,28 @@ +PRIMITIVES= par_vax.s +PARALLEL= parco.c par.c co.c +OCRT= ocrt.c builtin.c channel.c chan_struct.c + +COMMON= $(PRIMITIVES) $(PARALLEL) $(OCRT) + +SIZE2= em2.e +SIZE4= em4.e + +LIB2= /user0/bot/lib/lib2.a +LIB4= /user0/bot/lib/lib4.a + +ACK2= vax2 +ACK4= vax4 + +all: lib2 lib4 + +lib2: $(COMMON) $(SIZE2) + rm -f *.o $(LIB2) + $(ACK2) -c.o -L -Dvoid=char -Dptrdiff=long $(COMMON) $(SIZE2) + ar cq $(LIB2) *.o + rm -f *.o + +lib4: $(COMMON) $(SIZE4) + rm -f *.o $(LIB4) + $(ACK4) -c.o -L -Dvoid=char $(COMMON) $(SIZE4) + ar cq $(LIB4) *.o + rm -f *.o diff --git a/lang/occam/lib/builtin.c b/lang/occam/lib/builtin.c new file mode 100644 index 000000000..37ed2e895 --- /dev/null +++ b/lang/occam/lib/builtin.c @@ -0,0 +1,75 @@ +/* builtin.c - built in named processes */ +#include "channel.h" +#ifndef nil +#define nil 0 +#endif + +extern int errno; + +static void nullterm(s) register char *s; +/* Change Occam string to C string */ +{ + register len= (*s & 0377); + register char *p; + + while (--len>=0) { + p=s++; + *p = *s; + } + *s=0; +} + +static void lenterm(s) register char *s; +/* Change C string to Occam string */ +{ + register i=0; + register c0, c1; + + c0=0; + do { + c1=s[i]; + s[i++]=c0; + c0=c1; + } while (c0!=0); + *s= i-1; +} + +void b_open(mode, name, index) register char *mode, *name; long *index; +/* PROC open(VAR index, VALUE name[], mode[])= */ +{ + register FILE *fp; + register i; + + nullterm(name); + nullterm(mode); + + fp=fopen(name, mode); + + lenterm(name); + lenterm(mode); + + if (fp==nil) + *index= -errno; + else { + /* Find free file channel, there must be one free! */ + + for (i=0; (file[i].f.flgs&C_F_INUSE)!=0; i++) ; + + file[i].f.flgs|=C_F_INUSE; + unix_file[i]=fp; + *index=i; + } +} + +void b_close(index) long index; +/* PROC close(VALUE index)= */ +{ + fclose(unix_file[index]); + file[index].f.flgs&= ~C_F_INUSE; +} + +void b_exit(code) long code; +/* PROC exit(VALUE code)= */ +{ + exit((int) code); +} diff --git a/lang/occam/lib/channel.c b/lang/occam/lib/channel.c new file mode 100644 index 000000000..630f932f8 --- /dev/null +++ b/lang/occam/lib/channel.c @@ -0,0 +1,152 @@ +/* channel.c - basic channel handling routines */ +#include +#include +#include +#include "channel.h" + +static void disaster(); + +void c_init(c, z) register chan *c; register unsigned z; +/* Initialise an array of interprocess channels declared as: CHAN c[z]. */ +{ + do { + c->type=C_T_CHAN; + (c++)->c.synch=C_S_FREE; + } while (--z!=0); +} + +void chan_in(v, c) long *v; register chan *c; +/* Reads a value from channel c and returns it through v. */ +{ + switch(c->type) { + case C_T_FILE: + if ((c->f.flgs&C_F_READAHEAD)!=0) { + *v=(c->f.preread&0377); + c->f.flgs&= ~C_F_READAHEAD; + } else { + register FILE *fp= unix_file[c->f.index]; + + *v= feof(fp) ? C_F_EOF : getc(fp); + } + break; + case C_T_CHAN: + deadlock=0; /* Wait for value to arrive */ + while (c->c.synch!=C_S_ANY) resumenext(); + + *v=c->c.val; + c->c.synch=C_S_ACK; /* Acknowledge receipt */ + break; + default: + disaster(); + } +} + +void chan_out(v, c) long v; register chan *c; +/* Send value v through channel c. */ +{ + switch(c->type) { + case C_T_FILE: { + register FILE *fp= unix_file[c->f.index]; + struct sgttyb tty; + + if ((v& ~0xff)==0) /* Plain character */ + putc( (int) v, fp); + else + if (v==C_F_TEXT) { + ioctl(fileno(fp), TIOCGETP, &tty); + tty.sg_flags&= ~CBREAK; + tty.sg_flags|= ECHO|CRMOD; + ioctl(fileno(fp), TIOCSETN, &tty); + } else + if (v==C_F_RAW) { + ioctl(fileno(fp), TIOCGETP, &tty); + tty.sg_flags|= CBREAK; + tty.sg_flags&= ~(ECHO|CRMOD); + ioctl(fileno(fp), TIOCSETN, &tty); + } + } break; + case C_T_CHAN: + deadlock=0; /* Wait until channel is free */ + while (c->c.synch!=C_S_FREE) resumenext(); + + c->c.val=v; + c->c.synch=C_S_ANY; /* Channel has data */ + + deadlock=0; /* Wait for acknowledgement */ + while (c->c.synch!=C_S_ACK) resumenext(); + + c->c.synch=C_S_FREE; /* Back to normal */ + break; + default: + disaster(); + } +} + +static int timeout(); + +int chan_any(c) register chan *c; +{ + switch (c->type) { + case C_T_FILE: + if ((c->f.flgs&C_F_READAHEAD)!=0) + return 1; + else { + register FILE *fp= unix_file[c->f.index]; + + if (feof(fp)) + return 1; + else { + extern int errno; + register ch; + + deadlock=0; + /* No deadlock while waiting for key */ + + signal(SIGALRM, timeout); + alarm(1); + + errno=0; + ch=getc(fp); + + signal(SIGALRM, SIG_IGN); + alarm(0); + + if (errno==EINTR) + return 0; + else { + if (!feof(fp)) { + c->f.flgs|=C_F_READAHEAD; + c->f.preread=ch; + } + return 1; + } + } + } + case C_T_CHAN: + return c->c.synch==C_S_ANY; + default: + disaster(); + } +} + +/* The ch=getc(fp) in the above function calls read(2) to do its task, but if + * there's no input on the file (pipe or terminal) then the read will block. + * To stop this read from blocking, we use the fact that if the read is + * interrupted by a signal that is caught by the program, then the read returns + * error EINTR after the signal is processed. Thus we use a one second alarm + * to interrupt the read with a trap to timeout(). But since the alarm signal + * may occur *before* the read is called, it is continuously restarted in + * timeout() to prevent it from getting lost. + */ + +static int timeout(sig) +{ + signal(SIGALRM, timeout); + alarm(1); +} + +static void disaster() +{ + write(2, "Fatal error: Channel variable corrupted\n", 40); + abort(); +} diff --git a/lang/occam/lib/co.c b/lang/occam/lib/co.c new file mode 100644 index 000000000..88d3d72b2 --- /dev/null +++ b/lang/occam/lib/co.c @@ -0,0 +1,115 @@ +/* co.c - Routines to handle coroutines */ +#include "process.h" + +static void search(), RESUMERR(); + +void resume(id) identification id; +/* Stops the current process, by saving its stack, and searches for the + * process with identification 'id' in the group the running process + * belongs to. If 'id' cannot be found then repeat these actions with + * the running process' parent. If 'id' is found it is activated. It + * is a fatal error if 'id' cannot be found. + */ +{ + if (group!=nil) { + register wordsize size; + + size=top_size(group->s_brk); + (*group->active)->stack=alloc((unsigned) size); + + if (top_save(size, (*group->active)->stack)) + search(id); + else { + free((*group->active)->stack); + load_betweens(); + } + } else + RESUMERR(); +} + +static void search(id) identification id; +/* Searches for the process with identification 'id'. + * If the process is found it is activated and its process tree is + * traversed to find the running process. + */ +{ + register struct process **aproc, *proc; + + for(;;) { + aproc= &group->first; + + while (*aproc!=nil && (*aproc)->id!=id) + aproc= &(*aproc)->next; + + if (*aproc!=nil) break; + + save_between(group); + + if ((group=group->up)==nil) + RESUMERR(); + } + group->active=aproc; + proc= *aproc; + highest_group=group; + + while (proc->down!=nil) { + group=proc->down; + proc= *group->active; + } + top_load(proc->stack); +} + +static void delete_group(group) struct procgroup *group; +/* Removes the whole group and sub-groups recursively from the running + * process. + */ +{ + register struct process *proc, *next; + + proc=group->first; + + while (proc!=nil) { + if (proc->down!=nil) + delete_group(proc->down); + else + free(proc->stack); + next=proc->next; + free( (void *) proc); + proc=next; + } + delete_between(group); + free( (void *) group); +} + +void coend() +{ + register struct process *proc, *next; + register struct procgroup *junk; + + proc=group->first; + + while (proc!=nil) { + if (proc!= *group->active) { + if (proc->down!=nil) + delete_group(proc->down); + else + free(proc->stack); + } + next=proc->next; + free( (void *) proc); + proc=next; + } + delete_between(group); + junk=group; + group=group->up; + free( (void *) junk); + + if (group!=nil) + (*group->active)->down=nil; +} + +static void RESUMERR() +{ + write(2, "RESUMERR\n", 9); + abort(); +} diff --git a/lang/occam/lib/em2.e b/lang/occam/lib/em2.e new file mode 100644 index 000000000..fb81a1edc --- /dev/null +++ b/lang/occam/lib/em2.e @@ -0,0 +1,52 @@ + mes 2,2,4 + +oldtrp + bss 4, 0, 0 + + exp $init + pro $init, 0 + loc -321-1 + sim + lpi $catch1 + sig + sde oldtrp + cal $initfile + ret 0 + end 0 + + pro $catch1, 0 + lde oldtrp + sig + asp 4 + loe 0 + lde 4 + lol 0 + cal $catch + asp 8 + lol 0 + trp + rtt + end 0 + + exp $now + pro $now, 12 + zre deadlock + lal -12 + loc 35 + mon + asp 2 + ldl -12 + ret 4 + end 12 + + exp $block_mo + pro $block_mo, 0 + ldl 4 + ldl 8 + ldl 0 + loc 4 + loc 2 + cuu + bls 2 + ret 0 + end 0 diff --git a/lang/occam/lib/em4.e b/lang/occam/lib/em4.e new file mode 100644 index 000000000..ff948932c --- /dev/null +++ b/lang/occam/lib/em4.e @@ -0,0 +1,49 @@ + mes 2,4,4 + +oldtrp + bss 4, 0, 0 + + exp $init + pro $init, 0 + loc -321-1 + sim + lpi $catch1 + sig + ste oldtrp + cal $initfile + ret 0 + end 0 + + pro $catch1, 0 + loe oldtrp + sig + asp 4 + loe 0 + loe 4 + lol 0 + cal $catch + asp 12 + lol 0 + trp + rtt + end 0 + + exp $now + pro $now, 12 + zre deadlock + lal -12 + loc 35 + mon + asp 4 + lol -12 + ret 4 + end 12 + + exp $block_mo + pro $block_mo, 0 + lol 4 + lol 8 + lol 0 + bls 4 + ret 0 + end 0 diff --git a/lang/occam/lib/ocm_chan.h b/lang/occam/lib/ocm_chan.h new file mode 100644 index 000000000..1d456061f --- /dev/null +++ b/lang/occam/lib/ocm_chan.h @@ -0,0 +1,47 @@ +/* channel.h - channel definitions */ +#include +#include "parco.h" + +typedef union channel { + struct { /* Interprocess channel */ + char _type; /* Channel type, see note */ + char synch; /* State in channel synchronization */ + long val; /* Transmitted value */ + } c; + struct { /* File channel */ + char _type; /* Dummy field, see note */ + char index; /* Index in the file array */ + char flgs; /* Status flags: in use & readahead */ + char preread; /* Possible preread character */ + } f; +} chan; +#define type c._type /* Channel type */ +/* Note: The channel type should not be part of each structure in chan. But + * the C alignment rules would make chan about 50% bigger if we had done it + * the right way. Note that the order of fields in a struct cannot be a problem + * as long as struct c is the largest within the union. + */ + +#define C_T_CHAN 0 /* Type of a interprocess channel */ +#define C_T_FILE 1 /* Type of a file channel */ + +#define C_S_FREE 0 /* IP channel is free */ +#define C_S_ANY 1 /* IP channel contains data */ +#define C_S_ACK 2 /* IP channel data is removed */ + +#define C_F_EOF (-1L) /* File channel returns EOF */ +#define C_F_TEXT (-2L) /* File channel becomes line oriented */ +#define C_F_RAW (-3L) /* File channel becomes character oriented */ + +#define C_F_INUSE 0x01 /* File channel is connected to a UNIX file */ +#define C_F_READAHEAD 0x02 /* File channel has a preread character */ + +extern chan file[_NFILE]; /* Array of file channels */ +extern FILE *unix_file[_NFILE]; /* Pointers to buffered UNIX files */ + +void c_init(); + +void chan_in(), cbyte_in(), c_wa_in(), c_ba_in(); +void chan_out(), c_wa_out(), c_ba_out(); + +int chan_any(); diff --git a/lang/occam/lib/ocm_parco.h b/lang/occam/lib/ocm_parco.h new file mode 100644 index 000000000..1588d43c3 --- /dev/null +++ b/lang/occam/lib/ocm_parco.h @@ -0,0 +1,18 @@ +/* parco.h - Define names for simulation routines + * + * This file is to be included by users of the higher-level routines + * + */ + +void pc_begin(), resumenext(), parend(), resume(), coend(); +int pc_fork(); + +#define nullid ((int *) 0 - (int *) 0) + /* I.e. a 0 of type "pointer difference" */ + +#define parbegin(sbrk) pc_begin(sbrk, nullid) +#define parfork() pc_fork(nullid) +#define cobegin(sbrk, id) pc_begin(sbrk, id) +#define cofork(id) pc_fork(id) + +extern int deadlock; diff --git a/lang/occam/lib/ocm_proc.h b/lang/occam/lib/ocm_proc.h new file mode 100644 index 000000000..fcc9503bb --- /dev/null +++ b/lang/occam/lib/ocm_proc.h @@ -0,0 +1,52 @@ +/* process.h - Define administration types and functions + * + * This file is to be included by implementors of the higher + * level routines + * + */ +#include "parco.h" + +#ifndef ptrdiff /* This type must be able to hold a pointer difference */ +#define ptrdiff int /* Define as long int if necessary */ +#endif + +#define nil 0 +void *alloc(), free(); + +typedef ptrdiff wordsize, identification; + +wordsize top_size(); +int top_save(); +void top_load(); /* Primitives */ + +struct procgroup; + +struct process { + struct process *next; /* Next process in the same group */ + struct procgroup *down; /* Process group running under this process */ + void *stack; /* Pointer to the saved stack top */ + identification id; /* Coroutine identification */ +}; + +#define init_between __i_b__ /* These names are hidden */ +#define save_between __s_b__ +#define load_betweens __l_b__ +#define delete_between __d_b__ + +void init_between(), save_between(), load_betweens(), delete_between(); + +struct procgroup { + struct process **active;/* Active process within this group */ + struct procgroup *up; /* The group that this group belongs to */ + struct process *first; /* List of processes belonging to this group */ + void *s_brk; /* Point where the stack is split */ + void *between; /* Stack space between s_brk and up->s_brk */ +}; + +#define group __grp__ /* Ignore this please */ +#define highest_group __hgrp__ + +extern struct procgroup *group; /* Current running group */ +extern struct procgroup *highest_group; /* highest group that has been seen + * while searching for a process + */ diff --git a/lang/occam/lib/ocrt.c b/lang/occam/lib/ocrt.c new file mode 100644 index 000000000..c39eff3cf --- /dev/null +++ b/lang/occam/lib/ocrt.c @@ -0,0 +1,52 @@ +/* ocrt.c - Occam runtime support */ +#include "channel.h" + +int chandes[]= { 0, 0, sizeof(int)+sizeof(long) }; +int worddes[]= { 0, 0, sizeof(long) }; +int bytedes[]= { 0, 0, 1 }; +long any; + +void catch(sig, file, line) int sig; char *file; int line; +/* Catches traps in the occam program */ +{ + register char *mes; + + switch (sig) { + case 0: + mes="array bound error"; + break; + case 6: + mes="division by zero"; + break; + case 8: + mes="undefined variable"; + break; + default: + return; + } + fprintf(stderr, "%s (%d) F: %s\n", file, line, mes); + abort(); +} + +chan file[_NFILE]; +FILE *unix_file[_NFILE]; + +void initfile() +{ + register i; + register chan *c=file; + + for (i=0; i<_NFILE; i++) { + c->type=C_T_FILE; + c->f.flgs=0; + (c++)->f.index=i; + } + file[0].f.flgs|=C_F_INUSE; + unix_file[0]=stdin; + + file[1].f.flgs|=C_F_INUSE; + unix_file[1]=stdout; + + file[2].f.flgs|=C_F_INUSE; + unix_file[2]=stderr; +} diff --git a/lang/occam/lib/par.c b/lang/occam/lib/par.c new file mode 100644 index 000000000..ef3c45981 --- /dev/null +++ b/lang/occam/lib/par.c @@ -0,0 +1,92 @@ +/* par.c - Routines to simulate parallelism */ +#include "process.h" + +static void search_next(), DEADLOCK(); + +void resumenext() +/* Stops the current process, by saving its stack, and determines a new one + * to restart. In case the root of the process tree is passed more then once, + * without a process having done something useful, we'll have a deadlock. + */ +{ + if (group!=nil) { + register struct process *proc= *group->active; + register wordsize size; + + size=top_size(group->s_brk); + proc->stack=alloc((unsigned) size); + + if (top_save(size, proc->stack)) { + group->active= &proc->next; + search_next(); + } else { + free(proc->stack); + load_betweens(); + } + } else + if (++deadlock>1) DEADLOCK(); +} + +static void search_next() +/* Tries to resume the active process, if this is not possible, the process + * tree will be searched for another process. If the process tree is fully + * traversed, search will restart at the root of the tree. + */ +{ + while (*group->active==nil && group->up!=nil) { + save_between(group); + + group=group->up; + + group->active= &(*group->active)->next; + } + + if (*group->active==nil) { + if (++deadlock>1) DEADLOCK(); + group->active= &group->first; + } + + highest_group=group; + + while ((*group->active)->down!=nil) { + group=(*group->active)->down; + group->active= &group->first; + } + top_load((*group->active)->stack); +} + +void parend() +/* Deletes the current process from its process group and searches for a new + * process to run. The entire group is removed if this is the last process in + * the group, execution then continues with the process that set up this group + * in the first place. + */ +{ + register struct process *junk; + + junk= *group->active; + *group->active=junk->next; + free((void *) junk); + + if (group->first==nil) { + register struct procgroup *junk; + + delete_between(group); + + junk=group; + group=group->up; + free((void *) junk); + + if (group!=nil) + (*group->active)->down=nil; + } else { + deadlock=0; + search_next(); + } +} + +static void DEADLOCK() +{ + write(2, "DEADLOCK\n", 9); + abort(); +} diff --git a/lang/occam/lib/par_em2.e b/lang/occam/lib/par_em2.e new file mode 100644 index 000000000..ed45d527c --- /dev/null +++ b/lang/occam/lib/par_em2.e @@ -0,0 +1,53 @@ + mes 2,2,4 + exp $top_size + pro $top_size, 14 + ldl 0 ; s_brk + lor 1 ; s_brk SP + sbs 4 ; s_brk-SP + ret 4 ; return size of block to be saved + end 14 + + exp $top_save + pro $top_save, 0 + loe 0 + lde 4 ; load line number and file name + lim ; ignore mask + lor 0 ; LB + ldl 0 ; size of block + loc 4 + loc 2 + cuu + dup 2 + stl 0 ; push & store size in 2 bytes + lor 1 ; SP (the SP BEFORE pushing) + lor 1 ; SP (address of stack top to save) + ldl 4 ; area + lol 0 ; size + bls 2 ; move whole block + asp 18 ; remove the lot from the stack + loc 1 + ret 2 ; return 1 + end 0 + + exp $top_load + pro $top_load, 0 + ldl 0 + dup 4 + sde area ; copy area pointer from argument 0 + loi 4 ; load indirect to + str 1 ; restore SP + lde area ; load area, note that the SP is now correct + lor 1 ; SP (the SP AFTER, see above) + lde area + lof 4 ; size of block + bls 2 ; move block back (SP becomes the SP BEFORE again!) + asp 2 ; drop size + str 0 ; LB + sim ; ignore mask + sde 4 + ste 0 ; line and file + loc 0 + ret 2 ; return 0 + end 0 +area + bss 4,0,0 diff --git a/lang/occam/lib/par_em4.e b/lang/occam/lib/par_em4.e new file mode 100644 index 000000000..b47cffbd3 --- /dev/null +++ b/lang/occam/lib/par_em4.e @@ -0,0 +1,46 @@ + mes 2,4,4 + exp $top_size + pro $top_size, 20 + lol 0 ; s_brk + lor 1 ; s_brk SP + sbs 4 ; s_brk-SP + ret 4 ; return size of block to be saved + end 20 + + exp $top_save + pro $top_save, 0 + lde 0 ; load line number and file name + lim ; ignore mask + lor 0 ; LB + lol 0 ; size of block + lor 1 ; SP (the SP BEFORE pushing) + lor 1 ; SP (address of stack top to save) + lol 4 ; area + lol 0 ; size + bls 4 ; move whole block + asp 24 ; remove the lot from the stack + loc 1 + ret 4 ; return 1 + end 0 + + exp $top_load + pro $top_load, 0 + lol 0 + dup 4 + ste area ; copy area pointer from argument 0 + loi 4 ; load indirect to + str 1 ; restore sp + loe area ; load area, note that the SP is now correct + lor 1 ; SP (the SP AFTER, see above) + loe area + lof 4 ; size of block + bls 4 ; move block back (SP becomes the SP BEFORE again!) + asp 4 ; drop size + str 0 ; LB + sim ; ignore mask + sde 0 ; line and file + loc 0 + ret 4 ; return 0 + end 0 +area + bss 4,0,0 diff --git a/lang/occam/lib/par_vax.s b/lang/occam/lib/par_vax.s new file mode 100644 index 000000000..04ab0a977 --- /dev/null +++ b/lang/occam/lib/par_vax.s @@ -0,0 +1,51 @@ + # VAX code for the top_* primitives + + .set BIG, 0x8000 # 32K chunk per movc3 + .text + .align 1 + .globl _top_size + .globl _top_save + .globl _top_load + +_top_size: .word 0x0000 + subl3 sp, 4(ap), r0 # bytes between stack pointer and break + addl2 $(8+6+1)*4, r0 # add 8 regs, 6 pushed longwords (line, file, + ret # ap, fp, size, sp) and 1 extra argument + +_top_save: .word 0x0ff0 # save regs r4-r11 + movq hol0, -(sp) # push line number and file name + movq ap, -(sp) # push LB equivalents ap and fp + pushl 4(ap) # push size + pushal -4(sp) # push sp (the sp AFTER pushing) + movl $BIG, r6 # chunk size in r6 + movl 4(ap), r7 # size of block to move + movl sp, r1 # source address + movl 8(ap), r3 # destination address + cmpl r7, r6 + jlequ 0f +1: movc3 r6, (r1), (r3) # move chunk of the block, add r6 to r1 and r3 + subl2 r6, r7 + cmpl r7, r6 + jgtru 1b +0: movc3 r7, (r1), (r3) # move what's left + movl $1, r0 # return 1 + ret + +_top_load: .word 0x0000 + movl 4(ap), r1 # source + movl (r1), sp # restore sp + movl $BIG, r6 # chunk size + movl 4(r1), r7 # size + movl sp, r3 # destination + cmpl r7, r6 + jlequ 0f +1: movc3 r6, (r1), (r3) # move chunk of the block back + subl2 r6, r7 + cmpl r7, r6 + jgtru 1b +0: movc3 r7, (r1), (r3) # move what's left back + addl2 $8, sp # pop saved sp and size + movq (sp)+, ap # pop LB's + movq (sp)+, hol0 # pop line and file + clrl r0 # return 0 + ret diff --git a/lang/occam/lib/parco.c b/lang/occam/lib/parco.c new file mode 100644 index 000000000..55d7979b9 --- /dev/null +++ b/lang/occam/lib/parco.c @@ -0,0 +1,130 @@ +/* parco.c - Common routines for simulating parallelism or coroutines on + * machines with downward growing stacks + */ +#include "process.h" + +struct procgroup *group=nil, *highest_group; + +int deadlock=0; + +void pc_begin(s_brk, id) + register void *s_brk; + identification id; +/* Sets up a group of processes and puts the current process in it */ +{ + register struct procgroup *pg; + register struct process *p; + + pg= (struct procgroup *) alloc(sizeof *pg); + p= (struct process *) alloc(sizeof *p); + + pg->s_brk= s_brk==nil ? (void *) (&id +1) : s_brk; + pg->up=group; + pg->first=p; + pg->active= &pg->first; + + p->next=nil; + p->down=nil; + p->id=id; + + if (group!=nil) + (*group->active)->down=pg; + + group=pg; + init_between(group); +} + +int pc_fork(id) identification id; +/* Makes a copy of the stack top of the calling function and creates an + * entry for it in the current process group. Pc_fork() returns 1 in the + * current process, 0 in the copied process. The current process runs first. + */ +{ + register struct process *newp; + register wordsize size; + + newp= (struct process *) alloc(sizeof *newp); + + newp->down=nil; + newp->id=id; + + newp->next= *group->active; + *group->active= newp; + group->active= &newp->next; + + size=top_size(group->s_brk); + newp->stack=alloc((unsigned) size); + + if (top_save(size, newp->stack)) + return 1; + else { + free(newp->stack); + load_betweens(); + return 0; + } +} + +void init_between(group) register struct procgroup *group; +/* Allocates memory to hold the stack space between s_brk and up->s_brk. */ +{ + register wordsize size; + + if (group->up==nil + || (size= (wordsize) group->up->s_brk - (wordsize) group->s_brk)==0) + group->between=nil; + else + group->between=alloc((unsigned) size); +} + +void block_move(); + +void save_between(group) register struct procgroup *group; +/* Saves the stack space between s_brk and up->s_brk. */ +{ + register wordsize size; + + if (group->between!=nil) { + size= (wordsize) group->up->s_brk - (wordsize) group->s_brk; + block_move(size, group->s_brk, group->between); + } +} + +void load_betweens() +/* All stack pieces between s_brk and up->s_brk from the current group + * upto the 'highest_group' are loaded onto the stack at the right + * place (i.e. s_brk). + */ +{ + register struct procgroup *gr=group, *up; + register wordsize size; + + while (gr!=highest_group) { + up=gr->up; + if (gr->between!=nil) { + size= (wordsize) up->s_brk - (wordsize) gr->s_brk; + + block_move(size, gr->between, gr->s_brk); + } + gr=up; + } +} + +void delete_between(group) register struct procgroup *group; +/* Deallocates the stack space between s_brk and up->s_brk. */ +{ + if (group->between!=nil) + free(group->between); +} + +void *malloc(); + +void *alloc(size) unsigned size; +{ + register void *mem; + + if ((mem=malloc(size))==nil) { + write(2, "Heap error\n", 14); + abort(); + } + return mem; +}