Index: doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp	(revision 73fbe91d62a425ae1635a53f34682279e7767750)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp	(revision 73fbe91d62a425ae1635a53f34682279e7767750)
@@ -0,0 +1,212 @@
+#include "thrdlib/thread.h"
+
+#include <cassert>
+
+#include <algorithm>
+#include <atomic>
+#include <memory>
+#include <vector>
+
+//--------------------
+// Constants
+unsigned nframes;
+unsigned fsize;
+unsigned nproduce;
+
+//--------------------
+// Frame management
+
+class Frame {
+	static const thread_t reset;
+	static const thread_t set;
+	std::atomic<thread_t> rdy_state = { reset };
+	std::atomic<thread_t> rnd_state = { set };
+public:
+	unsigned number;
+	std::unique_ptr<unsigned char[]> data;
+
+private:
+	inline bool wait( thread_t self, std::atomic<thread_t> & state, std::atomic<thread_t> & other ) {
+		bool ret;
+		while(true) {
+			thread_t expected = state;
+			if( expected == set ) { ret = false; goto END; }
+			assert( expected == reset );
+			if( std::atomic_compare_exchange_strong( &state, &expected, self) ) {
+				thrdlib_park( self );
+				ret = true;
+				goto END;
+			}
+		}
+		END:
+		assert( state == set );
+		assert( other != set );
+		state = reset;
+		return ret;
+	}
+
+	inline bool publish(  std::atomic<thread_t> & state ) {
+		thread_t got = std::atomic_exchange( &state, set );
+		assert( got != set );
+
+		if( got == reset ) return false;
+
+		thrdlib_unpark( got );
+		return true;
+	}
+
+public:
+	inline bool wait_rendered( thread_t self ) {
+		return wait( self, rnd_state, rdy_state );
+	}
+
+	inline bool wait_ready   ( thread_t self ) {
+		return wait( self, rdy_state, rnd_state );
+	}
+
+	inline bool publish() {
+		return publish( rdy_state );
+	}
+
+	inline bool release() {
+		return publish( rnd_state );
+	}
+};
+
+const thread_t Frame::reset = nullptr;
+const thread_t Frame::set   = reinterpret_cast<thread_t>(1);
+
+std::unique_ptr<Frame[]> frames;
+volatile unsigned last_produced = 0;
+
+//--------------------
+// Threads
+thread_t volatile the_stats_thread = nullptr;
+
+inline void fence(void) {
+	std::atomic_thread_fence(std::memory_order_seq_cst);
+}
+
+struct {
+	struct {
+		volatile unsigned long long   parks = 0;
+		volatile unsigned long long unparks = 0;
+	} sim;
+	struct {
+		volatile unsigned long long   parks = 0;
+		volatile unsigned long long unparks = 0;
+	} rend;
+
+	struct {
+		volatile unsigned long long ran = 0;
+		volatile unsigned long long saw = 0;
+	} stats;
+} thrd_stats;
+
+void Stats( thread_t self ) {
+	the_stats_thread = self;
+	fence();
+	thrdlib_park( self );
+
+	std::vector<bool> seen;
+	seen.resize(nproduce, false);
+
+	while(last_produced < nproduce) {
+		thrdlib_yield();
+		thrd_stats.stats.ran++;
+		if( last_produced > 0 ) seen.at(last_produced - 1) = true;
+	}
+
+	thrd_stats.stats.saw = std::count(seen.begin(), seen.end(), true);
+}
+
+void Simulator( thread_t self ) {
+	for(unsigned i = 0; i < nproduce; i++) {
+		auto & frame = frames[i % nframes];
+		// Wait for the frames to be rendered
+		if( frame.wait_rendered( self ) ) {
+			thrd_stats.sim.parks++;
+		}
+
+		// Write the frame information
+		frame.number = i;
+		for( unsigned x = 0; x < fsize; x++ ) {
+			frame.data[x] = i;
+		}
+		std::cout << "Simulated " << i << std::endl;
+		last_produced = i+1;
+
+		// Publish it
+		if( frame.publish()  ) {
+			thrd_stats.sim.unparks++;
+		}
+	}
+}
+
+void Renderer( thread_t self ) {
+	thrdlib_unpark( the_stats_thread );
+	for(unsigned i = 0; i < nproduce; i++) {
+		auto & frame = frames[i % nframes];
+		// Wait for the frames to be ready
+		if( frame.wait_ready( self ) ) {
+			thrd_stats.rend.parks++;
+		}
+
+		// Render the frame
+		unsigned total = 0;
+		for( unsigned x = 0; x < fsize; x++ ) {
+			total += frame.data[x];
+		}
+
+		std::cout << "Rendered " << i << std::endl;
+		assert(total == i * fsize);
+
+		// Release
+		if( frame.release() ) {
+			thrd_stats.rend.unparks++;
+		}
+	}
+
+}
+
+
+
+int main() {
+	nframes  = 3;
+	fsize    = 1000;
+	nproduce = 60;
+
+	frames.reset(new Frame[nframes]);
+	for(unsigned i = 0; i < nframes; i++) {
+		frames[i].number = 0;
+		frames[i].data.reset(new unsigned char[fsize]);
+	}
+	std::cout << "Created frames" << std::endl;
+
+	thrdlib_setproccnt( 2 );
+
+	thread_t stats     = thrdlib_create( Stats     );
+	std::cout << "Created Stats Thread" << std::endl;
+	while( the_stats_thread == nullptr ) thrdlib_yield();
+	std::cout << "Creating Main Threads" << std::endl;
+	thread_t renderer  = thrdlib_create( Renderer  );
+	// while(true);
+	thread_t simulator = thrdlib_create( Simulator );
+
+	std::cout << "Running" << std::endl;
+
+	thrdlib_join( simulator );
+	thrdlib_join( renderer  );
+	thrdlib_join( stats     );
+
+	std::cout << "----------" << std::endl;
+	std::cout << "# Parks" << std::endl;
+	std::cout << "  Renderer   park: " << thrd_stats. sim.  parks << std::endl;
+	std::cout << "  Renderer unpark: " << thrd_stats. sim.unparks << std::endl;
+	std::cout << " Simulator   park: " << thrd_stats.rend.  parks << std::endl;
+	std::cout << " Simulator unpark: " << thrd_stats.rend.unparks << std::endl;
+
+	std::cout << "Stats thread" << std::endl;
+	std::cout << " Ran             : " << thrd_stats.stats.ran << " times" << std::endl;
+	std::cout << " Saw             : " << thrd_stats.stats.saw << " (" << ((100.f * thrd_stats.stats.saw) / nproduce) << "%)" << std::endl;
+}
Index: doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.h
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.h	(revision 73fbe91d62a425ae1635a53f34682279e7767750)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread.h	(revision 73fbe91d62a425ae1635a53f34682279e7767750)
@@ -0,0 +1,2 @@
+
+#include "thread_pthread.h"
Index: doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread_pthread.h
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread_pthread.h	(revision 73fbe91d62a425ae1635a53f34682279e7767750)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/thrdlib/thread_pthread.h	(revision 73fbe91d62a425ae1635a53f34682279e7767750)
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <pthread.h>
+#include <errno.h>
+#include <cstring>
+#include <cstdio>
+#include <iostream>
+
+#define CHECKED(x) { int err = x; if( err != 0 ) { std::cerr << "KERNEL ERROR: Operation \"" #x "\" return error " << err << " - " << strerror(err) << std::endl; std::abort(); } }
+
+struct __bin_sem_t {
+	pthread_mutex_t 	lock;
+	pthread_cond_t  	cond;
+	int     		val;
+
+	__bin_sem_t() {
+		// Create the mutex with error checking
+		pthread_mutexattr_t mattr;
+		pthread_mutexattr_init( &mattr );
+		pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
+		pthread_mutex_init(&lock, &mattr);
+
+		pthread_cond_init (&cond, nullptr);
+		val = 0;
+	}
+
+	~__bin_sem_t() {
+		CHECKED( pthread_mutex_destroy(&lock) );
+		CHECKED( pthread_cond_destroy (&cond) );
+	}
+
+	void wait() {
+		CHECKED( pthread_mutex_lock(&lock) );
+			while(val < 1) {
+				pthread_cond_wait(&cond, &lock);
+			}
+			val -= 1;
+		CHECKED( pthread_mutex_unlock(&lock) );
+	}
+
+	bool post() {
+		bool needs_signal = false;
+
+		CHECKED( pthread_mutex_lock(&lock) );
+			if(val < 1) {
+				val += 1;
+				pthread_cond_signal(&cond);
+				needs_signal = true;
+			}
+		CHECKED( pthread_mutex_unlock(&lock) );
+
+		return needs_signal;
+	}
+};
+
+#undef CHECKED
+
+#if defined(__cforall) || defined(__cpluplus)
+extern "C" {
+#endif
+	//--------------------
+	// Basic types
+	struct pthread_runner_t {
+		pthread_t handle;
+		__bin_sem_t sem;
+	};
+	typedef pthread_runner_t * thread_t;
+
+	//--------------------
+	// Basic thread support
+	thread_t thrdlib_create( void (*main)( thread_t ) ) {
+		thread_t thrd = new pthread_runner_t();
+		int r = pthread_create( &thrd->handle, nullptr, (void *(*)(void *))main, thrd );
+		if( r != 0 ) std::abort();
+		return thrd;
+	}
+
+	void thrdlib_join( thread_t handle ) {
+		void * ret;
+		int r = pthread_join( handle->handle, &ret );
+		if( r != 0 ) std::abort();
+		delete handle;
+	}
+
+	void thrdlib_park( thread_t handle ) {
+		handle->sem.wait();
+	}
+
+	void thrdlib_unpark( thread_t handle ) {
+		handle->sem.post();
+	}
+
+	void thrdlib_yield( void ) {
+		int r = pthread_yield();
+		if( r != 0 ) std::abort();
+	}
+
+	//--------------------
+	// Basic kernel features
+	void thrdlib_setproccnt( int ) {
+
+	}
+
+
+#if defined(__cforall) || defined(__cpluplus)
+}
+#endif
