Blame | Last modification | View Log | RSS feed
#define NBUFS 2
#define READMAX 2
#define BUFSIZ 2*READMAX
#define EOF 255
#define TIMEOUT 254
#define FILEMAXLEN 20
byte n[NBUFS];
byte ntotal[NBUFS];
byte putnext[NBUFS];
byte getnext[NBUFS];
bool eof[NBUFS];
bool roomwait[NBUFS];
bool datawait[NBUFS];
byte rwant;
/* use one big data array to simulate 2-d array */
#define bufstart(slot) (slot*BUFSIZ)
#define bufend(slot) ((slot+1)*BUFSIZ)
/* bit data[BUFSIZ*NBUFS]; */
bool selwait;
/* bool hastimeout; */
#define get 0
#define release 1
chan lock = [0] of { bit };
chan lockkill = [0] of { bit };
chan sel = [0] of { byte };
chan selcall = [0] of { byte };
chan selans = [0] of { byte, byte };
chan selkill = [0] of { bit };
chan readcall = [0] of { byte, byte };
chan readans = [0] of { byte };
chan readkill = [0] of { bit };
chan croom[NBUFS] = [0] of { bit };
chan cdata[NBUFS] = [0] of { bit };
proctype Lockrendez()
{
do
:: lock!get -> lock?release
:: lockkill?release -> break
od
}
proctype Copy(byte fd)
{
byte num;
bit b;
do :: 1 ->
/* make sure there's room */
lock?get;
if
:: (BUFSIZ-putnext[fd]) < READMAX ->
if
:: getnext[fd] == putnext[fd] ->
getnext[fd] = 0;
putnext[fd] = 0;
lock!release
:: getnext[fd] != putnext[fd] ->
roomwait[fd] = 1;
lock!release;
croom[fd]?b
fi
:: (BUFSIZ-putnext[fd]) >= READMAX ->
lock!release
fi;
/* simulate read into data buf at putnext */
if
:: ntotal[fd] > FILEMAXLEN ->
num = EOF
:: ntotal[fd] <= FILEMAXLEN ->
if
:: num = 1
:: num = READMAX
:: num = EOF
fi
fi;
/* here is where data transfer would happen */
lock?get;
if
:: num == EOF ->
eof[fd] = 1;
/* printf("Copy %d got eof\n", fd);/**/
if
:: datawait[fd] ->
datawait[fd] = 0;
lock!release;
cdata[fd]!1
:: !datawait[fd] && (rwant & (1<<fd)) && selwait ->
selwait = 0;
lock!release;
sel!fd
:: !datawait[fd] && !((rwant & (1<<fd)) && selwait) ->
lock!release
fi;
break
:: num != EOF ->
/* printf("Copy %d putting %d in; old putnext=%d, old n=%d\n", fd, num, putnext[fd], n[fd]); /* */
putnext[fd] = putnext[fd] + num;
n[fd] = n[fd] + num;
ntotal[fd] = ntotal[fd] + num;
assert(n[fd] > 0);
if
:: datawait[fd] ->
datawait[fd] = 0;
lock!release;
cdata[fd]!1
:: !datawait[fd] && (rwant & (1<<fd)) && selwait ->
selwait = 0;
lock!release;
sel!fd
:: !datawait[fd] && !((rwant & (1<<fd)) && selwait) ->
lock!release
fi
fi;
od
}
proctype Read()
{
byte ngot;
byte fd;
byte nwant;
bit b;
do
:: readcall?fd,nwant ->
if
:: eof[fd] && n[fd] == 0 ->
readans!EOF
:: !(eof[fd] && n[fd] == 0) ->
lock?get;
ngot = putnext[fd] - getnext[fd];
/* printf("Reading %d, want %d: ngot = %d - %d, n = %d\n", fd, nwant, putnext[fd], getnext[fd], n[fd]); /* */
if
:: ngot == 0 ->
if
:: eof[fd] ->
skip
:: !eof[fd] ->
/* sleep until there's data */
datawait[fd] = 1;
/* printf("Read sleeping\n"); /* */
lock!release;
cdata[fd]?b;
lock?get;
ngot = putnext[fd] - getnext[fd];
/* printf("Read awoke, ngot = %d\n", ngot); /**/
fi
:: ngot != 0 -> skip
fi;
if
:: ngot > nwant -> ngot = nwant
:: ngot <= nwant -> skip
fi;
/* here would take ngot elements from data, from getnext[fd] ... */
getnext[fd] = getnext[fd] + ngot;
assert(n[fd] >= ngot);
n[fd] = n[fd] - ngot;
if
:: ngot == 0 ->
assert(eof[fd]);
ngot = EOF
:: ngot != 0 -> skip
fi;
if
:: getnext[fd] == putnext[fd] && roomwait[fd] ->
getnext[fd] = 0;
putnext[fd] = 0;
roomwait[fd] = 0;
lock!release;
croom[fd]!0
:: getnext[fd] != putnext[fd] || !roomwait[fd] ->
lock!release
fi;
readans!ngot
fi
:: readkill?b -> break
od
}
proctype Select()
{
byte num;
byte i;
byte fd;
byte r;
bit b;
do
:: selcall?r ->
/* printf("Select called, r=%d\n", r); /**/
i = 0;
do
:: i < NBUFS ->
if
:: r & (1<<i) ->
if
:: eof[i] && n[i] == 0 ->
/* printf("Select got eof on %d\n", i);/**/
num = EOF;
r = i;
goto donesel
:: !eof[i] || n[i] != 0 -> skip
fi
:: !(r & (1<<i)) -> skip
fi;
i = i+1
:: i >= NBUFS -> break
od;
num = 0;
lock?get;
rwant = 0;
i = 0;
do
:: i < NBUFS ->
if
:: r & (1<<i) ->
if
:: n[i] > 0 || eof[i] ->
/* printf("Select found %d has n==%d\n", i, n[i]); /**/
num = num+1
:: n[i] == 0 && !eof[i] ->
/* printf("Select asks to wait for %d\n", i); /**/
r = r &(~(1<<i));
rwant = rwant | (1<<i)
fi
:: !(r & (1<<i)) -> skip
fi;
i = i+1
:: i >= NBUFS -> break
od;
if
:: num > 0 || rwant == 0 ->
rwant = 0;
lock!release;
:: num == 0 && rwant != 0 ->
selwait = 1;
lock!release;
/* printf("Select sleeps\n"); /**/
sel?fd;
/* printf("Select wakes up, fd=%d\n", fd); /**/
if
:: fd != TIMEOUT ->
if
:: (rwant & (1<<fd)) && (n[fd] > 0) ->
r = r | (1<<fd);
num = 1
:: !(rwant & (1<<fd)) || (n[fd] == 0) ->
num = 0
fi
:: fd == TIMEOUT -> skip
fi;
rwant = 0
fi;
donesel:
selans!num,r
:: selkill?b -> break
od
}
/* This routine is written knowing NBUFS == 2 in several places */
proctype User()
{
byte ndone;
byte i;
byte rw;
byte num;
byte nwant;
byte fd;
bool goteof[NBUFS];
ndone = 0;
do
:: ndone == NBUFS -> break
:: ndone < NBUFS ->
if
:: 1->
/* maybe use Read */
/* printf("User trying to read. Current goteofs: %d %d\n", goteof[0], goteof[1]); /**/
/* randomly pick fd 0 or 1 from non-eof ones */
if
:: !goteof[0] -> fd = 0
:: !goteof[1] -> fd = 1
fi;
if
:: nwant = 1
:: nwant = READMAX
fi;
readcall!fd,nwant;
readans?num;
if
:: num == EOF ->
goteof[fd] = 1;
ndone = ndone + 1
:: num != EOF -> assert(num != 0)
fi
:: 1->
/* printf("User trying to select. Current goteofs: %d %d\n", goteof[0], goteof[1]); /**/
/* maybe use Select, then Read */
/* randomly set the "i want" bit for non-eof fds */
if
:: !goteof[0] && !goteof[1] -> rw = (1<<0) | (1<<1)
:: !goteof[0] -> rw = (1<<0)
:: !goteof[1] -> rw = (1<<1)
fi;
selcall!rw;
selans?i,rw;
if
:: i == EOF ->
goteof[rw] = 1;
ndone = ndone + 1
:: i != EOF ->
/* this next statement knows NBUFS == 2 ! */
if
:: rw & (1<<0) -> fd = 0
:: rw & (1<<1) -> fd = 1
:: rw == 0 -> fd = EOF
fi;
if
:: nwant = 1
:: nwant = READMAX
fi;
if
:: fd != EOF ->
readcall!fd,nwant;
readans?num;
assert(num != 0)
:: fd == EOF -> skip
fi
fi
fi
od;
lockkill!release;
selkill!release;
readkill!release
}
init
{
byte i;
atomic {
run Lockrendez();
i = 0;
do
:: i < NBUFS ->
run Copy(i);
i = i+1
:: i >= NBUFS -> break
od;
run Select();
run Read();
run User()
}
}