shithub: 9intro

ref: 2b99422480d596ebc26921c87c6bb81a07949f3e
dir: /src/pc.c/

View raw version
#include <u.h>
#include <libc.h>

enum {Nmsgs = 4 };

typedef struct Buffer Buffer;
struct Buffer {
	QLock	lck;
	char*	msgs[Nmsgs];	// messages in buffer
	int	hd;		// head of the queue
	int	tl;		// tail. First empty slot.
	int	nmsgs;		// number of messages in buffer.
	Rendez	isfull;		// to sleep because of no room for put
	Rendez	isempty;	// to sleep when nothing to get
};

/* b->lck must be held by caller
 */
void
dump(int fd, char* msg, Buffer* b)
{
	int	i;
	char	buf[512];
	char*	s;

	s = seprint(buf, buf+sizeof(buf), "%s [", msg);
	for (i = b->hd; i != b->tl; i = ++i%Nmsgs)
		s = seprint(s, buf+sizeof(buf),"%s ", b->msgs[i]);
	s = seprint(s, buf+sizeof(buf), "]\n");
	write(fd, buf, s-buf);
}

void
put(Buffer* b, char* msg)
{
	qlock(&b->lck);
	if (b->nmsgs == Nmsgs){
		print("<full>\n");
		rsleep(&b->isfull);
	}
	if (msg == nil)
		b->msgs[b->tl] = nil;
	else
		b->msgs[b->tl] = strdup(msg);
	b->tl = ++b->tl % Nmsgs;
	b->nmsgs++;
	if (b->nmsgs == 1)
		rwakeup(&b->isempty);
	dump(1, "put:", b);
	qunlock(&b->lck);
}

void
init(Buffer *b)
{
	// release all locks, set everything to null values.
	memset(b, 0, sizeof(*b));
	// set the locks used by the Rendezes
	b->isempty.l = &b->lck;
	b->isfull.l = &b->lck;
}

char*
get(Buffer* b)
{
	char*	msg;

	qlock(&b->lck);
	if (b->nmsgs == 0){
		print("<empty>\n");
		rsleep(&b->isempty);
	}
	msg = b->msgs[b->hd];
	b->hd = ++b->hd % Nmsgs;
	b->nmsgs--;
	if (b->nmsgs == Nmsgs - 1)
		rwakeup(&b->isfull);
	dump(1, "get:", b);
	qunlock(&b->lck);
	return msg;
}


void
producer(Buffer* b, char id)
{
	char	msg[20];
	int	i;

	for (i = 0; i < 5 ; i++){
		seprint(msg, msg+20, "%c%d", id, i);
		put(b, msg);
	}
	put(b, nil);
	exits(nil);
}

void
consumer(Buffer* b)
{
	char*	msg;
	while(msg = get(b)){
		// consume it
		free(msg);
	}
	exits(nil);
}

Buffer buf;

void
main(int, char*[])
{
	init(&buf);
	if (rfork(RFPROC|RFMEM|RFNOWAIT) == 0)
		producer(&buf, 'a');
	if (rfork(RFPROC|RFMEM|RFNOWAIT) == 0)
		producer(&buf, 'b');
	if (rfork(RFPROC|RFMEM|RFNOWAIT) == 0)
		consumer(&buf);
	else
		consumer(&buf);
}