//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// boundedBufferEXT.c --
//
// Author           : Peter A. Buhr
// Created On       : Wed Apr 18 22:52:12 2018
// Last Modified By : Peter A. Buhr
// Last Modified On : Thu Aug 16 08:17:03 2018
// Update Count     : 8
//

#include <stdlib.hfa>										// random
#include <fstream.hfa>
#include <kernel.hfa>
#include <thread.hfa>
#include <unistd.h>										// getpid

//Duration default_preemption() { return 0; }

enum { BufferSize = 50 };

forall( otype T ) {
	monitor Buffer {
		int front, back, count;
		T elements[BufferSize];
	}; // Buffer

	void ?{}( Buffer(T) & buffer ) with( buffer ) { [front, back, count] = 0; }

	int query( Buffer(T) & buffer ) { return buffer.count; } // read-only, no mutual exclusion

	T remove( Buffer(T) & mutex buffer );				// forward

	void insert( Buffer(T) & mutex buffer, T elem ) with( buffer ) {
		if ( count == BufferSize ) waitfor( remove, buffer );
		elements[back] = elem;
		back = ( back + 1 ) % BufferSize;
		count += 1;
	} // insert

	T remove( Buffer(T) & mutex buffer ) with( buffer ) {
		if ( count == 0 ) waitfor( insert, buffer );
		T elem = elements[front];
		front = ( front + 1 ) % BufferSize;
		count -= 1;
		return elem;
	} // remove
}

const int Sentinel = -1;

thread Producer {
	Buffer(int) & buffer;
	unsigned int N;
};
void main( Producer & prod ) with( prod ) {
	for ( int i = 1; i <= N; i += 1 ) {
		yield( random( 5 ) );
		insert( buffer, 1 );
	} // for
}
void ?{}( Producer & prod, Buffer(int) * buffer, int N ) {
	&prod.buffer = buffer;
	prod.N = N;
}

thread Consumer {
	Buffer(int) & buffer;
	int & sum;											// summation of producer values
};
void main( Consumer & cons ) with( cons ) {
	sum = 0;
	for () {
		yield( random( 5 ) );
		int item = remove( buffer );
	  if ( item == Sentinel ) break;					// sentinel ?
		sum += item;
	} // for
}
void ?{}( Consumer & cons, Buffer(int) * buffer, int & sum ) {
	&cons.buffer = buffer;
	&cons.sum = &sum;
}

int main() {
	Buffer(int) buffer;
	enum { Prods = 4, Cons = 5 };
	Producer * prods[Prods];
	Consumer * cons[Cons];
	int sums[Cons];
	int i;
	processor p;

	//srandom( getpid() );
	srandom( 1003 );

	for ( i = 0; i < Cons; i += 1 ) {					// create consumers
		cons[i] = new( &buffer, sums[i] );
	} // for
	for ( i = 0; i < Prods; i += 1 ) {					// create producers
		prods[i] = new( &buffer, 100000 );
	} // for

	for ( i = 0; i < Prods; i += 1 ) {					// wait for producers to finish
		delete( prods[i] );
	} // for
	for ( i = 0; i < Cons; i += 1 ) {					// generate sentinal values to stop consumers
		insert( buffer, Sentinel );
	} // for
	int sum = 0;
	for ( i = 0; i < Cons; i += 1 ) {					// wait for consumers to finish
		delete( cons[i] );
		sum += sums[i];
	} // for
	sout | "total:" | sum | endl;
}

// Local Variables: //
// tab-width: 4 //
// compile-command: "cfa boundedBufferEXT.c" //
// End: //
