#include
#include
#include
#include
#include
#include “uthread.h”
#define VERBOSE 0
#define VVERBOSE 0
#define LIMIT 100L
#define STALL 500
#define LITTLESTALL 100
int verbose = VERBOSE;
int vverbose = VVERBOSE;
/*
* The amount of space in the bounded buffer.
*/
#define N 4
/*
* The type of values produced and consumed.
*/
typedef long Message;
/*
* The bounded buffer struct.
*/
typedef struct {
Message message[N];
long in;
long out;
} Buffer;
/*
* The function used to store data in the bounded buffer.
*/
void send(volatile Buffer *buf, Message msg)
{
/*
* Wait a random amount of time before producing a value.
*/
long stall = random() % STALL;
usleep(stall);
/*
* Wait until there is space in the buffer.
*/
while (buf->in – buf->out == N)
{
if(vverbose)
{
printf(“Send waits\n”);
}
uthread_yield();
}
/*
* There is space, so add the value in the buffer.
*/
if (verbose)
{
printf(“Buffer[%ld] = %ld\n”, buf->in % N, msg);
}
buf->message[buf->in % N] = msg;
buf->in++;
}
/*
* The function used to retrieve data from the bounded buffer.
*/
Message receive(volatile Buffer *buf)
{
/*
* Wait a random amount of time before requesting a value.
*/
long stall = random() % STALL;
usleep(stall);
/*
* Wait until there is some data in the buffer.
*/
while (buf->in == buf->out)
{
if (vverbose)
{
printf(“Receive waits\n”);
}
uthread_yield();
}
/*
* There is data, so get a value from the buffer.
*/
Message msg = buf->message[buf->out % N];
if (verbose)
{
printf(“%ld <- Buffer[%ld]\n", msg, buf->out % N);
}
buf->out++;
return msg;
}
/*
* Producer thread: it generates LIMIT messages and then stops.
*/
void *producer(void *buf)
{
int i;
Buffer *buffer = buf;
for (i = 0; i < LIMIT; ++i)
{
send(buffer, random());
}
return 0;
}
/*
* Consumer thread: it reads LIMIT messages and then stops.
*/
void *consumer(void *buf)
{
int i;
Buffer *buffer = buf;
volatile Message msg; /* volatile so it's not optimized out */
for (i = 0; i < LIMIT; ++i)
{
msg = receive(buffer);
}
return 0;
}
/*
* Monitoring thread: keeps track of the number of messages produced
* and consumed and prints them out every second.
*/
void *monitor(void *buf)
{
Buffer *buffer = buf;
while (buffer->in < LIMIT)
{
usleep(1000000);
fprintf(stderr, "Monitor: buffer->in = %ld, buffer->out = %ld\n”, buffer->in, buffer->out);
}
return 0;
}
/*
* Main function.
*/
int main(int argc, char **argv)
{
uthread_t p1, c1, m;
srandom(time(0));
int i;
uthread_init(3);
/*
* Check verbose flags.
*/
for (i = 1; i < argc; ++i)
{
if (!strcmp(argv[i], "-v"))
{
verbose = 1;
}
if (!strcmp(argv[i], "-vv"))
{
vverbose = 1;
}
}
/*
* Create and initialize buffer.
*/
Buffer *b = malloc(sizeof *b);
b->in = b->out = 0;
/*
* Create the producer, the consumers and the monitor.
*/
m = uthread_create(monitor, b);
p1 = uthread_create(producer, b);
c1 = uthread_create(consumer, b);
uthread_detach(m);
/*
* Wait for the threads to terminate.
*/
uthread_join(p1, NULL);
uthread_join(c1, NULL);
fprintf(stderr, “b->in = %ld, b->out = %ld\n”, b->in, b->out);
return 0;
}