Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/contend.cfa
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/contend.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/contend.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,99 @@
+#include <select.hfa>
+#include <thread.hfa>
+#include <channel.hfa>
+#include <locks.hfa>
+#include <fstream.hfa>
+#include <stdio.h>
+#include <time.hfa>
+#include <string.h>
+
+// #define NUM_CHANS 1
+#define GLUE_HELPER(x, y) x##y
+#define FN_GLUE(x, y) GLUE_HELPER(x, y)
+
+size_t Processors = 2, Producers = 1, Consumers = 1, ChannelSize = 10;
+
+channel(size_t) * chans;
+
+static inline void cons_wait_1( size_t & val ) { waituntil( val << chans[0] ) {} }
+static inline void cons_wait_2( size_t & val ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} }
+static inline void cons_wait_3( size_t & val ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} }
+static inline void cons_wait_4( size_t & val ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} }
+static inline void cons_wait_5( size_t & val ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or waituntil( val << chans[4] ) {} }
+static inline void cons_wait_6( size_t & val ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or waituntil( val << chans[4] ) {} or waituntil( val << chans[5] ) {} }
+static inline void cons_wait_7( size_t & val ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or waituntil( val << chans[4] ) {} or waituntil( val << chans[5] ) {} or waituntil( val << chans[6] ) {} }
+static inline void cons_wait_8( size_t & val ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or waituntil( val << chans[4] ) {} or waituntil( val << chans[5] ) {} or waituntil( val << chans[6] ) {} or waituntil( val << chans[7] ) {}}
+
+static inline void prods_wait_1( size_t val ) { waituntil( chans[0] << val ) {} }
+static inline void prods_wait_2( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} }
+static inline void prods_wait_3( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} }
+static inline void prods_wait_4( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} }
+static inline void prods_wait_5( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or waituntil( chans[4] << val ) {} }
+static inline void prods_wait_6( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or waituntil( chans[4] << val ) {} or waituntil( chans[5] << val ) {} }
+static inline void prods_wait_7( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or waituntil( chans[4] << val ) {} or waituntil( chans[5] << val ) {} or waituntil( chans[6] << val ) {} }
+static inline void prods_wait_8( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or waituntil( chans[4] << val ) {} or waituntil( chans[5] << val ) {} or waituntil( chans[6] << val ) {} or waituntil( chans[7] << val ) {}}
+
+size_t globalTotal = 0;
+
+thread Consumer {};
+void main( Consumer & this ) {
+    size_t val, i = 0;
+    try {
+        for(;; i++ ) {
+            FN_GLUE(cons_wait_, NUM_CHANS)(val);
+        }
+    } catch( channel_closed * e ) {}
+    __atomic_fetch_add( &globalTotal, i, __ATOMIC_SEQ_CST );
+}
+
+thread Producer {};
+void main( Producer & this ) {
+    try {
+        for( size_t i = 0;; i++ ) {
+            FN_GLUE(prods_wait_, NUM_CHANS)(i);
+        }
+    } catch( channel_closed * e ) {}
+}
+
+int main( int argc, char * argv[] ) {
+    switch ( argc ) {
+	  case 3:
+		if ( strcmp( argv[2], "d" ) != 0 ) {			// default ?
+			ChannelSize = atoi( argv[2] );
+		} // if
+	  case 2:
+		if ( strcmp( argv[1], "d" ) != 0 ) {			// default ?
+			Processors = atoi( argv[1] );
+			if ( Processors < 1 ) goto Usage;
+		} // if
+	  case 1:											// use defaults
+		break;
+	  default:
+	  Usage:
+		sout | "Usage: " | argv[0]
+             | " [ processors (> 0) | 'd' (default " | Processors
+			 | ") ] [ channel size (>= 0) | 'd' (default " | ChannelSize
+			 | ") ]" ;
+		exit( EXIT_FAILURE );
+	} // switch
+    Producers = Processors / 2;
+    Consumers = Processors / 2;
+
+    processor p[Processors - 1];
+
+    chans = aalloc( NUM_CHANS );
+    for ( i; NUM_CHANS )
+        chans[i]{ ChannelSize };
+
+    {
+        Producer p[Producers];
+        Consumer c[Consumers];
+
+        sleep(10`s);
+
+        for ( i; NUM_CHANS )
+            close( chans[i] );
+    }
+    adelete( chans );
+    printf("%zu\n", globalTotal);
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/future.cfa
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/future.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/future.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,182 @@
+#include <select.hfa>
+#include <thread.hfa>
+#include <future.hfa>
+#include <fstream.hfa>
+#include <stdio.h>
+#include <time.hfa>
+#include <string.h>
+
+// #define ANDOR
+
+size_t Processors = 2, Time = 10;
+
+size_t globalTotal = 0;
+future(size_t) A, B, C;
+volatile bool done_loop = false;
+volatile bool client_done = false;
+volatile bool server_done = false;
+
+static inline void wait() {
+    #ifdef OR
+    waituntil( A ) { get( A ); }
+    or waituntil( B ) { get( B ); }
+    or waituntil( C ) { get( C ); }
+    #endif
+    #ifdef AND
+    waituntil( A ) { get( A ); }
+    and waituntil( B ) { get( B ); }
+    #endif
+    #ifdef AND3
+    waituntil( A ) { get( A ); }
+    and waituntil( B ) { get( B ); }
+    and waituntil( C ) { get( C ); }
+    #endif
+    #ifdef ANDOR
+    waituntil( A ) { get( A ); }
+    and waituntil( B ) { get( B ); }
+    or waituntil( C ) { get( C ); }
+    #endif
+    #ifdef ORAND
+    (waituntil( A ) { get( A ); }
+    or waituntil( B ) { get( B ); })
+    and waituntil( C ) { get( C ); }
+    #endif
+    #ifdef BASIC
+    get( A );
+    #endif
+}
+
+static inline fulfill( size_t i ) {
+    #ifdef OR
+    if ( i % 3 == 0 ) {
+        fulfil(A, i);
+    } else if ( i % 3 == 1 ) {
+        fulfil(B, i);
+    } else {
+        fulfil(C, i);
+    }
+    #endif
+    #ifdef AND
+    if ( i % 2 == 0 ) {
+        fulfil(A, i);
+        fulfil(B, i);
+    } else {
+        fulfil(B, i);
+        fulfil(A, i);
+    }
+    #endif
+    #ifdef AND3
+    if ( i % 6 == 0 ) {
+        fulfil(A, i);
+        fulfil(B, i);
+        fulfil(C, i);
+    } else if ( i % 6 == 1 ) {
+        fulfil(A, i);
+        fulfil(C, i);
+        fulfil(B, i);
+    } else if ( i % 6 == 2 ) {
+        fulfil(B, i);
+        fulfil(A, i);
+        fulfil(C, i);
+    } else if ( i % 6 == 3 ) {
+        fulfil(B, i);
+        fulfil(C, i);
+        fulfil(A, i);
+    } else if ( i % 6 == 4 ) {
+        fulfil(C, i);
+        fulfil(A, i);
+        fulfil(B, i);
+    } else if ( i % 6 == 5 ) {
+        fulfil(C, i);
+        fulfil(B, i);
+        fulfil(A, i);
+    }
+    #endif
+    #ifdef ANDOR
+    if ( i % 4 == 0 ) {
+        fulfil(A, i);
+        fulfil(B, i);
+    } else if ( i % 4 == 1 ) {
+        fulfil(A, i);
+        fulfil(C, i);
+    } else if ( i % 4 == 2 ) {
+        fulfil(B, i);
+        fulfil(C, i);
+    } else {
+        fulfil(C, i);
+    }
+    #endif
+    #ifdef ORAND
+    if ( i % 4 == 0 ) {
+        fulfil(A, i);
+        fulfil(C, i);
+    } else if ( i % 4 == 1 ) {
+        fulfil(C, i);
+        fulfil(A, i);
+    } else if ( i % 4 == 2 ) {
+        fulfil(B, i);
+        fulfil(C, i);
+    } else {
+        fulfil(C, i);
+        fulfil(B, i);
+    }
+    #endif
+    #ifdef BASIC
+    fulfil(A, i);
+    #endif
+}
+
+thread Client {};
+void main( Client & this ) {
+    size_t i = 0;
+    for(; !client_done; i++ ) {
+        wait();
+        reset( A );
+        reset( B );
+        reset( C );
+        done_loop = true;
+    }
+    __atomic_fetch_add( &globalTotal, i, __ATOMIC_SEQ_CST );
+}
+
+thread Server {};
+void main( Server & this ) {
+    for( size_t i = 0; !server_done; i++ ) {
+        fulfill( i );
+        while( !done_loop ) {}
+        done_loop = false;
+    }
+}
+
+int main( int argc, char * argv[] ) {
+    switch ( argc ) {
+	  case 2:
+		if ( strcmp( argv[1], "d" ) != 0 ) {			// default ?
+			Time = atoi( argv[1] );
+			if ( Time < 0 ) goto Usage;
+		} // if
+	  case 1:											// use defaults
+		break;
+	  default:
+	  Usage:
+		sout | "Usage: " | argv[0]
+             | "[ time (>= 0) | 'd' (default " | Time
+			 | ") ]" ;
+		exit( EXIT_FAILURE );
+	} // switch
+    processor p[Processors - 1];
+
+    {
+        Server s;
+        {
+            Client c;
+
+            sleep(Time`s);
+
+            client_done = true;
+        }
+        server_done = true;
+        done_loop = true;
+    }
+    printf("%zu\n", globalTotal);
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/order.cfa
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/order.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/order.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,77 @@
+#include <select.hfa>
+#include <thread.hfa>
+#include <channel.hfa>
+#include <locks.hfa>
+#include <fstream.hfa>
+#include <stdio.h>
+#include <time.hfa>
+#include <string.h>
+
+size_t ChannelSize = 100, Channels = 2;
+
+channel(size_t) * chans;
+
+size_t globalTotal = 0;
+int cons_counter = 0, prod_counter = 0;
+
+thread SelectConsumer {};
+void main( SelectConsumer & this ) {
+    size_t val, i = 0;
+    try {
+        for(;; i++ ) {
+            waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {}
+        }
+    } catch( channel_closed * e ) {}
+    __atomic_fetch_add( &globalTotal, i, __ATOMIC_SEQ_CST );
+}
+
+thread SelectProducer {};
+void main( SelectProducer & this ) {
+    try {
+        for( size_t i = 0;; i++ ) {
+            waituntil( chans[0] << i ) {} or waituntil( chans[1] << i ) {}
+        }
+    } catch( channel_closed * e ) {}
+}
+
+thread Consumer {};
+void main( Consumer & this ) {
+    size_t val, i = 0;
+    try {
+        for(;; i++ ) {
+            remove( chans[1] );
+        }
+    } catch( channel_closed * e ) {}
+    __atomic_fetch_add( &globalTotal, i, __ATOMIC_SEQ_CST );
+}
+
+thread Producer {};
+void main( Producer & this ) {
+    try {
+        for( size_t i = 0;; i++ ) {
+            insert( chans[1], i );
+        }
+    } catch( channel_closed * e ) {}
+}
+
+int main( int argc, char * argv[] ) {
+    processor p[3];
+
+    chans = aalloc( Channels );
+    for ( i; Channels )
+        chans[i]{ ChannelSize };
+
+    {
+        Producer p;
+        SelectProducer sp;
+        Consumer c;
+        SelectConsumer sc;
+
+        sleep(10`s);
+
+        for ( i; Channels )
+            close( chans[i] );
+    }
+    adelete( chans );
+    printf("%zu\n", globalTotal);
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/sidechan.cfa
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/sidechan.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/sidechan.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,100 @@
+#include <select.hfa>
+#include <thread.hfa>
+#include <channel.hfa>
+#include <locks.hfa>
+#include <fstream.hfa>
+#include <stdio.h>
+#include <time.hfa>
+#include <string.h>
+
+size_t Sets = 1, ChannelSize = 100, Channels = 2;
+
+channel(size_t) * chans;
+
+size_t globalTotal = 0;
+int cons_counter = 0, prod_counter = 0;
+
+thread SelectConsumer {};
+void main( SelectConsumer & this ) {
+    size_t val, i = 0;
+    try {
+        for(;; i++ ) {
+            waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {}
+        }
+    } catch( channel_closed * e ) {}
+    __atomic_fetch_add( &globalTotal, i, __ATOMIC_SEQ_CST );
+}
+
+thread SelectProducer {};
+void main( SelectProducer & this ) {
+    try {
+        for( size_t i = 0;; i++ ) {
+            waituntil( chans[0] << i ) {} or waituntil( chans[1] << i ) {}
+        }
+    } catch( channel_closed * e ) {}
+}
+
+thread Consumer {};
+void main( Consumer & this ) {
+    const int idx = __atomic_fetch_add( &cons_counter, 1, __ATOMIC_SEQ_CST ) % Channels;
+    size_t val, i = 0;
+    try {
+        for(;; i++ ) {
+            remove( chans[idx] );
+        }
+    } catch( channel_closed * e ) {}
+    __atomic_fetch_add( &globalTotal, i, __ATOMIC_SEQ_CST );
+}
+
+thread Producer {};
+void main( Producer & this ) {
+    const int idx = __atomic_fetch_add( &prod_counter, 1, __ATOMIC_SEQ_CST ) % Channels;
+    try {
+        for( size_t i = 0;; i++ ) {
+            insert( chans[idx], i );
+        }
+    } catch( channel_closed * e ) {}
+}
+
+int main( int argc, char * argv[] ) {
+    switch ( argc ) {
+	  case 3:
+		if ( strcmp( argv[2], "d" ) != 0 ) {			// default ?
+			ChannelSize = atoi( argv[2] );
+		} // if
+	  case 2:
+		if ( strcmp( argv[1], "d" ) != 0 ) {			// default ?
+			Sets = atoi( argv[1] );
+			if ( Sets < 1 ) goto Usage;
+		} // if
+	  case 1:											// use defaults
+		break;
+	  default:
+	  Usage:
+		sout | "Usage: " | argv[0]
+             | " [ sets (> 0) | 'd' (default " | Sets
+			 | ") ] [ channel size (>= 0) | 'd' (default " | ChannelSize
+			 | ") ]" ;
+		exit( EXIT_FAILURE );
+	} // switch
+
+    processor p[Sets * 2 + Sets * Channels * 2 - 1];
+
+    chans = aalloc( Channels );
+    for ( i; Channels )
+        chans[i]{ ChannelSize };
+
+    {
+        Producer p[Sets * Channels];
+        SelectProducer sp[Sets];
+        Consumer c[Sets * Channels];
+        SelectConsumer sc[Sets];
+
+        sleep(10`s);
+
+        for ( i; Channels )
+            close( chans[i] );
+    }
+    adelete( chans );
+    printf("%zu\n", globalTotal);
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/spin.cfa
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/spin.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/cfa/spin.cfa	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,99 @@
+#include <select.hfa>
+#include <thread.hfa>
+#include <channel.hfa>
+#include <locks.hfa>
+#include <fstream.hfa>
+#include <stdio.h>
+#include <time.hfa>
+#include <string.h>
+
+// #define NUM_CHANS 1
+#define GLUE_HELPER(x, y) x##y
+#define FN_GLUE(x, y) GLUE_HELPER(x, y)
+
+size_t Processors = 2, Producers = 1, Consumers = 1, ChannelSize = 10;
+
+channel(size_t) * chans;
+
+static inline void cons_wait_1( size_t & val, size_t & i ) { waituntil( val << chans[0] ) {} or else { i--; }  }
+static inline void cons_wait_2( size_t & val, size_t & i ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or else { i--; }  }
+static inline void cons_wait_3( size_t & val, size_t & i ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or else { i--; }  }
+static inline void cons_wait_4( size_t & val, size_t & i ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or else { i--; }  }
+static inline void cons_wait_5( size_t & val, size_t & i ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or waituntil( val << chans[4] ) {} or else { i--; }  }
+static inline void cons_wait_6( size_t & val, size_t & i ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or waituntil( val << chans[4] ) {} or waituntil( val << chans[5] ) {} or else { i--; }  }
+static inline void cons_wait_7( size_t & val, size_t & i ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or waituntil( val << chans[4] ) {} or waituntil( val << chans[5] ) {} or waituntil( val << chans[6] ) {} or else { i--; }  }
+static inline void cons_wait_8( size_t & val, size_t & i ) { waituntil( val << chans[0] ) {} or waituntil( val << chans[1] ) {} or waituntil( val << chans[2] ) {} or waituntil( val << chans[3] ) {} or waituntil( val << chans[4] ) {} or waituntil( val << chans[5] ) {} or waituntil( val << chans[6] ) {} or waituntil( val << chans[7] ) {} or else { i--; } }
+
+static inline void prods_wait_1( size_t val ) { waituntil( chans[0] << val ) {} or else {} }
+static inline void prods_wait_2( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or else {} }
+static inline void prods_wait_3( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or else {} }
+static inline void prods_wait_4( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or else {} }
+static inline void prods_wait_5( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or waituntil( chans[4] << val ) {} or else {} }
+static inline void prods_wait_6( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or waituntil( chans[4] << val ) {} or waituntil( chans[5] << val ) {} or else {} }
+static inline void prods_wait_7( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or waituntil( chans[4] << val ) {} or waituntil( chans[5] << val ) {} or waituntil( chans[6] << val ) {} or else {} }
+static inline void prods_wait_8( size_t val ) { waituntil( chans[0] << val ) {} or waituntil( chans[1] << val ) {} or waituntil( chans[2] << val ) {} or waituntil( chans[3] << val ) {} or waituntil( chans[4] << val ) {} or waituntil( chans[5] << val ) {} or waituntil( chans[6] << val ) {} or waituntil( chans[7] << val ) {} or else {} }
+
+size_t globalTotal = 0;
+
+thread Consumer {};
+void main( Consumer & this ) {
+    size_t val, i = 0;
+    try {
+        for(;; i++ ) {
+            FN_GLUE(cons_wait_, NUM_CHANS)(val, i);
+        }
+    } catch( channel_closed * e ) {}
+    __atomic_fetch_add( &globalTotal, i, __ATOMIC_SEQ_CST );
+}
+
+thread Producer {};
+void main( Producer & this ) {
+    try {
+        for( size_t i = 0;; i++ ) {
+            FN_GLUE(prods_wait_, NUM_CHANS)(i);
+        }
+    } catch( channel_closed * e ) {}
+}
+
+int main( int argc, char * argv[] ) {
+    switch ( argc ) {
+	  case 3:
+		if ( strcmp( argv[2], "d" ) != 0 ) {			// default ?
+			ChannelSize = atoi( argv[2] );
+		} // if
+	  case 2:
+		if ( strcmp( argv[1], "d" ) != 0 ) {			// default ?
+			Processors = atoi( argv[1] );
+			if ( Processors < 1 ) goto Usage;
+		} // if
+	  case 1:											// use defaults
+		break;
+	  default:
+	  Usage:
+		sout | "Usage: " | argv[0]
+             | " [ processors (> 0) | 'd' (default " | Processors
+			 | ") ] [ channel size (>= 0) | 'd' (default " | ChannelSize
+			 | ") ]" ;
+		exit( EXIT_FAILURE );
+	} // switch
+    Producers = Processors / 2;
+    Consumers = Processors / 2;
+
+    processor p[Processors - 1];
+
+    chans = aalloc( NUM_CHANS );
+    for ( i; NUM_CHANS )
+        chans[i]{ ChannelSize };
+
+    {
+        Producer p[Producers];
+        Consumer c[Consumers];
+
+        sleep(10`s);
+
+        for ( i; NUM_CHANS )
+            close( chans[i] );
+    }
+    adelete( chans );
+    printf("%zu\n", globalTotal);
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus.txt
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus.txt	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus.txt	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,464 @@
+5
+2 4 8 16 24 32
+6 12 18 24 30
+CFA Go 
+contend2: 
+CFA:
+cores	throughput (entries)
+2	19898679
+2	19894150
+2	20137125
+2	19991476
+2	19234635
+4	24597417
+4	23137681
+4	23918947
+4	23122373
+4	24953526
+8	10070010
+8	9620363
+8	9545751
+8	9424066
+8	9460164
+16	6753442
+16	6886566
+16	7291622
+16	6762093
+16	6695073
+24	5786637
+24	6567375
+24	6523225
+24	6611613
+24	6535767
+32	6227126
+32	5669331
+32	5618844
+32	6231765
+32	5572424
+Go:
+cores	throughput (entries)
+2	40037157
+2	38945848
+2	37571150
+2	39936025
+2	37039238
+4	32175550
+4	31962675
+4	32105762
+4	31933749
+4	31992633
+8	15195906
+8	16230217
+8	15627983
+8	15570514
+8	16559040
+16	7221728
+16	6952933
+16	7086069
+16	7031895
+16	7093710
+24	4978681
+24	5140366
+24	5128459
+24	4630814
+24	4676848
+32	4131795
+32	4105783
+32	4481729
+32	4272797
+32	4268574
+contend4: 
+CFA:
+cores	throughput (entries)
+2	16339398
+2	14695219
+2	13848084
+2	16291888
+2	15029757
+4	19966677
+4	20854760
+4	19653169
+4	19833858
+4	21023458
+8	10699611
+8	11219280
+8	10511145
+8	11041690
+8	10967281
+16	7290494
+16	7218116
+16	7842921
+16	7623273
+16	7330702
+24	6109672
+24	6581276
+24	6395101
+24	6472148
+24	6199770
+32	6673246
+32	6836995
+32	6767080
+32	6038521
+32	6864899
+Go:
+cores	throughput (entries)
+2	20077486
+2	20275897
+2	20038097
+2	19919690
+2	20116470
+4	20032686
+4	19957974
+4	20134395
+4	20067732
+4	20055099
+8	11869308
+8	12165199
+8	11236909
+8	12228766
+8	12011988
+16	8018777
+16	8040533
+16	8026976
+16	7952682
+16	7853705
+24	6857428
+24	6334115
+24	6325502
+24	7042792
+24	6902630
+32	4949042
+32	4967659
+32	6227926
+32	6243556
+32	5023701
+contend8: 
+CFA:
+cores	throughput (entries)
+2	3915791
+2	3886691
+2	3959442
+2	4981399
+2	3941817
+4	11127006
+4	11221830
+4	11079265
+4	11151398
+4	11224959
+8	9223444
+8	9024163
+8	9123901
+8	9087014
+8	9453781
+16	7377324
+16	7136077
+16	6563752
+16	7158678
+16	6541387
+24	5955510
+24	5996812
+24	5746359
+24	6361212
+24	5918614
+32	6357515
+32	5691522
+32	6263042
+32	6347267
+32	6368643
+Go:
+cores	throughput (entries)
+2	11062704
+2	11834447
+2	11977981
+2	10213219
+2	11076487
+4	15936414
+4	15949952
+4	15949080
+4	15934646
+4	15939730
+8	8723728
+8	8543977
+8	8526952
+8	9357181
+8	9139019
+16	6443224
+16	6722238
+16	7064065
+16	7531808
+16	7044549
+24	5340807
+24	5546286
+24	6487048
+24	5620639
+24	6466995
+32	4698418
+32	3932033
+32	5878789
+32	4682276
+32	5956515
+spin2: 
+CFA:
+cores	throughput (entries)
+2	17117536
+2	20202783
+2	20556179
+2	20392088
+2	20470298
+4	25887873
+4	25952265
+4	25848766
+4	25837700
+4	25801944
+8	11134838
+8	11555854
+8	11188929
+8	11128470
+8	11699863
+16	8258208
+16	8448259
+16	7713563
+16	7775916
+16	8421946
+24	7250842
+24	7302187
+24	7447901
+24	7262134
+24	6677079
+32	6216074
+32	6948262
+32	6200769
+32	6901374
+32	6114399
+Go:
+cores	throughput (entries)
+2	51893214
+2	51889467
+2	51939463
+2	51801002
+2	51903499
+4	48397770
+4	48273065
+4	48357522
+4	48414843
+4	48354460
+8	17017886
+8	15747240
+8	17507556
+8	16836401
+8	16991476
+16	9864825
+16	9736384
+16	9466884
+16	10636287
+16	11018805
+24	8878797
+24	8309111
+24	8382343
+24	8208643
+24	8267685
+32	7726655
+32	8676947
+32	9565782
+32	7378698
+32	8821379
+spin4: 
+CFA:
+cores	throughput (entries)
+2	10885361
+2	10986228
+2	10922593
+2	10981854
+2	10802839
+4	20170365
+4	20575238
+4	21331044
+4	20673253
+4	18556265
+8	11737217
+8	11748248
+8	11486998
+8	12242609
+8	12343969
+16	7973731
+16	8434888
+16	7739464
+16	8085925
+16	8451073
+24	7494298
+24	7770603
+24	6847549
+24	6848642
+24	6955404
+32	6283388
+32	6267627
+32	6394047
+32	7238228
+32	6447263
+Go:
+cores	throughput (entries)
+2	24474628
+2	24450635
+2	24464130
+2	24388835
+2	24399848
+4	21964092
+4	21927900
+4	21917894
+4	21907439
+4	21919829
+8	9292641
+8	9897648
+8	10087481
+8	9856804
+8	9352230
+16	6875204
+16	7275156
+16	7308155
+16	6185134
+16	7332646
+24	5314855
+24	6130990
+24	6137104
+24	6149285
+24	6138690
+32	5794913
+32	4410110
+32	5699670
+32	5804679
+32	5715486
+spin8: 
+CFA:
+cores	throughput (entries)
+2	7533145
+2	7594283
+2	7638398
+2	7594530
+2	7485690
+4	16766189
+4	18061179
+4	17993902
+4	18011040
+4	16460498
+8	10867024
+8	10843424
+8	11083909
+8	10948061
+8	10822110
+16	7501685
+16	8353481
+16	7320773
+16	7526689
+16	8246035
+24	7236819
+24	6972608
+24	6408133
+24	6354528
+24	6509391
+32	5836946
+32	6608952
+32	6641278
+32	6795005
+32	5860346
+Go:
+cores	throughput (entries)
+2	13790874
+2	14567852
+2	14205324
+2	14504228
+2	14384568
+4	16067014
+4	16066057
+4	16073591
+4	16030101
+4	16061818
+8	9578833
+8	9532381
+8	8701030
+8	9584525
+8	8916123
+16	6552319
+16	6587695
+16	6573825
+16	7169936
+16	7405217
+24	6641876
+24	6621158
+24	5759567
+24	6683788
+24	5741050
+32	4853916
+32	6089821
+32	4777627
+32	4775830
+32	4797652
+sidechan: 
+CFA:
+cores	throughput (entries)
+6	52350358
+6	51089420
+6	51599645
+6	49724864
+6	50690583
+12	22415327
+12	20081063
+12	21935873
+12	21880536
+12	20033232
+18	15456025
+18	15387442
+18	14382883
+18	14035015
+18	15592819
+24	11865714
+24	12301650
+24	12088656
+24	12576841
+24	12162360
+30	13853077
+30	12833176
+30	13571913
+30	12692339
+30	12684621
+Go:
+cores	throughput (entries)
+6	45626050
+6	45619431
+6	44683942
+6	43678277
+6	45086748
+12	35205036
+12	34228171
+12	33791468
+12	35703621
+12	35832911
+18	26240847
+18	25969956
+18	21891404
+18	23696718
+18	24735429
+24	15259398
+24	14293074
+24	15512026
+24	15143365
+24	14071826
+30	11492999
+30	11337248
+30	12332749
+30	12230220
+30	12142768
+order: 
+CFA:
+cores	throughput (entries)
+4	153212169
+4	157994884
+4	158642649
+4	158440202
+4	158443807
+Go:
+cores	throughput (entries)
+4	69227256
+4	68925276
+4	68974826
+4	69283275
+4	69040020
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus_Order
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus_Order	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus_Order	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,1 @@
+15844020 & 6904002
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus_future.txt
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus_future.txt	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/nasus_future.txt	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,64 @@
+5
+2
+6
+CFA 
+future OR:
+CFA:
+cores	throughput (entries)
+2	15566828
+2	15086557
+2	15067263
+2	15120455
+2	15358905
+uC++:
+cores	throughput (entries)
+2	6900123
+2	7041717
+2	6856625
+2	7099780
+2	7001880
+future AND:
+CFA:
+cores	throughput (entries)
+2	12229605
+2	11796118
+2	11763758
+2	11973787
+2	11975449
+uC++:
+cores	throughput (entries)
+2	4431174
+2	4426260
+2	4494870
+2	4481836
+2	4521053
+future ANDOR:
+CFA:
+cores	throughput (entries)
+2	13551357
+2	13524679
+2	13222745
+2	13556235
+2	13315978
+uC++:
+cores	throughput (entries)
+2	10932140
+2	10528383
+2	10136509
+2	8971750
+2	10027387
+future ORAND:
+CFA:
+cores	throughput (entries)
+2	13020750
+2	13202965
+2	13277704
+2	13179737
+2	13017765
+uC++:
+cores	throughput (entries)
+2	5293289
+2	5185935
+2	5188311
+2	5175251
+2	5191507
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke.txt
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke.txt	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke.txt	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,465 @@
+5
+2 4 8 16 24 32
+6 12 18 24 30
+CFA Go 
+contend2: 
+CFA:
+cores	throughput (entries)
+2	9967035
+2	9800656
+2	9930224
+2	9985950
+2	9866750
+4	15365587
+4	15230284
+4	14863936
+4	14792464
+4	14456437
+8	11177325
+8	11399628
+8	11247990
+8	11116979
+8	11180166
+16	8630393
+16	8413553
+16	8586178
+16	8452667
+16	8510492
+24	8172246
+24	8190544
+24	8037263
+24	8029636
+24	8330698
+32	8403854
+32	8472348
+32	8493152
+32	8362818
+32	8390131
+Go:
+cores	throughput (entries)
+2	44914185
+2	45769369
+2	37580742
+2	41070461
+2	39787488
+4	32818773
+4	33049966
+4	33188220
+4	33045833
+4	33316967
+8	15983204
+8	15830646
+8	15569769
+8	15914976
+8	15894024
+16	9079211
+16	8908247
+16	9129370
+16	8989494
+16	9110099
+24	7927422
+24	7855155
+24	7915465
+24	7877308
+24	7971973
+32	7126295
+32	7450573
+32	7349965
+32	7480862
+32	7325246
+contend4: 
+CFA:
+cores	throughput (entries)
+2	7711287
+2	7636048
+2	7879877
+2	7632539
+2	7716597
+4	13538861
+4	13570963
+4	14061876
+4	13745413
+4	13435094
+8	11783506
+8	11835871
+8	11305173
+8	11595505
+8	11776842
+16	9314177
+16	9267802
+16	9198536
+16	9329322
+16	9120626
+24	8519394
+24	8350923
+24	8526669
+24	8506273
+24	8454808
+32	8212978
+32	8161628
+32	8197493
+32	8326109
+32	8335861
+Go:
+cores	throughput (entries)
+2	19305443
+2	18617443
+2	18798213
+2	18900110
+2	18730396
+4	16583610
+4	16976951
+4	16601629
+4	17066647
+4	16921525
+8	10182191
+8	10151597
+8	10274864
+8	10132974
+8	10313177
+16	8112814
+16	8154933
+16	8177719
+16	8144694
+16	8210164
+24	7494676
+24	7424790
+24	7503452
+24	7489997
+24	7457173
+32	7464628
+32	7597947
+32	7465098
+32	7578292
+32	7146705
+contend8: 
+CFA:
+cores	throughput (entries)
+2	4553172
+2	4358948
+2	4633044
+2	4298938
+2	4433528
+4	9268621
+4	9316788
+4	9134321
+4	9317794
+4	9096543
+8	11281989
+8	12106942
+8	12155325
+8	12070751
+8	11840874
+16	10199853
+16	10248616
+16	10268593
+16	10303374
+16	10322409
+24	8729770
+24	8707377
+24	8718720
+24	8638369
+24	8586905
+32	7948616
+32	8162892
+32	7993031
+32	7895951
+32	8222873
+Go:
+cores	throughput (entries)
+2	9455116
+2	9529410
+2	8207766
+2	7795882
+2	7684988
+4	7758234
+4	8248808
+4	8204068
+4	8252258
+4	7820115
+8	7224181
+8	7156840
+8	7248816
+8	7169039
+8	7250521
+16	6412117
+16	6429773
+16	6414842
+16	6474895
+16	6493768
+24	5910867
+24	5943544
+24	5889434
+24	5960548
+24	5854276
+32	5574433
+32	5501965
+32	5660822
+32	5525961
+32	5571871
+spin2: 
+CFA:
+cores	throughput (entries)
+2	11091685
+2	10716028
+2	10263026
+2	11024866
+2	10141356
+4	13458646
+4	12675243
+4	13601822
+4	12493029
+4	13526328
+8	11857151
+8	12449743
+8	12402808
+8	12115910
+8	12328377
+16	9285877
+16	9431990
+16	9498253
+16	9288202
+16	9314209
+24	9134958
+24	9037642
+24	8894318
+24	8878258
+24	8870078
+32	9574533
+32	9558834
+32	8891248
+32	9425577
+32	9575672
+Go:
+cores	throughput (entries)
+2	41407277
+2	41185974
+2	42546942
+2	41599985
+2	41537281
+4	18274724
+4	19403137
+4	19174836
+4	19832568
+4	20434642
+8	12161534
+8	11877215
+8	12092572
+8	11870295
+8	11953849
+16	9400275
+16	9379035
+16	9121639
+16	9313220
+16	9156810
+24	8163137
+24	8212680
+24	7718772
+24	8329378
+24	8242728
+32	8698636
+32	8738083
+32	8712188
+32	8968355
+32	9000456
+spin4: 
+CFA:
+cores	throughput (entries)
+2	8543234
+2	8548877
+2	8428083
+2	8904947
+2	8478075
+4	11365692
+4	12109844
+4	11446726
+4	11515624
+4	11992092
+8	11984771
+8	12153123
+8	11709308
+8	12103916
+8	11953110
+16	9904786
+16	9763922
+16	9743041
+16	9913004
+16	9661295
+24	8960227
+24	8932460
+24	8985062
+24	8957904
+24	9030960
+32	9189691
+32	9389309
+32	9431123
+32	9307976
+32	9216590
+Go:
+cores	throughput (entries)
+2	15669478
+2	15308587
+2	15510092
+2	15437039
+2	15227836
+4	10451307
+4	10417069
+4	9804714
+4	10495039
+4	9877950
+8	7258556
+8	7318110
+8	7471921
+8	7382093
+8	7262086
+16	6219816
+16	6146980
+16	6202815
+16	6120133
+16	6224194
+24	5730137
+24	5586527
+24	5596617
+24	5623077
+24	5682422
+32	5926340
+32	5851871
+32	5871301
+32	5875055
+32	5845408
+spin8: 
+CFA:
+cores	throughput (entries)
+2	5364493
+2	5298352
+2	5343768
+2	5369572
+2	5384383
+4	9898690
+4	9968625
+4	10025418
+4	9986221
+4	10228985
+8	11846407
+8	11885865
+8	11941307
+8	12353081
+8	12148637
+16	10518783
+16	10615015
+16	10459213
+16	10403451
+16	10398262
+24	8988384
+24	8997726
+24	8966938
+24	9034410
+24	9048297
+32	8790460
+32	8967228
+32	8962159
+32	8753670
+32	8859608
+Go:
+cores	throughput (entries)
+2	9066062
+2	9737392
+2	9142101
+2	9187665
+2	9519920
+4	7574448
+4	8050344
+4	7698715
+4	7666895
+4	7638515
+8	7160856
+8	7127596
+8	7059170
+8	7122960
+8	7130382
+16	6412929
+16	6486433
+16	6438736
+16	6485939
+16	6078041
+24	5900909
+24	5962074
+24	5956968
+24	5956481
+24	5970036
+32	5608255
+32	5671451
+32	5571902
+32	5565332
+32	5599883
+sidechan: 
+CFA:
+cores	throughput (entries)
+6	72354348
+6	71860298
+6	72277047
+6	73041939
+6	73059623
+12	25204538
+12	25305309
+12	24503906
+12	25391473
+12	25444230
+18	21692078
+18	22384941
+18	22535288
+18	22239042
+18	22360659
+24	18246388
+24	18267877
+24	17924009
+24	18457526
+24	17959192
+30	22892750
+30	22855602
+30	21234954
+30	22781023
+30	23008437
+Go:
+cores	throughput (entries)
+6	47262886
+6	47522972
+6	47191097
+6	47649131
+6	47126015
+12	37610289
+12	38562781
+12	37069115
+12	37159580
+12	38417947
+18	20760742
+18	20449941
+18	20645451
+18	20441743
+18	20929537
+24	14620575
+24	14475628
+24	14995888
+24	14401480
+24	14549618
+30	12383406
+30	11910359
+30	10780129
+30	12028827
+30	12367389
+order: 
+CFA:
+cores	throughput (entries)
+4	68683961
+4	69299441
+4	62515413
+4	68207586
+4	68368563
+Go:
+cores	throughput (entries)
+4	60368130
+4	60454358
+4	60967535
+4	59271747
+4	61334120
+
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke_Order
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke_Order	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke_Order	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,1 @@
+6836856 & 6045435
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke_future.txt
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke_future.txt	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/data/pyke_future.txt	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,64 @@
+5
+2
+6
+CFA 
+future OR:
+CFA:
+cores	throughput (entries)
+2	7979542
+2	8195420
+2	8339041
+2	7735845
+2	8279155
+uC++:
+cores	throughput (entries)
+2	4648297
+2	4766391
+2	4631747
+2	4600202
+2	4683445
+future AND:
+CFA:
+cores	throughput (entries)
+2	5400791
+2	5792970
+2	6061253
+2	6034621
+2	5792246
+uC++:
+cores	throughput (entries)
+2	4190818
+2	4127246
+2	4026182
+2	4219090
+2	4203589
+future ANDOR:
+CFA:
+cores	throughput (entries)
+2	6889728
+2	6644816
+2	6871689
+2	6713521
+2	6881730
+uC++:
+cores	throughput (entries)
+2	4465233
+2	4371764
+2	4374007
+2	4109526
+2	4262671
+future ORAND:
+CFA:
+cores	throughput (entries)
+2	6393712
+2	6276503
+2	6238200
+2	6444010
+2	6433157
+uC++:
+cores	throughput (entries)
+2	4198438
+2	4312017
+2	3417079
+2	3350573
+2	3331244
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/genPlots
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/genPlots	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/genPlots	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,5 @@
+#!/bin/bash -
+python3 plotData.py data/nasus.txt nasus_
+python3 plotData.py data/pyke.txt pyke_
+python3 plotData.py data/nasus_future.txt nasus_
+python3 plotData.py data/pyke_future.txt pyke_
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend/contend.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend/contend.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend/contend.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,123 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Processors, Channels, Prods, Cons, ChannelSize int = 2, 8, 1, 1, 10
+var cons_done, prod_done bool = false, false;
+var total_operations, cons_check, prod_check uint64 = 0, 0, 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int, Prods)
+var consJoin chan int = make(chan int, Cons)
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		
+		select {
+			case <- chans[0]:
+			case <- chans[1]:
+			case <- chans[2]:
+			case <- chans[3]:
+			case <- chans[4]:
+			case <- chans[5]:
+			case <- chans[6]:
+			case <- chans[7]:
+		}
+		if ! prod_done { count++ }
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+			case chans[2] <- count:
+			case chans[3] <- count:
+			case chans[4] <- count:
+			case chans[5] <- count:
+			case chans[6] <- count:
+			case chans[7] <- count:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ processors (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Processors, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Processors, _ = strconv.Atoi( os.Args[1] )
+				if Processors < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Processors );
+	Prods = Processors /2
+	Cons = Processors / 2
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+	for j := 0; j < Prods; j++ {
+		go producer( chans )
+	}
+
+	for j := 0; j < Cons; j++ {
+		go consumer( chans )
+	}
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Prods; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Cons; j++{
+		<-consJoin
+	}
+
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module contend
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend2/contend.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend2/contend.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend2/contend.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,111 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Processors, Channels, Prods, Cons, ChannelSize int = 2, 2, 1, 1, 10
+var cons_done, prod_done bool = false, false;
+var total_operations, cons_check, prod_check uint64 = 0, 0, 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int, Prods)
+var consJoin chan int = make(chan int, Cons)
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		
+		select {
+			case <- chans[0]:
+			case <- chans[1]:
+		}
+		if ! prod_done { count++ }
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ processors (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Processors, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Processors, _ = strconv.Atoi( os.Args[1] )
+				if Processors < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Processors );
+	Prods = Processors /2
+	Cons = Processors / 2
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+	for j := 0; j < Prods; j++ {
+		go producer( chans )
+	}
+
+	for j := 0; j < Cons; j++ {
+		go consumer( chans )
+	}
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Prods; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Cons; j++{
+		<-consJoin
+	}
+
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend2/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend2/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend2/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module contend
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend4/contend.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend4/contend.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend4/contend.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,115 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Processors, Channels, Prods, Cons, ChannelSize int = 2, 4, 1, 1, 10
+var cons_done, prod_done bool = false, false;
+var total_operations, cons_check, prod_check uint64 = 0, 0, 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int, Prods)
+var consJoin chan int = make(chan int, Cons)
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		
+		select {
+			case <- chans[0]:
+			case <- chans[1]:
+			case <- chans[2]:
+			case <- chans[3]:
+		}
+		if ! prod_done { count++ }
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+			case chans[2] <- count:
+			case chans[3] <- count:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ processors (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Processors, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Processors, _ = strconv.Atoi( os.Args[1] )
+				if Processors < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Processors );
+	Prods = Processors /2
+	Cons = Processors / 2
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+	for j := 0; j < Prods; j++ {
+		go producer( chans )
+	}
+
+	for j := 0; j < Cons; j++ {
+		go consumer( chans )
+	}
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Prods; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Cons; j++{
+		<-consJoin
+	}
+
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend4/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend4/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend4/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module contend
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend8/contend.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend8/contend.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend8/contend.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,123 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Processors, Channels, Prods, Cons, ChannelSize int = 2, 8, 1, 1, 10
+var cons_done, prod_done bool = false, false;
+var total_operations, cons_check, prod_check uint64 = 0, 0, 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int, Prods)
+var consJoin chan int = make(chan int, Cons)
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		
+		select {
+			case <- chans[0]:
+			case <- chans[1]:
+			case <- chans[2]:
+			case <- chans[3]:
+			case <- chans[4]:
+			case <- chans[5]:
+			case <- chans[6]:
+			case <- chans[7]:
+		}
+		if ! prod_done { count++ }
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+			case chans[2] <- count:
+			case chans[3] <- count:
+			case chans[4] <- count:
+			case chans[5] <- count:
+			case chans[6] <- count:
+			case chans[7] <- count:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ processors (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Processors, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Processors, _ = strconv.Atoi( os.Args[1] )
+				if Processors < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Processors );
+	Prods = Processors /2
+	Cons = Processors / 2
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+	for j := 0; j < Prods; j++ {
+		go producer( chans )
+	}
+
+	for j := 0; j < Cons; j++ {
+		go consumer( chans )
+	}
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Prods; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Cons; j++{
+		<-consJoin
+	}
+
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend8/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend8/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/contend8/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module contend
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/order/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/order/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/order/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module order
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/order/order.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/order/order.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/order/order.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,109 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+)
+
+var Channels, ChannelSize int = 2, 100
+var cons_done, prod_done bool = false, false;
+var total_operations uint64 = 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int)
+var consJoin chan int = make(chan int)
+
+func selectconsumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }		
+		select {
+			case <- chans[0]:
+			case <- chans[1]:
+		}
+		if ! prod_done { count++ }
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }		
+		<-chans[1]
+		if ! prod_done { count++ }
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func selectproducer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	var checksum uint64 = 0
+	for {
+		if prod_done { break }
+		checksum = checksum ^ count
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	var checksum uint64 = 0
+	for {
+		if prod_done { break }
+		checksum = checksum ^ count
+		chans[1] <- count
+		count++
+	}
+	prodJoin <- 0
+}
+
+
+func main() {
+	runtime.GOMAXPROCS( 4 );
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+
+	
+	go selectproducer( chans )
+	go selectconsumer( chans )
+	go producer( chans )
+	go consumer( chans )
+	
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < 2; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < 2; j++{
+		<-consJoin
+	}
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/sidechan/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/sidechan/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/sidechan/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module sidechan
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/sidechan/sidechan.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/sidechan/sidechan.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/sidechan/sidechan.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,136 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Sets, Channels, ChannelSize int = 1, 2, 100
+var cons_done, prod_done bool = false, false;
+var total_operations uint64 = 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int)
+var consJoin chan int = make(chan int)
+
+func selectconsumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }		
+		select {
+			case <- chans[0]:
+			case <- chans[1]:
+		}
+		if ! prod_done { count++ }
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func consumer( channel chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		<-channel
+		if ! prod_done { count++ }
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func selectproducer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	var checksum uint64 = 0
+	for {
+		if prod_done { break }
+		checksum = checksum ^ count
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func producer( channel chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		channel <- count
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ sets (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Sets, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Sets, _ = strconv.Atoi( os.Args[1] )
+				if Sets < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Sets * 2 + Sets * Channels * 2 );
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+
+	
+	for j := 0; j < Sets; j++ {
+		go selectproducer( chans )
+		go selectconsumer( chans )
+		for i := 0; i < Channels; i++ {
+			go producer( chans[i] )
+			go consumer( chans[i] )
+		}
+	}
+		
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Sets + Sets * Channels; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Sets + Sets * Channels; j++{
+		<-consJoin
+	}
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module spin
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin/spin.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin/spin.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin/spin.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,133 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Processors, Channels, Prods, Cons, ChannelSize int = 2, 8, 1, 1, 10
+var cons_done, prod_done bool = false, false;
+var total_operations uint64 = 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int)
+var consJoin chan int = make(chan int)
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		
+		select {
+			case <- chans[0]:
+				if ! prod_done { count++ }
+			case <- chans[1]:
+				if ! prod_done { count++ }
+			case <- chans[2]:
+				if ! prod_done { count++ }
+			case <- chans[3]:
+				if ! prod_done { count++ }
+			case <- chans[4]:
+				if ! prod_done { count++ }
+			case <- chans[5]:
+				if ! prod_done { count++ }
+			case <- chans[6]:
+				if ! prod_done { count++ }
+			case <- chans[7]:
+				if ! prod_done { count++ }
+			default:
+		}
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+			case chans[2] <- count:
+			case chans[3] <- count:
+			case chans[4] <- count:
+			case chans[5] <- count:
+			case chans[6] <- count:
+			case chans[7] <- count:
+			default:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ processors (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Processors, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Processors, _ = strconv.Atoi( os.Args[1] )
+				if Processors < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Processors );
+	Prods = Processors /2
+	Cons = Processors / 2
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+	for j := 0; j < Prods; j++ {
+		go producer( chans )
+	}
+
+	for j := 0; j < Cons; j++ {
+		go consumer( chans )
+	}
+		
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Prods; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Cons; j++{
+		<-consJoin
+	}
+
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin2/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin2/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin2/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module spin
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin2/spin.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin2/spin.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin2/spin.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,115 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Processors, Channels, Prods, Cons, ChannelSize int = 2, 2, 1, 1, 10
+var cons_done, prod_done bool = false, false;
+var total_operations uint64 = 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int)
+var consJoin chan int = make(chan int)
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		
+		select {
+			case <- chans[0]:
+				if ! prod_done { count++ }
+			case <- chans[1]:
+				if ! prod_done { count++ }
+			default:
+		}
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+			default:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ processors (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Processors, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Processors, _ = strconv.Atoi( os.Args[1] )
+				if Processors < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Processors );
+	Prods = Processors /2
+	Cons = Processors / 2
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+	for j := 0; j < Prods; j++ {
+		go producer( chans )
+	}
+
+	for j := 0; j < Cons; j++ {
+		go consumer( chans )
+	}
+		
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Prods; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Cons; j++{
+		<-consJoin
+	}
+
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin4/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin4/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin4/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module spin
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin4/spin.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin4/spin.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin4/spin.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,120 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Processors, Channels, Prods, Cons, ChannelSize int = 2, 4, 1, 1, 10
+var cons_done, prod_done bool = false, false;
+var total_operations uint64 = 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int)
+var consJoin chan int = make(chan int)
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		
+		select {
+			case <- chans[0]:
+				if ! prod_done { count++ }
+			case <- chans[1]:
+				if ! prod_done { count++ }
+			case <- chans[2]:
+				if ! prod_done { count++ }
+			case <- chans[3]:
+			default:
+		}
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+			case chans[2] <- count:
+			case chans[3] <- count:
+			default:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ processors (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Processors, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Processors, _ = strconv.Atoi( os.Args[1] )
+				if Processors < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Processors );
+	Prods = Processors /2
+	Cons = Processors / 2
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+	for j := 0; j < Prods; j++ {
+		go producer( chans )
+	}
+
+	for j := 0; j < Cons; j++ {
+		go consumer( chans )
+	}
+		
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Prods; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Cons; j++{
+		<-consJoin
+	}
+
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin8/go.mod
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin8/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin8/go.mod	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,3 @@
+module spin
+
+go 1.18
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin8/spin.go
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin8/spin.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/go/spin8/spin.go	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,133 @@
+package main
+
+import (
+	"fmt"
+	"sync"
+	"time"
+	"runtime"
+	"os"
+	"strconv"
+)
+
+var Processors, Channels, Prods, Cons, ChannelSize int = 2, 8, 1, 1, 10
+var cons_done, prod_done bool = false, false;
+var total_operations uint64 = 0
+var m sync.Mutex
+
+var prodJoin chan int = make(chan int)
+var consJoin chan int = make(chan int)
+
+func consumer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if cons_done { break }
+		
+		select {
+			case <- chans[0]:
+				if ! prod_done { count++ }
+			case <- chans[1]:
+				if ! prod_done { count++ }
+			case <- chans[2]:
+				if ! prod_done { count++ }
+			case <- chans[3]:
+				if ! prod_done { count++ }
+			case <- chans[4]:
+				if ! prod_done { count++ }
+			case <- chans[5]:
+				if ! prod_done { count++ }
+			case <- chans[6]:
+				if ! prod_done { count++ }
+			case <- chans[7]:
+				if ! prod_done { count++ }
+			default:
+		}
+	}
+	m.Lock()
+	total_operations += count
+	m.Unlock()
+	consJoin <- 0
+}
+
+func producer( chans [] chan uint64 ) {
+	var count uint64 = 0
+	for {
+		if prod_done { break }
+		select {
+			case chans[0] <- count:
+			case chans[1] <- count:
+			case chans[2] <- count:
+			case chans[3] <- count:
+			case chans[4] <- count:
+			case chans[5] <- count:
+			case chans[6] <- count:
+			case chans[7] <- count:
+			default:
+		}
+		count++
+	}
+	prodJoin <- 0
+}
+
+func usage() {
+	fmt.Printf( "Usage: %v " +
+		"[ processors (> 0) | 'd' (default %v) ] " +
+		"[ ChannelSize (> 0) | 'd' (default %v) ]\n",
+		os.Args[0], Processors, ChannelSize );
+	os.Exit( 1 );
+}
+
+func main() {
+	switch len( os.Args ) {
+		case 3:
+			if os.Args[2] != "d" {							// default ?
+				ChannelSize, _ = strconv.Atoi( os.Args[2] )
+					if ChannelSize < 0 { usage(); }
+			} // if
+		fallthrough
+		case 2:
+			if os.Args[1] != "d" {							// default ?
+				Processors, _ = strconv.Atoi( os.Args[1] )
+				if Processors < 1 { usage(); }
+			} // if
+		case 1:											// use defaults
+		default:
+		usage();
+	} // switch
+	runtime.GOMAXPROCS( Processors );
+	Prods = Processors /2
+	Cons = Processors / 2
+
+	// fmt.Println("Processors: ",Processors," Channels: ",Channels," ProdsPerChan: ",ProdsPerChan," ConsPerChan: ",ConsPerChan," Channel Size: ",ChannelSize)
+	
+	chans := make( [] chan uint64, Channels )
+	for i := range chans {
+		chans[i] = make(chan uint64, ChannelSize)
+	}
+	for j := 0; j < Prods; j++ {
+		go producer( chans )
+	}
+
+	for j := 0; j < Cons; j++ {
+		go consumer( chans )
+	}
+		
+
+	// wait 10 seconds
+	time.Sleep(time.Second * 10)
+	// fmt.Println("prod done\n")
+	prod_done = true
+	for j := 0; j < Prods; j++ {
+		<-prodJoin
+	}
+	// fmt.Println("cons done\n")
+	cons_done = true
+	for i := range chans {
+		close(chans[i])
+	}
+	
+	for j := 0; j < Cons; j++{
+		<-consJoin
+	}
+
+    fmt.Println(total_operations)
+}
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/plotData.py
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/plotData.py	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/plotData.py	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,273 @@
+import os
+import sys
+import time
+import itertools
+import matplotlib.pyplot as plt
+import matplotlib.ticker as ticks
+import math
+from scipy import stats as st
+import numpy as np
+from enum import Enum
+from statistics import median
+
+import matplotlib
+matplotlib.use("pgf")
+matplotlib.rcParams.update({
+    "pgf.texsystem": "pdflatex",
+    'font.family': 'serif',
+    'text.usetex': True,
+    'pgf.rcfonts': False,
+    'font.size': 16
+})
+marker = itertools.cycle(('o', 's', 'D', 'x', 'p', '^', 'h', '*', 'v' )) 
+
+readfile = open(sys.argv[1], "r")
+
+machineName = ""
+
+if len(sys.argv) > 2:
+    machineName = sys.argv[2]
+
+# first line has num times per experiment
+line = readfile.readline()
+numTimes = int(line)
+
+# second line has processor args
+line = readfile.readline()
+procs = []
+for val in line.split():
+    procs.append(int(val))
+
+# 3rd line has processor for side_chan bench
+line = readfile.readline()
+sideChanProcs = []
+for val in line.split():
+    sideChanProcs.append(int(val))
+
+# 4th line has number of variants
+line = readfile.readline()
+names = line.split()
+numVariants = len(names)
+
+lines = (line.rstrip() for line in readfile) # All lines including the blank ones
+lines = (line for line in lines if line) # Non-blank lines
+
+def sci_format(x, pos):
+    return '{:.1e}'.format(x).replace('+0', '')
+
+def sci_format_label(x):
+    return '{:.2e}'.format(x).replace('+0', '')
+
+class Bench(Enum):
+    Unset = 0
+    Contend2 = 1
+    Contend4 = 2
+    Contend8 = 3
+    Spin2 = 4
+    Spin4 = 5
+    Spin8 = 6
+    SideChan = 7
+    Future = 8
+    Order = 9
+
+nameSet = False
+currBench = Bench.Unset # default val
+count = 0
+procCount = 0
+currVariant = 0
+name = ""
+title = ""
+experiment_duration = 10.0
+var_name = ""
+future_variants=["CFA", "uC++"]
+future_names=["OR", "AND", "AND-OR", "OR-AND"]
+future_data=[[0.0 for i in range(len(future_names))] for j in range(2)]
+future_bars=[[[0.0 for i in range(len(future_names))],[0.0 for k in range(len(future_names))]] for j in range(2)]
+curr_future=0
+sendData = [0.0 for j in range(numVariants)]
+data = [[0.0 for i in range(len(procs))] for j in range(numVariants)]
+bars = [[[0.0 for i in range(len(procs))],[0.0 for k in range(len(procs))]] for j in range(numVariants)]
+sideData = [[0.0 for i in range(len(sideChanProcs))] for j in range(numVariants)]
+sideBars = [[[0.0 for i in range(len(sideChanProcs))],[0.0 for k in range(len(sideChanProcs))]] for j in range(numVariants)]
+tempData = [0.0 for i in range(numTimes)]
+orderData = [0.0 for i in range(numVariants)]
+for idx, line in enumerate(lines):
+    # print(line)
+    
+    if currBench == Bench.Unset:
+        if line == "contend2:":
+            name = "Contend_2"
+            title = "2 Clause Contend"
+            currBench = Bench.Contend2
+        elif line == "contend4:":
+            name = "Contend_4"
+            title = "4 Clause Contend"
+            currBench = Bench.Contend4
+        elif line == "contend8:":
+            name = "Contend_8"
+            title = "8 Clause Contend"
+            currBench = Bench.Contend8
+        elif line == "spin2:":
+            name = "Spin_2"
+            title = "2 Clause Spin"
+            currBench = Bench.Spin2
+        elif line == "spin4:":
+            name = "Spin_4"
+            title = "4 Clause Spin"
+            currBench = Bench.Spin4
+        elif line == "spin8:":
+            name = "Spin_8"
+            title = "8 Clause Spin"
+            currBench = Bench.Spin8
+        elif line == "sidechan:":
+            name = "Sidechan"
+            currBench = Bench.SideChan
+        elif line[0:6] == "future":
+            name = "Future"
+            title = "Future Synchronization"
+            currBench = Bench.Future
+        elif line == "order:":
+            name = "order"
+            currBench = Bench.Order
+        else:
+            print("Expected benchmark name")
+            print("Line: " + line)
+            sys.exit()
+        continue
+
+    if line[0:5] == "cores":
+        continue
+
+    if not nameSet:
+        nameSet = True
+        continue
+    
+    lineArr = line.split()
+    tempData[count] = float(lineArr[-1]) / experiment_duration
+    count += 1
+
+    if currBench == Bench.Future:
+        if count == numTimes:
+            currMedian = median( tempData )
+            future_data[currVariant][curr_future] = currMedian
+            lower, upper = st.t.interval(0.95, numTimes - 1, loc=np.mean(tempData), scale=st.sem(tempData))
+            future_bars[currVariant][0][curr_future] = currMedian - lower
+            future_bars[currVariant][1][curr_future] = upper - currMedian
+            count = 0
+            nameSet = False
+            currVariant += 1
+            if currVariant == 2:
+                curr_future += 1
+                # reset
+                currBench = Bench.Unset
+                currVariant = 0
+                if curr_future == len(future_names):
+                    x = np.arange(len(future_names))  # the label locations
+                    width = 0.45  # the width of the bars
+                    multiplier = .5
+                    fig, ax = plt.subplots(layout='constrained')
+                    plt.title(title + " Benchmark")
+                    plt.ylabel("Throughput (statement completions per second)")
+                    plt.xlabel("Operation")
+                    ax.yaxis.set_major_formatter(ticks.FuncFormatter(sci_format))
+                    for idx, arr in enumerate(future_data):
+                        offset = width * multiplier
+                        rects = ax.bar(x + offset, arr, width, label=future_variants[idx], yerr=[future_bars[idx][0], future_bars[idx][1]])
+                        # ax.bar_label(rects, padding=3, fmt='%.1e')
+                        ax.bar_label(rects, padding=3, fmt=sci_format_label)
+                        multiplier += 1
+                    plt.xticks(x + width, future_names)
+                    
+                    ax.legend(future_variants, loc='lower right')
+                    # fig.savefig("plots/" + machineName + name + ".png")
+                    plt.savefig("plots/" + machineName + name + ".pgf")
+                    fig.clf()
+
+    elif currBench == Bench.Order:
+        if count == numTimes:
+            currMedian = median( tempData )
+            orderData[currVariant] = currMedian
+            count = 0
+            currVariant += 1
+            procCount = 0
+            nameSet = False
+            if currVariant == numVariants:
+                fileName = "data/" + machineName + "Order"
+                f = open(fileName, 'w')
+                f.write(" & ".join(map(lambda a: str(int(a)), orderData)))
+                
+                # reset
+                currBench = Bench.Unset
+                currVariant = 0
+
+    elif currBench == Bench.SideChan:
+        if count == numTimes:
+            currMedian = median( tempData )
+            sideData[currVariant][procCount] = currMedian
+            lower, upper = st.t.interval(0.95, numTimes - 1, loc=np.mean(tempData), scale=st.sem(tempData))
+            sideBars[currVariant][0][procCount] = currMedian - lower
+            sideBars[currVariant][1][procCount] = upper - currMedian
+            count = 0
+            procCount += 1
+            if procCount == len(sideChanProcs):
+                procCount = 0
+                nameSet = False
+                currVariant += 1
+
+                if currVariant == numVariants:
+                    fig, ax = plt.subplots()
+                    plt.title(name + " Benchmark")
+                    plt.ylabel("Throughput (channel operations per second)")
+                    plt.xlabel("Cores")
+                    ax.yaxis.set_major_formatter(ticks.FuncFormatter(sci_format))
+                    for idx, arr in enumerate(sideData):
+                        plt.errorbar( sideChanProcs, arr, [sideBars[idx][0], sideBars[idx][1]], capsize=2, marker=next(marker) )
+                    plt.xticks(sideChanProcs)
+                    marker = itertools.cycle(('o', 's', 'D', 'x', 'p', '^', 'h', '*', 'v' )) 
+                    # plt.yscale("log")
+                    ax.legend(names)
+                    # fig.savefig("plots/" + machineName + name + ".png")
+                    plt.savefig("plots/" + machineName + name + ".pgf")
+                    fig.clf()
+
+                    # reset
+                    currBench = Bench.Unset
+                    currVariant = 0
+    else:
+        if count == numTimes:
+            currMedian = median( tempData )
+            data[currVariant][procCount] = currMedian
+            lower, upper = st.t.interval(0.95, numTimes - 1, loc=np.mean(tempData), scale=st.sem(tempData))
+            bars[currVariant][0][procCount] = currMedian - lower
+            bars[currVariant][1][procCount] = upper - currMedian
+            count = 0
+            procCount += 1
+
+            if procCount == len(procs):
+                procCount = 0
+                nameSet = False
+                currVariant += 1
+
+                if currVariant == numVariants:
+                    fig, ax = plt.subplots(layout='constrained')
+                    plt.title(title + " Benchmark")
+                    plt.ylabel("Throughput (channel operations per second)")
+                    plt.xlabel("Cores")
+                    ax.yaxis.set_major_formatter(ticks.FuncFormatter(sci_format))
+                    for idx, arr in enumerate(data):
+                        plt.errorbar( procs, arr, [bars[idx][0], bars[idx][1]], capsize=2, marker=next(marker) )
+                    plt.xticks(procs)
+                    marker = itertools.cycle(('o', 's', 'D', 'x', 'p', '^', 'h', '*', 'v' )) 
+                    # plt.yscale("log")
+                    # plt.ylim(1, None)
+                    # ax.get_yaxis().set_major_formatter(ticks.ScalarFormatter())
+                    # else:
+                    #     plt.ylim(0, None)
+                    ax.legend(names)
+                    # fig.savefig("plots/" + machineName + name + ".png")
+                    plt.savefig("plots/" + machineName + name + ".pgf")
+                    fig.clf()
+
+                    # reset
+                    currBench = Bench.Unset
+                    currVariant = 0
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/run
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/run	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/run	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,314 @@
+#!/bin/bash -
+
+false=0; true=1
+
+# Usage: arch [ hostname ] returns hostname, cores, startcore
+#
+#   Define machine architecture based on starting socket, CPUs (cores) per socket, number of
+#   sockets, has hyperthreading.
+
+start=0
+
+arch() {
+	hostname=${1:-`hostname`}			# return value
+	hashyper=${true}					# assume machine has hyperthreads
+	if [ "${hostname}" = "plg2" ] ; then
+		startsocket=${start}
+		cps=16							# coresPerSocket
+		sockets=2
+		hashyper=${false}				# has no hyperthreads
+	elif [ "${hostname}" = "nasus" ] ; then
+		startsocket=${start}
+		cps=64							# coresPerSocket
+		sockets=2
+	elif [ "${hostname}" = "pyke" ] ; then
+		startsocket=${start}
+		cps=24							# coresPerSocket
+		sockets=2
+	elif [ "${hostname}" = "jax" ] ; then
+		startsocket=${start}
+		cps=24							# coresPerSocket
+		sockets=4
+	else
+		echo "unsupported host" ${hostname}
+		exit 1
+	fi
+	cores=$(( ${cps} * ${sockets} ))
+	startcore=$(( ${startsocket} * ${cps} ))
+}
+
+# Usage: affinity (global cps, sockets, startsocket, hashyper, cores, startcore, wrap)
+#   returns taskset argument
+#
+#   This routine assumes hyperthreading has only 2 hyperthreads per core.
+#
+#   If hyperthread scanning is used: processor units are assigned across the low-number hyperthreads
+#   of the socket's cores. When the low-number hyperthreads are filled, the high-number hyperhtreads
+#   are assigned across the socket's cores. Then the next socket is assigned.
+#
+#   If hyperthread wrapping is used: processor units are assigned in low/high-number pairs of
+#   hyperthreads across the socket's cores. Then the next socket is assigned.
+
+wrap=${false}							# set to control hyperthread assignment across socket cores
+
+affinity() {
+	if [ ${wrap} -eq ${true} -a ${hashyper} -eq ${false} ] ; then
+		echo "architecture does not support hyperthreading for wrapping"
+		exit 1
+	fi
+	taskset=""							# return value
+	set -- $(( ${1} - 1 ))				# decrement $1
+	if [ ${1} -eq 0 ] ; then taskset="${startcore}-${startcore}"; return; fi
+	if [ ${1} -ge $(( ${cps} * ( ${sockets} - ${startsocket} ) * ( ${hashyper} + 1 ) )) ] ; then # error
+		echo "not enough cores $(( ${cores} * ${sockets} )) for $(( ${1} + 1 )) starting at ${startcore}"
+		exit 1
+	fi
+	if [ ${hashyper} -eq ${false} ] ; then taskset="${startcore}-$(( ${1} + ${startcore} ))"; return; fi # no hyperthreads
+	start2=$(( ${startcore} + ${cores} ))
+	if [ ${wrap} -eq ${true} ] ; then 	# hyperthread wrapping
+		end1=$(( ${1} / 2 + ${startcore} ))
+		end2=$(( ${end1} + ${cores} ))
+		if [ $(( ${1} % 2 )) -eq 0 ] ; then
+			end2=$(( ${end2} - 1 ))
+		fi
+		taskset="${startcore}-${end1},${start2}-${end2}"
+	else								# hyperthread scanning
+		if [ ${1} -lt ${cps} ] ; then taskset="${startcore}-$(( ${1} + ${startcore} ))"; return; fi
+		filled=$(( ${1} / ( ${cps} * 2 ) * ${cps} ))
+		modulus=$(( ${1} % ( ${cps} * 2 ) ))	# leftover cores added to saturated sockets
+		if [ ${modulus} -gt ${cps} ] ; then
+			taskset="${startcore}-$(( ${startcore} + ${filled} + ${cps} - 1 )),${start2}-$(( ${start2} + ${filled} + ${modulus} % ${cps} ))"
+		else
+			taskset="${startcore}-$(( ${startcore} + ${filled} + ${modulus} )),${start2}-$(( ${start2} + ${filled} - 1 ))"
+		fi
+	fi
+}
+
+numtimes=5
+# numtimes=1
+
+# num_threads='2 4 8 16 24 32'
+side_chan_threads='6 12 18 24 30' # must be mults of 6
+num_threads='2'
+# side_chan_threads='6'
+
+chan_size='10'
+future_time='10'
+future_flags=('-DOR' '-DAND3' '-DANDOR' '-DORAND')
+future_names=('OR' 'AND' 'ANDOR' 'ORAND')
+
+# toggle benchmarks
+spin=${true}
+contend=${true}
+sidechan=${true}
+future=${true}
+order=${true}
+spin=${false}
+contend=${false}
+sidechan=${false}
+future=${false}
+# order=${false}
+
+runCFA=${true}
+runGO=${true}
+# runUCPP=${true}
+# runCFA=${false}
+# runGO=${false}
+runUCPP=${false}
+
+cfa=~/cfa-cc/driver/cfa
+
+# Helpers to minimize code duplication
+
+# repeats a command ${numtimes}
+preprint=''
+repeat_command() {
+    t=1
+    while [ ${t} -le ${numtimes} ] ; do
+        echo -n -e ${preprint}
+        "${@}"
+        t=`expr ${t} + 1`
+    done
+}
+
+# prints the leading info for a given run of a variant
+print_header() {
+    echo ${1}':'
+    echo -e "cores\tthroughput (entries)"
+}
+
+# runs the current benchmark with provided args
+# only works for standard-run benchmarks (not Akka)
+# must split into pre and post args to be able to supply val of p
+pre_args=''
+post_args=''
+single_run() {
+    affinity ${1}
+    preprint="${1}\t"
+    repeat_command taskset -c ${taskset} ./a.${hostname} ${pre_args} ${1} ${post_args}
+}
+
+# runs the current bench for all processor vals
+# works for standard benchs that dont need to set a config file (not Akka or CAF)
+run_bench() {
+    for p in ${num_threads} ; do
+        single_run ${p}
+    done
+}
+
+run_side_chan() {
+    i=1
+    for p in ${side_chan_threads} ; do
+        affinity ${p}
+        preprint="${p}\t"
+        repeat_command taskset -c ${taskset} ./a.${hostname} ${pre_args} ${i} ${post_args}
+        i=`expr ${i} + 1`
+    done
+}
+
+run_order() {
+    affinity 4
+    preprint="4\t"
+    repeat_command taskset -c ${taskset} ./a.${hostname}
+}
+
+run_future() {
+    affinity 2
+    preprint="2\t"
+    repeat_command taskset -c ${taskset} ./a.${hostname} ${post_args}
+}
+
+arch # get hostname
+
+# set up leading info for python script
+echo $numtimes
+echo $num_threads
+echo $side_chan_threads
+
+if [ ${runCFA} -eq ${true} ]; then
+    echo -n 'CFA '
+fi
+if [ ${runGO} -eq ${true} ]; then
+    echo -n 'Go '
+fi
+echo ""
+
+# done printing header info for output
+
+# cfa flags
+cfa_flags='-quiet -O3 -nodebug -DNDEBUG'
+
+# UCPP flags
+UCPPflags="-quiet -g -Wall -Wextra -O3 -nodebug -DNDEBUG -multi"
+UCPP=~/ucpp/u++-7.0.0/bin/u++
+
+# run the benchmarks
+
+run_contend() {
+    post_args=${1}
+
+    if [ ${runCFA} -eq ${true} ] ; then
+        cd cfa # CFA RUN
+        print_header 'CFA'
+        ${cfa} ${cfa_flags} '-DNUM_CHANS='${3} ${2}.cfa -o a.${hostname} > /dev/null 2>&1
+        run_bench
+        rm a.${hostname}
+        cd - > /dev/null
+    fi # done CFA
+
+    if [ ${runGO} -eq ${true} ] ; then
+        cd go/${2}${3} # Go RUN
+        print_header 'Go'
+        go build -o a.${hostname} > /dev/null 2>&1
+        run_bench
+        rm a.${hostname}
+        cd - > /dev/null
+    fi # done Go
+}
+
+# /usr/bin/time -f "%Uu %Ss %Er %Mkb"
+if [ ${contend} -eq ${true} ] ; then
+    echo "contend2: "
+    run_contend ${chan_size} 'contend' '2'
+    echo "contend4: "
+    run_contend ${chan_size} 'contend' '4'
+    echo "contend8: "
+    run_contend ${chan_size} 'contend' '8'
+fi
+
+if [ ${spin} -eq ${true} ] ; then
+    echo "spin2: "
+    run_contend ${chan_size} 'spin' '2'
+    echo "spin4: "
+    run_contend ${chan_size} 'spin' '4'
+    echo "spin8: "
+    run_contend ${chan_size} 'spin' '8'
+fi
+
+if [ ${sidechan} -eq ${true} ] ; then
+    echo "sidechan: "
+    post_args=${chan_size}
+    if [ ${runCFA} -eq ${true} ] ; then
+        cd cfa # CFA RUN
+        print_header 'CFA'
+        ${cfa} ${cfa_flags} sidechan.cfa -o a.${hostname} > /dev/null 2>&1
+        run_side_chan
+        rm a.${hostname}
+        cd - > /dev/null
+    fi # done CFA
+
+    if [ ${runGO} -eq ${true} ] ; then
+        cd go/sidechan
+        print_header 'Go'
+        go build -o a.${hostname} > /dev/null 2>&1
+        run_side_chan
+        rm a.${hostname}
+        cd - > /dev/null
+    fi # done Go
+fi
+
+if [ ${future} -eq ${true} ] ; then
+    post_args=${future_time}
+    for i in ${!future_flags[@]}; do
+        echo 'future '${future_names[$i]}':'
+        if [ ${runCFA} -eq ${true} ] ; then
+            cd cfa # CFA RUN
+            print_header 'CFA'
+            ${cfa} ${cfa_flags} ${future_flags[$i]} future.cfa -o a.${hostname} > /dev/null 2>&1
+            run_future
+            rm a.${hostname}
+            cd - > /dev/null
+        fi # done CFA
+
+        if [ ${runUCPP} -eq ${true} ] ; then
+            cd ucpp
+            print_header 'uC++'
+            ${UCPP} ${UCPPflags} ${future_flags[$i]} future.cc -o a.${hostname} > /dev/null 2>&1
+            run_future
+            rm a.${hostname}
+            cd - > /dev/null
+        fi # done Go
+    done
+fi
+
+if [ ${order} -eq ${true} ] ; then
+    echo "order: "
+    post_args=${chan_size}
+    if [ ${runCFA} -eq ${true} ] ; then
+        cd cfa # CFA RUN
+        print_header 'CFA'
+        ${cfa} ${cfa_flags} order.cfa -o a.${hostname} > /dev/null 2>&1
+        run_order
+        rm a.${hostname}
+        cd - > /dev/null
+    fi # done CFA
+
+    if [ ${runGO} -eq ${true} ] ; then
+        cd go/order
+        print_header 'Go'
+        go build -o a.${hostname} > /dev/null 2>&1
+        run_order
+        rm a.${hostname}
+        cd - > /dev/null
+    fi # done Go
+fi
Index: doc/theses/colby_parsons_MMath/benchmarks/waituntil/ucpp/future.cc
===================================================================
--- doc/theses/colby_parsons_MMath/benchmarks/waituntil/ucpp/future.cc	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
+++ doc/theses/colby_parsons_MMath/benchmarks/waituntil/ucpp/future.cc	(revision f945fa7ba076d346ab1aa115747f79712d70331d)
@@ -0,0 +1,180 @@
+#include <iostream>
+using namespace std;
+#include <uFuture.h>
+
+// #define ANDOR
+
+size_t Processors = 2, Time = 10;
+size_t globalTotal = 0;
+volatile bool done_loop = false;
+volatile bool client_done = false;
+volatile bool server_done = false;
+
+Future_ISM<size_t> A, B, C;
+
+static inline void wait() {
+    #ifdef OR
+    _Select( A ) { A(); }
+    or _Select( B ) { B(); }
+    or _Select( C ) { C(); }
+    #endif
+    #ifdef AND
+    _Select( A ) { A(); }
+    and _Select( B ) { B(); }
+    #endif
+    #ifdef AND3
+    _Select( A ) { A(); }
+    and _Select( B ) { B(); }
+    and _Select( C ) { C(); }
+    #endif
+    #ifdef ANDOR
+    _Select( A ) { A(); }
+    and _Select( B ) { B(); }
+    or _Select( C ) { C(); }
+    #endif
+    #ifdef ORAND
+    (_Select( A ) { A(); }
+    or _Select( B ) { B(); })
+    and _Select( C ) { C(); }
+    #endif
+    #ifdef BASIC
+    A();
+    #endif
+}
+
+static inline void fulfill( size_t i ) {
+    #ifdef OR
+    if ( i % 3 == 0 ) {
+        A.delivery(i);
+    } else if ( i % 3 == 1 ) {
+        B.delivery(i);
+    } else {
+        C.delivery(i);
+    }
+    #endif
+    #ifdef AND
+    if ( i % 2 == 0 ) {
+        A.delivery(i);
+        B.delivery(i);
+    } else {
+        B.delivery(i);
+        A.delivery(i);
+    }
+    #endif
+    #ifdef AND3
+    if ( i % 6 == 0 ) {
+        A.delivery(i);
+        B.delivery(i);
+        C.delivery(i);
+    } else if ( i % 6 == 1 ) {
+        A.delivery(i);
+        C.delivery(i);
+        B.delivery(i);
+    } else if ( i % 6 == 2 ) {
+        B.delivery(i);
+        A.delivery(i);
+        C.delivery(i);
+    } else if ( i % 6 == 3 ) {
+        B.delivery(i);
+        C.delivery(i);
+        A.delivery(i);
+    } else if ( i % 6 == 4 ) {
+        C.delivery(i);
+        A.delivery(i);
+        B.delivery(i);
+    } else if ( i % 6 == 5 ) {
+        C.delivery(i);
+        B.delivery(i);
+        A.delivery(i);
+    }
+    #endif
+    #ifdef ANDOR
+    if ( i % 4 == 0 ) {
+        A.delivery(i);
+        B.delivery(i);
+    } else if ( i % 4 == 1 ) {
+        A.delivery(i);
+        C.delivery(i);
+    } else if ( i % 4 == 2 ) {
+        B.delivery(i);
+        C.delivery(i);
+    } else {
+        C.delivery(i);
+    }
+    #endif
+    #ifdef ORAND
+    if ( i % 4 == 0 ) {
+        A.delivery(i);
+        C.delivery(i);
+    } else if ( i % 4 == 1 ) {
+        C.delivery(i);
+        A.delivery(i);
+    } else if ( i % 4 == 2 ) {
+        B.delivery(i);
+        C.delivery(i);
+    } else {
+        C.delivery(i);
+        B.delivery(i);
+    }
+    #endif
+    #ifdef BASIC
+    A.delivery(i);
+    #endif
+}
+
+_Task Client {
+	void main() {
+		size_t i = 0;
+        for(; !client_done; i++ ) {
+            wait();
+            A.reset();
+            B.reset();
+            C.reset();
+            done_loop = true;
+        }
+        __atomic_fetch_add( &globalTotal, i, __ATOMIC_SEQ_CST );
+	} 
+};
+
+_Task Server {
+	void main() {
+		for( size_t i = 0; !server_done; i++ ) {
+            fulfill( i );
+            while( !done_loop ) {}
+            done_loop = false;
+        }
+	}
+};
+
+int main( int argc, char * argv[] ) {
+	switch ( argc ) {
+	  case 2:
+		if ( strcmp( argv[1], "d" ) != 0 ) {			// default ?
+			Time = atoi( argv[1] );
+			if ( Time < 0 ) goto Usage;
+		} // if
+	  case 1:											// use defaults
+		break;
+	  default:
+	  Usage:
+		cerr << "Usage: " << argv[0]
+             << "[ time (>= 0) | 'd' (default " << Time
+			 << ") ]" ;
+		exit( EXIT_FAILURE );
+	} // switch
+    uProcessor p[Processors - 1];
+
+    {
+        Server s;
+        {
+            Client c;
+
+            uBaseTask::sleep( uDuration( Time ) );
+
+            client_done = true;
+        }
+        server_done = true;
+        done_loop = true;
+    }
+    cout << globalTotal << endl;
+} // main
