#include <thread.h>
#include <synch.h>
#include <string.h>

class channel;

class rd_channel_end	{
	cond_t data_available;
	int priority;
	int ready;
	channel *body;
	rd_channel_end *next;
	friend channel;

	public:

	void *read(void *p, int sz);
	};

class wr_channel_end	{
	cond_t data_empty;
	int priority;
	int ready;
	channel *body;
	wr_channel_end *next;
	friend channel;

	public:

	void write(void *p, int sz);
	};

class channel	{
	mutex_t mutex;
	void *data;
	int sz;
	wr_channel_end *writers;
	rd_channel_end *readers;

	public:

	channel();
	~channel();
	};


	...

channel::channel()
: sz(0), data(0)
{
 mutex_init(&mutex, USYNC_THREAD, 0);
 cond_init(&data_available, USYNC_THREAD, 0);
 cond_init(&data_empty, USYNC_THREAD, 0);
}

channel::~channel()
{
 /* Try to shut down all users. */
 /* this will catch any that are waiting,
	but will miss threads that are off doing something
	else, and begin to use the channel after things are
	destroyed. */

 int pass = 0;
 while(sz!=(-1) || pass++<10)	{
	mutex_lock(&mutex);
 	sz = -1;
 	cond_broadcast(&data_empty);
 	cond_broadcast(&data_available);
	mutex_unlock(&mutex);
	thr_yield();
	}
 mutex_destroy(&mutex);
 cond_destroy(&data_available);
 cond_destroy(&data_empty);
}

void *channel::read(void *p, int sz_)
{
 (void) mutex_lock(&mutex);
 while(!data && sz!=(-1))
	(void)cond_wait(&data_available, &mutex);
 if(sz == -1)	{
	(void)mutex_unlock(&mutex);
	fprintf(stderr, "ERR: read on closed channel\n");
	thr_exit(0);
	}
 assert(sz == sz_);
 memcpy(p, data, sz);
 p = 0;
 sz = 0;
 cond_signal(&data_empty);
 (void)mutex_unlock(&mutex);
}

void write(void *p, int sz)
{
 (void) mutex_lock(&mutex);
 while(data && sz!=(-1))
	(void)cond_wait(&data_empty, &mutex);
 if(sz == -1)	{
	(void)mutex_unlock(&mutex);
	fprintf(stderr, "ERR: write on closed channel\n");
	thr_exit(0);
	}
 sz = sz_;
 data = p;
 cond_signal(&data_available);
 (void)mutex_unlock(&mutex);
}
