Index: Jenkinsfile
===================================================================
--- Jenkinsfile	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ Jenkinsfile	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -108,5 +108,5 @@
 
 			// Configure libcfa
-			sh 'make -j 8 --no-print-directory configure-libcfa'
+			sh 'make -j $(nproc) --no-print-directory configure-libcfa'
 		}
 	}
@@ -116,8 +116,8 @@
 		dir (BuildDir) {
 			// Build driver
-			sh 'make -j 8 --no-print-directory -C driver'
+			sh 'make -j $(nproc) --no-print-directory -C driver'
 
 			// Build translator
-			sh 'make -j 8 --no-print-directory -C src'
+			sh 'make -j $(nproc) --no-print-directory -C src'
 		}
 	}
@@ -126,5 +126,5 @@
 		// Build outside of the src tree to ease cleaning
 		dir (BuildDir) {
-			sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-debug"
+			sh "make -j $(nproc) --no-print-directory -C libcfa/${Settings.Architecture.name}-debug"
 		}
 	}
@@ -133,5 +133,5 @@
 		// Build outside of the src tree to ease cleaning
 		dir (BuildDir) {
-			sh "make -j 8 --no-print-directory -C libcfa/${Settings.Architecture.name}-nodebug"
+			sh "make -j $(nproc) --no-print-directory -C libcfa/${Settings.Architecture.name}-nodebug"
 		}
 	}
@@ -140,5 +140,5 @@
 		// Build outside of the src tree to ease cleaning
 		dir (BuildDir) {
-			sh "make -j 8 --no-print-directory install"
+			sh "make -j $(nproc) --no-print-directory install"
 		}
 	}
@@ -161,5 +161,5 @@
 		Tools.BuildStage('Test: full', Settings.RunAllTests) {
 			dir (BuildDir) {
-					jopt = ""
+					jopt = "-j $(nproc)"
 					if( Settings.Architecture.node == 'x86' ) {
 						jopt = "-j2"
Index: benchmark/io/http/protocol.cfa
===================================================================
--- benchmark/io/http/protocol.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ benchmark/io/http/protocol.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -173,21 +173,4 @@
 }
 
-static void zero_sqe(struct io_uring_sqe * sqe) {
-	sqe->flags = 0;
-	sqe->ioprio = 0;
-	sqe->fd = 0;
-	sqe->off = 0;
-	sqe->addr = 0;
-	sqe->len = 0;
-	sqe->fsync_flags = 0;
-	sqe->__pad2[0] = 0;
-	sqe->__pad2[1] = 0;
-	sqe->__pad2[2] = 0;
-	sqe->fd = 0;
-	sqe->off = 0;
-	sqe->addr = 0;
-	sqe->len = 0;
-}
-
 enum FSM_STATE {
 	Initial,
Index: c/theses/mubeen_zulfiqar_MMath/AllocDS1.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/AllocDS1.fig	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ 	(revision )
@@ -1,162 +1,0 @@
-#FIG 3.2  Produced by xfig version 3.2.7b
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
--2
-1200 2
-6 4200 1575 4500 1725
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 1650 20 20 4275 1650 4295 1650
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4350 1650 20 20 4350 1650 4370 1650
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4425 1650 20 20 4425 1650 4445 1650
--6
-6 2850 2475 3150 2850
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 2925 2475 2925 2700
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 2850 2700 3150 2700 3150 2850 2850 2850 2850 2700
--6
-6 4350 2475 4650 2850
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 4425 2475 4425 2700
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 4350 2700 4650 2700 4650 2850 4350 2850 4350 2700
--6
-6 3600 2475 3825 3150
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3675 2475 3675 2700
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 3600 2700 3825 2700 3825 2850 3600 2850 3600 2700
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 3600 3000 3825 3000 3825 3150 3600 3150 3600 3000
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3675 2775 3675 3000
--6
-6 4875 3600 5175 3750
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 3675 20 20 4950 3675 4970 3675
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 3675 20 20 5025 3675 5045 3675
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 3675 20 20 5100 3675 5120 3675
--6
-6 4875 2325 5175 2475
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 2400 20 20 4950 2400 4970 2400
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 2400 20 20 5025 2400 5045 2400
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 2400 20 20 5100 2400 5120 2400
--6
-6 5625 2325 5925 2475
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 2400 20 20 5700 2400 5720 2400
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 2400 20 20 5775 2400 5795 2400
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 2400 20 20 5850 2400 5870 2400
--6
-6 5625 3600 5925 3750
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 3675 20 20 5700 3675 5720 3675
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 3675 20 20 5775 3675 5795 3675
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 3675 20 20 5850 3675 5870 3675
--6
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2400 2100 2400 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2550 2100 2550 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2700 2100 2700 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2850 2100 2850 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3000 2100 3000 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3600 2100 3600 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3900 2100 3900 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 4050 2100 4050 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 4200 2100 4200 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 4350 2100 4350 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 4500 2100 4500 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3300 1500 3300 1800
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3600 1500 3600 1800
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3900 1500 3900 1800
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 3000 1500 4800 1500 4800 1800 3000 1800 3000 1500
-2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3225 1650 2625 2100
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3150 1650 2550 2100
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3450 1650 4050 2100
-2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3375 1650 3975 2100
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2100 2100 2100 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 1950 2250 3150 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3450 2250 4650 2250
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 1950 2100 3150 2100 3150 2550 1950 2550 1950 2100
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 3450 2100 4650 2100 4650 2550 3450 2550 3450 2100
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2250 2100 2250 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3750 2100 3750 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 2025 2475 2025 2700
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 2025 2775 2025 3000
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 1950 3000 2100 3000 2100 3150 1950 3150 1950 3000
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 1950 2700 2100 2700 2100 2850 1950 2850 1950 2700
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
-	1 1 1.00 45.00 90.00
-	 1950 3750 2700 3750 2700 3525
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 1950 3525 3150 3525 3150 3900 1950 3900 1950 3525
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
-	1 1 1.00 45.00 90.00
-	 3450 3750 4200 3750 4200 3525
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 3450 3525 4650 3525 4650 3900 3450 3900 3450 3525
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
-	1 1 1.00 45.00 90.00
-	 3150 4650 4200 4650 4200 4275
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 3150 4275 4650 4275 4650 4875 3150 4875 3150 4275
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 1950 2400 3150 2400
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3450 2400 4650 2400
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5400 2100 5400 3900
-4 2 0 50 -1 0 11 0.0000 2 120 300 1875 2250 lock\001
-4 1 0 50 -1 0 12 0.0000 2 135 1935 3900 1425 N kernel-thread buckets\001
-4 1 0 50 -1 0 12 0.0000 2 195 810 4425 2025 heap$_2$\001
-4 1 0 50 -1 0 12 0.0000 2 195 810 2175 2025 heap$_1$\001
-4 2 0 50 -1 0 11 0.0000 2 120 270 1875 2400 size\001
-4 2 0 50 -1 0 11 0.0000 2 120 270 1875 2550 free\001
-4 1 0 50 -1 0 12 0.0000 2 180 825 2550 3450 local pool\001
-4 0 0 50 -1 0 12 0.0000 2 135 360 3525 3700 lock\001
-4 0 0 50 -1 0 12 0.0000 2 135 360 3225 4450 lock\001
-4 2 0 50 -1 0 12 0.0000 2 135 600 1875 3000 free list\001
-4 1 0 50 -1 0 12 0.0000 2 180 825 4050 3450 local pool\001
-4 1 0 50 -1 0 12 0.0000 2 180 1455 3900 4200 global pool (sbrk)\001
-4 0 0 50 -1 0 12 0.0000 2 135 360 2025 3700 lock\001
-4 1 0 50 -1 0 12 0.0000 2 180 720 6450 3150 free pool\001
-4 1 0 50 -1 0 12 0.0000 2 180 390 6450 2925 heap\001
Index: c/theses/mubeen_zulfiqar_MMath/AllocDS2.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/AllocDS2.fig	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ 	(revision )
@@ -1,126 +1,0 @@
-#FIG 3.2  Produced by xfig version 3.2.7b
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
--2
-1200 2
-6 2850 2100 3150 2250
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 2925 2175 20 20 2925 2175 2945 2175
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3000 2175 20 20 3000 2175 3020 2175
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3075 2175 20 20 3075 2175 3095 2175
--6
-6 4050 2100 4350 2250
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4125 2175 20 20 4125 2175 4145 2175
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4200 2175 20 20 4200 2175 4220 2175
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 2175 20 20 4275 2175 4295 2175
--6
-6 4650 2100 4950 2250
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4725 2175 20 20 4725 2175 4745 2175
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4800 2175 20 20 4800 2175 4820 2175
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4875 2175 20 20 4875 2175 4895 2175
--6
-6 3450 2100 3750 2250
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3525 2175 20 20 3525 2175 3545 2175
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3600 2175 20 20 3600 2175 3620 2175
-1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3675 2175 20 20 3675 2175 3695 2175
--6
-6 3300 2175 3600 2550
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3375 2175 3375 2400
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 3300 2400 3600 2400 3600 2550 3300 2550 3300 2400
--6
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3150 1800 3150 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2850 1800 2850 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 4650 1800 4650 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 4950 1800 4950 2250
-2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 4500 1725 4500 2250
-2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5100 1725 5100 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3450 1800 3450 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3750 1800 3750 2250
-2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3300 1725 3300 2250
-2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 3900 1725 3900 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5250 1800 5250 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5400 1800 5400 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5550 1800 5550 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5700 1800 5700 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 5850 1800 5850 2250
-2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2700 1725 2700 2250
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3375 1275 3375 1575
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 2700 1275 2700 1575
-2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 2775 1275 2775 1575
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 5175 1275 5175 1575
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 5625 1275 5625 1575
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3750 1275 3750 1575
-2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 3825 1275 3825 1575
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2700 1950 6000 1950
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
-	 2700 2100 6000 2100
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 2700 1800 6000 1800 6000 2250 2700 2250 2700 1800
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 2775 2175 2775 2400
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 2775 2475 2775 2700
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 2700 2700 2850 2700 2850 2850 2700 2850 2700 2700
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 2700 2400 2850 2400 2850 2550 2700 2550 2700 2400
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
-	1 1 1.00 45.00 90.00
-	 4575 2175 4575 2400
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 4500 2400 5025 2400 5025 2550 4500 2550 4500 2400
-2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
-	1 1 1.00 45.00 90.00
-	 3600 3525 4650 3525 4650 3150
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 3600 3150 5100 3150 5100 3750 3600 3750 3600 3150
-4 2 0 50 -1 0 11 0.0000 2 120 300 2625 1950 lock\001
-4 1 0 50 -1 0 10 0.0000 2 150 1155 3000 1725 N$\\times$S$_1$\001
-4 1 0 50 -1 0 10 0.0000 2 150 1155 3600 1725 N$\\times$S$_2$\001
-4 1 0 50 -1 0 12 0.0000 2 180 390 4425 1500 heap\001
-4 2 0 50 -1 0 12 0.0000 2 135 1140 2550 1425 kernel threads\001
-4 2 0 50 -1 0 11 0.0000 2 120 270 2625 2100 size\001
-4 2 0 50 -1 0 11 0.0000 2 120 270 2625 2250 free\001
-4 2 0 50 -1 0 12 0.0000 2 135 600 2625 2700 free list\001
-4 0 0 50 -1 0 12 0.0000 2 135 360 3675 3325 lock\001
-4 1 0 50 -1 0 12 0.0000 2 180 1455 4350 3075 global pool (sbrk)\001
-4 1 0 50 -1 0 10 0.0000 2 150 1110 4800 1725 N$\\times$S$_t$\001
Index: doc/theses/mubeen_zulfiqar_MMath/Makefile
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/Makefile	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/mubeen_zulfiqar_MMath/Makefile	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,14 +1,15 @@
-DOC = uw-ethesis.pdf
-BASE = ${DOC:%.pdf=%} # remove suffix
 # directory for latex clutter files
-BUILD = build
-TEXSRC = $(wildcard *.tex)
-FIGSRC = $(wildcard *.fig)
-BIBSRC = $(wildcard *.bib)
-TEXLIB = .:../../LaTeXmacros:${BUILD}: # common latex macros
-BIBLIB = .:../../bibliography # common citation repository
+Build = build
+Figures = figures
+Pictures = pictures
+TeXSRC = ${wildcard *.tex}
+FigSRC = ${notdir ${wildcard ${Figures}/*.fig}}
+PicSRC = ${notdir ${wildcard ${Pictures}/*.fig}}
+BIBSRC = ${wildcard *.bib}
+TeXLIB = .:../../LaTeXmacros:${Build}: # common latex macros
+BibLIB = .:../../bibliography # common citation repository
 
 MAKEFLAGS = --no-print-directory # --silent
-VPATH = ${BUILD}
+VPATH = ${Build} ${Figures} ${Pictures} # extra search path for file names used in document
 
 ### Special Rules:
@@ -18,38 +19,46 @@
 
 ### Commands:
-LATEX = TEXINPUTS=${TEXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${BUILD}
-BIBTEX = BIBINPUTS=${BIBLIB} bibtex
-#GLOSSARY = INDEXSTYLE=${BUILD} makeglossaries-lite
+
+LaTeX = TEXINPUTS=${TeXLIB} && export TEXINPUTS && latex -halt-on-error -output-directory=${Build}
+BibTeX = BIBINPUTS=${BibLIB} bibtex
+#Glossary = INDEXSTYLE=${Build} makeglossaries-lite
 
 ### Rules and Recipes:
 
+DOC = uw-ethesis.pdf
+BASE = ${DOC:%.pdf=%} # remove suffix
+
 all: ${DOC}
 
-${BUILD}/%.dvi: ${TEXSRC} ${FIGSRC:%.fig=%.tex} ${BIBSRC} Makefile | ${BUILD}
-	${LATEX} ${BASE}
-	${BIBTEX} ${BUILD}/${BASE}
-	${LATEX} ${BASE}
-#	${GLOSSARY} ${BUILD}/${BASE}
-#	${LATEX} ${BASE}
+clean:
+	@rm -frv ${DOC} ${Build}
 
-${BUILD}:
+# File Dependencies #
+
+${Build}/%.dvi : ${TeXSRC} ${FigSRC:%.fig=%.tex} ${PicSRC:%.fig=%.pstex} ${BIBSRC} Makefile | ${Build}
+	${LaTeX} ${BASE}
+	${BibTeX} ${Build}/${BASE}
+	${LaTeX} ${BASE}
+	# if nedded, run latex again to get citations
+	if fgrep -s "LaTeX Warning: Citation" ${basename $@}.log ; then ${LaTeX} ${BASE} ; fi
+#	${Glossary} ${Build}/${BASE}
+#	${LaTeX} ${BASE}
+
+${Build}:
 	mkdir $@
 
-%.pdf : ${BUILD}/%.ps | ${BUILD}
+%.pdf : ${Build}/%.ps | ${Build}
 	ps2pdf $<
 
-%.ps : %.dvi | ${BUILD}
+%.ps : %.dvi | ${Build}
 	dvips $< -o $@
 
-%.tex : %.fig | ${BUILD}
-	fig2dev -L eepic $< > ${BUILD}/$@
+%.tex : %.fig | ${Build}
+	fig2dev -L eepic $< > ${Build}/$@
 
-%.ps : %.fig | ${BUILD}
-	fig2dev -L ps $< > ${BUILD}/$@
+%.ps : %.fig | ${Build}
+	fig2dev -L ps $< > ${Build}/$@
 
-%.pstex : %.fig | ${BUILD}
-	fig2dev -L pstex $< > ${BUILD}/$@
-	fig2dev -L pstex_t -p ${BUILD}/$@ $< > ${BUILD}/$@_t
-
-clean:
-	@rm -frv ${DOC} ${BUILD} *.fig.bak
+%.pstex : %.fig | ${Build}
+	fig2dev -L pstex $< > ${Build}/$@
+	fig2dev -L pstex_t -p ${Build}/$@ $< > ${Build}/$@_t
Index: doc/theses/mubeen_zulfiqar_MMath/allocator.tex
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/allocator.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/mubeen_zulfiqar_MMath/allocator.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,51 +1,10 @@
 \chapter{Allocator}
 
-\noindent
-====================
-
-Writing Points:
-\begin{itemize}
-\item
-Objective of uHeapLmmm.
-\item
-Design philosophy.
-\item
-Background and previous design of uHeapLmmm.
-\item
-Distributed design of uHeapLmmm.
-
------ SHOULD WE GIVE IMPLEMENTATION DETAILS HERE? -----
-
-\PAB{Maybe. There might be an Implementation chapter.}
-\item
-figure.
-\item
-Advantages of distributed design.
-\end{itemize}
-
-The new features added to uHeapLmmm (incl. @malloc\_size@ routine)
-\CFA alloc interface with examples.
-
-\begin{itemize}
-\item
-Why did we need it?
-\item
-The added benefits.
-\end{itemize}
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% uHeapLmmm Design
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Objective of uHeapLmmm}
-UHeapLmmm is a lightweight memory allocator. The objective behind uHeapLmmm is to design a minimal concurrent memory allocator that has new features and also fulfills GNU C Library requirements (FIX ME: cite requirements).
-
-\subsection{Design philosophy}
-The objective of uHeapLmmm's new design was to fulfill following requirements:
-\begin{itemize}
-\item It should be concurrent to be used in multi-threaded programs.
+\section{uHeap}
+uHeap is a lightweight memory allocator. The objective behind uHeap is to design a minimal concurrent memory allocator that has new features and also fulfills GNU C Library requirements (FIX ME: cite requirements).
+
+The objective of uHeap's new design was to fulfill following requirements:
+\begin{itemize}
+\item It should be concurrent and thread-safe for multi-threaded programs.
 \item It should avoid global locks, on resources shared across all threads, as much as possible.
 \item It's performance (FIX ME: cite performance benchmarks) should be comparable to the commonly used allocators (FIX ME: cite common allocators).
@@ -55,14 +14,21 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-\section{Background and previous design of uHeapLmmm}
-uHeapLmmm was originally designed by X in X (FIX ME: add original author after confirming with Peter).
-(FIX ME: make and add figure of previous design with description)
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Distributed design of uHeapLmmm}
-uHeapLmmm's design was reviewed and changed to fulfill new requirements (FIX ME: cite allocator philosophy). For this purpose, following two designs of uHeapLmm were proposed:
-
-\paragraph{Design 1: Decentralized}
+\section{Design choices for uHeap}
+uHeap's design was reviewed and changed to fulfill new requirements (FIX ME: cite allocator philosophy). For this purpose, following two designs of uHeapLmm were proposed:
+
+\paragraph{Design 1: Centralized}
+One heap, but lower bucket sizes are N-shared across KTs.
+This design leverages the fact that 95\% of allocation requests are less than 512 bytes and there are only 3--5 different request sizes.
+When KTs $\le$ N, the important bucket sizes are uncontented.
+When KTs $>$ N, the free buckets are contented.
+Therefore, threads are only contending for a small number of buckets, which are distributed among them to reduce contention.
+\begin{cquote}
+\centering
+\input{AllocDS2}
+\end{cquote}
+Problems: need to know when a kernel thread (KT) is created and destroyed to know when to assign a shared bucket-number.
+When no thread is assigned a bucket number, its free storage is unavailable. All KTs will be contended for one lock on sbrk for their initial allocations (before free-lists gets populated).
+
+\paragraph{Design 2: Decentralized N Heaps}
 Fixed number of heaps: shard the heap into N heaps each with a bump-area allocated from the @sbrk@ area.
 Kernel threads (KT) are assigned to the N heaps.
@@ -77,73 +43,171 @@
 Problems: need to know when a KT is created and destroyed to know when to assign/un-assign a heap to the KT.
 
-\paragraph{Design 2: Centralized}
-One heap, but lower bucket sizes are N-shared across KTs.
-This design leverages the fact that 95\% of allocation requests are less than 512 bytes and there are only 3--5 different request sizes.
-When KTs $\le$ N, the important bucket sizes are uncontented.
-When KTs $>$ N, the free buckets are contented.
-Therefore, threads are only contending for a small number of buckets, which are distributed among them to reduce contention.
-\begin{cquote}
+\paragraph{Design 3: Decentralized Per-thread Heaps}
+Design 3 is similar to design 2 but instead of having an M:N model, it uses a 1:1 model. So, instead of having N heaos and sharing them among M KTs, Design 3 has one heap for each KT.
+Dynamic number of heaps: create a thread-local heap for each kernel thread (KT) with a bump-area allocated from the @sbrk@ area.
+Each KT will have its own exclusive thread-local heap. Heap will be uncontended between KTs regardless how many KTs have been created.
+Operations on @sbrk@ area will still be protected by locks.
+%\begin{cquote}
+%\centering
+%\input{AllocDS3} FIXME add figs
+%\end{cquote}
+Problems: We cannot destroy the heap when a KT exits because our dynamic objects have ownership and they are returned to the heap that created them when the program frees a dynamic object. All dynamic objects point back to their owner heap. If a thread A creates an object O, passes it to another thread B, and A itself exits. When B will free object O, O should return to A's heap so A's heap should be preserved for the lifetime of the whole program as their might be objects in-use of other threads that were allocated by A. Also, we need to know when a KT is created and destroyed to know when to create/destroy a heap for the KT.
+
+\paragraph{Design 4: Decentralized Per-CPU Heaps}
+Design 4 is similar to Design 3 but instead of having a heap for each thread, it creates a heap for each CPU.
+Fixed number of heaps for a machine: create a heap for each CPU with a bump-area allocated from the @sbrk@ area.
+Each CPU will have its own CPU-local heap. When the program does a dynamic memory operation, it will be entertained by the heap of the CPU where the process is currently running on.
+Each CPU will have its own exclusive heap. Just like Design 3(FIXME cite), heap will be uncontended between KTs regardless how many KTs have been created.
+Operations on @sbrk@ area will still be protected by locks.
+To deal with preemtion during a dynamic memory operation, librseq(FIXME cite) will be used to make sure that the whole dynamic memory operation completes on one CPU. librseq's restartable sequences can make it possible to re-run a critical section and undo the current writes if a preemption happened during the critical section's execution.
+%\begin{cquote}
+%\centering
+%\input{AllocDS4} FIXME add figs
+%\end{cquote}
+
+Problems: This approach was slower than the per-thread model. Also, librseq does not provide such restartable sequences to detect preemtions in user-level threading system which is important to us as CFA(FIXME cite) has its own threading system that we want to support.
+
+Out of the four designs, Design 3 was chosen because of the following reasons.
+\begin{itemize}
+\item
+Decentralized designes are better in general as compared to centralized design because their concurrency is better across all bucket-sizes as design 1 shards a few buckets of selected sizes while other designs shards all the buckets. Decentralized designes shard the whole heap which has all the buckets with the addition of sharding sbrk area. So Design 1 was eliminated.
+\item
+Design 2 was eliminated because it has a possibility of contention in-case of KT > N while Design 3 and 4 have no contention in any scenerio.
+\item
+Design 4 was eliminated because it was slower than Design 3 and it provided no way to achieve user-threading safety using librseq. We had to use CFA interruption handling to achive user-threading safety which has some cost to it. Desing 4 was already slower than Design 3, adding cost of interruption handling on top of that would have made it even slower.
+\end{itemize}
+
+
+\subsection{Advantages of distributed design}
+
+The distributed design of uHeap is concurrent to work in multi-threaded applications.
+
+Some key benefits of the distributed design of uHeap are as follows:
+
+\begin{itemize}
+\item
+The bump allocation is concurrent as memory taken from sbrk is sharded across all heaps as bump allocation reserve. The call to sbrk will be protected using locks but bump allocation (on memory taken from sbrk) will not be contended once the sbrk call has returned.
+\item
+Low or almost no contention on heap resources.
+\item
+It is possible to use sharing and stealing techniques to share/find unused storage, when a free list is unused or empty.
+\item
+Distributed design avoids unnecassry locks on resources shared across all KTs.
+\end{itemize}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{uHeap Structure}
+
+As described in (FIXME cite 2.4) uHeap uses following features of multi-threaded memory allocators.
+\begin{itemize}
+\item
+uHeap has multiple heaps without a global heap and uses 1:1 model. (FIXME cite 2.5 1:1 model)
+\item
+uHeap uses object ownership. (FIXME cite 2.5.2)
+\item
+uHeap does not use object containers (FIXME cite 2.6) or any coalescing technique. Instead each dynamic object allocated by uHeap has a header than contains bookkeeping information.
+\item
+Each thread-local heap in uHeap has its own allocation buffer that is taken from the system using sbrk() call. (FIXME cite 2.7)
+\item
+Unless a heap is freeing an object that is owned by another thread's heap or heap is using sbrk() system call, uHeap is mostly lock-free which eliminates most of the contention on shared resources. (FIXME cite 2.8)
+\end{itemize}
+
+As uHeap uses a heap per-thread model to reduce contention on heap resources, we manage a list of heaps (heap-list) that can be used by threads. The list is empty at the start of the program. When a kernel thread (KT) is created, we check if heap-list is empty. If no then a heap is removed from the heap-list and is given to this new KT to use exclusively. If yes then a new heap object is created in dynamic memory and is given to this new KT to use exclusively. When a KT exits, its heap is not destroyed but instead its heap is put on the heap-list and is ready to be reused by new KTs.
+
+This reduces the memory footprint as the objects on free-lists of a KT that has exited can be reused by a new KT. Also, we preserve all the heaps that were created during the lifetime of the program till the end of the program. uHeap uses object ownership where an object is freed to the free-buckets of the heap that allocated it. Even after a KT A has exited, its heap has to be preserved as there might be objects in-use of other threads that were initially allocated by A and the passed to other threads.
+
+\begin{figure}
 \centering
-\input{AllocDS2}
-\end{cquote}
-Problems: need to know when a kernel thread (KT) is created and destroyed to know when to assign a shared bucket-number.
-When no thread is assigned a bucket number, its free storage is unavailable. All KTs will be contended for one lock on sbrk for their initial allocations (before free-lists gets populated).
-
-Out of the two designs, Design 1 was chosen because it's concurrency is better across all bucket-sizes as design-2 shards a few buckets of selected sizes while design-1 shards all the buckets. Design-2 shards the whole heap which has all the buckets with the addition of sharding sbrk area.
-
-\subsection{Advantages of distributed design}
-The distributed design of uHeapLmmm is concurrent to work in multi-threaded applications.
-
-Some key benefits of the distributed design of uHeapLmmm are as follows:
-
-\begin{itemize}
-\item
-The bump allocation is concurrent as memory taken from sbrk is sharded across all heaps as bump allocation reserve. The lock on bump allocation (on memory taken from sbrk) will only be contended if KTs > N. The contention on sbrk area is less likely as it will only happen in the case if heaps assigned to two KTs get short of bump allocation reserve simultanously.
-\item
-N heaps are created at the start of the program and destroyed at the end of program. When a KT is created, we only assign it to one of the heaps. When a KT is destroyed, we only dissociate it from the assigned heap but we do not destroy that heap. That heap will go back to our pool-of-heaps, ready to be used by some new KT. And if that heap was shared among multiple KTs (like the case of KTs > N) then, on deletion of one KT, that heap will be still in-use of the other KTs. This will prevent creation and deletion of heaps during run-time as heaps are re-usable which helps in keeping low-memory footprint.
-\item
-It is possible to use sharing and stealing techniques to share/find unused storage, when a free list is unused or empty.
-\item
-Distributed design avoids unnecassry locks on resources shared across all KTs.
-\end{itemize}
-
-FIX ME: Cite performance comparison of the two heap designs if required
+\includegraphics[width=0.65\textwidth]{figures/NewHeapStructure.eps}
+\caption{HeapStructure}
+\label{fig:heapStructureFig}
+\end{figure}
+
+Each heap uses seggregated free-buckets that have free objects of a specific size. Each free-bucket of a specific size has following 2 lists in it:
+\begin{itemize}
+\item
+Free list is used when a thread is freeing an object that is owned by its own heap so free list does not use any locks/atomic-operations as it is only used by the owner KT.
+\item
+Away list is used when a thread A is freeing an object that is owned by another KT B's heap. This object should be freed to the owner heap (B's heap) so A will place the object on the away list of B. Away list is lock protected as it is shared by all other threads.
+\end{itemize}
+
+When a dynamic object of a size S is requested. The thread-local heap will check if S is greater than or equal to the mmap threshhold. Any request larger than the mmap threshhold is fulfilled by allocating an mmap area of that size and such requests are not allocated on sbrk area. The value of this threshhold can be changed using mallopt routine but the new value should not be larger than our biggest free-bucket size.
+
+Algorithm~\ref{alg:heapObjectAlloc} briefly shows how an allocation request is fulfilled.
+
+\begin{algorithm}
+\caption{Dynamic object allocation of size S}\label{alg:heapObjectAlloc}
+\begin{algorithmic}[1]
+\State $\textit{O} \gets \text{NULL}$
+\If {$S < \textit{mmap-threshhold}$}
+	\State $\textit{B} \gets (\text{smallest free-bucket} \geq S)$
+	\If {$\textit{B's free-list is empty}$}
+		\If {$\textit{B's away-list is empty}$}
+			\If {$\textit{heap's allocation buffer} < S$}
+				\State $\text{get allocation buffer using system call sbrk()}$
+			\EndIf
+			\State $\textit{O} \gets \text{bump allocate an object of size S from allocation buffer}$
+		\Else
+			\State $\textit{merge B's away-list into free-list}$
+			\State $\textit{O} \gets \text{pop an object from B's free-list}$
+		\EndIf
+	\Else
+		\State $\textit{O} \gets \text{pop an object from B's free-list}$
+	\EndIf
+	\State $\textit{O's owner} \gets \text{B}$
+\Else
+	\State $\textit{O} \gets \text{allocate dynamic memory using system call mmap with size S}$
+\EndIf
+\State $\Return \textit{ O}$
+\end{algorithmic}
+\end{algorithm}
+
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 \section{Added Features and Methods}
-To improve the UHeapLmmm allocator (FIX ME: cite uHeapLmmm) interface and make it more user friendly, we added a few more routines to the C allocator. Also, we built a CFA (FIX ME: cite cforall) interface on top of C interface to increase the usability of the allocator.
+To improve the uHeap allocator (FIX ME: cite uHeap) interface and make it more user friendly, we added a few more routines to the C allocator. Also, we built a \CFA (FIX ME: cite cforall) interface on top of C interface to increase the usability of the allocator.
 
 \subsection{C Interface}
 We added a few more features and routines to the allocator's C interface that can make the allocator more usable to the programmers. THese features will programmer more control on the dynamic memory allocation.
 
-\subsubsection void * aalloc( size\_t dim, size\_t elemSize )
-aalloc is an extension of malloc. It allows programmer to allocate a dynamic array of objects without calculating the total size of array explicitly. The only alternate of this routine in the other allocators is calloc but calloc also fills the dynamic memory with 0 which makes it slower for a programmer who only wants to dynamically allocate an array of objects without filling it with 0.
-\paragraph{Usage}
-aalloc takes two parameters.
-
-\begin{itemize}
-\item
-dim: number of objects in the array
-\item
-elemSize: size of the object in the array.
-\end{itemize}
-It returns address of dynamic object allocatoed on heap that can contain dim number of objects of the size elemSize. On failure, it returns NULL pointer.
-
-\subsubsection void * resize( void * oaddr, size\_t size )
-resize is an extension of relloc. It allows programmer to reuse a cuurently allocated dynamic object with a new size requirement. Its alternate in the other allocators is realloc but relloc also copy the data in old object to the new object which makes it slower for the programmer who only wants to reuse an old dynamic object for a new size requirement but does not want to preserve the data in the old object to the new object.
-\paragraph{Usage}
-resize takes two parameters.
-
-\begin{itemize}
-\item
-oaddr: the address of the old object that needs to be resized.
-\item
-size: the new size requirement of the to which the old object needs to be resized.
-\end{itemize}
-It returns an object that is of the size given but it does not preserve the data in the old object. On failure, it returns NULL pointer.
-
-\subsubsection void * resize( void * oaddr, size\_t nalign, size\_t size )
-This resize is an extension of the above resize (FIX ME: cite above resize). In addition to resizing the size of of an old object, it can also realign the old object to a new alignment requirement.
+\subsection{Out of Memory}
+
+Most allocators use @nullptr@ to indicate an allocation failure, specifically out of memory;
+hence the need to return an alternate value for a zero-sized allocation.
+The alternative is to abort a program when out of memory.
+In theory, notifying the programmer allows recovery;
+in practice, it is almost impossible to gracefully when out of memory, so the cheaper approach of returning @nullptr@ for a zero-sized allocation is chosen.
+
+
+\subsection{\lstinline{void * aalloc( size_t dim, size_t elemSize )}}
+@aalloc@ is an extension of malloc. It allows programmer to allocate a dynamic array of objects without calculating the total size of array explicitly. The only alternate of this routine in the other allocators is calloc but calloc also fills the dynamic memory with 0 which makes it slower for a programmer who only wants to dynamically allocate an array of objects without filling it with 0.
+\paragraph{Usage}
+@aalloc@ takes two parameters.
+
+\begin{itemize}
+\item
+@dim@: number of objects in the array
+\item
+@elemSize@: size of the object in the array.
+\end{itemize}
+It returns address of dynamic object allocatoed on heap that can contain dim number of objects of the size elemSize. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{void * resize( void * oaddr, size_t size )}}
+@resize@ is an extension of relloc. It allows programmer to reuse a cuurently allocated dynamic object with a new size requirement. Its alternate in the other allocators is @realloc@ but relloc also copy the data in old object to the new object which makes it slower for the programmer who only wants to reuse an old dynamic object for a new size requirement but does not want to preserve the data in the old object to the new object.
+\paragraph{Usage}
+@resize@ takes two parameters.
+
+\begin{itemize}
+\item
+@oaddr@: the address of the old object that needs to be resized.
+\item
+@size@: the new size requirement of the to which the old object needs to be resized.
+\end{itemize}
+It returns an object that is of the size given but it does not preserve the data in the old object. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{void * resize( void * oaddr, size_t nalign, size_t size )}}
+This @resize@ is an extension of the above @resize@ (FIX ME: cite above resize). In addition to resizing the size of of an old object, it can also realign the old object to a new alignment requirement.
 \paragraph{Usage}
 This resize takes three parameters. It takes an additional parameter of nalign as compared to the above resize (FIX ME: cite above resize).
@@ -151,13 +215,13 @@
 \begin{itemize}
 \item
-oaddr: the address of the old object that needs to be resized.
-\item
-nalign: the new alignment to which the old object needs to be realigned.
-\item
-size: the new size requirement of the to which the old object needs to be resized.
-\end{itemize}
-It returns an object with the size and alignment given in the parameters. On failure, it returns a NULL pointer.
-
-\subsubsection void * amemalign( size\_t alignment, size\_t dim, size\_t elemSize )
+@oaddr@: the address of the old object that needs to be resized.
+\item
+@nalign@: the new alignment to which the old object needs to be realigned.
+\item
+@size@: the new size requirement of the to which the old object needs to be resized.
+\end{itemize}
+It returns an object with the size and alignment given in the parameters. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{void * amemalign( size_t alignment, size_t dim, size_t elemSize )}}
 amemalign is a hybrid of memalign and aalloc. It allows programmer to allocate an aligned dynamic array of objects without calculating the total size of the array explicitly. It frees the programmer from calculating the total size of the array.
 \paragraph{Usage}
@@ -166,13 +230,13 @@
 \begin{itemize}
 \item
-alignment: the alignment to which the dynamic array needs to be aligned.
-\item
-dim: number of objects in the array
-\item
-elemSize: size of the object in the array.
-\end{itemize}
-It returns a dynamic array of objects that has the capacity to contain dim number of objects of the size of elemSize. The returned dynamic array is aligned to the given alignment. On failure, it returns NULL pointer.
-
-\subsubsection void * cmemalign( size\_t alignment, size\_t dim, size\_t elemSize )
+@alignment@: the alignment to which the dynamic array needs to be aligned.
+\item
+@dim@: number of objects in the array
+\item
+@elemSize@: size of the object in the array.
+\end{itemize}
+It returns a dynamic array of objects that has the capacity to contain dim number of objects of the size of elemSize. The returned dynamic array is aligned to the given alignment. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{void * cmemalign( size_t alignment, size_t dim, size_t elemSize )}}
 cmemalign is a hybrid of amemalign and calloc. It allows programmer to allocate an aligned dynamic array of objects that is 0 filled. The current way to do this in other allocators is to allocate an aligned object with memalign and then fill it with 0 explicitly. This routine provides both features of aligning and 0 filling, implicitly.
 \paragraph{Usage}
@@ -181,71 +245,71 @@
 \begin{itemize}
 \item
-alignment: the alignment to which the dynamic array needs to be aligned.
-\item
-dim: number of objects in the array
-\item
-elemSize: size of the object in the array.
-\end{itemize}
-It returns a dynamic array of objects that has the capacity to contain dim number of objects of the size of elemSize. The returned dynamic array is aligned to the given alignment and is 0 filled. On failure, it returns NULL pointer.
-
-\subsubsection size\_t malloc\_alignment( void * addr )
-malloc\_alignment returns the alignment of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required alignment.
-\paragraph{Usage}
-malloc\_alignment takes one parameters.
-
-\begin{itemize}
-\item
-addr: the address of the currently allocated dynamic object.
-\end{itemize}
-malloc\_alignment returns the alignment of the given dynamic object. On failure, it return the value of default alignment of the uHeapLmmm allocator.
-
-\subsubsection bool malloc\_zero\_fill( void * addr )
-malloc\_zero\_fill returns whether a currently allocated dynamic object was initially zero filled at the time of allocation. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verifying the zero filled property of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was zero filled at the time of allocation.
-\paragraph{Usage}
-malloc\_zero\_fill takes one parameters.
-
-\begin{itemize}
-\item
-addr: the address of the currently allocated dynamic object.
-\end{itemize}
-malloc\_zero\_fill returns true if the dynamic object was initially zero filled and return false otherwise. On failure, it returns false.
-
-\subsubsection size\_t malloc\_size( void * addr )
-malloc\_size returns the allocation size of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required size. Its current alternate in the other allocators is malloc\_usable\_size. But, malloc\_size is different from malloc\_usable\_size as malloc\_usabe\_size returns the total data capacity of dynamic object including the extra space at the end of the dynamic object. On the other hand, malloc\_size returns the size that was given to the allocator at the allocation of the dynamic object. This size is updated when an object is realloced, resized, or passed through a similar allocator routine.
-\paragraph{Usage}
-malloc\_size takes one parameters.
-
-\begin{itemize}
-\item
-addr: the address of the currently allocated dynamic object.
-\end{itemize}
-malloc\_size returns the allocation size of the given dynamic object. On failure, it return zero.
-
-\subsubsection void * realloc( void * oaddr, size\_t nalign, size\_t size )
-This realloc is an extension of the default realloc (FIX ME: cite default realloc). In addition to reallocating an old object and preserving the data in old object, it can also realign the old object to a new alignment requirement.
-\paragraph{Usage}
-This realloc takes three parameters. It takes an additional parameter of nalign as compared to the default realloc.
-
-\begin{itemize}
-\item
-oaddr: the address of the old object that needs to be reallocated.
-\item
-nalign: the new alignment to which the old object needs to be realigned.
-\item
-size: the new size requirement of the to which the old object needs to be resized.
-\end{itemize}
-It returns an object with the size and alignment given in the parameters that preserves the data in the old object. On failure, it returns a NULL pointer.
-
-\subsection{CFA Malloc Interface}
-We added some routines to the malloc interface of CFA. These routines can only be used in CFA and not in our standalone uHeapLmmm allocator as these routines use some features that are only provided by CFA and not by C. It makes the allocator even more usable to the programmers.
-CFA provides the liberty to know the returned type of a call to the allocator. So, mainly in these added routines, we removed the object size parameter from the routine as allocator can calculate the size of the object from the returned type.
-
-\subsubsection T * malloc( void )
+@alignment@: the alignment to which the dynamic array needs to be aligned.
+\item
+@dim@: number of objects in the array
+\item
+@elemSize@: size of the object in the array.
+\end{itemize}
+It returns a dynamic array of objects that has the capacity to contain dim number of objects of the size of elemSize. The returned dynamic array is aligned to the given alignment and is 0 filled. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{size_t malloc_alignment( void * addr )}}
+@malloc_alignment@ returns the alignment of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required alignment.
+\paragraph{Usage}
+@malloc_alignment@ takes one parameters.
+
+\begin{itemize}
+\item
+@addr@: the address of the currently allocated dynamic object.
+\end{itemize}
+@malloc_alignment@ returns the alignment of the given dynamic object. On failure, it return the value of default alignment of the uHeap allocator.
+
+\subsection{\lstinline{bool malloc_zero_fill( void * addr )}}
+@malloc_zero_fill@ returns whether a currently allocated dynamic object was initially zero filled at the time of allocation. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verifying the zero filled property of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was zero filled at the time of allocation.
+\paragraph{Usage}
+@malloc_zero_fill@ takes one parameters.
+
+\begin{itemize}
+\item
+@addr@: the address of the currently allocated dynamic object.
+\end{itemize}
+@malloc_zero_fill@ returns true if the dynamic object was initially zero filled and return false otherwise. On failure, it returns false.
+
+\subsection{\lstinline{size_t malloc_size( void * addr )}}
+@malloc_size@ returns the allocation size of a currently allocated dynamic object. It allows the programmer in memory management and personal bookkeeping. It helps the programmer in verofying the alignment of a dynamic object especially in a scenerio similar to prudcer-consumer where a producer allocates a dynamic object and the consumer needs to assure that the dynamic object was allocated with the required size. Its current alternate in the other allocators is @malloc_usable_size@. But, @malloc_size@ is different from @malloc_usable_size@ as @malloc_usabe_size@ returns the total data capacity of dynamic object including the extra space at the end of the dynamic object. On the other hand, @malloc_size@ returns the size that was given to the allocator at the allocation of the dynamic object. This size is updated when an object is realloced, resized, or passed through a similar allocator routine.
+\paragraph{Usage}
+@malloc_size@ takes one parameters.
+
+\begin{itemize}
+\item
+@addr@: the address of the currently allocated dynamic object.
+\end{itemize}
+@malloc_size@ returns the allocation size of the given dynamic object. On failure, it return zero.
+
+\subsection{\lstinline{void * realloc( void * oaddr, size_t nalign, size_t size )}}
+This @realloc@ is an extension of the default @realloc@ (FIX ME: cite default @realloc@). In addition to reallocating an old object and preserving the data in old object, it can also realign the old object to a new alignment requirement.
+\paragraph{Usage}
+This @realloc@ takes three parameters. It takes an additional parameter of nalign as compared to the default @realloc@.
+
+\begin{itemize}
+\item
+@oaddr@: the address of the old object that needs to be reallocated.
+\item
+@nalign@: the new alignment to which the old object needs to be realigned.
+\item
+@size@: the new size requirement of the to which the old object needs to be resized.
+\end{itemize}
+It returns an object with the size and alignment given in the parameters that preserves the data in the old object. On failure, it returns a @NULL@ pointer.
+
+\subsection{\CFA Malloc Interface}
+We added some routines to the malloc interface of \CFA. These routines can only be used in \CFA and not in our standalone uHeap allocator as these routines use some features that are only provided by \CFA and not by C. It makes the allocator even more usable to the programmers.
+\CFA provides the liberty to know the returned type of a call to the allocator. So, mainly in these added routines, we removed the object size parameter from the routine as allocator can calculate the size of the object from the returned type.
+
+\subsection{\lstinline{T * malloc( void )}}
 This malloc is a simplified polymorphic form of defualt malloc (FIX ME: cite malloc). It does not take any parameter as compared to default malloc that takes one parameter.
 \paragraph{Usage}
 This malloc takes no parameters.
-It returns a dynamic object of the size of type T. On failure, it return NULL pointer.
-
-\subsubsection T * aalloc( size\_t dim )
+It returns a dynamic object of the size of type @T@. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * aalloc( size_t dim )}}
 This aalloc is a simplified polymorphic form of above aalloc (FIX ME: cite aalloc). It takes one parameter as compared to the above aalloc that takes two parameters.
 \paragraph{Usage}
@@ -254,9 +318,9 @@
 \begin{itemize}
 \item
-dim: required number of objects in the array.
-\end{itemize}
-It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. On failure, it return NULL pointer.
-
-\subsubsection T * calloc( size\_t dim )
+@dim@: required number of objects in the array.
+\end{itemize}
+It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type @T@. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * calloc( size_t dim )}}
 This calloc is a simplified polymorphic form of defualt calloc (FIX ME: cite calloc). It takes one parameter as compared to the default calloc that takes two parameters.
 \paragraph{Usage}
@@ -265,10 +329,10 @@
 \begin{itemize}
 \item
-dim: required number of objects in the array.
-\end{itemize}
-It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. On failure, it return NULL pointer.
-
-\subsubsection T * resize( T * ptr, size\_t size )
-This resize is a simplified polymorphic form of above resize (FIX ME: cite resize with alignment). It takes two parameters as compared to the above resize that takes three parameters. It frees the programmer from explicitly mentioning the alignment of the allocation as CFA provides gives allocator the liberty to get the alignment of the returned type.
+@dim@: required number of objects in the array.
+\end{itemize}
+It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type @T@. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * resize( T * ptr, size_t size )}}
+This resize is a simplified polymorphic form of above resize (FIX ME: cite resize with alignment). It takes two parameters as compared to the above resize that takes three parameters. It frees the programmer from explicitly mentioning the alignment of the allocation as \CFA provides gives allocator the liberty to get the alignment of the returned type.
 \paragraph{Usage}
 This resize takes two parameters.
@@ -276,24 +340,24 @@
 \begin{itemize}
 \item
-ptr: address of the old object.
-\item
-size: the required size of the new object.
-\end{itemize}
-It returns a dynamic object of the size given in paramters. The returned object is aligned to the alignemtn of type T. On failure, it return NULL pointer.
-
-\subsubsection T * realloc( T * ptr, size\_t size )
-This realloc is a simplified polymorphic form of defualt realloc (FIX ME: cite realloc with align). It takes two parameters as compared to the above realloc that takes three parameters. It frees the programmer from explicitly mentioning the alignment of the allocation as CFA provides gives allocator the liberty to get the alignment of the returned type.
-\paragraph{Usage}
-This realloc takes two parameters.
-
-\begin{itemize}
-\item
-ptr: address of the old object.
-\item
-size: the required size of the new object.
-\end{itemize}
-It returns a dynamic object of the size given in paramters that preserves the data in the given object. The returned object is aligned to the alignemtn of type T. On failure, it return NULL pointer.
-
-\subsubsection T * memalign( size\_t align )
+@ptr@: address of the old object.
+\item
+@size@: the required size of the new object.
+\end{itemize}
+It returns a dynamic object of the size given in paramters. The returned object is aligned to the alignemtn of type @T@. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * realloc( T * ptr, size_t size )}}
+This @realloc@ is a simplified polymorphic form of defualt @realloc@ (FIX ME: cite @realloc@ with align). It takes two parameters as compared to the above @realloc@ that takes three parameters. It frees the programmer from explicitly mentioning the alignment of the allocation as \CFA provides gives allocator the liberty to get the alignment of the returned type.
+\paragraph{Usage}
+This @realloc@ takes two parameters.
+
+\begin{itemize}
+\item
+@ptr@: address of the old object.
+\item
+@size@: the required size of the new object.
+\end{itemize}
+It returns a dynamic object of the size given in paramters that preserves the data in the given object. The returned object is aligned to the alignemtn of type @T@. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * memalign( size_t align )}}
 This memalign is a simplified polymorphic form of defualt memalign (FIX ME: cite memalign). It takes one parameters as compared to the default memalign that takes two parameters.
 \paragraph{Usage}
@@ -302,9 +366,9 @@
 \begin{itemize}
 \item
-align: the required alignment of the dynamic object.
-\end{itemize}
-It returns a dynamic object of the size of type T that is aligned to given parameter align. On failure, it return NULL pointer.
-
-\subsubsection T * amemalign( size\_t align, size\_t dim )
+@align@: the required alignment of the dynamic object.
+\end{itemize}
+It returns a dynamic object of the size of type @T@ that is aligned to given parameter align. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * amemalign( size_t align, size_t dim )}}
 This amemalign is a simplified polymorphic form of above amemalign (FIX ME: cite amemalign). It takes two parameter as compared to the above amemalign that takes three parameters.
 \paragraph{Usage}
@@ -313,11 +377,11 @@
 \begin{itemize}
 \item
-align: required alignment of the dynamic array.
-\item
-dim: required number of objects in the array.
-\end{itemize}
-It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. The returned object is aligned to the given parameter align. On failure, it return NULL pointer.
-
-\subsubsection T * cmemalign( size\_t align, size\_t dim  )
+@align@: required alignment of the dynamic array.
+\item
+@dim@: required number of objects in the array.
+\end{itemize}
+It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type @T@. The returned object is aligned to the given parameter align. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * cmemalign( size_t align, size_t dim  )}}
 This cmemalign is a simplified polymorphic form of above cmemalign (FIX ME: cite cmemalign). It takes two parameter as compared to the above cmemalign that takes three parameters.
 \paragraph{Usage}
@@ -326,49 +390,48 @@
 \begin{itemize}
 \item
-align: required alignment of the dynamic array.
-\item
-dim: required number of objects in the array.
-\end{itemize}
-It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type T. The returned object is aligned to the given parameter align and is zero filled. On failure, it return NULL pointer.
-
-\subsubsection T * aligned\_alloc( size\_t align )
-This aligned\_alloc is a simplified polymorphic form of defualt aligned\_alloc (FIX ME: cite aligned\_alloc). It takes one parameter as compared to the default aligned\_alloc that takes two parameters.
-\paragraph{Usage}
-This aligned\_alloc takes one parameter.
-
-\begin{itemize}
-\item
-align: required alignment of the dynamic object.
-\end{itemize}
-It returns a dynamic object of the size of type T that is aligned to the given parameter. On failure, it return NULL pointer.
-
-\subsubsection int posix\_memalign( T ** ptr, size\_t align )
-This posix\_memalign is a simplified polymorphic form of defualt posix\_memalign (FIX ME: cite posix\_memalign). It takes two parameters as compared to the default posix\_memalign that takes three parameters.
-\paragraph{Usage}
-This posix\_memalign takes two parameter.
-
-\begin{itemize}
-\item
-ptr: variable address to store the address of the allocated object.
-\item
-align: required alignment of the dynamic object.
-\end{itemize}
-
-It stores address of the dynamic object of the size of type T in given parameter ptr. This object is aligned to the given parameter. On failure, it return NULL pointer.
-
-\subsubsection T * valloc( void )
-This valloc is a simplified polymorphic form of defualt valloc (FIX ME: cite valloc). It takes no parameters as compared to the default valloc that takes one parameter.
-\paragraph{Usage}
-valloc takes no parameters.
-It returns a dynamic object of the size of type T that is aligned to the page size. On failure, it return NULL pointer.
-
-\subsubsection T * pvalloc( void )
-This pcvalloc is a simplified polymorphic form of defualt pcvalloc (FIX ME: cite pcvalloc). It takes no parameters as compared to the default pcvalloc that takes one parameter.
-\paragraph{Usage}
-pvalloc takes no parameters.
-It returns a dynamic object of the size that is calcutaed by rouding the size of type T. The returned object is also aligned to the page size. On failure, it return NULL pointer.
-
-\subsection Alloc Interface
-In addition to improve allocator interface both for CFA and our standalone allocator uHeapLmmm in C. We also added a new alloc interface in CFA that increases usability of dynamic memory allocation.
+@align@: required alignment of the dynamic array.
+\item
+@dim@: required number of objects in the array.
+\end{itemize}
+It returns a dynamic object that has the capacity to contain dim number of objects, each of the size of type @T@. The returned object is aligned to the given parameter align and is zero filled. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * aligned_alloc( size_t align )}}
+This @aligned_alloc@ is a simplified polymorphic form of defualt @aligned_alloc@ (FIX ME: cite @aligned_alloc@). It takes one parameter as compared to the default @aligned_alloc@ that takes two parameters.
+\paragraph{Usage}
+This @aligned_alloc@ takes one parameter.
+
+\begin{itemize}
+\item
+@align@: required alignment of the dynamic object.
+\end{itemize}
+It returns a dynamic object of the size of type @T@ that is aligned to the given parameter. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{int posix_memalign( T ** ptr, size_t align )}}
+This @posix_memalign@ is a simplified polymorphic form of defualt @posix_memalign@ (FIX ME: cite @posix_memalign@). It takes two parameters as compared to the default @posix_memalign@ that takes three parameters.
+\paragraph{Usage}
+This @posix_memalign@ takes two parameter.
+
+\begin{itemize}
+\item
+@ptr@: variable address to store the address of the allocated object.
+\item
+@align@: required alignment of the dynamic object.
+\end{itemize}
+
+It stores address of the dynamic object of the size of type @T@ in given parameter ptr. This object is aligned to the given parameter. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * valloc( void )}}
+This @valloc@ is a simplified polymorphic form of defualt @valloc@ (FIX ME: cite @valloc@). It takes no parameters as compared to the default @valloc@ that takes one parameter.
+\paragraph{Usage}
+@valloc@ takes no parameters.
+It returns a dynamic object of the size of type @T@ that is aligned to the page size. On failure, it returns a @NULL@ pointer.
+
+\subsection{\lstinline{T * pvalloc( void )}}
+\paragraph{Usage}
+@pvalloc@ takes no parameters.
+It returns a dynamic object of the size that is calcutaed by rouding the size of type @T@. The returned object is also aligned to the page size. On failure, it returns a @NULL@ pointer.
+
+\subsection{Alloc Interface}
+In addition to improve allocator interface both for \CFA and our standalone allocator uHeap in C. We also added a new alloc interface in \CFA that increases usability of dynamic memory allocation.
 This interface helps programmers in three major ways.
 
@@ -379,52 +442,52 @@
 Parametre Positions: alloc interface frees programmers from remembering parameter postions in call to routines.
 \item
-Object Size: alloc interface does not require programmer to mention the object size as CFA allows allocator to determince the object size from returned type of alloc call.
-\end{itemize}
-
-Alloc interface uses polymorphism, backtick routines (FIX ME: cite backtick) and ttype parameters of CFA (FIX ME: cite ttype) to provide a very simple dynamic memory allocation interface to the programmers. The new interfece has just one routine name alloc that can be used to perform a wide range of dynamic allocations. The parameters use backtick functions to provide a similar-to named parameters feature for our alloc interface so that programmers do not have to remember parameter positions in alloc call except the position of dimension (dim) parameter.
-
-\subsubsection{Routine: T * alloc( ... )}
-Call to alloc wihout any parameter returns one object of size of type T allocated dynamically.
+Object Size: alloc interface does not require programmer to mention the object size as \CFA allows allocator to determince the object size from returned type of alloc call.
+\end{itemize}
+
+Alloc interface uses polymorphism, backtick routines (FIX ME: cite backtick) and ttype parameters of \CFA (FIX ME: cite ttype) to provide a very simple dynamic memory allocation interface to the programmers. The new interfece has just one routine name alloc that can be used to perform a wide range of dynamic allocations. The parameters use backtick functions to provide a similar-to named parameters feature for our alloc interface so that programmers do not have to remember parameter positions in alloc call except the position of dimension (dim) parameter.
+
+\subsection{Routine: \lstinline{T * alloc( ... )}}
+Call to alloc wihout any parameter returns one object of size of type @T@ allocated dynamically.
 Only the dimension (dim) parameter for array allocation has the fixed position in the alloc routine. If programmer wants to allocate an array of objects that the required number of members in the array has to be given as the first parameter to the alloc routine.
-alocc routine accepts six kinds of arguments. Using different combinations of tha parameters, different kind of allocations can be performed. Any combincation of parameters can be used together except `realloc and `resize that should not be used simultanously in one call to routine as it creates ambiguity about whether to reallocate or resize a currently allocated dynamic object. If both `resize and `realloc are used in a call to alloc then the latter one will take effect or unexpected resulted might be produced.
+alocc routine accepts six kinds of arguments. Using different combinations of tha parameters, different kind of allocations can be performed. Any combincation of parameters can be used together except @`realloc@ and @`resize@ that should not be used simultanously in one call to routine as it creates ambiguity about whether to reallocate or resize a currently allocated dynamic object. If both @`resize@ and @`realloc@ are used in a call to alloc then the latter one will take effect or unexpected resulted might be produced.
 
 \paragraph{Dim}
-This is the only parameter in the alloc routine that has a fixed-position and it is also the only parameter that does not use a backtick function. It has to be passed at the first position to alloc call in-case of an array allocation of objects of type T.
-It represents the required number of members in the array allocation as in CFA's aalloc (FIX ME: cite aalloc).
-This parameter should be of type size\_t.
-
-Example: int a = alloc( 5 )
+This is the only parameter in the alloc routine that has a fixed-position and it is also the only parameter that does not use a backtick function. It has to be passed at the first position to alloc call in-case of an array allocation of objects of type @T@.
+It represents the required number of members in the array allocation as in \CFA's aalloc (FIX ME: cite aalloc).
+This parameter should be of type @size_t@.
+
+Example: @int a = alloc( 5 )@
 This call will return a dynamic array of five integers.
 
 \paragraph{Align}
-This parameter is position-free and uses a backtick routine align (`align). The parameter passed with `align should be of type size\_t. If the alignment parameter is not a power of two or is less than the default alignment of the allocator (that can be found out using routine libAlign in CFA) then the passed alignment parameter will be rejected and the default alignment will be used.
-
-Example: int b = alloc( 5 , 64`align )
+This parameter is position-free and uses a backtick routine align (@`align@). The parameter passed with @`align@ should be of type @size_t@. If the alignment parameter is not a power of two or is less than the default alignment of the allocator (that can be found out using routine libAlign in \CFA) then the passed alignment parameter will be rejected and the default alignment will be used.
+
+Example: @int b = alloc( 5 , 64`align )@
 This call will return a dynamic array of five integers. It will align the allocated object to 64.
 
 \paragraph{Fill}
-This parameter is position-free and uses a backtick routine fill (`fill). In case of realloc, only the extra space after copying the data in the old object will be filled with given parameter.
+This parameter is position-free and uses a backtick routine fill (@`fill@). In case of @realloc@, only the extra space after copying the data in the old object will be filled with given parameter.
 Three types of parameters can be passed using `fill.
 
 \begin{itemize}
 \item
-char: A char can be passed with `fill to fill the whole dynamic allocation with the given char recursively till the end of required allocation.
-\item
-Object of returned type: An object of type of returned type can be passed with `fill to fill the whole dynamic allocation with the given object recursively till the end of required allocation.
-\item
-Dynamic object of returned type: A dynamic object of type of returned type can be passed with `fill to fill the dynamic allocation with the given dynamic object. In this case, the allocated memory is not filled recursively till the end of allocation. The filling happen untill the end object passed to `fill or the end of requested allocation reaches.
-\end{itemize}
-
-Example: int b = alloc( 5 , 'a'`fill )
+@char@: A char can be passed with @`fill@ to fill the whole dynamic allocation with the given char recursively till the end of required allocation.
+\item
+Object of returned type: An object of type of returned type can be passed with @`fill@ to fill the whole dynamic allocation with the given object recursively till the end of required allocation.
+\item
+Dynamic object of returned type: A dynamic object of type of returned type can be passed with @`fill@ to fill the dynamic allocation with the given dynamic object. In this case, the allocated memory is not filled recursively till the end of allocation. The filling happen untill the end object passed to @`fill@ or the end of requested allocation reaches.
+\end{itemize}
+
+Example: @int b = alloc( 5 , 'a'`fill )@
 This call will return a dynamic array of five integers. It will fill the allocated object with character 'a' recursively till the end of requested allocation size.
 
-Example: int b = alloc( 5 , 4`fill )
+Example: @int b = alloc( 5 , 4`fill )@
 This call will return a dynamic array of five integers. It will fill the allocated object with integer 4 recursively till the end of requested allocation size.
 
-Example: int b = alloc( 5 , a`fill ) where a is a pointer of int type
+Example: @int b = alloc( 5 , a`fill )@ where @a@ is a pointer of int type
 This call will return a dynamic array of five integers. It will copy data in a to the returned object non-recursively untill end of a or the newly allocated object is reached.
 
 \paragraph{Resize}
-This parameter is position-free and uses a backtick routine resize (`resize). It represents the old dynamic object (oaddr) that the programmer wants to
+This parameter is position-free and uses a backtick routine resize (@`resize@). It represents the old dynamic object (oaddr) that the programmer wants to
 \begin{itemize}
 \item
@@ -435,17 +498,17 @@
 fill with something.
 \end{itemize}
-The data in old dynamic object will not be preserved in the new object. The type of object passed to `resize and the returned type of alloc call can be different.
-
-Example: int b = alloc( 5 , a`resize )
+The data in old dynamic object will not be preserved in the new object. The type of object passed to @`resize@ and the returned type of alloc call can be different.
+
+Example: @int b = alloc( 5 , a`resize )@
 This call will resize object a to a dynamic array that can contain 5 integers.
 
-Example: int b = alloc( 5 , a`resize , 32`align )
+Example: @int b = alloc( 5 , a`resize , 32`align )@
 This call will resize object a to a dynamic array that can contain 5 integers. The returned object will also be aligned to 32.
 
-Example: int b = alloc( 5 , a`resize , 32`align , 2`fill)
+Example: @int b = alloc( 5 , a`resize , 32`align , 2`fill )@
 This call will resize object a to a dynamic array that can contain 5 integers. The returned object will also be aligned to 32 and will be filled with 2.
 
 \paragraph{Realloc}
-This parameter is position-free and uses a backtick routine realloc (`realloc). It represents the old dynamic object (oaddr) that the programmer wants to
+This parameter is position-free and uses a backtick routine @realloc@ (@`realloc@). It represents the old dynamic object (oaddr) that the programmer wants to
 \begin{itemize}
 \item
@@ -456,12 +519,12 @@
 fill with something.
 \end{itemize}
-The data in old dynamic object will be preserved in the new object. The type of object passed to `realloc and the returned type of alloc call cannot be different.
-
-Example: int b = alloc( 5 , a`realloc )
+The data in old dynamic object will be preserved in the new object. The type of object passed to @`realloc@ and the returned type of alloc call cannot be different.
+
+Example: @int b = alloc( 5 , a`realloc )@
 This call will realloc object a to a dynamic array that can contain 5 integers.
 
-Example: int b = alloc( 5 , a`realloc , 32`align )
+Example: @int b = alloc( 5 , a`realloc , 32`align )@
 This call will realloc object a to a dynamic array that can contain 5 integers. The returned object will also be aligned to 32.
 
-Example: int b = alloc( 5 , a`realloc , 32`align , 2`fill)
+Example: @int b = alloc( 5 , a`realloc , 32`align , 2`fill )@
 This call will resize object a to a dynamic array that can contain 5 integers. The returned object will also be aligned to 32. The extra space after copying data of a to the returned object will be filled with 2.
Index: doc/theses/mubeen_zulfiqar_MMath/background.tex
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/background.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/mubeen_zulfiqar_MMath/background.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,7 +1,4 @@
-\chapter{Background}
-
-\noindent
+\begin{comment}
 ====================
-
 Writing Points:
 \begin{itemize}
@@ -19,46 +16,743 @@
 Features and limitations.
 \end{itemize}
-
-\noindent
-====================
-
-\section{Background}
-
-% FIXME: cite wasik
-\cite{wasik.thesis}
-
-\subsection{Memory Allocation}
-With dynamic allocation being an important feature of C, there are many standalone memory allocators that have been designed for different purposes. For this thesis, we chose 7 of the most popular and widely used memory allocators.
-
-\paragraph{dlmalloc}
-dlmalloc (FIX ME: cite allocator) is a thread-safe allocator that is single threaded and single heap. dlmalloc maintains free-lists of different sizes to store freed dynamic memory. (FIX ME: cite wasik)
-
-\paragraph{hoard}
-Hoard (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and using a heap layer framework. It has per-thred heaps that have thread-local free-lists, and a gloabl shared heap. (FIX ME: cite wasik)
-
-\paragraph{jemalloc}
-jemalloc (FIX ME: cite allocator) is a thread-safe allocator that uses multiple arenas. Each thread is assigned an arena. Each arena has chunks that contain contagious memory regions of same size. An arena has multiple chunks that contain regions of multiple sizes.
-
-\paragraph{ptmalloc}
-ptmalloc (FIX ME: cite allocator) is a modification of dlmalloc. It is a thread-safe multi-threaded memory allocator that uses multiple heaps. ptmalloc heap has similar design to dlmalloc's heap.
-
-\paragraph{rpmalloc}
-rpmalloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses per-thread heap. Each heap has multiple size-classes and each size-calss contains memory regions of the relevant size.
-
-\paragraph{tbb malloc}
-tbb malloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses private heap for each thread. Each private-heap has multiple bins of different sizes. Each bin contains free regions of the same size.
-
-\paragraph{tc malloc}
-tcmalloc (FIX ME: cite allocator) is a thread-safe allocator. It uses per-thread cache to store free objects that prevents contention on shared resources in multi-threaded application. A central free-list is used to refill per-thread cache when it gets empty.
-
-\subsection{Benchmarks}
-There are multiple benchmarks that are built individually and evaluate different aspects of a memory allocator. But, there is not standard set of benchamrks that can be used to evaluate multiple aspects of memory allocators.
-
-\paragraph{threadtest}
-(FIX ME: cite benchmark and hoard) Each thread repeatedly allocates and then deallocates 100,000 objects. Runtime of the benchmark evaluates its efficiency.
-
-\paragraph{shbench}
-(FIX ME: cite benchmark and hoard) Each thread allocates and randomly frees a number of random-sized objects. It is a stress test that also uses runtime to determine efficiency of the allocator.
-
-\paragraph{larson}
-(FIX ME: cite benchmark and hoard) Larson simulates a server environment. Multiple threads are created where each thread allocator and free a number of objects within a size range. Some objects are passed from threads to the child threads to free. It caluculates memory operations per second as an indicator of memory allocator's performance.
+\end{comment}
+
+\chapter[Background]{Background\footnote{Part of this chapter draws from similar background work in~\cite{wasik.thesis} with many updates.}}
+
+
+A program dynamically allocates and deallocates the storage for a variable, referred to as an \newterm{object}, through calls such as @malloc@ and @free@ in C, and @new@ and @delete@ in \CC.
+Space for each allocated object comes from the dynamic-allocation zone.
+A \newterm{memory allocator} contains a complex data-structure and code that manages the layout of objects in the dynamic-allocation zone.
+The management goals are to make allocation/deallocation operations as fast as possible while densely packing objects to make efficient use of memory.
+Objects in C/\CC cannot be moved to aid the packing process, only adjacent free storage can be \newterm{coalesced} into larger free areas.
+The allocator grows or shrinks the dynamic-allocation zone to obtain storage for objects and reduce memory usage via operating-system calls, such as @mmap@ or @sbrk@ in UNIX.
+
+
+\section{Allocator Components}
+\label{s:AllocatorComponents}
+
+\VRef[Figure]{f:AllocatorComponents} shows the two important data components for a memory allocator, management and storage, collectively called the \newterm{heap}.
+The \newterm{management data} is a data structure located at a known memory address and contains all information necessary to manage the storage data.
+The management data starts with fixed-sized information in the static-data memory that flows into the dynamic-allocation memory.
+The \newterm{storage data} is composed of allocated and freed objects, and \newterm{reserved memory}.
+Allocated objects (white) are variable sized, and allocated and maintained by the program;
+\ie only the program knows the location of allocated storage, not the memory allocator.
+\begin{figure}[h]
+\centering
+\input{AllocatorComponents}
+\caption{Allocator Components (Heap)}
+\label{f:AllocatorComponents}
+\end{figure}
+Freed objects (light grey) are memory deallocated by the program, which are linked into one or more lists facilitating easy location for new allocations.
+Often the free list is chained internally so it does not consume additional storage, \ie the link fields are placed at known locations in the unused memory blocks.
+Reserved memory (dark grey) is one or more blocks of memory obtained from the operating system but not yet allocated to the program;
+if there are multiple reserved blocks, they are also chained together, usually internally.
+
+Allocated and freed objects typically have additional management data embedded within them.
+\VRef[Figure]{f:AllocatedObject} shows an allocated object with a header, trailer, and alignment padding and spacing around the object.
+The header contains information about the object, \eg size, type, etc.
+The trailer may be used to simplify an allocation implementation, \eg coalescing, and/or for security purposes to mark the end of an object.
+An object may be preceded by padding to ensure proper alignment.
+Some algorithms quantize allocation requests into distinct sizes resulting in additional spacing after objects less than the quantized value.
+When padding and spacing are necessary, neither can be used to satisfy a future allocation request while the current allocation exists.
+A free object also contains management data, \eg size, chaining, etc.
+The amount of management data for a free node defines the minimum allocation size, \eg if 16 bytes are needed for a free-list node, any allocation request less than 16 bytes must be rounded up, otherwise the free list cannot use internal chaining.
+The information in an allocated or freed object is overwritten when it transitions from allocated to freed and vice-versa by new management information and possibly data.
+
+\begin{figure}
+\centering
+\input{AllocatedObject}
+\caption{Allocated Object}
+\label{f:AllocatedObject}
+\end{figure}
+
+
+\section{Single-Threaded Memory-Allocator}
+\label{s:SingleThreadedMemoryAllocator}
+
+A single-threaded memory-allocator does not run any threads itself, but is used by a single-threaded program.
+Because the memory allocator is only executed by a single thread, concurrency issues do not exist.
+The primary issues in designing a single-threaded memory-allocator are fragmentation and locality.
+
+
+\subsection{Fragmentation}
+\label{s:Fragmentation}
+
+Fragmentation is memory requested from the operating system but not used by the program;
+hence, allocated objects are not fragmentation.
+\VRef[Figure]{f:InternalExternalFragmentation}) shows fragmentation is divided into two forms: internal or external.
+
+\begin{figure}
+\centering
+\input{IntExtFragmentation}
+\caption{Internal and External Fragmentation}
+\label{f:InternalExternalFragmentation}
+\end{figure}
+
+\newterm{Internal fragmentation} is memory space that is allocated to the program, but is not intended to be accessed by the program, such as headers, trailers, padding, and spacing around an allocated object.
+This memory is typically used by the allocator for management purposes or required by the architecture for correctness, \eg alignment.
+Internal fragmentation is problematic when management space is a significant proportion of an allocated object.
+For example, if internal fragmentation is as large as the object being managed, then the memory usage for that object is doubled.
+An allocator should strive to keep internal management information to a minimum.
+
+\newterm{External fragmentation} is all memory space reserved from the operating system but not allocated to the program~\cite{Wilson95,Lim98,Siebert00}, which includes freed objects, all external management data, and reserved memory.
+This memory is problematic in two ways: heap blowup and highly fragmented memory.
+\newterm{Heap blowup} occurs when memory freed by the program is not reused for future allocations leading to potentially unbounded external fragmentation growth~\cite{Berger00}.
+Heap blowup can occur due to allocator policies that are too restrictive in reusing freed memory and/or no coalescing of free storage.
+Memory can become \newterm{highly fragmented} after multiple allocations and deallocations of objects.
+\VRef[Figure]{f:MemoryFragmentation} shows an example of how a small block of memory fragments as objects are allocated and deallocated over time.
+Blocks of free memory become smaller and non-contiguous making them less useful in serving allocation requests.
+Memory is highly fragmented when the sizes of most free blocks are unusable.
+For example, \VRef[Figure]{f:Contiguous} and \VRef[Figure]{f:HighlyFragmented} have the same quantity of external fragmentation, but \VRef[Figure]{f:HighlyFragmented} is highly fragmented.
+If there is a request to allocate a large object, \VRef[Figure]{f:Contiguous} is more likely to be able to satisfy it with existing free memory, while \VRef[Figure]{f:HighlyFragmented} likely has to request more memory from the operating system.
+
+\begin{figure}
+\centering
+\input{MemoryFragmentation}
+\caption{Memory Fragmentation}
+\label{f:MemoryFragmentation}
+\vspace{10pt}
+\subfigure[Contiguous]{
+	\input{ContigFragmentation}
+	\label{f:Contiguous}
+} % subfigure
+	\subfigure[Highly Fragmented]{
+	\input{NonContigFragmentation}
+\label{f:HighlyFragmented}
+} % subfigure
+\caption{Fragmentation Quality}
+\label{f:FragmentationQuality}
+\end{figure}
+
+For a single-threaded memory allocator, three basic approaches for controlling fragmentation have been identified~\cite{Johnstone99}.
+The first approach is a \newterm{sequential-fit algorithm} with one list of free objects that is searched for a block large enough to fit a requested object size.
+Different search policies determine the free object selected, \eg the first free object large enough or closest to the requested size.
+Any storage larger than the request can become spacing after the object or be split into a smaller free object.
+The cost of the search depends on the shape and quality of the free list, \eg a linear versus a binary-tree free-list, a sorted versus unsorted free-list.
+
+The second approach is a \newterm{segregated} or \newterm{binning algorithm} with a set of lists for different sized freed objects.
+When an object is allocated, the requested size is rounded up to the nearest bin-size, possibly with spacing after the object.
+A binning algorithm is fast at finding free memory of the appropriate size and allocating it, since the first free object on the free list is used.
+The fewer bin-sizes, the fewer lists need to be searched and maintained;
+however, the bin sizes are less likely to closely fit the requested object size, leading to more internal fragmentation.
+The more bin-sizes, the longer the search and the less likely free objects are to be reused, leading to more external fragmentation and potentially heap blowup.
+A variation of the binning algorithm allows objects to be allocated to the requested size, but when an object is freed, it is placed on the free list of the next smallest or equal bin-size.
+For example, with bin sizes of 8 and 16 bytes, a request for 12 bytes allocates only 12 bytes, but when the object is freed, it is placed on the 8-byte bin-list.
+For subsequent requests, the bin free-lists contain objects of different sizes, ranging from one bin-size to the next (8-16 in this example), and a sequential-fit algorithm may be used to find an object large enough for the requested size on the associated bin list.
+
+The third approach is \newterm{splitting} and \newterm{coalescing algorithms}.
+When an object is allocated, if there are no free objects of the requested size, a larger free object may be split into two smaller objects to satisfy the allocation request without obtaining more memory from the operating system.
+For example, in the buddy system, a block of free memory is split into two equal chunks, one of those chunks is again split into two equal chunks, and so on until a block just large enough to fit the requested object is created.
+When an object is deallocated it is coalesced with the objects immediately before and after it in memory, if they are free, turning them into one larger object.
+Coalescing can be done eagerly at each deallocation or lazily when an allocation cannot be fulfilled.
+In all cases, coalescing increases allocation latency, hence some allocations can cause unbounded delays during coalescing.
+While coalescing does not reduce external fragmentation, the coalesced blocks improve fragmentation quality so future allocations are less likely to cause heap blowup.
+Splitting and coalescing can be used with other algorithms to avoid highly fragmented memory.
+
+
+\subsection{Locality}
+\label{s:Locality}
+
+The principle of locality recognizes that programs tend to reference a small set of data, called a working set, for a certain period of time, where a working set is composed of temporal and spatial accesses~\cite{Denning05}.
+Temporal clustering implies a group of objects are accessed repeatedly within a short time period, while spatial clustering implies a group of objects physically close together (nearby addresses) are accessed repeatedly within a short time period.
+Temporal locality commonly occurs during an iterative computation with a fix set of disjoint variables, while spatial locality commonly occurs when traversing an array.
+
+Hardware takes advantage of temporal and spatial locality through multiple levels of caching (\ie memory hierarchy).
+When an object is accessed, the memory physically located around the object is also cached with the expectation that the current and nearby objects will be referenced within a short period of time.
+For example, entire cache lines are transferred between memory and cache and entire virtual-memory pages are transferred between disk and memory.
+A program exhibiting good locality has better performance due to fewer cache misses and page faults\footnote{With the advent of large RAM memory, paging is becoming less of an issue in modern programming.}.
+
+Temporal locality is largely controlled by how a program accesses its variables~\cite{Feng05}.
+Nevertheless, a memory allocator can have some indirect influence on temporal locality and largely dictates spatial locality.
+For temporal locality, an allocator can return storage for new allocations that was just freed as these memory locations are still \emph{warm} in the memory hierarchy.
+For spatial locality, an allocator can place objects used together close together in memory, so the working set of the program fits into the fewest possible cache lines and pages.
+However, usage patterns are different for every program as is the underlying hardware memory architecture;
+hence, no general-purpose memory-allocator can provide ideal locality for every program on every computer.
+
+There are a number of ways a memory allocator can degrade locality by increasing the working set.
+For example, a memory allocator may access multiple free objects before finding one to satisfy an allocation request (\eg sequential-fit algorithm).
+If there are a (large) number of objects accessed in very different areas of memory, the allocator may perturb the program's memory hierarchy causing multiple cache or page misses~\cite{Grunwald93}.
+Another way locality can be degraded is by spatially separating related data.
+For example, in a binning allocator, objects of different sizes are allocated from different bins that may be located in different pages of memory.
+
+
+\section{Multi-Threaded Memory-Allocator}
+\label{s:MultiThreadedMemoryAllocator}
+
+A multi-threaded memory-allocator does not run any threads itself, but is used by a multi-threaded program.
+In addition to single-threaded design issues of locality and fragmentation, a multi-threaded allocator may be simultaneously accessed by multiple threads, and hence, must deal with concurrency issues such as mutual exclusion, false sharing, and additional forms of heap blowup.
+
+
+\subsection{Mutual Exclusion}
+\label{s:MutualExclusion}
+
+\newterm{Mutual exclusion} provides sequential access to the shared management data of the heap.
+There are two performance issues for mutual exclusion.
+First is the overhead necessary to perform (at least) a hardware atomic operation every time a shared resource is accessed.
+Second is when multiple threads contend for a shared resource simultaneously, and hence, some threads must wait until the resource is released.
+Contention can be reduced in a number of ways:
+using multiple fine-grained locks versus a single lock, spreading the contention across a number of locks;
+using trylock and generating new storage if the lock is busy, yielding a classic space versus time tradeoff;
+using one of the many lock-free approaches for reducing contention on basic data-structure operations~\cite{Oyama99}.
+However, all of these approaches have degenerate cases where contention occurs.
+
+
+\subsection{False Sharing}
+\label{s:FalseSharing}
+
+False sharing is a dynamic phenomenon leading to cache thrashing.
+When two or more threads on separate CPUs simultaneously change different objects sharing a cache line, the change invalidates the other thread's associated cache, even though these threads may be uninterested in the other modified object.
+False sharing can occur in three different ways: program induced, allocator-induced active, and allocator-induced passive;
+a memory allocator can only affect the latter two.
+
+\paragraph{\newterm{Program-induced false-sharing}} occurs when one thread passes an object sharing a cache line to another thread, and both threads modify the respective objects.
+\VRef[Figure]{f:ProgramInducedFalseSharing} shows when Task$_1$ passes Object$_2$ to Task$_2$, a false-sharing situation forms when Task$_1$ modifies Object$_1$ and Task$_2$ modifies Object$_2$.
+Changes to Object$_1$ invalidate CPU$_2$'s cache line, and changes to Object$_2$ invalidate CPU$_1$'s cache line.
+
+\begin{figure}
+\centering
+\subfigure[Program-Induced False-Sharing]{
+	\input{ProgramFalseSharing}
+	\label{f:ProgramInducedFalseSharing}
+} \\
+\vspace{5pt}
+\subfigure[Allocator-Induced Active False-Sharing]{
+	\input{AllocInducedActiveFalseSharing}
+	\label{f:AllocatorInducedActiveFalseSharing}
+} \\
+\vspace{5pt}
+\subfigure[Allocator-Induced Passive False-Sharing]{
+	\input{AllocInducedPassiveFalseSharing}
+	\label{f:AllocatorInducedPassiveFalseSharing}
+} % subfigure
+\caption{False Sharing}
+\label{f:FalseSharing}
+\end{figure}
+
+\paragraph{\newterm{Allocator-induced active false-sharing}} occurs when objects are allocated within the same cache line but to different threads.
+For example, in \VRef[Figure]{f:AllocatorInducedActiveFalseSharing}, each task allocates an object and loads a cache-line of memory into its associated cache.
+Again, changes to Object$_1$ invalidate CPU$_2$'s cache line, and changes to Object$_2$ invalidate CPU$_1$'s cache line.
+
+\paragraph{\newterm{Allocator-induced passive false-sharing}} is another form of allocator-induced false-sharing caused by program-induced false-sharing.
+When an object in a program-induced false-sharing situation is deallocated, a future allocation of that object may cause passive false-sharing.
+For example, in \VRef[Figure]{f:AllocatorInducedPassiveFalseSharing}, Task$_1$ passes Object$_2$ to Task$_2$, and Task$_2$ subsequently deallocates Object$_2$.
+Allocator-induced passive false-sharing occurs when Object$_2$ is reallocated to Task$_2$ while Task$_1$ is still using Object$_1$.
+
+
+\subsection{Heap Blowup}
+\label{s:HeapBlowup}
+
+In a multi-threaded program, heap blowup can occur when memory freed by one thread is inaccessible to other threads due to the allocation strategy.
+Specific examples are presented in later sections.
+
+
+\section{Multi-Threaded Memory-Allocator Features}
+\label{s:MultiThreadedMemoryAllocatorFeatures}
+
+The following features are used in the construction of multi-threaded memory-allocators:
+\begin{list}{\arabic{enumi}.}{\usecounter{enumi}\topsep=0.5ex\parsep=0pt\itemsep=0pt}
+\item multiple heaps
+\begin{list}{\alph{enumii})}{\usecounter{enumii}\topsep=0.5ex\parsep=0pt\itemsep=0pt}
+\item with or without a global heap
+\item with or without ownership
+\end{list}
+\item object containers
+\begin{list}{\alph{enumii})}{\usecounter{enumii}\topsep=0.5ex\parsep=0pt\itemsep=0pt}
+\item with or without ownership
+\item fixed or variable sized
+\item global or local free-lists
+\end{list}
+\item hybrid private/public heap
+\item allocation buffer
+\item lock-free operations
+\end{list}
+The first feature, multiple heaps, pertains to different kinds of heaps.
+The second feature, object containers, pertains to the organization of objects within the storage area.
+The remaining features apply to different parts of the allocator design or implementation.
+
+
+\section{Multiple Heaps}
+\label{s:MultipleHeaps}
+
+A single-threaded allocator has at most one thread and heap, while a multi-threaded allocator has potentially multiple threads and heaps.
+The multiple threads cause complexity, and multiple heaps are a mechanism for dealing with the complexity.
+The spectrum ranges from multiple threads using a single heap, denoted as T:1 (see \VRef[Figure]{f:SingleHeap}), to multiple threads sharing multiple heaps, denoted as T:H (see \VRef[Figure]{f:SharedHeaps}), to one thread per heap, denoted as 1:1 (see \VRef[Figure]{f:PerThreadHeap}), which is almost back to a single-threaded allocator.
+
+
+\paragraph{T:1 model} where all threads allocate and deallocate objects from one heap.
+Memory is obtained from the freed objects, or reserved memory in the heap, or from the operating system (OS);
+the heap may also return freed memory to the operating system.
+The arrows indicate the direction memory conceptually moves for each kind of operation: allocation moves memory along the path from the heap/operating-system to the user application, while deallocation moves memory along the path from the application back to the heap/operating-system.
+To safely handle concurrency, a single heap uses locking to provide mutual exclusion.
+Whether using a single lock for all heap operations or fine-grained locking for different operations, a single heap may be a significant source of contention for programs with a large amount of memory allocation.
+
+\begin{figure}
+\centering
+\subfigure[T:1]{
+%	\input{SingleHeap.pstex_t}
+	\input{SingleHeap}
+	\label{f:SingleHeap}
+} % subfigure
+\vrule
+\subfigure[T:H]{
+%	\input{MultipleHeaps.pstex_t}
+	\input{SharedHeaps}
+	\label{f:SharedHeaps}
+} % subfigure
+\vrule
+\subfigure[1:1]{
+%	\input{MultipleHeapsGlobal.pstex_t}
+	\input{PerThreadHeap}
+	\label{f:PerThreadHeap}
+} % subfigure
+\caption{Multiple Heaps, Thread:Heap Relationship}
+\end{figure}
+
+
+\paragraph{T:H model} where each thread allocates storage from several heaps depending on certain criteria, with the goal of reducing contention by spreading allocations/deallocations across the heaps.
+The decision on when to create a new heap and which heap a thread allocates from depends on the allocator design.
+The performance goal is to reduce the ratio of heaps to threads.
+In general, locking is required, since more than one thread may concurrently access a heap during its lifetime, but contention is reduced because fewer threads access a specific heap.
+
+For example, multiple heaps are managed in a pool, starting with a single or a fixed number of heaps that increase\-/decrease depending on contention\-/space issues.
+At creation, a thread is associated with a heap from the pool.
+When the thread attempts an allocation and its associated heap is locked (contention), it scans for an unlocked heap in the pool.
+If an unlocked heap is found, the thread changes its association and uses that heap.
+If all heaps are locked, the thread may create a new heap, use it, and then place the new heap into the pool;
+or the thread can block waiting for a heap to become available.
+While the heap-pool approach often minimizes the number of extant heaps, the worse case can result in more heaps than threads;
+\eg if the number of threads is large at startup with many allocations creating a large number of heaps and then the number of threads reduces.
+
+Threads using multiple heaps need to determine the specific heap to access for an allocation/deallocation, \ie association of thread to heap.
+A number of techniques are used to establish this association.
+The simplest approach is for each thread to have a pointer to its associated heap (or to administrative information that points to the heap), and this pointer changes if the association changes.
+For threading systems with thread-local storage, the heap pointer is created using this mechanism;
+otherwise, the heap routines must simulate thread-local storage using approaches like hashing the thread's stack-pointer or thread-id to find its associated heap.
+
+The storage management for multiple heaps is more complex than for a single heap (see \VRef[Figure]{f:AllocatorComponents}).
+\VRef[Figure]{f:MultipleHeapStorage} illustrates the general storage layout for multiple heaps.
+Allocated and free objects are labelled by the thread or heap they are associated with.
+(Links between free objects are removed for simplicity.)
+The management information in the static zone must be able to locate all heaps in the dynamic zone.
+The management information for the heaps must reside in the dynamic-allocation zone if there are a variable number.
+Each heap in the dynamic zone is composed of a list of a free objects and a pointer to its reserved memory.
+An alternative implementation is for all heaps to share one reserved memory, which requires a separate lock for the reserved storage to ensure mutual exclusion when acquiring new memory.
+Because multiple threads can allocate/free/reallocate adjacent storage, all forms of false sharing may occur.
+Other storage-management options are to use @mmap@ to set aside (large) areas of virtual memory for each heap and suballocate each heap's storage within that area.
+
+\begin{figure}
+\centering
+\input{MultipleHeapsStorage}
+\caption{Multiple-Heap Storage}
+\label{f:MultipleHeapStorage}
+\end{figure}
+
+Multiple heaps increase external fragmentation as the ratio of heaps to threads increases, which can lead to heap blowup.
+The external fragmentation experienced by a program with a single heap is now multiplied by the number of heaps, since each heap manages its own free storage and allocates its own reserved memory.
+Additionally, objects freed by one heap cannot be reused by other threads, except indirectly by returning free memory to the operating system, which can be expensive.
+(Depending on how the operating system provides dynamic storage to an application, returning storage may be difficult or impossible, \eg the contiguous @sbrk@ area in Unix.)
+In the worst case, a program in which objects are allocated from one heap but deallocated to another heap means these freed objects are never reused.
+
+Adding a \newterm{global heap} (G) attempts to reduce the cost of obtaining/returning memory among heaps (sharing) by buffering storage within the application address-space.
+Now, each heap obtains and returns storage to/from the global heap rather than the operating system.
+Storage is obtained from the global heap only when a heap allocation cannot be fulfilled, and returned to the global heap when a heap's free memory exceeds some threshold.
+Similarly, the global heap buffers this memory, obtaining and returning storage to/from the operating system as necessary.
+The global heap does not have its own thread and makes no internal allocation requests;
+instead, it uses the application thread, which called one of the multiple heaps and then the global heap, to perform operations.
+Hence, the worst-case cost of a memory operation includes all these steps.
+With respect to heap blowup, the global heap provides an indirect mechanism to move free memory among heaps, which usually has a much lower cost than interacting with the operating system to achieve the same goal and is independent of the mechanism used by the operating system to present dynamic memory to an address space.
+
+However, since any thread may indirectly perform a memory operation on the global heap, it is a shared resource that requires locking.
+A single lock can be used to protect the global heap or fine-grained locking can be used to reduce contention.
+In general, the cost is minimal since the majority of memory operations are completed without the use of the global heap.
+
+
+\paragraph{1:1 model (thread heaps)} where each thread has its own heap, which eliminates most contention and locking because threads seldom accesses another thread's heap (see ownership in \VRef{s:Ownership}).
+An additional benefit of thread heaps is improved locality due to better memory layout.
+As each thread only allocates from its heap, all objects for a thread are consolidated in the storage area for that heap, better utilizing each CPUs cache and accessing fewer pages.
+In contrast, the T:H model spreads each thread's objects over a larger area in different heaps.
+Thread heaps can also eliminate allocator-induced active false-sharing, if memory is acquired so it does not overlap at crucial boundaries with memory for another thread's heap.
+For example, assume page boundaries coincide with cache line boundaries, then if a thread heap always acquires pages of memory, no two threads share a page or cache line unless pointers are passed among them.
+Hence, allocator-induced active false-sharing in \VRef[Figure]{f:AllocatorInducedActiveFalseSharing} cannot occur because the memory for thread heaps never overlaps.
+
+When a thread terminates, there are two options for handling its heap.
+First is to free all objects in the heap to the global heap and destroy the thread heap.
+Second is to place the thread heap on a list of available heaps and reuse it for a new thread in the future.
+Destroying the thread heap immediately may reduce external fragmentation sooner, since all free objects are freed to the global heap and may be reused by other threads.
+Alternatively, reusing thread heaps may improve performance if the inheriting thread makes similar allocation requests as the thread that previously held the thread heap.
+
+
+\subsection{User-Level Threading}
+
+It is possible to use any of the heap models with user-level (M:N) threading.
+However, an important goal of user-level threading is for fast operations (creation/termination/context-switching) by not interacting with the operating system, which allows the ability to create large numbers of high-performance interacting threads ($>$ 10,000).
+It is difficult to retain this goal, if the user-threading model is directly involved with the heap model.
+\VRef[Figure]{f:UserLevelKernelHeaps} shows that virtually all user-level threading systems use whatever kernel-level heap-model provided by the language runtime.
+Hence, a user thread allocates/deallocates from/to the heap of the kernel thread on which it is currently executing.
+
+\begin{figure}
+\centering
+\input{UserKernelHeaps}
+\caption{User-Level Kernel Heaps}
+\label{f:UserLevelKernelHeaps}
+\end{figure}
+
+Adopting this model results in a subtle problem with shared heaps.
+With kernel threading, an operation that is started by a kernel thread is always completed by that thread.
+For example, if a kernel thread starts an allocation/deallocation on a shared heap, it always completes that operation with that heap even if preempted.
+Any correctness locking associated with the shared heap is preserved across preemption.
+
+However, this correctness property is not preserved for user-level threading.
+A user thread can start an allocation/deallocation on one kernel thread, be preempted (time slice), and continue running on a different kernel thread to complete the operation~\cite{Dice02}.
+When the user thread continues on the new kernel thread, it may have pointers into the previous kernel-thread's heap and hold locks associated with it.
+To get the same kernel-thread safety, time slicing must be disabled/\-enabled around these operations, so the user thread cannot jump to another kernel thread.
+However, eagerly disabling/enabling time-slicing on the allocation/deallocation fast path is expensive, because preemption is rare (10--100 milliseconds).
+Instead, techniques exist to lazily detect this case in the interrupt handler, abort the preemption, and return to the operation so it can complete atomically.
+Occasionally ignoring a preemption should be benign.
+
+
+\begin{figure}
+\centering
+\subfigure[Ownership]{
+	\input{MultipleHeapsOwnership}
+} % subfigure
+\hspace{0.25in}
+\subfigure[No Ownership]{
+	\input{MultipleHeapsNoOwnership}
+} % subfigure
+\caption{Heap Ownership}
+\label{f:HeapsOwnership}
+\end{figure}
+
+
+\subsection{Ownership}
+\label{s:Ownership}
+
+\newterm{Ownership} defines which heap an object is returned-to on deallocation.
+If a thread returns an object to the heap it was originally allocated from, the heap has ownership of its objects.
+Alternatively, a thread can return an object to the heap it is currently allocating from, which can be any heap accessible during a thread's lifetime.
+\VRef[Figure]{f:HeapsOwnership} shows an example of multiple heaps (minus the global heap) with and without ownership.
+Again, the arrows indicate the direction memory conceptually moves for each kind of operation.
+For the 1:1 thread:heap relationship, a thread only allocates from its own heap, and without ownership, a thread only frees objects to its own heap, which means the heap is private to its owner thread and does not require any locking, called a \newterm{private heap}.
+For the T:1/T:H models with or without ownership or the 1:1 model with ownership, a thread may free objects to different heaps, which makes each heap publicly accessible to all threads, called a \newterm{public heap}.
+
+\VRef[Figure]{f:MultipleHeapStorageOwnership} shows the effect of ownership on storage layout.
+(For simplicity assume the heaps all use the same size of reserves storage.)
+In contrast to \VRef[Figure]{f:MultipleHeapStorage}, each reserved area used by a heap only contains free storage for that particular heap because threads must return free objects back to the owner heap.
+Again, because multiple threads can allocate/free/reallocate adjacent storage in the same heap, all forms of false sharing may occur.
+The exception is for the 1:1 model if reserved memory does not overlap a cache-line because all allocated storage within a used area is associated with a single thread.
+In this case, there is no allocator-induced active false-sharing (see \VRef[Figure]{f:AllocatorInducedActiveFalseSharing}) because two adjacent allocated objects used by different threads cannot share a cache-line.
+As well, there is no allocator-induced passive false-sharing (see \VRef[Figure]{f:AllocatorInducedActiveFalseSharing}) because two adjacent allocated objects used by different threads cannot occur because free objects are returned to the owner heap.
+% Passive false-sharing may still occur, if delayed ownership is used (see below).
+
+\begin{figure}
+\centering
+\input{MultipleHeapsOwnershipStorage.pstex_t}
+\caption{Multiple-Heap Storage with Ownership}
+\label{f:MultipleHeapStorageOwnership}
+\end{figure}
+
+The main advantage of ownership is preventing heap blowup by returning storage for reuse by the owner heap.
+Ownership prevents the classical problem where one thread performs allocations from one heap, passes the object to another thread, and the receiving thread deallocates the object to another heap, hence draining the initial heap of storage.
+As well, allocator-induced passive false-sharing is eliminated because returning an object to its owner heap means it can never be allocated to another thread.
+For example, in \VRef[Figure]{f:AllocatorInducedPassiveFalseSharing}, the deallocation by Task$_2$ returns Object$_2$ back to Task$_1$'s heap;
+hence a subsequent allocation by Task$_2$ cannot return this storage.
+The disadvantage of ownership is deallocating to another task's heap so heaps are no longer private and require locks to provide safe concurrent access.
+
+Object ownership can be immediate or delayed, meaning free objects may be batched on a separate free list either by the returning or receiving thread.
+While the returning thread can batch objects, batching across multiple heaps is complex and there is no obvious time when to push back to the owner heap.
+It is better for returning threads to immediately return to the receiving thread's batch list as the receiving thread has better knowledge when to incorporate the batch list into its free pool.
+Batching leverages the fact that most allocation patterns use the contention-free fast-path so locking on the batch list is rare for both the returning and receiving threads.
+
+It is possible for heaps to steal objects rather than return them and reallocating these objects when storage runs out on a heap.
+However, stealing can result in passive false-sharing.
+For example, in \VRef[Figure]{f:AllocatorInducedPassiveFalseSharing}, Object$_2$ may be deallocated to Task$_2$'s heap initially.
+If Task$_2$ reallocates Object$_2$ before it is returned to its owner heap, then passive false-sharing may occur.
+
+
+\section{Object Containers}
+\label{s:ObjectContainers}
+
+Bracketing every allocation with headers/trailers can result in significant internal fragmentation, as shown in \VRef[Figure]{f:ObjectHeaders}.
+Especially if the headers contain redundant management information, \eg object size may be the same for many objects because programs only allocate a small set of object sizes.
+As well, it can result in poor cache usage, since only a portion of the cache line is holding useful information from the program's perspective.
+Spatial locality can also be negatively affected leading to poor cache locality~\cite{Feng05}:
+while the header and object are together in memory, they are generally not accessed together;
+\eg the object is accessed by the program when it is allocated, while the header is accessed by the allocator when the object is free.
+
+\begin{figure}
+\centering
+\subfigure[Object Headers]{
+	\input{ObjectHeaders}
+	\label{f:ObjectHeaders}
+} % subfigure
+\subfigure[Object Container]{
+	\input{Container}
+	\label{f:ObjectContainer}
+} % subfigure
+\caption{Header Placement}
+\label{f:HeaderPlacement}
+\end{figure}
+
+An alternative approach factors common header/trailer information to a separate location in memory and organizes associated free storage into blocks called \newterm{object containers} (\newterm{superblocks} in~\cite{Berger00}), as in \VRef[Figure]{f:ObjectContainer}.
+The header for the container holds information necessary for all objects in the container;
+a trailer may also be used at the end of the container.
+Similar to the approach described for thread heaps in \VRef{s:MultipleHeaps}, if container boundaries do not overlap with memory of another container at crucial boundaries and all objects in a container are allocated to the same thread, allocator-induced active false-sharing is avoided.
+
+The difficulty with object containers lies in finding the object header/trailer given only the object address, since that is normally the only information passed to the deallocation operation.
+One way to do this is to start containers on aligned addresses in memory, then truncate the lower bits of the object address to obtain the header address (or round up and subtract the trailer size to obtain the trailer address).
+For example, if an object at address 0xFC28\,EF08 is freed and containers are aligned on 64\,KB (0x0001\,0000) addresses, then the container header is at 0xFC28\,0000.
+
+Normally, a container has homogeneous objects of fixed size, with fixed information in the header that applies to all container objects (\eg object size and ownership).
+This approach greatly reduces internal fragmentation since far fewer headers are required, and potentially increases spatial locality as a cache line or page holds more objects since the objects are closer together due to the lack of headers.
+However, although similar objects are close spatially within the same container, different sized objects are further apart in separate containers.
+Depending on the program, this may or may not improve locality.
+If the program uses several objects from a small number of containers in its working set, then locality is improved since fewer cache lines and pages are required.
+If the program uses many containers, there is poor locality, as both caching and paging increase.
+Another drawback is that external fragmentation may be increased since containers reserve space for objects that may never be allocated by the program, \ie there are often multiple containers for each size only partially full.
+However, external fragmentation can be reduced by using small containers.
+
+Containers with heterogeneous objects implies different headers describing them, which complicates the problem of locating a specific header solely by an address.
+A couple of solutions can be used to implement containers with heterogeneous objects.
+However, the problem with allowing objects of different sizes is that the number of objects, and therefore headers, in a single container is unpredictable.
+One solution allocates headers at one end of the container, while allocating objects from the other end of the container;
+when the headers meet the objects, the container is full.
+Freed objects cannot be split or coalesced since this causes the number of headers to change.
+The difficulty in this strategy remains in finding the header for a specific object;
+in general, a search is necessary to find the object's header among the container headers.
+A second solution combines the use of container headers and individual object headers.
+Each object header stores the object's heterogeneous information, such as its size, while the container header stores the homogeneous information, such as the owner when using ownership.
+This approach allows containers to hold different types of objects, but does not completely separate headers from objects.
+The benefit of the container in this case is to reduce some redundant information that is factored into the container header.
+
+In summary, object containers trade off internal fragmentation for external fragmentation by isolating common administration information to remove/reduce internal fragmentation, but at the cost of external fragmentation as some portion of a container may not be used and this portion is unusable for other kinds of allocations.
+A consequence of this tradeoff is its effect on spatial locality, which can produce positive or negative results depending on program access-patterns.
+
+
+\subsection{Container Ownership}
+\label{s:ContainerOwnership}
+
+Without ownership, objects in a container are deallocated to the heap currently associated with the thread that frees the object.
+Thus, different objects in a container may be on different heap free-lists (see \VRef[Figure]{f:ContainerNoOwnershipFreelist}).
+With ownership, all objects in a container belong to the same heap (see \VRef[Figure]{f:ContainerOwnershipFreelist}), so ownership of an object is determined by the container owner.
+If multiple threads can allocate/free/reallocate adjacent storage in the same heap, all forms of false sharing may occur.
+Only with the 1:1 model and ownership is active and passive false-sharing avoided (see \VRef{s:Ownership}).
+Passive false-sharing may still occur, if delayed ownership is used.
+
+\begin{figure}
+\centering
+\subfigure[No Ownership]{
+	\input{ContainerNoOwnershipFreelist}
+	\label{f:ContainerNoOwnershipFreelist}
+} % subfigure
+\vrule
+\subfigure[Ownership]{
+	\input{ContainerOwnershipFreelist}
+	\label{f:ContainerOwnershipFreelist}
+} % subfigure
+\caption{Free-list Structure with Container Ownership}
+\end{figure}
+
+A fragmented heap has multiple containers that may be partially or completely free.
+A completely free container can become reserved storage and be reset to allocate objects of a new size.
+When a heap reaches a threshold of free objects, it moves some free storage to the global heap for reuse to prevent heap blowup.
+Without ownership, when a heap frees objects to the global heap, individual objects must be passed, and placed on the global-heap's free-list.
+Containers cannot be freed to the global heap unless completely free because
+
+When a container changes ownership, the ownership of all objects within it change as well.
+Moving a container involves moving all objects on the heap's free-list in that container to the new owner.
+This approach can reduce contention for the global heap, since each request for objects from the global heap returns a container rather than individual objects.
+
+Additional restrictions may be applied to the movement of containers to prevent active false-sharing.
+For example, in \VRef[Figure]{f:ContainerFalseSharing1}, a container being used by Task$_1$ changes ownership, through the global heap.
+In \VRef[Figure]{f:ContainerFalseSharing2}, when Task$_2$ allocates an object from the newly acquired container it is actively false-sharing even though no objects are passed among threads.
+Note, once the object is freed by Task$_1$, no more false sharing can occur until the container changes ownership again.
+To prevent this form of false sharing, container movement may be restricted to when all objects in the container are free.
+One implementation approach that increases the freedom to return a free container to the operating system involves allocating containers using a call like @mmap@, which allows memory at an arbitrary address to be returned versus only storage at the end of the contiguous @sbrk@ area.
+
+\begin{figure}
+\centering
+\subfigure[]{
+	\input{ContainerFalseSharing1}
+	\label{f:ContainerFalseSharing1}
+} % subfigure
+\subfigure[]{
+	\input{ContainerFalseSharing2}
+	\label{f:ContainerFalseSharing2}
+} % subfigure
+\caption{Active False-Sharing using Containers}
+\label{f:ActiveFalseSharingContainers}
+\end{figure}
+
+Using containers with ownership increases external fragmentation since a new container for a requested object size must be allocated separately for each thread requesting it.
+In \VRef[Figure]{f:ExternalFragmentationContainerOwnership}, using object ownership allocates 80\% more space than without ownership.
+
+\begin{figure}
+\centering
+\subfigure[No Ownership]{
+	\input{ContainerNoOwnership}
+} % subfigure
+\\
+\subfigure[Ownership]{
+	\input{ContainerOwnership}
+} % subfigure
+\caption{External Fragmentation with Container Ownership}
+\label{f:ExternalFragmentationContainerOwnership}
+\end{figure}
+
+
+\subsection{Container Size}
+\label{s:ContainerSize}
+
+One way to control the external fragmentation caused by allocating a large container for a small number of requested objects is to vary the size of the container.
+As described earlier, container boundaries need to be aligned on addresses that are a power of two to allow easy location of the header (by truncating lower bits).
+Aligning containers in this manner also determines the size of the container.
+However, the size of the container has different implications for the allocator.
+
+The larger the container, the fewer containers are needed, and hence, the fewer headers need to be maintained in memory, improving both internal fragmentation and potentially performance.
+However, with more objects in a container, there may be more objects that are unallocated, increasing external fragmentation.
+With smaller containers, not only are there more containers, but a second new problem arises where objects are larger than the container.
+In general, large objects, \eg greater than 64\,KB, are allocated directly from the operating system and are returned immediately to the operating system to reduce long-term external fragmentation.
+If the container size is small, \eg 1\,KB, then a 1.5\,KB object is treated as a large object, which is likely to be inappropriate.
+Ideally, it is best to use smaller containers for smaller objects, and larger containers for medium objects, which leads to the issue of locating the container header.
+
+In order to find the container header when using different sized containers, a super container is used (see~\VRef[Figure]{f:SuperContainers}).
+The super container spans several containers, contains a header with information for finding each container header, and starts on an aligned address.
+Super-container headers are found using the same method used to find container headers by dropping the lower bits of an object address.
+The containers within a super container may be different sizes or all the same size.
+If the containers in the super container are different sizes, then the super-container header must be searched to determine the specific container for an object given its address.
+If all containers in the super container are the same size, \eg 16KB, then a specific container header can be found by a simple calculation.
+The free space at the end of a super container is used to allocate new containers.
+
+\begin{figure}
+\centering
+\input{SuperContainers}
+% \includegraphics{diagrams/supercontainer.eps}
+\caption{Super Containers}
+\label{f:SuperContainers}
+\end{figure}
+
+Minimal internal and external fragmentation is achieved by having as few containers as possible, each being as full as possible.
+It is also possible to achieve additional benefit by using larger containers for popular small sizes, as it reduces the number of containers with associated headers.
+However, this approach assumes it is possible for an allocator to determine in advance which sizes are popular.
+Keeping statistics on requested sizes allows the allocator to make a dynamic decision about which sizes are popular.
+For example, after receiving a number of allocation requests for a particular size, that size is considered a popular request size and larger containers are allocated for that size.
+If the decision is incorrect, larger containers than necessary are allocated that remain mostly unused.
+A programmer may be able to inform the allocator about popular object sizes, using a mechanism like @mallopt@, in order to select an appropriate container size for each object size.
+
+
+\subsection{Container Free-Lists}
+\label{s:containersfreelists}
+
+The container header allows an alternate approach for managing the heap's free-list.
+Rather than maintain a global free-list throughout the heap (see~\VRef[Figure]{f:GlobalFreeListAmongContainers}), the containers are linked through their headers and only the local free objects within a container are linked together (see~\VRef[Figure]{f:LocalFreeListWithinContainers}).
+Note, maintaining free lists within a container assumes all free objects in the container are associated with the same heap;
+thus, this approach only applies to containers with ownership.
+
+This alternate free-list approach can greatly reduce the complexity of moving all freed objects belonging to a container to another heap.
+To move a container using a global free-list, as in \VRef[Figure]{f:GlobalFreeListAmongContainers}, the free list is first searched to find all objects within the container.
+Each object is then removed from the free list and linked together to form a local free-list for the move to the new heap.
+With local free-lists in containers, as in \VRef[Figure]{f:LocalFreeListWithinContainers}, the container is simply removed from one heap's free list and placed on the new heap's free list.
+Thus, when using local free-lists, the operation of moving containers is reduced from $O(N)$ to $O(1)$.
+The cost is adding information to a header, which increases the header size, and therefore internal fragmentation.
+
+\begin{figure}
+\centering
+\subfigure[Global Free-List Among Containers]{
+	\input{FreeListAmongContainers}
+	\label{f:GlobalFreeListAmongContainers}
+} % subfigure
+\hspace{0.25in}
+\subfigure[Local Free-List Within Containers]{
+	\input{FreeListWithinContainers}
+	\label{f:LocalFreeListWithinContainers}
+} % subfigure
+\caption{Container Free-List Structure}
+\label{f:ContainerFreeListStructure}
+\end{figure}
+
+When all objects in the container are the same size, a single free-list is sufficient.
+However, when objects in the container are different size, the header needs a free list for each size class when using a binning allocation algorithm, which can be a significant increase in the container-header size.
+The alternative is to use a different allocation algorithm with a single free-list, such as a sequential-fit allocation-algorithm.
+
+
+\subsection{Hybrid Private/Public Heap}
+\label{s:HybridPrivatePublicHeap}
+
+Section~\Vref{s:Ownership} discusses advantages and disadvantages of public heaps (T:H model and with ownership) and private heaps (thread heaps with ownership).
+For thread heaps with ownership, it is possible to combine these approaches into a hybrid approach with both private and public heaps (see~\VRef[Figure]{f:HybridPrivatePublicHeap}).
+The main goal of the hybrid approach is to eliminate locking on thread-local allocation/deallocation, while providing ownership to prevent heap blowup.
+In the hybrid approach, a task first allocates from its private heap and second from its public heap if no free memory exists in the private heap.
+Similarly, a task first deallocates an object its private heap, and second to the public heap.
+Both private and public heaps can allocate/deallocate to/from the global heap if there is no free memory or excess free memory, although an implementation may choose to funnel all interaction with the global heap through one of the heaps.
+Note, deallocation from the private to the public (dashed line) is unlikely because there is no obvious advantages unless the public heap provides the only interface to the global heap.
+Finally, when a task frees an object it does not own, the object is either freed immediately to its owner's public heap or put in the freeing task's private heap for delayed ownership, which allows the freeing task to temporarily reuse an object before returning it to its owner or batch objects for an owner heap into a single return.
+
+\begin{figure}
+\centering
+\input{PrivatePublicHeaps.pstex_t}
+\caption{Hybrid Private/Public Heap for Per-thread Heaps}
+\label{f:HybridPrivatePublicHeap}
+% \vspace{10pt}
+% \input{RemoteFreeList.pstex_t}
+% \caption{Remote Free-List}
+% \label{f:RemoteFreeList}
+\end{figure}
+
+As mentioned, an implementation may have only one heap deal with the global heap, so the other heap can be simplified.
+For example, if only the private heap interacts with the global heap, the public heap can be reduced to a lock-protected free-list of objects deallocated by other threads due to ownership, called a \newterm{remote free-list}.
+To avoid heap blowup, the private heap allocates from the remote free-list when it reaches some threshold or it has no free storage.
+Since the remote free-list is occasionally cleared during an allocation, this adds to that cost.
+Clearing the remote free-list is $O(1)$ if the list can simply be added to the end of the private-heap's free-list, or $O(N)$ if some action must be performed for each freed object.
+
+If only the public heap interacts with other threads and the global heap, the private heap can handle thread-local allocations and deallocations without locking.
+In this scenario, the private heap must deallocate storage after reaching a certain threshold to the public heap (and then eventually to the global heap from the public heap) or heap blowup can occur.
+If the public heap does the major management, the private heap can be simplified to provide high-performance thread-local allocations and deallocations.
+
+The main disadvantage of each thread having both a private and public heap is the complexity of managing two heaps and their interactions in an allocator.
+Interestingly, heap implementations often focus on either a private or public heap, giving the impression a single versus a hybrid approach is being used.
+In many case, the hybrid approach is actually being used, but the simpler heap is just folded into the complex heap, even though the operations logically belong in separate heaps.
+For example, a remote free-list is actually a simple public-heap, but may be implemented as an integral component of the complex private-heap in an allocator, masking the presence of a hybrid approach.
+
+
+\section{Allocation Buffer}
+\label{s:AllocationBuffer}
+
+An allocation buffer is reserved memory (see~\VRef{s:AllocatorComponents}) not yet allocated to the program, and is used for allocating objects when the free list is empty.
+That is, rather than requesting new storage for a single object, an entire buffer is requested from which multiple objects are allocated later.
+Both any heap may use an allocation buffer, resulting in allocation from the buffer before requesting objects (containers) from the global heap or operating system, respectively.
+The allocation buffer reduces contention and the number of global/operating-system calls.
+For coalescing, a buffer is split into smaller objects by allocations, and recomposed into larger buffer areas during deallocations.
+
+Allocation buffers are useful initially when there are no freed objects in a heap because many allocations usually occur when a thread starts.
+Furthermore, to prevent heap blowup, objects should be reused before allocating a new allocation buffer.
+Thus, allocation buffers are often allocated more frequently at program/thread start, and then their use often diminishes.
+
+Using an allocation buffer with a thread heap avoids active false-sharing, since all objects in the allocation buffer are allocated to the same thread.
+For example, if all objects sharing a cache line come from the same allocation buffer, then these objects are allocated to the same thread, avoiding active false-sharing.
+Active false-sharing may still occur if objects are freed to the global heap and reused by another heap.
+
+Allocation buffers may increase external fragmentation, since some memory in the allocation buffer may never be allocated.
+A smaller allocation buffer reduces the amount of external fragmentation, but increases the number of calls to the global heap or operating system.
+The allocation buffer also slightly increases internal fragmentation, since a pointer is necessary to locate the next free object in the buffer.
+
+The unused part of a container, neither allocated or freed, is an allocation buffer.
+For example, when a container is created, rather than placing all objects within the container on the free list, the objects form an allocation buffer and are allocated from the buffer as allocation requests are made.
+This lazy method of constructing objects is beneficial in terms of paging and caching.
+For example, although an entire container, possibly spanning several pages, is allocated from the operating system, only a small part of the container is used in the working set of the allocator, reducing the number of pages and cache lines that are brought into higher levels of cache.
+
+
+\section{Lock-Free Operations}
+\label{s:LockFreeOperations}
+
+A lock-free algorithm guarantees safe concurrent-access to a data structure, so that at least one thread can make progress in the system, but an individual task has no bound to execution, and hence, may starve~\cite[pp.~745--746]{Herlihy93}.
+% A wait-free algorithm puts a finite bound on the number of steps any thread takes to complete an operation, so an individual task cannot starve
+Lock-free operations can be used in an allocator to reduce or eliminate the use of locks.
+Locks are a problem for high contention or if the thread holding the lock is preempted and other threads attempt to use that lock.
+With respect to the heap, these situations are unlikely unless all threads makes extremely high use of dynamic-memory allocation, which can be an indication of poor design.
+Nevertheless, lock-free algorithms can reduce the number of context switches, since a thread does not yield/block while waiting for a lock;
+on the other hand, a thread may busy-wait for an unbounded period.
+Finally, lock-free implementations have greater complexity and hardware dependency.
+Lock-free algorithms can be applied most easily to simple free-lists, \eg remote free-list, to allow lock-free insertion and removal from the head of a stack.
+Implementing lock-free operations for more complex data-structures (queue~\cite{Valois94}/deque~\cite{Sundell08}) is more complex.
+Michael~\cite{Michael04} and Gidenstam \etal \cite{Gidenstam05} have created lock-free variations of the Hoard allocator.
Index: doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -41,4 +41,18 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+
+\section{Benchmarks}
+There are multiple benchmarks that are built individually and evaluate different aspects of a memory allocator. But, there is not standard set of benchamrks that can be used to evaluate multiple aspects of memory allocators.
+
+\paragraph{threadtest}
+(FIX ME: cite benchmark and hoard) Each thread repeatedly allocates and then deallocates 100,000 objects. Runtime of the benchmark evaluates its efficiency.
+
+\paragraph{shbench}
+(FIX ME: cite benchmark and hoard) Each thread allocates and randomly frees a number of random-sized objects. It is a stress test that also uses runtime to determine efficiency of the allocator.
+
+\paragraph{larson}
+(FIX ME: cite benchmark and hoard) Larson simulates a server environment. Multiple threads are created where each thread allocator and free a number of objects within a size range. Some objects are passed from threads to the child threads to free. It caluculates memory operations per second as an indicator of memory allocator's performance.
+
+
 \section{Performance Matrices of Memory Allocators}
 
Index: doc/theses/mubeen_zulfiqar_MMath/figures/AddressSpace.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/AddressSpace.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/AddressSpace.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,48 @@
+#FIG 3.2  Produced by xfig version 3.2.7b
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5700 1350 6600 1350 6600 2100 5700 2100 5700 1350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1350 2100 1350 2100 2100 1200 2100 1200 1350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4800 1350 5700 1350 5700 2100 4800 2100 4800 1350
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2100 1725 2400 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3000 1725 2700 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3900 1725 4200 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4800 1725 4500 1725
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 2100 1350 3000 1350 3000 2100 2100 2100 2100 1350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1350 3900 1350 3900 2100 3000 2100 3000 1350
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3900 1350 4800 1350 4800 2100 3900 2100 3900 1350
+4 0 0 50 -1 0 11 0.0000 2 180 900 1200 2325 high address\001
+4 2 0 50 -1 0 11 0.0000 2 135 855 6600 2325 low address\001
+4 1 0 50 -1 0 11 0.0000 2 120 330 6150 2025 Data\001
+4 1 0 50 -1 0 11 0.0000 2 135 675 6150 1800 Code and\001
+4 1 0 50 -1 0 11 0.0000 2 120 390 6150 1575 Static\001
+4 1 0 50 -1 0 11 0.0000 2 135 390 1650 1800 Stack\001
+4 1 0 50 -1 0 11 0.0000 2 165 615 2550 1950 Memory\001
+4 1 0 50 -1 0 11 0.0000 2 165 615 4350 1950 Memory\001
+4 1 0 50 -1 0 11 0.0000 2 120 315 2550 1650 Free\001
+4 1 0 50 -1 0 11 0.0000 2 120 330 3450 2025 Data\001
+4 1 0 50 -1 0 11 0.0000 2 135 675 3450 1800 Code and\001
+4 1 0 50 -1 0 11 0.0000 2 165 645 3450 1575 Dynamic\001
+4 1 0 50 -1 0 11 0.0000 2 120 315 4350 1650 Free\001
+4 1 0 50 -1 0 11 0.0000 2 120 735 5250 1950 Allocation\001
+4 1 0 50 -1 0 11 0.0000 2 165 645 5250 1650 Dynamic\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/AllocDS1.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/AllocDS1.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/AllocDS1.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,162 @@
+#FIG 3.2  Produced by xfig version 3.2.7b
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 4200 1575 4500 1725
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 1650 20 20 4275 1650 4295 1650
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4350 1650 20 20 4350 1650 4370 1650
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4425 1650 20 20 4425 1650 4445 1650
+-6
+6 2850 2475 3150 2850
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2925 2475 2925 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2850 2700 3150 2700 3150 2850 2850 2850 2850 2700
+-6
+6 4350 2475 4650 2850
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4425 2475 4425 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4350 2700 4650 2700 4650 2850 4350 2850 4350 2700
+-6
+6 3600 2475 3825 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3675 2475 3675 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 2700 3825 2700 3825 2850 3600 2850 3600 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 3000 3825 3000 3825 3150 3600 3150 3600 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3675 2775 3675 3000
+-6
+6 4875 3600 5175 3750
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 3675 20 20 4950 3675 4970 3675
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 3675 20 20 5025 3675 5045 3675
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 3675 20 20 5100 3675 5120 3675
+-6
+6 4875 2325 5175 2475
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4950 2400 20 20 4950 2400 4970 2400
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5025 2400 20 20 5025 2400 5045 2400
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5100 2400 20 20 5100 2400 5120 2400
+-6
+6 5625 2325 5925 2475
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 2400 20 20 5700 2400 5720 2400
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 2400 20 20 5775 2400 5795 2400
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 2400 20 20 5850 2400 5870 2400
+-6
+6 5625 3600 5925 3750
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5700 3675 20 20 5700 3675 5720 3675
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5775 3675 20 20 5775 3675 5795 3675
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 5850 3675 20 20 5850 3675 5870 3675
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2400 2100 2400 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2550 2100 2550 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2700 2100 2700 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2850 2100 2850 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3000 2100 3000 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3600 2100 3600 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3900 2100 3900 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4050 2100 4050 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4200 2100 4200 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4350 2100 4350 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4500 2100 4500 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3300 1500 3300 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3600 1500 3600 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3900 1500 3900 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1500 4800 1500 4800 1800 3000 1800 3000 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3225 1650 2625 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3150 1650 2550 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3450 1650 4050 2100
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3375 1650 3975 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2100 2100 2100 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1950 2250 3150 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3450 2250 4650 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 2100 3150 2100 3150 2550 1950 2550 1950 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3450 2100 4650 2100 4650 2550 3450 2550 3450 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2250 2100 2250 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3750 2100 3750 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2025 2475 2025 2700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2025 2775 2025 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 3000 2100 3000 2100 3150 1950 3150 1950 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 2700 2100 2700 2100 2850 1950 2850 1950 2700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 45.00 90.00
+	 1950 3750 2700 3750 2700 3525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 3525 3150 3525 3150 3900 1950 3900 1950 3525
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 45.00 90.00
+	 3450 3750 4200 3750 4200 3525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3450 3525 4650 3525 4650 3900 3450 3900 3450 3525
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 45.00 90.00
+	 3150 4650 4200 4650 4200 4275
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3150 4275 4650 4275 4650 4875 3150 4875 3150 4275
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1950 2400 3150 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3450 2400 4650 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5400 2100 5400 3900
+4 2 0 50 -1 0 11 0.0000 2 120 300 1875 2250 lock\001
+4 1 0 50 -1 0 12 0.0000 2 135 1935 3900 1425 N kernel-thread buckets\001
+4 1 0 50 -1 0 12 0.0000 2 195 810 4425 2025 heap$_2$\001
+4 1 0 50 -1 0 12 0.0000 2 195 810 2175 2025 heap$_1$\001
+4 2 0 50 -1 0 11 0.0000 2 120 270 1875 2400 size\001
+4 2 0 50 -1 0 11 0.0000 2 120 270 1875 2550 free\001
+4 1 0 50 -1 0 12 0.0000 2 180 825 2550 3450 local pool\001
+4 0 0 50 -1 0 12 0.0000 2 135 360 3525 3700 lock\001
+4 0 0 50 -1 0 12 0.0000 2 135 360 3225 4450 lock\001
+4 2 0 50 -1 0 12 0.0000 2 135 600 1875 3000 free list\001
+4 1 0 50 -1 0 12 0.0000 2 180 825 4050 3450 local pool\001
+4 1 0 50 -1 0 12 0.0000 2 180 1455 3900 4200 global pool (sbrk)\001
+4 0 0 50 -1 0 12 0.0000 2 135 360 2025 3700 lock\001
+4 1 0 50 -1 0 12 0.0000 2 180 720 6450 3150 free pool\001
+4 1 0 50 -1 0 12 0.0000 2 180 390 6450 2925 heap\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/AllocDS2.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/AllocDS2.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/AllocDS2.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,126 @@
+#FIG 3.2  Produced by xfig version 3.2.7b
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 2850 2100 3150 2250
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 2925 2175 20 20 2925 2175 2945 2175
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3000 2175 20 20 3000 2175 3020 2175
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3075 2175 20 20 3075 2175 3095 2175
+-6
+6 4050 2100 4350 2250
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4125 2175 20 20 4125 2175 4145 2175
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4200 2175 20 20 4200 2175 4220 2175
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4275 2175 20 20 4275 2175 4295 2175
+-6
+6 4650 2100 4950 2250
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4725 2175 20 20 4725 2175 4745 2175
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4800 2175 20 20 4800 2175 4820 2175
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 4875 2175 20 20 4875 2175 4895 2175
+-6
+6 3450 2100 3750 2250
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3525 2175 20 20 3525 2175 3545 2175
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3600 2175 20 20 3600 2175 3620 2175
+1 3 0 1 0 0 50 -1 20 0.000 1 0.0000 3675 2175 20 20 3675 2175 3695 2175
+-6
+6 3300 2175 3600 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3375 2175 3375 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3300 2400 3600 2400 3600 2550 3300 2550 3300 2400
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3150 1800 3150 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2850 1800 2850 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 1800 4650 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4950 1800 4950 2250
+2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4500 1725 4500 2250
+2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5100 1725 5100 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3450 1800 3450 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3750 1800 3750 2250
+2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3300 1725 3300 2250
+2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3900 1725 3900 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5250 1800 5250 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5400 1800 5400 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5550 1800 5550 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5700 1800 5700 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5850 1800 5850 2250
+2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2700 1725 2700 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3375 1275 3375 1575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 1275 2700 1575
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2775 1275 2775 1575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5175 1275 5175 1575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5625 1275 5625 1575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3750 1275 3750 1575
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3825 1275 3825 1575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2700 1950 6000 1950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2700 2100 6000 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1800 6000 1800 6000 2250 2700 2250 2700 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2775 2175 2775 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2775 2475 2775 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 2700 2850 2700 2850 2850 2700 2850 2700 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 2400 2850 2400 2850 2550 2700 2550 2700 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4575 2175 4575 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4500 2400 5025 2400 5025 2550 4500 2550 4500 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 45.00 90.00
+	 3600 3525 4650 3525 4650 3150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 3150 5100 3150 5100 3750 3600 3750 3600 3150
+4 2 0 50 -1 0 11 0.0000 2 120 300 2625 1950 lock\001
+4 1 0 50 -1 0 10 0.0000 2 150 1155 3000 1725 N$\\times$S$_1$\001
+4 1 0 50 -1 0 10 0.0000 2 150 1155 3600 1725 N$\\times$S$_2$\001
+4 1 0 50 -1 0 12 0.0000 2 180 390 4425 1500 heap\001
+4 2 0 50 -1 0 12 0.0000 2 135 1140 2550 1425 kernel threads\001
+4 2 0 50 -1 0 11 0.0000 2 120 270 2625 2100 size\001
+4 2 0 50 -1 0 11 0.0000 2 120 270 2625 2250 free\001
+4 2 0 50 -1 0 12 0.0000 2 135 600 2625 2700 free list\001
+4 0 0 50 -1 0 12 0.0000 2 135 360 3675 3325 lock\001
+4 1 0 50 -1 0 12 0.0000 2 180 1455 4350 3075 global pool (sbrk)\001
+4 1 0 50 -1 0 10 0.0000 2 150 1110 4800 1725 N$\\times$S$_t$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/AllocInducedActiveFalseSharing.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/AllocInducedActiveFalseSharing.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/AllocInducedActiveFalseSharing.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,54 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 2250 2400 4050 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2250 2400 3150 2400 3150 2700 2250 2700 2250 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3150 2400 4050 2400 4050 2700 3150 2700 3150 2400
+4 1 0 50 -1 0 11 0.0000 2 195 870 2700 2625 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3600 2625 Object$_2$\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1050 1500 1950 1500 1950 1800 1050 1800 1050 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 900 900 3000 900 3000 1950 900 1950 900 900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1950 1950 2700 2400
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 1500 2850 1500 2850 1800 1950 1800 1950 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4350 1500 5250 1500 5250 1800 4350 1800 4350 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3300 900 5400 900 5400 1950 3300 1950 3300 900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4350 1950 3600 2400
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3450 1500 4350 1500 4350 1800 3450 1800 3450 1500
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+	 2850 1200 2850 975 2250 975 2250 1200 2850 1200
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+	 5250 1200 5250 975 4650 975 4650 1200 5250 1200
+4 1 0 50 -1 0 11 0.0000 2 195 735 2550 1125 Task$_1$\001
+4 0 0 50 -1 0 11 0.0000 2 195 720 975 1125 CPU$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 135 480 1950 1425 Cache\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 1500 1725 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2400 1725 Object$_2$\001
+4 2 0 50 -1 2 11 0.0000 2 135 585 2250 2250 1. alloc\001
+4 1 0 50 -1 0 11 0.0000 2 195 735 4950 1125 Task$_2$\001
+4 0 0 50 -1 0 11 0.0000 2 195 720 3375 1125 CPU$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3900 1725 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4800 1725 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 135 480 4350 1425 Cache\001
+4 2 0 50 -1 0 11 0.0000 2 180 630 2175 2625 Memory\001
+4 0 0 50 -1 2 11 0.0000 2 180 720 4050 2250 4. modify\001
+4 2 0 50 -1 2 11 0.0000 2 135 585 3900 2175 3. alloc\001
+4 0 0 50 -1 2 11 0.0000 2 180 720 2400 2175 2. modify\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/AllocInducedPassiveFalseSharing.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/AllocInducedPassiveFalseSharing.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/AllocInducedPassiveFalseSharing.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,58 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 3750.000 4062.500 2550 975 3750 750 4950 975
+	1 1 1.00 45.00 90.00
+6 2250 2400 4050 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2250 2400 3150 2400 3150 2700 2250 2700 2250 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3150 2400 4050 2400 4050 2700 3150 2700 3150 2400
+4 1 0 50 -1 0 11 0.0000 2 195 870 2700 2625 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3600 2625 Object$_2$\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1050 1500 1950 1500 1950 1800 1050 1800 1050 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 900 900 3000 900 3000 1950 900 1950 900 900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1950 1950 2700 2400
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 1500 2850 1500 2850 1800 1950 1800 1950 1500
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3450 1500 4350 1500 4350 1800 3450 1800 3450 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4350 1500 5250 1500 5250 1800 4350 1800 4350 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3300 900 5400 900 5400 1950 3300 1950 3300 900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4350 1950 3600 2400
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+	 5250 1200 5250 975 4650 975 4650 1200 5250 1200
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+	 2850 1200 2850 975 2250 975 2250 1200 2850 1200
+4 1 0 50 -1 0 11 0.0000 2 195 735 2550 1125 Task$_1$\001
+4 0 0 50 -1 0 11 0.0000 2 195 720 975 1125 CPU$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 135 480 1950 1425 Cache\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 1500 1725 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2400 1725 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 735 4950 1125 Task$_2$\001
+4 0 0 50 -1 0 11 0.0000 2 195 720 3375 1125 CPU$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3900 1725 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4800 1725 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 135 480 4350 1425 Cache\001
+4 0 0 50 -1 2 11 0.0000 2 180 720 4050 2250 6. modify\001
+4 2 0 50 -1 0 11 0.0000 2 180 630 2175 2625 Memory\001
+4 2 0 50 -1 2 11 0.0000 2 135 585 2250 2250 1. alloc\001
+4 0 0 50 -1 2 11 0.0000 2 180 720 2400 2175 3. modify\001
+4 2 0 50 -1 2 11 0.0000 2 135 585 3675 2325 5. alloc\001
+4 2 0 50 -1 2 11 0.0000 2 135 780 3975 2175 4. dealloc\001
+4 1 0 50 -1 2 11 0.0000 2 195 2400 3750 675 2.  pass Object$_2$ reference\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/AllocatedObject.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/AllocatedObject.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/AllocatedObject.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,28 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3900 1200 4800 1200 4800 1500 3900 1500 3900 1200
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 2100 1200 3000 1200 3000 1500 2100 1500 2100 1200
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 5700 1200 5700 1500 1200 1500 1200 1200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2100 1200 2100 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3000 1200 3000 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3900 1200 3900 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4800 1200 4800 1500
+4 1 0 50 -1 0 11 0.0000 2 135 555 1650 1425 Header\001
+4 1 0 50 -1 0 11 0.0000 2 180 600 2550 1425 Padding\001
+4 1 0 50 -1 0 11 0.0000 2 180 510 3450 1425 Object\001
+4 1 0 50 -1 0 11 0.0000 2 180 600 4350 1425 Spacing\001
+4 1 0 50 -1 0 11 0.0000 2 135 495 5250 1425 Trailer\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/AllocatorComponents.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/AllocatorComponents.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/AllocatorComponents.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,71 @@
+#FIG 3.2  Produced by xfig version 3.2.7b
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 2400 1575 3000 1950
+4 2 0 50 -1 0 11 0.0000 2 165 495 3000 1875 objects\001
+4 2 0 50 -1 0 11 0.0000 2 120 270 3000 1725 free\001
+-6
+6 2400 2100 2700 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 2400 2700 2700 2400 2700 2400 2400 2700 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 2100 2700 2400 2400 2400 2400 2100 2700 2100
+-6
+6 2325 2850 3000 3225
+4 2 0 50 -1 0 11 0.0000 2 135 600 3000 3000 reserved\001
+4 2 0 50 -1 0 11 0.0000 2 135 585 3000 3150 memory\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4200 1800 4800 1800 4800 2100 4200 2100 4200 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4200 2100 5100 2100 5100 2400 4200 2400 4200 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5100 2100 6300 2100 6300 2400 5100 2400 5100 2100
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3300 1800 4200 1800 4200 2100 3300 2100 3300 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 5400 1800 6300 1800 6300 2100 5400 2100 5400 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3300 2100 3600 2100 3600 2400 3300 2400 3300 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3300 2400 3900 2400 3900 2700 3300 2700 3300 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 2400 4800 2400 4800 2700 3900 2700 3900 2400
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 4800 2400 5400 2400 5400 2700 4800 2700 4800 2400
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 4800 1800 5400 1800 5400 2100 4800 2100 4800 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5400 2400 6300 2400 6300 2700 5400 2700 5400 2400
+2 2 0 1 0 7 60 -1 13 0.000 0 0 -1 0 0 5
+	 3300 2700 6300 2700 6300 3300 3300 3300 3300 2700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3750 1950 4800 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5100 1950 3300 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3450 2250 4800 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5100 2550 5400 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 2250 3300 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 2550 3300 2700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3150 1275 3150 3300
+4 1 0 50 -1 0 11 0.0000 2 120 795 2325 1425 Static Zone\001
+4 1 0 50 -1 0 11 0.0000 2 165 1845 4800 1425 Dynamic-Allocation Zone\001
+4 0 0 50 -1 2 11 0.0000 2 165 585 3300 1725 Storage\001
+4 2 0 50 -1 2 11 0.0000 2 165 1005 2325 2475 Management\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/CoalesceAllocated.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/CoalesceAllocated.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/CoalesceAllocated.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,24 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 2100 1200 2100 1500 1200 1500 1200 1200
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1200 3000 1200 3000 1500 2100 1500 2100 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1200 3900 1200 3900 1500 3000 1500 3000 1200
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 1200 4800 1200 4800 1500 3900 1500 3900 1200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 45.00 90.00
+	 2550 1200 2550 1050 1800 1050
+4 1 0 50 -1 0 11 0.0000 2 180 510 3450 1425 Object\001
+4 1 0 50 -1 0 11 0.0000 2 135 330 1650 1425 Size\001
+4 1 0 50 -1 0 11 0.0000 2 135 510 2550 1425 Owner\001
+4 1 0 50 -1 0 11 0.0000 2 195 780 4350 1425 $\\pm$Size\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/CoalesceFree.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/CoalesceFree.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/CoalesceFree.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,27 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 1200 4800 1200 4800 1500 3900 1500 3900 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 2100 1200 2100 1500 1200 1500 1200 1200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 45.00 90.00
+	 2550 1200 2550 1050 1800 1050
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 3
+	1 1 1.00 45.00 90.00
+	 3450 1200 3450 1050 4200 1050
+2 2 0 1 0 7 60 -1 18 0.000 0 0 -1 0 0 5
+	 3000 1200 3900 1200 3900 1500 3000 1500 3000 1200
+2 2 0 1 0 7 60 -1 18 0.000 0 0 -1 0 0 5
+	 2100 1200 3000 1200 3000 1500 2100 1500 2100 1200
+4 1 0 50 -1 0 11 0.0000 2 195 780 4350 1425 $\\pm$Size\001
+4 1 0 50 -1 0 11 0.0000 2 135 330 1650 1425 Size\001
+4 1 0 50 -1 0 11 0.0000 2 135 660 2550 1425 Previous\001
+4 1 0 50 -1 0 11 0.0000 2 135 375 3450 1425 Next\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/Container.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/Container.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/Container.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,29 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1200 1125 2100 1575
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1275 1200 2025 1200 2025 1500 1275 1500 1275 1200
+4 1 0 50 -1 0 11 0.0000 2 135 555 1650 1425 Header\001
+-6
+6 1950 1125 2850 1575
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2025 1200 2775 1200 2775 1500 2025 1500 2025 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 2400 1425 Object$_1$\001
+-6
+6 2700 1125 3600 1575
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2775 1200 3525 1200 3525 1500 2775 1500 2775 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 3150 1425 Object$_2$\001
+-6
+6 3450 1125 4350 1575
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3525 1200 4275 1200 4275 1500 3525 1500 3525 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 3900 1425 Object$_3$\001
+-6
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ContainerFalseSharing1.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ContainerFalseSharing1.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ContainerFalseSharing1.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,48 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 2100.000 1762.500 1800 1200 2100 1125 2400 1200
+	1 1 1.00 45.00 90.00
+6 1050 1200 1950 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 1800 1200 1800 1500 1200 1500 1200 1200
+4 1 0 50 -1 0 11 0.0000 2 195 765 1500 1425 Heap$_1$\001
+-6
+6 2250 1200 3150 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1200 3000 1200 3000 1500 2400 1500 2400 1200
+4 1 0 50 -1 0 11 0.0000 2 195 765 2700 1425 Heap$_2$\001
+-6
+6 1200 1950 3000 2250
+6 1200 1950 1800 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1950 1800 1950 1800 2250 1200 2250 1200 1950
+4 1 0 50 -1 0 11 0.0000 2 135 555 1500 2175 Header\001
+-6
+6 1650 1950 2550 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1950 2400 1950 2400 2250 1800 2250 1800 1950
+4 1 0 50 -1 0 11 0.0000 2 195 870 2100 2175 Object$_1$\001
+-6
+6 2400 1950 3000 2250
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 2400 1950 3000 1950 3000 2250 2400 2250 2400 1950
+4 1 0 50 -1 0 11 0.0000 2 135 345 2700 2175 Free\001
+-6
+-6
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 4
+	1 1 1.00 45.00 90.00
+	 1200 1350 1050 1350 1050 2100 1200 2100
+2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1650 1500 2100 1950
+4 2 0 50 -1 0 11 0.0000 2 90 315 975 1875 own\001
+4 0 0 50 -1 0 11 0.0000 2 180 510 1950 1725 modify\001
+4 1 0 50 -1 0 11 0.0000 2 180 2370 1875 825 pass object container indirectly\001
+4 1 0 50 -1 0 11 0.0000 2 180 1410 2025 1050 via the global heap\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ContainerFalseSharing2.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ContainerFalseSharing2.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ContainerFalseSharing2.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,48 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1050 1200 1950 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 1800 1200 1800 1500 1200 1500 1200 1200
+4 1 0 50 -1 0 11 0.0000 2 195 765 1500 1425 Heap$_1$\001
+-6
+6 2250 1200 3150 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1200 3000 1200 3000 1500 2400 1500 2400 1200
+4 1 0 50 -1 0 11 0.0000 2 195 765 2700 1425 Heap$_2$\001
+-6
+6 1200 1950 3150 2250
+6 1200 1950 1800 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1950 1800 1950 1800 2250 1200 2250 1200 1950
+4 1 0 50 -1 0 11 0.0000 2 135 555 1500 2175 Header\001
+-6
+6 1650 1950 2550 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1950 2400 1950 2400 2250 1800 2250 1800 1950
+4 1 0 50 -1 0 11 0.0000 2 195 870 2100 2175 Object$_1$\001
+-6
+6 2250 1950 3150 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1950 3000 1950 3000 2250 2400 2250 2400 1950
+4 1 0 50 -1 0 11 0.0000 2 195 870 2700 2175 Object$_2$\001
+-6
+-6
+2 1 0 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1650 1500 2100 1950
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 4
+	1 1 1.00 45.00 90.00
+	 3000 1350 3150 1350 3150 2100 3000 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 1500 2550 1950
+4 0 0 50 -1 0 11 0.0000 2 180 510 1950 1725 modify\001
+4 0 0 50 -1 0 11 0.0000 2 135 360 2625 1725 alloc\001
+4 0 0 50 -1 0 11 0.0000 2 90 315 3225 1725 own\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ContainerNoOwnership.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ContainerNoOwnership.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ContainerNoOwnership.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,56 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1350 1200 1950 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1350 1200 1950 1200 1950 1500 1350 1500 1350 1200
+4 1 0 50 -1 0 11 0.0000 2 135 555 1650 1425 Header\001
+-6
+6 1800 1800 2700 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 1800 2550 1800 2550 2100 1950 2100 1950 1800
+4 1 0 50 -1 0 11 0.0000 2 195 765 2250 2025 Heap$_1$\001
+-6
+6 1800 1200 2700 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 1200 2550 1200 2550 1500 1950 1500 1950 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 2250 1425 Object$_1$\001
+-6
+6 2400 1200 3300 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2550 1200 3150 1200 3150 1500 2550 1500 2550 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 2850 1425 Object$_2$\001
+-6
+6 3000 1200 3900 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3150 1200 3750 1200 3750 1500 3150 1500 3150 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 3450 1425 Object$_3$\001
+-6
+6 2700 1800 3600 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2850 1800 3450 1800 3450 2100 2850 2100 2850 1800
+4 1 0 50 -1 0 11 0.0000 2 195 765 3150 2025 Heap$_2$\001
+-6
+6 3750 1200 4350 1500
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3750 1200 4350 1200 4350 1500 3750 1500 3750 1200
+4 1 0 50 -1 0 11 0.0000 2 135 345 4050 1425 Free\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1950 1800 1950 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 1800 2550 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2850 1800 2550 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3450 1800 3750 1500
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ContainerNoOwnershipFreelist.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ContainerNoOwnershipFreelist.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ContainerNoOwnershipFreelist.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,68 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1425 2400 1425 2400 1650 2100 1650 2100 1425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3075 1425 3375 1425 3375 1650 3075 1650 3075 1425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1650 1425 2100 1425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2175 1500 2100 2325
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3150 1500 3075 2325
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2175 3450 3075 1425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3150 2400 2475 3375
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2175 2400 3075 3375
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1350 1275 1650 1275 1650 1575 1350 1575 1350 1275
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 1950 1350 2850 1350 2850 1800 1950 1800 1950 1350
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 3000 1350 3900 1350 3900 1800 3000 1800 3000 1350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1200 4050 1200 4050 1950 1800 1950 1800 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3075 3375 3375 3375 3375 3600 3075 3600 3075 3375
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 3375 2400 3375 2400 3600 2100 3600 2100 3375
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1350 3225 1650 3225 1650 3525 1350 3525 1350 3225
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1650 3375 2100 3375
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 1950 3300 2850 3300 2850 3750 1950 3750 1950 3300
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 3000 3300 3900 3300 3900 3750 3000 3750 3000 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 3150 4050 3150 4050 3900 1800 3900 1800 3150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 2325 2400 2325 2400 2550 2100 2550 2100 2325
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3075 2325 3375 2325 3375 2550 3075 2550 3075 2325
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 1950 2250 2850 2250 2850 2700 1950 2700 1950 2250
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 3000 2250 3900 2250 3900 2700 3000 2700 3000 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 2100 4050 2100 4050 2850 1800 2850 1800 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2475 3375 2775 3375 2775 3600 2475 3600 2475 3375
+4 1 0 50 -1 0 11 0.0000 2 195 495 1500 1500 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 1500 3450 H$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ContainerOwnership.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ContainerOwnership.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ContainerOwnership.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,81 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1200 1200 1800 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 1800 1200 1800 1500 1200 1500 1200 1200
+4 1 0 50 -1 0 11 0.0000 2 135 555 1500 1425 Header\001
+-6
+6 1650 1200 2550 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1200 2400 1200 2400 1500 1800 1500 1800 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 2100 1425 Object$_1$\001
+-6
+6 1650 1800 2550 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1800 2400 1800 2400 2100 1800 2100 1800 1800
+4 1 0 50 -1 0 11 0.0000 2 195 765 2100 2025 Heap$_1$\001
+-6
+6 2400 1200 3000 1500
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 2400 1200 3000 1200 3000 1500 2400 1500 2400 1200
+4 1 0 50 -1 0 11 0.0000 2 135 345 2700 1425 Free\001
+-6
+6 3000 1200 3600 1500
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1200 3600 1200 3600 1500 3000 1500 3000 1200
+4 1 0 50 -1 0 11 0.0000 2 135 345 3300 1425 Free\001
+-6
+6 4500 1200 5100 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4500 1200 5100 1200 5100 1500 4500 1500 4500 1200
+4 1 0 50 -1 0 11 0.0000 2 135 555 4800 1425 Header\001
+-6
+6 4950 1200 5850 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5100 1200 5700 1200 5700 1500 5100 1500 5100 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 5400 1425 Object$_2$\001
+-6
+6 5550 1200 6450 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5700 1200 6300 1200 6300 1500 5700 1500 5700 1200
+4 1 0 50 -1 0 11 0.0000 2 195 870 6000 1425 Object$_3$\001
+-6
+6 6300 1200 6900 1500
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 6300 1200 6900 1200 6900 1500 6300 1500 6300 1200
+4 1 0 50 -1 0 11 0.0000 2 135 345 6600 1425 Free\001
+-6
+6 5250 1800 6150 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5400 1800 6000 1800 6000 2100 5400 2100 5400 1800
+4 1 0 50 -1 0 11 0.0000 2 195 765 5700 2025 Heap$_2$\001
+-6
+6 3600 1200 4200 1500
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3600 1200 4200 1200 4200 1500 3600 1500 3600 1200
+4 1 0 50 -1 0 11 0.0000 2 135 345 3900 1425 Free\001
+-6
+6 6900 1200 7500 1500
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 6900 1200 7500 1200 7500 1500 6900 1500 6900 1200
+4 1 0 50 -1 0 11 0.0000 2 135 345 7200 1425 Free\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1800 1800 1800 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2400 1800 2400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5400 1800 5100 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 6000 1800 6300 1500
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ContainerOwnershipFreelist.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ContainerOwnershipFreelist.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ContainerOwnershipFreelist.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,63 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1425 2400 1425 2400 1650 2100 1650 2100 1425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3075 1425 3375 1425 3375 1650 3075 1650 3075 1425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1650 1425 2100 1425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2175 1500 2100 2325
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2175 2400 3075 1425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3150 1500 3075 2325
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1350 1275 1650 1275 1650 1575 1350 1575 1350 1275
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 1950 1350 2850 1350 2850 1800 1950 1800 1950 1350
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 3000 1350 3900 1350 3900 1800 3000 1800 3000 1350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1200 4050 1200 4050 1950 1800 1950 1800 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 3375 2400 3375 2400 3600 2100 3600 2100 3375
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1650 3375 2100 3375
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1350 3225 1650 3225 1650 3525 1350 3525 1350 3225
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3150 3375 3450 3375 3450 3600 3150 3600 3150 3375
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2175 3450 3150 3375
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 1950 3300 2850 3300 2850 3750 1950 3750 1950 3300
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 3000 3300 3900 3300 3900 3750 3000 3750 3000 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 3150 4050 3150 4050 3900 1800 3900 1800 3150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3075 2325 3375 2325 3375 2550 3075 2550 3075 2325
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 2325 2400 2325 2400 2550 2100 2550 2100 2325
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 1950 2250 2850 2250 2850 2700 1950 2700 1950 2250
+2 2 1 1 0 7 50 -1 -1 6.000 0 0 -1 0 0 5
+	 3000 2250 3900 2250 3900 2700 3000 2700 3000 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 2100 4050 2100 4050 2850 1800 2850 1800 2100
+4 1 0 50 -1 0 11 0.0000 2 195 495 1500 1500 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 1500 3450 H$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ContigFragmentation.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ContigFragmentation.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ContigFragmentation.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,22 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 900 1500 1800 1500 1800 1800 900 1800 900 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1500 2400 1500 2400 1800 1800 1800 1800 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1500 3000 1500 3000 1800 2400 1800 2400 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 900 1800 1500 1800 1500 2100 900 2100 900 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1500 1800 2700 1800 2700 2100 1500 2100 1500 1800
+2 3 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 7
+	 900 2400 3000 2400 3000 1800 2700 1800 2700 2100 900 2100
+	 900 2400
Index: doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingA.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingA.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingA.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,30 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2325 1500 2325 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2625 1500 3225 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1200 3750 1200 3750 1500 3000 1500 3000 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1200 2850 1200 2850 1500 2100 1500 2100 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 2100 2850 2100 2850 2400 2100 2400 2100 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2850 2100 3600 2100 3600 2400 2850 2400 2850 2100
+4 2 0 50 -1 0 11 0.0000 2 150 405 2250 1875 alloc\001
+4 0 0 50 -1 0 11 0.0000 2 150 405 3075 1875 alloc\001
+4 2 0 50 -1 0 11 0.0000 2 150 570 1950 2325 Cache\001
+4 1 0 50 -1 0 11 0.0000 2 210 855 2475 1425 Task$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 210 855 3375 1425 Task$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 210 1005 2475 2325 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 210 1005 3225 2325 Object$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingB.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingB.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingB.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,33 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 2962.500 1912.500 2475 1200 2925 1050 3450 1200
+	1 1 1.00 45.00 90.00
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1200 2850 1200 2850 1500 2100 1500 2100 1200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3300 1500 3300 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 1500 2550 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1200 3750 1200 3750 1500 3000 1500 3000 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2175 2100 2925 2100 2925 2400 2175 2400 2175 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2925 2100 3675 2100 3675 2400 2925 2400 2925 2100
+4 1 0 50 -1 0 11 0.0000 2 210 855 2475 1425 Task$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 210 855 3375 1425 Task$_2$\001
+4 2 0 50 -1 0 11 0.0000 2 195 585 2475 1875 modify\001
+4 0 0 50 -1 0 11 0.0000 2 195 585 3375 1875 modify\001
+4 2 0 50 -1 0 11 0.0000 2 150 570 2025 2325 Cache\001
+4 1 0 50 -1 0 11 0.0000 2 210 1005 2550 2325 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 210 1005 3300 2325 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 210 1440 3000 975 pass Object$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingC.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingC.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingC.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,30 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1200 2850 1200 2850 1500 2100 1500 2100 1200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3300 1500 3300 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 1500 2550 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1200 3750 1200 3750 1500 3000 1500 3000 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2175 2100 2925 2100 2925 2400 2175 2400 2175 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2925 2100 3675 2100 3675 2400 2925 2400 2925 2100
+4 1 0 50 -1 0 11 0.0000 2 195 735 2475 1425 Task$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 735 3375 1425 Task$_2$\001
+4 2 0 50 -1 0 11 0.0000 2 180 510 2475 1875 modify\001
+4 0 0 50 -1 0 11 0.0000 2 135 540 3375 1875 dealloc\001
+4 2 0 50 -1 0 11 0.0000 2 135 480 2025 2325 Cache\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2550 2325 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3300 2325 Object$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingD.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingD.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/FalseSharingD.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,30 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2325 1500 2325 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2625 1500 3225 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1200 3750 1200 3750 1500 3000 1500 3000 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1200 2850 1200 2850 1500 2100 1500 2100 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 2100 2850 2100 2850 2400 2100 2400 2100 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2850 2100 3600 2100 3600 2400 2850 2400 2850 2100
+4 2 0 50 -1 0 11 0.0000 2 180 510 2250 1875 modify\001
+4 0 0 50 -1 0 11 0.0000 2 135 360 3075 1875 alloc\001
+4 2 0 50 -1 0 11 0.0000 2 135 480 1950 2325 Cache\001
+4 1 0 50 -1 0 11 0.0000 2 195 735 2475 1425 Task$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 735 3375 1425 Task$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2475 2325 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3225 2325 Object$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/FreeListAmongContainers.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/FreeListAmongContainers.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/FreeListAmongContainers.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,69 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 2400 600 3000 900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 600 3000 600 3000 900 2400 900 2400 600
+4 1 0 50 -1 0 11 0.0000 2 180 405 2700 825 Heap\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3300 1500 3600 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3900 2100 3000 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3300 2400 4200 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4500 2100 4200 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 900 3000 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1200 3000 1200 3000 1500 2400 1500 2400 1200
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1200 3600 1200 3600 1500 3000 1500 3000 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1200 4200 1200 4200 1500 3600 1500 3600 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4200 1200 4800 1200 4800 1500 4200 1500 4200 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1800 3000 1800 3000 2100 2400 2100 2400 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 2400 3000 2400 3000 2700 2400 2700 2400 2400
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3000 2400 3600 2400 3600 2700 3000 2700 3000 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1800 3600 1800 3600 2100 3000 2100 3000 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 2400 4200 2400 4200 2700 3600 2700 3600 2400
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3600 1800 4200 1800 4200 2100 3600 2100 3600 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 4200 1800 4800 1800 4800 2100 4200 2100 4200 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 4200 2400 4800 2400 4800 2700 4200 2700 4200 2400
+2 1 0 0 7 7 50 -1 -1 0.000 0 0 -1 0 0 1
+	 2400 2850
+4 1 0 50 -1 0 11 0.0000 2 135 555 2700 1425 Header\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 3300 1425 Free\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3900 1425 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4500 1425 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 135 555 2700 2025 Header\001
+4 1 0 50 -1 0 11 0.0000 2 135 555 2700 2625 Header\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 3300 2625 Free\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3300 2025 Object$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3900 2625 Object$_4$\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 3900 2025 Free\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 4500 2025 Free\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 4500 2625 Free\001
+4 0 0 50 -1 0 11 0.0000 2 180 1110 3150 825 object free-list\001
+4 1 0 50 -1 0 11 0.0000 2 135 795 3750 1125 containers\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/FreeListWithinContainers.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/FreeListWithinContainers.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/FreeListWithinContainers.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,72 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 2850.000 1500.000 2700 1500 2850 1650 3000 1500
+	1 1 1.00 45.00 90.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 2850.000 2700.000 2700 2700 2850 2850 3000 2700
+	1 1 1.00 45.00 90.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 3150.000 1500.000 2700 2100 3150 2250 3600 2100
+	1 1 1.00 45.00 90.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 4050.000 2100.000 3900 2100 4050 2250 4200 2100
+	1 1 1.00 45.00 90.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 1 1 0 3750.000 2100.000 3300 2700 3750 2850 4200 2700
+	1 1 1.00 45.00 90.00
+6 2400 600 3000 900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 600 3000 600 3000 900 2400 900 2400 600
+4 1 0 50 -1 0 11 0.0000 2 180 405 2700 825 Heap\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1200 3000 1200 3000 1500 2400 1500 2400 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1800 3000 1800 3000 2100 2400 2100 2400 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 2400 3000 2400 3000 2700 2400 2700 2400 2400
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1200 3600 1200 3600 1500 3000 1500 3000 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1800 3600 1800 3600 2100 3000 2100 3000 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3000 2400 3600 2400 3600 2700 3000 2700 3000 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 900 2400 1200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 1500 2400 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 2100 2400 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1200 4200 1200 4200 1500 3600 1500 3600 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 2400 4200 2400 4200 2700 3600 2700 3600 2400
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3600 1800 4200 1800 4200 2100 3600 2100 3600 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4200 1200 4800 1200 4800 1500 4200 1500 4200 1200
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 4200 1800 4800 1800 4800 2100 4200 2100 4200 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 4200 2400 4800 2400 4800 2700 4200 2700 4200 2400
+4 0 0 50 -1 0 11 0.0000 2 135 1350 3150 825 container free-list\001
+4 1 0 50 -1 0 11 0.0000 2 135 555 2700 1425 Header\001
+4 1 0 50 -1 0 11 0.0000 2 135 555 2700 2025 Header\001
+4 1 0 50 -1 0 11 0.0000 2 135 555 2700 2625 Header\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 3300 1425 Free\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3300 2025 Object$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 3225 2625 Free\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3900 1425 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 3900 2025 Free\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3900 2625 Object$_4$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4500 1425 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 4500 2025 Free\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 4500 2625 Free\001
+4 1 0 50 -1 0 11 0.0000 2 135 795 3750 1125 containers\001
+4 0 0 50 -1 0 11 0.0000 2 180 1110 3150 1650 object free-list\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/HeapStructure.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/HeapStructure.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/HeapStructure.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,103 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1650 1200 2250 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1950 1350 150 150 1950 1350 2100 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 1950 1425 T$_2$\001
+-6
+6 1200 1200 1800 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1500 1350 150 150 1500 1350 1650 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 1500 1425 T$_1$\001
+-6
+6 2100 1200 2700 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2400 1350 150 150 2400 1350 2550 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 2400 1425 T$_3$\001
+-6
+6 2700 3000 3000 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 3000 3000 3000 3000 3300 2700 3300 2700 3000
+4 1 0 50 -1 0 11 0.0000 2 135 135 2850 3225 G\001
+-6
+6 1650 2400 2250 2700
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1950 2550 150 150 1950 2550 2100 2550
+4 1 0 50 -1 0 11 0.0000 2 195 465 1950 2625 T$_2$\001
+-6
+6 1200 2400 1800 2700
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1500 2550 150 150 1500 2550 1650 2550
+4 1 0 50 -1 0 11 0.0000 2 195 465 1500 2625 T$_1$\001
+-6
+6 2100 2400 2700 2700
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2400 2550 150 150 2400 2550 2550 2550
+4 1 0 50 -1 0 11 0.0000 2 195 465 2400 2625 T$_3$\001
+-6
+6 1650 3600 2250 4500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1950 3750 150 150 1950 3750 2100 3750
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1950 3900 1950 4200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 4200 2100 4200 2100 4500 1800 4500 1800 4200
+4 1 0 50 -1 0 11 0.0000 2 195 495 1950 4425 H$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 465 1950 3825 T$_2$\001
+-6
+6 1200 3600 1800 4500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1500 3750 150 150 1500 3750 1650 3750
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1500 3900 1500 4200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1350 4200 1650 4200 1650 4500 1350 4500 1350 4200
+4 1 0 50 -1 0 11 0.0000 2 195 495 1500 4425 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 465 1500 3825 T$_1$\001
+-6
+6 2100 3600 2700 4500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2400 3750 150 150 2400 3750 2550 3750
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2400 3900 2400 4200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2250 4200 2550 4200 2550 4500 2250 4500 2250 4200
+4 1 0 50 -1 0 11 0.0000 2 195 495 2400 4425 H$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 465 2400 3825 T$_3$\001
+-6
+6 2850 4200 3150 4500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2850 4200 3150 4200 3150 4500 2850 4500 2850 4200
+4 1 0 50 -1 0 11 0.0000 2 135 135 3000 4425 G\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1500 1500 1950 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1950 1500 1950 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2400 1500 1950 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1800 2100 1800 2100 2100 1800 2100 1800 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1500 2700 1650 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1500 2700 2250 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1950 2700 1650 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1950 2700 2250 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2400 2700 2250 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1500 3000 1800 3000 1800 3300 1500 3300 1500 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 3000 2400 3000 2400 3300 2100 3300 2100 3000
+4 1 0 50 -1 0 11 0.0000 2 195 495 1950 2025 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 2250 2025 $\\Leftrightarrow$\001
+4 0 0 50 -1 0 11 0.0000 2 135 240 2400 2025 OS\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 1650 3225 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 2250 3225 H$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 2550 3225 $\\Leftrightarrow$\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 3150 3225 $\\Leftrightarrow$\001
+4 0 0 50 -1 0 11 0.0000 2 135 240 3300 3225 OS\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 2700 4425 $\\Leftrightarrow$\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 3300 4425 $\\Leftrightarrow$\001
+4 0 0 50 -1 0 11 0.0000 2 135 240 3450 4425 OS\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/IntExtFragmentation.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/IntExtFragmentation.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/IntExtFragmentation.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,74 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 3150 1200 3900 1500
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3150 1200 3900 1200 3900 1500 3150 1500 3150 1200
+4 1 0 50 -1 0 11 0.0000 2 180 600 3525 1425 Spacing\001
+-6
+6 4425 1125 5775 1575
+2 2 0 2 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4500 1200 5700 1200 5700 1500 4500 1500 4500 1200
+4 1 0 50 -1 0 11 0.0000 2 180 1020 5100 1425 Free Memory\001
+-6
+6 1200 1575 2550 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1200 1575 1200 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1500 1650 1200 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2250 1650 2550 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2550 1575 2550 1725
+4 1 0 50 -1 0 11 0.0000 2 135 570 1875 1725 internal\001
+-6
+6 3150 1575 4500 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3150 1575 3150 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3450 1650 3150 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4200 1650 4500 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4500 1575 4500 1725
+4 1 0 50 -1 0 11 0.0000 2 135 570 3825 1725 internal\001
+-6
+6 4500 1575 5700 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4500 1575 4500 1725
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4725 1650 4500 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5475 1650 5700 1650
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5700 1575 5700 1725
+4 1 0 50 -1 0 11 0.0000 2 135 615 5100 1725 external\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2550 1200 2550 1500
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 1800 1200 2550 1200 2550 1500 1800 1500 1800 1200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3150 1200 3150 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3900 1200 3900 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1800 1200 1800 1500
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 4500 1200 4500 1500 1200 1500 1200 1200
+4 1 0 50 -1 0 11 0.0000 2 135 555 1500 1425 Header\001
+4 1 0 50 -1 0 11 0.0000 2 180 600 2175 1425 Padding\001
+4 1 0 50 -1 0 11 0.0000 2 180 510 2850 1425 Object\001
+4 1 0 50 -1 0 11 0.0000 2 135 495 4200 1425 Trailer\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/MemoryFragmentation.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/MemoryFragmentation.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/MemoryFragmentation.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,64 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 600 3600 600 3600 900 2100 900 2100 600
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 600 4500 600 4500 900 3600 900 3600 600
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 2100 1050 3600 1050 3600 1350 2100 1350 2100 1050
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1050 4500 1050 4500 1350 3600 1350 3600 1050
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1500 4500 1500 4500 1800 3600 1800 3600 1500
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3300 1500 3600 1500 3600 1800 3300 1800 3300 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1500 3300 1500 3300 1800 2100 1800 2100 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1950 3300 1950 3300 2250 2100 2250 2100 1950
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3300 1950 3600 1950 3600 2250 3300 2250 3300 1950
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1950 4500 1950 4500 2250 3600 2250 3600 1950
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 1800 2400 2100 2400 2100 2700 1800 2700 1800 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 2400 3300 2400 3300 2700 2100 2700 2100 2400
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3300 2400 3600 2400 3600 2700 3300 2700 3300 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 2400 4500 2400 4500 2700 3600 2700 3600 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 900 2400 1800 2400 1800 2700 900 2700 900 2400
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 900 1950 2100 1950 2100 2250 900 2250 900 1950
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 900 1500 2100 1500 2100 1800 900 1800 900 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 900 1050 2100 1050 2100 1350 900 1350 900 1050
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 900 600 2100 600 2100 900 900 900 900 600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 750 600 750 2700
+4 1 0 50 -1 0 11 0.0000 2 195 870 2850 825 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4050 825 Object$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4050 1275 Object$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4050 1725 Object$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4050 2175 Object$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4050 2625 Object$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2700 1725 Object$_4$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2700 2625 Object$_4$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2700 2175 Object$_4$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 1500 825 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 1500 1275 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 1500 1725 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 1350 2625 Object$_5$\001
+4 2 0 50 -1 0 11 0.0000 2 135 330 600 1725 time\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsNoOwnership.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsNoOwnership.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsNoOwnership.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,43 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1050 1800 1650 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 2100 1500 2100 1500 1800 1200 1800 1200 2100
+4 1 0 50 -1 0 11 0.0000 2 195 495 1350 2025 H$_1$\001
+-6
+6 1950 1800 2550 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 2100 2400 2100 2400 1800 2100 1800 2100 2100
+4 1 0 50 -1 0 11 0.0000 2 195 495 2250 2025 H$_2$\001
+-6
+1 3 0 1 0 7 50 -1 -1 0.000 0 -0.0000 1350 1350 150 150 1350 1350 1500 1350
+1 3 0 1 0 7 50 -1 -1 0.000 0 -0.0000 2250 1350 150 150 2250 1350 2400 1350
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1275 1800 1275 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	0 0 1.00 45.00 90.00
+	 1425 1500 1425 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2
+	0 0 1.00 45.00 90.00
+	 1425 1500 2175 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2
+	0 0 1.00 45.00 90.00
+	 2175 1500 1425 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	0 0 1.00 45.00 90.00
+	 2175 1500 2175 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 2325 1800 2325 1500
+4 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsOwnership.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsOwnership.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsOwnership.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,39 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1050 1800 1650 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 2100 1500 2100 1500 1800 1200 1800 1200 2100
+4 1 0 50 -1 0 11 0.0000 2 195 495 1350 2025 H$_1$\001
+-6
+6 1950 1800 2550 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 2100 2400 2100 2400 1800 2100 1800 2100 2100
+4 1 0 50 -1 0 11 0.0000 2 195 495 2250 2025 H$_2$\001
+-6
+1 3 0 1 0 7 50 -1 -1 0.000 0 -0.0000 1350 1350 150 150 1350 1350 1500 1350
+1 3 0 1 0 7 50 -1 -1 0.000 0 -0.0000 2250 1350 150 150 2250 1350 2400 1350
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 2175 1500 1425 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1425 1500 2175 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1275 1800 1275 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 2325 1800 2325 1500
+4 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsStorage.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsStorage.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/MultipleHeapsStorage.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,172 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 3000 1500 3450 1800
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1500 3300 1500 3300 1800 3000 1800 3000 1500
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 1750 H$_1$\001
+-6
+6 3300 1500 3750 1800
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3300 1500 3600 1500 3600 1800 3300 1800 3300 1500
+4 0 0 50 -1 0 9 0.0000 2 165 420 3325 1750 H$_2$\001
+-6
+6 4500 1500 5100 1800
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4500 1500 5100 1500 5100 1800 4500 1800 4500 1500
+4 0 0 50 -1 0 9 0.0000 2 165 420 4525 1750 H$_3$\001
+-6
+6 4050 1800 4650 2100
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4050 1800 4650 1800 4650 2100 4050 2100 4050 1800
+4 0 0 50 -1 0 9 0.0000 2 165 420 4075 2050 H$_1$\001
+-6
+6 4500 2400 5100 2700
+2 2 0 1 0 7 60 -1 13 0.000 0 0 -1 0 0 5
+	 4500 2400 5100 2400 5100 2700 4500 2700 4500 2400
+4 0 0 50 -1 0 9 0.0000 2 165 420 4525 2650 H$_2$\001
+-6
+6 3600 2100 4050 2400
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3600 2100 3900 2100 3900 2400 3600 2400 3600 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 3625 2350 H$_1$\001
+-6
+6 5100 2100 5550 2400
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 5100 2100 5400 2100 5400 2400 5100 2400 5100 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 5125 2350 H$_3$\001
+-6
+6 5700 2100 6150 2400
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 5700 2100 6000 2100 6000 2400 5700 2400 5700 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 5725 2350 H$_3$\001
+-6
+6 5250 1800 5700 2100
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 5250 1800 5550 1800 5550 2100 5250 2100 5250 1800
+4 0 0 50 -1 0 9 0.0000 2 165 420 5275 2050 H$_3$\001
+-6
+6 3600 1500 4200 1800
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1500 4200 1500 4200 1800 3600 1800 3600 1500
+4 0 0 50 -1 0 9 0.0000 2 165 390 3625 1750 T$_1$\001
+-6
+6 4200 1500 4650 1800
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 4200 1500 4500 1500 4500 1800 4200 1800 4200 1500
+4 0 0 50 -1 0 9 0.0000 2 165 390 4225 1750 T$_2$\001
+-6
+6 5100 1500 6000 1800
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 5100 1500 6000 1500 6000 1800 5100 1800 5100 1500
+4 0 0 50 -1 0 9 0.0000 2 165 390 5125 1750 T$_3$\001
+-6
+6 3600 1800 4050 2100
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1800 4050 1800 4050 2100 3600 2100 3600 1800
+4 0 0 50 -1 0 9 0.0000 2 165 390 3625 2050 T$_4$\001
+-6
+6 4950 1800 5400 2100
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 4950 1800 5250 1800 5250 2100 4950 2100 4950 1800
+4 0 0 50 -1 0 9 0.0000 2 165 390 4975 2050 T$_5$\001
+-6
+6 4650 1800 5100 2100
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 4650 1800 4950 1800 4950 2100 4650 2100 4650 1800
+4 0 0 50 -1 0 9 0.0000 2 165 390 4675 2050 T$_6$\001
+-6
+6 5550 1800 6000 2100
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 5550 1800 6000 1800 6000 2100 5550 2100 5550 1800
+4 0 0 50 -1 0 9 0.0000 2 165 390 5575 2050 T$_4$\001
+-6
+6 3000 1800 3600 2100
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1800 3600 1800 3600 2100 3000 2100 3000 1800
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 2050 H$_2$\001
+-6
+6 3000 2100 3450 2400
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3000 2100 3300 2100 3300 2400 3000 2400 3000 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 2350 H$_3$\001
+-6
+6 3300 2100 3750 2400
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3300 2100 3600 2100 3600 2400 3300 2400 3300 2100
+4 0 0 50 -1 0 9 0.0000 2 165 390 3325 2350 T$_2$\001
+-6
+6 5400 2100 5850 2400
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 5400 2100 5700 2100 5700 2400 5400 2400 5400 2100
+4 0 0 50 -1 0 9 0.0000 2 165 390 5425 2350 T$_1$\001
+-6
+6 3900 2100 4500 2400
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3900 2100 4500 2100 4500 2400 3900 2400 3900 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 3925 2350 H$_2$\001
+-6
+6 4500 2100 5100 2400
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 4500 2100 5100 2100 5100 2400 4500 2400 4500 2100
+4 0 0 50 -1 0 9 0.0000 2 165 390 4525 2350 T$_2$\001
+-6
+6 5100 2400 6000 2700
+2 2 0 1 0 7 60 -1 13 0.000 0 0 -1 0 0 5
+	 5100 2400 6000 2400 6000 2700 5100 2700 5100 2400
+4 0 0 50 -1 0 9 0.0000 2 165 420 5125 2650 H$_1$\001
+-6
+6 3000 2400 4500 2700
+2 2 0 1 0 7 60 -1 13 0.000 0 0 -1 0 0 5
+	 3000 2400 4500 2400 4500 2700 3000 2700 3000 2400
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 2650 H$_3$\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2100 1200 2100 2700
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1500 2700 1800 2400 1800 2400 1500 2700 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 1800 2550 1950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1800 1650 2400 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1500 1800 1800 1500 1800 1500 1500 1800 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1950 2700 2250 2400 2250 2400 1950 2700 1950
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 2400 2700 2700 2400 2700 2400 2400 2700 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 2250 2550 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 2475 3000 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 1575 3000 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2704 1743 5100 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 2025 3000 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2709 2187 4500 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 2625 3000 2400
+4 1 0 50 -1 0 11 0.0000 2 135 885 1500 1350 Static Zone\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 2550 1725 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 180 1950 4050 1350 Dynamic-Allocation Zone\001
+4 1 0 50 -1 0 11 0.0000 2 135 225 1650 1725 Hs\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 2550 2625 H$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 2550 2175 H$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/NonContigFragmentation.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/NonContigFragmentation.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/NonContigFragmentation.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,31 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 2100 1200 2100 1500 1200 1500 1200 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1200 3000 1200 3000 1500 2400 1500 2400 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1500 3300 1500 3300 1800 2700 1800 2700 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1500 1500 2100 1500 2100 1800 1500 1800 1500 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1800 3000 1800 3000 2100 1800 2100 1800 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1800 3300 1800 3300 2100 3000 2100 3000 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1200 3300 1200 3300 1500 3000 1500 3000 1200
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 1200 1500 1500 1500 1500 1800 1200 1800 1200 1500
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 2100 1200 2400 1200 2400 1500 2100 1500 2100 1200
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 1200 1800 1800 1800 1800 2100 1200 2100 1200 1800
+2 2 0 1 0 7 50 -1 17 0.000 0 0 -1 0 0 5
+	 2100 1500 2700 1500 2700 1800 2100 1800 2100 1500
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ObjectHeaders.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ObjectHeaders.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ObjectHeaders.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,33 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1050 1125 2775 1575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1950 1200 1950 1500
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 2700 1200 2700 1500 1200 1500 1200 1200
+4 1 0 50 -1 0 11 0.0000 2 195 915 1575 1425 Header$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2325 1425 Object$_1$\001
+-6
+6 2550 1125 4275 1575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3450 1200 3450 1500
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1200 4200 1200 4200 1500 2700 1500 2700 1200
+4 1 0 50 -1 0 11 0.0000 2 195 915 3075 1425 Header$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3825 1425 Object$_2$\001
+-6
+6 4050 1125 5775 1575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4950 1200 4950 1500
+2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4200 1200 5700 1200 5700 1500 4200 1500 4200 1200
+4 1 0 50 -1 0 11 0.0000 2 195 915 4575 1425 Header$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 5325 1425 Object$_3$\001
+-6
Index: doc/theses/mubeen_zulfiqar_MMath/figures/PerThreadGlobalHeap2.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/PerThreadGlobalHeap2.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/PerThreadGlobalHeap2.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,109 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 2250 3975 2775 4200
+4 2 0 50 -1 0 11 0.0000 2 150 435 2625 4125 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 2650 4175 2\001
+-6
+6 2175 3075 2775 3300
+4 2 0 50 -1 0 11 0.0000 2 195 465 2625 3225 Heap\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 2650 3275 2\001
+-6
+6 1200 3000 1950 4200
+6 1350 3975 1875 4200
+4 2 0 50 -1 0 11 0.0000 2 150 435 1725 4125 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 1750 4175 1\001
+-6
+6 1275 3075 1875 3300
+4 2 0 50 -1 0 11 0.0000 2 195 465 1725 3225 Heap\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 1750 3275 1\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1425 3300 1425 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1725 3900 1725 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 3000 1950 3000 1950 3300 1200 3300 1200 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 3900 1950 3900 1950 4200 1200 4200 1200 3900
+4 1 0 50 -1 0 11 1.5708 2 150 405 1350 3600 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 150 615 1800 3600 dealloc\001
+-6
+6 3075 3075 3675 3300
+4 2 0 50 -1 0 11 0.0000 2 195 465 3525 3225 Heap\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 3550 3275 3\001
+-6
+6 3150 3975 3675 4200
+4 2 0 50 -1 0 11 0.0000 2 150 435 3525 4125 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 3550 4175 3\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1875 2400 1425 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1725 3000 2175 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2325 2400 2325 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2625 3000 2625 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3075 2400 3525 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3225 3000 2775 2400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1725 1200 3225 1200 3225 1500 1725 1500 1725 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1725 2100 3225 2100 3225 2400 1725 2400 1725 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2325 1500 2325 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2625 2100 2625 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2325 3300 2325 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2625 3900 2625 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 3000 2850 3000 2850 3300 2100 3300 2100 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 3900 2850 3900 2850 4200 2100 4200 2100 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3225 3300 3225 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3525 3900 3525 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 3900 3750 3900 3750 4200 3000 4200 3000 3900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 3000 3750 3000 3750 3300 3000 3300 3000 3000
+4 1 0 50 -1 0 11 0.0000 2 195 1545 2475 1425 Operating System\001
+4 1 0 50 -1 0 11 0.0000 2 195 1035 2475 2325 Gobal Heap\001
+4 1 0 50 -1 0 11 1.5708 2 150 405 2250 1800 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 150 615 2700 1800 dealloc\001
+4 1 0 50 -1 0 11 0.8727 2 150 405 1575 2700 alloc\001
+4 1 0 50 -1 0 11 0.8727 2 150 615 1875 2700 dealloc\001
+4 1 0 50 -1 0 11 1.5708 2 150 405 2250 2700 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 150 615 2700 2700 dealloc\001
+4 1 0 50 -1 0 11 5.4105 2 150 615 3450 2775 dealloc\001
+4 1 0 50 -1 0 11 5.4105 2 150 405 3150 2775 alloc\001
+4 1 0 50 -1 0 11 1.5708 2 150 405 2250 3600 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 150 615 2700 3600 dealloc\001
+4 1 0 50 -1 0 11 1.5708 2 150 405 3150 3600 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 150 615 3600 3600 dealloc\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/PerThreadHeap.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/PerThreadHeap.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/PerThreadHeap.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,44 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 2700 1800 3000 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1800 3000 1800 3000 2100 2700 2100 2700 1800
+4 1 0 50 -1 0 11 0.0000 2 135 135 2850 2025 G\001
+-6
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1350 1350 150 150 1350 1350 1500 1350
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1800 1350 150 150 1800 1350 1950 1350
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2250 1350 150 150 2250 1350 2400 1350
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1350 1500 1350 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1800 1500 1800 1500 2100 1200 2100 1200 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1650 1800 1950 1800 1950 2100 1650 2100 1650 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2100 1800 2400 1800 2400 2100 2100 2100 2100 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1800 1500 1800 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 2250 1500 2250 1800
+4 1 0 50 -1 0 11 0.0000 2 195 1320 2550 2025 $\\Leftrightarrow$\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 3150 2025 $\\Leftrightarrow$\001
+4 0 0 50 -1 0 11 0.0000 2 135 240 3300 2025 OS\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 1350 2025 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 1800 2025 H$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 465 1800 1425 T$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 2250 2025 H$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_3$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/PrivatePublicHeaps2.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/PrivatePublicHeaps2.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/PrivatePublicHeaps2.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,100 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1200 1200 2400 1500
+6 1200 1275 2400 1500
+4 2 0 50 -1 0 11 0.0000 2 180 915 2250 1425 Public Heap\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 2275 1475 1\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 2400 1200 2400 1500 1200 1500 1200 1200
+-6
+6 3900 1200 5100 1500
+6 3900 1275 5100 1500
+4 0 0 50 -1 0 9 0.0000 2 105 75 4975 1475 2\001
+4 2 0 50 -1 0 11 0.0000 2 180 915 4950 1425 Public Heap\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 1200 5100 1200 5100 1500 3900 1500 3900 1200
+-6
+6 1425 2100 2700 2400
+6 1425 2175 2550 2400
+4 2 0 50 -1 0 11 0.0000 2 180 990 2550 2325 Private Heap\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1500 2100 2700 2100 2700 2400 1500 2400 1500 2100
+4 0 0 50 -1 0 9 0.0000 2 105 75 2575 2375 1\001
+-6
+6 3525 2100 4800 2400
+6 3525 2175 4650 2400
+4 2 0 50 -1 0 11 0.0000 2 180 990 4650 2325 Private Heap\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 2100 4800 2100 4800 2400 3600 2400 3600 2100
+4 0 0 50 -1 0 9 0.0000 2 105 75 4675 2375 2\001
+-6
+6 1200 3000 2400 3300
+6 1575 3075 2100 3300
+4 2 0 50 -1 0 11 0.0000 2 135 375 1950 3225 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 1975 3275 1\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 3000 2400 3000 2400 3300 1200 3300 1200 3000
+-6
+6 3900 3000 5100 3300
+6 4275 3075 4800 3300
+4 2 0 50 -1 0 11 0.0000 2 135 375 4650 3225 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 4675 3275 2\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 3000 5100 3000 5100 3300 3900 3300 3900 3000
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1275 1500 1275 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1950 3000 1950 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1575 2400 1575 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5025 1500 5025 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4350 2400 4350 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4350 2100 4350 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4650 3000 4650 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3900 3000 2400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2400 3000 3900 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1950 2100 1950 1500
+4 1 0 50 -1 0 11 0.0000 2 180 540 3150 1425 locking\001
+4 1 0 50 -1 0 11 1.5708 2 135 540 1875 1800 dealloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 540 4425 1800 dealloc\001
+4 1 0 50 -1 0 11 1.5708 2 135 540 1875 2700 dealloc\001
+4 1 0 50 -1 0 11 1.5708 2 135 360 1500 2700 alloc\001
+4 1 0 50 -1 0 11 1.5708 2 135 360 1200 2250 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 540 4725 2700 dealloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 360 4425 2700 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 360 5100 2250 alloc\001
+4 1 0 50 -1 0 11 5.4803 2 135 540 3375 2775 dealloc\001
+4 1 0 50 -1 0 11 0.8029 2 180 780 2700 2625 ownership\001
+4 1 0 50 -1 0 11 0.8029 2 135 540 2925 2775 dealloc\001
+4 1 0 50 -1 0 11 5.4803 2 180 780 3600 2625 ownership\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/ProgramFalseSharing.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/ProgramFalseSharing.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/ProgramFalseSharing.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,56 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 4050.000 4662.500 2850 1575 4050 1350 5250 1575
+	1 1 1.00 45.00 90.00
+6 2550 3000 4350 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2550 3000 3450 3000 3450 3300 2550 3300 2550 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3450 3000 4350 3000 4350 3300 3450 3300 3450 3000
+4 1 0 50 -1 0 11 0.0000 2 195 870 3000 3225 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 3900 3225 Object$_2$\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1350 2100 2250 2100 2250 2400 1350 2400 1350 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2250 2100 3150 2100 3150 2400 2250 2400 2250 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1500 3300 1500 3300 2550 1200 2550 1200 1500
+2 2 0 1 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3750 2100 4650 2100 4650 2400 3750 2400 3750 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4650 2100 5550 2100 5550 2400 4650 2400 4650 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1500 5700 1500 5700 2550 3600 2550 3600 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2250 2550 3000 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4650 2550 3900 3000
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+	 3150 1800 3150 1575 2550 1575 2550 1800 3150 1800
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+	 5550 1800 5550 1575 4950 1575 4950 1800 5550 1800
+4 1 0 50 -1 0 11 0.0000 2 195 735 2850 1725 Task$_1$\001
+4 0 0 50 -1 0 11 0.0000 2 195 720 1275 1725 CPU$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 135 480 2250 2025 Cache\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 1800 2325 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 2700 2325 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 735 5250 1725 Task$_2$\001
+4 0 0 50 -1 0 11 0.0000 2 195 720 3675 1725 CPU$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 4200 2325 Object$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 870 5100 2325 Object$_2$\001
+4 1 0 50 -1 0 11 0.0000 2 135 480 4650 2025 Cache\001
+4 2 0 50 -1 0 11 0.0000 2 180 630 2475 3225 Memory\001
+4 2 0 50 -1 2 11 0.0000 2 135 585 2550 2850 1. alloc\001
+4 0 0 50 -1 2 11 0.0000 2 180 720 2700 2775 3. modify\001
+4 0 0 50 -1 2 11 0.0000 2 180 720 4350 2850 4. modify\001
+4 1 0 50 -1 2 11 0.0000 2 195 2400 4050 1275 2.  pass Object$_2$ reference\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/RemoteFreeList.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/RemoteFreeList.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/RemoteFreeList.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,88 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1125 1200 2400 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 2400 1200 2400 1500 1200 1500 1200 1200
+4 2 0 50 -1 0 11 0.0000 2 180 990 2250 1425 Private Heap\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 2275 1475 1\001
+-6
+6 3825 1200 5100 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 1200 5100 1200 5100 1500 3900 1500 3900 1200
+4 0 0 50 -1 0 9 0.0000 2 105 75 4975 1475 2\001
+4 2 0 50 -1 0 11 0.0000 2 180 990 4950 1425 Private Heap\001
+-6
+6 1725 2100 3000 2400
+6 1725 2175 2850 2325
+4 2 0 50 -1 0 11 0.0000 2 135 975 2850 2325 Remote Free\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 2100 3000 2100 3000 2400 1800 2400 1800 2100
+4 0 0 50 -1 0 9 0.0000 2 105 75 2875 2375 1\001
+-6
+6 3225 2100 4500 2400
+6 3225 2175 4350 2325
+4 2 0 50 -1 0 11 0.0000 2 135 975 4350 2325 Remote Free\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3300 2100 4500 2100 4500 2400 3300 2400 3300 2100
+4 0 0 50 -1 0 9 0.0000 2 105 75 4375 2375 2\001
+-6
+6 1200 3000 2400 3300
+6 1575 3075 2100 3300
+4 2 0 50 -1 0 11 0.0000 2 135 375 1950 3225 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 1975 3275 1\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 3000 2400 3000 2400 3300 1200 3300 1200 3000
+-6
+6 3900 3000 5100 3300
+6 4275 3075 4800 3300
+4 2 0 50 -1 0 11 0.0000 2 135 375 4650 3225 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 4675 3275 2\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 3000 5100 3000 5100 3300 3900 3300 3900 3000
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3900 3000 3000 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1275 1500 1275 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1575 3000 1575 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4725 3000 4725 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5025 1500 5025 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2400 3000 3300 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2100 2100 2100 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4200 2100 4200 1500
+4 1 0 50 -1 0 11 1.5708 2 135 540 1500 2250 dealloc\001
+4 1 0 50 -1 0 11 1.5708 2 135 360 1200 2250 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 540 4800 2250 dealloc\001
+4 1 0 50 -1 0 11 0.0000 2 180 540 3150 2025 locking\001
+4 1 0 50 -1 0 11 0.5934 2 135 540 2850 2925 dealloc\001
+4 1 0 50 -1 0 11 5.6898 2 135 540 3450 2925 dealloc\001
+4 1 0 50 -1 0 11 0.5934 2 180 780 2700 2725 ownership\001
+4 1 0 50 -1 0 11 5.6898 2 180 780 3600 2725 ownership\001
+4 1 0 50 -1 0 11 1.5708 2 135 360 2025 1800 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 360 5100 2250 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 360 4275 1800 alloc\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/SharedHeaps.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/SharedHeaps.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/SharedHeaps.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,59 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1500 1200 2100 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1800 1350 150 150 1800 1350 1950 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 1800 1425 T$_2$\001
+-6
+6 1050 1200 1650 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1350 1350 150 150 1350 1350 1500 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
+-6
+6 1950 1200 2550 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2250 1350 150 150 2250 1350 2400 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_3$\001
+-6
+6 1275 1800 1875 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1425 1800 1725 1800 1725 2100 1425 2100 1425 1800
+4 1 0 50 -1 0 11 0.0000 2 195 495 1575 2025 H$_1$\001
+-6
+6 1725 1800 2325 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1875 1800 2175 1800 2175 2100 1875 2100 1875 1800
+4 1 0 50 -1 0 11 0.0000 2 195 495 2025 2025 H$_2$\001
+-6
+6 2475 1800 2775 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2475 1800 2775 1800 2775 2100 2475 2100 2475 1800
+4 1 0 50 -1 0 11 0.0000 2 135 135 2625 2025 G\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1275 1500 1500 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1425 1500 1950 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1725 1500 1650 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1875 1500 2025 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 2250 1500 2100 1800
+4 0 0 50 -1 0 11 0.0000 2 135 240 3075 2025 OS\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 2325 2025 $\\Leftrightarrow$\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 2925 2025 $\\Leftrightarrow$\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/SingleHeap.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/SingleHeap.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/SingleHeap.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,38 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1500 1200 2100 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1800 1350 150 150 1800 1350 1950 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 1800 1425 T$_2$\001
+-6
+6 1050 1200 1650 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 1350 1350 150 150 1350 1350 1500 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 1350 1425 T$_1$\001
+-6
+6 1950 1200 2550 1500
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2250 1350 150 150 2250 1350 2400 1350
+4 1 0 50 -1 0 11 0.0000 2 195 465 2250 1425 T$_3$\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1350 1500 1725 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 2250 1500 1875 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1650 1800 1950 1800 1950 2100 1650 2100 1650 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	0 0 1.00 45.00 90.00
+	0 0 1.00 45.00 90.00
+	 1800 1500 1800 1800
+4 1 0 50 -1 0 11 0.0000 2 195 495 1800 2025 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 195 1320 2100 2025 $\\Leftrightarrow$\001
+4 0 0 50 -1 0 11 0.0000 2 135 240 2250 2025 OS\001
Index: doc/theses/mubeen_zulfiqar_MMath/figures/SuperContainers.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/figures/SuperContainers.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/figures/SuperContainers.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,66 @@
+#FIG 3.2  Produced by xfig version 3.2.5-alpha5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 2100.000 1425.000 1800 1200 2100 1050 2400 1200
+	1 1 1.00 45.00 90.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 2656.250 3062.500 2100 1050 2700 975 3600 1200
+	1 1 1.00 45.00 90.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 3300.000 7487.500 2700 975 3900 975 5100 1200
+	1 1 1.00 45.00 90.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 3825.000 13587.500 2700 975 4950 975 6450 1200
+	1 1 1.00 45.00 90.00
+5 1 0 1 0 7 50 -1 -1 0.000 0 0 1 0 2100.000 2025.000 1800 1800 2100 1650 2400 1800
+	1 1 1.00 45.00 90.00
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 2400 1200 2400 1500 1200 1500 1200 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1200 2700 1200 2700 1500 2400 1500 2400 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1200 3600 1200 3600 1500 2700 1500 2700 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1200 3900 1200 3900 1500 3600 1500 3600 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 1200 5100 1200 5100 1500 3900 1500 3900 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5100 1200 5400 1200 5400 1500 5100 1500 5100 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5400 1200 6450 1200 6450 1500 5400 1500 5400 1200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1800 2400 1800 2400 2100 1200 2100 1200 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2400 1800 2700 1800 2700 2100 2400 2100 2400 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 1200 2175 1200 2325
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4125 2250 1200 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4725 2250 7200 2250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1800 6450 1800 6450 2100 2700 2100 2700 1800
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 6450 1200 7200 1200 7200 1500 6450 1500 6450 1200
+2 2 0 1 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 6450 1800 7200 1800 7200 2100 6450 2100 6450 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 2175 7200 2325
+4 1 0 50 -1 0 11 0.0000 2 180 1035 1800 1425 Super Header\001
+4 1 0 50 -1 0 11 0.0000 2 180 810 3150 1425 8B objects\001
+4 1 0 50 -1 0 11 0.0000 2 135 135 3750 1425 H\001
+4 1 0 50 -1 0 11 0.0000 2 180 990 4500 1425 256B objects\001
+4 1 0 50 -1 0 11 0.0000 2 135 135 2550 1425 H\001
+4 1 0 50 -1 0 11 0.0000 2 135 135 5250 1425 H\001
+4 1 0 50 -1 0 11 0.0000 2 180 900 5925 1425 64B objects\001
+4 1 0 50 -1 0 11 0.0000 2 180 1035 1800 2025 Super Header\001
+4 1 0 50 -1 0 11 0.0000 2 135 135 2550 2025 H\001
+4 1 0 50 -1 0 11 0.0000 2 135 435 4425 2325 64KB\001
+4 1 0 50 -1 0 11 0.0000 2 180 945 4650 2025 4KB objects\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 6825 1425 Free\001
+4 1 0 50 -1 0 11 0.0000 2 135 345 6825 2025 Free\001
Index: doc/theses/mubeen_zulfiqar_MMath/intro.tex
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/intro.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/mubeen_zulfiqar_MMath/intro.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,4 +1,150 @@
 \chapter{Introduction}
 
+% Shared-memory multi-processor computers are ubiquitous and important for improving application performance.
+% However, writing programs that take advantage of multiple processors is not an easy task~\cite{Alexandrescu01b}, \eg shared resources can become a bottleneck when increasing (scaling) threads.
+% One crucial shared resource is program memory, since it is used by all threads in a shared-memory concurrent-program~\cite{Berger00}.
+% Therefore, providing high-performance, scalable memory-management is important for virtually all shared-memory multi-threaded programs.
+
+\vspace*{-23pt}
+Memory management takes a sequence of program generated allocation/deallocation requests and attempts to satisfy them within a fixed-sized block of memory while minimizing the total amount of memory used.
+A general-purpose dynamic-allocation algorithm cannot anticipate future allocation requests so its output is rarely optimal.
+However, memory allocators do take advantage of regularities in allocation patterns for typical programs to produce excellent results, both in time and space (similar to LRU paging).
+In general, allocators use a number of similar techniques, each optimizing specific allocation patterns.
+Nevertheless, memory allocators are a series of compromises, occasionally with some static or dynamic tuning parameters to optimize specific program-request patterns.
+
+
+\section{Memory Structure}
+\label{s:MemoryStructure}
+
+\VRef[Figure]{f:ProgramAddressSpace} shows the typical layout of a program's address space divided into the following zones (right to left): static code/data, dynamic allocation, dynamic code/data, and stack, with free memory surrounding the dynamic code/data~\cite{memlayout}.
+Static code and data are placed into memory at load time from the executable and are fixed-sized at runtime.
+Dynamic-allocation memory starts empty and grows/shrinks as the program dynamically creates/deletes variables with independent lifetime.
+The programming-language's runtime manages this area, where management complexity is a function of the mechanism for deleting variables.
+Dynamic code/data memory is managed by the dynamic loader for libraries loaded at runtime, which is complex especially in a multi-threaded program~\cite{Huang06}.
+However, changes to the dynamic code/data space are typically infrequent, many occurring at program startup, and are largely outside of a program's control.
+Stack memory is managed by the program call-mechanism using a simple LIFO technique, which works well for sequential programs.
+For multi-threaded programs (and coroutines), a new stack is created for each thread;
+these thread stacks are commonly created in dynamic-allocation memory.
+This thesis focuses on management of the dynamic-allocation memory.
+
+\begin{figure}
+\centering
+\input{AddressSpace}
+\vspace{-5pt}
+\caption{Program Address Space Divided into Zones}
+\label{f:ProgramAddressSpace}
+\end{figure}
+
+
+\section{Dynamic Memory-Management}
+\label{s:DynamicMemoryManagement}
+
+Modern programming languages manage dynamic-allocation memory in different ways.
+Some languages, such as Lisp~\cite{CommonLisp}, Java~\cite{Java}, Haskell~\cite{Haskell}, Go~\cite{Go}, provide explicit allocation but \emph{implicit} deallocation of data through garbage collection~\cite{Wilson92}.
+In general, garbage collection supports memory compaction, where dynamic (live) data is moved during runtime to better utilize space.
+However, moving data requires finding pointers to it and updating them to reflect new data locations.
+Programming languages such as C~\cite{C}, \CC~\cite{C++}, and Rust~\cite{Rust} provide the programmer with explicit allocation \emph{and} deallocation of data.
+These languages cannot find and subsequently move live data because pointers can be created to any storage zone, including internal components of allocated objects, and may contain temporary invalid values generated by pointer arithmetic.
+Attempts have been made to perform quasi garbage collection in C/\CC~\cite{Boehm88}, but it is a compromise.
+This thesis only examines dynamic memory-management with \emph{explicit} deallocation.
+While garbage collection and compaction are not part this work, many of the results are applicable to the allocation phase in any memory-management approach.
+
+Most programs use a general-purpose allocator, often the one provided implicitly by the programming-language's runtime.
+When this allocator proves inadequate, programmers often write specialize allocators for specific needs.
+C and \CC allow easy replacement of the default memory allocator with an alternative specialized or general-purpose memory-allocator.
+(Jikes RVM MMTk~\cite{MMTk} provides a similar generalization for the Java virtual machine.)
+However, high-performance memory-allocators for kernel and user multi-threaded programs are still being designed and improved.
+For this reason, several alternative general-purpose allocators have been written for C/\CC with the goal of scaling in a multi-threaded program~\cite{Berger00,mtmalloc,streamflow,tcmalloc}.
+This thesis examines the design of high-performance allocators for use by kernel and user multi-threaded applications written in C/\CC.
+
+
+\section{Contributions}
+\label{s:Contributions}
+
+This work provides the following contributions in the area of concurrent dynamic allocation:
+\begin{enumerate}[leftmargin=*]
+\item
+Implementation of a new stand-lone concurrent low-latency memory-allocator ($\approx$1,200 lines of code) for C/\CC programs using kernel threads (1:1 threading), and specialized versions of the allocator for programming languages \uC and \CFA using user-level threads running over multiple kernel threads (M:N threading).
+
+\item
+Adopt returning of @nullptr@ for a zero-sized allocation, rather than an actual memory address, both of which can be passed to @free@.
+
+\item
+Extended the standard C heap functionality by preserving with each allocation its original request size versus the amount allocated, if an allocation is zero fill, and the allocation alignment.
+
+\item
+Use the zero fill and alignment as \emph{sticky} properties for @realloc@, to realign existing storage, or preserve existing zero-fill and alignment when storage is copied.
+Without this extension, it is unsafe to @realloc@ storage initially allocated with zero-fill/alignment as these properties are not preserved when copying.
+This silent generation of a problem is unintuitive to programmers and difficult to locate because it is transient.
+
+\item
+Provide additional heap operations to complete programmer expectation with respect to accessing different allocation properties.
+\begin{itemize}
+\item
+@resize( oaddr, size )@ re-purpose an old allocation for a new type \emph{without} preserving fill or alignment.
+\item
+@resize( oaddr, alignment, size )@ re-purpose an old allocation with new alignment but \emph{without} preserving fill.
+\item
+@realloc( oaddr, alignment, size )@ same as previous @realloc@ but adding or changing alignment.
+\item
+@aalloc( dim, elemSize )@ same as @calloc@ except memory is \emph{not} zero filled.
+\item
+@amemalign( alignment, dim, elemSize )@ same as @aalloc@ with memory alignment.
+\item
+@cmemalign( alignment, dim, elemSize )@ same as @calloc@ with memory alignment.
+\end{itemize}
+
+\item
+Provide additional heap wrapper functions in \CFA to provide a complete orthogonal set of allocation operations and properties.
+
+\item
+Provide additional query operations to access information about an allocation:
+\begin{itemize}
+\item
+@malloc_alignment( addr )@ returns the alignment of the allocation pointed-to by @addr@.
+If the allocation is not aligned or @addr@ is the @nulladdr@, the minimal alignment is returned.
+\item
+@malloc_zero_fill( addr )@ returns a boolean result indicating if the memory pointed-to by @addr@ is allocated with zero fill, e.g., by @calloc@/@cmemalign@.
+\item
+@malloc_size( addr )@ returns the size of the memory allocation pointed-to by @addr@.
+\item
+@malloc_usable_size( addr )@ returns the usable size of the memory pointed-to by @addr@, i.e., the bin size containing the allocation, where @malloc_size( addr )@ $\le$ @malloc_usable_size( addr )@.
+\end{itemize}
+
+\item
+Provide mostly contention-free allocation and free operations via a heap-per-kernel-thread implementation.
+
+\item
+Provide complete, fast, and contention-free allocation statistics to help understand program behaviour:
+\begin{itemize}
+\item
+@malloc_stats()@ print memory-allocation statistics on the file-descriptor set by @malloc_stats_fd@.
+\item
+@malloc_info( options, stream )@ print memory-allocation statistics as an XML string on the specified file-descriptor set by @malloc_stats_fd@.
+\item
+@malloc_stats_fd( fd )@ set file-descriptor number for printing memory-allocation statistics (default @STDERR_FILENO@).
+This file descriptor is used implicitly by @malloc_stats@ and @malloc_info@.
+\end{itemize}
+
+\item
+Provide extensive runtime checks to valid allocation operations and identify the amount of unfreed storage at program termination.
+
+\item
+Build 4 different versions of the allocator:
+\begin{itemize}
+\item
+static or dynamic linking
+\item
+statistic/debugging (testing) or no statistic/debugging (performance)
+\end{itemize}
+A program may link to any of these 4 versions of the allocator often without recompilation.
+(It is possible to separate statistics and debugging, giving 8 different versions.)
+
+\item
+A micro-benchmark test-suite for comparing allocators rather than relying on a suite of arbitrary programs.
+These micro-benchmarks have adjustment knobs to simulate allocation patterns hard-coded into arbitrary test programs
+\end{enumerate}
+
+\begin{comment}
 \noindent
 ====================
@@ -26,9 +172,9 @@
 
 \section{Introduction}
-Dynamic memory allocation and management is one of the core features of C. It gives programmer the freedom to allocate, free, use, and manage dynamic memory himself. The programmer is not given the complete control of the dynamic memory management instead an interface of memory allocator is given to the progrmmer that can be used to allocate/free dynamic memory for the application's use.
-
-Memory allocator is a layer between thr programmer and the system. Allocator gets dynamic memory from the system in heap/mmap area of application storage and manages it for programmer's use.
-
-GNU C Library (FIX ME: cite this) provides an interchangeable memory allocator that can be replaced with a custom memory allocator that supports required features and fulfills application's custom needs. It also allows others to innovate in memory allocation and design their own memory allocator. GNU C Library has set guidelines that should be followed when designing a standalone memory allocator. GNU C Library requires new memory allocators to have atlease following set of functions in their allocator's interface:
+Dynamic memory allocation and management is one of the core features of C. It gives programmer the freedom to allocate, free, use, and manage dynamic memory himself. The programmer is not given the complete control of the dynamic memory management instead an interface of memory allocator is given to the programmer that can be used to allocate/free dynamic memory for the application's use.
+
+Memory allocator is a layer between the programmer and the system. Allocator gets dynamic memory from the system in heap/mmap area of application storage and manages it for programmer's use.
+
+GNU C Library (FIX ME: cite this) provides an interchangeable memory allocator that can be replaced with a custom memory allocator that supports required features and fulfills application's custom needs. It also allows others to innovate in memory allocation and design their own memory allocator. GNU C Library has set guidelines that should be followed when designing a stand-alone memory allocator. GNU C Library requires new memory allocators to have at lease following set of functions in their allocator's interface:
 
 \begin{itemize}
@@ -43,5 +189,5 @@
 \end{itemize}
 
-In addition to the above functions, GNU C Library also provides some more functions to increase the usability of the dynamic memory allocator. Most standalone allocators also provide all or some of the above additional functions.
+In addition to the above functions, GNU C Library also provides some more functions to increase the usability of the dynamic memory allocator. Most stand-alone allocators also provide all or some of the above additional functions.
 
 \begin{itemize}
@@ -60,5 +206,5 @@
 \end{itemize}
 
-With the rise of concurrent applications, memory allocators should be able to fulfill dynamic memory requests from multiple threads in parallel without causing contention on shared resources. There needs to be a set of a standard benchmarks that can be used to evaluate an allocator's performance in different scenerios.
+With the rise of concurrent applications, memory allocators should be able to fulfill dynamic memory requests from multiple threads in parallel without causing contention on shared resources. There needs to be a set of a standard benchmarks that can be used to evaluate an allocator's performance in different scenarios.
 
 \section{Research Objectives}
@@ -69,7 +215,8 @@
 Design a lightweight concurrent memory allocator with added features and usability that are currently not present in the other memory allocators.
 \item
-Design a suite of benchmarks to evalute multiple aspects of a memory allocator.
+Design a suite of benchmarks to evaluate multiple aspects of a memory allocator.
 \end{itemize}
 
 \section{An outline of the thesis}
 LAST FIX ME: add outline at the end
+\end{comment}
Index: doc/theses/mubeen_zulfiqar_MMath/performance.tex
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/performance.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/mubeen_zulfiqar_MMath/performance.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -18,4 +18,42 @@
 \noindent
 ====================
+
+\section{Machine Specification}
+
+The performance experiments were run on three different multicore systems to determine if there is consistency across platforms:
+\begin{itemize}
+\item
+AMD EPYC 7662, 64-core socket $\times$ 2, 2.0 GHz
+\item
+Huawei ARM TaiShan 2280 V2 Kunpeng 920, 24-core socket $\times$ 4, 2.6 GHz
+\item
+Intel Xeon Gold 5220R, 48-core socket $\times$ 2, 2.20GHz
+\end{itemize}
+
+
+\section{Existing Memory Allocators}
+With dynamic allocation being an important feature of C, there are many stand-alone memory allocators that have been designed for different purposes. For this thesis, we chose 7 of the most popular and widely used memory allocators.
+
+\paragraph{dlmalloc}
+dlmalloc (FIX ME: cite allocator) is a thread-safe allocator that is single threaded and single heap. dlmalloc maintains free-lists of different sizes to store freed dynamic memory. (FIX ME: cite wasik)
+
+\paragraph{hoard}
+Hoard (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and using a heap layer framework. It has per-thread heaps that have thread-local free-lists, and a global shared heap. (FIX ME: cite wasik)
+
+\paragraph{jemalloc}
+jemalloc (FIX ME: cite allocator) is a thread-safe allocator that uses multiple arenas. Each thread is assigned an arena. Each arena has chunks that contain contagious memory regions of same size. An arena has multiple chunks that contain regions of multiple sizes.
+
+\paragraph{ptmalloc}
+ptmalloc (FIX ME: cite allocator) is a modification of dlmalloc. It is a thread-safe multi-threaded memory allocator that uses multiple heaps. ptmalloc heap has similar design to dlmalloc's heap.
+
+\paragraph{rpmalloc}
+rpmalloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses per-thread heap. Each heap has multiple size-classes and each size-class contains memory regions of the relevant size.
+
+\paragraph{tbb malloc}
+tbb malloc (FIX ME: cite allocator) is a thread-safe allocator that is multi-threaded and uses private heap for each thread. Each private-heap has multiple bins of different sizes. Each bin contains free regions of the same size.
+
+\paragraph{tc malloc}
+tcmalloc (FIX ME: cite allocator) is a thread-safe allocator. It uses per-thread cache to store free objects that prevents contention on shared resources in multi-threaded application. A central free-list is used to refill per-thread cache when it gets empty.
+
 
 \section{Memory Allocators}
Index: doc/theses/mubeen_zulfiqar_MMath/pictures/MultipleHeapsOwnershipStorage.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/pictures/MultipleHeapsOwnershipStorage.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/pictures/MultipleHeapsOwnershipStorage.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,240 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 4500 2400 6000 2700
+2 2 0 1 0 7 60 -1 13 0.000 0 0 -1 0 0 5
+	 4500 2400 6000 2400 6000 2700 4500 2700 4500 2400
+4 0 0 50 -1 0 9 0.0000 2 165 420 4525 2650 H$_1$\001
+-6
+6 3000 2400 4500 2700
+2 2 0 1 0 7 60 -1 13 0.000 0 0 -1 0 0 5
+	 3000 2400 4500 2400 4500 2700 3000 2700 3000 2400
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 2650 H$_2$\001
+-6
+6 3000 2700 4500 3000
+2 2 0 1 0 7 60 -1 13 0.000 0 0 -1 0 0 5
+	 3000 2700 4500 2700 4500 3000 3000 3000 3000 2700
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 2950 H$_3$\001
+-6
+6 3000 1500 4650 1800
+6 3000 1500 3450 1800
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1500 3300 1500 3300 1800 3000 1800 3000 1500
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 1750 H$_1$\001
+-6
+6 4200 1500 4650 1800
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4200 1500 4500 1500 4500 1800 4200 1800 4200 1500
+4 0 0 50 -1 0 9 0.0000 2 165 420 4225 1750 H$_1$\001
+-6
+6 3900 1500 4350 1800
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3900 1500 4200 1500 4200 1800 3900 1800 3900 1500
+4 0 0 50 -1 0 9 0.0000 2 165 420 3925 1750 H$_1$\001
+-6
+6 3300 1500 3750 1800
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3300 1500 3600 1500 3600 1800 3300 1800 3300 1500
+4 0 0 50 -1 0 9 0.0000 2 165 390 3325 1750 T$_1$\001
+-6
+6 3600 1500 4050 1800
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1500 3900 1500 3900 1800 3600 1800 3600 1500
+4 0 0 50 -1 0 9 0.0000 2 165 390 3625 1750 T$_2$\001
+-6
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 3300 1500 3300 1800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4200 1500 4200 1800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 3900 1500 3900 1800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 3600 1500 3600 1800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1500 4500 1500 4500 1800 3000 1800 3000 1500
+-6
+6 4500 1500 6000 1800
+6 4500 1500 5100 1800
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4500 1500 5100 1500 5100 1800 4500 1800 4500 1500
+4 0 0 50 -1 0 9 0.0000 2 165 420 4525 1750 H$_3$\001
+-6
+6 5100 1500 5550 1800
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 5100 1500 5550 1500 5550 1800 5100 1800 5100 1500
+4 0 0 50 -1 0 9 0.0000 2 165 390 5125 1750 T$_3$\001
+-6
+6 5550 1500 6000 1800
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 5550 1500 6000 1500 6000 1800 5550 1800 5550 1500
+4 0 0 50 -1 0 9 0.0000 2 165 390 5575 1750 T$_1$\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4500 1500 6000 1500 6000 1800 4500 1800 4500 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 5100 1500 5100 1800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 5550 1500 5550 1800
+-6
+6 3000 1800 4650 2100
+6 4200 1800 4650 2100
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4200 1800 4500 1800 4500 2100 4200 2100 4200 1800
+4 0 0 50 -1 0 9 0.0000 2 165 420 4225 2050 H$_2$\001
+-6
+6 3900 1800 4350 2100
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3900 1800 4200 1800 4200 2100 3900 2100 3900 1800
+4 0 0 50 -1 0 9 0.0000 2 165 420 3925 2050 H$_2$\001
+-6
+6 3000 1800 3600 2100
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3000 1800 3600 1800 3600 2100 3000 2100 3000 1800
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 2050 H$_2$\001
+-6
+6 3600 1800 4050 2100
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 1800 3900 1800 3900 2100 3600 2100 3600 1800
+4 0 0 50 -1 0 9 0.0000 2 165 390 3625 2050 T$_3$\001
+-6
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 3600 1800 3600 2100
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 3900 1800 3900 2100
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4200 1800 4200 2100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 1800 4500 1800 4500 2100 3000 2100 3000 1800
+-6
+6 4500 1800 6000 2100
+6 4500 1800 4950 2100
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4500 1800 4800 1800 4800 2100 4500 2100 4500 1800
+4 0 0 50 -1 0 9 0.0000 2 165 420 4525 2050 H$_1$\001
+-6
+6 5400 1800 6000 2100
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 5400 1800 6000 1800 6000 2100 5400 2100 5400 1800
+4 0 0 50 -1 0 9 0.0000 2 165 420 5425 2050 H$_1$\001
+-6
+6 4800 1800 5400 2100
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 4800 1800 5400 1800 5400 2100 4800 2100 4800 1800
+4 0 0 50 -1 0 9 0.0000 2 165 390 4825 2050 T$_1$\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4500 1800 6000 1800 6000 2100 4500 2100 4500 1800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4800 1800 4800 2100
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 5400 1800 5400 2100
+-6
+6 3000 2100 4650 2400
+6 4200 2100 4650 2400
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4200 2100 4500 2100 4500 2400 4200 2400 4200 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 4225 2350 H$_3$\001
+-6
+6 3000 2100 3450 2400
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3000 2100 3300 2100 3300 2400 3000 2400 3000 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 3025 2350 H$_3$\001
+-6
+6 3600 2100 4050 2400
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 3600 2100 3900 2100 3900 2400 3600 2400 3600 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 3625 2350 H$_3$\001
+-6
+6 3300 2100 3750 2400
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3300 2100 3600 2100 3600 2400 3300 2400 3300 2100
+4 0 0 50 -1 0 9 0.0000 2 165 390 3325 2350 T$_1$\001
+-6
+6 3900 2100 4350 2400
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 2100 4200 2100 4200 2400 3900 2400 3900 2100
+4 0 0 50 -1 0 9 0.0000 2 165 390 3925 2350 T$_1$\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3000 2100 4500 2100 4500 2400 3000 2400 3000 2100
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 3300 2100 3300 2400
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 3900 2100 3900 2400
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4200 2100 4200 2400
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 3600 2100 3600 2400
+-6
+6 4500 2100 6000 2400
+6 4950 2100 5550 2400
+2 2 0 0 0 7 60 -1 17 0.000 0 0 -1 0 0 5
+	 4950 2100 5550 2100 5550 2400 4950 2400 4950 2100
+4 0 0 50 -1 0 9 0.0000 2 165 420 4975 2350 H$_2$\001
+-6
+6 4500 2100 4950 2400
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 4500 2100 4950 2100 4950 2400 4500 2400 4500 2100
+4 0 0 50 -1 0 9 0.0000 2 165 390 4525 2350 T$_2$\001
+-6
+6 5550 2100 6000 2400
+2 2 0 0 0 7 60 -1 -1 0.000 0 0 -1 0 0 5
+	 5550 2100 6000 2100 6000 2400 5550 2400 5550 2100
+4 0 0 50 -1 0 9 0.0000 2 165 390 5575 2350 T$_3$\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4500 2100 6000 2100 6000 2400 4500 2400 4500 2100
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4950 2100 4950 2400
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 5550 2100 5550 2400
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2100 1200 2100 3000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1500 2700 1800 2400 1800 2400 1500 2700 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 1800 2550 1950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1800 1650 2400 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 1500 1800 1800 1500 1800 1500 1500 1800 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 1950 2700 2250 2400 2250 2400 1950 2700 1950
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2700 2400 2700 2700 2400 2700 2400 2400 2700 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2550 2250 2550 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 2475 3000 2100
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 1575 3000 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2700 2025 3000 1800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2704 1743 4500 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2691 2163 3000 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2691 2618 3000 2700
+4 1 0 50 -1 0 11 0.0000 2 135 885 1500 1350 Static Zone\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 2550 1725 H$_1$\001
+4 1 0 50 -1 0 11 0.0000 2 180 1950 4050 1350 Dynamic-Allocation Zone\001
+4 1 0 50 -1 0 11 0.0000 2 135 225 1650 1725 Hs\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 2550 2625 H$_3$\001
+4 1 0 50 -1 0 11 0.0000 2 195 495 2550 2175 H$_2$\001
Index: doc/theses/mubeen_zulfiqar_MMath/pictures/PrivatePublicHeaps.fig
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/pictures/PrivatePublicHeaps.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ doc/theses/mubeen_zulfiqar_MMath/pictures/PrivatePublicHeaps.fig	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,117 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1200 1200 2400 1500
+6 1200 1275 2400 1500
+4 2 0 50 -1 0 11 0.0000 2 180 915 2250 1425 Public Heap\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 2275 1475 1\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1200 1200 2400 1200 2400 1500 1200 1500 1200 1200
+-6
+6 3900 1200 5100 1500
+6 3900 1275 5100 1500
+4 0 0 50 -1 0 9 0.0000 2 105 75 4975 1475 2\001
+4 2 0 50 -1 0 11 0.0000 2 180 915 4950 1425 Public Heap\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3900 1200 5100 1200 5100 1500 3900 1500 3900 1200
+-6
+6 1425 2100 2700 2400
+6 1425 2175 2550 2400
+4 2 0 50 -1 0 11 0.0000 2 180 990 2550 2325 Private Heap\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1500 2100 2700 2100 2700 2400 1500 2400 1500 2100
+4 0 0 50 -1 0 9 0.0000 2 105 75 2575 2375 1\001
+-6
+6 3525 2100 4800 2400
+6 3525 2175 4650 2400
+4 2 0 50 -1 0 11 0.0000 2 180 990 4650 2325 Private Heap\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3600 2100 4800 2100 4800 2400 3600 2400 3600 2100
+4 0 0 50 -1 0 9 0.0000 2 105 75 4675 2375 2\001
+-6
+6 2550 600 3750 900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2550 600 3750 600 3750 900 2550 900 2550 600
+4 1 0 50 -1 0 11 0.0000 2 180 945 3150 825 Global Heap\001
+-6
+6 1575 3075 2100 3300
+4 2 0 50 -1 0 11 0.0000 2 135 375 1950 3225 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 1975 3275 1\001
+-6
+6 4275 3075 4800 3300
+4 2 0 50 -1 0 11 0.0000 2 135 375 4650 3225 Task\001
+4 0 0 50 -1 0 9 0.0000 2 105 75 4675 3275 2\001
+-6
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1275 1500 1275 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 5025 1500 5025 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4650 3000 4650 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 3975 3075 2400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2325 3075 3900 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	1 1 1.00 45.00 90.00
+	1 1 1.00 45.00 90.00
+	 1950 1200 2550 900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	1 1 1.00 45.00 90.00
+	1 1 1.00 45.00 90.00
+	 3750 900 4350 1200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	1 1 1.00 45.00 90.00
+	1 1 1.00 45.00 90.00
+	 2550 2100 2550 900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+	1 1 1.00 45.00 90.00
+	1 1 1.00 45.00 90.00
+	 3750 2100 3750 900
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4650 2100 4650 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1650 2400 1650 3000
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 1650 2100 1650 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 2025 3000 2025 2400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+	1 1 1.00 45.00 90.00
+	 4275 2400 4275 3000
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+	 2325 3300 2325 3000 1200 3000 1200 3300 2325 3300
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+	 5100 3300 5100 3000 3975 3000 3975 3300 5100 3300
+4 1 0 50 -1 0 11 0.0000 2 180 540 3150 1425 locking\001
+4 1 0 50 -1 0 11 1.5708 2 135 360 1200 2250 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 540 4725 2700 dealloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 360 5100 2250 alloc\001
+4 1 0 50 -1 0 11 5.4803 2 135 540 3375 2775 dealloc\001
+4 1 0 50 -1 0 11 0.8029 2 180 780 2700 2625 ownership\001
+4 1 0 50 -1 0 11 0.8029 2 135 540 2925 2775 dealloc\001
+4 1 0 50 -1 0 11 5.4803 2 180 780 3600 2625 ownership\001
+4 1 0 50 -1 0 11 4.7124 2 135 540 4725 1800 dealloc\001
+4 1 0 50 -1 0 11 1.5708 2 135 540 1575 2700 dealloc\001
+4 1 0 50 -1 0 11 1.5708 2 135 540 1575 1800 dealloc\001
+4 1 0 50 -1 0 11 1.5708 2 135 360 1950 2700 alloc\001
+4 1 0 50 -1 0 11 4.7124 2 135 360 4350 2700 alloc\001
Index: doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.bib
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.bib	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.bib	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -34,2 +34,371 @@
     year          = "2008"
 }
+
+@article{Sleator85,
+    author	= {Sleator, Daniel Dominic and Tarjan, Robert Endre},
+    title	= {Self-Adjusting Binary Search Trees},
+    journal	= jacm,
+    volume	= 32,
+    number	= 3,
+    year	= 1985,
+    issn	= {0004-5411},
+    pages	= {652-686},
+    doi		= {http://doi.acm.org.proxy.lib.uwaterloo.ca/10.1145/3828.3835},
+    address	= {New York, NY, USA},
+}
+
+@article{Berger00,
+    author	= {Emery D. Berger and Kathryn S. McKinley and Robert D. Blumofe and Paul R. Wilson},
+    title	= {Hoard: A Scalable Memory Allocator for Multithreaded Applications},
+    booktitle	= {International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS-IX)},
+    journal	= sigplan,
+    volume	= 35,
+    number	= 11,
+    month	= nov,
+    year	= 2000,
+    pages	= {117-128},
+    note	= {International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS-IX)},
+}
+
+@inproceedings{berger02reconsidering,
+    author	= {Emery D. Berger and Benjamin G. Zorn and Kathryn S. McKinley},
+    title	= {Reconsidering Custom Memory Allocation},
+    booktitle	= {Proceedings of the 17th ACM SIGPLAN Conference on Object-Oriented Programming: Systems, Languages, and Applications (OOPSLA) 2002},
+    month	= nov,
+    year	= 2002,
+    location	= {Seattle, Washington, USA},
+    publisher	= {ACM},
+    address	= {New York, NY, USA},
+}
+
+@article{larson99memory,
+    author	= {Per-{\AA}ke Larson and Murali Krishnan},
+    title	= {Memory Allocation for Long-Running Server Applications},
+    journal	= sigplan,
+    volume	= 34,
+    number	= 3,
+    pages	= {176-185},
+    year	= 1999,
+    url		= {http://citeseer.ist.psu.edu/article/larson98memory.html}
+}
+
+@techreport{gidpt04,
+    author	= {Anders Gidenstam and Marina Papatriantafilou and Philippas Tsigas},
+    title	= {Allocating Memory in a Lock-Free Manner},
+    number	= {2004-04},
+    institution	= {Computing Science},
+    address	= {Chalmers University of Technology},
+    year	= 2004,
+    url		= {http://citeseer.ist.psu.edu/gidenstam04allocating.html} 
+}
+
+@phdthesis{berger02thesis,
+    author	= {Emery Berger},
+    title	= {Memory Management for High-Performance Applications},
+    school	= {The University of Texas at Austin},
+    year	= 2002,
+    month	= aug,
+    url		= {http://citeseer.ist.psu.edu/article/berger02memory.html}
+}
+
+@misc{sgimisc,
+    author	= {SGI},
+    title	= {The Standard Template Library for {C++}},
+    note	= {\textsf{www.sgi.com/\-tech/\-stl/\-Allocators.html}},
+}
+
+@misc{dlmalloc,
+    author	= {Doug Lea},
+    title	= {dlmalloc version 2.8.4},
+    month	= may,
+    year	= 2009,
+    note	= {\textsf{ftp://g.oswego.edu/\-pub/\-misc/\-malloc.c}},
+}
+
+@misc{ptmalloc2,
+    author	= {Wolfram Gloger},
+    title	= {ptmalloc version 2},
+    month	= jun,
+    year	= 2006,
+    note	= {\textsf{http://www.malloc.de/\-malloc/\-ptmalloc2-current.tar.gz}},
+}
+
+@misc{nedmalloc,
+    author	= {Niall Douglas},
+    title	= {nedmalloc version 1.06 Beta},
+    month	= jan,
+    year	= 2010,
+    note	= {\textsf{http://\-prdownloads.\-sourceforge.\-net/\-nedmalloc/\-nedmalloc\_v1.06beta1\_svn1151.zip}},
+}
+
+@misc{hoard,
+    author	= {Emery D. Berger},
+    title	= {hoard version 3.8},
+    month	= nov,
+    year	= 2009,
+    note	= {\textsf{http://www.cs.umass.edu/\-$\sim$emery/\-hoard/\-hoard-3.8/\-source/hoard-38.tar.gz}},
+}
+
+@comment{mtmalloc,
+    author	= {Greg Nakhimovsky},
+    title	= {Improving Scalability of Multithreaded Dynamic Memory Allocation},
+    journal	= {Dr. Dobb's},
+    month	= jul,
+    year	= 2001,
+    url		= {http://www.ddj.com/mobile/184404685?pgno=1}
+}
+
+@misc{mtmalloc,
+    key		= {mtmalloc},
+    title	= {mtmalloc.c},
+    year	= 2009,
+    note	= {\textsf{http://src.opensolaris.org/\-source/\-xref/\-onnv/\-onnv-gate/\-usr/\-src/\-lib/\-libmtmalloc/\-common/\-mtmalloc.c}},
+}
+
+@misc{tcmalloc,
+    author	= {Sanjay Ghemawat and Paul Menage},
+    title	= {tcmalloc version 1.5},
+    month	= jan,
+    year	= 2010,
+    note	= {\textsf{http://google-perftools.\-googlecode.\-com/\-files/\-google-perftools-1.5.tar.gz}},
+}
+
+@inproceedings{streamflow,
+    author	= {Scott Schneider and Christos D. Antonopoulos and Dimitrios S. Nikolopoulos},
+    title	= {Scalable Locality-Conscious Multithreaded Memory Allocation},
+    booktitle	= {International Symposium on Memory Management (ISSM'06)},
+    month	= jun,
+    year	= 2006,
+    pages	= {84-94},
+    location	= {Ottawa, Ontario, Canada},
+    publisher	= {ACM},
+    address	= {New York, NY, USA},
+}
+
+@misc{streamflowweb,
+    author	= {Scott Schneider and Christos Antonopoulos and Dimitrios Nikolopoulos},
+    title	= {Streamflow},
+    note	= {\textsf{http://people.cs.vt.edu/\-\char`\~scschnei/\-streamflow}},
+}
+
+@inproceedings{Blumofe94,
+    author	= {R. Blumofe and C. Leiserson},
+    title	= {Scheduling Multithreaded Computations by Work Stealing},
+    booktitle	= {Proceedings of the 35th Annual Symposium on Foundations of Computer Science, Santa Fe, New Mexico.},
+    pages	= {356-368},
+    year	= 1994,
+    month	= nov,
+    url		= {http://citeseer.ist.psu.edu/article/blumofe94scheduling.html}
+}
+
+@article{Johnstone99,
+    author	= {Mark S. Johnstone and Paul R. Wilson},
+    title	= {The Memory Fragmentation Problem: Solved?},
+    journal	= sigplan,
+    volume	= 34,
+    number	= 3,
+    pages	= {26-36},
+    year	= 1999,
+}
+
+@inproceedings{Grunwald93,
+    author	= {Dirk Grunwald and Benjamin G. Zorn and Robert Henderson},
+    title	= {Improving the Cache Locality of Memory Allocation},
+    booktitle	= {{SIGPLAN} Conference on Programming Language Design and Implementation},
+    pages	= {177-186},
+    year	= 1993,
+    url		= {http://citeseer.ist.psu.edu/grunwald93improving.html}
+}
+
+@inproceedings{Wilson95,
+    author	= {Wilson, Paul R. and Johnstone, Mark S. and Neely, Michael and Boles, David},
+    title	= {Dynamic Storage Allocation: A Survey and Critical Review},
+    booktitle	= {Proc. Int. Workshop on Memory Management},
+    address	= {Kinross Scotland, UK},
+    year	= 1995,
+    url		= {http://citeseer.ist.psu.edu/wilson95dynamic.html} 
+}
+
+@inproceedings{Siebert00,
+    author	= {Fridtjof Siebert},
+    title	= {Eliminating External Fragmentation in a Non-moving Garbage Collector for Java},
+    booktitle	= {CASES '00: Proceedings of the 2000 international conference on Compilers, architecture, and synthesis for embedded systems},
+    year	= 2000,
+    isbn	= {1-58113-338-3},
+    pages	= {9-17},
+    location	= {San Jose, California, United States},
+    doi		= {http://doi.acm.org.proxy.lib.uwaterloo.ca/10.1145/354880.354883},
+    publisher	= {ACM Press},
+    address	= {New York, NY, USA}
+}
+
+@inproceedings{Lim98,
+   author	= {Tian F. Lim and Przemyslaw Pardyak and Brian N. Bershad},
+   title	= {A Memory-Efficient Real-Time Non-copying Garbage Collector},
+   booktitle	= {ISMM '98: Proceedings of the 1st international symposium on Memory management},
+   year		= 1998,
+   isbn		= {1-58113-114-3},
+   pages	= {118-129},
+   location	= {Vancouver, British Columbia, Canada},
+   doi		= {http://doi.acm.org.proxy.lib.uwaterloo.ca/10.1145/286860.286873},
+   publisher	= {ACM Press},
+   address	= {New York, NY, USA}
+}
+
+@article{Chang01,
+    author	= {J. Morris Chang and Woo Hyong Lee and Witawas Srisa-an},
+    title	= {A Study of the Allocation Behavior of {C++} Programs},
+    journal	= {J. Syst. Softw.},
+    volume	= 57,
+    number	= 2,
+    year	= 2001,
+    issn	= {0164-1212},
+    pages	= {107-118},
+    doi		= {http://dx.doi.org/10.1016/S0164-1212(00)00122-9},
+    publisher	= {Elsevier Science Inc.},
+    address	= {New York, NY, USA}
+}
+
+@article{Herlihy93,
+    author	= {Maurice Herlihy},
+    title	= {A Methodology for Implementing Highly Concurrent Data Objects},
+    journal	= toplas,
+    volume	= 15,
+    number	= 5,
+    year	= 1993,
+    issn	= {0164-0925},
+    pages	= {745-770},
+    doi		= {http://doi.acm.org.proxy.lib.uwaterloo.ca/10.1145/161468.161469},
+    publisher	= {ACM Press},
+    address	= {New York, NY, USA}
+}
+
+@article{Denning05,
+    author	= {Peter J. Denning},
+    title	= {The Locality Principle},
+    journal	= cacm,
+    volume	= 48,
+    number	= 7,
+    year	= 2005,
+    issn	= {0001-0782},
+    pages	= {19-24},
+    doi		= {http://doi.acm.org.proxy.lib.uwaterloo.ca/10.1145/1070838.1070856},
+    publisher	= {ACM Press},
+    address	= {New York, NY, USA}
+}
+
+@misc{wilson-locality,
+    author	= {Paul R. Wilson},
+    title	= {Locality of Reference, Patterns in Program Behavior, Memory Management, and Memory Hierarchies},
+    url		= {http://citeseer.ist.psu.edu/337869.html}
+}
+
+@inproceedings{Feng05,
+    author	= {Yi Feng and Emery D. Berger},
+    title	= {A Locality-Improving Dynamic Memory Allocator},
+    booktitle	= {Proceedings of the 2005 Workshop on Memory System Performance},
+    location	= {Chicago, Illinois},
+    publisher	= {ACM},
+    address	= {New York, NY, USA},
+    month	= jun,
+    year	= 2005,
+    pages	= {68-77},
+}
+
+@inproceedings{grunwald-locality,
+    author	= {Dirk Grunwald and Benjamin Zorn and Robert Henderson},
+    title	= {Improving the Cache Locality of Memory Allocation},
+    booktitle	= {PLDI '93: Proceedings of the ACM SIGPLAN 1993 conference on Programming language design and implementation},
+    year	= 1993,
+    isbn	= {0-89791-598-4},
+    pages	= {177-186},
+    location	= {Albuquerque, New Mexico, United States},
+    doi		= {http://doi.acm.org.proxy.lib.uwaterloo.ca/10.1145/155090.155107},
+    publisher	= {ACM Press},
+    address	= {New York, NY, USA}
+}
+
+@article{Alexandrescu01b,
+    author	= {Andrei Alexandrescu},
+    title	= {{volatile} -- Multithreaded Programmer's Best Friend},
+    journal	= {Dr. Dobb's},
+    month	= feb,
+    year	= 2001,
+    url		= {http://www.ddj.com/cpp/184403766}
+}
+
+@article{Attardi03,
+    author	= {Joseph Attardi and Neelakanth Nadgir},
+    title	= {A Comparison of Memory Allocators in Multiprocessors},
+    journal	= {Sun Developer Network},
+    month	= jun,
+    year	= 2003,
+    note	= {\textsf{http://developers.sun.com/\-solaris/\-articles/\-multiproc/\-multiproc.html}},
+}
+
+@unpublished{memlayout,
+    author	= {Peter Jay Salzman},
+    title	= {Memory Layout and the Stack},
+    journal	= {Using GNU's GDB Debugger},
+    note	= {\textsf{http://dirac.org/\-linux/\-gdb/\-02a-Memory\_Layout\_And\_The\_Stack.php}},
+}
+
+@unpublished{Ferguson07,
+    author	= {Justin N. Ferguson},
+    title	= {Understanding the Heap by Breaking It},
+    note	= {\textsf{https://www.blackhat.com/\-presentations/\-bh-usa-07/Ferguson/\-Whitepaper/\-bh-usa-07-ferguson-WP.pdf}},
+}
+
+@inproceedings{Huang06,
+    author	= {Xianglong Huang and Brian T Lewis and Kathryn S McKinley},
+    title	= {Dynamic Code Management: Improving Whole Program Code Locality in Managed Runtimes},
+    booktitle	= {VEE '06: Proceedings of the 2nd international conference on Virtual execution environments},
+    year	= 2006,
+    isbn	= {1-59593-332-6},
+    pages	= {133-143},
+    location	= {Ottawa, Ontario, Canada},
+    doi		= {http://doi.acm.org/10.1145/1134760.1134779},
+    publisher	= {ACM Press},
+    address	= {New York, NY, USA}
+ }
+
+@inproceedings{Herlihy03,
+    author	= {M. Herlihy and V. Luchangco and M. Moir},
+    title	= {Obstruction-free Synchronization: Double-ended Queues as an Example},
+    booktitle	= {Proceedings of the 23rd IEEE International Conference on Distributed Computing Systems},
+    year	= 2003,
+    month	= may,
+    url		= {http://www.cs.brown.edu/~mph/publications.html}
+}
+
+@techreport{Detlefs93,
+    author	= {David L. Detlefs and Al Dosser and Benjamin Zorn},
+    title	= {Memory Allocation Costs in Large {C} and {C++} Programs},
+    number	= {CU-CS-665-93},
+    institution = {University of Colorado},
+    address	= {130 Lytton Avenue, Palo Alto, CA 94301 and Campus Box 430, Boulder, CO 80309},
+    year	= 1993,
+    url		= {http://citeseer.ist.psu.edu/detlefs93memory.html} 
+}
+
+@inproceedings{Oyama99,
+    author	= {Y. Oyama and K. Taura and A. Yonezawa},
+    title	= {Executing Parallel Programs With Synchronization Bottlenecks Efficiently},
+    booktitle	= {Proceedings of International Workshop on Parallel and Distributed Computing for Symbolic and Irregular Applications (PDSIA '99)},
+    year	= {1999},
+    pages	= {182--204},
+    publisher	= {World Scientific},
+    address	= {Sendai, Japan},
+}
+
+@inproceedings{Dice02,
+    author	= {Dave Dice and Alex Garthwaite},
+    title	= {Mostly Lock-Free Malloc},
+    booktitle	= {Proceedings of the 3rd international symposium on Memory management (ISMM'02)},
+    month	= jun,
+    year	= 2002,
+    pages	= {163-174},
+    location	= {Berlin, Germany},
+    publisher	= {ACM},
+    address	= {New York, NY, USA},
+}
Index: doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex
===================================================================
--- doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/mubeen_zulfiqar_MMath/uw-ethesis.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -85,4 +85,8 @@
 \usepackage{comment} % Removes large sections of the document.
 \usepackage{tabularx}
+\usepackage{subfigure}
+
+\usepackage{algorithm}
+\usepackage{algpseudocode}
 
 % Hyperlinks make it very easy to navigate an electronic document.
@@ -168,5 +172,6 @@
 %\usepackageinput{common}
 \CFAStyle						% CFA code-style for all languages
-\lstset{basicstyle=\linespread{0.9}\tt}			% CFA typewriter font
+\lstset{basicstyle=\linespread{0.9}\sf}			% CFA typewriter font
+\newcommand{\uC}{$\mu$\CC}
 \newcommand{\PAB}[1]{{\color{red}PAB: #1}}
 
@@ -224,5 +229,5 @@
 \addcontentsline{toc}{chapter}{\textbf{References}}
 
-\bibliography{uw-ethesis,pl}
+\bibliography{pl,uw-ethesis}
 % Tip: You can create multiple .bib files to organize your references.
 % Just list them all in the \bibliogaphy command, separated by commas (no spaces).
Index: doc/theses/thierry_delisle_PhD/thesis/text/existing.tex
===================================================================
--- doc/theses/thierry_delisle_PhD/thesis/text/existing.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/thierry_delisle_PhD/thesis/text/existing.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,4 +1,16 @@
 \chapter{Previous Work}\label{existing}
-Scheduling is a topic with a very long history, predating its use in computer science. As such, early work in computed science was inspired from other fields and focused principally on solving scheduling upfront rather that as the system is running.
+Scheduling is the process of assigning resources to incomming requests.
+A very common form of this is assigning available workers to work-requests.
+The need for scheduling is very common in Computer Science, \eg Operating Systems and Hypervisors schedule available CPUs, NICs schedule available bamdwith, but it is also common in other fields.
+For example, assmebly lines are an example of scheduling where parts needed assembly are assigned to line workers.
+
+In all these cases, the choice of a scheduling algorithm generally depends first and formost on how much information is available to the scheduler.
+Workloads that are well-kown, consistent and homegenous can benefit from a scheduler that is optimized to use this information while ill-defined inconsistent heterogenous workloads will require general algorithms.
+A secondary aspect to that is how much information can be gathered versus how much information must be given as part of the input.
+There is therefore a spectrum of scheduling algorithms, going from static schedulers that are well informed from the start, to schedulers that gather most of the information needed, to schedulers that can only rely on very limitted information.
+Note that this description includes both infomation about each requests, \eg time to complete or resources needed, and information about the relationships between request, \eg whether or not some request must be completed before another request starts.
+
+Scheduling physical resources, for example in assembly lines, is generally amenable to using very well informed scheduling since information can be gathered much faster than the physical resources can be assigned and workloads are likely to stay stable for long periods of time.
+When a faster pace is needed and changes are much more frequent gathering information on workloads, up-front or live, can become much more limiting and more general schedulers are needed.
 
 \section{Naming Convention}
@@ -6,12 +18,13 @@
 
 \section{Static Scheduling}
-Static schedulers require that programmers explicitly and exhaustively specify dependencies among tasks in order to schedule them. The scheduler then processes this input ahead of time and producess a \newterm{schedule} to which the system can later adhere. An example application for these schedulers
-
+Static schedulers require that tasks have their dependencies and costs explicitly and exhaustively specified prior schedule.
+The scheduler then processes this input ahead of time and producess a \newterm{schedule} to which the system can later adhere.
+This approach is generally popular in real-time systems since the need for strong guarantees justifies the cost of supplying this information.
 In general, static schedulers are less relavant to this project since they require input from the programmers that \CFA does not have as part of its concurrency semantic.
-\todo{Rate-monotonic scheduling}
+Specifying this information explicitly can add a significant burden on the programmers and reduces flexibility, for this reason the \CFA scheduler does not require this information.
 
 
 \section{Dynamic Scheduling}
-It may be difficult to fulfill the requirements of static scheduler if dependencies are be conditionnal. In this case, it may be preferable to detect dependencies at runtime. This detection effectively takes the form of halting or suspending a task with unfulfilled dependencies and adding one or more new task(s) to the system. The new task(s) have the responsability of adding the dependent task back in the system once completed. As a consequence, the scheduler may have an incomplete view of the system, seeing only tasks we no pending dependencies. Schedulers that support this detection at runtime are referred to as \newterm{Dynamic Schedulers}.
+It may be difficult to fulfill the requirements of static scheduler if dependencies are conditionnal. In this case, it may be preferable to detect dependencies at runtime. This detection effectively takes the form of halting or suspending a task with unfulfilled dependencies and adding one or more new task(s) to the system. The new task(s) have the responsability of adding the dependent task back in the system once completed. As a consequence, the scheduler may have an incomplete view of the system, seeing only tasks we no pending dependencies. Schedulers that support this detection at runtime are referred to as \newterm{Dynamic Schedulers}.
 
 \subsection{Explicitly Informed Dynamic Schedulers}
@@ -29,6 +42,4 @@
 \subsubsection{Feedback Scheduling}
 As mentionned, Schedulers may also gather information about each tasks to direct their decisions. This design effectively moves the scheduler to some extent into the realm of \newterm{Control Theory}\cite{wiki:controltheory}. This gathering does not generally involve programmers and as such does not increase programmer burden the same way explicitly provided information may. However, some feedback schedulers do offer the option to programmers to offer additionnal information on certain tasks, in order to direct scheduling decision. The important distinction being whether or not the scheduler can function without this additionnal information.
-
-Feedback scheduler
 
 
Index: doc/theses/thierry_delisle_PhD/thesis/text/io.tex
===================================================================
--- doc/theses/thierry_delisle_PhD/thesis/text/io.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/theses/thierry_delisle_PhD/thesis/text/io.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,5 +1,5 @@
 \chapter{User Level \io}
 As mentioned in Section~\ref{prev:io}, User-Level \io requires multiplexing the \io operations of many \glspl{thrd} onto fewer \glspl{proc} using asynchronous \io operations.
-Different operating systems offer various forms of asynchronous operations and as mentioned in Chapter~\ref{intro}, this work is exclusively focused on the Linux operating-system.
+Different operating systems offer various forms of asynchronous operations and, as mentioned in Chapter~\ref{intro}, this work is exclusively focused on the Linux operating-system.
 
 \section{Kernel Interface}
@@ -178,4 +178,6 @@
 Since completions are sent to the instance where requests were submitted, all instances with pending operations must be polled continously
 \footnote{As will be described in Chapter~\ref{practice}, this does not translate into constant cpu usage.}.
+Note that once an operation completes, there is nothing that ties it to the @io_uring@ instance that handled it.
+There is nothing preventing a new operation with, for example, the same file descriptors to a different @io_uring@ instance.
 
 A complicating aspect of submission is @io_uring@'s support for chains of operations, where the completion of an operation triggers the submission of the next operation on the link.
@@ -240,7 +242,7 @@
 To remove this requirement, a \gls{thrd} would need the ability to ``yield to a specific \gls{proc}'', \ie, park with the promise that it will be run next on a specific \gls{proc}, the \gls{proc} attached to the correct ring.}
 , greatly simplifying both allocation and submission.
-In this design, allocation and submission form a ring partitionned ring buffer as shown in Figure~\ref{fig:pring}.
+In this design, allocation and submission form a partitionned ring buffer as shown in Figure~\ref{fig:pring}.
 Once added to the ring buffer, the attached \gls{proc} has a significant amount of flexibility with regards to when to do the system call.
-Possible options are: when the \gls{proc} runs out of \glspl{thrd} to run, after running a given number of threads \glspl{thrd}, etc.
+Possible options are: when the \gls{proc} runs out of \glspl{thrd} to run, after running a given number of \glspl{thrd}, etc.
 
 \begin{figure}
Index: doc/user/user.tex
===================================================================
--- doc/user/user.tex	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ doc/user/user.tex	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -11,6 +11,6 @@
 %% Created On       : Wed Apr  6 14:53:29 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Sat Feb 12 17:04:03 2022
-%% Update Count     : 5376
+%% Last Modified On : Mon Feb 14 17:20:39 2022
+%% Update Count     : 5382
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -8223,6 +8223,6 @@
 Random numbers are values generated independently, i.e., new values do not depend on previous values (independent trials), \eg lottery numbers, shuffled cards, dice roll, coin flip.
 While a primary goal of programming is computing values that are \emph{not} random, random values are useful in simulation, cryptography, games, etc.
-A random-number generator is an algorithm computing independent values.
-If the algorithm uses deterministic computation (predictable sequence of values), it generates \emph{pseudo} random numbers versus \emph{true} random numbers.
+A random-number generator is an algorithm that computes independent values.
+If the algorithm uses deterministic computation (a predictable sequence of values), it generates \emph{pseudo} random numbers versus \emph{true} random numbers.
 
 All \newterm{pseudo random-number generators} (\newterm{PRNG}) involve some technique to scramble bits of a value, \eg multiplicative recurrence:
@@ -8249,8 +8249,8 @@
 Finally, a PRNG usually generates a range of large values, \eg ©[0, UINT_MAX]©, which are scaled using the modulus operator, \eg ©prng() % 5© produces random values in the range 0--4.
 
-\CFA provides a sequential and concurrent PRNGs.
+\CFA provides a sequential PRNG type only accessible by a single thread (not thread-safe) and a set of global and companion thread PRNG functions accessible by multiple threads without contention.
 \begin{itemize}
 \item
-For sequential programs, like coroutining, the PRNG is used to randomize behaviour or values during execution, \eg in games, a character makes a random move or an object takes on a random value.
+The ©PRNG© type is for sequential programs, like coroutining:
 \begin{cfa}
 struct PRNG { ... }; $\C[3.75in]{// opaque type}$
@@ -8264,6 +8264,7 @@
 uint32_t calls( PRNG & prng ); $\C{// number of calls}\CRT$
 \end{cfa}
-Sequential execution is repeatable given the same starting seeds for all ©PRNG©s. 
-In this scenario, it is useful to have multiple ©PRNG©, \eg one per player or object so a type is provided to generate multiple instances.
+A ©PRNG© object is used to randomize behaviour or values during execution, \eg in games, a character makes a random move or an object takes on a random value.
+In this scenario, it is useful to have multiple ©PRNG© objects, \eg one per player or object.
+However, sequential execution is still repeatable given the same starting seeds for all ©PRNG©s. 
 \VRef[Figure]{f:SequentialPRNG} shows an example that creates two sequential ©PRNG©s, sets both to the same seed (1009), and illustrates the three forms for generating random values, where both ©PRNG©s generate the same sequence of values.
 
@@ -8307,5 +8308,4 @@
 \end{tabular}
 \end{cquote}
-\vspace{-10pt}
 \caption{Sequential PRNG}
 \label{f:SequentialPRNG}
@@ -8313,16 +8313,5 @@
 
 \item
-For concurrent programs, it is important the PRNG is thread-safe and not a point of contention.
-A PRNG in concurrent programs is often used to randomize execution in short-running programs, \eg ©yield( prng() % 5 )©.
-
-Because concurrent execution is non-deterministic, seeding the concurrent PRNG is less important, as repeatable execution is impossible.
-Hence, there is one system-wide PRNG (global seed) but each \CFA thread has its own non-contended PRNG state.
-If the global seed is set, threads start with this seed, until it is reset and than threads start with the reset seed.
-Hence, these threads generate the same sequence of random numbers from their specific starting seed.
-If the global seed is \emph{not} set, threads start with a random seed, until the global seed is set.
-Hence, these threads generate different sequences of random numbers.
-If each thread needs its own seed, use a sequential ©PRNG© in each thread.
-
-There are two versions of the PRNG functions to manipulate the thread-local PRNG-state, which are differentiated by performance.
+The PRNG global and companion thread functions are for concurrent programming, such as randomizing execution in short-running programs, \eg ©yield( prng() % 5 )©.
 \begin{cfa}
 void set_seed( uint32_t seed ); $\C[3.75in]{// set global seed}$
@@ -8337,6 +8326,15 @@
 uint32_t prng( $thread\LstStringStyle{\textdollar}$ & th, uint32_t l, uint32_t u );	$\C{// [l,u]}\CRT$
 \end{cfa}
-The slower ©prng© functions call ©active_thread© internally to access the thread-local PRNG-state, while the faster ©prng© functions are passed a pointer to the active thread.
-If the thread pointer is known, \eg in a thread ©main©, eliminating the call to ©active_thread© significantly reduces the cost for accessing the thread's PRNG state.
+The only difference between the two sets of ©prng© routines is performance.
+
+Because concurrent execution is non-deterministic, seeding the concurrent PRNG is less important, as repeatable execution is impossible.
+Hence, there is one system-wide PRNG (global seed) but each \CFA thread has its own non-contended PRNG state.
+If the global seed is set, threads start with this seed, until it is reset and then threads start with the reset seed.
+Hence, these threads generate the same sequence of random numbers from their specific starting seed.
+If the global seed is \emph{not} set, threads start with a random seed, until the global seed is set.
+Hence, these threads generate different sequences of random numbers.
+If each thread needs its own seed, use a sequential ©PRNG© in each thread.
+The slower ©prng© functions \emph{without} a thread argument call ©active_thread© internally to indirectly access the current thread's PRNG state, while the faster ©prng© functions \emph{with} a thread argument directly access the thread through the thread parameter.
+If a thread pointer is available, \eg in thread main, eliminating the call to ©active_thread© significantly reduces the cost of accessing the thread's PRNG state.
 \VRef[Figure]{f:ConcurrentPRNG} shows an example using the slower/faster concurrent PRNG in the program main and a thread.
 
Index: driver/cc1.cc
===================================================================
--- driver/cc1.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ driver/cc1.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,6 +10,6 @@
 // Created On       : Fri Aug 26 14:23:51 2005
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 21 09:46:24 2021
-// Update Count     : 419
+// Last Modified On : Thu Feb 17 18:04:23 2022
+// Update Count     : 422
 //
 
@@ -61,5 +61,5 @@
 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );		// "__CFA_FLAG__=" suffix
 
-static void checkEnv1( const char * args[], int & nargs ) { // stage 1
+static void checkEnv1() {								// stage 1
 	extern char ** environ;
 
@@ -155,5 +155,5 @@
 	cerr << "Stage1" << endl;
 	#endif // __DEBUG_H__
-	checkEnv1( args, nargs );							// arguments passed via environment variables
+	checkEnv1();										// arguments passed via environment variables
 	#ifdef __DEBUG_H__
 	for ( int i = 1; i < argc; i += 1 ) {
Index: libcfa/src/Makefile.am
===================================================================
--- libcfa/src/Makefile.am	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/Makefile.am	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -63,4 +63,5 @@
 	containers/queueLockFree.hfa \
 	containers/stackLockFree.hfa \
+	containers/string_sharectx.hfa \
 	containers/vector2.hfa \
 	vec/vec.hfa \
@@ -118,4 +119,5 @@
 	concurrency/exception.hfa \
 	concurrency/kernel.hfa \
+	concurrency/kernel/cluster.hfa \
 	concurrency/locks.hfa \
 	concurrency/monitor.hfa \
@@ -133,5 +135,5 @@
 	concurrency/io/call.cfa \
 	concurrency/iofwd.hfa \
-	concurrency/kernel_private.hfa \
+	concurrency/kernel/private.hfa \
 	concurrency/kernel/startup.cfa \
 	concurrency/preemption.cfa \
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/coroutine.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -27,5 +27,5 @@
 #include <unwind.h>
 
-#include "kernel_private.hfa"
+#include "kernel/private.hfa"
 #include "exception.hfa"
 #include "math.hfa"
Index: libcfa/src/concurrency/io.cfa
===================================================================
--- libcfa/src/concurrency/io.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/io.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -41,5 +41,5 @@
 	#include "kernel.hfa"
 	#include "kernel/fwd.hfa"
-	#include "kernel_private.hfa"
+	#include "kernel/private.hfa"
 	#include "io/types.hfa"
 
@@ -93,12 +93,10 @@
 	extern void __kernel_unpark( thread$ * thrd, unpark_hint );
 
-	bool __cfa_io_drain( processor * proc ) {
+	bool __cfa_io_drain( $io_context * ctx ) {
 		/* paranoid */ verify( ! __preemption_enabled() );
 		/* paranoid */ verify( ready_schedule_islocked() );
-		/* paranoid */ verify( proc );
-		/* paranoid */ verify( proc->io.ctx );
+		/* paranoid */ verify( ctx );
 
 		// Drain the queue
-		$io_context * ctx = proc->io.ctx;
 		unsigned head = *ctx->cq.head;
 		unsigned tail = *ctx->cq.tail;
@@ -110,4 +108,8 @@
 		if(count == 0) return false;
 
+		if(!__atomic_try_acquire(&ctx->cq.lock)) {
+			return false;
+		}
+
 		for(i; count) {
 			unsigned idx = (head + i) & mask;
@@ -130,4 +132,6 @@
 		/* paranoid */ verify( ready_schedule_islocked() );
 		/* paranoid */ verify( ! __preemption_enabled() );
+
+		__atomic_unlock(&ctx->cq.lock);
 
 		return true;
@@ -175,9 +179,9 @@
 			/* paranoid */ verify( ! __preemption_enabled() );
 
-			ctx.proc->io.pending = false;
+			__atomic_store_n(&ctx.proc->io.pending, false, __ATOMIC_RELAXED);
 		}
 
 		ready_schedule_lock();
-		bool ret = __cfa_io_drain( proc );
+		bool ret = __cfa_io_drain( &ctx );
 		ready_schedule_unlock();
 		return ret;
@@ -287,5 +291,5 @@
 	//=============================================================================================
 	// submission
-	static inline void __submit( struct $io_context * ctx, __u32 idxs[], __u32 have, bool lazy) {
+	static inline void __submit_only( struct $io_context * ctx, __u32 idxs[], __u32 have) {
 		// We can proceed to the fast path
 		// Get the right objects
@@ -304,6 +308,12 @@
 		sq.to_submit += have;
 
-		ctx->proc->io.pending = true;
-		ctx->proc->io.dirty   = true;
+		__atomic_store_n(&ctx->proc->io.pending, true, __ATOMIC_RELAXED);
+		__atomic_store_n(&ctx->proc->io.dirty  , true, __ATOMIC_RELAXED);
+	}
+
+	static inline void __submit( struct $io_context * ctx, __u32 idxs[], __u32 have, bool lazy) {
+		__sub_ring_t & sq = ctx->sq;
+		__submit_only(ctx, idxs, have);
+
 		if(sq.to_submit > 30) {
 			__tls_stats()->io.flush.full++;
@@ -402,8 +412,12 @@
 // I/O Arbiter
 //=============================================================================================
-	static inline void block(__outstanding_io_queue & queue, __outstanding_io & item) {
+	static inline bool enqueue(__outstanding_io_queue & queue, __outstanding_io & item) {
+		bool was_empty;
+
 		// Lock the list, it's not thread safe
 		lock( queue.lock __cfaabi_dbg_ctx2 );
 		{
+			was_empty = empty(queue.queue);
+
 			// Add our request to the list
 			add( queue.queue, item );
@@ -414,5 +428,5 @@
 		unlock( queue.lock );
 
-		wait( item.sem );
+		return was_empty;
 	}
 
@@ -432,5 +446,7 @@
 		pa.want = want;
 
-		block(this.pending, (__outstanding_io&)pa);
+		enqueue(this.pending, (__outstanding_io&)pa);
+
+		wait( pa.sem );
 
 		return pa.ctx;
@@ -485,5 +501,14 @@
 		ei.lazy = lazy;
 
-		block(ctx->ext_sq, (__outstanding_io&)ei);
+		bool we = enqueue(ctx->ext_sq, (__outstanding_io&)ei);
+
+		__atomic_store_n(&ctx->proc->io.pending, true, __ATOMIC_SEQ_CST);
+
+		if( we ) {
+			sigval_t value = { PREEMPT_IO };
+			pthread_sigqueue(ctx->proc->kernel_thread, SIGUSR1, value);
+		}
+
+		wait( ei.sem );
 
 		__cfadbg_print_safe(io, "Kernel I/O : %u submitted from arbiter\n", have);
@@ -501,5 +526,5 @@
 					__external_io & ei = (__external_io&)drop( ctx.ext_sq.queue );
 
-					__submit(&ctx, ei.idxs, ei.have, ei.lazy);
+					__submit_only(&ctx, ei.idxs, ei.have);
 
 					post( ei.sem );
Index: libcfa/src/concurrency/io/setup.cfa
===================================================================
--- libcfa/src/concurrency/io/setup.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/io/setup.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -39,4 +39,6 @@
 
 #else
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
 	#include <errno.h>
 	#include <stdint.h>
@@ -56,6 +58,8 @@
 
 	#include "bitmanip.hfa"
-	#include "kernel_private.hfa"
+	#include "fstream.hfa"
+	#include "kernel/private.hfa"
 	#include "thread.hfa"
+#pragma GCC diagnostic pop
 
 	void ?{}(io_context_params & this) {
@@ -111,5 +115,5 @@
 		this.ext_sq.empty = true;
 		(this.ext_sq.queue){};
-		__io_uring_setup( this, cl.io.params, proc->idle_fd );
+		__io_uring_setup( this, cl.io.params, proc->idle_wctx.evfd );
 		__cfadbg_print_safe(io_core, "Kernel I/O : Created ring for io_context %u (%p)\n", this.fd, &this);
 	}
@@ -121,7 +125,4 @@
 		__cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %u\n", this.fd);
 	}
-
-	extern void __disable_interrupts_hard();
-	extern void __enable_interrupts_hard();
 
 	static void __io_uring_setup( $io_context & this, const io_context_params & params_in, int procfd ) {
@@ -213,4 +214,5 @@
 
 		// completion queue
+		cq.lock      = 0;
 		cq.head      = (volatile __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
 		cq.tail      = (volatile __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
@@ -226,12 +228,8 @@
 			__cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd);
 
-			__disable_interrupts_hard();
-
 			int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1);
 			if (ret < 0) {
 				abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno));
 			}
-
-			__enable_interrupts_hard();
 
 			__cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd);
@@ -258,4 +256,13 @@
 		struct __sub_ring_t & sq = this.sq;
 		struct __cmp_ring_t & cq = this.cq;
+		{
+			__u32 fhead = sq.free_ring.head;
+			__u32 ftail = sq.free_ring.tail;
+
+			__u32 total = *sq.num;
+			__u32 avail = ftail - fhead;
+
+			if(avail != total) abort | "Processor (" | (void*)this.proc | ") tearing down ring with" | (total - avail) | "entries allocated but not submitted, out of" | total;
+		}
 
 		// unmap the submit queue entries
Index: libcfa/src/concurrency/io/types.hfa
===================================================================
--- libcfa/src/concurrency/io/types.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/io/types.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -23,4 +23,5 @@
 #include "bits/locks.hfa"
 #include "bits/queue.hfa"
+#include "iofwd.hfa"
 #include "kernel/fwd.hfa"
 
@@ -77,4 +78,6 @@
 
 	struct __cmp_ring_t {
+		volatile bool lock;
+
 		// Head and tail of the ring
 		volatile __u32 * head;
@@ -170,21 +173,2 @@
 	// void __ioctx_prepare_block($io_context & ctx);
 #endif
-
-//-----------------------------------------------------------------------
-// IO user data
-struct io_future_t {
-	future_t self;
-	__s32 result;
-};
-
-static inline {
-	thread$ * fulfil( io_future_t & this, __s32 result, bool do_unpark = true ) {
-		this.result = result;
-		return fulfil(this.self, do_unpark);
-	}
-
-	// Wait for the future to be fulfilled
-	bool wait     ( io_future_t & this ) { return wait     (this.self); }
-	void reset    ( io_future_t & this ) { return reset    (this.self); }
-	bool available( io_future_t & this ) { return available(this.self); }
-}
Index: libcfa/src/concurrency/iofwd.hfa
===================================================================
--- libcfa/src/concurrency/iofwd.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/iofwd.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -19,4 +19,5 @@
 extern "C" {
 	#include <asm/types.h>
+	#include <sys/stat.h> // needed for mode_t
 	#if CFA_HAVE_LINUX_IO_URING_H
 		#include <linux/io_uring.h>
@@ -24,4 +25,5 @@
 }
 #include "bits/defs.hfa"
+#include "kernel/fwd.hfa"
 #include "time.hfa"
 
@@ -47,5 +49,4 @@
 
 struct cluster;
-struct io_future_t;
 struct $io_context;
 
@@ -57,4 +58,23 @@
 
 struct io_uring_sqe;
+
+//-----------------------------------------------------------------------
+// IO user data
+struct io_future_t {
+	future_t self;
+	__s32 result;
+};
+
+static inline {
+	thread$ * fulfil( io_future_t & this, __s32 result, bool do_unpark = true ) {
+		this.result = result;
+		return fulfil(this.self, do_unpark);
+	}
+
+	// Wait for the future to be fulfilled
+	bool wait     ( io_future_t & this ) { return wait     (this.self); }
+	void reset    ( io_future_t & this ) { return reset    (this.self); }
+	bool available( io_future_t & this ) { return available(this.self); }
+}
 
 //----------
@@ -133,2 +153,21 @@
 // Check if a function is blocks a only the user thread
 bool has_user_level_blocking( fptr_t func );
+
+#if CFA_HAVE_LINUX_IO_URING_H
+	static inline void zero_sqe(struct io_uring_sqe * sqe) {
+		sqe->flags = 0;
+		sqe->ioprio = 0;
+		sqe->fd = 0;
+		sqe->off = 0;
+		sqe->addr = 0;
+		sqe->len = 0;
+		sqe->fsync_flags = 0;
+		sqe->__pad2[0] = 0;
+		sqe->__pad2[1] = 0;
+		sqe->__pad2[2] = 0;
+		sqe->fd = 0;
+		sqe->off = 0;
+		sqe->addr = 0;
+		sqe->len = 0;
+	}
+#endif
Index: libcfa/src/concurrency/kernel.cfa
===================================================================
--- libcfa/src/concurrency/kernel.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/kernel.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -19,4 +19,7 @@
 // #define __CFA_DEBUG_PRINT_RUNTIME_CORE__
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+
 //C Includes
 #include <errno.h>
@@ -25,4 +28,5 @@
 #include <signal.h>
 #include <unistd.h>
+
 extern "C" {
 	#include <sys/eventfd.h>
@@ -31,5 +35,5 @@
 
 //CFA Includes
-#include "kernel_private.hfa"
+#include "kernel/private.hfa"
 #include "preemption.hfa"
 #include "strstream.hfa"
@@ -40,4 +44,5 @@
 #define __CFA_INVOKE_PRIVATE__
 #include "invoke.h"
+#pragma GCC diagnostic pop
 
 #if !defined(__CFA_NO_STATISTICS__)
@@ -131,8 +136,6 @@
 static void mark_awake(__cluster_proc_list & idles, processor & proc);
 
-extern void __cfa_io_start( processor * );
-extern bool __cfa_io_drain( processor * );
+extern bool __cfa_io_drain( $io_context * );
 extern bool __cfa_io_flush( processor *, int min_comp );
-extern void __cfa_io_stop ( processor * );
 static inline bool __maybe_io_drain( processor * );
 
@@ -159,10 +162,11 @@
 	verify(this);
 
-	io_future_t future; // used for idle sleep when io_uring is present
-	future.self.ptr = 1p;  // mark it as already fulfilled so we know if there is a pending request or not
-	eventfd_t idle_val;
-	iovec idle_iovec = { &idle_val, sizeof(idle_val) };
-
-	__cfa_io_start( this );
+	/* paranoid */ verify( this->idle_wctx.ftr   != 0p );
+	/* paranoid */ verify( this->idle_wctx.rdbuf != 0p );
+
+	// used for idle sleep when io_uring is present
+	// mark it as already fulfilled so we know if there is a pending request or not
+	this->idle_wctx.ftr->self.ptr = 1p;
+	iovec idle_iovec = { this->idle_wctx.rdbuf, sizeof(eventfd_t) };
 
 	__cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this);
@@ -231,5 +235,5 @@
 				}
 
-				idle_sleep( this, future, idle_iovec );
+				idle_sleep( this, *this->idle_wctx.ftr, idle_iovec );
 
 				// We were woken up, remove self from idle
@@ -251,5 +255,5 @@
 			if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
 
-			if(this->io.pending && !this->io.dirty) {
+			if(__atomic_load_n(&this->io.pending, __ATOMIC_RELAXED) && !__atomic_load_n(&this->io.dirty, __ATOMIC_RELAXED)) {
 				__IO_STATS__(true, io.flush.dirty++; )
 				__cfa_io_flush( this, 0 );
@@ -259,11 +263,4 @@
 		__cfadbg_print_safe(runtime_core, "Kernel : core %p stopping\n", this);
 	}
-
-	for(int i = 0; !available(future); i++) {
-		if(i > 1000) __cfaabi_dbg_write( "ERROR: kernel has bin spinning on a flush after exit loop.\n", 60);
-		__cfa_io_flush( this, 1 );
-	}
-
-	__cfa_io_stop( this );
 
 	post( this->terminated );
@@ -634,6 +631,6 @@
 
 	int fd = 1;
-	if( __atomic_load_n(&fdp->fd, __ATOMIC_SEQ_CST) != 1 ) {
-		fd = __atomic_exchange_n(&fdp->fd, 1, __ATOMIC_RELAXED);
+	if( __atomic_load_n(&fdp->sem, __ATOMIC_SEQ_CST) != 1 ) {
+		fd = __atomic_exchange_n(&fdp->sem, 1, __ATOMIC_RELAXED);
 	}
 
@@ -677,9 +674,9 @@
 	__cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
 
-	this->idle_wctx.fd = 1;
+	this->idle_wctx.sem = 1;
 
 	eventfd_t val;
 	val = 1;
-	eventfd_write( this->idle_fd, val );
+	eventfd_write( this->idle_wctx.evfd, val );
 
 	/* paranoid */ verify( ! __preemption_enabled() );
@@ -689,5 +686,5 @@
 	// Tell everyone we are ready to go do sleep
 	for() {
-		int expected = this->idle_wctx.fd;
+		int expected = this->idle_wctx.sem;
 
 		// Someone already told us to wake-up! No time for a nap.
@@ -695,5 +692,5 @@
 
 		// Try to mark that we are going to sleep
-		if(__atomic_compare_exchange_n(&this->idle_wctx.fd, &expected, this->idle_fd, false,  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) {
+		if(__atomic_compare_exchange_n(&this->idle_wctx.sem, &expected, this->idle_wctx.evfd, false,  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) {
 			// Every one agreed, taking a nap
 			break;
@@ -713,5 +710,5 @@
 		{
 			eventfd_t val;
-			ssize_t ret = read( this->idle_fd, &val, sizeof(val) );
+			ssize_t ret = read( this->idle_wctx.evfd, &val, sizeof(val) );
 			if(ret < 0) {
 				switch((int)errno) {
@@ -740,5 +737,5 @@
 			reset(future);
 
-			__kernel_read(this, future, iov, this->idle_fd );
+			__kernel_read(this, future, iov, this->idle_wctx.evfd );
 		}
 
@@ -750,5 +747,5 @@
 	__STATS__(true, ready.sleep.halts++; )
 
-	proc.idle_wctx.fd = 0;
+	proc.idle_wctx.sem = 0;
 
 	/* paranoid */ verify( ! __preemption_enabled() );
@@ -842,5 +839,5 @@
 		if(head == tail) return false;
 		ready_schedule_lock();
-		ret = __cfa_io_drain( proc );
+		ret = __cfa_io_drain( ctx );
 		ready_schedule_unlock();
 	#endif
Index: libcfa/src/concurrency/kernel.hfa
===================================================================
--- libcfa/src/concurrency/kernel.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/kernel.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -48,14 +48,30 @@
 extern struct cluster * mainCluster;
 
-// Processor id, required for scheduling threads
-
-
+// Coroutine used py processors for the 2-step context switch
 coroutine processorCtx_t {
 	struct processor * proc;
 };
 
-
+struct io_future_t;
+
+// Information needed for idle sleep
 struct __fd_waitctx {
-	volatile int fd;
+	// semaphore/future like object
+	// values can be 0, 1 or some file descriptor.
+	// 0 - is the default state
+	// 1 - means the proc should wake-up immediately
+	// FD - means the proc is going asleep and should be woken by writing to the FD.
+	volatile int sem;
+
+	// The event FD that corresponds to this processor
+	int evfd;
+
+	// buffer into which the proc will read from evfd
+	// unused if not using io_uring for idle sleep
+	void * rdbuf;
+
+	// future use to track the read of the eventfd
+	// unused if not using io_uring for idle sleep
+	io_future_t * ftr;
 };
 
@@ -92,6 +108,8 @@
 	struct {
 		$io_context * ctx;
-		bool pending;
-		bool dirty;
+		unsigned id;
+		unsigned target;
+		volatile bool pending;
+		volatile bool dirty;
 	} io;
 
@@ -103,8 +121,5 @@
 	bool pending_preemption;
 
-	// Idle lock (kernel semaphore)
-	int idle_fd;
-
-	// Idle waitctx
+	// context for idle sleep
 	struct __fd_waitctx idle_wctx;
 
@@ -155,5 +170,5 @@
 void ^?{}(__intrusive_lane_t & this);
 
-// Aligned timestamps which are used by the relaxed ready queue
+// Aligned timestamps which are used by the ready queue and io subsystem
 struct __attribute__((aligned(128))) __timestamp_t {
 	volatile unsigned long long tv;
@@ -161,51 +176,11 @@
 };
 
+static inline void  ?{}(__timestamp_t & this) { this.tv = 0; this.ma = 0; }
+static inline void ^?{}(__timestamp_t &) {}
+
+
 struct __attribute__((aligned(16))) __cache_id_t {
 	volatile unsigned id;
 };
-
-// Aligned timestamps which are used by the relaxed ready queue
-struct __attribute__((aligned(128))) __help_cnts_t {
-	volatile unsigned long long src;
-	volatile unsigned long long dst;
-	volatile unsigned long long tri;
-};
-
-static inline void  ?{}(__timestamp_t & this) { this.tv = 0; this.ma = 0; }
-static inline void ^?{}(__timestamp_t &) {}
-
-struct __attribute__((aligned(128))) __ready_queue_caches_t;
-void  ?{}(__ready_queue_caches_t & this);
-void ^?{}(__ready_queue_caches_t & this);
-
-//TODO adjust cache size to ARCHITECTURE
-// Structure holding the ready queue
-struct __ready_queue_t {
-	// Data tracking the actual lanes
-	// On a seperate cacheline from the used struct since
-	// used can change on each push/pop but this data
-	// only changes on shrink/grow
-	struct {
-		// Arary of lanes
-		__intrusive_lane_t * volatile data;
-
-		// Array of times
-		__timestamp_t * volatile tscs;
-
-		__cache_id_t * volatile caches;
-
-		// Array of stats
-		__help_cnts_t * volatile help;
-
-		// Number of lanes (empty or not)
-		volatile size_t count;
-	} lanes;
-};
-
-void  ?{}(__ready_queue_t & this);
-void ^?{}(__ready_queue_t & this);
-#if !defined(__CFA_NO_STATISTICS__)
-	unsigned cnt(const __ready_queue_t & this, unsigned idx);
-#endif
 
 // Idle Sleep
@@ -233,6 +208,33 @@
 // Cluster
 struct __attribute__((aligned(128))) cluster {
-	// Ready queue for threads
-	__ready_queue_t ready_queue;
+	struct {
+		struct {
+			// Arary of subqueues
+			__intrusive_lane_t * data;
+
+			// Time since subqueues were processed
+			__timestamp_t * tscs;
+
+			// Number of subqueue / timestamps
+			size_t count;
+		} readyQ;
+
+		struct {
+			// Array of $io_
+			$io_context ** data;
+
+ 			// Time since subqueues were processed
+			__timestamp_t * tscs;
+
+			// Number of I/O subqueues
+ 			size_t count;
+		} io;
+
+		// Cache each kernel thread belongs to
+		__cache_id_t * caches;
+	} sched;
+
+	// // Ready queue for threads
+	// __ready_queue_t ready_queue;
 
 	// Name of the cluster
Index: libcfa/src/concurrency/kernel/cluster.cfa
===================================================================
--- libcfa/src/concurrency/kernel/cluster.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ libcfa/src/concurrency/kernel/cluster.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,548 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2022 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// cluster.cfa -- file that includes helpers for subsystem that need cluster wide support
+//
+// Author           : Thierry Delisle
+// Created On       : Fri Mar 11 12:39:24 2022
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#define __cforall_thread__
+#define _GNU_SOURCE
+
+#include "bits/defs.hfa"
+#include "device/cpu.hfa"
+#include "kernel/cluster.hfa"
+#include "kernel/private.hfa"
+
+#include "stdlib.hfa"
+#include "limits.hfa"
+#include "math.hfa"
+
+#include "ready_subqueue.hfa"
+
+#include <errno.h>
+#include <unistd.h>
+
+extern "C" {
+	#include <sys/syscall.h>  // __NR_xxx
+}
+
+// No overriden function, no environment variable, no define
+// fall back to a magic number
+#ifndef __CFA_MAX_PROCESSORS__
+	#define __CFA_MAX_PROCESSORS__ 1024
+#endif
+
+#if !defined(__CFA_NO_STATISTICS__)
+	#define __STATS(...) __VA_ARGS__
+#else
+	#define __STATS(...)
+#endif
+
+// returns the maximum number of processors the RWLock support
+__attribute__((weak)) unsigned __max_processors() {
+	const char * max_cores_s = getenv("CFA_MAX_PROCESSORS");
+	if(!max_cores_s) {
+		__cfadbg_print_nolock(ready_queue, "No CFA_MAX_PROCESSORS in ENV\n");
+		return __CFA_MAX_PROCESSORS__;
+	}
+
+	char * endptr = 0p;
+	long int max_cores_l = strtol(max_cores_s, &endptr, 10);
+	if(max_cores_l < 1 || max_cores_l > 65535) {
+		__cfadbg_print_nolock(ready_queue, "CFA_MAX_PROCESSORS out of range : %ld\n", max_cores_l);
+		return __CFA_MAX_PROCESSORS__;
+	}
+	if('\0' != *endptr) {
+		__cfadbg_print_nolock(ready_queue, "CFA_MAX_PROCESSORS not a decimal number : %s\n", max_cores_s);
+		return __CFA_MAX_PROCESSORS__;
+	}
+
+	return max_cores_l;
+}
+
+#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
+	// No forward declaration needed
+	#define __kernel_rseq_register rseq_register_current_thread
+	#define __kernel_rseq_unregister rseq_unregister_current_thread
+#elif defined(CFA_HAVE_LINUX_RSEQ_H)
+	static void __kernel_raw_rseq_register  (void);
+	static void __kernel_raw_rseq_unregister(void);
+
+	#define __kernel_rseq_register __kernel_raw_rseq_register
+	#define __kernel_rseq_unregister __kernel_raw_rseq_unregister
+#else
+	// No forward declaration needed
+	// No initialization needed
+	static inline void noop(void) {}
+
+	#define __kernel_rseq_register noop
+	#define __kernel_rseq_unregister noop
+#endif
+
+//=======================================================================
+// Cluster wide reader-writer lock
+//=======================================================================
+void  ?{}(__scheduler_RWLock_t & this) {
+	this.max   = __max_processors();
+	this.alloc = 0;
+	this.ready = 0;
+	this.data  = alloc(this.max);
+	this.write_lock  = false;
+
+	/*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.alloc), &this.alloc));
+	/*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.ready), &this.ready));
+
+}
+void ^?{}(__scheduler_RWLock_t & this) {
+	free(this.data);
+}
+
+
+//=======================================================================
+// Lock-Free registering/unregistering of threads
+unsigned register_proc_id( void ) with(*__scheduler_lock) {
+	__kernel_rseq_register();
+
+	bool * handle = (bool *)&kernelTLS().sched_lock;
+
+	// Step - 1 : check if there is already space in the data
+	uint_fast32_t s = ready;
+
+	// Check among all the ready
+	for(uint_fast32_t i = 0; i < s; i++) {
+		bool * volatile * cell = (bool * volatile *)&data[i]; // Cforall is bugged and the double volatiles causes problems
+		/* paranoid */ verify( handle != *cell );
+
+		bool * null = 0p; // Re-write every loop since compare thrashes it
+		if( __atomic_load_n(cell, (int)__ATOMIC_RELAXED) == null
+			&& __atomic_compare_exchange_n( cell, &null, handle, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+			/* paranoid */ verify(i < ready);
+			/* paranoid */ verify( (kernelTLS().sched_id = i, true) );
+			return i;
+		}
+	}
+
+	if(max <= alloc) abort("Trying to create more than %ud processors", __scheduler_lock->max);
+
+	// Step - 2 : F&A to get a new spot in the array.
+	uint_fast32_t n = __atomic_fetch_add(&alloc, 1, __ATOMIC_SEQ_CST);
+	if(max <= n) abort("Trying to create more than %ud processors", __scheduler_lock->max);
+
+	// Step - 3 : Mark space as used and then publish it.
+	data[n] = handle;
+	while() {
+		unsigned copy = n;
+		if( __atomic_load_n(&ready, __ATOMIC_RELAXED) == n
+			&& __atomic_compare_exchange_n(&ready, &copy, n + 1, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
+			break;
+		Pause();
+	}
+
+	// Return new spot.
+	/* paranoid */ verify(n < ready);
+	/* paranoid */ verify( (kernelTLS().sched_id = n, true) );
+	return n;
+}
+
+void unregister_proc_id( unsigned id ) with(*__scheduler_lock) {
+	/* paranoid */ verify(id < ready);
+	/* paranoid */ verify(id == kernelTLS().sched_id);
+	/* paranoid */ verify(data[id] == &kernelTLS().sched_lock);
+
+	bool * volatile * cell = (bool * volatile *)&data[id]; // Cforall is bugged and the double volatiles causes problems
+
+	__atomic_store_n(cell, 0p, __ATOMIC_RELEASE);
+
+	__kernel_rseq_unregister();
+}
+
+//-----------------------------------------------------------------------
+// Writer side : acquire when changing the ready queue, e.g. adding more
+//  queues or removing them.
+uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+
+	// Step 1 : lock global lock
+	// It is needed to avoid processors that register mid Critical-Section
+	//   to simply lock their own lock and enter.
+	__atomic_acquire( &write_lock );
+
+	// Make sure we won't deadlock ourself
+	// Checking before acquiring the writer lock isn't safe
+	// because someone else could have locked us.
+	/* paranoid */ verify( ! kernelTLS().sched_lock );
+
+	// Step 2 : lock per-proc lock
+	// Processors that are currently being registered aren't counted
+	//   but can't be in read_lock or in the critical section.
+	// All other processors are counted
+	uint_fast32_t s = ready;
+	for(uint_fast32_t i = 0; i < s; i++) {
+		volatile bool * llock = data[i];
+		if(llock) __atomic_acquire( llock );
+	}
+
+	/* paranoid */ verify( ! __preemption_enabled() );
+	return s;
+}
+
+void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+
+	// Step 1 : release local locks
+	// This must be done while the global lock is held to avoid
+	//   threads that where created mid critical section
+	//   to race to lock their local locks and have the writer
+	//   immidiately unlock them
+	// Alternative solution : return s in write_lock and pass it to write_unlock
+	for(uint_fast32_t i = 0; i < last_s; i++) {
+		volatile bool * llock = data[i];
+		if(llock) __atomic_store_n(llock, (bool)false, __ATOMIC_RELEASE);
+	}
+
+	// Step 2 : release global lock
+	/*paranoid*/ assert(true == write_lock);
+	__atomic_store_n(&write_lock, (bool)false, __ATOMIC_RELEASE);
+
+	/* paranoid */ verify( ! __preemption_enabled() );
+}
+
+//=======================================================================
+// Cluster growth
+static const unsigned __readyq_single_shard = 2;
+
+//-----------------------------------------------------------------------
+// Check that all the intrusive queues in the data structure are still consistent
+static void check_readyQ( cluster * cltr ) with (cltr->sched) {
+	#if defined(__CFA_WITH_VERIFY__)
+		{
+			const unsigned lanes_count = readyQ.count;
+			for( idx ; lanes_count ) {
+				__intrusive_lane_t & sl = readyQ.data[idx];
+				assert(!readyQ.data[idx].lock);
+
+					if(is_empty(sl)) {
+						assert( sl.anchor.next == 0p );
+						assert( sl.anchor.ts   == -1llu );
+						assert( mock_head(sl)  == sl.prev );
+					} else {
+						assert( sl.anchor.next != 0p );
+						assert( sl.anchor.ts   != -1llu );
+						assert( mock_head(sl)  != sl.prev );
+					}
+			}
+		}
+	#endif
+}
+
+// Call this function of the intrusive list was moved using memcpy
+// fixes the list so that the pointers back to anchors aren't left dangling
+static inline void fix(__intrusive_lane_t & ll) {
+	if(is_empty(ll)) {
+		verify(ll.anchor.next == 0p);
+		ll.prev = mock_head(ll);
+	}
+}
+
+static void assign_list(unsigned & valrq, unsigned & valio, dlist(processor) & list, unsigned count) {
+	processor * it = &list`first;
+	for(unsigned i = 0; i < count; i++) {
+		/* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
+		it->rdq.id = valrq;
+		it->rdq.target = MAX;
+		it->io.id = valio;
+		it->io.target = MAX;
+		valrq += __shard_factor.readyq;
+		valio += __shard_factor.io;
+		it = &(*it)`next;
+	}
+}
+
+static void reassign_cltr_id(struct cluster * cltr) {
+	unsigned prefrq = 0;
+	unsigned prefio = 0;
+	assign_list(prefrq, prefio, cltr->procs.actives, cltr->procs.total - cltr->procs.idle);
+	assign_list(prefrq, prefio, cltr->procs.idles  , cltr->procs.idle );
+}
+
+static void assign_io($io_context ** data, size_t count, dlist(processor) & list) {
+	processor * it = &list`first;
+	while(it) {
+		/* paranoid */ verifyf( it, "Unexpected null iterator\n");
+		/* paranoid */ verifyf( it->io.id < count, "Processor %p has id %u above count %zu\n", it, it->rdq.id, count);
+		data[it->io.id] = it->io.ctx;
+		it = &(*it)`next;
+	}
+}
+
+static void reassign_cltr_io(struct cluster * cltr) {
+	assign_io(cltr->sched.io.data, cltr->sched.io.count, cltr->procs.actives);
+	assign_io(cltr->sched.io.data, cltr->sched.io.count, cltr->procs.idles  );
+}
+
+static void fix_times( __timestamp_t * volatile & tscs, unsigned count ) {
+	tscs = alloc(count, tscs`realloc);
+	for(i; count) {
+		tscs[i].tv = rdtscl();
+		tscs[i].ma = 0;
+	}
+}
+
+// Grow the ready queue
+void ready_queue_grow(struct cluster * cltr) {
+	int target = cltr->procs.total;
+
+	/* paranoid */ verify( ready_mutate_islocked() );
+	__cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue\n");
+
+	// Make sure that everything is consistent
+	/* paranoid */ check_readyQ( cltr );
+
+
+	// Find new count
+	// Make sure we always have atleast 1 list
+	size_t ocount = cltr->sched.readyQ.count;
+	size_t ncount = max(target * __shard_factor.readyq, __readyq_single_shard);
+
+	// Do we have to do anything?
+	if( ocount != ncount ) {
+
+		// grow the ready queue
+		with( cltr->sched ) {
+
+			// Allocate new array (uses realloc and memcpies the data)
+			readyQ.data = alloc( ncount, readyQ.data`realloc );
+
+			// Fix the moved data
+			for( idx; ocount ) {
+				fix(readyQ.data[idx]);
+			}
+
+			// Construct new data
+			for( idx; ocount ~ ncount) {
+				(readyQ.data[idx]){};
+			}
+
+			// Update original count
+			readyQ.count = ncount;
+		}
+
+
+		fix_times(cltr->sched.readyQ.tscs, cltr->sched.readyQ.count);
+	}
+
+	// Fix the io times
+	cltr->sched.io.count = target * __shard_factor.io;
+	fix_times(cltr->sched.io.tscs, cltr->sched.io.count);
+
+	// realloc the caches
+	cltr->sched.caches = alloc( target, cltr->sched.caches`realloc );
+
+	// reassign the clusters.
+	reassign_cltr_id(cltr);
+
+	cltr->sched.io.data = alloc( cltr->sched.io.count, cltr->sched.io.data`realloc );
+	reassign_cltr_io(cltr);
+
+	// Make sure that everything is consistent
+	/* paranoid */ check_readyQ( cltr );
+	/* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
+
+	__cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue done\n");
+
+	/* paranoid */ verify( ready_mutate_islocked() );
+}
+
+// Shrink the ready queue
+void ready_queue_shrink(struct cluster * cltr) {
+	/* paranoid */ verify( ready_mutate_islocked() );
+	__cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n");
+
+	// Make sure that everything is consistent
+	/* paranoid */ check_readyQ( cltr );
+
+	int target = cltr->procs.total;
+
+	with( cltr->sched ) {
+		// Remember old count
+		size_t ocount = readyQ.count;
+
+		// Find new count
+		// Make sure we always have atleast 1 list
+		size_t ncount = max(target * __shard_factor.readyq, __readyq_single_shard);
+		/* paranoid */ verifyf( ocount >= ncount, "Error in shrinking size calculation, %zu >= %zu", ocount, ncount );
+		/* paranoid */ verifyf( ncount == target * __shard_factor.readyq || ncount == __readyq_single_shard,
+		/* paranoid */          "Error in shrinking size calculation, expected %u or %u, got %zu", target * __shard_factor.readyq, __readyq_single_shard, ncount );
+
+		readyQ.count = ncount;
+
+		// for printing count the number of displaced threads
+		#if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_READY_QUEUE__)
+			__attribute__((unused)) size_t displaced = 0;
+		#endif
+
+		// redistribute old data
+		for( idx; ncount ~ ocount) {
+			// Lock is not strictly needed but makes checking invariants much easier
+			__attribute__((unused)) bool locked = __atomic_try_acquire(&readyQ.data[idx].lock);
+			verify(locked);
+
+			// As long as we can pop from this lane to push the threads somewhere else in the queue
+			while(!is_empty(readyQ.data[idx])) {
+				struct thread$ * thrd;
+				unsigned long long _;
+				[thrd, _] = pop(readyQ.data[idx]);
+
+				push(cltr, thrd, true);
+
+				// for printing count the number of displaced threads
+				#if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_READY_QUEUE__)
+					displaced++;
+				#endif
+			}
+
+			// Unlock the lane
+			__atomic_unlock(&readyQ.data[idx].lock);
+
+			// TODO print the queue statistics here
+
+			^(readyQ.data[idx]){};
+		}
+
+		__cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue displaced %zu threads\n", displaced);
+
+		// Allocate new array (uses realloc and memcpies the data)
+		readyQ.data = alloc( ncount, readyQ.data`realloc );
+
+		// Fix the moved data
+		for( idx; ncount ) {
+			fix(readyQ.data[idx]);
+		}
+
+		fix_times(readyQ.tscs, ncount);
+	}
+	cltr->sched.caches = alloc( target, cltr->sched.caches`realloc );
+
+	// Fix the io times
+	cltr->sched.io.count = target * __shard_factor.io;
+	fix_times(cltr->sched.io.tscs, cltr->sched.io.count);
+
+	reassign_cltr_id(cltr);
+
+	cltr->sched.io.data = alloc( cltr->sched.io.count, cltr->sched.io.data`realloc );
+	reassign_cltr_io(cltr);
+
+	// Make sure that everything is consistent
+	/* paranoid */ verify( (target == 0) == (cltr->sched.caches == 0p) );
+	/* paranoid */ check_readyQ( cltr );
+
+	__cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue done\n");
+	/* paranoid */ verify( ready_mutate_islocked() );
+}
+
+void ready_queue_close(struct cluster * cltr) {
+	free( cltr->sched.readyQ.data );
+	free( cltr->sched.readyQ.tscs );
+	cltr->sched.readyQ.data = 0p;
+	cltr->sched.readyQ.tscs = 0p;
+ 	cltr->sched.readyQ.count = 0;
+
+	free( cltr->sched.io.tscs );
+	free( cltr->sched.caches );
+}
+
+// Ctor
+void ?{}( __intrusive_lane_t & this ) {
+	this.lock = false;
+	this.prev = mock_head(this);
+	this.anchor.next = 0p;
+	this.anchor.ts   = -1llu;
+	#if !defined(__CFA_NO_STATISTICS__)
+		this.cnt  = 0;
+	#endif
+
+	// We add a boat-load of assertions here because the anchor code is very fragile
+	/* paranoid */ _Static_assert( offsetof( thread$, link ) == offsetof(__intrusive_lane_t, anchor) );
+	/* paranoid */ verify( offsetof( thread$, link ) == offsetof(__intrusive_lane_t, anchor) );
+	/* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( thread$, link )) == (uintptr_t)(&this.anchor) );
+	/* paranoid */ verify( &mock_head(this)->link.next == &this.anchor.next );
+	/* paranoid */ verify( &mock_head(this)->link.ts   == &this.anchor.ts   );
+	/* paranoid */ verify( mock_head(this)->link.next == 0p );
+	/* paranoid */ verify( mock_head(this)->link.ts   == -1llu  );
+	/* paranoid */ verify( mock_head(this) == this.prev );
+	/* paranoid */ verify( __alignof__(__intrusive_lane_t) == 128 );
+	/* paranoid */ verify( __alignof__(this) == 128 );
+	/* paranoid */ verifyf( ((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128) );
+}
+
+// Dtor is trivial
+void ^?{}( __intrusive_lane_t & this ) {
+	// Make sure the list is empty
+	/* paranoid */ verify( this.anchor.next == 0p );
+	/* paranoid */ verify( this.anchor.ts   == -1llu );
+	/* paranoid */ verify( mock_head(this)  == this.prev );
+}
+
+#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
+	// No definition needed
+#elif defined(CFA_HAVE_LINUX_RSEQ_H)
+
+	#if defined( __x86_64 ) || defined( __i386 )
+		#define RSEQ_SIG	0x53053053
+	#elif defined( __ARM_ARCH )
+		#ifdef __ARMEB__
+		#define RSEQ_SIG    0xf3def5e7      /* udf    #24035    ; 0x5de3 (ARMv6+) */
+		#else
+		#define RSEQ_SIG    0xe7f5def3      /* udf    #24035    ; 0x5de3 */
+		#endif
+	#endif
+
+	extern void __disable_interrupts_hard();
+	extern void __enable_interrupts_hard();
+
+	static void __kernel_raw_rseq_register  (void) {
+		/* paranoid */ verify( __cfaabi_rseq.cpu_id == RSEQ_CPU_ID_UNINITIALIZED );
+
+		// int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), 0, (sigset_t *)0p, _NSIG / 8);
+		int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), 0, RSEQ_SIG);
+		if(ret != 0) {
+			int e = errno;
+			switch(e) {
+			case EINVAL: abort("KERNEL ERROR: rseq register invalid argument");
+			case ENOSYS: abort("KERNEL ERROR: rseq register no supported");
+			case EFAULT: abort("KERNEL ERROR: rseq register with invalid argument");
+			case EBUSY : abort("KERNEL ERROR: rseq register already registered");
+			case EPERM : abort("KERNEL ERROR: rseq register sig  argument  on unregistration does not match the signature received on registration");
+			default: abort("KERNEL ERROR: rseq register unexpected return %d", e);
+			}
+		}
+	}
+
+	static void __kernel_raw_rseq_unregister(void) {
+		/* paranoid */ verify( __cfaabi_rseq.cpu_id >= 0 );
+
+		// int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, (sigset_t *)0p, _NSIG / 8);
+		int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
+		if(ret != 0) {
+			int e = errno;
+			switch(e) {
+			case EINVAL: abort("KERNEL ERROR: rseq unregister invalid argument");
+			case ENOSYS: abort("KERNEL ERROR: rseq unregister no supported");
+			case EFAULT: abort("KERNEL ERROR: rseq unregister with invalid argument");
+			case EBUSY : abort("KERNEL ERROR: rseq unregister already registered");
+			case EPERM : abort("KERNEL ERROR: rseq unregister sig  argument  on unregistration does not match the signature received on registration");
+			default: abort("KERNEL ERROR: rseq unregisteunexpected return %d", e);
+			}
+		}
+	}
+#else
+	// No definition needed
+#endif
Index: libcfa/src/concurrency/kernel/cluster.hfa
===================================================================
--- libcfa/src/concurrency/kernel/cluster.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ libcfa/src/concurrency/kernel/cluster.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,80 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2022 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// cluster.hfa -- file that includes helpers for subsystem that need cluster wide support
+//
+// Author           : Thierry Delisle
+// Created On       : Tue Mar 15 16:40:12 2022
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include "kernel/private.hfa"
+
+//-----------------------------------------------------------------------
+// Calc moving average based on existing average, before and current time.
+static inline unsigned long long moving_average(unsigned long long currtsc, unsigned long long instsc, unsigned long long old_avg) {
+	/* paranoid */ verifyf( currtsc < 45000000000000000, "Suspiciously large current time: %'llu (%llx)\n", currtsc, currtsc );
+	/* paranoid */ verifyf( instsc  < 45000000000000000, "Suspiciously large insert time: %'llu (%llx)\n", instsc, instsc );
+	/* paranoid */ verifyf( old_avg < 15000000000000, "Suspiciously large previous average: %'llu (%llx)\n", old_avg, old_avg );
+
+	const unsigned long long new_val = currtsc > instsc ? currtsc - instsc : 0;
+	const unsigned long long total_weight = 16;
+	const unsigned long long new_weight   = 4;
+	const unsigned long long old_weight = total_weight - new_weight;
+	const unsigned long long ret = ((new_weight * new_val) + (old_weight * old_avg)) / total_weight;
+	return ret;
+}
+
+//-----------------------------------------------------------------------
+// Calc age a timestamp should be before needing help.
+forall(Data_t * | { unsigned long long ts(Data_t & this); })
+static inline unsigned long long calc_cutoff(
+	const unsigned long long ctsc,
+	const processor * proc,
+	size_t count,
+	Data_t * data,
+	__timestamp_t * tscs,
+	const unsigned shard_factor
+) {
+	unsigned start = proc->rdq.id;
+	unsigned long long max = 0;
+	for(i; shard_factor) {
+		unsigned long long ptsc = ts(data[start + i]);
+		if(ptsc != -1ull) {
+			/* paranoid */ verify( start + i < count );
+			unsigned long long tsc = moving_average(ctsc, ptsc, tscs[start + i].ma);
+			if(tsc > max) max = tsc;
+		}
+	}
+	return (max + 2 * max) / 2;
+}
+
+static inline unsigned cache_id(struct cluster * cltr, unsigned idx) with (cltr->sched) {
+	// Figure out the current cpu and make sure it is valid
+	const int cpu = __kernel_getcpu();
+	/* paranoid */ verify(cpu >= 0);
+	/* paranoid */ verify(cpu < cpu_info.hthrd_count);
+	unsigned this_cache = cpu_info.llc_map[cpu].cache;
+
+	// Super important: don't write the same value over and over again
+	// We want to maximise our chances that his particular values stays in cache
+	if(caches[idx].id != this_cache)
+		__atomic_store_n(&caches[idx].id, this_cache, __ATOMIC_RELAXED);
+
+	return this_cache;
+}
+
+static struct {
+	const unsigned readyq;
+	const unsigned io;
+} __shard_factor = { 2, 1 };
+
+// Local Variables: //
+// mode: c //
+// tab-width: 4 //
+// End: //
Index: libcfa/src/concurrency/kernel/fwd.hfa
===================================================================
--- libcfa/src/concurrency/kernel/fwd.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/kernel/fwd.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -347,5 +347,5 @@
 					struct oneshot * want = expected == 0p ? 1p : 2p;
 					if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
-						if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return 0p; }
+						if( expected == 0p ) { return 0p; }
 						thread$ * ret = post( *expected, do_unpark );
 						__atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
Index: libcfa/src/concurrency/kernel/private.hfa
===================================================================
--- libcfa/src/concurrency/kernel/private.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ libcfa/src/concurrency/kernel/private.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,374 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// kernel/private.hfa --
+//
+// Author           : Thierry Delisle
+// Created On       : Mon Feb 13 12:27:26 2017
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Wed Aug 12 08:21:33 2020
+// Update Count     : 9
+//
+
+#pragma once
+
+#if !defined(__cforall_thread__)
+	#error kernel/private.hfa should only be included in libcfathread source
+#endif
+
+#include "kernel.hfa"
+#include "thread.hfa"
+
+#include "alarm.hfa"
+#include "stats.hfa"
+
+extern "C" {
+#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
+	#include <rseq/rseq.h>
+#elif defined(CFA_HAVE_LINUX_RSEQ_H)
+	#include <linux/rseq.h>
+#else
+	#ifndef _GNU_SOURCE
+	#error kernel/private requires gnu_source
+	#endif
+	#include <sched.h>
+#endif
+}
+
+// Defines whether or not we *want* to use io_uring_enter as the idle_sleep blocking call
+#define CFA_WANT_IO_URING_IDLE
+
+// Defines whether or not we *can* use io_uring_enter as the idle_sleep blocking call
+#if defined(CFA_WANT_IO_URING_IDLE) && defined(CFA_HAVE_LINUX_IO_URING_H)
+	#if defined(CFA_HAVE_IORING_OP_READ) || (defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV))
+		#define CFA_WITH_IO_URING_IDLE
+	#endif
+#endif
+
+//-----------------------------------------------------------------------------
+// Scheduler
+extern "C" {
+	void disable_interrupts() OPTIONAL_THREAD;
+	void enable_interrupts( bool poll = true );
+}
+
+void schedule_thread$( thread$ *, unpark_hint hint ) __attribute__((nonnull (1)));
+
+extern bool __preemption_enabled();
+
+enum {
+	PREEMPT_NORMAL    = 0,
+	PREEMPT_TERMINATE = 1,
+	PREEMPT_IO = 2,
+};
+
+static inline void __disable_interrupts_checked() {
+	/* paranoid */ verify( __preemption_enabled() );
+	disable_interrupts();
+	/* paranoid */ verify( ! __preemption_enabled() );
+}
+
+static inline void __enable_interrupts_checked( bool poll = true ) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+	enable_interrupts( poll );
+	/* paranoid */ verify( __preemption_enabled() );
+}
+
+//release/wake-up the following resources
+void __thread_finish( thread$ * thrd );
+
+//-----------------------------------------------------------------------------
+// Hardware
+
+#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
+	// No data needed
+#elif defined(CFA_HAVE_LINUX_RSEQ_H)
+	extern "Cforall" {
+		extern __attribute__((aligned(128))) thread_local volatile struct rseq __cfaabi_rseq;
+	}
+#else
+	// No data needed
+#endif
+
+static inline int __kernel_getcpu() {
+	/* paranoid */ verify( ! __preemption_enabled() );
+#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
+	return rseq_current_cpu();
+#elif defined(CFA_HAVE_LINUX_RSEQ_H)
+	int r = __cfaabi_rseq.cpu_id;
+	/* paranoid */ verify( r >= 0 );
+	return r;
+#else
+	return sched_getcpu();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Processor
+void main(processorCtx_t *);
+
+void * __create_pthread( pthread_t *, void * (*)(void *), void * );
+void __destroy_pthread( pthread_t pthread, void * stack, void ** retval );
+
+extern cluster * mainCluster;
+
+//-----------------------------------------------------------------------------
+// Threads
+extern "C" {
+      void __cfactx_invoke_thread(void (*main)(void *), void * this);
+}
+
+__cfaabi_dbg_debug_do(
+	extern void __cfaabi_dbg_thread_register  ( thread$ * thrd );
+	extern void __cfaabi_dbg_thread_unregister( thread$ * thrd );
+)
+
+#define TICKET_BLOCKED (-1) // thread is blocked
+#define TICKET_RUNNING ( 0) // thread is running
+#define TICKET_UNBLOCK ( 1) // thread should ignore next block
+
+//-----------------------------------------------------------------------------
+// Utils
+void doregister( struct cluster * cltr, struct thread$ & thrd );
+void unregister( struct cluster * cltr, struct thread$ & thrd );
+
+//-----------------------------------------------------------------------------
+// I/O
+$io_arbiter * create(void);
+void destroy($io_arbiter *);
+
+//=======================================================================
+// Cluster lock API
+//=======================================================================
+// Lock-Free registering/unregistering of threads
+// Register a processor to a given cluster and get its unique id in return
+unsigned register_proc_id( void );
+
+// Unregister a processor from a given cluster using its id, getting back the original pointer
+void unregister_proc_id( unsigned );
+
+//=======================================================================
+// Reader-writer lock implementation
+// Concurrent with doregister/unregister,
+//    i.e., threads can be added at any point during or between the entry/exit
+
+//-----------------------------------------------------------------------
+// simple spinlock underlying the RWLock
+// Blocking acquire
+static inline void __atomic_acquire(volatile bool * ll) {
+	while( __builtin_expect(__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST), false) ) {
+		while(__atomic_load_n(ll, (int)__ATOMIC_RELAXED))
+			Pause();
+	}
+	/* paranoid */ verify(*ll);
+}
+
+// Non-Blocking acquire
+static inline bool __atomic_try_acquire(volatile bool * ll) {
+	return !__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST);
+}
+
+// Release
+static inline void __atomic_unlock(volatile bool * ll) {
+	/* paranoid */ verify(*ll);
+	__atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
+}
+
+//-----------------------------------------------------------------------
+// Reader-Writer lock protecting the ready-queues
+// while this lock is mostly generic some aspects
+// have been hard-coded to for the ready-queue for
+// simplicity and performance
+struct __scheduler_RWLock_t {
+	// total cachelines allocated
+	unsigned int max;
+
+	// cachelines currently in use
+	volatile unsigned int alloc;
+
+	// cachelines ready to itereate over
+	// (!= to alloc when thread is in second half of doregister)
+	volatile unsigned int ready;
+
+	// writer lock
+	volatile bool write_lock;
+
+	// data pointer
+	volatile bool * volatile * data;
+};
+
+void  ?{}(__scheduler_RWLock_t & this);
+void ^?{}(__scheduler_RWLock_t & this);
+
+extern __scheduler_RWLock_t * __scheduler_lock;
+
+//-----------------------------------------------------------------------
+// Reader side : acquire when using the ready queue to schedule but not
+//  creating/destroying queues
+static inline void ready_schedule_lock(void) with(*__scheduler_lock) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+	/* paranoid */ verify( ! kernelTLS().in_sched_lock );
+	/* paranoid */ verify( data[kernelTLS().sched_id] == &kernelTLS().sched_lock );
+	/* paranoid */ verify( !kernelTLS().this_processor || kernelTLS().this_processor->unique_id == kernelTLS().sched_id );
+
+	// Step 1 : make sure no writer are in the middle of the critical section
+	while(__atomic_load_n(&write_lock, (int)__ATOMIC_RELAXED))
+		Pause();
+
+	// Fence needed because we don't want to start trying to acquire the lock
+	// before we read a false.
+	// Not needed on x86
+	// std::atomic_thread_fence(std::memory_order_seq_cst);
+
+	// Step 2 : acquire our local lock
+	__atomic_acquire( &kernelTLS().sched_lock );
+	/*paranoid*/ verify(kernelTLS().sched_lock);
+
+	#ifdef __CFA_WITH_VERIFY__
+		// Debug, check if this is owned for reading
+		kernelTLS().in_sched_lock = true;
+	#endif
+}
+
+static inline void ready_schedule_unlock(void) with(*__scheduler_lock) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+	/* paranoid */ verify( data[kernelTLS().sched_id] == &kernelTLS().sched_lock );
+	/* paranoid */ verify( !kernelTLS().this_processor || kernelTLS().this_processor->unique_id == kernelTLS().sched_id );
+	/* paranoid */ verify( kernelTLS().sched_lock );
+	/* paranoid */ verify( kernelTLS().in_sched_lock );
+	#ifdef __CFA_WITH_VERIFY__
+		// Debug, check if this is owned for reading
+		kernelTLS().in_sched_lock = false;
+	#endif
+	__atomic_unlock(&kernelTLS().sched_lock);
+}
+
+#ifdef __CFA_WITH_VERIFY__
+	static inline bool ready_schedule_islocked(void) {
+		/* paranoid */ verify( ! __preemption_enabled() );
+		/* paranoid */ verify( (!kernelTLS().in_sched_lock) || kernelTLS().sched_lock );
+		return kernelTLS().sched_lock;
+	}
+
+	static inline bool ready_mutate_islocked() {
+		return __scheduler_lock->write_lock;
+	}
+#endif
+
+//-----------------------------------------------------------------------
+// Writer side : acquire when changing the ready queue, e.g. adding more
+//  queues or removing them.
+uint_fast32_t ready_mutate_lock( void );
+
+void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ );
+
+//-----------------------------------------------------------------------
+// Lock-Free registering/unregistering of threads
+// Register a processor to a given cluster and get its unique id in return
+// For convenience, also acquires the lock
+static inline [unsigned, uint_fast32_t] ready_mutate_register() {
+	unsigned id = register_proc_id();
+	uint_fast32_t last = ready_mutate_lock();
+	return [id, last];
+}
+
+// Unregister a processor from a given cluster using its id, getting back the original pointer
+// assumes the lock is acquired
+static inline void ready_mutate_unregister( unsigned id, uint_fast32_t last_s ) {
+	ready_mutate_unlock( last_s );
+	unregister_proc_id( id );
+}
+
+//-----------------------------------------------------------------------
+// Cluster idle lock/unlock
+static inline void lock(__cluster_proc_list & this) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+
+	// Start by locking the global RWlock so that we know no-one is
+	// adding/removing processors while we mess with the idle lock
+	ready_schedule_lock();
+
+	lock( this.lock __cfaabi_dbg_ctx2 );
+
+	/* paranoid */ verify( ! __preemption_enabled() );
+}
+
+static inline bool try_lock(__cluster_proc_list & this) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+
+	// Start by locking the global RWlock so that we know no-one is
+	// adding/removing processors while we mess with the idle lock
+	ready_schedule_lock();
+
+	if(try_lock( this.lock __cfaabi_dbg_ctx2 )) {
+		// success
+		/* paranoid */ verify( ! __preemption_enabled() );
+		return true;
+	}
+
+	// failed to lock
+	ready_schedule_unlock();
+
+	/* paranoid */ verify( ! __preemption_enabled() );
+	return false;
+}
+
+static inline void unlock(__cluster_proc_list & this) {
+	/* paranoid */ verify( ! __preemption_enabled() );
+
+	unlock(this.lock);
+
+	// Release the global lock, which we acquired when locking
+	ready_schedule_unlock();
+
+	/* paranoid */ verify( ! __preemption_enabled() );
+}
+
+//=======================================================================
+// Ready-Queue API
+//-----------------------------------------------------------------------
+// push thread onto a ready queue for a cluster
+// returns true if the list was previously empty, false otherwise
+__attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint);
+
+//-----------------------------------------------------------------------
+// pop thread from the local queues of a cluster
+// returns 0p if empty
+// May return 0p spuriously
+__attribute__((hot)) struct thread$ * pop_fast(struct cluster * cltr);
+
+//-----------------------------------------------------------------------
+// pop thread from any ready queue of a cluster
+// returns 0p if empty
+// May return 0p spuriously
+__attribute__((hot)) struct thread$ * pop_slow(struct cluster * cltr);
+
+//-----------------------------------------------------------------------
+// search all ready queues of a cluster for any thread
+// returns 0p if empty
+// guaranteed to find any threads added before this call
+__attribute__((hot)) struct thread$ * pop_search(struct cluster * cltr);
+
+//-----------------------------------------------------------------------
+// get preferred ready for new thread
+unsigned ready_queue_new_preferred();
+
+//-----------------------------------------------------------------------
+// Increase the width of the ready queue (number of lanes) by 4
+void ready_queue_grow  (struct cluster * cltr);
+
+//-----------------------------------------------------------------------
+// Decrease the width of the ready queue (number of lanes) by 4
+void ready_queue_shrink(struct cluster * cltr);
+
+//-----------------------------------------------------------------------
+// Decrease the width of the ready queue (number of lanes) by 4
+void ready_queue_close(struct cluster * cltr);
+
+// Local Variables: //
+// mode: c //
+// tab-width: 4 //
+// End: //
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -18,20 +18,21 @@
 
 // C Includes
-#include <errno.h>										// errno
+#include <errno.h>					// errno
 #include <signal.h>
-#include <string.h>										// strerror
-#include <unistd.h>										// sysconf
+#include <string.h>					// strerror
+#include <unistd.h>					// sysconf
 
 extern "C" {
-	#include <limits.h>									// PTHREAD_STACK_MIN
-	#include <unistd.h>									// syscall
-	#include <sys/eventfd.h>							// eventfd
-	#include <sys/mman.h>								// mprotect
-	#include <sys/resource.h>							// getrlimit
+	#include <limits.h>				// PTHREAD_STACK_MIN
+	#include <unistd.h>				// syscall
+	#include <sys/eventfd.h>			// eventfd
+	#include <sys/mman.h>				// mprotect
+	#include <sys/resource.h>			// getrlimit
 }
 
 // CFA Includes
-#include "kernel_private.hfa"
-#include "startup.hfa"									// STARTUP_PRIORITY_XXX
+#include "kernel/private.hfa"
+#include "iofwd.hfa"
+#include "startup.hfa"					// STARTUP_PRIORITY_XXX
 #include "limits.hfa"
 #include "math.hfa"
@@ -97,4 +98,6 @@
 extern void __kernel_alarm_startup(void);
 extern void __kernel_alarm_shutdown(void);
+extern void __cfa_io_start( processor * );
+extern void __cfa_io_stop ( processor * );
 
 //-----------------------------------------------------------------------------
@@ -111,4 +114,6 @@
 KERNEL_STORAGE(__stack_t,            mainThreadCtx);
 KERNEL_STORAGE(__scheduler_RWLock_t, __scheduler_lock);
+KERNEL_STORAGE(eventfd_t,            mainIdleEventFd);
+KERNEL_STORAGE(io_future_t,          mainIdleFuture);
 #if !defined(__CFA_NO_STATISTICS__)
 KERNEL_STORAGE(__stats_t, mainProcStats);
@@ -224,5 +229,10 @@
 	(*mainProcessor){};
 
+	mainProcessor->idle_wctx.rdbuf = &storage_mainIdleEventFd;
+	mainProcessor->idle_wctx.ftr   = (io_future_t*)&storage_mainIdleFuture;
+	/* paranoid */ verify( sizeof(storage_mainIdleEventFd) == sizeof(eventfd_t) );
+
 	register_tls( mainProcessor );
+	__cfa_io_start( mainProcessor );
 
 	// Start by initializing the main thread
@@ -304,4 +314,5 @@
 	mainProcessor->local_data = 0p;
 
+	__cfa_io_stop( mainProcessor );
 	unregister_tls( mainProcessor );
 
@@ -355,4 +366,13 @@
 	register_tls( proc );
 
+	__cfa_io_start( proc );
+
+	// used for idle sleep when io_uring is present
+	io_future_t future;
+	eventfd_t idle_buf;
+	proc->idle_wctx.ftr = &future;
+	proc->idle_wctx.rdbuf = &idle_buf;
+
+
 	// SKULLDUGGERY: We want to create a context for the processor coroutine
 	// which is needed for the 2-step context switch. However, there is no reason
@@ -381,4 +401,6 @@
 	// Main routine of the core returned, the core is now fully terminated
 	__cfadbg_print_safe(runtime_core, "Kernel : core %p main ended (%p)\n", proc, &proc->runner);
+
+	__cfa_io_stop( proc );
 
 	#if !defined(__CFA_NO_STATISTICS__)
@@ -515,5 +537,5 @@
 	this.rdq.its = 0;
 	this.rdq.itr = 0;
-	this.rdq.id  = MAX;
+	this.rdq.id  = 0;
 	this.rdq.target = MAX;
 	this.rdq.last = MAX;
@@ -532,15 +554,15 @@
 	this.local_data = 0p;
 
-	this.idle_fd = eventfd(0, 0);
-	if (idle_fd < 0) {
+	idle_wctx.evfd = eventfd(0, 0);
+	if (idle_wctx.evfd < 0) {
 		abort("KERNEL ERROR: PROCESSOR EVENTFD - %s\n", strerror(errno));
 	}
 
-	this.idle_wctx.fd = 0;
+	idle_wctx.sem = 0;
 
 	// I'm assuming these two are reserved for standard input and output
 	// so I'm using them as sentinels with idle_wctx.
-	/* paranoid */ verify( this.idle_fd != 0 );
-	/* paranoid */ verify( this.idle_fd != 1 );
+	/* paranoid */ verify( idle_wctx.evfd != 0 );
+	/* paranoid */ verify( idle_wctx.evfd != 1 );
 
 	#if !defined(__CFA_NO_STATISTICS__)
@@ -554,5 +576,5 @@
 // Not a ctor, it just preps the destruction but should not destroy members
 static void deinit(processor & this) {
-	close(this.idle_fd);
+	close(this.idle_wctx.evfd);
 }
 
@@ -605,5 +627,9 @@
 	this.name = name;
 	this.preemption_rate = preemption_rate;
-	ready_queue{};
+	this.sched.readyQ.data = 0p;
+	this.sched.readyQ.tscs = 0p;
+ 	this.sched.readyQ.count = 0;
+	this.sched.io.tscs = 0p;
+	this.sched.caches = 0p;
 
 	#if !defined(__CFA_NO_STATISTICS__)
@@ -644,5 +670,14 @@
 	// Unlock the RWlock
 	ready_mutate_unlock( last_size );
+
+	ready_queue_close( &this );
+	/* paranoid */ verify( this.sched.readyQ.data == 0p );
+	/* paranoid */ verify( this.sched.readyQ.tscs == 0p );
+ 	/* paranoid */ verify( this.sched.readyQ.count == 0 );
+	/* paranoid */ verify( this.sched.io.tscs == 0p );
+	/* paranoid */ verify( this.sched.caches == 0p );
+
 	enable_interrupts( false ); // Don't poll, could be in main cluster
+
 
 	#if !defined(__CFA_NO_STATISTICS__)
@@ -736,5 +771,5 @@
 	check( pthread_attr_init( &attr ), "pthread_attr_init" ); // initialize attribute
 
-	size_t stacksize = DEFAULT_STACK_SIZE;
+	size_t stacksize = max( PTHREAD_STACK_MIN, DEFAULT_STACK_SIZE );
 
 	void * stack;
Index: bcfa/src/concurrency/kernel_private.hfa
===================================================================
--- libcfa/src/concurrency/kernel_private.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ 	(revision )
@@ -1,365 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// kernel_private.hfa --
-//
-// Author           : Thierry Delisle
-// Created On       : Mon Feb 13 12:27:26 2017
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Aug 12 08:21:33 2020
-// Update Count     : 9
-//
-
-#pragma once
-
-#if !defined(__cforall_thread__)
-	#error kernel_private.hfa should only be included in libcfathread source
-#endif
-
-#include "kernel.hfa"
-#include "thread.hfa"
-
-#include "alarm.hfa"
-#include "stats.hfa"
-
-extern "C" {
-#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
-	#include <rseq/rseq.h>
-#elif defined(CFA_HAVE_LINUX_RSEQ_H)
-	#include <linux/rseq.h>
-#else
-	#ifndef _GNU_SOURCE
-	#error kernel_private requires gnu_source
-	#endif
-	#include <sched.h>
-#endif
-}
-
-// Defines whether or not we *want* to use io_uring_enter as the idle_sleep blocking call
-#define CFA_WANT_IO_URING_IDLE
-
-// Defines whether or not we *can* use io_uring_enter as the idle_sleep blocking call
-#if defined(CFA_WANT_IO_URING_IDLE) && defined(CFA_HAVE_LINUX_IO_URING_H)
-	#if defined(CFA_HAVE_IORING_OP_READ) || (defined(CFA_HAVE_READV) && defined(CFA_HAVE_IORING_OP_READV))
-		#define CFA_WITH_IO_URING_IDLE
-	#endif
-#endif
-
-//-----------------------------------------------------------------------------
-// Scheduler
-extern "C" {
-	void disable_interrupts() OPTIONAL_THREAD;
-	void enable_interrupts( bool poll = true );
-}
-
-void schedule_thread$( thread$ *, unpark_hint hint ) __attribute__((nonnull (1)));
-
-extern bool __preemption_enabled();
-
-static inline void __disable_interrupts_checked() {
-	/* paranoid */ verify( __preemption_enabled() );
-	disable_interrupts();
-	/* paranoid */ verify( ! __preemption_enabled() );
-}
-
-static inline void __enable_interrupts_checked( bool poll = true ) {
-	/* paranoid */ verify( ! __preemption_enabled() );
-	enable_interrupts( poll );
-	/* paranoid */ verify( __preemption_enabled() );
-}
-
-//release/wake-up the following resources
-void __thread_finish( thread$ * thrd );
-
-//-----------------------------------------------------------------------------
-// Hardware
-
-#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
-	// No data needed
-#elif defined(CFA_HAVE_LINUX_RSEQ_H)
-	extern "Cforall" {
-		extern __attribute__((aligned(128))) thread_local volatile struct rseq __cfaabi_rseq;
-	}
-#else
-	// No data needed
-#endif
-
-static inline int __kernel_getcpu() {
-	/* paranoid */ verify( ! __preemption_enabled() );
-#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
-	return rseq_current_cpu();
-#elif defined(CFA_HAVE_LINUX_RSEQ_H)
-	int r = __cfaabi_rseq.cpu_id;
-	/* paranoid */ verify( r >= 0 );
-	return r;
-#else
-	return sched_getcpu();
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Processor
-void main(processorCtx_t *);
-
-void * __create_pthread( pthread_t *, void * (*)(void *), void * );
-void __destroy_pthread( pthread_t pthread, void * stack, void ** retval );
-
-extern cluster * mainCluster;
-
-//-----------------------------------------------------------------------------
-// Threads
-extern "C" {
-      void __cfactx_invoke_thread(void (*main)(void *), void * this);
-}
-
-__cfaabi_dbg_debug_do(
-	extern void __cfaabi_dbg_thread_register  ( thread$ * thrd );
-	extern void __cfaabi_dbg_thread_unregister( thread$ * thrd );
-)
-
-#define TICKET_BLOCKED (-1) // thread is blocked
-#define TICKET_RUNNING ( 0) // thread is running
-#define TICKET_UNBLOCK ( 1) // thread should ignore next block
-
-//-----------------------------------------------------------------------------
-// Utils
-void doregister( struct cluster * cltr, struct thread$ & thrd );
-void unregister( struct cluster * cltr, struct thread$ & thrd );
-
-//-----------------------------------------------------------------------------
-// I/O
-$io_arbiter * create(void);
-void destroy($io_arbiter *);
-
-//=======================================================================
-// Cluster lock API
-//=======================================================================
-// Lock-Free registering/unregistering of threads
-// Register a processor to a given cluster and get its unique id in return
-unsigned register_proc_id( void );
-
-// Unregister a processor from a given cluster using its id, getting back the original pointer
-void unregister_proc_id( unsigned );
-
-//=======================================================================
-// Reader-writer lock implementation
-// Concurrent with doregister/unregister,
-//    i.e., threads can be added at any point during or between the entry/exit
-
-//-----------------------------------------------------------------------
-// simple spinlock underlying the RWLock
-// Blocking acquire
-static inline void __atomic_acquire(volatile bool * ll) {
-	while( __builtin_expect(__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST), false) ) {
-		while(__atomic_load_n(ll, (int)__ATOMIC_RELAXED))
-			Pause();
-	}
-	/* paranoid */ verify(*ll);
-}
-
-// Non-Blocking acquire
-static inline bool __atomic_try_acquire(volatile bool * ll) {
-	return !__atomic_exchange_n(ll, (bool)true, __ATOMIC_SEQ_CST);
-}
-
-// Release
-static inline void __atomic_unlock(volatile bool * ll) {
-	/* paranoid */ verify(*ll);
-	__atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
-}
-
-//-----------------------------------------------------------------------
-// Reader-Writer lock protecting the ready-queues
-// while this lock is mostly generic some aspects
-// have been hard-coded to for the ready-queue for
-// simplicity and performance
-struct __scheduler_RWLock_t {
-	// total cachelines allocated
-	unsigned int max;
-
-	// cachelines currently in use
-	volatile unsigned int alloc;
-
-	// cachelines ready to itereate over
-	// (!= to alloc when thread is in second half of doregister)
-	volatile unsigned int ready;
-
-	// writer lock
-	volatile bool write_lock;
-
-	// data pointer
-	volatile bool * volatile * data;
-};
-
-void  ?{}(__scheduler_RWLock_t & this);
-void ^?{}(__scheduler_RWLock_t & this);
-
-extern __scheduler_RWLock_t * __scheduler_lock;
-
-//-----------------------------------------------------------------------
-// Reader side : acquire when using the ready queue to schedule but not
-//  creating/destroying queues
-static inline void ready_schedule_lock(void) with(*__scheduler_lock) {
-	/* paranoid */ verify( ! __preemption_enabled() );
-	/* paranoid */ verify( ! kernelTLS().in_sched_lock );
-	/* paranoid */ verify( data[kernelTLS().sched_id] == &kernelTLS().sched_lock );
-	/* paranoid */ verify( !kernelTLS().this_processor || kernelTLS().this_processor->unique_id == kernelTLS().sched_id );
-
-	// Step 1 : make sure no writer are in the middle of the critical section
-	while(__atomic_load_n(&write_lock, (int)__ATOMIC_RELAXED))
-		Pause();
-
-	// Fence needed because we don't want to start trying to acquire the lock
-	// before we read a false.
-	// Not needed on x86
-	// std::atomic_thread_fence(std::memory_order_seq_cst);
-
-	// Step 2 : acquire our local lock
-	__atomic_acquire( &kernelTLS().sched_lock );
-	/*paranoid*/ verify(kernelTLS().sched_lock);
-
-	#ifdef __CFA_WITH_VERIFY__
-		// Debug, check if this is owned for reading
-		kernelTLS().in_sched_lock = true;
-	#endif
-}
-
-static inline void ready_schedule_unlock(void) with(*__scheduler_lock) {
-	/* paranoid */ verify( ! __preemption_enabled() );
-	/* paranoid */ verify( data[kernelTLS().sched_id] == &kernelTLS().sched_lock );
-	/* paranoid */ verify( !kernelTLS().this_processor || kernelTLS().this_processor->unique_id == kernelTLS().sched_id );
-	/* paranoid */ verify( kernelTLS().sched_lock );
-	/* paranoid */ verify( kernelTLS().in_sched_lock );
-	#ifdef __CFA_WITH_VERIFY__
-		// Debug, check if this is owned for reading
-		kernelTLS().in_sched_lock = false;
-	#endif
-	__atomic_unlock(&kernelTLS().sched_lock);
-}
-
-#ifdef __CFA_WITH_VERIFY__
-	static inline bool ready_schedule_islocked(void) {
-		/* paranoid */ verify( ! __preemption_enabled() );
-		/* paranoid */ verify( (!kernelTLS().in_sched_lock) || kernelTLS().sched_lock );
-		return kernelTLS().sched_lock;
-	}
-
-	static inline bool ready_mutate_islocked() {
-		return __scheduler_lock->write_lock;
-	}
-#endif
-
-//-----------------------------------------------------------------------
-// Writer side : acquire when changing the ready queue, e.g. adding more
-//  queues or removing them.
-uint_fast32_t ready_mutate_lock( void );
-
-void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ );
-
-//-----------------------------------------------------------------------
-// Lock-Free registering/unregistering of threads
-// Register a processor to a given cluster and get its unique id in return
-// For convenience, also acquires the lock
-static inline [unsigned, uint_fast32_t] ready_mutate_register() {
-	unsigned id = register_proc_id();
-	uint_fast32_t last = ready_mutate_lock();
-	return [id, last];
-}
-
-// Unregister a processor from a given cluster using its id, getting back the original pointer
-// assumes the lock is acquired
-static inline void ready_mutate_unregister( unsigned id, uint_fast32_t last_s ) {
-	ready_mutate_unlock( last_s );
-	unregister_proc_id( id );
-}
-
-//-----------------------------------------------------------------------
-// Cluster idle lock/unlock
-static inline void lock(__cluster_proc_list & this) {
-	/* paranoid */ verify( ! __preemption_enabled() );
-
-	// Start by locking the global RWlock so that we know no-one is
-	// adding/removing processors while we mess with the idle lock
-	ready_schedule_lock();
-
-	lock( this.lock __cfaabi_dbg_ctx2 );
-
-	/* paranoid */ verify( ! __preemption_enabled() );
-}
-
-static inline bool try_lock(__cluster_proc_list & this) {
-	/* paranoid */ verify( ! __preemption_enabled() );
-
-	// Start by locking the global RWlock so that we know no-one is
-	// adding/removing processors while we mess with the idle lock
-	ready_schedule_lock();
-
-	if(try_lock( this.lock __cfaabi_dbg_ctx2 )) {
-		// success
-		/* paranoid */ verify( ! __preemption_enabled() );
-		return true;
-	}
-
-	// failed to lock
-	ready_schedule_unlock();
-
-	/* paranoid */ verify( ! __preemption_enabled() );
-	return false;
-}
-
-static inline void unlock(__cluster_proc_list & this) {
-	/* paranoid */ verify( ! __preemption_enabled() );
-
-	unlock(this.lock);
-
-	// Release the global lock, which we acquired when locking
-	ready_schedule_unlock();
-
-	/* paranoid */ verify( ! __preemption_enabled() );
-}
-
-//=======================================================================
-// Ready-Queue API
-//-----------------------------------------------------------------------
-// push thread onto a ready queue for a cluster
-// returns true if the list was previously empty, false otherwise
-__attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint);
-
-//-----------------------------------------------------------------------
-// pop thread from the local queues of a cluster
-// returns 0p if empty
-// May return 0p spuriously
-__attribute__((hot)) struct thread$ * pop_fast(struct cluster * cltr);
-
-//-----------------------------------------------------------------------
-// pop thread from any ready queue of a cluster
-// returns 0p if empty
-// May return 0p spuriously
-__attribute__((hot)) struct thread$ * pop_slow(struct cluster * cltr);
-
-//-----------------------------------------------------------------------
-// search all ready queues of a cluster for any thread
-// returns 0p if empty
-// guaranteed to find any threads added before this call
-__attribute__((hot)) struct thread$ * pop_search(struct cluster * cltr);
-
-//-----------------------------------------------------------------------
-// get preferred ready for new thread
-unsigned ready_queue_new_preferred();
-
-//-----------------------------------------------------------------------
-// Increase the width of the ready queue (number of lanes) by 4
-void ready_queue_grow  (struct cluster * cltr);
-
-//-----------------------------------------------------------------------
-// Decrease the width of the ready queue (number of lanes) by 4
-void ready_queue_shrink(struct cluster * cltr);
-
-
-// Local Variables: //
-// mode: c //
-// tab-width: 4 //
-// End: //
Index: libcfa/src/concurrency/locks.cfa
===================================================================
--- libcfa/src/concurrency/locks.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/locks.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -19,5 +19,5 @@
 
 #include "locks.hfa"
-#include "kernel_private.hfa"
+#include "kernel/private.hfa"
 
 #include <kernel.hfa>
Index: libcfa/src/concurrency/locks.hfa
===================================================================
--- libcfa/src/concurrency/locks.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/locks.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -164,7 +164,7 @@
 }
 
-static inline bool lock(linear_backoff_then_block_lock & this) with(this) {
+static inline void lock(linear_backoff_then_block_lock & this) with(this) {
 	// if owner just return
-	if (active_thread() == owner) return true;
+	if (active_thread() == owner) return;
 	size_t compare_val = 0;
 	int spin = spin_start;
@@ -172,5 +172,5 @@
 	for( ;; ) {
 		compare_val = 0;
-		if (internal_try_lock(this, compare_val)) return true;
+		if (internal_try_lock(this, compare_val)) return;
 		if (2 == compare_val) break;
 		for (int i = 0; i < spin; i++) Pause();
@@ -179,10 +179,7 @@
 	}
 
-	if(2 != compare_val && try_lock_contention(this)) return true;
+	if(2 != compare_val && try_lock_contention(this)) return;
 	// block until signalled
-	while (block(this)) if(try_lock_contention(this)) return true;
-
-	// this should never be reached as block(this) always returns true
-	return false;
+	while (block(this)) if(try_lock_contention(this)) return;
 }
 
Index: libcfa/src/concurrency/monitor.cfa
===================================================================
--- libcfa/src/concurrency/monitor.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/monitor.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -22,5 +22,5 @@
 #include <inttypes.h>
 
-#include "kernel_private.hfa"
+#include "kernel/private.hfa"
 
 #include "bits/algorithm.hfa"
Index: libcfa/src/concurrency/mutex.cfa
===================================================================
--- libcfa/src/concurrency/mutex.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/mutex.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -21,5 +21,5 @@
 #include "mutex.hfa"
 
-#include "kernel_private.hfa"
+#include "kernel/private.hfa"
 
 //-----------------------------------------------------------------------------
Index: libcfa/src/concurrency/mutex_stmt.hfa
===================================================================
--- libcfa/src/concurrency/mutex_stmt.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/mutex_stmt.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -12,29 +12,30 @@
 };
 
+
+struct __mutex_stmt_lock_guard {
+    void ** lockarr;
+    __lock_size_t count;
+};
+
+static inline void ?{}( __mutex_stmt_lock_guard & this, void * lockarr [], __lock_size_t count  ) {
+    this.lockarr = lockarr;
+    this.count = count;
+
+    // Sort locks based on address
+    __libcfa_small_sort(this.lockarr, count);
+
+    // acquire locks in order
+    // for ( size_t i = 0; i < count; i++ ) {
+    //     lock(*this.lockarr[i]);
+    // }
+}
+
+static inline void ^?{}( __mutex_stmt_lock_guard & this ) with(this) {
+    // for ( size_t i = count; i > 0; i-- ) {
+    //     unlock(*lockarr[i - 1]);
+    // }
+}
+
 forall(L & | is_lock(L)) {
-
-    struct __mutex_stmt_lock_guard {
-        L ** lockarr;
-        __lock_size_t count;
-    };
-    
-    static inline void ?{}( __mutex_stmt_lock_guard(L) & this, L * lockarr [], __lock_size_t count  ) {
-        this.lockarr = lockarr;
-        this.count = count;
-
-        // Sort locks based on address
-        __libcfa_small_sort(this.lockarr, count);
-
-        // acquire locks in order
-        for ( size_t i = 0; i < count; i++ ) {
-            lock(*this.lockarr[i]);
-        }
-    }
-    
-    static inline void ^?{}( __mutex_stmt_lock_guard(L) & this ) with(this) {
-        for ( size_t i = count; i > 0; i-- ) {
-            unlock(*lockarr[i - 1]);
-        }
-    }
 
     struct scoped_lock {
@@ -51,10 +52,10 @@
     }
 
-    static inline L * __get_ptr( L & this ) {
+    static inline void * __get_mutexstmt_lock_ptr( L & this ) {
         return &this;
     }
 
-    static inline L __get_type( L & this );
+    static inline L __get_mutexstmt_lock_type( L & this );
 
-    static inline L __get_type( L * this );
+    static inline L __get_mutexstmt_lock_type( L * this );
 }
Index: libcfa/src/concurrency/preemption.cfa
===================================================================
--- libcfa/src/concurrency/preemption.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/preemption.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jun 5 14:20:42 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Nov  6 07:42:13 2020
-// Update Count     : 54
+// Last Modified On : Thu Feb 17 11:18:57 2022
+// Update Count     : 59
 //
 
@@ -31,5 +31,5 @@
 #include "bits/debug.hfa"
 #include "bits/signal.hfa"
-#include "kernel_private.hfa"
+#include "kernel/private.hfa"
 
 
@@ -97,9 +97,4 @@
 }
 
-enum {
-	PREEMPT_NORMAL    = 0,
-	PREEMPT_TERMINATE = 1,
-};
-
 //=============================================================================================
 // Kernel Preemption logic
@@ -243,5 +238,5 @@
 //----------
 // special case for preemption since used often
-bool __preemption_enabled() {
+__attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() {
 	// create a assembler label before
 	// marked as clobber all to avoid movement
@@ -664,4 +659,5 @@
 	choose(sfp->si_value.sival_int) {
 		case PREEMPT_NORMAL   : ;// Normal case, nothing to do here
+		case PREEMPT_IO       : ;// I/O asked to stop spinning, nothing to do here
 		case PREEMPT_TERMINATE: verify( __atomic_load_n( &__cfaabi_tls.this_processor->do_terminate, __ATOMIC_SEQ_CST ) );
 		default:
Index: libcfa/src/concurrency/ready_queue.cfa
===================================================================
--- libcfa/src/concurrency/ready_queue.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/ready_queue.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -20,23 +20,15 @@
 
 
-// #define USE_RELAXED_FIFO
-// #define USE_WORK_STEALING
-// #define USE_CPU_WORK_STEALING
 #define USE_AWARE_STEALING
 
 #include "bits/defs.hfa"
 #include "device/cpu.hfa"
-#include "kernel_private.hfa"
-
-#include "stdlib.hfa"
+#include "kernel/cluster.hfa"
+#include "kernel/private.hfa"
+
 #include "limits.hfa"
-#include "math.hfa"
-
-#include <errno.h>
-#include <unistd.h>
-
-extern "C" {
-	#include <sys/syscall.h>  // __NR_xxx
-}
+
+// #include <errno.h>
+// #include <unistd.h>
 
 #include "ready_subqueue.hfa"
@@ -50,765 +42,130 @@
 #endif
 
-// No overriden function, no environment variable, no define
-// fall back to a magic number
-#ifndef __CFA_MAX_PROCESSORS__
-	#define __CFA_MAX_PROCESSORS__ 1024
-#endif
-
-#if   defined(USE_AWARE_STEALING)
-	#define READYQ_SHARD_FACTOR 2
-	#define SEQUENTIAL_SHARD 2
-#elif defined(USE_CPU_WORK_STEALING)
-	#define READYQ_SHARD_FACTOR 2
-#elif defined(USE_RELAXED_FIFO)
-	#define BIAS 4
-	#define READYQ_SHARD_FACTOR 4
-	#define SEQUENTIAL_SHARD 1
-#elif defined(USE_WORK_STEALING)
-	#define READYQ_SHARD_FACTOR 2
-	#define SEQUENTIAL_SHARD 2
-#else
-	#error no scheduling strategy selected
-#endif
-
 static inline struct thread$ * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats));
 static inline struct thread$ * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats));
 static inline struct thread$ * search(struct cluster * cltr);
-static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred);
-
-
-// returns the maximum number of processors the RWLock support
-__attribute__((weak)) unsigned __max_processors() {
-	const char * max_cores_s = getenv("CFA_MAX_PROCESSORS");
-	if(!max_cores_s) {
-		__cfadbg_print_nolock(ready_queue, "No CFA_MAX_PROCESSORS in ENV\n");
-		return __CFA_MAX_PROCESSORS__;
-	}
-
-	char * endptr = 0p;
-	long int max_cores_l = strtol(max_cores_s, &endptr, 10);
-	if(max_cores_l < 1 || max_cores_l > 65535) {
-		__cfadbg_print_nolock(ready_queue, "CFA_MAX_PROCESSORS out of range : %ld\n", max_cores_l);
-		return __CFA_MAX_PROCESSORS__;
-	}
-	if('\0' != *endptr) {
-		__cfadbg_print_nolock(ready_queue, "CFA_MAX_PROCESSORS not a decimal number : %s\n", max_cores_s);
-		return __CFA_MAX_PROCESSORS__;
-	}
-
-	return max_cores_l;
-}
-
-#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
-	// No forward declaration needed
-	#define __kernel_rseq_register rseq_register_current_thread
-	#define __kernel_rseq_unregister rseq_unregister_current_thread
-#elif defined(CFA_HAVE_LINUX_RSEQ_H)
-	static void __kernel_raw_rseq_register  (void);
-	static void __kernel_raw_rseq_unregister(void);
-
-	#define __kernel_rseq_register __kernel_raw_rseq_register
-	#define __kernel_rseq_unregister __kernel_raw_rseq_unregister
-#else
-	// No forward declaration needed
-	// No initialization needed
-	static inline void noop(void) {}
-
-	#define __kernel_rseq_register noop
-	#define __kernel_rseq_unregister noop
-#endif
-
-//=======================================================================
-// Cluster wide reader-writer lock
-//=======================================================================
-void  ?{}(__scheduler_RWLock_t & this) {
-	this.max   = __max_processors();
-	this.alloc = 0;
-	this.ready = 0;
-	this.data  = alloc(this.max);
-	this.write_lock  = false;
-
-	/*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.alloc), &this.alloc));
-	/*paranoid*/ verify(__atomic_is_lock_free(sizeof(this.ready), &this.ready));
-
-}
-void ^?{}(__scheduler_RWLock_t & this) {
-	free(this.data);
-}
-
-
-//=======================================================================
-// Lock-Free registering/unregistering of threads
-unsigned register_proc_id( void ) with(*__scheduler_lock) {
-	__kernel_rseq_register();
-
-	bool * handle = (bool *)&kernelTLS().sched_lock;
-
-	// Step - 1 : check if there is already space in the data
-	uint_fast32_t s = ready;
-
-	// Check among all the ready
-	for(uint_fast32_t i = 0; i < s; i++) {
-		bool * volatile * cell = (bool * volatile *)&data[i]; // Cforall is bugged and the double volatiles causes problems
-		/* paranoid */ verify( handle != *cell );
-
-		bool * null = 0p; // Re-write every loop since compare thrashes it
-		if( __atomic_load_n(cell, (int)__ATOMIC_RELAXED) == null
-			&& __atomic_compare_exchange_n( cell, &null, handle, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
-			/* paranoid */ verify(i < ready);
-			/* paranoid */ verify( (kernelTLS().sched_id = i, true) );
-			return i;
-		}
-	}
-
-	if(max <= alloc) abort("Trying to create more than %ud processors", __scheduler_lock->max);
-
-	// Step - 2 : F&A to get a new spot in the array.
-	uint_fast32_t n = __atomic_fetch_add(&alloc, 1, __ATOMIC_SEQ_CST);
-	if(max <= n) abort("Trying to create more than %ud processors", __scheduler_lock->max);
-
-	// Step - 3 : Mark space as used and then publish it.
-	data[n] = handle;
-	while() {
-		unsigned copy = n;
-		if( __atomic_load_n(&ready, __ATOMIC_RELAXED) == n
-			&& __atomic_compare_exchange_n(&ready, &copy, n + 1, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
-			break;
-		Pause();
-	}
-
-	// Return new spot.
-	/* paranoid */ verify(n < ready);
-	/* paranoid */ verify( (kernelTLS().sched_id = n, true) );
-	return n;
-}
-
-void unregister_proc_id( unsigned id ) with(*__scheduler_lock) {
-	/* paranoid */ verify(id < ready);
-	/* paranoid */ verify(id == kernelTLS().sched_id);
-	/* paranoid */ verify(data[id] == &kernelTLS().sched_lock);
-
-	bool * volatile * cell = (bool * volatile *)&data[id]; // Cforall is bugged and the double volatiles causes problems
-
-	__atomic_store_n(cell, 0p, __ATOMIC_RELEASE);
-
-	__kernel_rseq_unregister();
-}
-
-//-----------------------------------------------------------------------
-// Writer side : acquire when changing the ready queue, e.g. adding more
-//  queues or removing them.
-uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
-	/* paranoid */ verify( ! __preemption_enabled() );
-
-	// Step 1 : lock global lock
-	// It is needed to avoid processors that register mid Critical-Section
-	//   to simply lock their own lock and enter.
-	__atomic_acquire( &write_lock );
-
-	// Make sure we won't deadlock ourself
-	// Checking before acquiring the writer lock isn't safe
-	// because someone else could have locked us.
-	/* paranoid */ verify( ! kernelTLS().sched_lock );
-
-	// Step 2 : lock per-proc lock
-	// Processors that are currently being registered aren't counted
-	//   but can't be in read_lock or in the critical section.
-	// All other processors are counted
-	uint_fast32_t s = ready;
-	for(uint_fast32_t i = 0; i < s; i++) {
-		volatile bool * llock = data[i];
-		if(llock) __atomic_acquire( llock );
-	}
-
-	/* paranoid */ verify( ! __preemption_enabled() );
-	return s;
-}
-
-void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) {
-	/* paranoid */ verify( ! __preemption_enabled() );
-
-	// Step 1 : release local locks
-	// This must be done while the global lock is held to avoid
-	//   threads that where created mid critical section
-	//   to race to lock their local locks and have the writer
-	//   immidiately unlock them
-	// Alternative solution : return s in write_lock and pass it to write_unlock
-	for(uint_fast32_t i = 0; i < last_s; i++) {
-		volatile bool * llock = data[i];
-		if(llock) __atomic_store_n(llock, (bool)false, __ATOMIC_RELEASE);
-	}
-
-	// Step 2 : release global lock
-	/*paranoid*/ assert(true == write_lock);
-	__atomic_store_n(&write_lock, (bool)false, __ATOMIC_RELEASE);
-
-	/* paranoid */ verify( ! __preemption_enabled() );
-}
-
-//=======================================================================
-// caches handling
-
-struct __attribute__((aligned(128))) __ready_queue_caches_t {
-	// Count States:
-	// - 0  : No one is looking after this cache
-	// - 1  : No one is looking after this cache, BUT it's not empty
-	// - 2+ : At least one processor is looking after this cache
-	volatile unsigned count;
-};
-
-void  ?{}(__ready_queue_caches_t & this) { this.count = 0; }
-void ^?{}(__ready_queue_caches_t & this) {}
-
-static inline void depart(__ready_queue_caches_t & cache) {
-	/* paranoid */ verify( cache.count > 1);
-	__atomic_fetch_add(&cache.count, -1, __ATOMIC_SEQ_CST);
-	/* paranoid */ verify( cache.count != 0);
-	/* paranoid */ verify( cache.count < 65536 ); // This verify assumes no cluster will have more than 65000 kernel threads mapped to a single cache, which could be correct but is super weird.
-}
-
-static inline void arrive(__ready_queue_caches_t & cache) {
-	// for() {
-	// 	unsigned expected = cache.count;
-	// 	unsigned desired  = 0 == expected ? 2 : expected + 1;
-	// }
-}
 
 //=======================================================================
 // Cforall Ready Queue used for scheduling
 //=======================================================================
-unsigned long long moving_average(unsigned long long currtsc, unsigned long long instsc, unsigned long long old_avg) {
-	/* paranoid */ verifyf( currtsc < 45000000000000000, "Suspiciously large current time: %'llu (%llx)\n", currtsc, currtsc );
-	/* paranoid */ verifyf( instsc  < 45000000000000000, "Suspiciously large insert time: %'llu (%llx)\n", instsc, instsc );
-	/* paranoid */ verifyf( old_avg < 15000000000000, "Suspiciously large previous average: %'llu (%llx)\n", old_avg, old_avg );
-
-	const unsigned long long new_val = currtsc > instsc ? currtsc - instsc : 0;
-	const unsigned long long total_weight = 16;
-	const unsigned long long new_weight   = 4;
-	const unsigned long long old_weight = total_weight - new_weight;
-	const unsigned long long ret = ((new_weight * new_val) + (old_weight * old_avg)) / total_weight;
-	return ret;
-}
-
-void ?{}(__ready_queue_t & this) with (this) {
-	#if defined(USE_CPU_WORK_STEALING)
-		lanes.count = cpu_info.hthrd_count * READYQ_SHARD_FACTOR;
-		lanes.data = alloc( lanes.count );
-		lanes.tscs = alloc( lanes.count );
-		lanes.help = alloc( cpu_info.hthrd_count );
-
-		for( idx; (size_t)lanes.count ) {
-			(lanes.data[idx]){};
-			lanes.tscs[idx].tv = rdtscl();
-			lanes.tscs[idx].ma = rdtscl();
-		}
-		for( idx; (size_t)cpu_info.hthrd_count ) {
-			lanes.help[idx].src = 0;
-			lanes.help[idx].dst = 0;
-			lanes.help[idx].tri = 0;
-		}
-	#else
-		lanes.data   = 0p;
-		lanes.tscs   = 0p;
-		lanes.caches = 0p;
-		lanes.help   = 0p;
-		lanes.count  = 0;
-	#endif
-}
-
-void ^?{}(__ready_queue_t & this) with (this) {
-	#if !defined(USE_CPU_WORK_STEALING)
-		verify( SEQUENTIAL_SHARD == lanes.count );
-	#endif
-
-	free(lanes.data);
-	free(lanes.tscs);
-	free(lanes.caches);
-	free(lanes.help);
-}
-
-//-----------------------------------------------------------------------
-#if defined(USE_AWARE_STEALING)
-	__attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {
-		processor * const proc = kernelTLS().this_processor;
-		const bool external = (!proc) || (cltr != proc->cltr);
-		const bool remote   = hint == UNPARK_REMOTE;
-
-		unsigned i;
-		if( external || remote ) {
-			// Figure out where thread was last time and make sure it's valid
-			/* paranoid */ verify(thrd->preferred >= 0);
-			if(thrd->preferred * READYQ_SHARD_FACTOR < lanes.count) {
-				/* paranoid */ verify(thrd->preferred * READYQ_SHARD_FACTOR < lanes.count);
-				unsigned start = thrd->preferred * READYQ_SHARD_FACTOR;
-				do {
-					unsigned r = __tls_rand();
-					i = start + (r % READYQ_SHARD_FACTOR);
-					/* paranoid */ verify( i < lanes.count );
-					// If we can't lock it retry
-				} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
-			} else {
-				do {
-					i = __tls_rand() % lanes.count;
-				} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
-			}
+// void ?{}(__ready_queue_t & this) with (this) {
+// 	lanes.data   = 0p;
+// 	lanes.tscs   = 0p;
+// 	lanes.caches = 0p;
+// 	lanes.count  = 0;
+// }
+
+// void ^?{}(__ready_queue_t & this) with (this) {
+// 	free(lanes.data);
+// 	free(lanes.tscs);
+// 	free(lanes.caches);
+// }
+
+//-----------------------------------------------------------------------
+__attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->sched) {
+	processor * const proc = kernelTLS().this_processor;
+	const bool external = (!proc) || (cltr != proc->cltr);
+	const bool remote   = hint == UNPARK_REMOTE;
+	const size_t lanes_count = readyQ.count;
+
+	/* paranoid */ verify( __shard_factor.readyq > 0 );
+	/* paranoid */ verify( lanes_count > 0 );
+
+	unsigned i;
+	if( external || remote ) {
+		// Figure out where thread was last time and make sure it's valid
+		/* paranoid */ verify(thrd->preferred >= 0);
+		unsigned start = thrd->preferred * __shard_factor.readyq;
+		if(start < lanes_count) {
+			do {
+				unsigned r = __tls_rand();
+				i = start + (r % __shard_factor.readyq);
+				/* paranoid */ verify( i < lanes_count );
+				// If we can't lock it retry
+			} while( !__atomic_try_acquire( &readyQ.data[i].lock ) );
 		} else {
 			do {
-				unsigned r = proc->rdq.its++;
-				i = proc->rdq.id + (r % READYQ_SHARD_FACTOR);
-				/* paranoid */ verify( i < lanes.count );
-				// If we can't lock it retry
-			} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
-		}
-
-		// Actually push it
-		push(lanes.data[i], thrd);
-
-		// Unlock and return
-		__atomic_unlock( &lanes.data[i].lock );
-
-		#if !defined(__CFA_NO_STATISTICS__)
-			if(unlikely(external || remote)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
-			else __tls_stats()->ready.push.local.success++;
-		#endif
-	}
-
-	static inline unsigned long long calc_cutoff(const unsigned long long ctsc, const processor * proc, __ready_queue_t & rdq) {
-		unsigned start = proc->rdq.id;
-		unsigned long long max = 0;
-		for(i; READYQ_SHARD_FACTOR) {
-			unsigned long long ptsc = ts(rdq.lanes.data[start + i]);
-			if(ptsc != -1ull) {
-				/* paranoid */ verify( start + i < rdq.lanes.count );
-				unsigned long long tsc = moving_average(ctsc, ptsc, rdq.lanes.tscs[start + i].ma);
-				if(tsc > max) max = tsc;
-			}
-		}
-		return (max + 2 * max) / 2;
-	}
-
-	__attribute__((hot)) struct thread$ * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
-		/* paranoid */ verify( lanes.count > 0 );
-		/* paranoid */ verify( kernelTLS().this_processor );
-		/* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
-
-		processor * const proc = kernelTLS().this_processor;
-		unsigned this = proc->rdq.id;
-		/* paranoid */ verify( this < lanes.count );
-		__cfadbg_print_safe(ready_queue, "Kernel : pop from %u\n", this);
-
-		// Figure out the current cpu and make sure it is valid
-		const int cpu = __kernel_getcpu();
-		/* paranoid */ verify(cpu >= 0);
-		/* paranoid */ verify(cpu < cpu_info.hthrd_count);
-		unsigned this_cache = cpu_info.llc_map[cpu].cache;
-
-		// Super important: don't write the same value over and over again
-		// We want to maximise our chances that his particular values stays in cache
-		if(lanes.caches[this / READYQ_SHARD_FACTOR].id != this_cache)
-			__atomic_store_n(&lanes.caches[this / READYQ_SHARD_FACTOR].id, this_cache, __ATOMIC_RELAXED);
-
-		const unsigned long long ctsc = rdtscl();
-
-		if(proc->rdq.target == MAX) {
-			uint64_t chaos = __tls_rand();
-			unsigned ext = chaos & 0xff;
-			unsigned other  = (chaos >> 8) % (lanes.count);
-
-			if(ext < 3 || __atomic_load_n(&lanes.caches[other / READYQ_SHARD_FACTOR].id, __ATOMIC_RELAXED) == this_cache) {
-				proc->rdq.target = other;
-			}
-		}
-		else {
-			const unsigned target = proc->rdq.target;
-			__cfadbg_print_safe(ready_queue, "Kernel : %u considering helping %u, tcsc %llu\n", this, target, lanes.tscs[target].tv);
-			/* paranoid */ verify( lanes.tscs[target].tv != MAX );
-			if(target < lanes.count) {
-				const unsigned long long cutoff = calc_cutoff(ctsc, proc, cltr->ready_queue);
-				const unsigned long long age = moving_average(ctsc, lanes.tscs[target].tv, lanes.tscs[target].ma);
-				__cfadbg_print_safe(ready_queue, "Kernel : Help attempt on %u from %u, age %'llu vs cutoff %'llu, %s\n", target, this, age, cutoff, age > cutoff ? "yes" : "no");
-				if(age > cutoff) {
-					thread$ * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help));
-					if(t) return t;
-				}
-			}
-			proc->rdq.target = MAX;
-		}
-
-		for(READYQ_SHARD_FACTOR) {
-			unsigned i = this + (proc->rdq.itr++ % READYQ_SHARD_FACTOR);
-			if(thread$ * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t;
-		}
-
-		// All lanes where empty return 0p
-		return 0p;
-
-	}
-	__attribute__((hot)) struct thread$ * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
-		unsigned i = __tls_rand() % lanes.count;
-		return try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal));
-	}
-	__attribute__((hot)) struct thread$ * pop_search(struct cluster * cltr) {
-		return search(cltr);
-	}
-#endif
-#if defined(USE_CPU_WORK_STEALING)
-	__attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {
-		__cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
-
-		processor * const proc = kernelTLS().this_processor;
-		const bool external = (!proc) || (cltr != proc->cltr);
-
-		// Figure out the current cpu and make sure it is valid
-		const int cpu = __kernel_getcpu();
-		/* paranoid */ verify(cpu >= 0);
-		/* paranoid */ verify(cpu < cpu_info.hthrd_count);
-		/* paranoid */ verify(cpu * READYQ_SHARD_FACTOR < lanes.count);
-
-		// Figure out where thread was last time and make sure it's
-		/* paranoid */ verify(thrd->preferred >= 0);
-		/* paranoid */ verify(thrd->preferred < cpu_info.hthrd_count);
-		/* paranoid */ verify(thrd->preferred * READYQ_SHARD_FACTOR < lanes.count);
-		const int prf = thrd->preferred * READYQ_SHARD_FACTOR;
-
-		const cpu_map_entry_t & map;
-		choose(hint) {
-			case UNPARK_LOCAL : &map = &cpu_info.llc_map[cpu];
-			case UNPARK_REMOTE: &map = &cpu_info.llc_map[prf];
-		}
-		/* paranoid */ verify(map.start * READYQ_SHARD_FACTOR < lanes.count);
-		/* paranoid */ verify(map.self * READYQ_SHARD_FACTOR < lanes.count);
-		/* paranoid */ verifyf((map.start + map.count) * READYQ_SHARD_FACTOR <= lanes.count, "have %zu lanes but map can go up to %u", lanes.count, (map.start + map.count) * READYQ_SHARD_FACTOR);
-
-		const int start = map.self * READYQ_SHARD_FACTOR;
-		unsigned i;
+				i = __tls_rand() % lanes_count;
+			} while( !__atomic_try_acquire( &readyQ.data[i].lock ) );
+		}
+	} else {
 		do {
-			unsigned r;
-			if(unlikely(external)) { r = __tls_rand(); }
-			else { r = proc->rdq.its++; }
-			choose(hint) {
-				case UNPARK_LOCAL : i = start + (r % READYQ_SHARD_FACTOR);
-				case UNPARK_REMOTE: i = prf   + (r % READYQ_SHARD_FACTOR);
-			}
+			unsigned r = proc->rdq.its++;
+			i = proc->rdq.id + (r % __shard_factor.readyq);
+			/* paranoid */ verify( i < lanes_count );
 			// If we can't lock it retry
-		} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
-
-		// Actually push it
-		push(lanes.data[i], thrd);
-
-		// Unlock and return
-		__atomic_unlock( &lanes.data[i].lock );
-
-		#if !defined(__CFA_NO_STATISTICS__)
-			if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
-			else __tls_stats()->ready.push.local.success++;
-		#endif
-
-		__cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
-
-	}
-
-	// Pop from the ready queue from a given cluster
-	__attribute__((hot)) thread$ * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
-		/* paranoid */ verify( lanes.count > 0 );
-		/* paranoid */ verify( kernelTLS().this_processor );
-
-		processor * const proc = kernelTLS().this_processor;
-		const int cpu = __kernel_getcpu();
-		/* paranoid */ verify(cpu >= 0);
-		/* paranoid */ verify(cpu < cpu_info.hthrd_count);
-		/* paranoid */ verify(cpu * READYQ_SHARD_FACTOR < lanes.count);
-
-		const cpu_map_entry_t & map = cpu_info.llc_map[cpu];
-		/* paranoid */ verify(map.start * READYQ_SHARD_FACTOR < lanes.count);
-		/* paranoid */ verify(map.self * READYQ_SHARD_FACTOR < lanes.count);
-		/* paranoid */ verifyf((map.start + map.count) * READYQ_SHARD_FACTOR <= lanes.count, "have %zu lanes but map can go up to %u", lanes.count, (map.start + map.count) * READYQ_SHARD_FACTOR);
-
-		const int start = map.self * READYQ_SHARD_FACTOR;
-		const unsigned long long ctsc = rdtscl();
-
-		// Did we already have a help target
-		if(proc->rdq.target == MAX) {
-			unsigned long long max = 0;
-			for(i; READYQ_SHARD_FACTOR) {
-				unsigned long long tsc = moving_average(ctsc, ts(lanes.data[start + i]), lanes.tscs[start + i].ma);
-				if(tsc > max) max = tsc;
-			}
-			//  proc->rdq.cutoff = (max + 2 * max) / 2;
-			/* paranoid */ verify(lanes.count < 65536); // The following code assumes max 65536 cores.
-			/* paranoid */ verify(map.count < 65536); // The following code assumes max 65536 cores.
-
-			if(0 == (__tls_rand() % 100)) {
-				proc->rdq.target = __tls_rand() % lanes.count;
-			} else {
-				unsigned cpu_chaos = map.start + (__tls_rand() % map.count);
-				proc->rdq.target = (cpu_chaos * READYQ_SHARD_FACTOR) + (__tls_rand() % READYQ_SHARD_FACTOR);
-				/* paranoid */ verify(proc->rdq.target >= (map.start * READYQ_SHARD_FACTOR));
-				/* paranoid */ verify(proc->rdq.target <  ((map.start + map.count) * READYQ_SHARD_FACTOR));
-			}
-
-			/* paranoid */ verify(proc->rdq.target != MAX);
-		}
-		else {
-			unsigned long long max = 0;
-			for(i; READYQ_SHARD_FACTOR) {
-				unsigned long long tsc = moving_average(ctsc, ts(lanes.data[start + i]), lanes.tscs[start + i].ma);
-				if(tsc > max) max = tsc;
-			}
-			const unsigned long long cutoff = (max + 2 * max) / 2;
-			{
-				unsigned target = proc->rdq.target;
-				proc->rdq.target = MAX;
-				lanes.help[target / READYQ_SHARD_FACTOR].tri++;
-				if(moving_average(ctsc, lanes.tscs[target].tv, lanes.tscs[target].ma) > cutoff) {
-					thread$ * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help));
-					proc->rdq.last = target;
-					if(t) return t;
-				}
-				proc->rdq.target = MAX;
-			}
-
-			unsigned last = proc->rdq.last;
-			if(last != MAX && moving_average(ctsc, lanes.tscs[last].tv, lanes.tscs[last].ma) > cutoff) {
-				thread$ * t = try_pop(cltr, last __STATS(, __tls_stats()->ready.pop.help));
-				if(t) return t;
-			}
-			else {
-				proc->rdq.last = MAX;
-			}
-		}
-
-		for(READYQ_SHARD_FACTOR) {
-			unsigned i = start + (proc->rdq.itr++ % READYQ_SHARD_FACTOR);
-			if(thread$ * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t;
-		}
-
-		// All lanes where empty return 0p
-		return 0p;
-	}
-
-	__attribute__((hot)) struct thread$ * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
-		processor * const proc = kernelTLS().this_processor;
-		unsigned last = proc->rdq.last;
-		if(last != MAX) {
-			struct thread$ * t = try_pop(cltr, last __STATS(, __tls_stats()->ready.pop.steal));
-			if(t) return t;
-			proc->rdq.last = MAX;
-		}
-
-		unsigned i = __tls_rand() % lanes.count;
-		return try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal));
-	}
-	__attribute__((hot)) struct thread$ * pop_search(struct cluster * cltr) {
-		return search(cltr);
-	}
-#endif
-#if defined(USE_RELAXED_FIFO)
-	//-----------------------------------------------------------------------
-	// get index from random number with or without bias towards queues
-	static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
-		unsigned i;
-		bool local;
-		unsigned rlow  = r % BIAS;
-		unsigned rhigh = r / BIAS;
-		if((0 != rlow) && preferred >= 0) {
-			// (BIAS - 1) out of BIAS chances
-			// Use perferred queues
-			i = preferred + (rhigh % READYQ_SHARD_FACTOR);
-			local = true;
-		}
-		else {
-			// 1 out of BIAS chances
-			// Use all queues
-			i = rhigh;
-			local = false;
-		}
-		return [i, local];
-	}
-
-	__attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {
-		__cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
-
-		const bool external = (hint != UNPARK_LOCAL) || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
-		/* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
-
-		bool local;
-		int preferred = external ? -1 : kernelTLS().this_processor->rdq.id;
-
-		// Try to pick a lane and lock it
-		unsigned i;
-		do {
-			// Pick the index of a lane
-			unsigned r = __tls_rand_fwd();
-			[i, local] = idx_from_r(r, preferred);
-
-			i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
-
-			#if !defined(__CFA_NO_STATISTICS__)
-				if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED);
-				else if(local) __tls_stats()->ready.push.local.attempt++;
-				else __tls_stats()->ready.push.share.attempt++;
-			#endif
-
-			// If we can't lock it retry
-		} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
-
-		// Actually push it
-		push(lanes.data[i], thrd);
-
-		// Unlock and return
-		__atomic_unlock( &lanes.data[i].lock );
-
-		// Mark the current index in the tls rng instance as having an item
-		__tls_rand_advance_bck();
-
-		__cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
-
-		// Update statistics
-		#if !defined(__CFA_NO_STATISTICS__)
-			if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
-			else if(local) __tls_stats()->ready.push.local.success++;
-			else __tls_stats()->ready.push.share.success++;
-		#endif
-	}
-
-	// Pop from the ready queue from a given cluster
-	__attribute__((hot)) thread$ * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
-		/* paranoid */ verify( lanes.count > 0 );
-		/* paranoid */ verify( kernelTLS().this_processor );
-		/* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
-
-		unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
-		int preferred = kernelTLS().this_processor->rdq.id;
-
-
-		// As long as the list is not empty, try finding a lane that isn't empty and pop from it
-		for(25) {
-			// Pick two lists at random
-			unsigned ri = __tls_rand_bck();
-			unsigned rj = __tls_rand_bck();
-
-			unsigned i, j;
-			__attribute__((unused)) bool locali, localj;
-			[i, locali] = idx_from_r(ri, preferred);
-			[j, localj] = idx_from_r(rj, preferred);
-
-			i %= count;
-			j %= count;
-
-			// try popping from the 2 picked lists
-			struct thread$ * thrd = try_pop(cltr, i, j __STATS(, *(locali || localj ? &__tls_stats()->ready.pop.local : &__tls_stats()->ready.pop.help)));
-			if(thrd) {
-				return thrd;
-			}
-		}
-
-		// All lanes where empty return 0p
-		return 0p;
-	}
-
-	__attribute__((hot)) struct thread$ * pop_slow(struct cluster * cltr) { return pop_fast(cltr); }
-	__attribute__((hot)) struct thread$ * pop_search(struct cluster * cltr) {
-		return search(cltr);
-	}
-#endif
-#if defined(USE_WORK_STEALING)
-	__attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {
-		__cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
-
-		// #define USE_PREFERRED
-		#if !defined(USE_PREFERRED)
-		const bool external = (hint != UNPARK_LOCAL) || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
-		/* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
-		#else
-			unsigned preferred = thrd->preferred;
-			const bool external = (hint != UNPARK_LOCAL) || (!kernelTLS().this_processor) || preferred == MAX || thrd->curr_cluster != cltr;
-			/* paranoid */ verifyf(external || preferred < lanes.count, "Invalid preferred queue %u for %u lanes", preferred, lanes.count );
-
-			unsigned r = preferred % READYQ_SHARD_FACTOR;
-			const unsigned start = preferred - r;
-		#endif
-
-		// Try to pick a lane and lock it
-		unsigned i;
-		do {
-			#if !defined(__CFA_NO_STATISTICS__)
-				if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED);
-				else __tls_stats()->ready.push.local.attempt++;
-			#endif
-
-			if(unlikely(external)) {
-				i = __tls_rand() % lanes.count;
-			}
-			else {
-				#if !defined(USE_PREFERRED)
-					processor * proc = kernelTLS().this_processor;
-					unsigned r = proc->rdq.its++;
-					i =  proc->rdq.id + (r % READYQ_SHARD_FACTOR);
-				#else
-					i = start + (r++ % READYQ_SHARD_FACTOR);
-				#endif
-			}
-			// If we can't lock it retry
-		} while( !__atomic_try_acquire( &lanes.data[i].lock ) );
-
-		// Actually push it
-		push(lanes.data[i], thrd);
-
-		// Unlock and return
-		__atomic_unlock( &lanes.data[i].lock );
-
-		#if !defined(__CFA_NO_STATISTICS__)
-			if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
-			else __tls_stats()->ready.push.local.success++;
-		#endif
-
-		__cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
-	}
-
-	// Pop from the ready queue from a given cluster
-	__attribute__((hot)) thread$ * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
-		/* paranoid */ verify( lanes.count > 0 );
-		/* paranoid */ verify( kernelTLS().this_processor );
-		/* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
-
-		processor * proc = kernelTLS().this_processor;
-
-		if(proc->rdq.target == MAX) {
-			unsigned long long min = ts(lanes.data[proc->rdq.id]);
-			for(int i = 0; i < READYQ_SHARD_FACTOR; i++) {
-				unsigned long long tsc = ts(lanes.data[proc->rdq.id + i]);
-				if(tsc < min) min = tsc;
-			}
-			proc->rdq.cutoff = min;
-			proc->rdq.target = __tls_rand() % lanes.count;
-		}
-		else {
-			unsigned target = proc->rdq.target;
-			proc->rdq.target = MAX;
-			const unsigned long long bias = 0; //2_500_000_000;
-			const unsigned long long cutoff = proc->rdq.cutoff > bias ? proc->rdq.cutoff - bias : proc->rdq.cutoff;
-			if(lanes.tscs[target].tv < cutoff && ts(lanes.data[target]) < cutoff) {
+		} while( !__atomic_try_acquire( &readyQ.data[i].lock ) );
+	}
+
+	// Actually push it
+	push(readyQ.data[i], thrd);
+
+	// Unlock and return
+	__atomic_unlock( &readyQ.data[i].lock );
+
+	#if !defined(__CFA_NO_STATISTICS__)
+		if(unlikely(external || remote)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
+		else __tls_stats()->ready.push.local.success++;
+	#endif
+}
+
+__attribute__((hot)) struct thread$ * pop_fast(struct cluster * cltr) with (cltr->sched) {
+	const size_t lanes_count = readyQ.count;
+
+	/* paranoid */ verify( __shard_factor.readyq > 0 );
+	/* paranoid */ verify( lanes_count > 0 );
+	/* paranoid */ verify( kernelTLS().this_processor );
+	/* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes_count );
+
+	processor * const proc = kernelTLS().this_processor;
+	unsigned this = proc->rdq.id;
+	/* paranoid */ verify( this < lanes_count );
+	__cfadbg_print_safe(ready_queue, "Kernel : pop from %u\n", this);
+
+	// Figure out the current cache is
+	const unsigned this_cache = cache_id(cltr, this / __shard_factor.readyq);
+	const unsigned long long ctsc = rdtscl();
+
+	if(proc->rdq.target == MAX) {
+		uint64_t chaos = __tls_rand();
+		unsigned ext = chaos & 0xff;
+		unsigned other  = (chaos >> 8) % (lanes_count);
+
+		if(ext < 3 || __atomic_load_n(&caches[other / __shard_factor.readyq].id, __ATOMIC_RELAXED) == this_cache) {
+			proc->rdq.target = other;
+		}
+	}
+	else {
+		const unsigned target = proc->rdq.target;
+		__cfadbg_print_safe(ready_queue, "Kernel : %u considering helping %u, tcsc %llu\n", this, target, readyQ.tscs[target].tv);
+		/* paranoid */ verify( readyQ.tscs[target].tv != MAX );
+		if(target < lanes_count) {
+			const unsigned long long cutoff = calc_cutoff(ctsc, proc, lanes_count, cltr->sched.readyQ.data, cltr->sched.readyQ.tscs, __shard_factor.readyq);
+			const unsigned long long age = moving_average(ctsc, readyQ.tscs[target].tv, readyQ.tscs[target].ma);
+			__cfadbg_print_safe(ready_queue, "Kernel : Help attempt on %u from %u, age %'llu vs cutoff %'llu, %s\n", target, this, age, cutoff, age > cutoff ? "yes" : "no");
+			if(age > cutoff) {
 				thread$ * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help));
 				if(t) return t;
 			}
 		}
-
-		for(READYQ_SHARD_FACTOR) {
-			unsigned i = proc->rdq.id + (proc->rdq.itr++ % READYQ_SHARD_FACTOR);
-			if(thread$ * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t;
-		}
-		return 0p;
-	}
-
-	__attribute__((hot)) struct thread$ * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
-		unsigned i = __tls_rand() % lanes.count;
-		return try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal));
-	}
-
-	__attribute__((hot)) struct thread$ * pop_search(struct cluster * cltr) with (cltr->ready_queue) {
-		return search(cltr);
-	}
-#endif
+		proc->rdq.target = MAX;
+	}
+
+	for(__shard_factor.readyq) {
+		unsigned i = this + (proc->rdq.itr++ % __shard_factor.readyq);
+		if(thread$ * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t;
+	}
+
+	// All lanes where empty return 0p
+	return 0p;
+
+}
+__attribute__((hot)) struct thread$ * pop_slow(struct cluster * cltr) {
+	unsigned i = __tls_rand() % (cltr->sched.readyQ.count);
+	return try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal));
+}
+__attribute__((hot)) struct thread$ * pop_search(struct cluster * cltr) {
+	return search(cltr);
+}
 
 //=======================================================================
@@ -820,10 +177,10 @@
 //-----------------------------------------------------------------------
 // try to pop from a lane given by index w
-static inline struct thread$ * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) {
-	/* paranoid */ verify( w < lanes.count );
+static inline struct thread$ * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->sched) {
+	/* paranoid */ verify( w < readyQ.count );
 	__STATS( stats.attempt++; )
 
 	// Get relevant elements locally
-	__intrusive_lane_t & lane = lanes.data[w];
+	__intrusive_lane_t & lane = readyQ.data[w];
 
 	// If list looks empty retry
@@ -845,7 +202,5 @@
 	// Actually pop the list
 	struct thread$ * thrd;
-	#if defined(USE_AWARE_STEALING) || defined(USE_WORK_STEALING) || defined(USE_CPU_WORK_STEALING)
-		unsigned long long tsc_before = ts(lane);
-	#endif
+	unsigned long long tsc_before = ts(lane);
 	unsigned long long tsv;
 	[thrd, tsv] = pop(lane);
@@ -861,18 +216,12 @@
 	__STATS( stats.success++; )
 
-	#if defined(USE_AWARE_STEALING) || defined(USE_WORK_STEALING) || defined(USE_CPU_WORK_STEALING)
-		if (tsv != MAX) {
-			unsigned long long now = rdtscl();
-			unsigned long long pma = __atomic_load_n(&lanes.tscs[w].ma, __ATOMIC_RELAXED);
-			__atomic_store_n(&lanes.tscs[w].tv, tsv, __ATOMIC_RELAXED);
-			__atomic_store_n(&lanes.tscs[w].ma, moving_average(now, tsc_before, pma), __ATOMIC_RELAXED);
-		}
-	#endif
-
-	#if defined(USE_AWARE_STEALING) || defined(USE_CPU_WORK_STEALING)
-		thrd->preferred = w / READYQ_SHARD_FACTOR;
-	#else
-		thrd->preferred = w;
-	#endif
+	if (tsv != MAX) {
+		unsigned long long now = rdtscl();
+		unsigned long long pma = __atomic_load_n(&readyQ.tscs[w].ma, __ATOMIC_RELAXED);
+		__atomic_store_n(&readyQ.tscs[w].tv, tsv, __ATOMIC_RELAXED);
+		__atomic_store_n(&readyQ.tscs[w].ma, moving_average(now, tsc_before, pma), __ATOMIC_RELAXED);
+	}
+
+	thrd->preferred = w / __shard_factor.readyq;
 
 	// return the popped thread
@@ -883,7 +232,8 @@
 // try to pop from any lanes making sure you don't miss any threads push
 // before the start of the function
-static inline struct thread$ * search(struct cluster * cltr) with (cltr->ready_queue) {
-	/* paranoid */ verify( lanes.count > 0 );
-	unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
+static inline struct thread$ * search(struct cluster * cltr) {
+	const size_t lanes_count = cltr->sched.readyQ.count;
+	/* paranoid */ verify( lanes_count > 0 );
+	unsigned count = __atomic_load_n( &lanes_count, __ATOMIC_RELAXED );
 	unsigned offset = __tls_rand();
 	for(i; count) {
@@ -902,18 +252,8 @@
 // get preferred ready for new thread
 unsigned ready_queue_new_preferred() {
-	unsigned pref = 0;
+	unsigned pref = MAX;
 	if(struct thread$ * thrd = publicTLS_get( this_thread )) {
 		pref = thrd->preferred;
 	}
-	else {
-		#if defined(USE_CPU_WORK_STEALING)
-			pref = __kernel_getcpu();
-		#endif
-	}
-
-	#if defined(USE_CPU_WORK_STEALING)
-		/* paranoid */ verify(pref >= 0);
-		/* paranoid */ verify(pref < cpu_info.hthrd_count);
-	#endif
 
 	return pref;
@@ -921,271 +261,12 @@
 
 //-----------------------------------------------------------------------
-// Check that all the intrusive queues in the data structure are still consistent
-static void check( __ready_queue_t & q ) with (q) {
-	#if defined(__CFA_WITH_VERIFY__)
-		{
-			for( idx ; lanes.count ) {
-				__intrusive_lane_t & sl = lanes.data[idx];
-				assert(!lanes.data[idx].lock);
-
-					if(is_empty(sl)) {
-						assert( sl.anchor.next == 0p );
-						assert( sl.anchor.ts   == -1llu );
-						assert( mock_head(sl)  == sl.prev );
-					} else {
-						assert( sl.anchor.next != 0p );
-						assert( sl.anchor.ts   != -1llu );
-						assert( mock_head(sl)  != sl.prev );
-					}
-			}
-		}
-	#endif
-}
-
-//-----------------------------------------------------------------------
 // Given 2 indexes, pick the list with the oldest push an try to pop from it
-static inline struct thread$ * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) {
+static inline struct thread$ * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->sched) {
 	// Pick the bet list
 	int w = i;
-	if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
-		w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
+	if( __builtin_expect(!is_empty(readyQ.data[j]), true) ) {
+		w = (ts(readyQ.data[i]) < ts(readyQ.data[j])) ? i : j;
 	}
 
 	return try_pop(cltr, w __STATS(, stats));
 }
-
-// Call this function of the intrusive list was moved using memcpy
-// fixes the list so that the pointers back to anchors aren't left dangling
-static inline void fix(__intrusive_lane_t & ll) {
-			if(is_empty(ll)) {
-				verify(ll.anchor.next == 0p);
-				ll.prev = mock_head(ll);
-			}
-}
-
-static void assign_list(unsigned & value, dlist(processor) & list, unsigned count) {
-	processor * it = &list`first;
-	for(unsigned i = 0; i < count; i++) {
-		/* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
-		it->rdq.id = value;
-		it->rdq.target = MAX;
-		value += READYQ_SHARD_FACTOR;
-		it = &(*it)`next;
-	}
-}
-
-static void reassign_cltr_id(struct cluster * cltr) {
-	unsigned preferred = 0;
-	assign_list(preferred, cltr->procs.actives, cltr->procs.total - cltr->procs.idle);
-	assign_list(preferred, cltr->procs.idles  , cltr->procs.idle );
-}
-
-static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) {
-	#if defined(USE_AWARE_STEALING) || defined(USE_WORK_STEALING)
-		lanes.tscs = alloc(lanes.count, lanes.tscs`realloc);
-		for(i; lanes.count) {
-			lanes.tscs[i].tv = rdtscl();
-			lanes.tscs[i].ma = 0;
-		}
-	#endif
-}
-
-#if defined(USE_CPU_WORK_STEALING)
-	// ready_queue size is fixed in this case
-	void ready_queue_grow(struct cluster * cltr) {}
-	void ready_queue_shrink(struct cluster * cltr) {}
-#else
-	// Grow the ready queue
-	void ready_queue_grow(struct cluster * cltr) {
-		size_t ncount;
-		int target = cltr->procs.total;
-
-		/* paranoid */ verify( ready_mutate_islocked() );
-		__cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue\n");
-
-		// Make sure that everything is consistent
-		/* paranoid */ check( cltr->ready_queue );
-
-		// grow the ready queue
-		with( cltr->ready_queue ) {
-			// Find new count
-			// Make sure we always have atleast 1 list
-			if(target >= 2) {
-				ncount = target * READYQ_SHARD_FACTOR;
-			} else {
-				ncount = SEQUENTIAL_SHARD;
-			}
-
-			// Allocate new array (uses realloc and memcpies the data)
-			lanes.data = alloc( ncount, lanes.data`realloc );
-
-			// Fix the moved data
-			for( idx; (size_t)lanes.count ) {
-				fix(lanes.data[idx]);
-			}
-
-			// Construct new data
-			for( idx; (size_t)lanes.count ~ ncount) {
-				(lanes.data[idx]){};
-			}
-
-			// Update original
-			lanes.count = ncount;
-
-			lanes.caches = alloc( target, lanes.caches`realloc );
-		}
-
-		fix_times(cltr);
-
-		reassign_cltr_id(cltr);
-
-		// Make sure that everything is consistent
-		/* paranoid */ check( cltr->ready_queue );
-
-		__cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue done\n");
-
-		/* paranoid */ verify( ready_mutate_islocked() );
-	}
-
-	// Shrink the ready queue
-	void ready_queue_shrink(struct cluster * cltr) {
-		/* paranoid */ verify( ready_mutate_islocked() );
-		__cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n");
-
-		// Make sure that everything is consistent
-		/* paranoid */ check( cltr->ready_queue );
-
-		int target = cltr->procs.total;
-
-		with( cltr->ready_queue ) {
-			// Remember old count
-			size_t ocount = lanes.count;
-
-			// Find new count
-			// Make sure we always have atleast 1 list
-			lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD;
-			/* paranoid */ verify( ocount >= lanes.count );
-			/* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR || target < 2 );
-
-			// for printing count the number of displaced threads
-			#if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_READY_QUEUE__)
-				__attribute__((unused)) size_t displaced = 0;
-			#endif
-
-			// redistribute old data
-			for( idx; (size_t)lanes.count ~ ocount) {
-				// Lock is not strictly needed but makes checking invariants much easier
-				__attribute__((unused)) bool locked = __atomic_try_acquire(&lanes.data[idx].lock);
-				verify(locked);
-
-				// As long as we can pop from this lane to push the threads somewhere else in the queue
-				while(!is_empty(lanes.data[idx])) {
-					struct thread$ * thrd;
-					unsigned long long _;
-					[thrd, _] = pop(lanes.data[idx]);
-
-					push(cltr, thrd, true);
-
-					// for printing count the number of displaced threads
-					#if defined(__CFA_DEBUG_PRINT__) || defined(__CFA_DEBUG_PRINT_READY_QUEUE__)
-						displaced++;
-					#endif
-				}
-
-				// Unlock the lane
-				__atomic_unlock(&lanes.data[idx].lock);
-
-				// TODO print the queue statistics here
-
-				^(lanes.data[idx]){};
-			}
-
-			__cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue displaced %zu threads\n", displaced);
-
-			// Allocate new array (uses realloc and memcpies the data)
-			lanes.data = alloc( lanes.count, lanes.data`realloc );
-
-			// Fix the moved data
-			for( idx; (size_t)lanes.count ) {
-				fix(lanes.data[idx]);
-			}
-
-			lanes.caches = alloc( target, lanes.caches`realloc );
-		}
-
-		fix_times(cltr);
-
-
-		reassign_cltr_id(cltr);
-
-		// Make sure that everything is consistent
-		/* paranoid */ check( cltr->ready_queue );
-
-		__cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue done\n");
-		/* paranoid */ verify( ready_mutate_islocked() );
-	}
-#endif
-
-#if !defined(__CFA_NO_STATISTICS__)
-	unsigned cnt(const __ready_queue_t & this, unsigned idx) {
-		/* paranoid */ verify(this.lanes.count > idx);
-		return this.lanes.data[idx].cnt;
-	}
-#endif
-
-
-#if   defined(CFA_HAVE_LINUX_LIBRSEQ)
-	// No definition needed
-#elif defined(CFA_HAVE_LINUX_RSEQ_H)
-
-	#if defined( __x86_64 ) || defined( __i386 )
-		#define RSEQ_SIG	0x53053053
-	#elif defined( __ARM_ARCH )
-		#ifdef __ARMEB__
-		#define RSEQ_SIG    0xf3def5e7      /* udf    #24035    ; 0x5de3 (ARMv6+) */
-		#else
-		#define RSEQ_SIG    0xe7f5def3      /* udf    #24035    ; 0x5de3 */
-		#endif
-	#endif
-
-	extern void __disable_interrupts_hard();
-	extern void __enable_interrupts_hard();
-
-	static void __kernel_raw_rseq_register  (void) {
-		/* paranoid */ verify( __cfaabi_rseq.cpu_id == RSEQ_CPU_ID_UNINITIALIZED );
-
-		// int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), 0, (sigset_t *)0p, _NSIG / 8);
-		int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), 0, RSEQ_SIG);
-		if(ret != 0) {
-			int e = errno;
-			switch(e) {
-			case EINVAL: abort("KERNEL ERROR: rseq register invalid argument");
-			case ENOSYS: abort("KERNEL ERROR: rseq register no supported");
-			case EFAULT: abort("KERNEL ERROR: rseq register with invalid argument");
-			case EBUSY : abort("KERNEL ERROR: rseq register already registered");
-			case EPERM : abort("KERNEL ERROR: rseq register sig  argument  on unregistration does not match the signature received on registration");
-			default: abort("KERNEL ERROR: rseq register unexpected return %d", e);
-			}
-		}
-	}
-
-	static void __kernel_raw_rseq_unregister(void) {
-		/* paranoid */ verify( __cfaabi_rseq.cpu_id >= 0 );
-
-		// int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, (sigset_t *)0p, _NSIG / 8);
-		int ret = syscall(__NR_rseq, &__cfaabi_rseq, sizeof(struct rseq), RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
-		if(ret != 0) {
-			int e = errno;
-			switch(e) {
-			case EINVAL: abort("KERNEL ERROR: rseq unregister invalid argument");
-			case ENOSYS: abort("KERNEL ERROR: rseq unregister no supported");
-			case EFAULT: abort("KERNEL ERROR: rseq unregister with invalid argument");
-			case EBUSY : abort("KERNEL ERROR: rseq unregister already registered");
-			case EPERM : abort("KERNEL ERROR: rseq unregister sig  argument  on unregistration does not match the signature received on registration");
-			default: abort("KERNEL ERROR: rseq unregisteunexpected return %d", e);
-			}
-		}
-	}
-#else
-	// No definition needed
-#endif
Index: libcfa/src/concurrency/ready_subqueue.hfa
===================================================================
--- libcfa/src/concurrency/ready_subqueue.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/ready_subqueue.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -25,36 +25,4 @@
 	);
 	return rhead;
-}
-
-// Ctor
-void ?{}( __intrusive_lane_t & this ) {
-	this.lock = false;
-	this.prev = mock_head(this);
-	this.anchor.next = 0p;
-	this.anchor.ts   = -1llu;
-	#if !defined(__CFA_NO_STATISTICS__)
-		this.cnt  = 0;
-	#endif
-
-	// We add a boat-load of assertions here because the anchor code is very fragile
-	/* paranoid */ _Static_assert( offsetof( thread$, link ) == offsetof(__intrusive_lane_t, anchor) );
-	/* paranoid */ verify( offsetof( thread$, link ) == offsetof(__intrusive_lane_t, anchor) );
-	/* paranoid */ verify( ((uintptr_t)( mock_head(this) ) + offsetof( thread$, link )) == (uintptr_t)(&this.anchor) );
-	/* paranoid */ verify( &mock_head(this)->link.next == &this.anchor.next );
-	/* paranoid */ verify( &mock_head(this)->link.ts   == &this.anchor.ts   );
-	/* paranoid */ verify( mock_head(this)->link.next == 0p );
-	/* paranoid */ verify( mock_head(this)->link.ts   == -1llu  );
-	/* paranoid */ verify( mock_head(this) == this.prev );
-	/* paranoid */ verify( __alignof__(__intrusive_lane_t) == 128 );
-	/* paranoid */ verify( __alignof__(this) == 128 );
-	/* paranoid */ verifyf( ((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128) );
-}
-
-// Dtor is trivial
-void ^?{}( __intrusive_lane_t & this ) {
-	// Make sure the list is empty
-	/* paranoid */ verify( this.anchor.next == 0p );
-	/* paranoid */ verify( this.anchor.ts   == -1llu );
-	/* paranoid */ verify( mock_head(this)  == this.prev );
 }
 
Index: libcfa/src/concurrency/thread.cfa
===================================================================
--- libcfa/src/concurrency/thread.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/concurrency/thread.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -19,5 +19,5 @@
 #include "thread.hfa"
 
-#include "kernel_private.hfa"
+#include "kernel/private.hfa"
 #include "exception.hfa"
 
Index: libcfa/src/containers/string.cfa
===================================================================
--- libcfa/src/containers/string.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/containers/string.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -92,5 +92,5 @@
 }
 
-string ?=?(string & this, string other) {
+string & ?=?(string & this, string & other) { //// <---- straw man change
     (*this.inner) = (*other.inner);
     return this;
@@ -235,4 +235,20 @@
 int find(const string &s, const char* search, size_t searchsize) {
     return find( *s.inner, search, searchsize);
+}
+
+int findFrom(const string &s, size_t fromPos, char search) {
+    return findFrom( *s.inner, fromPos, search );
+}
+
+int findFrom(const string &s, size_t fromPos, const string &search) {
+    return findFrom( *s.inner, fromPos, *search.inner );
+}
+
+int findFrom(const string &s, size_t fromPos, const char* search) {
+    return findFrom( *s.inner, fromPos, search );
+}
+
+int findFrom(const string &s, size_t fromPos, const char* search, size_t searchsize) {
+    return findFrom( *s.inner, fromPos, search, searchsize );
 }
 
Index: libcfa/src/containers/string.hfa
===================================================================
--- libcfa/src/containers/string.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/containers/string.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -41,6 +41,6 @@
 void ?=?(string &s, const string &other);
 void ?=?(string &s, char other);
-string ?=?(string &s, string other);  // string tolerates memcpys; still saw calls to autogen 
-
+string & ?=?(string &s, string &other);  // surprising ret seems to help avoid calls to autogen
+//string ?=?( string &, string ) = void;
 void ^?{}(string &s);
 
@@ -93,4 +93,9 @@
 int find(const string &s, const char* search, size_t searchsize);
 
+int findFrom(const string &s, size_t fromPos, char search);
+int findFrom(const string &s, size_t fromPos, const string &search);
+int findFrom(const string &s, size_t fromPos, const char* search);
+int findFrom(const string &s, size_t fromPos, const char* search, size_t searchsize);
+
 bool includes(const string &s, const string &search);
 bool includes(const string &s, const char* search);
Index: libcfa/src/containers/string_res.cfa
===================================================================
--- libcfa/src/containers/string_res.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/containers/string_res.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -15,22 +15,15 @@
 
 #include "string_res.hfa"
-#include <stdlib.hfa>  // e.g. malloc
-#include <string.h>    // e.g. strlen
+#include "string_sharectx.hfa"
+#include "stdlib.hfa"
+
+// Workaround for observed performance penalty from calling CFA's alloc.
+// Workaround is:  EndVbyte = TEMP_ALLOC(char, CurrSize)
+// Should be:      EndVbyte = alloc(CurrSize)
+#define TEMP_ALLOC(T, n) (( T* ) malloc( n * sizeof( T ) ))
+
+#include <assert.h>
 
 //######################### VbyteHeap "header" #########################
-
-
-
-
-
-
-
-
-// DON'T COMMIT:
-// #define VbyteDebug
-
-
-
-
 
 #ifdef VbyteDebug
@@ -54,24 +47,24 @@
 
     
-static inline void compaction( VbyteHeap & );				// compaction of the byte area
-static inline void garbage( VbyteHeap & );				// garbage collect the byte area
-static inline void extend( VbyteHeap &, int );			// extend the size of the byte area
-static inline void reduce( VbyteHeap &, int );			// reduce the size of the byte area
-
-static inline void ?{}( VbyteHeap &, int = 1000 );
-static inline void ^?{}( VbyteHeap & );
-static inline void ByteCopy( VbyteHeap &, char *, int, int, char *, int, int ); // copy a block of bytes from one location in the heap to another
-static inline int ByteCmp( VbyteHeap &, char *, int, int, char *, int, int );	// compare 2 blocks of bytes
-static inline char *VbyteAlloc( VbyteHeap &, int );			// allocate a block bytes in the heap
-
-
-static inline void AddThisAfter( HandleNode &, HandleNode & );
-static inline void DeleteNode( HandleNode & );
-static inline void MoveThisAfter( HandleNode &, const HandleNode & );		// move current handle after parameter handle
+static void compaction( VbyteHeap & );				// compaction of the byte area
+static void garbage( VbyteHeap &, int );				// garbage collect the byte area
+static void extend( VbyteHeap &, int );			// extend the size of the byte area
+static void reduce( VbyteHeap &, int );			// reduce the size of the byte area
+
+static void ?{}( VbyteHeap &, size_t = 1000 );
+static void ^?{}( VbyteHeap & );
+
+static int ByteCmp( char *, int, int, char *, int, int );	// compare 2 blocks of bytes
+static char *VbyteAlloc( VbyteHeap &, int );			// allocate a block bytes in the heap
+static char *VbyteTryAdjustLast( VbyteHeap &, int );
+
+static void AddThisAfter( HandleNode &, HandleNode & );
+static void DeleteNode( HandleNode & );
+static void MoveThisAfter( HandleNode &, const HandleNode & );		// move current handle after parameter handle
 
 
 // Allocate the storage for the variable sized area and intialize the heap variables.
 
-static inline void ?{}( VbyteHeap & this, int Size ) with(this) {
+static void ?{}( VbyteHeap & this, size_t Size ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:VbyteHeap::VbyteHeap, this:" | &this | " Size:" | Size;
@@ -79,7 +72,8 @@
     NoOfCompactions = NoOfExtensions = NoOfReductions = 0;
     InitSize = CurrSize = Size;
-    StartVbyte = EndVbyte = alloc(CurrSize);
+    StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
     ExtVbyte = (void *)( StartVbyte + CurrSize );
     Header.flink = Header.blink = &Header;
+    Header.ulink = & this;
 #ifdef VbyteDebug
     HeaderPtr = &Header;
@@ -91,5 +85,5 @@
 // Release the dynamically allocated storage for the byte area.
 
-static inline void ^?{}( VbyteHeap & this ) with(this) {
+static void ^?{}( VbyteHeap & this ) with(this) {
     free( StartVbyte );
 } // ~VbyteHeap
@@ -102,5 +96,5 @@
 // creator.
 
-void ?{}( HandleNode & this ) with(this) {
+static void ?{}( HandleNode & this ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:HandleNode::HandleNode, this:" | &this;
@@ -117,5 +111,5 @@
 // collection.
 
-void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {
+static void ?{}( HandleNode & this, VbyteHeap & vh ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:HandleNode::HandleNode, this:" | &this;
@@ -123,4 +117,5 @@
     s = 0;
     lnth = 0;
+    ulink = &vh;
     AddThisAfter( this, *vh.Header.blink );
 #ifdef VbyteDebug
@@ -133,5 +128,5 @@
 // is the responsibility of the creator to destroy it.
 
-void ^?{}( HandleNode & this ) with(this) {
+static void ^?{}( HandleNode & this ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:HandleNode::~HandleNode, this:" | & this;
@@ -149,10 +144,38 @@
 } // ~HandleNode
 
+
+//######################### String Sharing Context #########################
+
+static string_sharectx * ambient_string_sharectx;               // fickle top of stack
+static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack
+
+void ?{}( string_sharectx & this, StringSharectx_Mode mode ) with( this ) {
+    (older){ ambient_string_sharectx };
+    if ( mode == NEW_SHARING ) {
+        (activeHeap){ new( (size_t) 1000 ) };
+    } else {
+        verify( mode == NO_SHARING );
+        (activeHeap){ 0p };
+    }
+    ambient_string_sharectx = & this;
+}
+
+void ^?{}( string_sharectx & this ) with( this ) {
+    if ( activeHeap ) delete( activeHeap );
+
+    // unlink this from older-list starting from ambient_string_sharectx
+    // usually, this==ambient_string_sharectx and the loop runs zero times
+    string_sharectx *& c = ambient_string_sharectx;
+    while ( c != &this ) &c = &c->older;              // find this
+    c = this.older;                                   // unlink
+}
+
 //######################### String Resource #########################
 
 
-VbyteHeap HeapArea;
-
-VbyteHeap * DEBUG_string_heap = & HeapArea;
+VbyteHeap * DEBUG_string_heap() {
+    assert( ambient_string_sharectx->activeHeap && "No sharing context is active" );
+    return ambient_string_sharectx->activeHeap;
+}
 
 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {
@@ -160,8 +183,11 @@
 }
 
+size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) {
+    return heap->CurrSize;
+}
+
 const char * DEBUG_string_heap_start( VbyteHeap * heap ) {
     return heap->StartVbyte;
 }
-
 
 // Returns the size of the string in bytes
@@ -187,98 +213,113 @@
     // Store auto-newline state so it can be restored
     bool anl = getANL$(out);
-    nlOff(out);
-    for (size_t i = 0; i < s.Handle.lnth; i++) {
-        // Need to re-apply on the last output operator, for whole-statement version
-        if (anl && i == s.Handle.lnth-1) nlOn(out);
-        out | s[i];
-    }
-    return out;
+    if( s.Handle.lnth == 0 ) {
+        sout | "";
+    } else {
+        nlOff(out);
+        for (size_t i = 0; i < s.Handle.lnth; i++) {
+            // Need to re-apply on the last output operator, for whole-statement version
+            if (anl && i == s.Handle.lnth-1) nlOn(out);
+            out | s[i];
+        }
+    }
 }
 
 // Empty constructor
 void ?{}(string_res &s) with(s) {
-    (Handle){ HeapArea };
+    if( ambient_string_sharectx->activeHeap ) {
+        (Handle){ * ambient_string_sharectx->activeHeap };
+        (shareEditSet_owns_ulink){ false };
+        verify( Handle.s == 0p && Handle.lnth == 0 );
+    } else {
+        (Handle){ * new( (size_t) 10 ) };  // TODO: can I lazily avoid allocating for empty string
+        (shareEditSet_owns_ulink){ true };
+        Handle.s = Handle.ulink->StartVbyte;
+        verify( Handle.lnth == 0 );
+    }
     s.shareEditSet_prev = &s;
     s.shareEditSet_next = &s;
 }
 
+static void eagerCopyCtorHelper(string_res &s, const char* rhs, size_t rhslnth) with(s) {
+    if( ambient_string_sharectx->activeHeap ) {
+        (Handle){ * ambient_string_sharectx->activeHeap };
+        (shareEditSet_owns_ulink){ false };
+    } else {
+        (Handle){ * new( rhslnth ) };
+        (shareEditSet_owns_ulink){ true };
+    }
+    Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
+    Handle.lnth = rhslnth;
+    memmove( Handle.s, rhs, rhslnth );
+    s.shareEditSet_prev = &s;
+    s.shareEditSet_next = &s;
+}
+
 // Constructor from a raw buffer and size
 void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) {
-    (Handle){ HeapArea };
-    Handle.s = VbyteAlloc(HeapArea, rhslnth);
+    eagerCopyCtorHelper(s, rhs, rhslnth);
+}
+
+// private ctor (not in header): use specified heap (ignore ambient) and copy chars in
+void ?{}( string_res &s, VbyteHeap & heap, const char* rhs, size_t rhslnth ) with(s) {
+    (Handle){ heap };
+    Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
     Handle.lnth = rhslnth;
-    for ( int i = 0; i < rhslnth; i += 1 ) {		// copy characters
-        Handle.s[i] = rhs[i];
-    } // for
+    (s.shareEditSet_owns_ulink){ false };
+    memmove( Handle.s, rhs, rhslnth );
     s.shareEditSet_prev = &s;
     s.shareEditSet_next = &s;
 }
 
-// String literal constructor
-void ?{}(string_res &s, const char* rhs) {
-    (s){ rhs, strlen(rhs) };
-}
-
 // General copy constructor
 void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) {
 
-    (s.Handle){ HeapArea };
-    s.Handle.s = s2.Handle.s + start;
-    s.Handle.lnth = end - start;
-    MoveThisAfter(s.Handle, s2.Handle );			// insert this handle after rhs handle
-    // ^ bug?  skip others at early point in string
-    
-    if (mode == COPY_VALUE) {
-        // make s alone in its shareEditSet
-        s.shareEditSet_prev = &s;
-        s.shareEditSet_next = &s;
+    verify( start <= end && end <= s2.Handle.lnth );
+
+    if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) {
+        // crossing heaps (including private): copy eagerly
+        eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
+        verify(s.shareEditSet_prev == &s);
+        verify(s.shareEditSet_next == &s);
     } else {
-        assert( mode == SHARE_EDITS );
-
-        // s2 is logically const but not implementation const
-        string_res & s2mod = (string_res &) s2;
-
-        // insert s after s2 on shareEditSet
-        s.shareEditSet_next = s2mod.shareEditSet_next;
-        s.shareEditSet_prev = &s2mod;
-        s.shareEditSet_next->shareEditSet_prev = &s;
-        s.shareEditSet_prev->shareEditSet_next = &s;
-    }
-}
-
-void assign(string_res &this, const char* buffer, size_t bsize) {
-
-    // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs
-    string_res * shareEditSetStartPeer = & this;
-    string_res * shareEditSetEndPeer = & this;
-    for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
-        if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
-            shareEditSetStartPeer = editPeer;
+        (s.Handle){};
+        s.Handle.s = s2.Handle.s + start;
+        s.Handle.lnth = end - start;
+        s.Handle.ulink = s2.Handle.ulink;
+
+        AddThisAfter(s.Handle, s2.Handle );			// insert this handle after rhs handle
+        // ^ bug?  skip others at early point in string
+
+        if (mode == COPY_VALUE) {
+            verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap);
+            // requested logical copy in same heap: defer copy until write
+
+            (s.shareEditSet_owns_ulink){ false };
+
+            // make s alone in its shareEditSet
+            s.shareEditSet_prev = &s;
+            s.shareEditSet_next = &s;
+        } else {
+            verify( mode == SHARE_EDITS );
+            // sharing edits with source forces same heap as source (ignore context)
+
+            (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink };
+
+            // s2 is logically const but not implementation const
+            string_res & s2mod = (string_res &) s2;
+
+            // insert s after s2 on shareEditSet
+            s.shareEditSet_next = s2mod.shareEditSet_next;
+            s.shareEditSet_prev = &s2mod;
+            s.shareEditSet_next->shareEditSet_prev = &s;
+            s.shareEditSet_prev->shareEditSet_next = &s;
         }
-        if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
-            shareEditSetEndPeer = editPeer;
-        }
-    }
-
-    // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
-    // `this` occurs in the middle of it, to be replaced
-    // build up the new text in `pasting`
-
-    string_res pasting = {
-        shareEditSetStartPeer->Handle.s,                   // start of SES
-        this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this
-    append( pasting,
-        buffer,                                            // start of replacement for this
-        bsize );                                           // length of replacement for this
-    append( pasting,
-        this.Handle.s + this.Handle.lnth,                  // start of SES after this
-        shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
-        (this.Handle.s + this.Handle.lnth) );              // length of SES, after this
-
-    // The above string building can trigger compaction.
-    // The reference points (that are arguments of the string building) may move during that building.
-    // From this point on, they are stable.
-    // So now, capture their values for use in the overlap cases, below.
-    // Do not factor these definitions with the arguments used above.
+    }
+}
+
+static void assignEditSet(string_res & this, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,
+    char * resultSesStart,
+    size_t resultSesLnth,
+    HandleNode * resultPadPosition, size_t bsize ) {
 
     char * beforeBegin = shareEditSetStartPeer->Handle.s;
@@ -290,15 +331,16 @@
     size_t oldLnth = this.Handle.lnth;
 
-    this.Handle.s = pasting.Handle.s + beforeLen;
+    this.Handle.s = resultSesStart + beforeLen;
     this.Handle.lnth = bsize;
-    MoveThisAfter( this.Handle, pasting.Handle );
+    if (resultPadPosition)
+        MoveThisAfter( this.Handle, *resultPadPosition );
 
     // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
-    char *limit = pasting.Handle.s + pasting.Handle.lnth;
+    char *limit = resultSesStart + resultSesLnth;
     for (string_res * p = this.shareEditSet_next; p != &this; p = p->shareEditSet_next) {
-        assert (p->Handle.s >= beforeBegin);
+        verify (p->Handle.s >= beforeBegin);
         if ( p->Handle.s >= afterBegin ) {
-            assert ( p->Handle.s <= afterBegin + afterLen );
-            assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
+            verify ( p->Handle.s <= afterBegin + afterLen );
+            verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
             // p starts after the edit
             // take start and end as end-anchored
@@ -318,5 +360,5 @@
             } else {
                 // p ends after the edit
-                assert ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
+                verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
                 // take end as end-anchored
                 // stretch-shrink p according to the edit
@@ -326,9 +368,9 @@
             // take start as start-anchored
             size_t startOffsetFromStart = p->Handle.s - beforeBegin;
-            p->Handle.s = pasting.Handle.s + startOffsetFromStart;
+            p->Handle.s = resultSesStart + startOffsetFromStart;
         } else {
-            assert ( p->Handle.s < afterBegin );
+            verify ( p->Handle.s < afterBegin );
             // p starts during the edit
-            assert( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
+            verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
             if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
                 // p ends during the edit; p does not include the last character replaced
@@ -344,24 +386,117 @@
             }
         }
-        MoveThisAfter( p->Handle, pasting.Handle );	// move substring handle to maintain sorted order by string position
-    }
-}
-
-void ?=?(string_res &s, const char* other) {
-    assign(s, other, strlen(other));
-}
-
-void ?=?(string_res &s, char other) {
-    assign(s, &other, 1);
+        if (resultPadPosition)
+            MoveThisAfter( p->Handle, *resultPadPosition );	// move substring handle to maintain sorted order by string position
+    }
+}
+
+static string_res & assign_(string_res &this, const char* buffer, size_t bsize, const string_res & valSrc) {
+
+    // traverse the incumbent share-edit set (SES) to recover the range of a base string to which `this` belongs
+    string_res * shareEditSetStartPeer = & this;
+    string_res * shareEditSetEndPeer = & this;
+    for (string_res * editPeer = this.shareEditSet_next; editPeer != &this; editPeer = editPeer->shareEditSet_next) {
+        if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
+            shareEditSetStartPeer = editPeer;
+        }
+        if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
+            shareEditSetEndPeer = editPeer;
+        }
+    }
+
+    verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
+    size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
+    verify( origEditSetLength >= this.Handle.lnth );
+
+    if ( this.shareEditSet_owns_ulink ) {                 // assigning to private context
+        // ok to overwrite old value within LHS
+        char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
+        int prefixLen = this.Handle.s - prefixStartOrig;
+        char * suffixStartOrig = this.Handle.s + this.Handle.lnth;
+        int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
+
+        int delta = bsize - this.Handle.lnth;
+        if ( char * oldBytes = VbyteTryAdjustLast( *this.Handle.ulink, delta ) ) {
+            // growing: copy from old to new
+            char * dest = VbyteAlloc( *this.Handle.ulink, origEditSetLength + delta );
+            char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
+            destCursor += prefixLen;  memcpy(destCursor, buffer         , bsize    );
+            destCursor += bsize;      memcpy(destCursor, suffixStartOrig, suffixLen);
+            assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
+                dest,
+                origEditSetLength + delta,
+                0p, bsize);
+            free( oldBytes );
+        } else {
+            // room is already allocated in-place: bubble suffix and overwite middle
+            memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
+            memcpy( this.Handle.s, buffer, bsize );
+
+            assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
+                shareEditSetStartPeer->Handle.s,
+                origEditSetLength + delta,
+                0p, bsize);
+        }
+
+    } else if (                                           // assigning to shared context
+        this.Handle.lnth == origEditSetLength &&          // overwriting entire run of SES
+        & valSrc &&                                       // sourcing from a managed string
+        valSrc.Handle.ulink == this.Handle.ulink  ) {     // sourcing from same heap
+
+        // SES's result will only use characters from the source string => reuse source
+        assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
+            valSrc.Handle.s,
+            valSrc.Handle.lnth,
+            &((string_res&)valSrc).Handle, bsize);
+        
+    } else {
+        // overwriting a proper substring of some string: mash characters from old and new together (copy on write)
+        // OR we are importing characters: need to copy eagerly (can't refer to source)
+
+        // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
+        // `this` occurs in the middle of it, to be replaced
+        // build up the new text in `pasting`
+
+        string_res pasting = {
+            * this.Handle.ulink,                               // maintain same heap, regardless of context
+            shareEditSetStartPeer->Handle.s,                   // start of SES
+            this.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before this
+        append( pasting,
+            buffer,                                            // start of replacement for this
+            bsize );                                           // length of replacement for this
+        append( pasting,
+            this.Handle.s + this.Handle.lnth,                  // start of SES after this
+            shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
+            (this.Handle.s + this.Handle.lnth) );              // length of SES, after this
+
+        // The above string building can trigger compaction.
+        // The reference points (that are arguments of the string building) may move during that building.
+        // From this point on, they are stable.
+
+        assignEditSet(this, shareEditSetStartPeer, shareEditSetEndPeer, 
+            pasting.Handle.s,
+            pasting.Handle.lnth,
+            &pasting.Handle, bsize);
+    }
+
+    return this;
+}
+
+string_res & assign(string_res &this, const char* buffer, size_t bsize) {
+    return assign_(this, buffer, bsize, *0p);
+}
+
+string_res & ?=?(string_res &s, char other) {
+    return assign(s, &other, 1);
 }
 
 // Copy assignment operator
-void ?=?(string_res & this, const string_res & rhs) with( this ) {
-    assign(this, rhs.Handle.s, rhs.Handle.lnth);
-}
-
-void ?=?(string_res & this, string_res & rhs) with( this ) {
+string_res & ?=?(string_res & this, const string_res & rhs) with( this ) {
+    return assign_(this, rhs.Handle.s, rhs.Handle.lnth, rhs);
+}
+
+string_res & ?=?(string_res & this, string_res & rhs) with( this ) {
     const string_res & rhs2 = rhs;
-    this = rhs2;
+    return this = rhs2;
 }
 
@@ -374,6 +509,10 @@
     s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next;
     s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev;
-    s.shareEditSet_next = &s;
-    s.shareEditSet_prev = &s;
+    // s.shareEditSet_next = &s;
+    // s.shareEditSet_prev = &s;
+
+    if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out
+        delete( s.Handle.ulink );
+    }
 }
 
@@ -387,4 +526,9 @@
 }
 
+void assignAt(const string_res &s, size_t index, char val) {
+    string_res editZone = { s, SHARE_EDITS, index, index+1 };
+    assign(editZone, &val, 1);
+}
+
 
 ///////////////////////////////////////////////////////////////////
@@ -392,17 +536,17 @@
 
 void append(string_res &str1, const char * buffer, size_t bsize) {
-    size_t clnth = size(str1) + bsize;
-    if ( str1.Handle.s + size(str1) == buffer ) { // already juxtapose ?
+    size_t clnth = str1.Handle.lnth + bsize;
+    if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ?
         // no-op
     } else {						// must copy some text
-        if ( str1.Handle.s + size(str1) == VbyteAlloc(HeapArea, 0) ) { // str1 at end of string area ?
-            VbyteAlloc(HeapArea, bsize); // create room for 2nd part at the end of string area
+        if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?
+            VbyteAlloc( *str1.Handle.ulink, bsize ); // create room for 2nd part at the end of string area
         } else {					// copy the two parts
-            char * str1oldBuf = str1.Handle.s;
-            str1.Handle.s = VbyteAlloc( HeapArea, clnth );
-            ByteCopy( HeapArea, str1.Handle.s, 0, str1.Handle.lnth, str1oldBuf, 0, str1.Handle.lnth);
+            char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth );
+            char * str1oldBuf = str1.Handle.s;  // must read after VbyteAlloc call in case it gs's
+            str1.Handle.s = str1newBuf;
+            memcpy( str1.Handle.s, str1oldBuf,  str1.Handle.lnth );
         } // if
-        ByteCopy( HeapArea, str1.Handle.s, str1.Handle.lnth, bsize, (char*)buffer, 0, (int)bsize);
-        //       VbyteHeap & this, char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth 
+        memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize );
     } // if
     str1.Handle.lnth = clnth;
@@ -417,7 +561,4 @@
 }
 
-void ?+=?(string_res &s, const char* other) {
-    append( s, other, strlen(other) );
-}
 
 
@@ -429,5 +570,5 @@
 
 bool ?==?(const string_res &s1, const string_res &s2) {
-    return ByteCmp( HeapArea, s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;
+    return ByteCmp( s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;
 }
 
@@ -455,21 +596,42 @@
 
 int find(const string_res &s, char search) {
-    for (i; size(s)) {
-        if (s[i] == search) return i;
-    }
-    return size(s);
-}
+    return findFrom(s, 0, search);
+}
+
+int findFrom(const string_res &s, size_t fromPos, char search) {
+    // FIXME: This paricular overload (find of single char) is optimized to use memchr.
+    // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match.
+    char * searchFrom = s.Handle.s + fromPos;
+    size_t searchLnth = s.Handle.lnth - fromPos;
+    int searchVal = search;
+    char * foundAt = (char *) memchr(searchFrom, searchVal, searchLnth);
+    if (foundAt == 0p) return s.Handle.lnth;
+    else return foundAt - s.Handle.s;
+}
+
+int find(const string_res &s, const string_res &search) {
+    return findFrom(s, 0, search);
+}
+
+int findFrom(const string_res &s, size_t fromPos, const string_res &search) {
+    return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth);
+}
+
+int find(const string_res &s, const char* search) {
+    return findFrom(s, 0, search);
+}
+int findFrom(const string_res &s, size_t fromPos, const char* search) {
+    return findFrom(s, fromPos, search, strlen(search));
+}
+
+int find(const string_res &s, const char* search, size_t searchsize) {
+    return findFrom(s, 0, search, searchsize);
+}
+
+int findFrom(const string_res &s, size_t fromPos, const char* search, size_t searchsize) {
 
     /* Remaining implementations essentially ported from Sunjay's work */
 
-int find(const string_res &s, const string_res &search) {
-    return find(s, search.Handle.s, search.Handle.lnth);
-}
-
-int find(const string_res &s, const char* search) {
-    return find(s, search, strlen(search));
-}
-
-int find(const string_res &s, const char* search, size_t searchsize) {
+
     // FIXME: This is a naive algorithm. We probably want to switch to someting
     // like Boyer-Moore in the future.
@@ -481,5 +643,5 @@
     }
 
-    for (size_t i = 0; i < s.Handle.lnth; i++) {
+    for (size_t i = fromPos; i < s.Handle.lnth; i++) {
         size_t remaining = s.Handle.lnth - i;
         // Never going to find the search string if the remaining string is
@@ -596,8 +758,11 @@
 // Add a new HandleNode node n after the current HandleNode node.
 
-static inline void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {
+static void AddThisAfter( HandleNode & this, HandleNode & n ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:AddThisAfter, this:" | &this | " n:" | &n;
 #endif // VbyteDebug
+    // Performance note: we are on the critical path here. MB has ensured that the verifies don't contribute to runtime (are compiled away, like they're supposed to be).
+    verify( n.ulink != 0p );
+    verify( this.ulink == n.ulink );
     flink = n.flink;
     blink = &n;
@@ -624,5 +789,5 @@
 // Delete the current HandleNode node.
 
-static inline void DeleteNode( HandleNode & this ) with(this) {
+static void DeleteNode( HandleNode & this ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:DeleteNode, this:" | &this;
@@ -638,8 +803,7 @@
 
 // Allocates specified storage for a string from byte-string area. If not enough space remains to perform the
-// allocation, the garbage collection routine is called and a second attempt is made to allocate the space. If the
-// second attempt fails, a further attempt is made to create a new, larger byte-string area.
-
-static inline char * VbyteAlloc( VbyteHeap & this, int size ) with(this) {
+// allocation, the garbage collection routine is called.
+
+static char * VbyteAlloc( VbyteHeap & this, int size ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:VbyteAlloc, size:" | size;
@@ -650,10 +814,6 @@
     NoBytes = ( uintptr_t )EndVbyte + size;
     if ( NoBytes > ( uintptr_t )ExtVbyte ) {		// enough room for new byte-string ?
-		garbage( this );					// firer up the garbage collector
-		NoBytes = ( uintptr_t )EndVbyte + size;		// try again
-		if ( NoBytes > ( uintptr_t )ExtVbyte ) {	// enough room for new byte-string ?
-assert( 0 && "need to implement actual growth" );
-			// extend( size );				// extend the byte-string area
-		} // if
+		garbage( this, size );					// firer up the garbage collector
+		verify( (( uintptr_t )EndVbyte + size) <= ( uintptr_t )ExtVbyte  && "garbage run did not free up required space" );
     } // if
     r = EndVbyte;
@@ -666,16 +826,45 @@
 
 
+// Adjusts the last allocation in this heap by delta bytes, or resets this heap to be able to offer
+// new allocations of its original size + delta bytes. Positive delta means bigger;
+// negative means smaller.  A null return indicates that the original heap location has room for
+// the requested growth.  A non-null return indicates that copying to a new location is required
+// but has not been done; the returned value is the old heap storage location; `this` heap is
+// modified to reference the new location.  In the copy-requred case, the caller should use
+// VbyteAlloc to claim the new space, while doing optimal copying from old to new, then free old.
+
+static char * VbyteTryAdjustLast( VbyteHeap & this, int delta ) with(this) {
+
+    if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
+        // room available
+        EndVbyte += delta;
+        return 0p;
+    }
+
+    char *oldBytes = StartVbyte;
+
+    NoOfExtensions += 1;
+    CurrSize *= 2;
+    StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
+    ExtVbyte = StartVbyte + CurrSize;
+
+    return oldBytes;
+}
+
+
 // Move an existing HandleNode node h somewhere after the current HandleNode node so that it is in ascending order by
 // the address in the byte string area.
 
-static inline void MoveThisAfter( HandleNode & this, const HandleNode  & h ) with(this) {
+static void MoveThisAfter( HandleNode & this, const HandleNode  & h ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h;
 #endif // VbyteDebug
+    verify( h.ulink != 0p );
+    verify( this.ulink == h.ulink );
     if ( s < h.s ) {					// check argument values
 		// serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:"
 		//      | ( h->s ) | " and keep handles in ascending order";
 		// exit(-1 );
-		assert( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order");
+		verify( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order");
     } // if
 
@@ -709,21 +898,4 @@
 //######################### VbyteHeap #########################
 
-// Move characters from one location in the byte-string area to another. The routine handles the following situations:
-//
-// if the |Src| > |Dst| => truncate
-// if the |Dst| > |Src| => pad Dst with blanks
-
-void ByteCopy( VbyteHeap & this, char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth ) {
-    for ( int i = 0; i < DstLnth; i += 1 ) {
-      if ( i == SrcLnth ) {				// |Dst| > |Src|
-	    for ( ; i < DstLnth; i += 1 ) {		// pad Dst with blanks
-		Dst[DstStart + i] = ' ';
-	    } // for
-	    break;
-	} // exit
-	Dst[DstStart + i] = Src[SrcStart + i];
-    } // for
-} // ByteCopy
-
 // Compare two byte strings in the byte-string area. The routine returns the following values:
 //
@@ -732,5 +904,5 @@
 // -1 => Src1-byte-string < Src2-byte-string
 
-int ByteCmp( VbyteHeap & this, char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth )  with(this) {
+int ByteCmp( char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth )  {
 #ifdef VbyteDebug
     serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth;
@@ -789,5 +961,5 @@
     h = Header.flink;					// ignore header node
     for (;;) {
-		ByteCopy( this, EndVbyte, 0, h->lnth, h->s, 0, h->lnth );
+		memmove( EndVbyte, h->s, h->lnth );
 		obase = h->s;
 		h->s = EndVbyte;
@@ -810,8 +982,16 @@
 
 
+static double heap_expansion_freespace_threshold = 0.1;  // default inherited from prior work: expand heap when less than 10% "free" (i.e. garbage)
+                                                         // probably an unreasonable default, but need to assess early-round tests on changing it
+
+void TUNING_set_string_heap_liveness_threshold( double val ) {
+    heap_expansion_freespace_threshold = 1.0 - val;
+}
+
+
 // Garbage determines the amount of free space left in the heap and then reduces, leave the same, or extends the size of
 // the heap.  The heap is then compacted in the existing heap or into the newly allocated heap.
 
-void garbage(VbyteHeap & this ) with(this) {
+void garbage(VbyteHeap & this, int minreq ) with(this) {
 #ifdef VbyteDebug
     serr | "enter:garbage";
@@ -837,8 +1017,7 @@
     AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed;
     
-    if ( AmountFree < ( int )( CurrSize * 0.1 )) {	// free space less than 10% ?
-
-assert( 0 && "need to implement actual growth" );
-//		extend( CurrSize );				// extend the heap
+    if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) {	// free space less than threshold or not enough to serve cur request
+
+		extend( this, max( CurrSize, minreq ) );				// extend the heap
 
 			//  Peter says, "This needs work before it should be used."
@@ -846,6 +1025,9 @@
 			//		reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory
 
-    } // if
-    compaction(this);					// compact the byte area, in the same or new heap area
+        // `extend` implies a `compaction` during the copy
+
+    } else {
+        compaction(this);					// in-place
+    }// if
 #ifdef VbyteDebug
     {
@@ -867,6 +1049,4 @@
 #undef VbyteDebug
 
-//WIP
-#if 0
 
 
@@ -874,5 +1054,5 @@
 // area is deleted.
 
-void VbyteHeap::extend( int size ) {
+void extend( VbyteHeap & this, int size ) with (this) {
 #ifdef VbyteDebug
     serr | "enter:extend, size:" | size;
@@ -884,8 +1064,8 @@
     
     CurrSize += size > InitSize ? size : InitSize;	// minimum extension, initial size
-    StartVbyte = EndVbyte = new char[CurrSize];
+    StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
     ExtVbyte = (void *)( StartVbyte + CurrSize );
-    compaction();					// copy from old heap to new & adjust pointers to new heap
-    delete OldStartVbyte;				// release old heap
+    compaction(this);					// copy from old heap to new & adjust pointers to new heap
+    free( OldStartVbyte );				// release old heap
 #ifdef VbyteDebug
     serr | "exit:extend, CurrSize:" | CurrSize;
@@ -893,4 +1073,6 @@
 } // extend
 
+//WIP
+#if 0
 
 // Extend the size of the byte-string area by creating a new area and copying the old area into it. The old byte-string
Index: libcfa/src/containers/string_res.hfa
===================================================================
--- libcfa/src/containers/string_res.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/containers/string_res.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -17,4 +17,5 @@
 
 #include <fstream.hfa>
+#include <string.h>    // e.g. strlen
 
     
@@ -27,4 +28,5 @@
     HandleNode *flink;					// forward link
     HandleNode *blink;					// backward link
+    VbyteHeap *ulink;                   // upward link
 
     char *s;						// pointer to byte string
@@ -32,13 +34,10 @@
 }; // HandleNode
 
-void ?{}( HandleNode & );			// constructor for header node
-
-void ?{}( HandleNode &, VbyteHeap & );		// constructor for nodes in the handle list
-void ^?{}( HandleNode & );			// destructor for handle nodes
-
-extern VbyteHeap * DEBUG_string_heap;
+VbyteHeap * DEBUG_string_heap();
+size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap );
 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap );
 const char * DEBUG_string_heap_start( VbyteHeap * heap );
 
+void TUNING_set_string_heap_liveness_threshold( double val );
 
 //######################### String #########################
@@ -47,4 +46,5 @@
 struct string_res {
     HandleNode Handle; // chars, start, end, global neighbours
+    bool shareEditSet_owns_ulink;
     string_res * shareEditSet_prev;
     string_res * shareEditSet_next;
@@ -74,6 +74,8 @@
 // Constructors, Assignment Operators, Destructor
 void ?{}(string_res &s); // empty string
-void ?{}(string_res &s, const char* initial); // copy from string literal (NULL-terminated)
 void ?{}(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer
+static inline void ?{}(string_res &s, const char* rhs) { // copy from string literal (NULL-terminated)
+    (s){ rhs, strlen(rhs) };
+}
 
 void ?{}(string_res &s, const string_res & s2) = void;
@@ -86,9 +88,11 @@
 }
 
-void assign(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer
-void ?=?(string_res &s, const char* other); // copy from string literal (NULL-terminated)
-void ?=?(string_res &s, const string_res &other);
-void ?=?(string_res &s, string_res &other);
-void ?=?(string_res &s, char other);
+string_res & assign(string_res &s, const char* buffer, size_t bsize); // copy specific length from buffer
+static inline string_res & ?=?(string_res &s, const char* other) {  // copy from string literal (NULL-terminated)
+    return assign(s, other, strlen(other));
+}
+string_res & ?=?(string_res &s, const string_res &other);
+string_res & ?=?(string_res &s, string_res &other);
+string_res & ?=?(string_res &s, char other);
 
 void ^?{}(string_res &s);
@@ -99,10 +103,13 @@
 
 // Concatenation
+void append(string_res &s, const char* buffer, size_t bsize);
 void ?+=?(string_res &s, char other); // append a character
 void ?+=?(string_res &s, const string_res &s2); // append-concatenate to first string
-void ?+=?(string_res &s, const char* other);
-void append(string_res &s, const char* buffer, size_t bsize);
+static inline void ?+=?(string_res &s, const char* other) {
+    append( s, other, strlen(other) );
+}
 
 // Character access
+void assignAt(const string_res &s, size_t index, char val);
 char ?[?](const string_res &s, size_t index); // Mike changed to ret by val from Sunjay's ref, to match Peter's
 //char codePointAt(const string_res &s, size_t index); // revisit under Unicode
@@ -121,4 +128,9 @@
 int find(const string_res &s, const char* search);
 int find(const string_res &s, const char* search, size_t searchsize);
+
+int findFrom(const string_res &s, size_t fromPos, char search);
+int findFrom(const string_res &s, size_t fromPos, const string_res &search);
+int findFrom(const string_res &s, size_t fromPos, const char* search);
+int findFrom(const string_res &s, size_t fromPos, const char* search, size_t searchsize);
 
 bool includes(const string_res &s, const string_res &search);
Index: libcfa/src/containers/string_sharectx.hfa
===================================================================
--- libcfa/src/containers/string_sharectx.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ libcfa/src/containers/string_sharectx.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,58 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// string_sharectx -- utility for controlling string sharing / isolation
+//
+// Author           : Michael L. Brooks
+// Created On       : Fri Sep 03 11:00:00 2021
+// Last Modified By : Michael L. Brooks
+// Last Modified On : Fri Sep 03 11:00:00 2021
+// Update Count     : 1
+//
+
+#pragma once
+
+//######################### String Sharing Context #########################
+
+struct VbyteHeap;
+
+// A string_sharectx 
+//
+// Usage:
+// void bar() {
+//    c();
+//    string_sharectx c = {NEW_SHARING};
+//    d();
+// }
+// void foo() {
+//    a();
+//    string_sharectx c = {NO_SHARING};
+//    b();
+//    bar();
+//    e();
+// }
+// int main() {
+//    foo();
+// }
+//
+// a, d: share string character ranges within themselves, not with each other
+// b, c, e: never share anything
+//
+struct string_sharectx {
+    // private
+    VbyteHeap * activeHeap;
+    string_sharectx * older;
+};
+
+enum StringSharectx_Mode { NEW_SHARING, NO_SHARING };
+
+void ?{}( string_sharectx &, StringSharectx_Mode );
+void ^?{}( string_sharectx & );
+
+void ?{}( string_sharectx & ) = void;
+void ?{}( string_sharectx &, string_sharectx ) = void;
+void ?=?( string_sharectx &, string_sharectx ) = void;
+
Index: libcfa/src/math.trait.hfa
===================================================================
--- libcfa/src/math.trait.hfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ libcfa/src/math.trait.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -16,7 +16,7 @@
 #pragma once
 
-trait Not( T ) {
-	void ?{}( T &, zero_t );
-	int !?( T );
+trait Not( U ) {
+	void ?{}( U &, zero_t );
+	int !?( U );
 }; // Not
 
@@ -26,9 +26,9 @@
 }; // Equality
 
-trait Relational( T | Equality( T ) ) {
-	int ?<?( T, T );
-	int ?<=?( T, T );
-	int ?>?( T, T );
-	int ?>=?( T, T );
+trait Relational( U | Equality( U ) ) {
+	int ?<?( U, U );
+	int ?<=?( U, U );
+	int ?>?( U, U );
+	int ?>=?( U, U );
 }; // Relational
 
@@ -39,9 +39,9 @@
 }; // Signed
 
-trait Additive( T | Signed( T ) ) {
-	T ?+?( T, T );
-	T ?-?( T, T );
-	T ?+=?( T &, T );
-	T ?-=?( T &, T );
+trait Additive( U | Signed( U ) ) {
+	U ?+?( U, U );
+	U ?-?( U, U );
+	U ?+=?( U &, U );
+	U ?-=?( U &, U );
 }; // Additive
 
@@ -49,14 +49,14 @@
 	void ?{}( T &, one_t );
 	// T ?++( T & );
-	// T ++?( T &);
+	// T ++?( T & );
 	// T ?--( T & );
 	// T --?( T & );
 }; // Incdec
 
-trait Multiplicative( T | Incdec( T ) ) {
-	T ?*?( T, T );
-	T ?/?( T, T );
-	T ?%?( T, T );
-	T ?/=?( T &, T );
+trait Multiplicative( U | Incdec( U ) ) {
+	U ?*?( U, U );
+	U ?/?( U, U );
+	U ?%?( U, U );
+	U ?/=?( U &, U );
 }; // Multiplicative
 
Index: c/AST/AssertAcyclic.cpp
===================================================================
--- src/AST/AssertAcyclic.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ 	(revision )
@@ -1,53 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// AssertAcyclic.cpp -- Check that ast::ptr does not form a cycle.
-//
-// Author           : Andrew Beach
-// Created On       : Thu Jun 06 15:00:00 2019
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri Jun 07 14:32:00 2019
-// Update Count     : 1
-//
-
-#include "AssertAcyclic.hpp"
-
-#include "AST/Pass.hpp"
-
-namespace {
-
-class NoStrongCyclesCore {
-    std::vector<const ast::Node *> parents;
-public:
-	void previsit( const ast::Node * node ) {
-		for (auto & parent : parents) {
-			assert(parent != node);
-		}
-		parents.push_back(node);
-	}
-	void postvisit( const ast::Node * ) {
-		parents.pop_back();
-	}
-};
-
-}
-
-namespace ast {
-
-void assertAcyclic( const std::list< ast::ptr< ast::Decl > > & translationUnit ) {
-   	Pass<NoStrongCyclesCore> visitor;
-	for ( auto & decl : translationUnit ) {
-		decl->accept( visitor );
-	}
-}
-
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: c/AST/AssertAcyclic.hpp
===================================================================
--- src/AST/AssertAcyclic.hpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ 	(revision )
@@ -1,35 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// AssertAcyclic.hpp -- Check that ast::ptr does not form a cycle.
-//
-// Author           : Andrew Beach
-// Created On       : Thr Jun  6 15:00:00 2019
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri Jun  7 14:32:00 2019
-// Update Count     : 1
-//
-
-#pragma once
-
-#include <list>
-
-#include "Node.hpp"
-namespace ast {
-    class Decl;
-};
-
-namespace ast {
-
-void assertAcyclic( const std::list< ast::ptr< ast::Decl > > & translationUnit );
-
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/AST/Convert.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -9,7 +9,7 @@
 // Author           : Thierry Delisle
 // Created On       : Thu May 09 15::37::05 2019
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Feb  2 13:19:22 2022
-// Update Count     : 41
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Mar 16 15:01:00 2022
+// Update Count     : 42
 //
 
@@ -49,14 +49,11 @@
 //================================================================================================
 namespace ast {
-
-// This is to preserve the FindSpecialDecls hack. It does not (and perhaps should not)
-// allow us to use the same stratagy in the new ast.
-// xxx - since convert back pass works, this concern seems to be unnecessary.
-
-// these need to be accessed in new FixInit now
-ast::ptr<ast::Type> sizeType = nullptr;
-const ast::FunctionDecl * dereferenceOperator = nullptr;
-const ast::StructDecl   * dtorStruct = nullptr;
-const ast::FunctionDecl * dtorStructDestroy = nullptr;
+// These are the shared local information used by ConverterNewToOld and
+// ConverterOldToNew to update the global information in the two versions.
+
+static ast::ptr<ast::Type> sizeType = nullptr;
+static const ast::FunctionDecl * dereferenceOperator = nullptr;
+static const ast::StructDecl   * dtorStruct = nullptr;
+static const ast::FunctionDecl * dtorStructDestroy = nullptr;
 
 }
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/AST/Decl.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -39,8 +39,11 @@
 	if ( uniqueId ) return;  // ensure only set once
 	uniqueId = ++lastUniqueId;
-	idMap[ uniqueId ] = this;
+	// The extra readonly pointer is causing some reference counting issues.
+	// idMap[ uniqueId ] = this;
 }
 
 readonly<Decl> Decl::fromId( UniqueId id ) {
+	// Right now this map is always empty, so don't use it.
+	assert( false );
 	IdMapType::const_iterator i = idMap.find( id );
 	if ( i != idMap.end() ) return i->second;
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/AST/Fwd.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -141,9 +141,5 @@
 
 class TranslationUnit;
-// TODO: Get from the TranslationUnit:
-extern ptr<Type> sizeType;
-extern const FunctionDecl * dereferenceOperator;
-extern const StructDecl   * dtorStruct;
-extern const FunctionDecl * dtorStructDestroy;
+class TranslationGlobal;
 
 }
Index: src/AST/GenericSubstitution.cpp
===================================================================
--- src/AST/GenericSubstitution.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/AST/GenericSubstitution.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -45,5 +45,5 @@
 			visit_children = false;
 			const AggregateDecl * aggr = ty->aggr();
-			sub = TypeSubstitution{ aggr->params.begin(), aggr->params.end(), ty->params.begin() };
+			sub = TypeSubstitution( aggr->params, ty->params );
 		}
 
Index: src/AST/TranslationUnit.hpp
===================================================================
--- src/AST/TranslationUnit.hpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/AST/TranslationUnit.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,6 +10,6 @@
 // Created On       : Tue Jun 11 15:30:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Jun 11 15:42:00 2019
-// Update Count     : 0
+// Last Modified On : Tue Mar 11 11:19:00 2022
+// Update Count     : 1
 //
 
@@ -23,16 +23,18 @@
 namespace ast {
 
+class TranslationGlobal {
+public:
+	std::map< UniqueId, Decl * > idMap;
+
+	ptr<Type> sizeType;
+	const FunctionDecl * dereference;
+	const StructDecl * dtorStruct;
+	const FunctionDecl * dtorDestroy;
+};
+
 class TranslationUnit {
 public:
 	std::list< ptr< Decl > > decls;
-
-	struct Global {
-		std::map< UniqueId, Decl * > idMap;
-
-		ptr<Type> sizeType;
-		const FunctionDecl * dereference;
-		const StructDecl * dtorStruct;
-		const FunctionDecl * dtorDestroy;
-	} global;
+	TranslationGlobal global;
 };
 
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/AST/TypeSubstitution.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -37,4 +37,6 @@
   public:
 	TypeSubstitution();
+	template< typename FormalContainer, typename ActualContainer >
+	TypeSubstitution( FormalContainer formals, ActualContainer actuals );
 	template< typename FormalIterator, typename ActualIterator >
 	TypeSubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
@@ -76,6 +78,8 @@
 	bool empty() const;
 
+	template< typename FormalContainer, typename ActualContainer >
+	void addAll( FormalContainer formals, ActualContainer actuals );
 	template< typename FormalIterator, typename ActualIterator >
-	void add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
+	void addAll( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
 
 	/// create a new TypeSubstitution using bindings from env containing all of the type variables in expr
@@ -112,7 +116,24 @@
 };
 
+template< typename FormalContainer, typename ActualContainer >
+TypeSubstitution::TypeSubstitution( FormalContainer formals, ActualContainer actuals ) {
+	assert( formals.size() == actuals.size() );
+	addAll( formals.begin(), formals.end(), actuals.begin() );
+}
+
+template< typename FormalIterator, typename ActualIterator >
+TypeSubstitution::TypeSubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
+	addAll( formalBegin, formalEnd, actualBegin );
+}
+
+template< typename FormalContainer, typename ActualContainer >
+void TypeSubstitution::addAll( FormalContainer formals, ActualContainer actuals ) {
+	assert( formals.size() == actuals.size() );
+	addAll( formals.begin(), formals.end(), actuals.begin() );
+}
+
 // this is the only place where type parameters outside a function formal may be substituted.
 template< typename FormalIterator, typename ActualIterator >
-void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
+void TypeSubstitution::addAll( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
 	// FormalIterator points to a TypeDecl
 	// ActualIterator points to a Type
@@ -129,16 +150,8 @@
 			} // if
 		} else {
-			
+			// Is this an error?
 		} // if
 	} // for
 }
-
-
-
-template< typename FormalIterator, typename ActualIterator >
-TypeSubstitution::TypeSubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
-	add( formalBegin, formalEnd, actualBegin );
-}
-
 
 } // namespace ast
Index: src/AST/Util.cpp
===================================================================
--- src/AST/Util.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ src/AST/Util.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,80 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Util.hpp -- General utilities for working with the AST.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Jan 19  9:46:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Mar 11 18:07:00 2022
+// Update Count     : 1
+//
+
+#include "Util.hpp"
+
+#include "Node.hpp"
+#include "ParseNode.hpp"
+#include "Pass.hpp"
+#include "TranslationUnit.hpp"
+
+#include <vector>
+
+namespace ast {
+
+namespace {
+
+/// Check that ast::ptr/strong references do not form a cycle.
+struct NoStrongCyclesCore {
+	std::vector<const Node *> parents;
+
+	void previsit( const Node * node ) {
+		for ( auto & parent : parents ) {
+			assert( parent != node );
+		}
+		parents.push_back( node );
+	}
+
+	void postvisit( const Node * node ) {
+		assert( !parents.empty() );
+		assert( parents.back() == node );
+		parents.pop_back();
+	}
+};
+
+/// Check that every note that can has a set CodeLocation.
+struct SetCodeLocationsCore {
+	void previsit( const ParseNode * node ) {
+		assert( node->location.isSet() );
+	}
+};
+
+struct InvariantCore {
+	// To save on the number of visits: this is a kind of composed core.
+	// None of the passes should make changes so ordering doesn't matter.
+	NoStrongCyclesCore no_strong_cycles;
+	SetCodeLocationsCore set_code_locations;
+
+	void previsit( const Node * node ) {
+		no_strong_cycles.previsit( node );
+	}
+
+	void previsit( const ParseNode * node ) {
+		no_strong_cycles.previsit( node );
+		set_code_locations.previsit( node );
+	}
+
+	void postvisit( const Node * node ) {
+		no_strong_cycles.postvisit( node );
+	}
+};
+
+} // namespace
+
+void checkInvariants( TranslationUnit & transUnit ) {
+	ast::Pass<InvariantCore>::run( transUnit );
+}
+
+} // namespace ast
Index: src/AST/Util.hpp
===================================================================
--- src/AST/Util.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ src/AST/Util.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,26 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Util.hpp -- General utilities for working with the AST.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Jan 19  9:37:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Feb 18  9:43:00 2022
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+
+class TranslationUnit;
+
+/// Check anything that should always be true of the AST between passes.
+/// Insert this whenever you want additional debugging checks.
+void checkInvariants( TranslationUnit & transUnit );
+
+}
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/AST/module.mk	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -16,6 +16,4 @@
 
 SRC_AST = \
-	AST/AssertAcyclic.cpp \
-	AST/AssertAcyclic.hpp \
 	AST/Attribute.cpp \
 	AST/Attribute.hpp \
@@ -64,4 +62,6 @@
 	AST/TypeSubstitution.cpp \
 	AST/TypeSubstitution.hpp \
+	AST/Util.cpp \
+	AST/Util.hpp \
 	AST/Visitor.hpp
 
Index: src/Common/CodeLocationTools.cpp
===================================================================
--- src/Common/CodeLocationTools.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Common/CodeLocationTools.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -9,7 +9,7 @@
 // Author           : Andrew Beach
 // Created On       : Fri Dec  4 15:42:00 2020
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Feb  1 09:14:39 2022
-// Update Count     : 3
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Mar 14 15:14:00 2022
+// Update Count     : 4
 //
 
@@ -239,4 +239,25 @@
 };
 
+class LocalFillCore : public ast::WithGuards {
+	CodeLocation const * parent;
+public:
+	LocalFillCore( CodeLocation const & location ) : parent( &location ) {
+		assert( location.isSet() );
+	}
+
+	template<typename node_t>
+	auto previsit( node_t const * node )
+			-> typename std::enable_if<has_code_location<node_t>::value, node_t const *>::type {
+		if ( node->location.isSet() ) {
+			GuardValue( parent ) = &node->location;
+			return node;
+		} else {
+			node_t * mut = ast::mutate( node );
+			mut->location = *parent;
+			return mut;
+		}
+	}
+};
+
 } // namespace
 
@@ -278,2 +299,8 @@
 	ast::Pass<FillCore>::run( unit );
 }
+
+ast::Node const * localFillCodeLocations(
+		CodeLocation const & location , ast::Node const * node ) {
+	ast::Pass<LocalFillCore> visitor( location );
+	return node->accept( visitor );
+}
Index: src/Common/CodeLocationTools.hpp
===================================================================
--- src/Common/CodeLocationTools.hpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Common/CodeLocationTools.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,11 +10,13 @@
 // Created On       : Fri Dec  4 15:35:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Dec  9  9:53:00 2020
-// Update Count     : 1
+// Last Modified On : Mon Mar 14 15:14:00 2022
+// Update Count     : 2
 //
 
 #pragma once
 
+struct CodeLocation;
 namespace ast {
+	class Node;
 	class TranslationUnit;
 }
@@ -28,2 +30,7 @@
 // Assign a nearby code-location to any unset code locations in the forest.
 void forceFillCodeLocations( ast::TranslationUnit & unit );
+
+// Fill in code-locations with a parent code location,
+// using the provided CodeLocation as the base.
+ast::Node const *
+	localFillCodeLocations( CodeLocation const &, ast::Node const * );
Index: src/Common/Examine.cc
===================================================================
--- src/Common/Examine.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Common/Examine.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -5,16 +5,18 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Examine.h --
+// Examine.cc -- Helpers for examining AST code.
 //
 // Author           : Andrew Beach
 // Created On       : Wed Sept 2 14:02 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Sep  8 12:15 2020
-// Update Count     : 0
+// Last Modified On : Fri Dec 10 10:27 2021
+// Update Count     : 1
 //
 
 #include "Common/Examine.h"
 
+#include "AST/Type.hpp"
 #include "CodeGen/OperatorTable.h"
+#include "InitTweak/InitTweak.h"
 
 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) {
@@ -36,4 +38,35 @@
 
 namespace {
+
+// getTypeofThis but does some extra checks used in this module.
+const ast::Type * getTypeofThisSolo( const ast::FunctionDecl * func ) {
+	if ( 1 != func->params.size() ) {
+		return nullptr;
+	}
+	auto ref = func->type->params.front().as<ast::ReferenceType>();
+	return (ref) ? ref->base : nullptr;
+}
+
+}
+
+const ast::DeclWithType * isMainFor(
+		const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind ) {
+	if ( "main" != func->name ) return nullptr;
+	if ( 1 != func->params.size() ) return nullptr;
+
+	auto param = func->params.front();
+
+	auto type = dynamic_cast<const ast::ReferenceType *>( param->get_type() );
+	if ( !type ) return nullptr;
+
+	auto obj = type->base.as<ast::StructInstType>();
+	if ( !obj ) return nullptr;
+
+	if ( kind != obj->base->kind ) return nullptr;
+
+	return param;
+}
+
+namespace {
 	Type * getDestructorParam( FunctionDecl * func ) {
 		if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
@@ -48,4 +81,11 @@
 		return nullptr;
 	}
+
+const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) {
+	if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
+	//return InitTweak::getParamThis( func )->type;
+	return getTypeofThisSolo( func );
+}
+
 }
 
@@ -57,2 +97,11 @@
 	return false;
 }
+
+bool isDestructorFor(
+		const ast::FunctionDecl * func, const ast::StructDecl * type_decl ) {
+	if ( const ast::Type * type = getDestructorParam( func ) ) {
+		auto stype = dynamic_cast<const ast::StructInstType *>( type );
+		return stype && stype->base.get() == type_decl;
+	}
+	return false;
+}
Index: src/Common/Examine.h
===================================================================
--- src/Common/Examine.h	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Common/Examine.h	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -5,19 +5,24 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Examine.h --
+// Examine.h -- Helpers for examining AST code.
 //
 // Author           : Andrew Beach
 // Created On       : Wed Sept 2 13:57 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Sep  8 12:08 2020
-// Update Count     : 0
+// Last Modified On : Fri Dec 10 10:28 2021
+// Update Count     : 1
 //
 
+#include "AST/Decl.hpp"
 #include "SynTree/Declaration.h"
 
 /// Check if this is a main function for a type of an aggregate kind.
 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );
+const ast::DeclWithType * isMainFor(
+	const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind );
 // Returns a pointer to the parameter if true, nullptr otherwise.
 
 /// Check if this function is a destructor for the given structure.
 bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );
+bool isDestructorFor(
+	const ast::FunctionDecl * func, const ast::StructDecl * type );
Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Concurrency/Keywords.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -422,6 +422,7 @@
 			;
 		else if ( auto param = isMainFor( decl, cast_target ) ) {
-			// This should never trigger.
-			assert( vtable_decl );
+			if ( !vtable_decl ) {
+				SemanticError( decl, context_error );
+			}
 			// Should be safe because of isMainFor.
 			StructInstType * struct_type = static_cast<StructInstType *>(
@@ -1203,5 +1204,5 @@
 					//new TypeofType( noQualifiers, args.front()->clone() )
 					new TypeofType( noQualifiers, new UntypedExpr(
-							new NameExpr( "__get_type" ),
+							new NameExpr( "__get_mutexstmt_lock_type" ),
 							{ args.front()->clone() }
 						) 
@@ -1215,5 +1216,5 @@
 				map_range < std::list<Initializer*> > ( args, [](Expression * var ){
 					return new SingleInit( new UntypedExpr(
-							new NameExpr( "__get_ptr" ),
+							new NameExpr( "__get_mutexstmt_lock_ptr" ),
 							{ var }
 					) );
@@ -1226,5 +1227,5 @@
 		TypeExpr * lock_type_expr = new TypeExpr( 
 			new TypeofType( noQualifiers, new UntypedExpr(
-				new NameExpr( "__get_type" ),
+				new NameExpr( "__get_mutexstmt_lock_type" ),
 				{ args.front()->clone() }
 				) 
Index: src/Concurrency/KeywordsNew.cpp
===================================================================
--- src/Concurrency/KeywordsNew.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Concurrency/KeywordsNew.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,7 +10,9 @@
 // Created On       : Tue Nov 16  9:53:00 2021
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Dec  1 11:24:00 2021
-// Update Count     : 1
+// Last Modified On : Fri Mar 11 10:40:00 2022
+// Update Count     : 2
 //
+
+#include <iostream>
 
 #include "Concurrency/Keywords.h"
@@ -18,10 +20,16 @@
 #include "AST/Copy.hpp"
 #include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
 #include "AST/Pass.hpp"
 #include "AST/Stmt.hpp"
+#include "AST/DeclReplacer.hpp"
 #include "AST/TranslationUnit.hpp"
 #include "CodeGen/OperatorTable.h"
+#include "Common/Examine.h"
 #include "Common/utility.h"
+#include "Common/UniqueName.h"
+#include "ControlStruct/LabelGeneratorNew.hpp"
 #include "InitTweak/InitTweak.h"
+#include "Virtual/Tables.h"
 
 namespace Concurrency {
@@ -29,5 +37,9 @@
 namespace {
 
-inline static bool isThread( const ast::DeclWithType * decl ) {
+// --------------------------------------------------------------------------
+// Loose Helper Functions:
+
+/// Detect threads constructed with the keyword thread.
+bool isThread( const ast::DeclWithType * decl ) {
 	auto baseType = decl->get_type()->stripDeclarator();
 	auto instType = dynamic_cast<const ast::StructInstType *>( baseType );
@@ -36,6 +48,835 @@
 }
 
+/// Get the virtual type id if given a type name.
+std::string typeIdType( std::string const & exception_name ) {
+	return exception_name.empty() ? std::string()
+		: Virtual::typeIdType( exception_name );
+}
+
+/// Get the vtable type name if given a type name.
+std::string vtableTypeName( std::string const & exception_name ) {
+	return exception_name.empty() ? std::string()
+		: Virtual::vtableTypeName( exception_name );
+}
+
+static ast::Type * mutate_under_references( ast::ptr<ast::Type>& type ) {
+	ast::Type * mutType = type.get_and_mutate();
+	for ( ast::ReferenceType * mutRef
+		; (mutRef = dynamic_cast<ast::ReferenceType *>( mutType ))
+		; mutType = mutRef->base.get_and_mutate() );
+	return mutType;
+}
+
+// Describe that it adds the generic parameters and the uses of the generic
+// parameters on the function and first "this" argument.
+ast::FunctionDecl * fixupGenerics(
+		const ast::FunctionDecl * func, const ast::StructDecl * decl ) {
+	const CodeLocation & location = decl->location;
+	// We have to update both the declaration
+	auto mutFunc = ast::mutate( func );
+	auto mutType = mutFunc->type.get_and_mutate();
+
+	if ( decl->params.empty() ) {
+		return mutFunc;
+	}
+
+	assert( 0 != mutFunc->params.size() );
+	assert( 0 != mutType->params.size() );
+
+	// Add the "forall" clause information.
+	for ( const ast::ptr<ast::TypeDecl> & typeParam : decl->params ) {
+		auto typeDecl = ast::deepCopy( typeParam );
+		mutFunc->type_params.push_back( typeDecl );
+		mutType->forall.push_back(
+			new ast::TypeInstType( typeDecl->name, typeDecl ) );
+		for ( auto & assertion : typeDecl->assertions ) {
+			mutFunc->assertions.push_back( assertion );
+			mutType->assertions.emplace_back(
+				new ast::VariableExpr( location, assertion ) );
+		}
+		typeDecl->assertions.clear();
+	}
+
+	// Even chain_mutate is not powerful enough for this:
+	ast::ptr<ast::Type>& paramType = strict_dynamic_cast<ast::ObjectDecl *>(
+		mutFunc->params[0].get_and_mutate() )->type;
+	auto paramTypeInst = strict_dynamic_cast<ast::StructInstType *>(
+		mutate_under_references( paramType ) );
+	auto typeParamInst = strict_dynamic_cast<ast::StructInstType *>(
+		mutate_under_references( mutType->params[0] ) );
+
+	for ( const ast::ptr<ast::TypeDecl> & typeDecl : mutFunc->type_params ) {
+		paramTypeInst->params.push_back(
+			new ast::TypeExpr( location,
+				new ast::TypeInstType( typeDecl->name, typeDecl ) ) );
+		typeParamInst->params.push_back(
+			new ast::TypeExpr( location,
+				new ast::TypeInstType( typeDecl->name, typeDecl ) ) );
+	}
+
+	return mutFunc;
+}
+
 // --------------------------------------------------------------------------
-struct MutexKeyword final {
+struct ConcurrentSueKeyword : public ast::WithDeclsToAdd<> {
+	ConcurrentSueKeyword(
+		std::string&& type_name, std::string&& field_name,
+		std::string&& getter_name, std::string&& context_error,
+		std::string&& exception_name,
+		bool needs_main, ast::AggregateDecl::Aggregate cast_target
+	) :
+		type_name( type_name ), field_name( field_name ),
+		getter_name( getter_name ), context_error( context_error ),
+		exception_name( exception_name ),
+		typeid_name( typeIdType( exception_name ) ),
+		vtable_name( vtableTypeName( exception_name ) ),
+		needs_main( needs_main ), cast_target( cast_target )
+	{}
+
+	virtual ~ConcurrentSueKeyword() {}
+
+	const ast::Decl * postvisit( const ast::StructDecl * decl );
+	const ast::DeclWithType * postvisit( const ast::FunctionDecl * decl );
+	const ast::Expr * postvisit( const ast::KeywordCastExpr * expr );
+
+	struct StructAndField {
+		const ast::StructDecl * decl;
+		const ast::ObjectDecl * field;
+	};
+
+	const ast::StructDecl * handleStruct( const ast::StructDecl * );
+	void handleMain( const ast::FunctionDecl *, const ast::StructInstType * );
+	void addTypeId( const ast::StructDecl * );
+	void addVtableForward( const ast::StructDecl * );
+	const ast::FunctionDecl * forwardDeclare( const ast::StructDecl * );
+	StructAndField addField( const ast::StructDecl * );
+	void addGetRoutines( const ast::ObjectDecl *, const ast::FunctionDecl * );
+	void addLockUnlockRoutines( const ast::StructDecl * );
+
+private:
+	const std::string type_name;
+	const std::string field_name;
+	const std::string getter_name;
+	const std::string context_error;
+	const std::string exception_name;
+	const std::string typeid_name;
+	const std::string vtable_name;
+	const bool needs_main;
+	const ast::AggregateDecl::Aggregate cast_target;
+
+	const ast::StructDecl   * type_decl = nullptr;
+	const ast::FunctionDecl * dtor_decl = nullptr;
+	const ast::StructDecl * except_decl = nullptr;
+	const ast::StructDecl * typeid_decl = nullptr;
+	const ast::StructDecl * vtable_decl = nullptr;
+
+};
+
+// Handles thread type declarations:
+//
+// thread Mythread {                         struct MyThread {
+//  int data;                                  int data;
+//  a_struct_t more_data;                      a_struct_t more_data;
+//                                =>             thread$ __thrd_d;
+// };                                        };
+//                                           static inline thread$ * get_thread( MyThread * this ) { return &this->__thrd_d; }
+//
+struct ThreadKeyword final : public ConcurrentSueKeyword {
+	ThreadKeyword() : ConcurrentSueKeyword(
+		"thread$",
+		"__thrd",
+		"get_thread",
+		"thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
+		"ThreadCancelled",
+		true,
+		ast::AggregateDecl::Thread )
+	{}
+
+	virtual ~ThreadKeyword() {}
+};
+
+// Handles coroutine type declarations:
+//
+// coroutine MyCoroutine {                   struct MyCoroutine {
+//  int data;                                  int data;
+//  a_struct_t more_data;                      a_struct_t more_data;
+//                                =>             coroutine$ __cor_d;
+// };                                        };
+//                                           static inline coroutine$ * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
+//
+struct CoroutineKeyword final : public ConcurrentSueKeyword {
+	CoroutineKeyword() : ConcurrentSueKeyword(
+		"coroutine$",
+		"__cor",
+		"get_coroutine",
+		"coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
+		"CoroutineCancelled",
+		true,
+		ast::AggregateDecl::Coroutine )
+	{}
+
+	virtual ~CoroutineKeyword() {}
+};
+
+// Handles monitor type declarations:
+//
+// monitor MyMonitor {                       struct MyMonitor {
+//  int data;                                  int data;
+//  a_struct_t more_data;                      a_struct_t more_data;
+//                                =>             monitor$ __mon_d;
+// };                                        };
+//                                           static inline monitor$ * get_coroutine( MyMonitor * this ) {
+//                                               return &this->__cor_d;
+//                                           }
+//                                           void lock(MyMonitor & this) {
+//                                               lock(get_monitor(this));
+//                                           }
+//                                           void unlock(MyMonitor & this) {
+//                                               unlock(get_monitor(this));
+//                                           }
+//
+struct MonitorKeyword final : public ConcurrentSueKeyword {
+	MonitorKeyword() : ConcurrentSueKeyword(
+		"monitor$",
+		"__mon",
+		"get_monitor",
+		"monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
+		"",
+		false,
+		ast::AggregateDecl::Monitor )
+	{}
+
+	virtual ~MonitorKeyword() {}
+};
+
+// Handles generator type declarations:
+//
+// generator MyGenerator {                   struct MyGenerator {
+//  int data;                                  int data;
+//  a_struct_t more_data;                      a_struct_t more_data;
+//                                =>             int __generator_state;
+// };                                        };
+//
+struct GeneratorKeyword final : public ConcurrentSueKeyword {
+	GeneratorKeyword() : ConcurrentSueKeyword(
+		"generator$",
+		"__generator_state",
+		"get_generator",
+		"Unable to find builtin type generator$\n",
+		"",
+		true,
+		ast::AggregateDecl::Generator )
+	{}
+
+	virtual ~GeneratorKeyword() {}
+};
+
+const ast::Decl * ConcurrentSueKeyword::postvisit(
+		const ast::StructDecl * decl ) {
+	if ( !decl->body ) {
+		return decl;
+	} else if ( cast_target == decl->kind ) {
+		return handleStruct( decl );
+	} else if ( type_name == decl->name ) {
+		assert( !type_decl );
+		type_decl = decl;
+	} else if ( exception_name == decl->name ) {
+		assert( !except_decl );
+		except_decl = decl;
+	} else if ( typeid_name == decl->name ) {
+		assert( !typeid_decl );
+		typeid_decl = decl;
+	} else if ( vtable_name == decl->name ) {
+		assert( !vtable_decl );
+		vtable_decl = decl;
+	}
+	return decl;
+}
+
+// Try to get the full definition, but raise an error on conflicts.
+const ast::FunctionDecl * getDefinition(
+		const ast::FunctionDecl * old_decl,
+		const ast::FunctionDecl * new_decl ) {
+	if ( !new_decl->stmts ) {
+		return old_decl;
+	} else if ( !old_decl->stmts ) {
+		return new_decl;
+	} else {
+		assert( !old_decl->stmts || !new_decl->stmts );
+		return nullptr;
+	}
+}
+
+const ast::DeclWithType * ConcurrentSueKeyword::postvisit(
+		const ast::FunctionDecl * decl ) {
+	if ( type_decl && isDestructorFor( decl, type_decl ) ) {
+		// Check for forward declarations, try to get the full definition.
+		dtor_decl = (dtor_decl) ? getDefinition( dtor_decl, decl ) : decl;
+	} else if ( !vtable_name.empty() && decl->has_body() ) {
+		if (const ast::DeclWithType * param = isMainFor( decl, cast_target )) {
+			if ( !vtable_decl ) {
+				SemanticError( decl, context_error );
+			}
+			// Should be safe because of isMainFor.
+			const ast::StructInstType * struct_type =
+				static_cast<const ast::StructInstType *>(
+					static_cast<const ast::ReferenceType *>(
+						param->get_type() )->base.get() );
+
+			handleMain( decl, struct_type );
+		}
+	}
+	return decl;
+}
+
+const ast::Expr * ConcurrentSueKeyword::postvisit(
+		const ast::KeywordCastExpr * expr ) {
+	if ( cast_target == expr->target ) {
+		// Convert `(thread &)ex` to `(thread$ &)*get_thread(ex)`, etc.
+		if ( !type_decl || !dtor_decl ) {
+			SemanticError( expr, context_error );
+		}
+		assert( nullptr == expr->result );
+		auto cast = ast::mutate( expr );
+		cast->result = new ast::ReferenceType( new ast::StructInstType( type_decl ) );
+		cast->concrete_target.field  = field_name;
+		cast->concrete_target.getter = getter_name;
+		return cast;
+	}
+	return expr;
+}
+
+const ast::StructDecl * ConcurrentSueKeyword::handleStruct(
+		const ast::StructDecl * decl ) {
+	assert( decl->body );
+
+	if ( !type_decl || !dtor_decl ) {
+		SemanticError( decl, context_error );
+	}
+
+	if ( !exception_name.empty() ) {
+		if( !typeid_decl || !vtable_decl ) {
+			SemanticError( decl, context_error );
+		}
+		addTypeId( decl );
+		addVtableForward( decl );
+	}
+
+	const ast::FunctionDecl * func = forwardDeclare( decl );
+	StructAndField addFieldRet = addField( decl );
+	decl = addFieldRet.decl;
+	const ast::ObjectDecl * field = addFieldRet.field;
+
+	addGetRoutines( field, func );
+	// Add routines to monitors for use by mutex stmt.
+	if ( ast::AggregateDecl::Monitor == cast_target ) {
+		addLockUnlockRoutines( decl );
+	}
+
+	return decl;
+}
+
+void ConcurrentSueKeyword::handleMain(
+		const ast::FunctionDecl * decl, const ast::StructInstType * type ) {
+	assert( vtable_decl );
+	assert( except_decl );
+
+	const CodeLocation & location = decl->location;
+
+	std::vector<ast::ptr<ast::Expr>> poly_args = {
+		new ast::TypeExpr( location, type ),
+	};
+	ast::ObjectDecl * vtable_object = Virtual::makeVtableInstance(
+		location,
+		"_default_vtable_object_declaration",
+		new ast::StructInstType( vtable_decl, copy( poly_args ) ),
+		type,
+		nullptr
+	);
+	declsToAddAfter.push_back( vtable_object );
+	declsToAddAfter.push_back(
+		new ast::ObjectDecl(
+			location,
+			Virtual::concurrentDefaultVTableName(),
+			new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
+			new ast::SingleInit( location,
+				new ast::VariableExpr( location, vtable_object ) ),
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		)
+	);
+	declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
+		location,
+		vtable_object,
+		new ast::StructInstType( except_decl, copy( poly_args ) )
+	) );
+}
+
+void ConcurrentSueKeyword::addTypeId( const ast::StructDecl * decl ) {
+	assert( typeid_decl );
+	const CodeLocation & location = decl->location;
+
+	ast::StructInstType * typeid_type =
+		new ast::StructInstType( typeid_decl, ast::CV::Const );
+	typeid_type->params.push_back(
+		new ast::TypeExpr( location, new ast::StructInstType( decl ) ) );
+	declsToAddBefore.push_back(
+		Virtual::makeTypeIdInstance( location, typeid_type ) );
+	// If the typeid_type is going to be kept, the other reference will have
+	// been made by now, but we also get to avoid extra mutates.
+	ast::ptr<ast::StructInstType> typeid_cleanup = typeid_type;
+}
+
+void ConcurrentSueKeyword::addVtableForward( const ast::StructDecl * decl ) {
+	assert( vtable_decl );
+	const CodeLocation& location = decl->location;
+
+	std::vector<ast::ptr<ast::Expr>> poly_args = {
+		new ast::TypeExpr( location, new ast::StructInstType( decl ) ),
+	};
+	declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
+		location,
+		new ast::StructInstType( vtable_decl, copy( poly_args ) ),
+		new ast::StructInstType( except_decl, copy( poly_args ) )
+	) );
+	ast::ObjectDecl * vtable_object = Virtual::makeVtableForward(
+		location,
+		"_default_vtable_object_declaration",
+		new ast::StructInstType( vtable_decl, std::move( poly_args ) )
+	);
+	declsToAddBefore.push_back( vtable_object );
+	declsToAddBefore.push_back(
+		new ast::ObjectDecl(
+			location,
+			Virtual::concurrentDefaultVTableName(),
+			new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
+			nullptr,
+			ast::Storage::Extern,
+			ast::Linkage::Cforall
+		)
+	);
+}
+
+const ast::FunctionDecl * ConcurrentSueKeyword::forwardDeclare(
+		const ast::StructDecl * decl ) {
+	const CodeLocation & location = decl->location;
+
+	ast::StructDecl * forward = ast::deepCopy( decl );
+	{
+		// If removing members makes ref-count go to zero, do not free.
+		ast::ptr<ast::StructDecl> forward_ptr = forward;
+		forward->body = false;
+		forward->members.clear();
+		forward_ptr.release();
+	}
+
+	ast::ObjectDecl * this_decl = new ast::ObjectDecl(
+		location,
+		"this",
+		new ast::ReferenceType( new ast::StructInstType( decl ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	ast::ObjectDecl * ret_decl = new ast::ObjectDecl(
+		location,
+		"ret",
+		new ast::PointerType( new ast::StructInstType( type_decl ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	ast::FunctionDecl * get_decl = new ast::FunctionDecl(
+		location,
+		getter_name,
+		{}, // forall
+		{ this_decl }, // params
+		{ ret_decl }, // returns
+		nullptr, // stmts
+		ast::Storage::Static,
+		ast::Linkage::Cforall,
+		{ new ast::Attribute( "const" ) },
+		ast::Function::Inline
+	);
+	get_decl = fixupGenerics( get_decl, decl );
+
+	ast::FunctionDecl * main_decl = nullptr;
+	if ( needs_main ) {
+		// `this_decl` is copied here because the original was used above.
+		main_decl = new ast::FunctionDecl(
+			location,
+			"main",
+			{},
+			{ ast::deepCopy( this_decl ) },
+			{},
+			nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		);
+		main_decl = fixupGenerics( main_decl, decl );
+	}
+
+	declsToAddBefore.push_back( forward );
+	if ( needs_main ) declsToAddBefore.push_back( main_decl );
+	declsToAddBefore.push_back( get_decl );
+
+	return get_decl;
+}
+
+ConcurrentSueKeyword::StructAndField ConcurrentSueKeyword::addField(
+		const ast::StructDecl * decl ) {
+	const CodeLocation & location = decl->location;
+
+	ast::ObjectDecl * field = new ast::ObjectDecl(
+		location,
+		field_name,
+		new ast::StructInstType( type_decl ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	auto mutDecl = ast::mutate( decl );
+	mutDecl->members.push_back( field );
+
+	return {mutDecl, field};
+}
+
+void ConcurrentSueKeyword::addGetRoutines(
+		const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) {
+	// Say it is generated at the "same" places as the forward declaration.
+	const CodeLocation & location = forward->location;
+
+	const ast::DeclWithType * param = forward->params.front();
+	ast::Stmt * stmt = new ast::ReturnStmt( location,
+		new ast::AddressExpr( location,
+			new ast::MemberExpr( location,
+				field,
+				new ast::CastExpr( location,
+					new ast::VariableExpr( location, param ),
+					ast::deepCopy( param->get_type()->stripReferences() ),
+					ast::ExplicitCast
+				)
+			)
+		)
+	);
+
+	ast::FunctionDecl * decl = ast::deepCopy( forward );
+	decl->stmts = new ast::CompoundStmt( location, { stmt } );
+	declsToAddAfter.push_back( decl );
+}
+
+void ConcurrentSueKeyword::addLockUnlockRoutines(
+		const ast::StructDecl * decl ) {
+	// This should only be used on monitors.
+	assert( ast::AggregateDecl::Monitor == cast_target );
+
+	const CodeLocation & location = decl->location;
+
+	// The parameter for both routines.
+	ast::ObjectDecl * this_decl = new ast::ObjectDecl(
+		location,
+		"this",
+		new ast::ReferenceType( new ast::StructInstType( decl ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
+		location,
+		"lock",
+		{ /* forall */ },
+		{
+			// Copy the declaration of this.
+			ast::deepCopy( this_decl ),
+		},
+		{ /* returns */ },
+		nullptr,
+		ast::Storage::Static,
+		ast::Linkage::Cforall,
+		{ /* attributes */ },
+		ast::Function::Inline
+	);
+	lock_decl = fixupGenerics( lock_decl, decl );
+
+	lock_decl->stmts = new ast::CompoundStmt( location, {
+		new ast::ExprStmt( location,
+			new ast::UntypedExpr( location,
+				new ast::NameExpr( location, "lock" ),
+				{
+					new ast::UntypedExpr( location,
+						new ast::NameExpr( location, "get_monitor" ),
+						{ new ast::VariableExpr( location,
+							InitTweak::getParamThis( lock_decl ) ) }
+					)
+				}
+			)
+		)
+	} );
+
+	ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
+		location,
+		"unlock",
+		{ /* forall */ },
+		{
+			// Last use, consume the declaration of this.
+			this_decl,
+		},
+		{ /* returns */ },
+		nullptr,
+		ast::Storage::Static,
+		ast::Linkage::Cforall,
+		{ /* attributes */ },
+		ast::Function::Inline
+	);
+	unlock_decl = fixupGenerics( unlock_decl, decl );
+
+	unlock_decl->stmts = new ast::CompoundStmt( location, {
+		new ast::ExprStmt( location,
+			new ast::UntypedExpr( location,
+				new ast::NameExpr( location, "unlock" ),
+				{
+					new ast::UntypedExpr( location,
+						new ast::NameExpr( location, "get_monitor" ),
+						{ new ast::VariableExpr( location,
+							InitTweak::getParamThis( unlock_decl ) ) }
+					)
+				}
+			)
+		)
+	} );
+
+	declsToAddAfter.push_back( lock_decl );
+	declsToAddAfter.push_back( unlock_decl );
+}
+
+
+// --------------------------------------------------------------------------
+struct SuspendKeyword final :
+		public ast::WithStmtsToAdd<>, public ast::WithGuards {
+	SuspendKeyword() = default;
+	virtual ~SuspendKeyword() = default;
+
+	void previsit( const ast::FunctionDecl * );
+	const ast::DeclWithType * postvisit( const ast::FunctionDecl * );
+	const ast::Stmt * postvisit( const ast::SuspendStmt * );
+
+private:
+	bool is_real_suspend( const ast::FunctionDecl * );
+
+	const ast::Stmt * make_generator_suspend( const ast::SuspendStmt * );
+	const ast::Stmt * make_coroutine_suspend( const ast::SuspendStmt * );
+
+	struct LabelPair {
+		ast::Label obj;
+		int idx;
+	};
+
+	LabelPair make_label(const ast::Stmt * stmt ) {
+		labels.push_back( ControlStruct::newLabel( "generator", stmt ) );
+		return { labels.back(), int(labels.size()) };
+	}
+
+	const ast::DeclWithType * in_generator = nullptr;
+	const ast::FunctionDecl * decl_suspend = nullptr;
+	std::vector<ast::Label> labels;
+};
+
+void SuspendKeyword::previsit( const ast::FunctionDecl * decl ) {
+	GuardValue( in_generator ); in_generator = nullptr;
+
+	// If it is the real suspend, grab it if we don't have one already.
+	if ( is_real_suspend( decl ) ) {
+		decl_suspend = decl_suspend ? decl_suspend : decl;
+		return;
+	}
+
+	// Otherwise check if this is a generator main and, if so, handle it.
+	auto param = isMainFor( decl, ast::AggregateDecl::Generator );
+	if ( !param ) return;
+
+	if ( 0 != decl->returns.size() ) {
+		SemanticError( decl->location, "Generator main must return void" );
+	}
+
+	in_generator = param;
+	GuardValue( labels ); labels.clear();
+}
+
+const ast::DeclWithType * SuspendKeyword::postvisit(
+		const ast::FunctionDecl * decl ) {
+	// Only modify a full definition of a generator with states.
+	if ( !decl->stmts || !in_generator || labels.empty() ) return decl;
+
+	const CodeLocation & location = decl->location;
+
+	// Create a new function body:
+	// static void * __generator_labels[] = {&&s0, &&s1, ...};
+	// void * __generator_label = __generator_labels[GEN.__generator_state];
+	// goto * __generator_label;
+	// s0: ;
+	// OLD_BODY
+
+	// This is the null statement inserted right before the body.
+	ast::NullStmt * noop = new ast::NullStmt( location );
+	noop->labels.push_back( ControlStruct::newLabel( "generator", noop ) );
+	const ast::Label & first_label = noop->labels.back();
+
+	// Add each label to the init, starting with the first label.
+	std::vector<ast::ptr<ast::Init>> inits = {
+		new ast::SingleInit( location,
+			new ast::LabelAddressExpr( location, copy( first_label ) ) ) };
+	// Then go through all the stored labels, and clear the store.
+	for ( auto && label : labels ) {
+		inits.push_back( new ast::SingleInit( label.location,
+			new ast::LabelAddressExpr( label.location, std::move( label )
+			) ) );
+	}
+	labels.clear();
+	// Then construct the initializer itself.
+	auto init = new ast::ListInit( location, std::move( inits ) );
+
+	ast::ObjectDecl * generatorLabels = new ast::ObjectDecl(
+		location,
+		"__generator_labels",
+		new ast::ArrayType(
+			new ast::PointerType( new ast::VoidType() ),
+			nullptr,
+			ast::FixedLen,
+			ast::DynamicDim
+		),
+		init,
+		ast::Storage::Classes(),
+		ast::Linkage::AutoGen
+	);
+
+	ast::ObjectDecl * generatorLabel = new ast::ObjectDecl(
+		location,
+		"__generator_label",
+		new ast::PointerType( new ast::VoidType() ),
+		new ast::SingleInit( location,
+			new ast::UntypedExpr( location,
+				new ast::NameExpr( location, "?[?]" ),
+				{
+					// TODO: Could be a variable expr.
+					new ast::NameExpr( location, "__generator_labels" ),
+					new ast::UntypedMemberExpr( location,
+						new ast::NameExpr( location, "__generator_state" ),
+						new ast::VariableExpr( location, in_generator )
+					)
+				}
+			)
+		),
+		ast::Storage::Classes(),
+		ast::Linkage::AutoGen
+	);
+
+	ast::BranchStmt * theGoTo = new ast::BranchStmt(
+		location, new ast::VariableExpr( location, generatorLabel )
+	);
+
+	// The noop goes here in order.
+
+	ast::CompoundStmt * body = new ast::CompoundStmt( location, {
+		{ new ast::DeclStmt( location, generatorLabels ) },
+		{ new ast::DeclStmt( location, generatorLabel ) },
+		{ theGoTo },
+		{ noop },
+		{ decl->stmts },
+	} );
+
+	auto mutDecl = ast::mutate( decl );
+	mutDecl->stmts = body;
+	return mutDecl;
+}
+
+const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) {
+	switch ( stmt->type ) {
+	case ast::SuspendStmt::None:
+		// Use the context to determain the implicit target.
+		if ( in_generator ) {
+			return make_generator_suspend( stmt );
+		} else {
+			return make_coroutine_suspend( stmt );
+		}
+	case ast::SuspendStmt::Coroutine:
+		return make_coroutine_suspend( stmt );
+	case ast::SuspendStmt::Generator:
+		// Generator suspends must be directly in a generator.
+		if ( !in_generator ) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type." );
+		return make_generator_suspend( stmt );
+	}
+	assert( false );
+	return stmt;
+}
+
+/// Find the real/official suspend declaration.
+bool SuspendKeyword::is_real_suspend( const ast::FunctionDecl * decl ) {
+	return ( !decl->linkage.is_mangled
+		&& 0 == decl->params.size()
+		&& 0 == decl->returns.size()
+		&& "__cfactx_suspend" == decl->name );
+}
+
+const ast::Stmt * SuspendKeyword::make_generator_suspend(
+		const ast::SuspendStmt * stmt ) {
+	assert( in_generator );
+	// Target code is:
+	//   GEN.__generator_state = X;
+	//   THEN
+	//   return;
+	//   __gen_X:;
+
+	const CodeLocation & location = stmt->location;
+
+	LabelPair label = make_label( stmt );
+
+	// This is the context saving statement.
+	stmtsToAddBefore.push_back( new ast::ExprStmt( location,
+		new ast::UntypedExpr( location,
+			new ast::NameExpr( location, "?=?" ),
+			{
+				new ast::UntypedMemberExpr( location,
+					new ast::NameExpr( location, "__generator_state" ),
+					new ast::VariableExpr( location, in_generator )
+				),
+				ast::ConstantExpr::from_int( location, label.idx ),
+			}
+		)
+	) );
+
+	// The THEN component is conditional (return is not).
+	if ( stmt->then ) {
+		stmtsToAddBefore.push_back( stmt->then.get() );
+	}
+	stmtsToAddBefore.push_back( new ast::ReturnStmt( location, nullptr ) );
+
+	// The null statement replaces the old suspend statement.
+	return new ast::NullStmt( location, { label.obj } );
+}
+
+const ast::Stmt * SuspendKeyword::make_coroutine_suspend(
+		const ast::SuspendStmt * stmt ) {
+	// The only thing we need from the old statement is the location.
+	const CodeLocation & location = stmt->location;
+
+	if ( !decl_suspend ) {
+		SemanticError( location, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n" );
+	}
+	if ( stmt->then ) {
+		SemanticError( location, "Compound statement following coroutines is not implemented." );
+	}
+
+	return new ast::ExprStmt( location,
+		new ast::UntypedExpr( location,
+			ast::VariableExpr::functionPointer( location, decl_suspend ) )
+	);
+}
+
+// --------------------------------------------------------------------------
+struct MutexKeyword final : public ast::WithDeclsToAdd<> {
 	const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
 	void postvisit( const ast::StructDecl * decl );
@@ -50,5 +891,6 @@
 	ast::CompoundStmt * addStatements( const ast::CompoundStmt * body, const std::vector<ast::ptr<ast::Expr>> & args );
 	ast::CompoundStmt * addThreadDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt * body, const std::vector<const ast::DeclWithType *> & args );
-
+	ast::ExprStmt * genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param);
+	ast::IfStmt * genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam );
 private:
 	const ast::StructDecl * monitor_decl = nullptr;
@@ -59,4 +901,6 @@
 
 	static ast::ptr<ast::Type> generic_func;
+
+	UniqueName mutex_func_namer = UniqueName("__lock_unlock_curr");
 };
 
@@ -160,8 +1004,11 @@
 
 const ast::Stmt * MutexKeyword::postvisit( const ast::MutexStmt * stmt ) {
+	if ( !lock_guard_decl ) {
+		SemanticError( stmt->location, "mutex stmt requires a header, add #include <mutex_stmt.hfa>\n" );
+	}
 	ast::CompoundStmt * body =
 			new ast::CompoundStmt( stmt->location, { stmt->stmt } );
-	addStatements( body, stmt->mutexObjs );
-	return body;
+	
+	return addStatements( body, stmt->mutexObjs );;
 }
 
@@ -251,5 +1098,5 @@
 				{
 					new ast::SingleInit( location,
-						new ast::AddressExpr(
+						new ast::AddressExpr( location,
 							new ast::VariableExpr( location, monitor ) ) ),
 					new ast::SingleInit( location,
@@ -358,11 +1205,71 @@
 }
 
+// generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it
+// used to undo the type erasure done by storing all the lock pointers as void 
+ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) {
+	return new ast::ExprStmt( location,
+		new ast::UntypedExpr( location,
+			new ast::NameExpr( location, fnName ), {
+				ast::UntypedExpr::createDeref(
+					location,
+					new ast::CastExpr( location, 
+						param,
+						new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr(
+							expr->location,
+							new ast::NameExpr( expr->location, "__get_mutexstmt_lock_type" ),
+							{ expr }
+						) ) ),
+						ast::GeneratedFlag::ExplicitCast
+					)
+				)
+			}
+		)
+	);
+}
+
+ast::IfStmt * MutexKeyword::genTypeDiscrimLockUnlock( const std::string & fnName, const std::vector<ast::ptr<ast::Expr>> & args, const CodeLocation & location, ast::UntypedExpr * thisParam ) {
+	ast::IfStmt * outerLockIf = nullptr;
+	ast::IfStmt * lastLockIf = nullptr;
+
+	//adds an if/elif clause for each lock to assign type from void ptr based on ptr address
+	for ( long unsigned int i = 0; i < args.size(); i++ ) {
+		
+		ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
+			new ast::NameExpr( location, "?==?" ), {
+				ast::deepCopy( thisParam ),
+				new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() ))
+			}
+		);
+
+		ast::IfStmt * currLockIf = new ast::IfStmt( 
+			location,
+			ifCond,
+			genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) )
+		);
+		
+		if ( i == 0 ) {
+			outerLockIf = currLockIf;
+		} else {
+			// add ifstmt to else of previous stmt
+			lastLockIf->else_ = currLockIf;
+		}
+
+		lastLockIf = currLockIf;
+	}
+	return outerLockIf;
+}
+
 ast::CompoundStmt * MutexKeyword::addStatements(
 		const ast::CompoundStmt * body,
 		const std::vector<ast::ptr<ast::Expr>> & args ) {
-	ast::CompoundStmt * mutBody = ast::mutate( body );
 
 	// Code is generated near the beginning of the compound statement.
-	const CodeLocation & location = mutBody->location;
+	const CodeLocation & location = body->location;
+
+		// final body to return
+	ast::CompoundStmt * newBody = new ast::CompoundStmt( location );
+
+	// std::string lockFnName = mutex_func_namer.newName();
+	// std::string unlockFnName = mutex_func_namer.newName();
 
 	// Make pointer to the monitors.
@@ -372,11 +1279,5 @@
 		new ast::ArrayType(
 			new ast::PointerType(
-				new ast::TypeofType(
-					new ast::UntypedExpr(
-						location,
-						new ast::NameExpr( location, "__get_type" ),
-						{ args.front() }
-					)
-				)
+				new ast::VoidType()
 			),
 			ast::ConstantExpr::from_ulong( location, args.size() ),
@@ -392,5 +1293,5 @@
 						new ast::UntypedExpr(
 							expr->location,
-							new ast::NameExpr( expr->location, "__get_ptr" ),
+							new ast::NameExpr( expr->location, "__get_mutexstmt_lock_ptr" ),
 							{ expr }
 						)
@@ -405,20 +1306,53 @@
 	ast::StructInstType * lock_guard_struct =
 			new ast::StructInstType( lock_guard_decl );
-	ast::TypeExpr * lock_type_expr = new ast::TypeExpr(
-		location,
-		new ast::TypeofType(
-			new ast::UntypedExpr(
-				location,
-				new ast::NameExpr( location, "__get_type" ),
-				{ args.front() }
-			)
-		)
-	);
-
-	lock_guard_struct->params.push_back( lock_type_expr );
-
-	// In reverse order:
+
+	// use try stmts to lock and finally to unlock
+	ast::TryStmt * outerTry = nullptr;
+	ast::TryStmt * currentTry;
+	ast::CompoundStmt * lastBody = nullptr;
+
+	// adds a nested try stmt for each lock we are locking
+	for ( long unsigned int i = 0; i < args.size(); i++ ) {
+		ast::UntypedExpr * innerAccess = new ast::UntypedExpr( 
+			location,
+			new ast::NameExpr( location,"?[?]" ), {
+				new ast::NameExpr( location, "__monitors" ),
+				ast::ConstantExpr::from_int( location, i )
+			}
+		);
+
+		// make the try body
+		ast::CompoundStmt * currTryBody = new ast::CompoundStmt( location );
+		ast::IfStmt * lockCall = genTypeDiscrimLockUnlock( "lock", args, location, innerAccess );
+		currTryBody->push_back( lockCall );
+
+		// make the finally stmt
+		ast::CompoundStmt * currFinallyBody = new ast::CompoundStmt( location );
+		ast::IfStmt * unlockCall = genTypeDiscrimLockUnlock( "unlock", args, location, innerAccess );
+		currFinallyBody->push_back( unlockCall );
+
+		// construct the current try
+		currentTry = new ast::TryStmt( 
+			location, 
+			currTryBody, 
+			{}, 
+			new ast::FinallyStmt( location, currFinallyBody )
+		);
+		if ( i == 0 ) outerTry = currentTry;
+		else {
+			// pushback try into the body of the outer try
+			lastBody->push_back( currentTry );
+		}
+		lastBody = currTryBody;
+	}
+
+	// push body into innermost try body
+	if ( lastBody != nullptr ) {
+		lastBody->push_back( body );
+		newBody->push_front( outerTry );
+	}	
+
 	// monitor_guard_t __guard = { __monitors, # };
-	mutBody->push_front(
+	newBody->push_front(
 		new ast::DeclStmt(
 			location,
@@ -447,7 +1381,100 @@
 
 	// monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
-	mutBody->push_front( new ast::DeclStmt( location, monitors ) );
-
-	return mutBody;
+	newBody->push_front( new ast::DeclStmt( location, monitors ) );
+
+	// // The parameter for both __lock_curr/__unlock_curr routines.
+	// ast::ObjectDecl * this_decl = new ast::ObjectDecl(
+	// 	location,
+	// 	"this",
+	// 	new ast::PointerType( new ast::VoidType() ),
+	// 	nullptr,
+	// 	{},
+	// 	ast::Linkage::Cforall
+	// );
+
+	// ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
+	// 	location,
+	// 	lockFnName,
+	// 	{ /* forall */ },
+	// 	{
+	// 		// Copy the declaration of this.
+	// 		this_decl,
+	// 	},
+	// 	{ /* returns */ },
+	// 	nullptr,
+	// 	0,
+	// 	ast::Linkage::Cforall,
+	// 	{ /* attributes */ },
+	// 	ast::Function::Inline
+	// );
+
+	// ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
+	// 	location,
+	// 	unlockFnName,
+	// 	{ /* forall */ },
+	// 	{
+	// 		// Copy the declaration of this.
+	// 		ast::deepCopy( this_decl ),
+	// 	},
+	// 	{ /* returns */ },
+	// 	nullptr,
+	// 	0,
+	// 	ast::Linkage::Cforall,
+	// 	{ /* attributes */ },
+	// 	ast::Function::Inline
+	// );
+
+	// ast::IfStmt * outerLockIf = nullptr;
+	// ast::IfStmt * outerUnlockIf = nullptr;
+	// ast::IfStmt * lastLockIf = nullptr;
+	// ast::IfStmt * lastUnlockIf = nullptr;
+
+	// //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
+	// for ( long unsigned int i = 0; i < args.size(); i++ ) {
+	// 	ast::VariableExpr * thisParam = new ast::VariableExpr( location, InitTweak::getParamThis( lock_decl ) );
+	// 	ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
+	// 		new ast::NameExpr( location, "?==?" ), {
+	// 			thisParam,
+	// 			new ast::CastExpr( location, new ast::AddressExpr( location, args.at(i) ), new ast::PointerType( new ast::VoidType() ))
+	// 		}
+	// 	);
+
+	// 	ast::IfStmt * currLockIf = new ast::IfStmt( 
+	// 		location,
+	// 		ast::deepCopy( ifCond ),
+	// 		genVirtLockUnlockExpr( "lock", args.at(i), location, ast::deepCopy( thisParam ) )
+	// 	);
+
+	// 	ast::IfStmt * currUnlockIf = new ast::IfStmt( 
+	// 		location,
+	// 		ifCond,
+	// 		genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) )
+	// 	);
+		
+	// 	if ( i == 0 ) {
+	// 		outerLockIf = currLockIf;
+	// 		outerUnlockIf = currUnlockIf;
+	// 	} else {
+	// 		// add ifstmt to else of previous stmt
+	// 		lastLockIf->else_ = currLockIf;
+	// 		lastUnlockIf->else_ = currUnlockIf;
+	// 	}
+
+	// 	lastLockIf = currLockIf;
+	// 	lastUnlockIf = currUnlockIf;
+	// }
+	
+	// // add pointer typing if/elifs to body of routines
+	// lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } );
+	// unlock_decl->stmts = new ast::CompoundStmt( location, { outerUnlockIf } );
+
+	// // add routines to scope
+	// declsToAddBefore.push_back( lock_decl );
+	// declsToAddBefore.push_back( unlock_decl );
+
+	// newBody->push_front(new ast::DeclStmt( location, lock_decl ));
+	// newBody->push_front(new ast::DeclStmt( location, unlock_decl ));
+
+	return newBody;
 }
 
@@ -564,8 +1591,12 @@
 
 // --------------------------------------------------------------------------
+// Interface Functions:
 
 void implementKeywords( ast::TranslationUnit & translationUnit ) {
-	(void)translationUnit;
-	assertf(false, "Apply Keywords not implemented." );
+	ast::Pass<ThreadKeyword>::run( translationUnit );
+	ast::Pass<CoroutineKeyword>::run( translationUnit );
+	ast::Pass<MonitorKeyword>::run( translationUnit );
+	ast::Pass<GeneratorKeyword>::run( translationUnit );
+	ast::Pass<SuspendKeyword>::run( translationUnit );
 }
 
Index: src/ControlStruct/ExceptTranslateNew.cpp
===================================================================
--- src/ControlStruct/ExceptTranslateNew.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ControlStruct/ExceptTranslateNew.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -9,7 +9,7 @@
 // Author           : Andrew Beach
 // Created On       : Mon Nov  8 11:53:00 2021
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Jan 31 18:49:58 2022
-// Update Count     : 1
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Mar 11 17:51:00 2022
+// Update Count     : 2
 //
 
@@ -27,17 +27,4 @@
 
 	typedef std::list<ast::CatchStmt*> CatchList;
-
-	void split( CatchList& allHandlers, CatchList& terHandlers,
-				CatchList& resHandlers ) {
-		while ( !allHandlers.empty() ) {
-			ast::CatchStmt * stmt = allHandlers.front();
-			allHandlers.pop_front();
-			if (stmt->kind == ast::ExceptionKind::Terminate) {
-				terHandlers.push_back(stmt);
-			} else {
-				resHandlers.push_back(stmt);
-			}
-		}
-	}
 
 	void appendDeclStmt( ast::CompoundStmt * block, ast::DeclWithType * item ) {
@@ -171,21 +158,20 @@
 	ast::Stmt * create_resume_rethrow( const ast::ThrowStmt * throwStmt );
 
-	// Types used in translation, make sure to use clone.
+	// Types used in translation, first group are internal.
+	ast::ObjectDecl * make_index_object( CodeLocation const & ) const;
+	ast::ObjectDecl * make_exception_object( CodeLocation const & ) const;
+	ast::ObjectDecl * make_bool_object( CodeLocation const & ) const;
+	ast::ObjectDecl * make_voidptr_object( CodeLocation const & ) const;
+	ast::ObjectDecl * make_unused_index_object( CodeLocation const & ) const;
 	// void (*function)();
-	ast::FunctionDecl * try_func_t;
+	ast::FunctionDecl * make_try_function( CodeLocation const & ) const;
 	// void (*function)(int, exception);
-	ast::FunctionDecl * catch_func_t;
+	ast::FunctionDecl * make_catch_function( CodeLocation const & ) const;
 	// int (*function)(exception);
-	ast::FunctionDecl * match_func_t;
+	ast::FunctionDecl * make_match_function( CodeLocation const & ) const;
 	// bool (*function)(exception);
-	ast::FunctionDecl * handle_func_t;
+	ast::FunctionDecl * make_handle_function( CodeLocation const & ) const;
 	// void (*function)(__attribute__((unused)) void *);
-	ast::FunctionDecl * finally_func_t;
-
-	ast::StructInstType * create_except_type() {
-		assert( except_decl );
-		return new ast::StructInstType( except_decl );
-	}
-	void init_func_types();
+	ast::FunctionDecl * make_finally_function( CodeLocation const & ) const;
 
 public:
@@ -199,22 +185,35 @@
 };
 
-void TryMutatorCore::init_func_types() {
+ast::ObjectDecl * TryMutatorCore::make_index_object(
+		CodeLocation const & location ) const {
+	return new ast::ObjectDecl(
+		location,
+		"__handler_index",
+		new ast::BasicType(ast::BasicType::SignedInt),
+		nullptr, //init
+		ast::Storage::Classes{},
+		ast::Linkage::Cforall
+		);
+}
+
+ast::ObjectDecl * TryMutatorCore::make_exception_object(
+		CodeLocation const & location ) const {
 	assert( except_decl );
-
-	ast::ObjectDecl index_obj(
-		{},
-		"__handler_index",
-		new ast::BasicType(ast::BasicType::SignedInt)
-		);
-	ast::ObjectDecl exception_obj(
-		{},
+	return new ast::ObjectDecl(
+		location,
 		"__exception_inst",
 		new ast::PointerType(
 			new ast::StructInstType( except_decl )
 			),
-		NULL
-		);
-	ast::ObjectDecl bool_obj(
-		{},
+		nullptr, //init
+		ast::Storage::Classes{},
+		ast::Linkage::Cforall
+		);
+}
+
+ast::ObjectDecl * TryMutatorCore::make_bool_object(
+		CodeLocation const & location ) const {
+	return new ast::ObjectDecl(
+		location,
 		"__ret_bool",
 		new ast::BasicType( ast::BasicType::Bool ),
@@ -225,6 +224,10 @@
 		std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
 		);
-	ast::ObjectDecl voidptr_obj(
-		{},
+}
+
+ast::ObjectDecl * TryMutatorCore::make_voidptr_object(
+		CodeLocation const & location ) const {
+	return new ast::ObjectDecl(
+		location,
 		"__hook",
 		new ast::PointerType(
@@ -237,7 +240,10 @@
 		std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
 		);
-
-	ast::ObjectDecl unused_index_obj(
-		{},
+}
+
+ast::ObjectDecl * TryMutatorCore::make_unused_index_object(
+		CodeLocation const & location ) const {
+	return new ast::ObjectDecl(
+		location,
 		"__handler_index",
 		new ast::BasicType(ast::BasicType::SignedInt),
@@ -248,8 +254,10 @@
 		std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
 	);
-	//unused_index_obj->attributes.push_back( new Attribute( "unused" ) );
-
-	try_func_t = new ast::FunctionDecl(
-		{},
+}
+
+ast::FunctionDecl * TryMutatorCore::make_try_function(
+		CodeLocation const & location ) const {
+	return new ast::FunctionDecl(
+		location,
 		"try",
 		{}, //forall
@@ -260,10 +268,13 @@
 		ast::Linkage::Cforall
 	);
-
-	catch_func_t = new ast::FunctionDecl(
-		{},
+}
+
+ast::FunctionDecl * TryMutatorCore::make_catch_function(
+		CodeLocation const & location ) const {
+	return new ast::FunctionDecl(
+		location,
 		"catch",
 		{}, //forall
-		{ast::deepCopy(&index_obj), ast::deepCopy(&exception_obj)},//param
+		{ make_index_object( location ), make_exception_object( location ) },
 		{}, //return void
 		nullptr,
@@ -271,32 +282,41 @@
 		ast::Linkage::Cforall
 	);
-
-	match_func_t = new ast::FunctionDecl(
-		{},
+}
+
+ast::FunctionDecl * TryMutatorCore::make_match_function(
+		CodeLocation const & location ) const {
+	return new ast::FunctionDecl(
+		location,
 		"match",
 		{}, //forall
-		{ast::deepCopy(&exception_obj)},
-		{ast::deepCopy(&unused_index_obj)},
+		{ make_exception_object( location ) },
+		{ make_unused_index_object( location ) },
 		nullptr,
 		ast::Storage::Classes{},
 		ast::Linkage::Cforall
 	);
-
-	handle_func_t = new ast::FunctionDecl(
-		{},
+}
+
+ast::FunctionDecl * TryMutatorCore::make_handle_function(
+		CodeLocation const & location ) const {
+	return new ast::FunctionDecl(
+		location,
 		"handle",
 		{}, //forall
-		{ast::deepCopy(&exception_obj)},
-		{ast::deepCopy(&bool_obj)},
+		{ make_exception_object( location ) },
+		{ make_bool_object( location ) },
 		nullptr,
 		ast::Storage::Classes{},
 		ast::Linkage::Cforall
 	);
-
-	finally_func_t = new ast::FunctionDecl(
-		{},
+}
+
+ast::FunctionDecl * TryMutatorCore::make_finally_function(
+		CodeLocation const & location ) const {
+	return new ast::FunctionDecl(
+		location,
 		"finally",
 		{}, //forall
-		{ast::deepCopy(&voidptr_obj)},
+		{ make_voidptr_object( location ) },
 		{}, //return void
 		nullptr,
@@ -304,28 +324,12 @@
 		ast::Linkage::Cforall
 	);
-
-	//catch_func_t.get_parameters().push_back( index_obj.clone() );
-	//catch_func_t.get_parameters().push_back( exception_obj.clone() );
-	//match_func_t.get_returnVals().push_back( unused_index_obj );
-	//match_func_t.get_parameters().push_back( exception_obj.clone() );
-	//handle_func_t.get_returnVals().push_back( bool_obj.clone() );
-	//handle_func_t.get_parameters().push_back( exception_obj.clone() );
-	//finally_func_t.get_parameters().push_back( voidptr_obj.clone() );
 }
 
 // TryStmt Mutation Helpers
-
-/*
-ast::CompoundStmt * TryMutatorCore::take_try_block( ast::TryStmt *tryStmt ) {
-	ast::CompoundStmt * block = tryStmt->body;
-	tryStmt->body = nullptr;
-	return block;
-}
-*/
 
 ast::FunctionDecl * TryMutatorCore::create_try_wrapper(
 		const ast::CompoundStmt *body ) {
 
-	ast::FunctionDecl * ret = ast::deepCopy(try_func_t);
+	ast::FunctionDecl * ret = make_try_function( body->location );
 	ret->stmts = body;
 	return ret;
@@ -339,5 +343,5 @@
 	const CodeLocation loc = handlers.front()->location;
 
-	ast::FunctionDecl * func_t = ast::deepCopy(catch_func_t);
+	ast::FunctionDecl * func_t = make_catch_function( loc );
 	const ast::DeclWithType * index_obj = func_t->params.front();
 	const ast::DeclWithType * except_obj = func_t->params.back();
@@ -386,5 +390,5 @@
 		// handler->body = nullptr;
 
-		handler_wrappers.push_back( new ast::CaseStmt(loc, 
+		handler_wrappers.push_back( new ast::CaseStmt(loc,
 			ast::ConstantExpr::from_int(loc, index) ,
 			{ block, new ast::ReturnStmt( loc, nullptr ) }
@@ -393,18 +397,9 @@
 	// TODO: Some sort of meaningful error on default perhaps?
 
-	/*
-	std::list<Statement*> stmt_handlers;
-	while ( !handler_wrappers.empty() ) {
-		stmt_handlers.push_back( handler_wrappers.front() );
-		handler_wrappers.pop_front();
-	}
-	*/
-
-	ast::SwitchStmt * handler_lookup = new ast::SwitchStmt(loc, 
+	ast::SwitchStmt * handler_lookup = new ast::SwitchStmt( loc,
 		new ast::VariableExpr( loc, index_obj ),
 		std::move(handler_wrappers)
 		);
-	ast::CompoundStmt * body = new ast::CompoundStmt(loc, 
-		{handler_lookup});
+	ast::CompoundStmt * body = new ast::CompoundStmt( loc, {handler_lookup} );
 
 	func_t->stmts = body;
@@ -433,5 +428,5 @@
 
 	// Check for type match.
-	ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc, 
+	ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
 		new ast::VariableExpr(loc, except_obj ),
 		local_except->get_type()
@@ -445,12 +440,7 @@
 	}
 	// Construct the match condition.
-	block->push_back( new ast::IfStmt(loc, 
+	block->push_back( new ast::IfStmt(loc,
 		cond, modded_handler->body, nullptr ) );
 
-	// xxx - how does this work in new ast
-	//modded_handler->set_decl( nullptr );
-	//modded_handler->set_cond( nullptr );
-	//modded_handler->set_body( nullptr );
-	//delete modded_handler;
 	return block;
 }
@@ -467,5 +457,5 @@
 	ast::CompoundStmt * body = new ast::CompoundStmt(loc);
 
-	ast::FunctionDecl * func_t = ast::deepCopy(match_func_t);
+	ast::FunctionDecl * func_t = make_match_function( loc );
 	const ast::DeclWithType * except_obj = func_t->params.back();
 
@@ -490,5 +480,5 @@
 	}
 
-	body->push_back( new ast::ReturnStmt(loc, 
+	body->push_back( new ast::ReturnStmt(loc,
 		ast::ConstantExpr::from_int( loc, 0 ) ));
 
@@ -525,5 +515,5 @@
 	ast::CompoundStmt * body = new ast::CompoundStmt(loc);
 
-	ast::FunctionDecl * func_t = ast::deepCopy(handle_func_t);
+	ast::FunctionDecl * func_t = make_handle_function( loc );
 	const ast::DeclWithType * except_obj = func_t->params.back();
 
@@ -535,6 +525,6 @@
 		ast::CompoundStmt * handling_code;
 		if (handler->body.as<ast::CompoundStmt>()) {
-			handling_code = 
-			strict_dynamic_cast<ast::CompoundStmt*>( handler->body.get_and_mutate() );
+			handling_code = strict_dynamic_cast<ast::CompoundStmt*>(
+				handler->body.get_and_mutate() );
 		} else {
 			handling_code = new ast::CompoundStmt(loc);
@@ -600,11 +590,8 @@
 	const ast::CompoundStmt * body = finally->body;
 
-	ast::FunctionDecl * func_t = ast::deepCopy(finally_func_t);
+	ast::FunctionDecl * func_t = make_finally_function( tryStmt->location );
 	func_t->stmts = body;
 
-	// finally->set_block( nullptr );
-	// delete finally;
 	tryStmt->finally = nullptr;
-
 
 	return func_t;
@@ -617,14 +604,4 @@
 
 	const CodeLocation loc = finally_wrapper->location;
-	// Make Cleanup Attribute.
-	/*
-	std::list< ast::Attribute * > attributes;
-	{
-		std::list<  > attr_params;
-		attr_params.push_back( nameOf( finally_wrapper ) );
-		attributes.push_back( new Attribute( "cleanup", attr_params ) );
-	}
-	*/
-
 	return new ast::ObjectDecl(
 		loc,
@@ -644,9 +621,8 @@
 	// return false;
 	const CodeLocation loc = throwStmt->location;
-	ast::Stmt * result = new ast::ReturnStmt(loc, 
+	ast::Stmt * result = new ast::ReturnStmt(loc,
 		ast::ConstantExpr::from_bool( loc, false )
 		);
 	result->labels = throwStmt->labels;
-	// delete throwStmt; done by postvisit
 	return result;
 }
@@ -660,5 +636,4 @@
 		assert( nullptr == except_decl );
 		except_decl = structDecl;
-		init_func_types();
 	} else if ( structDecl->name == "__cfaehm_try_resume_node" ) {
 		assert( nullptr == node_decl );
@@ -706,6 +681,4 @@
 		}
 	}
-	// split( mutStmt->handlers,
-	//		termination_handlers, resumption_handlers );
 
 	if ( resumption_handlers.size() ) {
Index: src/InitTweak/FixGlobalInit.cc
===================================================================
--- src/InitTweak/FixGlobalInit.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/InitTweak/FixGlobalInit.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -113,9 +113,15 @@
 		accept_all(translationUnit, fixer);
 
+		// Say these magic declarations come at the end of the file.
+		CodeLocation const & location = translationUnit.decls.back()->location;
+
 		if ( !fixer.core.initStmts.empty() ) {
 			std::vector<ast::ptr<ast::Expr>> ctorParams;
-			if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int({}, 200));
-			auto initFunction = new ast::FunctionDecl({}, "__global_init__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.initStmts)), 
-				ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("constructor", std::move(ctorParams))});
+			if (inLibrary) ctorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
+			auto initFunction = new ast::FunctionDecl(location,
+				"__global_init__", {}, {}, {},
+				new ast::CompoundStmt(location, std::move(fixer.core.initStmts)),
+				ast::Storage::Static, ast::Linkage::C,
+				{new ast::Attribute("constructor", std::move(ctorParams))});
 
 			translationUnit.decls.emplace_back( initFunction );
@@ -124,7 +130,10 @@
 		if ( !fixer.core.destroyStmts.empty() ) {
 			std::vector<ast::ptr<ast::Expr>> dtorParams;
-			if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int({}, 200));
-			auto destroyFunction = new ast::FunctionDecl({}, "__global_destroy__", {}, {}, {}, new ast::CompoundStmt({}, std::move(fixer.core.destroyStmts)), 
-				ast::Storage::Static, ast::Linkage::C, {new ast::Attribute("destructor", std::move(dtorParams))});
+			if (inLibrary) dtorParams.emplace_back(ast::ConstantExpr::from_int(location, 200));
+			auto destroyFunction = new ast::FunctionDecl( location,
+				"__global_destroy__", {}, {}, {},
+				new ast::CompoundStmt(location, std::move(fixer.core.destroyStmts)),
+				ast::Storage::Static, ast::Linkage::C,
+				{new ast::Attribute("destructor", std::move(dtorParams))});
 
 			translationUnit.decls.emplace_back(destroyFunction);
Index: src/InitTweak/FixInitNew.cpp
===================================================================
--- src/InitTweak/FixInitNew.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/InitTweak/FixInitNew.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -16,4 +16,5 @@
 #include "CodeGen/GenType.h"           // for genPrettyType
 #include "CodeGen/OperatorTable.h"
+#include "Common/CodeLocationTools.hpp"
 #include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
 #include "Common/SemanticError.h"      // for SemanticError
@@ -85,5 +86,5 @@
 	/// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
 	/// arguments and return value temporaries
-	struct ResolveCopyCtors final : public ast::WithGuards, public ast::WithStmtsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithVisitorRef<ResolveCopyCtors> {
+	struct ResolveCopyCtors final : public ast::WithGuards, public ast::WithStmtsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithVisitorRef<ResolveCopyCtors>, public ast::WithConstTranslationUnit {
 		const ast::Expr * postvisit( const ast::ImplicitCopyCtorExpr * impCpCtorExpr );
 		const ast::StmtExpr * previsit( const ast::StmtExpr * stmtExpr );
@@ -189,5 +190,5 @@
 	/// for any member that is missing a corresponding ctor/dtor call.
 	/// error if a member is used before constructed
-	struct GenStructMemberCalls final : public ast::WithGuards, public ast::WithShortCircuiting, public ast::WithSymbolTable, public ast::WithVisitorRef<GenStructMemberCalls> {
+	struct GenStructMemberCalls final : public ast::WithGuards, public ast::WithShortCircuiting, public ast::WithSymbolTable, public ast::WithVisitorRef<GenStructMemberCalls>, public ast::WithConstTranslationUnit {
 		void previsit( const ast::FunctionDecl * funcDecl );
 		const ast::DeclWithType * postvisit( const ast::FunctionDecl * funcDecl );
@@ -214,5 +215,5 @@
 
 	/// expands ConstructorExpr nodes into comma expressions, using a temporary for the first argument
-	struct FixCtorExprs final : public ast::WithDeclsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting {
+	struct FixCtorExprs final : public ast::WithDeclsToAdd<>, public ast::WithSymbolTable, public ast::WithShortCircuiting, public ast::WithConstTranslationUnit {
 		const ast::Expr * postvisit( const ast::ConstructorExpr * ctorExpr );
 	};
@@ -509,5 +510,5 @@
 		// (VariableExpr and already resolved expression)
 		CP_CTOR_PRINT( std::cerr << "ResolvingCtorDtor " << untyped << std::endl; )
-		ast::ptr<ast::Expr> resolved = ResolvExpr::findVoidExpression(untyped, symtab);
+		ast::ptr<ast::Expr> resolved = ResolvExpr::findVoidExpression(untyped, { symtab, transUnit().global } );
 		assert( resolved );
 		if ( resolved->env ) {
@@ -553,5 +554,5 @@
 		ast::ptr<ast::Expr> guard = mutArg;
 
-		ast::ptr<ast::ObjectDecl> tmp = new ast::ObjectDecl({}, "__tmp", mutResult, nullptr );
+		ast::ptr<ast::ObjectDecl> tmp = new ast::ObjectDecl(loc, "__tmp", mutResult, nullptr );
 
 		// create and resolve copy constructor
@@ -587,11 +588,12 @@
 
 	ast::Expr * ResolveCopyCtors::destructRet( const ast::ObjectDecl * ret, const ast::Expr * arg ) {
+		auto global = transUnit().global;
 		// TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
 		// check for existing cleanup attribute before adding another(?)
 		// need to add __Destructor for _tmp_cp variables as well
 
-		assertf( ast::dtorStruct, "Destructor generation requires __Destructor definition." );
-		assertf( ast::dtorStruct->members.size() == 2, "__Destructor definition does not have expected fields." );
-		assertf( ast::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." );
+		assertf( global.dtorStruct, "Destructor generation requires __Destructor definition." );
+		assertf( global.dtorStruct->members.size() == 2, "__Destructor definition does not have expected fields." );
+		assertf( global.dtorDestroy, "Destructor generation requires __destroy_Destructor." );
 
 		const CodeLocation loc = ret->location;
@@ -610,5 +612,5 @@
 		auto dtorFunc = getDtorFunc( ret, new ast::ExprStmt(loc, dtor ), stmtsToAddBefore );
 
-		auto dtorStructType = new ast::StructInstType(ast::dtorStruct);
+		auto dtorStructType = new ast::StructInstType( global.dtorStruct );
 
 		// what does this do???
@@ -622,9 +624,9 @@
 		static UniqueName namer( "_ret_dtor" );
 		auto retDtor = new ast::ObjectDecl(loc, namer.newName(), dtorStructType, new ast::ListInit(loc, { new ast::SingleInit(loc, ast::ConstantExpr::null(loc) ), new ast::SingleInit(loc, new ast::CastExpr( new ast::VariableExpr(loc, dtorFunc ), dtorType ) ) } ) );
-		retDtor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, ast::dtorStructDestroy ) } ) );
+		retDtor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, global.dtorDestroy ) } ) );
 		stmtsToAddBefore.push_back( new ast::DeclStmt(loc, retDtor ) );
 
 		if ( arg ) {
-			auto member = new ast::MemberExpr(loc, ast::dtorStruct->members.front().strict_as<ast::DeclWithType>(), new ast::VariableExpr(loc, retDtor ) );
+			auto member = new ast::MemberExpr(loc, global.dtorStruct->members.front().strict_as<ast::DeclWithType>(), new ast::VariableExpr(loc, retDtor ) );
 			auto object = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, ret ) ), new ast::PointerType(new ast::VoidType() ) );
 			ast::Expr * assign = createBitwiseAssignment( member, object );
@@ -799,14 +801,20 @@
 	// to prevent warnings ('_unq0' may be used uninitialized in this function),
 	// insert an appropriate zero initializer for UniqueExpr temporaries.
-	ast::Init * makeInit( const ast::Type * t ) {
+	ast::Init * makeInit( const ast::Type * t, CodeLocation const & loc ) {
 		if ( auto inst = dynamic_cast< const ast::StructInstType * >( t ) ) {
 			// initizer for empty struct must be empty
-			if ( inst->base->members.empty() ) return new ast::ListInit({}, {});
+			if ( inst->base->members.empty() ) {
+				return new ast::ListInit( loc, {} );
+			}
 		} else if ( auto inst = dynamic_cast< const ast::UnionInstType * >( t ) ) {
 			// initizer for empty union must be empty
-			if ( inst->base->members.empty() ) return new ast::ListInit({}, {});
-		}
-
-		return new ast::ListInit( {}, { new ast::SingleInit( {}, ast::ConstantExpr::from_int({}, 0) ) } );
+			if ( inst->base->members.empty() ) {
+				return new ast::ListInit( loc, {} );
+			}
+		}
+
+		return new ast::ListInit( loc, {
+			new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) )
+		} );
 	}
 
@@ -832,5 +840,5 @@
 			} else {
 				// expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
-				mutExpr->object = new ast::ObjectDecl( mutExpr->location, toString("_unq", mutExpr->id), mutExpr->result, makeInit( mutExpr->result ) );
+				mutExpr->object = new ast::ObjectDecl( mutExpr->location, toString("_unq", mutExpr->id), mutExpr->result, makeInit( mutExpr->result, mutExpr->location ) );
 				mutExpr->var = new ast::VariableExpr( mutExpr->location, mutExpr->object );
 			}
@@ -1172,4 +1180,5 @@
 			auto guard = makeFuncGuard( [this]() { symtab.enterScope(); }, [this]() { symtab.leaveScope(); } );
 			symtab.addFunction( function );
+			auto global = transUnit().global;
 
 			// need to iterate through members in reverse in order for
@@ -1217,6 +1226,6 @@
 
 							static UniqueName memberDtorNamer = { "__memberDtor" };
-							assertf( ast::dtorStruct, "builtin __Destructor not found." );
-							assertf( ast::dtorStructDestroy, "builtin __destroy_Destructor not found." );
+							assertf( global.dtorStruct, "builtin __Destructor not found." );
+							assertf( global.dtorDestroy, "builtin __destroy_Destructor not found." );
 
 							ast::Expr * thisExpr = new ast::CastExpr( new ast::AddressExpr( new ast::VariableExpr(loc, thisParam ) ), new ast::PointerType( new ast::VoidType(), ast::CV::Qualifiers() ) );
@@ -1228,6 +1237,6 @@
 							auto dtorType = new ast::PointerType( dtorFtype );
 
-							auto destructor = new ast::ObjectDecl(loc, memberDtorNamer.newName(), new ast::StructInstType( ast::dtorStruct ), new ast::ListInit(loc, { new ast::SingleInit(loc, thisExpr ), new ast::SingleInit(loc, new ast::CastExpr( dtorExpr, dtorType ) ) } ) );
-							destructor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr({}, ast::dtorStructDestroy ) } ) );
+							auto destructor = new ast::ObjectDecl(loc, memberDtorNamer.newName(), new ast::StructInstType( global.dtorStruct ), new ast::ListInit(loc, { new ast::SingleInit(loc, thisExpr ), new ast::SingleInit(loc, new ast::CastExpr( dtorExpr, dtorType ) ) } ) );
+							destructor->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr( loc, global.dtorDestroy ) } ) );
 							mutStmts->push_front( new ast::DeclStmt(loc, destructor ) );
 							mutStmts->kids.splice( mutStmts->kids.begin(), stmtsToAdd );
@@ -1323,9 +1332,9 @@
 
 	const ast::Expr * GenStructMemberCalls::postvisit( const ast::UntypedExpr * untypedExpr ) {
-		// Expression * newExpr = untypedExpr;
 		// xxx - functions returning ast::ptr seems wrong...
-		auto res = ResolvExpr::findVoidExpression( untypedExpr, symtab );
-		return res.release();
-		// return newExpr;
+		auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
+		// Fix CodeLocation (at least until resolver is fixed).
+		auto fix = localFillCodeLocations( untypedExpr->location, res.release() );
+		return strict_dynamic_cast<const ast::Expr *>( fix );
 	}
 
@@ -1361,5 +1370,5 @@
 
 		// resolve assignment and dispose of new env
-		auto resolved = ResolvExpr::findVoidExpression( assign, symtab );
+		auto resolved = ResolvExpr::findVoidExpression( assign, { symtab, transUnit().global } );
 		auto mut = resolved.get_and_mutate();
 		assertf(resolved.get() == mut, "newly resolved expression must be unique");
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Parser/parser.yy	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Feb 11 14:26:15 2022
-// Update Count     : 5174
+// Last Modified On : Mon Mar 14 16:35:29 2022
+// Update Count     : 5276
 //
 
@@ -610,4 +610,18 @@
 	// | RESUME '(' comma_expression ')' compound_statement
 	//   	{ SemanticError( yylloc, "Resume expression is currently unimplemented." ); $$ = nullptr; }
+	| IDENTIFIER IDENTIFIER								// syntax error
+		{
+			SemanticError( yylloc, ::toString( "Adjacent identifiers are not meaningful in an expression. "
+											   "Possible problem is identifier \"", *$1.str,
+											   "\" is a misspelled typename or an incorrectly specified type name, "
+											   "e.g., missing generic parameter or missing struct/union/enum before typename." ) );
+			$$ = nullptr;
+ 		}
+	| IDENTIFIER direct_type							// syntax error
+		{
+			SemanticError( yylloc, ::toString( "Identifier \"", *$1.str, "\" cannot appear before a type. "
+											   "Possible problem is misspelled storage or CV qualifier." ) );
+			$$ = nullptr;
+		}
 	;
 
@@ -638,5 +652,4 @@
 			// Historic, transitional: Disallow commas in subscripts.
 			// Switching to this behaviour may help check if a C compatibilty case uses comma-exprs in subscripts.
-		// { SemanticError( yylloc, "New array subscript is currently unimplemented." ); $$ = nullptr; }
 			// Current: Commas in subscripts make tuples.
 		{ $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, new ExpressionNode( build_tuple( (ExpressionNode *)($3->set_last( $5 ) ) )) ) ); }
@@ -647,4 +660,8 @@
 		// equivalent to the old x[i,j].
 		{ $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
+	| constant '[' assignment_expression ']'			// 3[a], 'a'[a], 3.5[a]
+		{ $$ = new ExpressionNode( build_binary_val( OperKinds::Index, $1, $3 ) ); }
+	| string_literal '[' assignment_expression ']'		// "abc"[3], 3["abc"]
+		{ $$ = new ExpressionNode( build_binary_val( OperKinds::Index, new ExpressionNode( $1 ), $3 ) ); }
 	| postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
 		{
@@ -1052,4 +1069,11 @@
 	identifier_or_type_name ':' attribute_list_opt statement
 		{ $$ = $4->add_label( $1, $3 ); }
+	| identifier_or_type_name ':' attribute_list_opt error // syntax error
+		{
+			SemanticError( yylloc, ::toString( "Label \"", *$1.str, "\" must be associated with a statement, "
+											   "where a declaration, case, or default is not a statement. "
+											   "Move the label or terminate with a semi-colon." ) );
+			$$ = nullptr;
+		}
 	;
 
@@ -1086,4 +1110,6 @@
 	| statement_list_nodecl statement
 		{ assert( $1 ); $1->set_last( $2 ); $$ = $1; }
+	| statement_list_nodecl error						// syntax error
+		{ SemanticError( yylloc, "Declarations only allowed at the start of the switch body, i.e., after the '{'." ); $$ = nullptr; }
 	;
 
@@ -1093,5 +1119,4 @@
 	| MUTEX '(' ')' comma_expression ';'
 		{ $$ = new StatementNode( build_mutex( nullptr, new StatementNode( build_expr( $4 ) ) ) ); }
-		// { SemanticError( yylloc, "Mutex expression is currently unimplemented." ); $$ = nullptr; }
 	;
 
@@ -1113,4 +1138,6 @@
 			$$ = $7 ? new StatementNode( build_compound( (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
 		}
+	| SWITCH '(' comma_expression ')' '{' error '}'		// CFA, syntax error
+		{ SemanticError( yylloc, "Only declarations can appear before the list of case clauses." ); $$ = nullptr; }
 	| CHOOSE '(' comma_expression ')' case_clause		// CFA
 		{ $$ = new StatementNode( build_switch( false, $3, $5 ) ); }
@@ -1120,4 +1147,6 @@
 			$$ = $7 ? new StatementNode( build_compound( (StatementNode *)((new StatementNode( $7 ))->set_last( sw )) ) ) : sw;
 		}
+	| CHOOSE '(' comma_expression ')' '{' error '}'		// CFA, syntax error
+		{ SemanticError( yylloc, "Only declarations can appear before the list of case clauses." ); $$ = nullptr; }
 	;
 
@@ -1158,14 +1187,14 @@
 
 case_label:												// CFA
-	CASE case_value_list ':'					{ $$ = $2; }
+	CASE error											// syntax error
+		{ SemanticError( yylloc, "Missing case list after case." ); $$ = nullptr; }
+	| CASE case_value_list ':'					{ $$ = $2; }
+	| CASE case_value_list error						// syntax error
+		{ SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; }
 	| DEFAULT ':'								{ $$ = new StatementNode( build_default() ); }
 		// A semantic check is required to ensure only one default clause per switch/choose statement.
-	;
-
-//label_list_opt:
-//	// empty
-//	| identifier_or_type_name ':'
-//	| label_list_opt identifier_or_type_name ':'
-//	;
+	| DEFAULT error										//  syntax error
+		{ SemanticError( yylloc, "Missing colon after default." ); $$ = nullptr; }
+	;
 
 case_label_list:										// CFA
@@ -1403,6 +1432,6 @@
 	| when_clause_opt ELSE statement
 		{ $$ = build_waitfor_timeout( nullptr, maybe_build_compound( $3 ), $1 ); }
-		// "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
-	| when_clause_opt timeout statement WOR ELSE statement
+	// "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
+	| when_clause_opt timeout statement WOR ELSE statement // syntax error
 		{ SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
 	| when_clause_opt timeout statement WOR when_clause ELSE statement
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,6 +10,6 @@
 // Created On       : Wed Jun 5 14:30:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Oct  1 14:55:00 2019
-// Update Count     : 2
+// Last Modified On : Wed Mar 16 11:58:00 2022
+// Update Count     : 3
 //
 
@@ -595,4 +595,5 @@
 	/// Actually visits expressions to find their candidate interpretations
 	class Finder final : public ast::WithShortCircuiting {
+		const ResolveContext & context;
 		const ast::SymbolTable & symtab;
 	public:
@@ -618,6 +619,6 @@
 
 		Finder( CandidateFinder & f )
-		: symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),
-		  targetType( f.targetType ) {}
+		: context( f.context ), symtab( context.symtab ), selfFinder( f ),
+		  candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
 
 		void previsit( const ast::Node * ) { visit_children = false; }
@@ -872,5 +873,5 @@
 			Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
 
-			CandidateFinder funcFinder{ symtab, tenv };
+			CandidateFinder funcFinder( context, tenv );
 			if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
 				auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
@@ -918,5 +919,5 @@
 			// find function operators
 			ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" };
-			CandidateFinder opFinder{ symtab, tenv };
+			CandidateFinder opFinder( context, tenv );
 			// okay if there aren't any function operations
 			opFinder.find( opExpr, ResolvMode::withoutFailFast() );
@@ -1059,5 +1060,5 @@
 
 		void postvisit( const ast::AddressExpr * addressExpr ) {
-			CandidateFinder finder{ symtab, tenv };
+			CandidateFinder finder( context, tenv );
 			finder.find( addressExpr->arg );
 
@@ -1079,9 +1080,9 @@
 			ast::ptr< ast::Type > toType = castExpr->result;
 			assert( toType );
-			toType = resolveTypeof( toType, symtab );
+			toType = resolveTypeof( toType, context );
 			// toType = SymTab::validateType( castExpr->location, toType, symtab );
 			toType = adjustExprType( toType, tenv, symtab );
 
-			CandidateFinder finder{ symtab, tenv, toType };
+			CandidateFinder finder( context, tenv, toType );
 			finder.find( castExpr->arg, ResolvMode::withAdjustment() );
 
@@ -1136,5 +1137,5 @@
 		void postvisit( const ast::VirtualCastExpr * castExpr ) {
 			assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
-			CandidateFinder finder{ symtab, tenv };
+			CandidateFinder finder( context, tenv );
 			// don't prune here, all alternatives guaranteed to have same type
 			finder.find( castExpr->arg, ResolvMode::withoutPrune() );
@@ -1153,5 +1154,5 @@
 			auto target = inst->base.get();
 
-			CandidateFinder finder{ symtab, tenv };
+			CandidateFinder finder( context, tenv );
 
 			auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
@@ -1202,5 +1203,5 @@
 
 		void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
-			CandidateFinder aggFinder{ symtab, tenv };
+			CandidateFinder aggFinder( context, tenv );
 			aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
 			for ( CandidateRef & agg : aggFinder.candidates ) {
@@ -1287,9 +1288,9 @@
 				addCandidate(
 					new ast::SizeofExpr{
-						sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) },
+						sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
 					tenv );
 			} else {
 				// find all candidates for the argument to sizeof
-				CandidateFinder finder{ symtab, tenv };
+				CandidateFinder finder( context, tenv );
 				finder.find( sizeofExpr->expr );
 				// find the lowest-cost candidate, otherwise ambiguous
@@ -1311,9 +1312,9 @@
 				addCandidate(
 					new ast::AlignofExpr{
-						alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) },
+						alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
 					tenv );
 			} else {
 				// find all candidates for the argument to alignof
-				CandidateFinder finder{ symtab, tenv };
+				CandidateFinder finder( context, tenv );
 				finder.find( alignofExpr->expr );
 				// find the lowest-cost candidate, otherwise ambiguous
@@ -1354,9 +1355,9 @@
 
 		void postvisit( const ast::LogicalExpr * logicalExpr ) {
-			CandidateFinder finder1{ symtab, tenv };
+			CandidateFinder finder1( context, tenv );
 			finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
 			if ( finder1.candidates.empty() ) return;
 
-			CandidateFinder finder2{ symtab, tenv };
+			CandidateFinder finder2( context, tenv );
 			finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
 			if ( finder2.candidates.empty() ) return;
@@ -1384,15 +1385,15 @@
 		void postvisit( const ast::ConditionalExpr * conditionalExpr ) {
 			// candidates for condition
-			CandidateFinder finder1{ symtab, tenv };
+			CandidateFinder finder1( context, tenv );
 			finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
 			if ( finder1.candidates.empty() ) return;
 
 			// candidates for true result
-			CandidateFinder finder2{ symtab, tenv };
+			CandidateFinder finder2( context, tenv );
 			finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
 			if ( finder2.candidates.empty() ) return;
 
 			// candidates for false result
-			CandidateFinder finder3{ symtab, tenv };
+			CandidateFinder finder3( context, tenv );
 			finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
 			if ( finder3.candidates.empty() ) return;
@@ -1445,7 +1446,7 @@
 		void postvisit( const ast::CommaExpr * commaExpr ) {
 			ast::TypeEnvironment env{ tenv };
-			ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
-
-			CandidateFinder finder2{ symtab, env };
+			ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
+
+			CandidateFinder finder2( context, env );
 			finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
 
@@ -1460,5 +1461,5 @@
 
 		void postvisit( const ast::ConstructorExpr * ctorExpr ) {
-			CandidateFinder finder{ symtab, tenv };
+			CandidateFinder finder( context, tenv );
 			finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
 			for ( CandidateRef & r : finder.candidates ) {
@@ -1469,9 +1470,9 @@
 		void postvisit( const ast::RangeExpr * rangeExpr ) {
 			// resolve low and high, accept candidates where low and high types unify
-			CandidateFinder finder1{ symtab, tenv };
+			CandidateFinder finder1( context, tenv );
 			finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
 			if ( finder1.candidates.empty() ) return;
 
-			CandidateFinder finder2{ symtab, tenv };
+			CandidateFinder finder2( context, tenv );
 			finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
 			if ( finder2.candidates.empty() ) return;
@@ -1549,5 +1550,5 @@
 
 		void postvisit( const ast::UniqueExpr * unqExpr ) {
-			CandidateFinder finder{ symtab, tenv };
+			CandidateFinder finder( context, tenv );
 			finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
 			for ( CandidateRef & r : finder.candidates ) {
@@ -1558,5 +1559,5 @@
 
 		void postvisit( const ast::StmtExpr * stmtExpr ) {
-			addCandidate( resolveStmtExpr( stmtExpr, symtab ), tenv );
+			addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
 		}
 
@@ -1570,5 +1571,5 @@
 			for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
 				// calculate target type
-				const ast::Type * toType = resolveTypeof( initAlt.type, symtab );
+				const ast::Type * toType = resolveTypeof( initAlt.type, context );
 				// toType = SymTab::validateType( initExpr->location, toType, symtab );
 				toType = adjustExprType( toType, tenv, symtab );
@@ -1576,5 +1577,5 @@
 				// types are not bound to the initialization type, since return type variables are
 				// only open for the duration of resolving the UntypedExpr.
-				CandidateFinder finder{ symtab, tenv, toType };
+				CandidateFinder finder( context, tenv, toType );
 				finder.find( initExpr->expr, ResolvMode::withAdjustment() );
 				for ( CandidateRef & cand : finder.candidates ) {
@@ -1693,5 +1694,5 @@
 		}
 		else {
-			satisfyAssertions(candidate, localSyms, satisfied, errors);
+			satisfyAssertions(candidate, context.symtab, satisfied, errors);
 			needRecomputeKey = true;
 		}
@@ -1855,5 +1856,5 @@
 			r->expr = ast::mutate_field(
 				r->expr.get(), &ast::Expr::result,
-				adjustExprType( r->expr->result, r->env, localSyms ) );
+				adjustExprType( r->expr->result, r->env, context.symtab ) );
 		}
 	}
@@ -1873,5 +1874,5 @@
 
 	for ( const auto & x : xs ) {
-		out.emplace_back( localSyms, env );
+		out.emplace_back( context, env );
 		out.back().find( x, ResolvMode::withAdjustment() );
 
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,6 +10,6 @@
 // Created On       : Wed Jun 5 14:30:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Oct  1  9:51:00 2019
-// Update Count     : 2
+// Last Modified On : Wed Mar 16 15:22:00 2022
+// Update Count     : 3
 //
 
@@ -25,8 +25,10 @@
 namespace ResolvExpr {
 
+struct ResolveContext;
+
 /// Data to perform expression resolution
 struct CandidateFinder {
 	CandidateList candidates;          ///< List of candidate resolutions
-	const ast::SymbolTable & localSyms;   ///< Symbol table to lookup candidates
+	const ResolveContext & context;  ///< Information about where the canditates are being found.
 	const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
 	ast::ptr< ast::Type > targetType;  ///< Target type for resolution
@@ -34,7 +36,7 @@
 
 	CandidateFinder(
-		const ast::SymbolTable & syms, const ast::TypeEnvironment & env,
+		const ResolveContext & context, const ast::TypeEnvironment & env,
 		const ast::Type * tt = nullptr )
-	: candidates(), localSyms( syms ), env( env ), targetType( tt ) {}
+	: candidates(), context( context ), env( env ), targetType( tt ) {}
 
 	/// Fill candidates with feasible resolutions for `expr`
Index: src/ResolvExpr/CandidatePrinter.cpp
===================================================================
--- src/ResolvExpr/CandidatePrinter.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ResolvExpr/CandidatePrinter.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,6 +10,6 @@
 // Created On       : Tue Nov  9  9:54:00 2021
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Nov  9 15:47:00 2021
-// Update Count     : 0
+// Last Modified On : Wed Mar 16 13:56:00 2022
+// Update Count     : 1
 //
 
@@ -22,4 +22,5 @@
 #include "AST/TranslationUnit.hpp"
 #include "ResolvExpr/CandidateFinder.hpp"
+#include "ResolvExpr/Resolver.h"
 
 #include <iostream>
@@ -29,5 +30,6 @@
 namespace {
 
-class CandidatePrintCore : public ast::WithSymbolTable {
+class CandidatePrintCore : public ast::WithSymbolTable,
+		public ast::WithConstTranslationUnit {
 	std::ostream & os;
 public:
@@ -36,5 +38,5 @@
 	void postvisit( const ast::ExprStmt * stmt ) {
 		ast::TypeEnvironment env;
-		CandidateFinder finder( symtab, env );
+		CandidateFinder finder( { symtab, transUnit().global }, env );
 		finder.find( stmt->expr, ResolvMode::withAdjustment() );
 		int count = 1;
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 12:12:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue May 19 16:49:04 2015
-// Update Count     : 3
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Mar 16 16:09:00 2022
+// Update Count     : 4
 //
 
@@ -22,4 +22,5 @@
 #include "AST/Node.hpp"
 #include "AST/Pass.hpp"
+#include "AST/TranslationUnit.hpp"
 #include "AST/Type.hpp"
 #include "AST/TypeEnvironment.hpp"
@@ -119,7 +120,8 @@
 namespace {
 	struct ResolveTypeof_new : public ast::WithShortCircuiting {
-		const ast::SymbolTable & localSymtab;
-
-		ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {}
+		const ResolveContext & context;
+
+		ResolveTypeof_new( const ResolveContext & context ) :
+			context( context ) {}
 
 		void previsit( const ast::TypeofType * ) { visit_children = false; }
@@ -137,5 +139,5 @@
 				ast::TypeEnvironment dummy;
 				ast::ptr< ast::Expr > newExpr =
-					resolveInVoidContext( typeofType->expr, localSymtab, dummy );
+					resolveInVoidContext( typeofType->expr, context, dummy );
 				assert( newExpr->result && ! newExpr->result->isVoid() );
 				newType = newExpr->result;
@@ -161,6 +163,6 @@
 } // anonymous namespace
 
-const ast::Type * resolveTypeof( const ast::Type * type , const ast::SymbolTable & symtab ) {
-	ast::Pass< ResolveTypeof_new > mutator{ symtab };
+const ast::Type * resolveTypeof( const ast::Type * type , const ResolveContext & context ) {
+	ast::Pass< ResolveTypeof_new > mutator( context );
 	return type->accept( mutator );
 }
@@ -168,12 +170,13 @@
 struct FixArrayDimension {
 	// should not require a mutable symbol table - prevent pass template instantiation
-	const ast::SymbolTable & _symtab; 
-	FixArrayDimension(const ast::SymbolTable & symtab): _symtab(symtab) {}
+	const ResolveContext & context;
+	FixArrayDimension(const ResolveContext & context) : context( context ) {}
 
 	const ast::ArrayType * previsit (const ast::ArrayType * arrayType) {
 		if (!arrayType->dimension) return arrayType;
 		auto mutType = mutate(arrayType);
-		ast::ptr<ast::Type> sizetype = ast::sizeType ? ast::sizeType : new ast::BasicType(ast::BasicType::LongUnsignedInt); 
-		mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, _symtab);
+		auto globalSizeType = context.global.sizeType;
+		ast::ptr<ast::Type> sizetype = globalSizeType ? globalSizeType : new ast::BasicType(ast::BasicType::LongUnsignedInt);
+		mutType->dimension = findSingleExpression(arrayType->dimension, sizetype, context );
 
 		if (InitTweak::isConstExpr(mutType->dimension)) {
@@ -187,14 +190,14 @@
 };
 
-const ast::Type * fixArrayType( const ast::Type * type, const ast::SymbolTable & symtab) {
-	ast::Pass<FixArrayDimension> visitor {symtab};
+const ast::Type * fixArrayType( const ast::Type * type, const ResolveContext & context ) {
+	ast::Pass<FixArrayDimension> visitor(context);
 	return type->accept(visitor);
 }
 
-const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab ) {
-	if (!decl->isTypeFixed) { 
+const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & context ) {
+	if (!decl->isTypeFixed) {
 		auto mutDecl = mutate(decl);
-		auto resolvedType = resolveTypeof(decl->type, symtab);
-		resolvedType = fixArrayType(resolvedType, symtab);
+		auto resolvedType = resolveTypeof(decl->type, context);
+		resolvedType = fixArrayType(resolvedType, context);
 		mutDecl->type = resolvedType;
 
Index: src/ResolvExpr/ResolveTypeof.h
===================================================================
--- src/ResolvExpr/ResolveTypeof.h	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ResolvExpr/ResolveTypeof.h	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 12:14:53 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:38:35 2017
-// Update Count     : 3
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Mar 16 11:33:00 2022
+// Update Count     : 4
 //
 
@@ -22,12 +22,13 @@
 namespace ast {
 	class Type;
-	class SymbolTable;
 	class ObjectDecl;
 }
 
 namespace ResolvExpr {
+	struct ResolveContext;
+
 	Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
-	const ast::Type * resolveTypeof( const ast::Type *, const ast::SymbolTable & );
-	const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ast::SymbolTable & symtab );
+	const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
+	const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ResolvExpr/Resolver.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Sun May 17 12:17:01 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Feb  1 16:27:14 2022
-// Update Count     : 245
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Mar 18 10:41:00 2022
+// Update Count     : 247
 //
 
@@ -997,5 +997,5 @@
 		/// Calls the CandidateFinder and finds the single best candidate
 		CandidateRef findUnfinishedKindExpression(
-			const ast::Expr * untyped, const ast::SymbolTable & symtab, const std::string & kind,
+			const ast::Expr * untyped, const ResolveContext & context, const std::string & kind,
 			std::function<bool(const Candidate &)> pred = anyCandidate, ResolvMode mode = {}
 		) {
@@ -1007,5 +1007,5 @@
 			++recursion_level;
 			ast::TypeEnvironment env;
-			CandidateFinder finder{ symtab, env };
+			CandidateFinder finder( context, env );
 			finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
 			--recursion_level;
@@ -1129,5 +1129,6 @@
 
 	ast::ptr< ast::Expr > resolveInVoidContext(
-		const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env
+		const ast::Expr * expr, const ResolveContext & context,
+		ast::TypeEnvironment & env
 	) {
 		assertf( expr, "expected a non-null expression" );
@@ -1136,5 +1137,5 @@
 		ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
 		CandidateRef choice = findUnfinishedKindExpression(
-			untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
+			untyped, context, "", anyCandidate, ResolvMode::withAdjustment() );
 
 		// a cast expression has either 0 or 1 interpretations (by language rules);
@@ -1149,8 +1150,8 @@
 		/// context.
 		ast::ptr< ast::Expr > findVoidExpression(
-			const ast::Expr * untyped, const ast::SymbolTable & symtab
+			const ast::Expr * untyped, const ResolveContext & context
 		) {
 			ast::TypeEnvironment env;
-			ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env );
+			ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, context, env );
 			finishExpr( newExpr, env, untyped->env );
 			return newExpr;
@@ -1163,5 +1164,5 @@
 		/// lowest cost, returning the resolved version
 		ast::ptr< ast::Expr > findKindExpression(
-			const ast::Expr * untyped, const ast::SymbolTable & symtab,
+			const ast::Expr * untyped, const ResolveContext & context,
 			std::function<bool(const Candidate &)> pred = anyCandidate,
 			const std::string & kind = "", ResolvMode mode = {}
@@ -1169,5 +1170,5 @@
 			if ( ! untyped ) return {};
 			CandidateRef choice =
-				findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
+				findUnfinishedKindExpression( untyped, context, kind, pred, mode );
 			ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
 			return std::move( choice->expr );
@@ -1176,8 +1177,8 @@
 		/// Resolve `untyped` to the single expression whose candidate is the best match
 		ast::ptr< ast::Expr > findSingleExpression(
-			const ast::Expr * untyped, const ast::SymbolTable & symtab
+			const ast::Expr * untyped, const ResolveContext & context
 		) {
 			Stats::ResolveTime::start( untyped );
-			auto res = findKindExpression( untyped, symtab );
+			auto res = findKindExpression( untyped, context );
 			Stats::ResolveTime::stop();
 			return res;
@@ -1186,10 +1187,11 @@
 
 	ast::ptr< ast::Expr > findSingleExpression(
-		const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
+		const ast::Expr * untyped, const ast::Type * type,
+		const ResolveContext & context
 	) {
 		assert( untyped && type );
 		ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
-		ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
-		removeExtraneousCast( newExpr, symtab );
+		ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
+		removeExtraneousCast( newExpr, context.symtab );
 		return newExpr;
 	}
@@ -1217,7 +1219,7 @@
 		/// Resolve `untyped` as an integral expression, returning the resolved version
 		ast::ptr< ast::Expr > findIntegralExpression(
-			const ast::Expr * untyped, const ast::SymbolTable & symtab
+			const ast::Expr * untyped, const ResolveContext & context
 		) {
-			return findKindExpression( untyped, symtab, hasIntegralType, "condition" );
+			return findKindExpression( untyped, context, hasIntegralType, "condition" );
 		}
 
@@ -1249,4 +1251,5 @@
 		// for work previously in GenInit
 		static InitTweak::ManagedTypes_new managedTypes;
+		ResolveContext context;
 
 		bool inEnumDecl = false;
@@ -1254,6 +1257,9 @@
 	public:
 		static size_t traceId;
-		Resolver_new() = default;
-		Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
+		Resolver_new( const ast::TranslationGlobal & global ) :
+			context{ symtab, global } {}
+		Resolver_new( const ResolveContext & context ) :
+			ast::WithSymbolTable{ context.symtab },
+			context{ symtab, context.global } {}
 
 		const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
@@ -1272,5 +1278,5 @@
 		const ast::AsmStmt *         previsit( const ast::AsmStmt * );
 		const ast::IfStmt *          previsit( const ast::IfStmt * );
-		const ast::WhileDoStmt *       previsit( const ast::WhileDoStmt * );
+		const ast::WhileDoStmt *     previsit( const ast::WhileDoStmt * );
 		const ast::ForStmt *         previsit( const ast::ForStmt * );
 		const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
@@ -1299,20 +1305,20 @@
 
 	void resolve( ast::TranslationUnit& translationUnit ) {
-		ast::Pass< Resolver_new >::run( translationUnit );
+		ast::Pass< Resolver_new >::run( translationUnit, translationUnit.global );
 	}
 
 	ast::ptr< ast::Init > resolveCtorInit(
-		const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab
+		const ast::ConstructorInit * ctorInit, const ResolveContext & context
 	) {
 		assert( ctorInit );
-		ast::Pass< Resolver_new > resolver{ symtab };
+		ast::Pass< Resolver_new > resolver( context );
 		return ctorInit->accept( resolver );
 	}
 
 	const ast::Expr * resolveStmtExpr(
-		const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab
+		const ast::StmtExpr * stmtExpr, const ResolveContext & context
 	) {
 		assert( stmtExpr );
-		ast::Pass< Resolver_new > resolver{ symtab };
+		ast::Pass< Resolver_new > resolver( context );
 		auto ret = mutate(stmtExpr->accept(resolver));
 		strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
@@ -1321,10 +1327,10 @@
 
 	namespace {
-		const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ast::SymbolTable & symtab) {
+		const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ResolveContext & context) {
 			std::string name = attr->normalizedName();
 			if (name == "constructor" || name == "destructor") {
 				if (attr->params.size() == 1) {
 					auto arg = attr->params.front();
-					auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), symtab );
+					auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), context );
 					auto result = eval(arg);
 
@@ -1369,5 +1375,5 @@
 
 			for (auto & attr: mutDecl->attributes) {
-				attr = handleAttribute(mutDecl->location, attr, symtab);
+				attr = handleAttribute(mutDecl->location, attr, context );
 			}
 
@@ -1382,5 +1388,5 @@
 			}
 			for (auto & asst : mutDecl->assertions) {
-				asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), symtab);
+				asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), context);
 				symtab.addId(asst);
 				mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
@@ -1394,10 +1400,10 @@
 
 			for (auto & param : mutDecl->params) {
-				param = fixObjectType(param.strict_as<ast::ObjectDecl>(), symtab);
+				param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context);
 				symtab.addId(param);
 				paramTypes.emplace_back(param->get_type());
 			}
 			for (auto & ret : mutDecl->returns) {
-				ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), symtab);
+				ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context);
 				returnTypes.emplace_back(ret->get_type());
 			}
@@ -1470,5 +1476,5 @@
 			// enumerator initializers should not use the enum type to initialize, since the
 			// enum type is still incomplete at this point. Use `int` instead.
-			objectDecl = fixObjectType(objectDecl, symtab);
+			objectDecl = fixObjectType(objectDecl, context);
 			currentObject = ast::CurrentObject{
 				objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
@@ -1476,5 +1482,5 @@
 		else {
 			if (!objectDecl->isTypeFixed) {
-				auto newDecl = fixObjectType(objectDecl, symtab);
+				auto newDecl = fixObjectType(objectDecl, context);
 				auto mutDecl = mutate(newDecl);
 
@@ -1507,5 +1513,5 @@
 			// nested type decls are hoisted already. no need to do anything
 			if (auto obj = member.as<ast::ObjectDecl>()) {
-				member = fixObjectType(obj, symtab);
+				member = fixObjectType(obj, context);
 			}
 		}
@@ -1530,14 +1536,14 @@
 		return ast::mutate_field(
 			assertDecl, &ast::StaticAssertDecl::cond,
-			findIntegralExpression( assertDecl->cond, symtab ) );
+			findIntegralExpression( assertDecl->cond, context ) );
 	}
 
 	template< typename PtrType >
-	const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) {
+	const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
 		if ( type->dimension ) {
-			ast::ptr< ast::Type > sizeType = ast::sizeType;
+			ast::ptr< ast::Type > sizeType = context.global.sizeType;
 			ast::mutate_field(
 				type, &PtrType::dimension,
-				findSingleExpression( type->dimension, sizeType, symtab ) );
+				findSingleExpression( type->dimension, sizeType, context ) );
 		}
 		return type;
@@ -1545,9 +1551,9 @@
 
 	const ast::ArrayType * Resolver_new::previsit( const ast::ArrayType * at ) {
-		return handlePtrType( at, symtab );
+		return handlePtrType( at, context );
 	}
 
 	const ast::PointerType * Resolver_new::previsit( const ast::PointerType * pt ) {
-		return handlePtrType( pt, symtab );
+		return handlePtrType( pt, context );
 	}
 
@@ -1557,5 +1563,5 @@
 
 		return ast::mutate_field(
-			exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, symtab ) );
+			exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, context ) );
 	}
 
@@ -1564,5 +1570,5 @@
 
 		asmExpr = ast::mutate_field(
-			asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, symtab ) );
+			asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, context ) );
 
 		return asmExpr;
@@ -1578,10 +1584,10 @@
 	const ast::IfStmt * Resolver_new::previsit( const ast::IfStmt * ifStmt ) {
 		return ast::mutate_field(
-			ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, symtab ) );
+			ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
 	}
 
 	const ast::WhileDoStmt * Resolver_new::previsit( const ast::WhileDoStmt * whileDoStmt ) {
 		return ast::mutate_field(
-			whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, symtab ) );
+			whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
 	}
 
@@ -1589,10 +1595,10 @@
 		if ( forStmt->cond ) {
 			forStmt = ast::mutate_field(
-				forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, symtab ) );
+				forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
 		}
 
 		if ( forStmt->inc ) {
 			forStmt = ast::mutate_field(
-				forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, symtab ) );
+				forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, context ) );
 		}
 
@@ -1604,5 +1610,5 @@
 		switchStmt = ast::mutate_field(
 			switchStmt, &ast::SwitchStmt::cond,
-			findIntegralExpression( switchStmt->cond, symtab ) );
+			findIntegralExpression( switchStmt->cond, context ) );
 		currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
 		return switchStmt;
@@ -1617,5 +1623,5 @@
 			ast::ptr< ast::Expr > untyped =
 				new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
-			ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, symtab );
+			ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, context );
 
 			// case condition cannot have a cast in C, so it must be removed here, regardless of
@@ -1638,5 +1644,5 @@
 			branchStmt = ast::mutate_field(
 				branchStmt, &ast::BranchStmt::computedTarget,
-				findSingleExpression( branchStmt->computedTarget, target, symtab ) );
+				findSingleExpression( branchStmt->computedTarget, target, context ) );
 		}
 		return branchStmt;
@@ -1648,5 +1654,5 @@
 			returnStmt = ast::mutate_field(
 				returnStmt, &ast::ReturnStmt::expr,
-				findSingleExpression( returnStmt->expr, functionReturn, symtab ) );
+				findSingleExpression( returnStmt->expr, functionReturn, context ) );
 		}
 		return returnStmt;
@@ -1663,5 +1669,5 @@
 			throwStmt = ast::mutate_field(
 				throwStmt, &ast::ThrowStmt::expr,
-				findSingleExpression( throwStmt->expr, exceptType, symtab ) );
+				findSingleExpression( throwStmt->expr, exceptType, context ) );
 		}
 		return throwStmt;
@@ -1707,5 +1713,5 @@
 
 			ast::TypeEnvironment env;
-			CandidateFinder funcFinder{ symtab, env };
+			CandidateFinder funcFinder( context, env );
 
 			// Find all candidates for a function in canonical form
@@ -1921,9 +1927,9 @@
 				);
 
-				clause2.target.args.emplace_back( findSingleExpression( init, symtab ) );
+				clause2.target.args.emplace_back( findSingleExpression( init, context ) );
 			}
 
 			// Resolve the conditions as if it were an IfStmt, statements normally
-			clause2.cond = findSingleExpression( clause.cond, symtab );
+			clause2.cond = findSingleExpression( clause.cond, context );
 			clause2.stmt = clause.stmt->accept( *visitor );
 
@@ -1940,6 +1946,6 @@
 			ast::ptr< ast::Type > target =
 				new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
-			timeout2.time = findSingleExpression( stmt->timeout.time, target, symtab );
-			timeout2.cond = findSingleExpression( stmt->timeout.cond, symtab );
+			timeout2.time = findSingleExpression( stmt->timeout.time, target, context );
+			timeout2.cond = findSingleExpression( stmt->timeout.cond, context );
 			timeout2.stmt = stmt->timeout.stmt->accept( *visitor );
 
@@ -1954,5 +1960,5 @@
 			ast::WaitForStmt::OrElse orElse2;
 
-			orElse2.cond = findSingleExpression( stmt->orElse.cond, symtab );
+			orElse2.cond = findSingleExpression( stmt->orElse.cond, context );
 			orElse2.stmt = stmt->orElse.stmt->accept( *visitor );
 
@@ -1975,5 +1981,5 @@
 		for (auto & expr : exprs) {
 			// only struct- and union-typed expressions are viable candidates
-			expr = findKindExpression( expr, symtab, structOrUnion, "with expression" );
+			expr = findKindExpression( expr, context, structOrUnion, "with expression" );
 
 			// if with expression might be impure, create a temporary so that it is evaluated once
@@ -2001,5 +2007,5 @@
 		ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
 			singleInit->location, singleInit->value, currentObject.getOptions() };
-		ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, symtab );
+		ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, context );
 		const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
 
Index: src/ResolvExpr/Resolver.h
===================================================================
--- src/ResolvExpr/Resolver.h	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ResolvExpr/Resolver.h	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 12:18:34 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Feb 18 20:40:38 2019
-// Update Count     : 4
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Mar 16 11:32:00 2022
+// Update Count     : 5
 //
 
@@ -23,5 +23,7 @@
 class Declaration;
 class Expression;
+class DeletedExpr;
 class StmtExpr;
+class Type;
 namespace SymTab {
 	class Indexer;
@@ -35,4 +37,5 @@
 	class StmtExpr;
 	class SymbolTable;
+	class TranslationGlobal;
 	class TranslationUnit;
 	class Type;
@@ -55,4 +58,10 @@
 	void resolveWithExprs( std::list< Declaration * > & translationUnit );
 
+	/// Helper Type: Passes around information between various sub-calls.
+	struct ResolveContext {
+		const ast::SymbolTable & symtab;
+		const ast::TranslationGlobal & global;
+	};
+
 	/// Checks types and binds syntactic constructs to typed representations
 	void resolve( ast::TranslationUnit& translationUnit );
@@ -62,17 +71,17 @@
 	/// context.
 	ast::ptr< ast::Expr > resolveInVoidContext(
-		const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env );
+		const ast::Expr * expr, const ResolveContext &, ast::TypeEnvironment & env );
 	/// Resolve `untyped` to the single expression whose candidate is the best match for the
 	/// given type.
 	ast::ptr< ast::Expr > findSingleExpression(
-		const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab );
+		const ast::Expr * untyped, const ast::Type * type, const ResolveContext & );
 	ast::ptr< ast::Expr > findVoidExpression(
-		const ast::Expr * untyped, const ast::SymbolTable & symtab);
+		const ast::Expr * untyped, const ResolveContext & );
 	/// Resolves a constructor init expression
 	ast::ptr< ast::Init > resolveCtorInit(
-		const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
+		const ast::ConstructorInit * ctorInit, const ResolveContext & context );
 	/// Resolves a statement expression
 	const ast::Expr * resolveStmtExpr(
-		const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab );
+		const ast::StmtExpr * stmtExpr, const ResolveContext & context );
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/ResolvExpr/Unify.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -943,5 +943,5 @@
 			// check that the other type is compatible and named the same
 			auto otherInst = dynamic_cast< const XInstType * >( other );
-			this->result = otherInst && inst->name == otherInst->name;
+			if (otherInst && inst->name == otherInst->name) this->result = otherInst;
 			return otherInst;
 		}
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/SymTab/Validate.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -194,4 +194,26 @@
 	};
 
+	// These structs are the sub-sub-passes of ForallPointerDecay_old.
+
+	struct TraitExpander_old final {
+		void previsit( FunctionType * );
+		void previsit( StructDecl * );
+		void previsit( UnionDecl * );
+	};
+
+	struct AssertionFixer_old final {
+		void previsit( FunctionType * );
+		void previsit( StructDecl * );
+		void previsit( UnionDecl * );
+	};
+
+	struct CheckOperatorTypes_old final {
+		void previsit( ObjectDecl * );
+	};
+
+	struct FixUniqueIds_old final {
+		void previsit( DeclarationWithType * );
+	};
+
 	struct ReturnChecker : public WithGuards {
 		/// Checks that return statements return nothing if their return type is void
@@ -386,5 +408,4 @@
 
 	void validate_D( std::list< Declaration * > & translationUnit ) {
-		PassVisitor<ForallPointerDecay_old> fpd;
 		{
 			Stats::Heap::newPass("validate-D");
@@ -394,5 +415,5 @@
 			});
 			Stats::Time::TimeBlock("Forall Pointer Decay", [&]() {
-				acceptAll( translationUnit, fpd ); // must happen before autogenerateRoutines, after Concurrency::applyKeywords because uniqueIds must be set on declaration before resolution
+				decayForallPointers( translationUnit ); // must happen before autogenerateRoutines, after Concurrency::applyKeywords because uniqueIds must be set on declaration before resolution
 			});
 			Stats::Time::TimeBlock("Hoist Control Declarations", [&]() {
@@ -454,6 +475,29 @@
 
 	void decayForallPointers( std::list< Declaration * > & translationUnit ) {
-		PassVisitor<ForallPointerDecay_old> fpd;
-		acceptAll( translationUnit, fpd );
+		PassVisitor<TraitExpander_old> te;
+		acceptAll( translationUnit, te );
+		PassVisitor<AssertionFixer_old> af;
+		acceptAll( translationUnit, af );
+		PassVisitor<CheckOperatorTypes_old> cot;
+		acceptAll( translationUnit, cot );
+		PassVisitor<FixUniqueIds_old> fui;
+		acceptAll( translationUnit, fui );
+	}
+
+	void decayForallPointersA( std::list< Declaration * > & translationUnit ) {
+		PassVisitor<TraitExpander_old> te;
+		acceptAll( translationUnit, te );
+	}
+	void decayForallPointersB( std::list< Declaration * > & translationUnit ) {
+		PassVisitor<AssertionFixer_old> af;
+		acceptAll( translationUnit, af );
+	}
+	void decayForallPointersC( std::list< Declaration * > & translationUnit ) {
+		PassVisitor<CheckOperatorTypes_old> cot;
+		acceptAll( translationUnit, cot );
+	}
+	void decayForallPointersD( std::list< Declaration * > & translationUnit ) {
+		PassVisitor<FixUniqueIds_old> fui;
+		acceptAll( translationUnit, fui );
 	}
 
@@ -470,8 +514,14 @@
 		PassVisitor<EnumAndPointerDecay_old> epc;
 		PassVisitor<LinkReferenceToTypes_old> lrt( indexer );
-		PassVisitor<ForallPointerDecay_old> fpd;
+		PassVisitor<TraitExpander_old> te;
+		PassVisitor<AssertionFixer_old> af;
+		PassVisitor<CheckOperatorTypes_old> cot;
+		PassVisitor<FixUniqueIds_old> fui;
 		type->accept( epc );
 		type->accept( lrt );
-		type->accept( fpd );
+		type->accept( te );
+		type->accept( af );
+		type->accept( cot );
+		type->accept( fui );
 	}
 
@@ -972,4 +1022,36 @@
 	}
 
+	/// Replace all traits in assertion lists with their assertions.
+	void expandTraits( std::list< TypeDecl * > & forall ) {
+		for ( TypeDecl * type : forall ) {
+			std::list< DeclarationWithType * > asserts;
+			asserts.splice( asserts.end(), type->assertions );
+			// expand trait instances into their members
+			for ( DeclarationWithType * assertion : asserts ) {
+				if ( TraitInstType * traitInst = dynamic_cast< TraitInstType * >( assertion->get_type() ) ) {
+					// expand trait instance into all of its members
+					expandAssertions( traitInst, back_inserter( type->assertions ) );
+					delete traitInst;
+				} else {
+					// pass other assertions through
+					type->assertions.push_back( assertion );
+				} // if
+			} // for
+		}
+	}
+
+	/// Fix each function in the assertion list and check for invalid void type.
+	void fixAssertions(
+			std::list< TypeDecl * > & forall, BaseSyntaxNode * node ) {
+		for ( TypeDecl * type : forall ) {
+			for ( DeclarationWithType *& assertion : type->assertions ) {
+				bool isVoid = fixFunction( assertion );
+				if ( isVoid ) {
+					SemanticError( node, "invalid type void in assertion of function " );
+				} // if
+			} // for
+		}
+	}
+
 	void ForallPointerDecay_old::previsit( ObjectDecl * object ) {
 		// ensure that operator names only apply to functions or function pointers
@@ -994,4 +1076,39 @@
 	void ForallPointerDecay_old::previsit( UnionDecl * aggrDecl ) {
 		forallFixer( aggrDecl->parameters, aggrDecl );
+	}
+
+	void TraitExpander_old::previsit( FunctionType * ftype ) {
+		expandTraits( ftype->forall );
+	}
+
+	void TraitExpander_old::previsit( StructDecl * aggrDecl ) {
+		expandTraits( aggrDecl->parameters );
+	}
+
+	void TraitExpander_old::previsit( UnionDecl * aggrDecl ) {
+		expandTraits( aggrDecl->parameters );
+	}
+
+	void AssertionFixer_old::previsit( FunctionType * ftype ) {
+		fixAssertions( ftype->forall, ftype );
+	}
+
+	void AssertionFixer_old::previsit( StructDecl * aggrDecl ) {
+		fixAssertions( aggrDecl->parameters, aggrDecl );
+	}
+
+	void AssertionFixer_old::previsit( UnionDecl * aggrDecl ) {
+		fixAssertions( aggrDecl->parameters, aggrDecl );
+	}
+
+	void CheckOperatorTypes_old::previsit( ObjectDecl * object ) {
+		// ensure that operator names only apply to functions or function pointers
+		if ( CodeGen::isOperator( object->name ) && ! dynamic_cast< FunctionType * >( object->type->stripDeclarator() ) ) {
+			SemanticError( object->location, toCString( "operator ", object->name.c_str(), " is not a function or function pointer." )  );
+		}
+	}
+
+	void FixUniqueIds_old::previsit( DeclarationWithType * decl ) {
+		decl->fixUniqueId();
 	}
 
Index: src/SymTab/Validate.h
===================================================================
--- src/SymTab/Validate.h	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/SymTab/Validate.h	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -43,4 +43,8 @@
 	void validate_F( std::list< Declaration * > &translationUnit );
 	void decayForallPointers( std::list< Declaration * > & translationUnit );
+	void decayForallPointersA( std::list< Declaration * > & translationUnit );
+	void decayForallPointersB( std::list< Declaration * > & translationUnit );
+	void decayForallPointersC( std::list< Declaration * > & translationUnit );
+	void decayForallPointersD( std::list< Declaration * > & translationUnit );
 
 	const ast::Type * validateType(
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Tuples/TupleAssignment.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -9,7 +9,7 @@
 // Author           : Rodolfo G. Esteves
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Dec 13 23:45:33 2019
-// Update Count     : 9
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Mar 16 14:06:00 2022
+// Update Count     : 10
 //
 
@@ -465,5 +465,5 @@
 					// resolve ctor/dtor for the new object
 					ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
-							InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms );
+							InitTweak::genCtorInit( location, ret ), spotter.crntFinder.context );
 					// remove environments from subexpressions of stmtExpr
 					ast::Pass< EnvRemover > rm{ env };
@@ -560,5 +560,5 @@
 					// resolve the cast expression so that rhsCand return type is bound by the cast
 					// type as needed, and transfer the resulting environment
-					ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env };
+					ResolvExpr::CandidateFinder finder( spotter.crntFinder.context, env );
 					finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
 					assert( finder.candidates.size() == 1 );
@@ -609,5 +609,5 @@
 					// explode the LHS so that each field of a tuple-valued expr is assigned
 					ResolvExpr::CandidateList lhs;
-					explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true );
+					explode( *lhsCand, crntFinder.context.symtab, back_inserter(lhs), true );
 					for ( ResolvExpr::CandidateRef & cand : lhs ) {
 						// each LHS value must be a reference - some come in with a cast, if not
@@ -629,5 +629,5 @@
 							if ( isTuple( rhsCand->expr ) ) {
 								// multiple assignment
-								explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
+								explode( *rhsCand, crntFinder.context.symtab, back_inserter(rhs), true );
 								matcher.reset(
 									new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
@@ -648,5 +648,5 @@
 							// multiple assignment
 							ResolvExpr::CandidateList rhs;
-							explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
+							explode( rhsCand, crntFinder.context.symtab, back_inserter(rhs), true );
 							matcher.reset(
 								new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
@@ -678,5 +678,5 @@
 				)
 
-				ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env };
+				ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env );
 
 				try {
Index: src/Validate/FindSpecialDeclsNew.cpp
===================================================================
--- src/Validate/FindSpecialDeclsNew.cpp	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Validate/FindSpecialDeclsNew.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -30,6 +30,6 @@
 
 struct FindDeclsCore : public ast::WithShortCircuiting {
-	ast::TranslationUnit::Global & global;
-	FindDeclsCore( ast::TranslationUnit::Global & g ) : global( g ) {}
+	ast::TranslationGlobal & global;
+	FindDeclsCore( ast::TranslationGlobal & g ) : global( g ) {}
 
 	void previsit( const ast::Decl * decl );
@@ -74,10 +74,4 @@
 	ast::Pass<FindDeclsCore>::run( translationUnit, translationUnit.global );
 
-	// TODO: When everything gets the globals from the translation unit,
-	// remove these.
-	ast::dereferenceOperator = translationUnit.global.dereference;
-	ast::dtorStruct = translationUnit.global.dtorStruct;
-	ast::dtorStructDestroy = translationUnit.global.dtorDestroy;
-
 	// TODO: conditionally generate 'fake' declarations for missing features,
 	// so that translation can proceed in the event that builtins, prelude,
Index: src/Validate/ForallPointerDecay.cpp
===================================================================
--- src/Validate/ForallPointerDecay.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ src/Validate/ForallPointerDecay.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,245 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallPointerDecay.cpp --
+//
+// Author           : Andrew Beach
+// Created On       : Tue Dec  7 16:15:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Feb 11 10:59:00 2022
+// Update Count     : 0
+//
+
+#include "ForallPointerDecay.hpp"
+
+#include "AST/Copy.hpp"
+#include "AST/Decl.hpp"
+#include "AST/DeclReplacer.hpp"
+#include "AST/Pass.hpp"
+#include "CodeGen/OperatorTable.h"
+#include "Common/CodeLocation.h"
+#include "SymTab/FixFunction.h"
+
+#include "AST/Print.hpp"
+
+namespace Validate {
+
+namespace {
+
+// Create a function type only using information on the FunctionDecl.
+ast::FunctionType * makeFuncType( const ast::FunctionDecl * decl ) {
+	auto type = new ast::FunctionType( decl->type->isVarArgs );
+	for ( auto & param : decl->params ) {
+		type->params.emplace_back( param->get_type() );
+	}
+	for ( auto & ret : decl->returns ) {
+		type->returns.emplace_back( ret->get_type() );
+	}
+	for ( auto & type_param : decl->type_params ) {
+		type->forall.emplace_back(
+			new ast::TypeInstType( type_param->name, type_param ) );
+	}
+	for ( auto & assertion : decl->assertions ) {
+		type->assertions.emplace_back( new ast::VariableExpr(
+			assertion->location, assertion ) );
+	}
+	return type;
+}
+
+template<typename T>
+void append( std::vector<T> & dst, std::vector<T> & src ) {
+	dst.reserve( dst.size() + src.size() );
+	for ( auto el : src ) {
+		dst.emplace_back( std::move( el ) );
+	}
+	src.clear();
+}
+
+// Component Passes:
+/// Expand assertions from a trait instance,
+/// performing appropriate type variable substitutions.
+struct TraitExpander final {
+	using AssertionList = std::vector<ast::ptr<ast::DeclWithType>>;
+
+	static AssertionList expandTrait( const ast::TraitInstType * inst ) {
+		assertf( inst->base, "Trait instance not linked to base trait: %s",
+			toCString( inst ) );
+		AssertionList assertions;
+		// Substitute trait decl parameters for instance parameters.
+		ast::TypeSubstitution sub( inst->base->params, inst->params );
+		for ( const ast::ptr<ast::Decl> & decl : inst->base->members ) {
+			ast::ptr<ast::DeclWithType> copy =
+				ast::deepCopy( decl.strict_as<ast::DeclWithType>() );
+
+			int count = sub.apply( copy );
+			(void)count;
+
+			// Update the type (type substution does not seem to cover it).
+			if ( auto func = copy.as<ast::FunctionDecl>() ) {
+				auto mut = ast::mutate( func );
+				mut->type = makeFuncType( func );
+				copy = mut;
+			}
+			assertions.push_back( copy );
+		}
+		return assertions;
+	}
+
+	static AssertionList expandAssertions( const AssertionList & old ) {
+		AssertionList assertions;
+		for ( const ast::ptr<ast::DeclWithType> & decl : old ) {
+			if ( auto traitInst = dynamic_cast<const ast::TraitInstType *>(
+					decl->get_type() ) ) {
+				auto moreAsserts = expandTrait( traitInst );
+				append( assertions, moreAsserts );
+			} else {
+				assertions.push_back( decl );
+			}
+		}
+		return assertions;
+	}
+
+	using TypeDeclVec = std::vector<ast::ptr<ast::TypeDecl>>;
+
+	static TypeDeclVec expandTypeDecls( const TypeDeclVec & old ) {
+		TypeDeclVec typeDecls;
+		for ( const ast::TypeDecl * typeDecl : old ) {
+			typeDecls.push_back( ast::mutate_field( typeDecl,
+				&ast::TypeDecl::assertions,
+				expandAssertions( typeDecl->assertions ) ) );
+		}
+		return typeDecls;
+	}
+
+	const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ) {
+		if ( decl->assertions.empty() ) {
+			return decl;
+		}
+		auto mut = ast::mutate( decl );
+		mut->assertions = expandAssertions( decl->assertions );
+		// Update the assertion list on the type as well.
+		auto mutType = ast::mutate( mut->type.get() );
+		mutType->assertions.clear();
+		for ( auto & assertion : mut->assertions ) {
+			mutType->assertions.emplace_back(
+				new ast::VariableExpr( mut->location, assertion ) );
+		}
+		mut->type = mutType;
+		return mut;
+	}
+
+	const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
+		if ( decl->params.empty() ) {
+			return decl;
+		}
+		return ast::mutate_field( decl, &ast::StructDecl::params,
+			expandTypeDecls( decl->params ) );
+	}
+
+	const ast::UnionDecl * previsit( const ast::UnionDecl * decl ) {
+		if ( decl->params.empty() ) {
+			return decl;
+		}
+		return ast::mutate_field( decl, &ast::UnionDecl::params,
+			expandTypeDecls( decl->params ) );
+	}
+};
+
+std::vector<ast::ptr<ast::DeclWithType>> fixAssertionList(
+		const ast::ParseNode * node,
+		const std::vector<ast::ptr<ast::DeclWithType>> & assertions ) {
+	std::vector<ast::ptr<ast::DeclWithType>> ret;
+	for ( const auto & assn : assertions ) {
+		bool isVoid = false;
+		ret.push_back( SymTab::fixFunction( assn, isVoid ) );
+		if ( isVoid ) {
+			SemanticError( node->location, node,
+				"invalid type void in assertion of function " );
+		}
+	}
+	return ret;
+}
+
+std::vector<ast::ptr<ast::TypeDecl>> fixTypeDeclList(
+		const ast::ParseNode * node,
+		const std::vector<ast::ptr<ast::TypeDecl>> & type_params ) {
+	std::vector<ast::ptr<ast::TypeDecl>> ret;
+	ret.reserve( type_params.size() );
+	for ( const ast::TypeDecl * type_param : type_params ) {
+		auto mutParam = ast::mutate( type_param );
+		mutParam->assertions = fixAssertionList( node, mutParam->assertions );
+		ret.push_back( mutParam );
+	}
+	return ret;
+}
+
+struct AssertionFunctionFixer final {
+	const ast::FunctionDecl * previsit( const ast::FunctionDecl * decl ) {
+		if ( decl->assertions.empty() ) {
+			return decl;
+		}
+		return ast::mutate_field( decl, &ast::FunctionDecl::assertions,
+			fixAssertionList( decl, decl->assertions ) );
+	}
+
+	const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
+		if ( decl->params.empty() ) {
+			return decl;
+		}
+		return ast::mutate_field( decl, &ast::StructDecl::params,
+			fixTypeDeclList( decl, decl->params ) );
+	}
+
+	const ast::UnionDecl * previsit( const ast::UnionDecl * decl ) {
+		if ( decl->params.empty() ) {
+			return decl;
+		}
+		return ast::mutate_field( decl, &ast::UnionDecl::params,
+			fixTypeDeclList( decl, decl->params ) );
+	}
+};
+
+struct OberatorChecker final {
+	void previsit( const ast::ObjectDecl * obj ) {
+		if ( CodeGen::isOperator( obj->name ) ) {
+			auto type = obj->type->stripDeclarator();
+			if ( ! dynamic_cast< const ast::FunctionType * >( type ) ) {
+				SemanticError( obj->location,
+					toCString( "operator ", obj->name.c_str(), " is not "
+					"a function or function pointer." ) );
+			}
+		}
+	}
+};
+
+struct UniqueFixCore final {
+	const ast::DeclWithType * postvisit( const ast::DeclWithType * decl ) {
+		if ( decl->uniqueId ) {
+			return decl;
+		} else {
+			auto mut = ast::mutate( decl );
+			mut->fixUniqueId();
+			return mut;
+		}
+	}
+};
+
+} // namespace
+
+void decayForallPointers( ast::TranslationUnit & transUnit ) {
+	ast::Pass<TraitExpander>::run( transUnit );
+	ast::Pass<AssertionFunctionFixer>::run( transUnit );
+	ast::Pass<OberatorChecker>::run( transUnit );
+	ast::Pass<UniqueFixCore>::run( transUnit );
+}
+
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/ForallPointerDecay.hpp
===================================================================
--- src/Validate/ForallPointerDecay.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ src/Validate/ForallPointerDecay.hpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,35 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallPointerDecay.hpp --
+//
+// Author           : Andrew Beach
+// Created On       : Tue Dec  7 16:15:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Dec  8 11:50:00 2021
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace Validate {
+
+/// Cleans up assertion lists and expands traits.
+/// Also checks that operator names are used properly on functions and
+/// assigns unique IDs. This is a "legacy" pass.
+void decayForallPointers( ast::TranslationUnit & transUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/module.mk
===================================================================
--- src/Validate/module.mk	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Validate/module.mk	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -20,4 +20,6 @@
 	Validate/CompoundLiteral.cpp \
 	Validate/CompoundLiteral.hpp \
+	Validate/ForallPointerDecay.cpp \
+	Validate/ForallPointerDecay.hpp \
 	Validate/HandleAttributes.cc \
 	Validate/HandleAttributes.h \
Index: src/Virtual/Tables.cc
===================================================================
--- src/Virtual/Tables.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Virtual/Tables.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,8 +10,15 @@
 // Created On       : Mon Aug 31 11:11:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Apr 21 15:36:00 2021
-// Update Count     : 2
-//
-
+// Last Modified On : Fri Mar 11 10:40:00 2022
+// Update Count     : 3
+//
+
+#include "AST/Attribute.hpp"
+#include "AST/Copy.hpp"
+#include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Init.hpp"
+#include "AST/Stmt.hpp"
+#include "AST/Type.hpp"
 #include <SynTree/Attribute.h>
 #include <SynTree/Declaration.h>
@@ -77,7 +84,31 @@
 }
 
+static ast::ObjectDecl * makeVtableDeclaration(
+		CodeLocation const & location, std::string const & name,
+		ast::StructInstType const * type, ast::Init const * init ) {
+	ast::Storage::Classes storage;
+	if ( nullptr == init ) {
+		storage.is_extern = true;
+	}
+	return new ast::ObjectDecl(
+		location,
+		name,
+		type,
+		init,
+		storage,
+		ast::Linkage::Cforall
+	);
+}
+
 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {
 	assert( type );
 	return makeVtableDeclaration( name, type, nullptr );
+}
+
+ast::ObjectDecl * makeVtableForward(
+		CodeLocation const & location, std::string const & name,
+		ast::StructInstType const * vtableType ) {
+	assert( vtableType );
+	return makeVtableDeclaration( location, name, vtableType, nullptr );
 }
 
@@ -123,4 +154,70 @@
 }
 
+static std::vector<ast::ptr<ast::Init>> buildInits(
+		CodeLocation const & location,
+		//std::string const & name,
+		ast::StructInstType const * vtableType,
+		ast::Type const * objectType ) {
+	ast::StructDecl const * vtableStruct = vtableType->base;
+
+	std::vector<ast::ptr<ast::Init>> inits;
+	inits.reserve( vtableStruct->members.size() );
+
+	// This is designed to run before the resolver.
+	for ( auto field : vtableStruct->members ) {
+		if ( std::string( "parent" ) == field->name ) {
+			// This will not work with polymorphic state.
+			auto oField = field.strict_as<ast::ObjectDecl>();
+			auto fieldType = oField->type.strict_as<ast::PointerType>();
+			auto parentType = fieldType->base.strict_as<ast::StructInstType>();
+			std::string const & parentInstance = instanceName( parentType->name );
+			inits.push_back(
+					new ast::SingleInit( location, new ast::AddressExpr( new ast::NameExpr( location, parentInstance ) ) ) );
+		} else if ( std::string( "__cfavir_typeid" ) == field->name ) {
+			std::string const & baseType = baseTypeName( vtableType->name );
+			std::string const & typeId = typeIdName( baseType );
+			inits.push_back( new ast::SingleInit( location, new ast::AddressExpr( new ast::NameExpr( location, typeId ) ) ) );
+		} else if ( std::string( "size" ) == field->name ) {
+			inits.push_back( new ast::SingleInit( location, new ast::SizeofExpr( location, objectType )
+			) );
+		} else if ( std::string( "align" ) == field->name ) {
+			inits.push_back( new ast::SingleInit( location,
+				new ast::AlignofExpr( location, objectType )
+			) );
+		} else {
+			inits.push_back( new ast::SingleInit( location,
+				new ast::NameExpr( location, field->name )
+			) );
+		}
+		//ast::Expr * expr = buildInitExpr(...);
+		//inits.push_back( new ast::SingleInit( location, expr ) )
+	}
+
+	return inits;
+}
+
+ast::ObjectDecl * makeVtableInstance(
+		CodeLocation const & location,
+		std::string const & name,
+		ast::StructInstType const * vtableType,
+		ast::Type const * objectType,
+		ast::Init const * init ) {
+	assert( vtableType );
+	assert( objectType );
+
+	// Build the initialization.
+	if ( nullptr == init ) {
+		init = new ast::ListInit( location,
+			buildInits( location, vtableType, objectType ) );
+
+	// The provided init should initialize everything except the parent
+	// pointer, the size-of and align-of fields. These should be inserted.
+	} else {
+		// Except this is not yet supported.
+		assert(false);
+	}
+	return makeVtableDeclaration( location, name, vtableType, init );
+}
+
 namespace {
 	std::string const functionName = "get_exception_vtable";
@@ -140,5 +237,5 @@
 		new ReferenceType( noQualifiers, vtableType ),
 		nullptr,
-        { new Attribute("unused") }
+		{ new Attribute("unused") }
 	) );
 	type->parameters.push_back( new ObjectDecl(
@@ -157,4 +254,31 @@
 		type,
 		nullptr
+	);
+}
+
+ast::FunctionDecl * makeGetExceptionForward(
+		CodeLocation const & location,
+		ast::Type const * vtableType,
+		ast::Type const * exceptType ) {
+	assert( vtableType );
+	assert( exceptType );
+	return new ast::FunctionDecl(
+		location,
+		functionName,
+		{ /* forall */ },
+		{ new ast::ObjectDecl(
+			location,
+			"__unused",
+			new ast::PointerType( exceptType )
+		) },
+		{ new ast::ObjectDecl(
+			location,
+			"_retvalue",
+			new ast::ReferenceType( vtableType )
+		) },
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall,
+		{ new ast::Attribute( "unused" ) }
 	);
 }
@@ -172,4 +296,17 @@
 }
 
+ast::FunctionDecl * makeGetExceptionFunction(
+		CodeLocation const & location,
+		ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType ) {
+	assert( vtableInstance );
+	assert( exceptType );
+	ast::FunctionDecl * func = makeGetExceptionForward(
+			location, ast::deepCopy( vtableInstance->type ), exceptType );
+	func->stmts = new ast::CompoundStmt( location, {
+		new ast::ReturnStmt( location, new ast::VariableExpr( location, vtableInstance ) )
+	} );
+	return func;
+}
+
 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
 	assert( typeIdType );
@@ -191,3 +328,26 @@
 }
 
-}
+ast::ObjectDecl * makeTypeIdInstance(
+		CodeLocation const & location,
+		ast::StructInstType const * typeIdType ) {
+	assert( typeIdType );
+	ast::StructInstType * type = ast::mutate( typeIdType );
+	type->set_const( true );
+	std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
+	return new ast::ObjectDecl(
+		location,
+		typeid_name,
+		type,
+		new ast::ListInit( location, {
+			new ast::SingleInit( location,
+				new ast::AddressExpr( location,
+					new ast::NameExpr( location, "__cfatid_exception_t" ) ) )
+		} ),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall,
+		nullptr,
+		{ new ast::Attribute( "cfa_linkonce" ) }
+	);
+}
+
+}
Index: src/Virtual/Tables.h
===================================================================
--- src/Virtual/Tables.h	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/Virtual/Tables.h	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,10 +10,12 @@
 // Created On       : Mon Aug 31 11:07:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Apr 21 10:30:00 2021
-// Update Count     : 2
+// Last Modified On : Wec Dec  8 16:58:00 2021
+// Update Count     : 3
 //
 
 #include <list>  // for list
 
+#include <string>
+#include "AST/Fwd.hpp"
 class Declaration;
 class StructDecl;
@@ -35,4 +37,7 @@
  * vtableType node is consumed.
  */
+ast::ObjectDecl * makeVtableForward(
+	CodeLocation const & location, std::string const & name,
+	ast::StructInstType const * vtableType );
 
 ObjectDecl * makeVtableInstance(
@@ -43,4 +48,10 @@
  * vtableType and init (if provided) nodes are consumed.
  */
+ast::ObjectDecl * makeVtableInstance(
+	CodeLocation const & location,
+	std::string const & name,
+	ast::StructInstType const * vtableType,
+	ast::Type const * objectType,
+	ast::Init const * init = nullptr );
 
 // Some special code for how exceptions interact with virtual tables.
@@ -49,4 +60,8 @@
  * linking the vtableType to the exceptType. Both nodes are consumed.
  */
+ast::FunctionDecl * makeGetExceptionForward(
+	CodeLocation const & location,
+	ast::Type const * vtableType,
+	ast::Type const * exceptType );
 
 FunctionDecl * makeGetExceptionFunction(
@@ -55,4 +70,7 @@
  * exceptType node is consumed.
  */
+ast::FunctionDecl * makeGetExceptionFunction(
+	CodeLocation const & location,
+	ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType );
 
 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
@@ -60,4 +78,6 @@
  * TODO: Should take the parent type. Currently locked to the exception_t.
  */
+ast::ObjectDecl * makeTypeIdInstance(
+	const CodeLocation & location, ast::StructInstType const * typeIdType );
 
 }
Index: src/main.cc
===================================================================
--- src/main.cc	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ src/main.cc	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -10,6 +10,6 @@
 // Created On       : Fri May 15 23:12:02 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Jan 26 14:09:00 2022
-// Update Count     : 670
+// Last Modified On : Fri Mar 11 10:39:00 2022
+// Update Count     : 671
 //
 
@@ -76,4 +76,5 @@
 #include "Validate/Autogen.hpp"             // for autogenerateRoutines
 #include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
+#include "Validate/ForallPointerDecay.hpp"  // for decayForallPointers
 #include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
 #include "Validate/InitializerLength.hpp"   // for setLengthFromInitializer
@@ -331,6 +332,4 @@
 
 		if( useNewAST ) {
-			PASS( "Apply Concurrent Keywords", Concurrency::applyKeywords( translationUnit ) );
-			PASS( "Forall Pointer Decay", SymTab::decayForallPointers( translationUnit ) );
 			CodeTools::fillLocations( translationUnit );
 
@@ -342,4 +341,11 @@
 
 			forceFillCodeLocations( transUnit );
+
+			PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
+
+			// Must be after implement concurrent keywords; because uniqueIds
+			//   must be set on declaration before resolution.
+			// Must happen before autogen routines are added.
+			PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) );
 
 			// Must happen before autogen routines are added.
@@ -487,6 +493,4 @@
 			PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) );
 		}
-
-		
 
 		PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) );
Index: tests/.expect/declarationSpecifier.arm64.txt
===================================================================
--- tests/.expect/declarationSpecifier.arm64.txt	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/.expect/declarationSpecifier.arm64.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1132,5 +1132,5 @@
 char **_X13cfa_args_argvPPc_1;
 char **_X13cfa_args_envpPPc_1;
-signed int _X17cfa_main_returnedi_1 = ((signed int )0);
+__attribute__ ((weak)) extern signed int _X17cfa_main_returnedi_1;
 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
     __attribute__ ((unused)) signed int _X12_retval_maini_1;
@@ -1149,6 +1149,9 @@
     signed int _tmp_cp_ret6;
     signed int _X3reti_2 = (((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6);
-    {
-        ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
+    if ( ((&_X17cfa_main_returnedi_1)!=((signed int *)0)) ) {
+        {
+            ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
+        }
+
     }
 
Index: tests/.expect/gccExtensions.arm64.txt
===================================================================
--- tests/.expect/gccExtensions.arm64.txt	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/.expect/gccExtensions.arm64.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -324,5 +324,5 @@
 char **_X13cfa_args_argvPPc_1;
 char **_X13cfa_args_envpPPc_1;
-signed int _X17cfa_main_returnedi_1 = ((signed int )0);
+__attribute__ ((weak)) extern signed int _X17cfa_main_returnedi_1;
 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
     __attribute__ ((unused)) signed int _X12_retval_maini_1;
@@ -341,6 +341,9 @@
     signed int _tmp_cp_ret6;
     signed int _X3reti_2 = (((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6);
-    {
-        ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
+    if ( ((&_X17cfa_main_returnedi_1)!=((signed int *)0)) ) {
+        {
+            ((void)(_X17cfa_main_returnedi_1=((signed int )1)));
+        }
+
     }
 
Index: tests/.expect/random.arm64.txt
===================================================================
--- tests/.expect/random.arm64.txt	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/.expect/random.arm64.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,17 +1,17 @@
 õ
 =
-V
+K
 -911259971
 6
--4
+11
 1232105397
 0
-18
+11
 -914096085
 1
-15
+20
 2077092859
 1
-11
+12
 0.677254
 0.678106775246139
Index: tests/Makefile.am
===================================================================
--- tests/Makefile.am	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/Makefile.am	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -66,6 +66,6 @@
 PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
 
-.PHONY: list .validate
-.INTERMEDIATE: .validate .validate.cfa
+.PHONY: list .validate .test_makeflags
+.INTERMEDIATE: .validate .validate.cfa .test_makeflags
 EXTRA_PROGRAMS = avl_test linkonce .dummy_hack # build but do not install
 EXTRA_DIST = test.py \
@@ -123,4 +123,7 @@
 	@+${TEST_PY} --list ${concurrent}
 
+.test_makeflags:
+	@echo "${MAKEFLAGS}"
+
 .validate: .validate.cfa
 	$(CFACOMPILE) .validate.cfa -fsyntax-only -Wall -Wextra -Werror
Index: tests/collections/.expect/string-api-coverage-noshare.txt
===================================================================
--- tests/collections/.expect/string-api-coverage-noshare.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/collections/.expect/string-api-coverage-noshare.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,1 @@
+string-api-coverage.txt
Index: tests/collections/.expect/string-api-coverage.txt
===================================================================
--- tests/collections/.expect/string-api-coverage.txt	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/collections/.expect/string-api-coverage.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,3 +1,5 @@
 hello hello hello
+
+hello
 true false
 true false
Index: tests/collections/.expect/string-ctx-manage.txt
===================================================================
--- tests/collections/.expect/string-ctx-manage.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/collections/.expect/string-ctx-manage.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,7 @@
+hi
+bye
+hi
+bye
+hi
+bye
+done
Index: tests/collections/.expect/string-gc.txt
===================================================================
--- tests/collections/.expect/string-gc.txt	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/collections/.expect/string-gc.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -38,2 +38,13 @@
 x from 5 to 15
 y from 5 to 15
+======================== fillNoCompact
+about to expand, a = aaa
+expanded, a = aaa
+about to expand, a = aaa
+expanded, a = aaa
+about to expand, a = aaa
+expanded, a = aaa
+about to expand, a = aaa
+expanded, a = aaa
+about to expand, a = aaa
+expanded, a = aaa
Index: tests/collections/.expect/string-overwrite-noshare.txt
===================================================================
--- tests/collections/.expect/string-overwrite-noshare.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/collections/.expect/string-overwrite-noshare.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,1 @@
+string-overwrite.txt
Index: tests/collections/.expect/vector-err-pass-perm-it-byval.txt
===================================================================
--- tests/collections/.expect/vector-err-pass-perm-it-byval.txt	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/collections/.expect/vector-err-pass-perm-it-byval.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,3 +1,3 @@
-error: Unique best alternative includes deleted identifier in Generated Cast of:
+collections/vector-demo.cfa:95:1 error: Unique best alternative includes deleted identifier in Generated Cast of:
   Application of
     Deleted Expression
Index: tests/collections/string-api-coverage-noshare.cfa
===================================================================
--- tests/collections/string-api-coverage-noshare.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/collections/string-api-coverage-noshare.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,2 @@
+#define STRING_SHARING_OFF
+#include "string-api-coverage.cfa"
Index: tests/collections/string-api-coverage.cfa
===================================================================
--- tests/collections/string-api-coverage.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/collections/string-api-coverage.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,3 +1,4 @@
 #include <containers/string.hfa>
+#include <string_sharectx.hfa>
 
 void assertWellFormedHandleList( int maxLen ) { // with(HeapArea)
@@ -25,4 +26,9 @@
 
 int main () {
+
+    #ifdef STRING_SHARING_OFF
+    string_sharectx c = { NO_SHARING };
+    #endif
+
     string s = "hello";
     string s2 = "hello";
@@ -31,5 +37,11 @@
 
     // IO operator, x2
-    sout | s | s | s;
+    sout | s | s | s;  // hello hello hello
+
+    // empty ctor then assign
+    string sxx;
+    sout | sxx;  // (blank line)
+    sxx = s;
+    sout | sxx;  // hello
 
     // Comparisons
Index: tests/collections/string-ctx-manage.cfa
===================================================================
--- tests/collections/string-ctx-manage.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/collections/string-ctx-manage.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,79 @@
+#include <string.hfa>
+#include <string_sharectx.hfa>
+#include <string_res.hfa>
+
+// In these tests, shared heaps are never remotely full and string sizes are tiny.
+// So here, the SUT should put a yes-sharing string in a heap with lots of spare room.
+// The SUT should always keep a no-sharing string's buffer 1x--2x the string's size.
+// This check uses 3x as a heuristic split between those cases.
+void assertSpareRoomInHeap( string & s, bool expectOversized ) {
+    double bytesInHeap = DEBUG_string_bytes_in_heap(s.inner->Handle.ulink);
+    double bytesUsed =  s.inner->Handle.lnth;
+    double overhead = bytesInHeap / bytesUsed;
+    assert (overhead >= 1);
+    if ( expectOversized )
+        assert( overhead >= 3.0 );
+    else 
+        assert( overhead < 3.0 );
+}
+
+void baseline() {
+    string x = "hi";
+    assertSpareRoomInHeap( x, true );
+
+    string y = x; // construct y in same context, no write yet => no copy yet
+    assertSpareRoomInHeap( y, true );
+    assert( y.inner->Handle.s == x.inner->Handle.s);
+    sout | y; // hi
+
+    x = "bye";
+    assertSpareRoomInHeap( x, true );
+    y = x; // y in same context, no write yet => no copy yet
+    assertSpareRoomInHeap( y, true );
+    assert( y.inner->Handle.s == x.inner->Handle.s);
+    sout | y; // bye
+}
+
+void eagerCopy() {
+    string x = "hi";
+    assertSpareRoomInHeap( x, true );
+    string_sharectx c = { NEW_SHARING };
+
+    string y = x; // construct y in different context => eager copy
+    assertSpareRoomInHeap( y, true );
+    assert( y.inner->Handle.s != x.inner->Handle.s);
+    sout | y; // hi
+
+    x = "bye";
+    assertSpareRoomInHeap( x, true );
+    y = x; // y was already in different context => eager copy
+    assertSpareRoomInHeap( y, true );
+    assert( y.inner->Handle.s != x.inner->Handle.s);
+    sout | y; // bye
+}
+
+void soloAlloc() {
+    string x = "hi";
+    assertSpareRoomInHeap( x, true );
+    string_sharectx c = { NO_SHARING };
+    
+    string y = x; // y allocates into private pad, implying eager copy
+    assertSpareRoomInHeap( y, false );
+    assert( y.inner->Handle.s != x.inner->Handle.s);
+    sout | y; // hi
+
+    x = "bye";
+    assertSpareRoomInHeap( x, true );
+    y = x; // into private y => eager copy
+    assertSpareRoomInHeap( y, false );
+    assert( y.inner->Handle.s != x.inner->Handle.s);
+    sout | y; // bye
+}
+
+
+int main() {
+    baseline();
+    eagerCopy();
+    soloAlloc();
+    printf("done\n");
+}
Index: tests/collections/string-gc.cfa
===================================================================
--- tests/collections/string-gc.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/collections/string-gc.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -2,9 +2,9 @@
 
 size_t bytesRemaining() {
-    return DEBUG_string_bytes_avail_until_gc( DEBUG_string_heap );
+    return DEBUG_string_bytes_avail_until_gc( DEBUG_string_heap() );
 }
 
 size_t heapOffsetStart( string_res & s ) {
-    const char * startByte = DEBUG_string_heap_start( DEBUG_string_heap );
+    const char * startByte = DEBUG_string_heap_start( DEBUG_string_heap() );
     assert( s.Handle.s >= startByte );
     return s.Handle.s - startByte;
@@ -120,6 +120,34 @@
 }
 
+void fillNoCompact() {
+    // show that allocating in a heap filled with mostly live strings (no collectable garbage) causes heap growth
+
+    sout | "======================== fillNoCompact";
+
+    size_t lastTimeBytesAvail = bytesRemaining();
+    assert( lastTimeBytesAvail >= 200 ); // starting this test with nontrivial room
+
+    // mostly fill the pad
+    string_res a = "aaa";  // will have to be moved
+    string_res z = "zzz";
+    for (i; 5) {
+        while ( bytesRemaining() > 10 ) {
+            z += ".";
+        }
+        sout | "about to expand, a = " | a;
+        while ( bytesRemaining() <= 10 ) {
+            z += ".";
+        }
+        sout | "expanded, a = " | a;
+
+        // each growth gives more usable space than the last
+        assert( bytesRemaining() > lastTimeBytesAvail );
+        lastTimeBytesAvail = bytesRemaining();
+    }
+}
+
 int main() {
     basicFillCompact();
     fillCompact_withSharedEdits();
+    fillNoCompact();
 }
Index: tests/collections/string-overwrite-noshare.cfa
===================================================================
--- tests/collections/string-overwrite-noshare.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/collections/string-overwrite-noshare.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,2 @@
+#define STRING_SHARING_OFF
+#include "string-overwrite.cfa"
Index: tests/collections/string-overwrite.cfa
===================================================================
--- tests/collections/string-overwrite.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/collections/string-overwrite.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -1,3 +1,4 @@
 #include <containers/string.hfa>
+#include <string_sharectx.hfa>
 
 /*
@@ -11,5 +12,5 @@
 WE = witness end
 
-The dest does:
+The test does:
   starts with the entire string being, initially, the alphabet; prints this entire alphabet
   sets up modifier and witness as ranges within it, and prints a visualization of those ranges
@@ -24,4 +25,5 @@
 This API's convention has Start positions being inclusive and end positions being exclusive.
 
+                                v Case number in output
 With 1 equivalence class:
 MS = ME = WS = WE               1
@@ -118,5 +120,4 @@
     struct { int ms; int me; int ws; int we; char *replaceWith; char *label; } cases[] = {
         { 12, 14, 10, 20, "xxxxx", "warmup" },
-//        { 12, 14, 12, 14, "xxxxx", ""       },  // the bug that got me into this test (should be a dup with case 6)
         { 10, 10, 10, 10, "=====", "1"      },
         { 10, 10, 10, 10, "=="   , ""       },
@@ -223,10 +224,4 @@
         { 12, 14, 10, 16, "="    , ""       },
         { 12, 14, 10, 16, ""     , ""       },
-/*
-        { , , , , "=====", "NN"     },
-        {  "=="   , ""       },
-        {  "="    , ""       },
-        {  ""     , ""       },
-*/
     };
     for ( i; sizeof(cases)/sizeof(cases[0]) ) {
@@ -238,13 +233,11 @@
 
 
-// void f( string & s, string & toEdit ) {
-
-//     sout | s | "|" | toEdit | "|";
-
-//     s(14, 16) = "-";
-//     sout | s | "|" | toEdit | "|";
-// }
-
 int main() {
+
+    #ifdef STRING_SHARING_OFF
+    string_sharectx c = { NO_SHARING };
+    #endif
+
+
     //          0         1         2
     //          01234567890123456789012345
Index: tests/concurrent/.expect/keywordErrors.nast.txt
===================================================================
--- tests/concurrent/.expect/keywordErrors.nast.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/concurrent/.expect/keywordErrors.nast.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,6 @@
+concurrent/keywordErrors.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread A with body
+
+concurrent/keywordErrors.cfa:6:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread B with body
+
Index: tests/concurrent/.expect/keywordErrors.oast.txt
===================================================================
--- tests/concurrent/.expect/keywordErrors.oast.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/concurrent/.expect/keywordErrors.oast.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,6 @@
+concurrent/keywordErrors.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread A: with body 1
+
+concurrent/keywordErrors.cfa:6:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread B: with body 1
+
Index: sts/concurrent/.expect/keywordErrors.txt
===================================================================
--- tests/concurrent/.expect/keywordErrors.txt	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ 	(revision )
@@ -1,6 +1,0 @@
-concurrent/keywordErrors.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
-thread A: with body 1
-
-concurrent/keywordErrors.cfa:6:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
-thread B: with body 1
-
Index: tests/concurrent/.expect/mainError.nast.txt
===================================================================
--- tests/concurrent/.expect/mainError.nast.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/concurrent/.expect/mainError.nast.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,11 @@
+concurrent/mainError.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread Test with body
+
+concurrent/mainError.cfa:2:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+main: function
+... with parameters
+  reference to instance of struct Test with body
+... returning nothing
+ with body
+  Compound Statement:
+
Index: tests/concurrent/.expect/mainError.oast.txt
===================================================================
--- tests/concurrent/.expect/mainError.oast.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/concurrent/.expect/mainError.oast.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,11 @@
+concurrent/mainError.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread Test: with body 1
+
+concurrent/mainError.cfa:2:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+main: function
+... with parameters
+  reference to instance of struct Test with body 1
+... returning nothing
+... with body
+  CompoundStmt
+
Index: tests/concurrent/mainError.cfa
===================================================================
--- tests/concurrent/mainError.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/concurrent/mainError.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,2 @@
+thread Test {};
+void main(Test&) {}
Index: tests/concurrent/mutexstmt/.expect/locks.txt
===================================================================
--- tests/concurrent/mutexstmt/.expect/locks.txt	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/concurrent/mutexstmt/.expect/locks.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -3,6 +3,4 @@
 Start Test: multi lock deadlock/mutual exclusion
 End Test: multi lock deadlock/mutual exclusion
-Start Test: single scoped lock mutual exclusion
-End Test: single scoped lock mutual exclusion
-Start Test: multi scoped lock deadlock/mutual exclusion
-End Test: multi scoped lock deadlock/mutual exclusion
+Start Test: multi polymorphic lock deadlock/mutual exclusion
+End Test: multi polymorphic lock deadlock/mutual exclusion
Index: tests/concurrent/mutexstmt/.expect/scoped_lock.txt
===================================================================
--- tests/concurrent/mutexstmt/.expect/scoped_lock.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/concurrent/mutexstmt/.expect/scoped_lock.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,4 @@
+Start Test: single scoped lock mutual exclusion
+End Test: single scoped lock mutual exclusion
+Start Test: multi scoped lock deadlock/mutual exclusion
+End Test: multi scoped lock deadlock/mutual exclusion
Index: tests/concurrent/mutexstmt/locks.cfa
===================================================================
--- tests/concurrent/mutexstmt/locks.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/concurrent/mutexstmt/locks.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -3,4 +3,6 @@
 
 const unsigned int num_times = 10000;
+
+Duration default_preemption() { return 0; }
 
 single_acquisition_lock m1, m2, m3, m4, m5;
@@ -22,8 +24,18 @@
 }
 
+void refTest( single_acquisition_lock & m ) {
+	mutex ( m ) {
+		assert(!insideFlag);
+		insideFlag = true;
+		assert(insideFlag);
+		insideFlag = false;
+	}
+}
+
 thread T_Multi {};
 
 void main( T_Multi & this ) {
 	for (unsigned int i = 0; i < num_times; i++) {
+		refTest( m1 );
 		mutex ( m1 ) {
 			assert(!insideFlag);
@@ -59,14 +71,18 @@
 }
 
-thread T_Mutex_Scoped {};
+single_acquisition_lock l1;
+linear_backoff_then_block_lock l2;
+owner_lock l3;
 
-void main( T_Mutex_Scoped & this ) {
+monitor monitor_t {};
+
+monitor_t l4;
+
+thread T_Multi_Poly {};
+
+void main( T_Multi_Poly & this ) {
 	for (unsigned int i = 0; i < num_times; i++) {
-		{
-			scoped_lock(single_acquisition_lock) s{m1};
-			count++;
-		}
-		{
-			scoped_lock(single_acquisition_lock) s{m1};
+		refTest( l1 );
+		mutex ( l1, l4 ) {
 			assert(!insideFlag);
 			insideFlag = true;
@@ -74,13 +90,5 @@
 			insideFlag = false;
 		}
-	}
-}
-
-thread T_Multi_Scoped {};
-
-void main( T_Multi_Scoped & this ) {
-	for (unsigned int i = 0; i < num_times; i++) {
-		{
-			scoped_lock(single_acquisition_lock) s{m1};
+		mutex ( l1, l2, l3 ) {
 			assert(!insideFlag);
 			insideFlag = true;
@@ -88,10 +96,5 @@
 			insideFlag = false;
 		}
-		{
-			scoped_lock(single_acquisition_lock) s1{m1};
-			scoped_lock(single_acquisition_lock) s2{m2};
-			scoped_lock(single_acquisition_lock) s3{m3};
-			scoped_lock(single_acquisition_lock) s4{m4};
-			scoped_lock(single_acquisition_lock) s5{m5};
+		mutex ( l3, l1, l4 ) {
 			assert(!insideFlag);
 			insideFlag = true;
@@ -99,26 +102,5 @@
 			insideFlag = false;
 		}
-		{
-			scoped_lock(single_acquisition_lock) s1{m1};
-			scoped_lock(single_acquisition_lock) s3{m3};
-			assert(!insideFlag);
-			insideFlag = true;
-			assert(insideFlag);
-			insideFlag = false;
-		}
-		{
-			scoped_lock(single_acquisition_lock) s1{m1};
-			scoped_lock(single_acquisition_lock) s2{m2};
-			scoped_lock(single_acquisition_lock) s4{m4};
-			assert(!insideFlag);
-			insideFlag = true;
-			assert(insideFlag);
-			insideFlag = false;
-		}
-		{
-			scoped_lock(single_acquisition_lock) s1{m1};
-			scoped_lock(single_acquisition_lock) s3{m3};
-			scoped_lock(single_acquisition_lock) s4{m4};
-			scoped_lock(single_acquisition_lock) s5{m5};
+		mutex ( l1, l2, l4 ) {
 			assert(!insideFlag);
 			insideFlag = true;
@@ -131,9 +113,9 @@
 int num_tasks = 10;
 int main() {
-	processor p[10];
+	processor p[num_tasks - 1];
 
 	printf("Start Test: single lock mutual exclusion\n");
 	{
-		T_Mutex t[10];
+		T_Mutex t[num_tasks];
 	}
 	assert(count == num_tasks * num_times);
@@ -141,19 +123,11 @@
 	printf("Start Test: multi lock deadlock/mutual exclusion\n");
 	{
-		T_Multi t[10];
+		T_Multi t[num_tasks];
 	}
 	printf("End Test: multi lock deadlock/mutual exclusion\n");
-	
-	count = 0;
-	printf("Start Test: single scoped lock mutual exclusion\n");
+	printf("Start Test: multi polymorphic lock deadlock/mutual exclusion\n");
 	{
-		T_Mutex_Scoped t[10];
+		T_Multi_Poly t[num_tasks];
 	}
-	assert(count == num_tasks * num_times);
-	printf("End Test: single scoped lock mutual exclusion\n");
-	printf("Start Test: multi scoped lock deadlock/mutual exclusion\n");
-	{
-		T_Multi_Scoped t[10];
-	}
-	printf("End Test: multi scoped lock deadlock/mutual exclusion\n");	
+	printf("End Test: multi polymorphic lock deadlock/mutual exclusion\n");
 }
Index: tests/concurrent/mutexstmt/scoped_lock.cfa
===================================================================
--- tests/concurrent/mutexstmt/scoped_lock.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/concurrent/mutexstmt/scoped_lock.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,97 @@
+#include <mutex_stmt.hfa>
+#include <locks.hfa>
+#include <stats.hfa>
+
+const unsigned int num_times = 10000;
+
+single_acquisition_lock m1, m2, m3, m4, m5;
+
+bool insideFlag = false;
+int count = 0;
+
+thread T_Mutex_Scoped {};
+
+void main( T_Mutex_Scoped & this ) {
+	for (unsigned int i = 0; i < num_times; i++) {
+		{
+			scoped_lock(single_acquisition_lock) s{m1};
+			count++;
+		}
+		{
+			scoped_lock(single_acquisition_lock) s{m1};
+			assert(!insideFlag);
+			insideFlag = true;
+			assert(insideFlag);
+			insideFlag = false;
+		}
+	}
+}
+
+thread T_Multi_Scoped {};
+
+void main( T_Multi_Scoped & this ) {
+	for (unsigned int i = 0; i < num_times; i++) {
+		{
+			scoped_lock(single_acquisition_lock) s{m1};
+			assert(!insideFlag);
+			insideFlag = true;
+			assert(insideFlag);
+			insideFlag = false;
+		}
+		{
+			scoped_lock(single_acquisition_lock) s1{m1};
+			scoped_lock(single_acquisition_lock) s2{m2};
+			scoped_lock(single_acquisition_lock) s3{m3};
+			scoped_lock(single_acquisition_lock) s4{m4};
+			scoped_lock(single_acquisition_lock) s5{m5};
+			assert(!insideFlag);
+			insideFlag = true;
+			assert(insideFlag);
+			insideFlag = false;
+		}
+		{
+			scoped_lock(single_acquisition_lock) s1{m1};
+			scoped_lock(single_acquisition_lock) s3{m3};
+			assert(!insideFlag);
+			insideFlag = true;
+			assert(insideFlag);
+			insideFlag = false;
+		}
+		{
+			scoped_lock(single_acquisition_lock) s1{m1};
+			scoped_lock(single_acquisition_lock) s2{m2};
+			scoped_lock(single_acquisition_lock) s4{m4};
+			assert(!insideFlag);
+			insideFlag = true;
+			assert(insideFlag);
+			insideFlag = false;
+		}
+		{
+			scoped_lock(single_acquisition_lock) s1{m1};
+			scoped_lock(single_acquisition_lock) s3{m3};
+			scoped_lock(single_acquisition_lock) s4{m4};
+			scoped_lock(single_acquisition_lock) s5{m5};
+			assert(!insideFlag);
+			insideFlag = true;
+			assert(insideFlag);
+			insideFlag = false;
+		}
+	}
+}
+
+int num_tasks = 10;
+int main() {
+	processor p[10];
+
+	printf("Start Test: single scoped lock mutual exclusion\n");
+	{
+		T_Mutex_Scoped t[10];
+	}
+	assert(count == num_tasks * num_times);
+	printf("End Test: single scoped lock mutual exclusion\n");
+	printf("Start Test: multi scoped lock deadlock/mutual exclusion\n");
+	{
+		T_Multi_Scoped t[10];
+	}
+	printf("End Test: multi scoped lock deadlock/mutual exclusion\n");
+}
Index: tests/io/.expect/away_fair.txt
===================================================================
--- tests/io/.expect/away_fair.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/io/.expect/away_fair.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,12 @@
+starting
+100
+200
+300
+400
+500
+600
+700
+800
+900
+1000
+done
Index: tests/io/.expect/comp_fair.txt.disable
===================================================================
--- tests/io/.expect/comp_fair.txt.disable	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/io/.expect/comp_fair.txt.disable	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,12 @@
+starting
+100
+200
+300
+400
+500
+600
+700
+800
+900
+1000
+done
Index: tests/io/away_fair.cfa
===================================================================
--- tests/io/away_fair.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/io/away_fair.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,106 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2022 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// away_fair.cfa -- Test that spinning doesn't cause submissions to get stuck.
+//                  This test should work without io_uring but isn't very useful without
+//
+// Author           : Thierry Delisle
+// Created On       : Wed Mar 2 12:56:51 2022
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include <bits/defs.hfa>
+#include <fstream.hfa>
+#include <kernel.hfa>
+#include <thread.hfa>
+#include <iofwd.hfa>
+
+Duration default_preemption() {
+	return 0;
+}
+
+enum { TIMES = 1000 };
+
+volatile unsigned counter = 0;
+
+// ----- Spinner -----
+// spins trying to prevent other threads from getting to this processor
+thread Spinner {};
+void ^?{}(Spinner &mutex ) {}
+void main(Spinner &) {
+	unsigned last = 0;
+	for() {
+		unsigned curr = __atomic_load_n(&counter, __ATOMIC_SEQ_CST);
+
+		if(curr >= TIMES) return;
+
+		if(last == curr) {
+			Pause();
+			continue;
+		}
+
+		last = curr;
+		yield();
+	}
+}
+
+// ----- Submitter -----
+// try to submit io but yield so that it's likely we are moved to the slow path
+thread Submitter {};
+void ^?{}(Submitter &mutex ) {}
+void main(Submitter & this) {
+	for(TIMES) {
+		#if CFA_HAVE_LINUX_IO_URING_H
+			io_future_t f;
+			struct io_uring_sqe * sqe;
+			__u32 idx;
+			struct $io_context * ctx = cfa_io_allocate(&sqe, &idx, 1);
+
+			zero_sqe(sqe);
+			sqe->opcode = IORING_OP_NOP;
+			sqe->user_data = (uintptr_t)&f;
+		#endif
+
+		yield( prng( this, 15 ) );
+
+		#if CFA_HAVE_LINUX_IO_URING_H
+			// Submit everything
+			asm volatile("": : :"memory");
+			cfa_io_submit( ctx, &idx, 1, false );
+		#endif
+
+		unsigned i = __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST );
+		if(0 == (i % 100)) sout | i;
+
+		#if CFA_HAVE_LINUX_IO_URING_H
+			wait( f );
+		#endif
+	}
+}
+
+// ----- Yielder -----
+// Add some chaos into the mix
+thread Yielder {};
+void ^?{}(Yielder &mutex ) {}
+void main(Yielder&) {
+	while(TIMES > __atomic_load_n(&counter, __ATOMIC_SEQ_CST)) {
+		yield();
+	}
+}
+
+
+int main() {
+	processor p;
+	sout | "starting";
+	{
+		Yielder y;
+		Spinner s;
+		Submitter io;
+	}
+	sout | "done";
+}
Index: tests/io/comp_fair.cfa
===================================================================
--- tests/io/comp_fair.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/io/comp_fair.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,138 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2022 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// comp_fair.cfa -- Test that spinning doesn't cause completions to get stuck.
+//                  This test should work without io_uring but isn't very useful without
+//
+// Author           : Thierry Delisle
+// Created On       : Thu Mar 10 15:06:50 2022
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+
+#include <concurrency/locks.hfa>
+#include <fstream.hfa>
+#include <iofwd.hfa>
+#include <kernel.hfa>
+#include <thread.hfa>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+struct {
+      semaphore sem;
+      int pipe[2];
+
+} globals;
+
+Duration default_preemption() {
+	return 0;
+}
+
+enum { TIMES = 1000 };
+
+volatile unsigned counter = 0;
+
+
+// ----- Spinner -----
+// spins trying to prevent other threads from getting to this processor
+thread Spinner {};
+void main(Spinner &) {
+	unsigned last = 0;
+	for() {
+		unsigned curr = __atomic_load_n(&counter, __ATOMIC_SEQ_CST);
+
+		if(curr >= TIMES) return;
+
+		if(last == curr) {
+			Pause();
+			continue;
+		}
+
+		last = curr;
+		yield();
+	}
+}
+
+// ----- Reader -----
+// Reader from the pipe to test completion doesn't starve
+thread Reader {};
+void main(Reader & this) {
+      bool do_read = has_user_level_blocking( (fptr_t)async_read );
+
+      for(TIMES) {
+		yield( prng( this, 15 ) );
+
+            io_future_t f;
+            if ( do_read ) {
+                  char thrash[1];
+                  async_read(f, globals.pipe[0], thrash, 1, 0);
+            } else {
+                  fulfil(f, 0); // If we don't have user-level blocking just play along
+            }
+
+            P( globals.sem );
+
+            unsigned i = __atomic_add_fetch( &counter, 1, __ATOMIC_SEQ_CST );
+		if(0 == (i % 100)) sout | i;
+
+            wait( f );
+
+            if(f.result < 0)
+                  abort | "Read error" | -f.result | ":" | strerror(-f.result);
+      }
+
+      P( globals.sem );
+}
+
+// ----- Writer -----
+// Writes to the pipe so the Reader can unblock
+// takes its sweet time so the Reader has to block
+thread Writer {};
+void main(Writer & this) {
+      for(TIMES) {
+            yield( prng( this, 15 ) );
+
+            V( globals.sem );
+
+            sleep( 1`us );
+
+            char buf[1] = { '+' };
+            int ret = write( globals.pipe[1], buf, 1 );
+            if(ret < 0)
+                  abort | "Write error" | errno | ":" | strerror(errno);
+
+      }
+}
+
+// ----- Yielder -----
+// Add some chaos into the mix
+thread Yielder {};
+void ^?{}(Yielder &mutex ) {}
+void main(Yielder&) {
+	while(TIMES > __atomic_load_n(&counter, __ATOMIC_SEQ_CST)) {
+		yield();
+	}
+}
+
+int main() {
+      int ret = pipe(globals.pipe);
+      if(ret != 0)
+            abort | "Pipe error" | errno | ":" | strerror(errno);
+
+     	processor p;
+	sout | "starting";
+	{
+		Yielder y;
+		Spinner s;
+		Reader ior;
+            Writer iow;
+	}
+	sout | "done";
+}
Index: tests/io/many_read.cfa
===================================================================
--- tests/io/many_read.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/io/many_read.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// many_read.cfa -- Make sure that multiple concurrent reads to mess up.
+// many_read.cfa -- Make sure that multiple concurrent reads don't mess up.
 //
 // Author           : Thierry Delisle
Index: tests/meta/dumpable.cfa
===================================================================
--- tests/meta/dumpable.cfa	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/meta/dumpable.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -72,6 +72,8 @@
 	}
 
-	if((buf.f_bsize * buf.f_bavail) < 536870912) {
-		serr | "Available diskspace is less than ~500Mb: " | (buf.f_bsize * buf.f_bavail);
+	uint64_t avail = buf.f_bavail;
+	avail *= buf.f_bsize;
+	if(avail < 536870912_l64u) {
+		serr | "Available diskspace is less than ~500Mb: " | avail;
 	}
 
Index: tests/pybin/settings.py
===================================================================
--- tests/pybin/settings.py	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/pybin/settings.py	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -155,4 +155,5 @@
 	global generating
 	global make
+	global make_jobfds
 	global output_width
 	global timeout
@@ -168,4 +169,5 @@
 	generating   = options.regenerate_expected
 	make         = ['make']
+	make_jobfds  = []
 	output_width = 24
 	timeout      = Timeouts(options.timeout, options.global_timeout)
@@ -177,8 +179,11 @@
 		os.putenv('DISTCC_LOG', os.path.join(BUILDDIR, 'distcc_error.log'))
 
-def update_make_cmd(force, jobs):
+def update_make_cmd(flags):
 	global make
-
-	make = ['make'] if not force else ['make', "-j%i" % jobs]
+	make = ['make', *flags]
+
+def update_make_fds(r, w):
+	global make_jobfds
+	make_jobfds = (r, w)
 
 def validate():
@@ -187,15 +192,9 @@
 	global distcc
 	distcc       = "DISTCC_CFA_PATH=~/.cfadistcc/%s/cfa" % tools.config_hash()
-	errf = os.path.join(BUILDDIR, ".validate.err")
-	make_ret, out = tools.make( ".validate", error_file = errf, output_file=subprocess.DEVNULL, error=subprocess.DEVNULL )
+	make_ret, out, err = tools.make( ".validate", output_file=subprocess.PIPE, error=subprocess.PIPE )
 	if make_ret != 0:
-		with open (errf, "r") as myfile:
-			error=myfile.read()
 		print("ERROR: Invalid configuration %s:%s" % (arch.string, debug.string), file=sys.stderr)
-		print("       verify returned : \n%s" % error, file=sys.stderr)
-		tools.rm(errf)
+		print("       verify returned : \n%s" % err, file=sys.stderr)
 		sys.exit(1)
-
-	tools.rm(errf)
 
 def prep_output(tests):
Index: tests/pybin/tools.py
===================================================================
--- tests/pybin/tools.py	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/pybin/tools.py	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -23,5 +23,5 @@
 
 # helper functions to run terminal commands
-def sh(*cmd, timeout = False, output_file = None, input_file = None, input_text = None, error = subprocess.STDOUT, ignore_dry_run = False):
+def sh(*cmd, timeout = False, output_file = None, input_file = None, input_text = None, error = subprocess.STDOUT, ignore_dry_run = False, pass_fds = []):
 	try:
 		cmd = list(cmd)
@@ -65,22 +65,23 @@
 				**({'input' : bytes(input_text, encoding='utf-8')} if input_text else {'stdin' : input_file}),
 				stdout  = output_file,
-				stderr  = error
+				stderr  = error,
+				pass_fds = pass_fds
 			) as proc:
 
 				try:
-					out, _ = proc.communicate(
+					out, errout = proc.communicate(
 						timeout = settings.timeout.single if timeout else None
 					)
 
-					return proc.returncode, out.decode("latin-1") if out else None
+					return proc.returncode, out.decode("latin-1") if out else None, errout.decode("latin-1") if errout else None
 				except subprocess.TimeoutExpired:
 					if settings.timeout2gdb:
 						print("Process {} timeout".format(proc.pid))
 						proc.communicate()
-						return 124, str(None)
+						return 124, str(None), "Subprocess Timeout 2 gdb"
 					else:
 						proc.send_signal(signal.SIGABRT)
 						proc.communicate()
-						return 124, str(None)
+						return 124, str(None), "Subprocess Timeout 2 gdb"
 
 	except Exception as ex:
@@ -105,7 +106,7 @@
 		return (False, "No file")
 
-	code, out = sh("file", fname, output_file=subprocess.PIPE)
+	code, out, err = sh("file", fname, output_file=subprocess.PIPE)
 	if code != 0:
-		return (False, "'file EXPECT' failed with code {}".format(code))
+		return (False, "'file EXPECT' failed with code {} '{}'".format(code, err))
 
 	match = re.search(".*: (.*)", out)
@@ -190,5 +191,5 @@
 	]
 	cmd = [s for s in cmd if s]
-	return sh(*cmd, output_file=output_file, error=error)
+	return sh(*cmd, output_file=output_file, error=error, pass_fds=settings.make_jobfds)
 
 def make_recon(target):
@@ -241,10 +242,10 @@
 # move a file
 def mv(source, dest):
-	ret, _ = sh("mv", source, dest)
+	ret, _, _ = sh("mv", source, dest)
 	return ret
 
 # cat one file into the other
 def cat(source, dest):
-	ret, _ = sh("cat", source, output_file=dest)
+	ret, _, _ = sh("cat", source, output_file=dest)
 	return ret
 
@@ -289,33 +290,141 @@
 #               system
 ################################################################################
+def jobserver_version():
+	make_ret, out, err = sh('make', '.test_makeflags', '-j2', output_file=subprocess.PIPE, error=subprocess.PIPE)
+	if make_ret != 0:
+		print("ERROR: cannot find Makefile jobserver version", file=sys.stderr)
+		print("       test returned : {} '{}'".format(make_ret, err), file=sys.stderr)
+		sys.exit(1)
+
+	re_jobs = re.search("--jobserver-(auth|fds)", out)
+	if not re_jobs:
+		print("ERROR: cannot find Makefile jobserver version", file=sys.stderr)
+		print("       MAKEFLAGS are : '{}'".format(out), file=sys.stderr)
+		sys.exit(1)
+
+	return "--jobserver-{}".format(re_jobs.group(1))
+
+def prep_recursive_make(N):
+	if N < 2:
+		return []
+
+	# create the pipe
+	(r, w) = os.pipe()
+
+	# feel it with N-1 tokens, (Why N-1 and not N, I don't know it's in the manpage for make)
+	os.write(w, b'+' * (N - 1));
+
+	# prep the flags for make
+	make_flags = ["-j{}".format(N), "--jobserver-auth={},{}".format(r, w)]
+
+	# tell make about the pipes
+	os.environ["MAKEFLAGS"] = os.environ["MFLAGS"] = " ".join(make_flags)
+
+	# make sure pass the pipes to our children
+	settings.update_make_fds(r, w)
+
+	return make_flags
+
+def prep_unlimited_recursive_make():
+	# prep the flags for make
+	make_flags = ["-j"]
+
+	# tell make about the pipes
+	os.environ["MAKEFLAGS"] = os.environ["MFLAGS"] = "-j"
+
+	return make_flags
+
+
+def eval_hardware():
+	# we can create as many things as we want
+	# how much hardware do we have?
+	if settings.distribute:
+		# remote hardware is allowed
+		# how much do we have?
+		ret, jstr, _ = sh("distcc", "-j", output_file=subprocess.PIPE, ignore_dry_run=True)
+		return int(jstr.strip()) if ret == 0 else multiprocessing.cpu_count()
+	else:
+		# remote isn't allowed, use local cpus
+		return multiprocessing.cpu_count()
+
 # count number of jobs to create
-def job_count( options, tests ):
+def job_count( options ):
 	# check if the user already passed in a number of jobs for multi-threading
-	if not options.jobs:
-		make_flags = os.environ.get('MAKEFLAGS')
-		force = bool(make_flags)
-		make_jobs_fds = re.search("--jobserver-(auth|fds)=\s*([0-9]+),([0-9]+)", make_flags) if make_flags else None
-		if make_jobs_fds :
-			tokens = os.read(int(make_jobs_fds.group(2)), 1024)
-			options.jobs = len(tokens)
-			os.write(int(make_jobs_fds.group(3)), tokens)
-		else :
-			if settings.distribute:
-				ret, jstr = sh("distcc", "-j", output_file=subprocess.PIPE, ignore_dry_run=True)
-				if ret == 0:
-					options.jobs = int(jstr.strip())
-				else :
-					options.jobs = multiprocessing.cpu_count()
-			else:
-				options.jobs = multiprocessing.cpu_count()
+	make_env = os.environ.get('MAKEFLAGS')
+	make_flags = make_env.split() if make_env else None
+	jobstr = jobserver_version()
+
+	if options.jobs and make_flags:
+		print('WARNING: -j options should not be specified when called form Make', file=sys.stderr)
+
+	# Top level make is calling the shots, just follow
+	if make_flags:
+		# do we have -j and --jobserver-...
+		jobopt = None
+		exists_fds = None
+		for f in make_flags:
+			jobopt = f if f.startswith("-j") else jobopt
+			exists_fds = f if f.startswith(jobstr) else exists_fds
+
+		# do we have limited parallelism?
+		if exists_fds :
+			try:
+				rfd, wfd = tuple(exists_fds.split('=')[1].split(','))
+			except:
+				print("ERROR: jobserver has unrecoginzable format, was '{}'".format(exists_fds), file=sys.stderr)
+				sys.exit(1)
+
+			# read the token pipe to count number of available tokens and restore the pipe
+			# this assumes the test suite script isn't invoked in parellel with something else
+			tokens = os.read(int(rfd), 65536)
+			os.write(int(wfd), tokens)
+
+			# the number of tokens is off by one for obscure but well documented reason
+			# see man make for more details
+			options.jobs = len(tokens) + 1
+
+		# do we have unlimited parallelism?
+		elif jobopt and jobopt != "-j1":
+			# check that this actually make sense
+			if jobopt != "-j":
+				print("ERROR: -j option passed by make but no {}, was '{}'".format(jobstr, jobopt), file=sys.stderr)
+				sys.exit(1)
+
+			options.jobs = eval_hardware()
+			flags = prep_unlimited_recursive_make()
+
+
+		# then no parallelism
+		else:
+			options.jobs = 1
+
+		# keep all flags make passed along, except the weird 'w' which is about subdirectories
+		flags = [f for f in make_flags if f != 'w']
+
+	# Arguments are calling the shots, fake the top level make
+	elif options.jobs :
+
+		# make sure we have a valid number of jobs that corresponds to user input
+		if options.jobs < 0 :
+			print('ERROR: Invalid number of jobs', file=sys.stderr)
+			sys.exit(1)
+
+		flags = prep_recursive_make(options.jobs)
+
+	# Arguments are calling the shots, fake the top level make, but 0 is a special case
+	elif options.jobs == 0:
+		options.jobs = eval_hardware()
+		flags = prep_unlimited_recursive_make()
+
+	# No one says to run in parallel, then don't
 	else :
-		force = True
-
-	# make sure we have a valid number of jobs that corresponds to user input
-	if options.jobs <= 0 :
-		print('ERROR: Invalid number of jobs', file=sys.stderr)
-		sys.exit(1)
-
-	return min( options.jobs, len(tests) ), force
+		options.jobs = 1
+		flags = []
+
+	# Make sure we call make as expected
+	settings.update_make_cmd( flags )
+
+	# return the job count
+	return options.jobs
 
 # enable core dumps for all the test children
@@ -334,5 +443,5 @@
 	distcc_hash = os.path.join(settings.SRCDIR, '../tools/build/distcc_hash')
 	config = "%s-%s" % (settings.arch.target, settings.debug.path)
-	_, out = sh(distcc_hash, config, output_file=subprocess.PIPE, ignore_dry_run=True)
+	_, out, _ = sh(distcc_hash, config, output_file=subprocess.PIPE, ignore_dry_run=True)
 	return out.strip()
 
@@ -374,8 +483,12 @@
 
 	if not os.path.isfile(core):
-		return 1, "ERR No core dump (limit soft: {} hard: {})".format(*resource.getrlimit(resource.RLIMIT_CORE))
+		return 1, "ERR No core dump, expected '{}' (limit soft: {} hard: {})".format(core, *resource.getrlimit(resource.RLIMIT_CORE))
 
 	try:
-		return sh('gdb', '-n', path, core, '-batch', '-x', cmd, output_file=subprocess.PIPE)
+		ret, out, err = sh('gdb', '-n', path, core, '-batch', '-x', cmd, output_file=subprocess.PIPE)
+		if ret == 0:
+			return 0, out
+		else:
+			return 1, err
 	except:
 		return 1, "ERR Could not read core with gdb"
Index: tests/test.py
===================================================================
--- tests/test.py	(revision ef3c3833c4827da48ddf6e7ee029edbe59595593)
+++ tests/test.py	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -140,5 +140,5 @@
 	parser.add_argument('--regenerate-expected', help='Regenerate the .expect by running the specified tets, can be used with --all option', action='store_true')
 	parser.add_argument('--archive-errors', help='If called with a valid path, on test crashes the test script will copy the core dump and the executable to the specified path.', type=str, default='')
-	parser.add_argument('-j', '--jobs', help='Number of tests to run simultaneously', type=int)
+	parser.add_argument('-j', '--jobs', help='Number of tests to run simultaneously, 0 (default) for unlimited', nargs='?', const=0, type=int)
 	parser.add_argument('--list-comp', help='List all valide arguments', action='store_true')
 	parser.add_argument('--list-dist', help='List all tests for distribution', action='store_true')
@@ -195,5 +195,5 @@
 	# build, skipping to next test on error
 	with Timed() as comp_dur:
-		make_ret, _ = make( test.target(), output_file=subprocess.DEVNULL, error=out_file, error_file = err_file )
+		make_ret, _, _ = make( test.target(), output_file=subprocess.DEVNULL, error=out_file, error_file = err_file )
 
 	# ----------
@@ -208,5 +208,5 @@
 				if settings.dry_run or is_exe(exe_file):
 					# run test
-					retcode, _ = sh(exe_file, output_file=out_file, input_file=in_file, timeout=True)
+					retcode, _, _ = sh(exe_file, output_file=out_file, input_file=in_file, timeout=True)
 				else :
 					# simply cat the result into the output
@@ -226,5 +226,5 @@
 			else :
 				# fetch return code and error from the diff command
-				retcode, error = diff(cmp_file, out_file)
+				retcode, error, _ = diff(cmp_file, out_file)
 
 		else:
@@ -366,8 +366,8 @@
 			print(os.path.relpath(t.expect(), settings.SRCDIR), end=' ')
 			print(os.path.relpath(t.input() , settings.SRCDIR), end=' ')
-			code, out = make_recon(t.target())
+			code, out, err = make_recon(t.target())
 
 			if code != 0:
-				print('ERROR: recond failed for test {}'.format(t.target()), file=sys.stderr)
+				print('ERROR: recond failed for test {}: {} \'{}\''.format(t.target(), code, err), file=sys.stderr)
 				sys.exit(1)
 
@@ -417,4 +417,6 @@
 			if is_empty(t.expect()):
 				print('WARNING: test "{}" has empty .expect file'.format(t.target()), file=sys.stderr)
+
+	options.jobs = job_count( options )
 
 	# for each build configurations, run the test
@@ -430,9 +432,8 @@
 			local_tests = settings.ast.filter( tests )
 			local_tests = settings.arch.filter( local_tests )
-			options.jobs, forceJobs = job_count( options, local_tests )
-			settings.update_make_cmd(forceJobs, options.jobs)
 
 			# check the build configuration works
 			settings.validate()
+			jobs = min(options.jobs, len(local_tests))
 
 			# print configuration
@@ -440,5 +441,5 @@
 				'Regenerating' if settings.generating else 'Running',
 				len(local_tests),
-				options.jobs,
+				jobs,
 				settings.ast.string,
 				settings.arch.string,
@@ -450,5 +451,5 @@
 
 			# otherwise run all tests and make sure to return the correct error code
-			failed = run_tests(local_tests, options.jobs)
+			failed = run_tests(local_tests, jobs)
 			if failed:
 				if not settings.continue_:
Index: tests/zombies/string-perf/.gitignore
===================================================================
--- tests/zombies/string-perf/.gitignore	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/.gitignore	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,6 @@
+!Makefile
+perfexp-*
+make-corpus
+corpus-*.txt
+corpusx-*.txt
+measurement-*.csv
Index: tests/zombies/string-perf/Makefile
===================================================================
--- tests/zombies/string-perf/Makefile	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/Makefile	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,190 @@
+
+CFABUILD = ~/cfa2/build-perf
+LIBCFA = $(CFABUILD)/libcfa/*/src/.libs/libcfa.so
+
+CFA = $(CFABUILD)/driver/cfa
+PERFFLAGS_CFA = -nodebug -O2
+PERFFLAGS_CXX = -DNDEBUG -O2 -Wl,--no-as-needed -ldl
+
+
+# function: convert to upper case
+define uc
+$(shell echo $(1) | tr  '[:lower:]' '[:upper:]')
+endef
+
+# function: project numbered element of filename named by hyphen-delimited tuple
+# (call hyphProj,q-w-e-r.txt,1) is Q
+define ucHyphProj
+$(call uc,$(word $(2),$(subst -, ,$(basename $(1)))))
+endef
+
+# function: cross two lists, adding hyphen delimiters
+# (call hyphCross,a b c,1 2) is a-1 a-2 b-1 b-2 c-1 c-2
+define hyphCross
+$(foreach x,$(1),$(foreach xs,$(2),$(x)-$(xs)))
+endef
+
+define hyphCross3
+$(call hyphCross,$(1),$(call hyphCross,$(2),$(3)))
+endef
+
+define hyphCross4
+$(call hyphCross,$(1),$(call hyphCross3,$(2),$(3),$(4)))
+endef
+
+define hyphCross5
+$(call hyphCross,$(1),$(call hyphCross4,$(2),$(3),$(4),$(5)))
+endef
+
+OPERATIONS=pta peq pbv pall pno
+ALLOCS=reuse fresh
+CFA_APILEVELS=hl ll
+CFA_SHARINGS=share noshare
+PLATFORMS=cfa stl buhr94
+
+ifneq ($(filter cfa,$(PLATFORMS)),)
+    CFA_APIS=$(call hyphCross,$(CFA_APILEVELS),$(CFA_SHARINGS))
+endif
+
+ifneq ($(filter stl,$(PLATFORMS)),)
+    STL_APIS=na-na
+endif
+
+ifneq ($(filter buhr94,$(PLATFORMS)),)
+    BUHR94_APIS=na-na
+endif
+
+APIS = $(CFA_APIS) $(STL_APIS) $(BUHR94_APIS)
+
+OPERATIONS_USING_ALLOCS=pta peq
+define enrichOperationsAllocs
+$(call hyphCross3,$(filter peq pta,$(OPERATIONS)),$(1),$(ALLOCS)) $(call hyphCross3,$(filter-out peq pta,$(OPERATIONS)),$(1),na)
+endef
+
+CFA_PERFPROGS=$(call hyphCross,perfexp-cfa,$(call enrichOperationsAllocs,$(CFA_APIS)))
+STL_PERFPROGS=$(call hyphCross,perfexp-stl,$(call enrichOperationsAllocs,$(STL_APIS)))
+BUHR94_PERFPROGS=$(call hyphCross,perfexp-buhr94,$(call enrichOperationsAllocs,$(BUHR94_APIS)))
+
+PERFPROGS = $(CFA_PERFPROGS) $(STL_PERFPROGS) $(BUHR94_PERFPROGS)
+
+all : $(PERFPROGS)
+
+PP_SPLIT := $(shell echo "${PERFPROGS}" | sed -e 's/ /\\n/g')
+echoPerfProgs:
+	echo -e '$(PP_SPLIT)'
+
+perfexp-%.o: API=$(call ucHyphProj,$@,2)
+perfexp-%.o: OPERATION=$(call ucHyphProj,$@,3)
+perfexp-%.o: CFA_APILEVEL=$(call ucHyphProj,$@,4)
+perfexp-%.o: CFA_SHARING=$(call ucHyphProj,$@,5)
+perfexp-%.o: ALLOC=$(call ucHyphProj,$@,6)
+perfexp-%.o: SCENARIO_SWITCH=-DIMPL_$(API)_$(CFA_APILEVEL)_$(CFA_SHARING) -DOP_$(OPERATION) -DALLOC_$(ALLOC)
+
+perfexp-cfa-%.o: CMD=$(CFA) -c $(PERFFLAGS_CFA) $< -o $@ $(SCENARIO_SWITCH)
+perfexp-stl-%.o: CMD=$(CXX) -c -xc++ $(PERFFLAGS_CXX) $< -o $@ $(SCENARIO_SWITCH)
+perfexp-buhr94-%.o: CMD=$(CXX) -xc++ -c $(PERFFLAGS_CXX) $< -o $@ $(SCENARIO_SWITCH)
+
+perfexp-cfa-peq-%.o: prog.cfa $(LIBCFA)
+	$(CMD)
+perfexp-cfa-pta-%.o: prog.cfa $(LIBCFA)
+	$(CMD)
+perfexp-cfa-pbv-%.o: prog-passbyval.cfa $(LIBCFA)
+	$(CMD)
+perfexp-cfa-pb%.o: prog-passbyX.cfa $(LIBCFA)
+	$(CMD)
+perfexp-cfa-pfi-%.o: prog-find.cfa $(LIBCFA)
+	$(CMD)
+perfexp-cfa-pall-%.o: prog-allocn.cfa $(LIBCFA)
+	$(CMD)
+perfexp-cfa-pno-%.o: prog-normalize.cfa $(LIBCFA)
+	$(CMD)
+perfexp-stl-peq-%.o: prog.cfa
+	$(CMD)
+perfexp-stl-pta-%.o: prog.cfa
+	$(CMD)
+perfexp-stl-pbv-%.o: prog-passbyval.cfa
+	$(CMD)
+perfexp-stl-pfi-%.o: prog-find.cfa
+	$(CMD)
+perfexp-stl-pall-%.o: prog-allocn.cfa
+	$(CMD)
+perfexp-stl-pno-%.o: prog-normalize.cfa
+	$(CMD)
+perfexp-buhr94-peq-%.o: prog.cfa buhr94-string.o buhr94-VbyteSM.o
+	$(CMD)
+perfexp-buhr94-pta-%.o: prog.cfa buhr94-string.o buhr94-VbyteSM.o
+	$(CMD)
+perfexp-buhr94-pta-%.o: prog-passbyval.cfa buhr94-string.o buhr94-VbyteSM.o
+	$(CMD)
+perfexp-buhr94-pall-%.o: prog-allocn.cfa buhr94-string.o buhr94-VbyteSM.o
+	$(CMD)
+perfexp-buhr94-pno-%.o: prog-normalize.cfa buhr94-string.o buhr94-VbyteSM.o
+	$(CMD)
+
+# one of the pbx cases also needs to link with not_string_res.o (handling manually)
+perfexp-cfa-%: perfexp-cfa-%.o $(LIBCFA)
+	$(CFA) $(PERFFLAGS_CFA) $< -o $@  
+perfexp-stl-%: perfexp-stl-%.o $(LIBCFA)
+	$(CFA) $(PERFFLAGS_CFA) $< /lib/x86_64-linux-gnu/libstdc++.so.6 -o $@
+perfexp-buhr94-% : perfexp-buhr94-%.o buhr94-string.o buhr94-VbyteSM.o
+	$(CXX) $(PERFFLAGS_CXX) $^ -o $@
+
+buhr94-string.o:
+	$(CXX) -xc++ -c $(PERFFLAGS_CXX) ~/usys1/sm/string/StringSharing/src/string.cc -o $@
+
+buhr94-VbyteSM.o:
+	$(CXX) -xc++ -c $(PERFFLAGS_CXX) ~/usys1/sm/string/StringSharing/src/VbyteSM.cc -o $@
+
+clean:
+	rm -f *.o perfexp*
+
+MEASURE = $(PERFPROGS)
+CORPORI = corpus-100-*-1.txt
+
+measurement: $(MEASURE)
+	tofile=measurement-`date '+%F--%H-%M-%S'`.csv ; \
+	echo $$tofile ; \
+	for prog in $(MEASURE) ; do \
+	    for corpus in $(CORPORI) ; do \
+			corpusbody=`cat $$corpus` ; \
+			printed=`./$$prog 100 10 $$corpusbody` ; \
+			echo $$prog,$$corpus,$$printed  >>  $$tofile ; \
+			echo $$prog,$$corpus,$$printed  ; \
+		done ; \
+	done
+#			printed=`./$$prog 10000 - 10 $$corpusbody` ; \
+
+CFA_EXPANSIONS=0.02 0.05 0.1 0.2 0.5 0.9
+
+measurement2: $(MEASURE)
+	tofile=measurement-`date '+%F--%H-%M-%S'`.csv ; \
+	for prog in $(MEASURE) ; do \
+	    for corpus in $(CORPORI) ; do \
+			for expansion in $(CFA_EXPANSIONS) ; do \
+				corpusbody= ; \
+				echo ./$$prog 1000 1.006 $$expansion 10 \`cat $$corpus\` ; \
+			done ; \
+		done ; \
+	done ; \
+	echo $$tofile ; \
+	for prog in $(MEASURE) ; do \
+	    for corpus in $(CORPORI) ; do \
+			for expansion in $(CFA_EXPANSIONS) ; do \
+				corpusbody=`cat $$corpus` ; \
+				printed=`./$$prog 1000 1.006 $$expansion 10 $$corpusbody` ; \
+				echo $$prog,$$corpus,$$expansion,$$printed  >>  $$tofile ; \
+				echo $$prog,$$corpus,$$expansion,$$printed  ; \
+			done ; \
+		done ; \
+	done
+
+measurement3: $(MEASURE)
+	for prog in $(MEASURE) ; do \
+	    for corpus in $(CORPORI) ; do \
+			for expansion in $(CFA_EXPANSIONS) ; do \
+				corpusbody=`cat $$corpus` ; \
+				LD_PRELOAD=~/plg2/mubeen-stat-shim/malloc/mallocWrappers.so ./$$prog 1000 1.006 $$expansion 1 $$corpusbody ; \
+				mv preload_dump.txt preload_dump--qrun1--$$corpus--expansion-$$expansion.txt ; \
+			done ; \
+		done ; \
+	done
Index: tests/zombies/string-perf/corpori-about.txt
===================================================================
--- tests/zombies/string-perf/corpori-about.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpori-about.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,9 @@
+corpus-100-* are for general-purpose mixed tests
+corpus-1-* are single-item corpori, for running exact-length variations  (made by hand with a clipboard)
+corpusx-* are purposed for getting started with the "normalize" test, using randomness to have rare -s, yet awkwardly avoiding SSO with min-length 16
+          x means 1% -s
+
+IIRC, ./make-corpus 100 20           DROVE    corpus-100-20-1.txt
+ergo, ./make-corpus 100 5 15 0.01    IS FOR   corpusx-100-20-1.txt
+
+./make-corpus 100 5 15 0.01  >  corpusx-100-20-1.txt
Index: tests/zombies/string-perf/corpus-100-1-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-1-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpus-100-1-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,100 @@
+t
+w
+m
+k
+b
+n
+x
+n
+a
+s
+g
+f
+a
+g
+p
+l
+b
+l
+g
+f
+f
+i
+n
+q
+l
+t
+k
+p
+g
+p
+o
+j
+p
+e
+t
+i
+f
+h
+r
+k
+l
+w
+f
+j
+m
+o
+g
+s
+w
+t
+j
+u
+v
+n
+g
+s
+h
+r
+g
+g
+g
+t
+v
+k
+o
+m
+j
+r
+m
+x
+j
+o
+m
+i
+n
+n
+k
+i
+x
+c
+b
+o
+v
+v
+q
+g
+r
+t
+d
+y
+t
+m
+v
+o
+t
+i
+h
+i
+h
+r
Index: tests/zombies/string-perf/corpus-100-10-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-10-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpus-100-10-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,100 @@
+arffxh
+qx
+fbfnvxvw
+ktcfgonnoklj
+eqqe
+ywvjewor
+pqrqdnuj
+kyjbjvmwcdpibqfyam
+rgshymadcvmxilijw
+vvkb
+secaddobw
+veuk
+ama
+k
+autadrvnukiymlerahoxduvnava
+ln
+ni
+nme
+cywlbjwfe
+nsxqqthqrj
+dwk
+iwhw
+t
+cskdfjljlyej
+ufynwlldivusu
+pxbpdtcgy
+tkasrjlmqmdnxosjmpckusivilr
+utboebivmv
+diotjfms
+dueapnvabpnvjo
+osv
+ftal
+ofnvtgqyewytkwwmnkkwbxnvtdcndpsuwisqrj
+vhrrtpoifbtefruboafeduwargtjxfcvovplnhtu
+pankwp
+wufcsfdklyvlga
+vwyjmgfirxkfihwl
+uqinvnajmwutygrxgbloivgggmqplcvitevps
+chvydugutmxhbjdipjwhyk
+utdbrvtq
+e
+whmdfgrfpv
+sgfedmfpxaje
+ecawaemylyfqhy
+wunr
+svgh
+widimg
+o
+mqk
+ryxyphyo
+vdxaxtggwfoaobidrrpieqcdqctxbkeyncymxg
+unlweogi
+xaqctsgku
+lx
+pxduwrufoqtanxo
+iutllyfghrcld
+avxfsx
+nfngynu
+es
+bpxo
+fv
+xxldxl
+ytryu
+ejogyligfuhutw
+bsjyqwdqier
+ysahx
+vgmkq
+pldm
+axjsjk
+gpequwv
+pxdplbxxnot
+dwpm
+px
+yjffy
+wviutbsyqgd
+eqixunwm
+vdyneis
+kfjin
+doyci
+halykmv
+jkagnbvu
+rfywojm
+mctrmbyo
+ayyvxlh
+rwe
+rqhyrgpbtkqx
+ikhjyw
+axkbjrbbrhtlx
+lpkbtgokgwushetestceumxy
+pg
+chppyassihdqfxjmfdsxy
+cujbvcscnwjfmlhiepr
+gygrn
+ugmueqrprptnrkkepap
+ivp
+eycnqpboypjdhdub
+rqm
+cst
+ktohkqnjsd
+lhqkwcpgfmkaebpifi
Index: tests/zombies/string-perf/corpus-100-2-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-2-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpus-100-2-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,100 @@
+q
+yc
+by
+e
+wt
+od
+ev
+v
+c
+gjhk
+xla
+t
+u
+e
+q
+v
+e
+c
+h
+e
+dt
+icsppbpddi
+ge
+lbrv
+hbil
+ssq
+y
+g
+p
+yf
+p
+j
+i
+ejb
+baciblv
+g
+d
+qpo
+f
+b
+vqvfr
+v
+n
+cq
+e
+cr
+qx
+ve
+luht
+j
+hcc
+vil
+xmw
+m
+r
+x
+f
+g
+c
+pwv
+k
+p
+mu
+k
+x
+eke
+winogdv
+l
+ja
+i
+btgs
+u
+b
+t
+l
+l
+s
+biajn
+paxy
+piy
+e
+kud
+vl
+w
+t
+q
+tt
+vd
+us
+u
+mldo
+h
+oc
+paol
+oihhxe
+x
+gkwby
+v
+g
+b
Index: tests/zombies/string-perf/corpus-100-20-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-20-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpus-100-20-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,100 @@
+wlgfygaqsdfmqvcygkiyaasjonymuarrnaamiadd
+krvjuwrhgqjgmvwaujuudplgpxo
+euwomuajssryjd
+v
+ey
+nvtslfydfquj
+tbxpbiitchgfoehs
+fiaydngdrmv
+xhjyhbbrjwtsdcjilensmnupebuvpqkoavniwqaiowbt
+mcmqqffgcxkeuivmvkoryypr
+xgycbaofoixvphyntfjdbxyomspmihojqpnrreyimxgdhhsbmcgqcffpyuejc
+ssmgmel
+oamuftdywrdekgjpxkmewrbpmnyatmoiodduyitvdyanhmefwsltkmmxcnavaoeotklsuhqxhrmoeswdlixwxmuaa
+wcndshpfclmsltkalqsiuhqueohbrjxollreukjwvyr
+sfkevdoskgnqwwtoitfthabekmbilvrhbc
+yib
+ujgoigiaofhlmhorrbuap
+uwtw
+thnmdyurkdckuhtg
+cuovxj
+pdtmyqasynhenfvxkxkfigldiitfjdgyia
+isodtclxrsvrdwejflwktiebrjhqsjfddvgyytxs
+v
+sspcxd
+ixjobbylutwcwayfaacauqvgjrynpcpbcy
+gdqtxmqcjtbrvdtvykthwlikenchpeyxhs
+hfljrfnldsfbrruaqjiepxgyokaotujbbwnuebghtniohfqyqbfialh
+ykfufqyinmdtplblylcj
+skkwpvwdfpepuavobeepkyhvc
+v
+xhksrup
+sokyerocrmq
+twkevraymxpkfagwwvgqltrplirfvkari
+vg
+vhqwwecykcygirtejmprgup
+whcjdi
+cqhbpl
+rxhqgsidwrpplvmcpklrvrdktvtwnhcffkvnfgqexgtmfhou
+cpptscnoxmcfpkm
+gbhnrlnyiagpqbltqdnlgeceqfmgryixarnugevogcgxdrtwujidnlkhswpkvbkysbtyfpnlr
+lwnfvlphofsyonvfaugmtbppdufsjypwxdduoucgcwfrmew
+yfbuirklorfaquxqadnrxpxc
+ftdjsriav
+jpnuefahxwf
+xifrixpkouhshakpdivmx
+j
+rmmrjtljcrbmrsygqgyxjmpmulbtx
+yrwnjhhxslpwxjpwpiepgpeycykduintaljmuqkpccmalfadng
+w
+yvayiftrsqtgaidt
+tvyiymnyqeh
+ddlbdkjigddwamairtgnpfwqsk
+l
+wwtciuhufpckvbkkbvcucqnjneeawp
+vpnb
+jivqbadwdohfmlcocrarwhuvwmroc
+p
+e
+efpicsylalwdccuevtlqrlfm
+ihpvlfdqunuomi
+aite
+rkgnwagi
+sknadmmipfedburjlrrixe
+inphnvrso
+jriv
+qllwomtgygasoaxqilgsbdkttpfnxbtrogqdullttnnknnbybj
+cmexjuew
+frowagcutorneh
+sudtvmlxcrxlmckkkeyhehjc
+atqfbqxxttvhft
+wrwmwjyhoxougayjbsbgvtgtqapahllggkufttmku
+ibdhmgdnoy
+wvbwndgcopkykpuheich
+fmarvfikhuifvhsyqwpghqsylcdvgmoncri
+wqkgns
+jdhkteccoswpgavfgitumnd
+nvxtjsguvphrtjtketbmtwrchoyucehpchmnbuiykrrgdnrjhuw
+toibdhxgoixq
+mfs
+psrkmbnasxkpwn
+lxmpglxwvxnnl
+hsncnxoon
+jnbbkrkwpwoxkmuiklwxigtvihvyxkpjarkllwkbvychnyramq
+vwsthcqi
+dyldsxoeuyhqajanjsqvjrtjkosofcqibclvadauejnftoufj
+dufaepoagvcwgfbtbbwdxemolidgpmuvjavoskqyisyoaakde
+geousaexitmdpwgnnbxeciwbwyeicisimjfijjgrgtxxqgoehmilxhpugtfkeausjabumipucnuutjbdyjqwsgtbcalgcgaoiblulbppolkkulntwfqpnlsqnewrm
+ivbuqmvjdnupxreoobvftlsmcitcdgbleeixr
+h
+ueouxsl
+uhuqtndxyyacgenmiwkce
+ybaqvyjiler
+unwbmxaoaispvcmigsfgtfysgidsnubklalxxooawiqumfgsylbusapa
+ssyqvlcy
+cyoqcnbslpxrjydmwvnmvyiqxypldqlfpaxrq
+mcrntdoyqlwgbvflo
+kgqpwfwpf
+jxywatkvwbwnpuvqsbchioocgnhddoannakptwmsxjjngfgyhkjrbathnbkrsnhgprvjqkequnf
+tnfdyoucqrkeuwxnkftayslpdqhxgoeacjdd
+biossun
Index: tests/zombies/string-perf/corpus-100-5-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-5-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpus-100-5-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,100 @@
+hsiq
+erkpoqlew
+tpgsfigwyn
+tbpuf
+nns
+ukakbqxhnob
+wvlhckh
+wdvoyc
+orjemthy
+xweonftkbh
+gs
+yrfujgy
+xr
+e
+fl
+c
+d
+drnwcqhwwc
+xv
+tfp
+hnmsutaiaew
+maw
+aa
+h
+qlbphi
+nx
+wo
+qlpqtpv
+uitslvsf
+tvqunydboe
+lugegvvcntvic
+bpo
+uuqtnl
+mrldxvrs
+v
+atfn
+cxswa
+nxg
+oaydjnu
+rusjnwh
+ycvo
+an
+wptlnaxdcwilldl
+aeqpe
+gfaeu
+fidc
+y
+ny
+qb
+ypbebgg
+w
+nxctx
+o
+oywsyvj
+xa
+bnh
+povxugvtt
+v
+tfgnvfm
+gkbtib
+mqlf
+achxi
+reb
+uwxbmtjyj
+mklwn
+jf
+p
+ctwacerif
+d
+gfrcqtmggysd
+i
+u
+fknbkpfo
+nw
+rcb
+vd
+pr
+vtqahcpemwqax
+qfsbsrvmvwlrcdiw
+gq
+iawxg
+w
+mwbf
+vivpeil
+wficp
+gwvc
+xbgelfbbdeif
+rd
+vofcnlkpdpwcnb
+ncs
+qxur
+acjctousdau
+nfjr
+gvmj
+al
+reamxdobo
+ue
+njoibdpkw
+ssbccbpduufkslyvasr
+hfq
Index: tests/zombies/string-perf/corpus-5-20-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-5-20-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpus-5-20-1.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,5 @@
+xtprjlkvxoha
+fwjvjxlhetotwuvrrkplahwm
+tmjdpckmmgwmtgqpwnpsjhktwyvhvkbpakuppfccoboijhbhu
+agxkcwlyeilialuvbkbgopjfbtpcbmsbtsnxpaywklhk
+cibpmhges
Index: tests/zombies/string-perf/corpus-5-20-2.txt
===================================================================
--- tests/zombies/string-perf/corpus-5-20-2.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpus-5-20-2.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,5 @@
+cyvgqodbfmnkefjurrjmfloimkldtmcxlafcqkfwxuhe
+sbulkjsvydklonfb
+dotktl
+ykvwtaymbvalgsjfwwqnkxrfdgb
+amma
Index: tests/zombies/string-perf/corpus-5-20-3.txt
===================================================================
--- tests/zombies/string-perf/corpus-5-20-3.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/corpus-5-20-3.txt	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,5 @@
+otado
+drymnkbfofeqkjbythdtprmnjbikhwfmre
+fpdmgiqw
+a
+twhxqwrenbhvnqusgma
Index: tests/zombies/string-perf/make-corpus.cfa
===================================================================
--- tests/zombies/string-perf/make-corpus.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/make-corpus.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,87 @@
+#include <stdlib.hfa>
+#include <math.h>
+#include <limits.h>
+#include <unistd.h>
+#include <string.h>
+
+// U(0,1)
+static double U() {
+    return (double)rand() / (double)INT_MAX;
+}
+
+// generate random draws from a geometric distribution of the given mean
+// https://math.stackexchange.com/questions/485448/prove-the-way-to-generate-geometrically-distributed-random-numbers
+static double denom;
+static void initialize(int mean) {
+    srand(getpid());
+    double p = 1.0 / (double) mean;
+    denom = log(1-p);
+}
+static int nextGeoRand() {
+    // ret = ⌊ln(U)/ln(1−p)⌋ where U ~ U(0, 1)
+    return 1 + (int) (log(U()) / denom);
+}
+
+// write a randomly generated alphabetic string whose length is adjused from a draw of the above distribution
+static void emit1( int offset, double mcfreq, char mchar ) {
+    int lim = offset + nextGeoRand();
+    // printf("==%d\n", lim);
+    for (i; lim) {
+        char emit;
+        if (U() < mcfreq) emit = mchar;
+        else emit = 'a' + (rand() % ('z'-'a'));
+        printf("%c", emit);
+    }
+    printf("\n");
+}
+
+// usage: ./make-corpus toGen mean [offset=0] [mcfreq=0.0] [mchar='-']
+//
+// Outputs alphabetic (plus magic-char) strings, one per line.
+// toGen: number of strings (lines)
+// 
+// generated length ~  offset + geo(mean)
+//                  >= 1
+//
+// offset=0,  mean=1:  constant length 1
+// offset=0,  mean=2:  lengths go like number of coin tosses it takes to get heads
+// offset=0,  mean=6:  lengths go like number of cube die rolls it takes to get :::
+// offset=15, mean=1:  constant length 16
+// offset=15, mean=2:  population's minimum is 16 and mean is 17
+//
+// Magic Char (mc) does not affect these lengths.  Any mc occurrence replaces an alphabetic char.
+// mcfreq: (in [0,1]) expected fraction of the characters output that are mchar
+//
+int main(int argc, char ** argv) {
+
+    int toGen;
+    int mean;
+    int offset = 0;
+    double mcfreq = 0.0;
+    char mchar = '-';
+
+    assert(argc >= 3 && argc <= 6);
+    switch(argc) {
+        case 6:
+            assert(strlen(argv[5]) == 0);
+            mchar = argv[5][0];
+        case 5:
+            mcfreq = atof(argv[4]);
+            assert(mcfreq >= 0.0 && mcfreq <= 1.0);
+        case 4:
+            offset = atoi(argv[3]);
+            assert(offset >= 0 && offset < 10000);
+        default:
+            mean = atoi(argv[2]);
+            assert(mean > 0);
+            assert(mean < 1000);
+            toGen = atoi(argv[1]);
+            assert(toGen > 0);
+            assert(toGen < 1000000);
+    }
+
+    initialize(mean);
+    for( i; toGen ) {
+        emit1(offset, mcfreq, mchar);
+    }
+}
Index: tests/zombies/string-perf/make-flamegraph.sh
===================================================================
--- tests/zombies/string-perf/make-flamegraph.sh	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/make-flamegraph.sh	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# $1 is SUT id     : stl-pall-na-na-na
+# $2 is CLI middle : 1000 1.006 0.1 -w 10000000
+# $3 is corpus id  : -1-500-1  (goes with corpus-1-500-1.txt)
+#
+# usage for that example:   ./make-flamegraph.sh cfa-pall-ll-share-na '1000 1.006 0.1 -w 10000000' -1-500-1
+#
+# another
+# $3 is coprus id  : x-100-20-1  (goes with corpusx-100-20-1.txt)
+
+SLUG=perf--$1--${2//[ .]/-}--$3
+
+perf record --call-graph dwarf -m16M ~/plg2/cfa2/cfa-cc/tests/zombies/string-perf/perfexp-$1 $2 `cat ~/plg2/cfa2/cfa-cc/tests/zombies/string-perf/corpus$3.txt`
+
+mv perf.data $SLUG.data
+perf script -i $SLUG.data > $SLUG.perf
+../flamegraph/FlameGraph/stackcollapse-perf.pl $SLUG.perf > $SLUG.folded
+../flamegraph/FlameGraph/flamegraph.pl $SLUG.folded > $SLUG.svg
+cp $SLUG.svg ~/plg2/flames
Index: tests/zombies/string-perf/not_string_res.cfa
===================================================================
--- tests/zombies/string-perf/not_string_res.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/not_string_res.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,5 @@
+#include <string_res.hfa>
+#include "not_string_res.hfa"
+
+void ?{}( not_string_res & this, const string_res & src, StrResInitMode, size_t start, size_t end ) {}
+void ^?{}( not_string_res & this ) {}
Index: tests/zombies/string-perf/not_string_res.hfa
===================================================================
--- tests/zombies/string-perf/not_string_res.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/not_string_res.hfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,6 @@
+struct not_string_res {
+    size_t junk[7];
+};
+
+void ?{}( not_string_res & this, const string_res & src, StrResInitMode, size_t start, size_t end );
+void ^?{}( not_string_res & this );
Index: tests/zombies/string-perf/pbx-correctness-demos.cfa
===================================================================
--- tests/zombies/string-perf/pbx-correctness-demos.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/pbx-correctness-demos.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,206 @@
+// see also C++ investigation in ~/plg2/cfa2/mycode/string/raii/ctor-calls.cpp
+
+#include <string.hfa>
+#include <string_res.hfa>
+
+/*
+call_substrOfPart:
+    In all cases, of both HL and LL, there is a temporary object.
+    It represents narrowing the range, from full-string, to [1..3].
+    The only matter to control is whether that temporary shares edits with the string from which it was created.
+    In HL, two knobs control it, and the 
+*/
+
+void calltest_HL() {
+
+    #define HELPER_BODY(param) \
+        sout | "early in helper with " | param; \
+        param[0] = '+'; \
+        sout | "late in helper with " | param;
+
+    void helper1( string   q ) { HELPER_BODY(q) }
+    void helper2( string & q ) { HELPER_BODY(q) }
+    #undef HELPER_BODY
+
+    string fred;
+
+
+    sout | "===";
+    sout | "HL: substring of part";
+
+    sout | "---";
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper1( fred(1,3) );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, sys-style, in which we want to gets its changes as side effects.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( fred(1,3) );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, trans-style, in which we give it a logical copy, to prevent it from pulluting our gold one.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( (string){ fred(1,3) } );
+    sout | "after helper with " | fred;
+
+
+    sout | "===";
+    sout | "HL: substring of whole";
+
+    sout | "---";
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper1( fred(0,4) );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, sys-style, in which we want to gets its changes as side effects.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( fred(0,4) );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, trans-style, in which we give it a logical copy, to prevent it from pulluting our gold one.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( (string){ fred(0,4) } );
+    sout | "after helper with " | fred;
+
+
+
+    sout | "===";
+    sout | "HL: whole original string";
+
+    sout | "---";
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper1( fred );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, sys-style, in which we want to gets its changes as side effects.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( fred );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, trans-style, in which we give it a logical copy, to prevent it from pulluting our gold one.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( (string){ fred } );
+    sout | "after helper with " | fred;
+}
+
+void calltest_LL() {
+
+    #define HELPER_BODY(param) \
+        sout | "early in helper with " | param; \
+        assignAt(param, 0, '+'); \
+        sout | "late in helper with " | param;
+
+    void helper1( string_res & q ) { HELPER_BODY(q) } // arg should always be a temporary constructed with COPY_VALUE
+    void helper2( string_res & q ) { HELPER_BODY(q) } // arg can refer to whatever you want
+    #undef HELPER_BODY
+
+    /*
+    In LL, both functions are translated to the same thing.
+    "The only allowed call of #1" becomes respecting the restriction of the comment at helper1.
+    A sys call of #2 is different from the only allowed call of #1.
+    A trans call of #2 is the same as the only allowed call of #1.
+    */
+
+    string_res fred;
+
+    sout | "===";
+    sout | "LL: substring of part";
+
+    sout | "---";
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper1( (string_res){ fred, COPY_VALUE, 1, 3 } );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, sys-style, in which we want to gets its changes as side effects.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( (string_res){ fred, SHARE_EDITS, 1, 3 } );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, trans-style, in which we give it a logical copy, to prevent it from pulluting our gold one.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( (string_res){ fred, COPY_VALUE, 1, 3 } );
+    sout | "after helper with " | fred;
+
+
+    sout | "===";
+    sout | "LL: substring of whole";
+
+    sout | "---";
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper1( (string_res){ fred, COPY_VALUE, 0, 4 } );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, sys-style, in which we want to gets its changes as side effects.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( (string_res){ fred, SHARE_EDITS, 0, 4 } );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, trans-style, in which we give it a logical copy, to prevent it from pulluting our gold one.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( (string_res){ fred, COPY_VALUE, 0, 4 } );
+    sout | "after helper with " | fred;
+
+
+    sout | "===";
+    sout | "LL: whole original string";
+
+    sout | "---";
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper1( (string_res){ fred, COPY_VALUE } );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, sys-style, in which we want to gets its changes as side effects.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( fred );
+    sout | "after helper with " | fred;
+
+    sout | "---";
+    // Calling a by-ref function, trans-style, in which we give it a logical copy, to prevent it from pulluting our gold one.
+    fred = "abcd";
+    sout | "before helper with " | fred;
+    helper2( (string_res){ fred, COPY_VALUE } );
+    sout | "after helper with " | fred;
+}
+
+
+
+int main() {
+
+    calltest_HL();
+    calltest_LL();
+
+}
Index: tests/zombies/string-perf/pbx-correctness-demos.cpp
===================================================================
--- tests/zombies/string-perf/pbx-correctness-demos.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/pbx-correctness-demos.cpp	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,102 @@
+// see also C++ investigation in ~/plg2/cfa2/mycode/string/raii/ctor-calls.cpp
+
+#include <string>
+#include <iostream>
+
+using namespace std;
+
+#define HELPER_BODY(param) \
+    cout << "early in helper with " << param << endl; \
+    param[0] = '+'; \
+    cout << "late in helper with " << param << endl;
+
+void helper1( string   q ) { HELPER_BODY(q) }
+void helper2( string & q ) { HELPER_BODY(q) }
+#undef HELPER_BODY
+
+
+void calltest_HL() {
+
+    string fred;
+
+
+    cout << "===" << endl;
+    cout << "HL: substring of part" << endl;
+
+    cout << "---" << endl;
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    cout << "before helper with " << fred << endl;
+    helper1( fred.substr(1,3) );
+    cout << "after helper with " << fred << endl;
+
+    cout << "---" << endl;
+    // Calling a by-ref function, catching side effects the only place STL-string gives them, in an explicit copy.
+    fred = "abcd";
+    cout << "before helper with " << fred << endl;
+    {
+        string fred_sub = fred.substr(1,3);
+        helper2( fred_sub );
+        cout << "after helper with temp having " << fred_sub << endl;
+    }
+    cout << "after helper with original having " << fred << endl;
+
+
+    cout << "===" << endl;
+    cout << "HL: substring of whole" << endl;
+
+    cout << "---" << endl;
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    cout << "before helper with " << fred << endl;
+    helper1( fred.substr(0,4) );
+    cout << "after helper with " << fred << endl;
+
+    cout << "---" << endl;
+    // Calling a by-ref function, catching side effects the only place STL-string gives them, in an explicit copy.
+    fred = "abcd";
+    cout << "before helper with " << fred << endl;
+    {
+        string fred_sub = fred.substr(0,4);
+        helper2( fred_sub );
+        cout << "after helper with temp having " << fred_sub << endl;
+    }
+    cout << "after helper with original having " << fred << endl;
+
+
+
+    cout << "===" << endl;
+    cout << "HL: whole original string" << endl;
+
+    cout << "---" << endl;
+    // Calling a by-val function, the only way it supports, in which it gets a private logical copy.
+    fred = "abcd";
+    cout << "before helper with " << fred << endl;
+    helper1( fred );
+    cout << "after helper with " << fred << endl;
+
+    cout << "---" << endl;
+    // Calling a by-ref function, sys-style, in which we want to gets its changes as side effects.
+    fred = "abcd";
+    cout << "before helper with " << fred << endl;
+    helper2( fred );
+    cout << "after helper with " << fred << endl;
+
+    cout << "---" << endl;
+    // Calling a by-ref function, trans-style, in which we give it a logical copy, to prevent it from pulluting our gold one; copy needs explicit variable.
+    fred = "abcd";
+    cout << "before helper with " << fred << endl;
+    {
+        string fred_cpy = fred;
+        helper2( fred_cpy );
+    }
+    cout << "after helper with " << fred << endl;
+}
+
+
+
+int main() {
+
+    calltest_HL();
+
+}
Index: tests/zombies/string-perf/prog-allocn.cfa
===================================================================
--- tests/zombies/string-perf/prog-allocn.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/prog-allocn.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,218 @@
+#if defined IMPL_STL_NA_NA
+  #define IMPL_STL
+#endif
+
+#if defined IMPL_BUHR94_NA_NA
+  #define IMPL_BUHR94
+#endif
+
+#if defined IMPL_STL
+  #include <string>
+  #include <iostream>
+  #include <cstdio>
+  using namespace std;
+  #define IMPL_CXX
+
+#elif defined IMPL_CFA_HL_SHARE
+  #define IMPL_CFA_HL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_SHARE
+  #define IMPL_CFA_LL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_HL_NOSHARE
+  #define IMPL_CFA_HL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_NOSHARE
+  #define IMPL_CFA_LL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_BUHR94
+  #include <iostream>
+  #include <cstdio>
+  #include "/u0/mlbrooks/usys1/sm/string/StringSharing/src/string.h"
+  #define IMPL_CXX
+
+#else
+  #error Bad IMPL_
+#endif
+
+
+#if defined IMPL_CFA_HL
+  #include <string.hfa>
+  extern void TUNING_set_string_heap_liveness_threshold(double);  // in string_res.hfa
+#elif defined IMPL_CFA_LL
+  #include <string_res.hfa>
+#endif
+
+#if defined CFA_NOSHARE
+  #include <string_sharectx.hfa>
+  #define STRING_SHARING_CONTROL \
+    string_sharectx c = { NO_SHARING };
+#else 
+  #define STRING_SHARING_CONTROL
+#endif
+
+#if defined IMPL_CFA
+  #include <math.hfa>
+  extern "C" {
+    void malloc_stats( void );
+  }
+#elif defined IMPL_CXX
+  #include <algorithm>
+  using std::min;
+  #include <malloc.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h> // atoi
+#include <string.h> // strlen, only during setup
+
+#if defined IMPL_STL || defined IMPL_BUHR94
+    #define PRINT(s) std::cout << s << std::endl
+#elif defined IMPL_CFA_HL || defined IMPL_CFA_LL
+    #define PRINT(s) sout | s;
+#else
+    #error Unhandled print case
+#endif
+
+#if defined IMPL_CFA_LL
+    #define STRING_T string_res
+    #define ASSIGN_CHAR(str, idx, val) assignAt(str, idx, val)
+#else
+    #define STRING_T string
+    #define ASSIGN_CHAR(str, idx, val) str[idx] = val
+#endif
+
+double meanLen(int N, char ** strings) {
+    int totalLen = 0;
+    for (int i = 0 ; i < N; i ++) {
+        totalLen += strlen(strings[i]);
+    }
+    return (double)totalLen / (double)N;
+}
+
+volatile int checkthis = 0;
+#define MAYBE( op ) if (checkthis) { op; }
+
+int corpuslen = 0;
+char ** corpus = (char**) 0;
+size_t corpus_next_pos = 0;
+
+double repsPerLevel;
+double repBalance = 0.0000001;
+
+clock_t start, endTarget, end_actual;
+size_t allocationCountTarget = 0;
+
+size_t allocationCountActual = 0;
+//size_t allocationBytesActual = 0;
+
+void helper( int depth ) {
+
+    if (depth == 0) return;
+
+    corpus_next_pos += 1;
+    corpus_next_pos %= corpuslen;
+
+    STRING_T q = corpus[corpus_next_pos];
+//    ASSIGN_CHAR(q, 0, '@');    // Turns out my implementation is slow at this step.  A separate test could work it.  It's inessential to the allocation test, given the assumption that both string reps allocate eagerly in their heaps from a constant.  In the STL, that assumption is upheld by my observation that commenting out this line didn't speed it up.  In CFA-share, I know it to be true of the implementation.
+
+    allocationCountActual += 1;
+//    allocationBytesActual += q`len;
+
+//    if (depth > 0) {
+
+        repBalance += repsPerLevel;
+        int curRepLimit = repBalance;
+        repBalance -= curRepLimit;
+
+        for ( int i = 0 ;  i < curRepLimit;  i++ ) {
+            if ((allocationCountActual+1) % allocationCountTarget == 0 && clock() > endTarget) return;
+            helper(depth-1);
+        }
+//    }
+
+    MAYBE(PRINT(q));
+}
+
+int main( int argc, char ** argv ) {
+
+    STRING_SHARING_CONTROL
+
+
+    const char * usage_args[] = {"Depth RepsPerLevel ExpansionThreshold    ExecTimeSecs   Corpus...",
+                                 "Depth RepsPerLevel ExpansionThreshold -w WorkAllocCount Corpus..."};
+    const int static_arg_posns = 5;
+    int used_arg_posns = static_arg_posns;
+
+    int launchDepth = -1;
+    double expansionThreshold = -1.0;
+    int execTimeSecs = -1;
+
+    switch (min(argc, static_arg_posns)) {
+      case 5: if ( strcmp(argv[4], "-w") == 0 ) {
+                used_arg_posns ++;
+                allocationCountTarget = atoi(argv[5]);
+              } else {
+                execTimeSecs = atoi(argv[4]);
+              }
+      case 4: expansionThreshold = atof(argv[3]);
+      case 3: repsPerLevel = atof(argv[2]);
+      case 2: launchDepth = atoi(argv[1]);
+    }
+
+    corpuslen = argc - used_arg_posns;
+    corpus = argv + used_arg_posns;
+
+    if (launchDepth < 1 || repsPerLevel < 1.0 || (execTimeSecs < 1 && allocationCountTarget < 1) || corpuslen < 1 ||
+        (expansionThreshold != -1.0 && (expansionThreshold <= 0.0 || expansionThreshold >= 1.0))) {
+      for (int u = 0; u < sizeof(usage_args) / sizeof(*usage_args); u++) {
+        printf("usage: %s %s\n", argv[0], usage_args[u]);
+      }
+      printf("output:\nxxx,corpusItemCount,corpusMeanLenChars,allocationCountActual,execTimeActualSec,topIters\n");
+      exit(1);
+    }
+
+    if (expansionThreshold != -1.0 ) {
+      #if defined IMPL_CFA
+      TUNING_set_string_heap_liveness_threshold(expansionThreshold);
+      #else
+      printf("cannot set expansion threshold on non-CFA implementation");
+      exit(1);
+      #endif
+    }
+
+    double meanCorpusLen = meanLen(corpuslen, corpus);
+
+    // time driven experiment: re-check time every 10000 allocations
+    if (execTimeSecs > 0) allocationCountTarget = 10000;
+
+    start = clock();
+    endTarget = start + CLOCKS_PER_SEC * max(0, execTimeSecs);
+
+    size_t top_iters = 0;
+
+    for(;;) {
+            #if defined OP_PALL
+                helper( launchDepth );
+            #else
+                #error Bad OP_
+            #endif
+
+            top_iters++;
+
+            if ((allocationCountActual+1) % allocationCountTarget == 0 && clock() > endTarget) break;
+    }
+    end_actual = clock();
+    double elapsed = ((double) (end_actual - start)) / CLOCKS_PER_SEC;
+    printf("xxx,%d,%f,%ld,%f,%ld\n", corpuslen, meanCorpusLen, allocationCountActual, elapsed, top_iters);
+
+    // malloc_stats();
+
+    return 0;
+}
Index: tests/zombies/string-perf/prog-find.cfa
===================================================================
--- tests/zombies/string-perf/prog-find.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/prog-find.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,184 @@
+#if defined IMPL_STL_NA_NA
+  #define IMPL_STL
+#endif
+
+#if defined IMPL_BUHR94_NA_NA
+  #define IMPL_BUHR94
+#endif
+
+#if defined IMPL_STL
+  #include <string>
+  #include <iostream>
+  #include <cstdio>
+  using namespace std;
+  #define IMPL_CXX
+
+#elif defined IMPL_CFA_HL_SHARE
+  #define IMPL_CFA_HL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_SHARE
+  #define IMPL_CFA_LL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_HL_NOSHARE
+  #define IMPL_CFA_HL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_NOSHARE
+  #define IMPL_CFA_LL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_BUHR94
+  #include <iostream>
+  #include <cstdio>
+  #include "/u0/mlbrooks/usys1/sm/string/StringSharing/src/string.h"
+  #define IMPL_CXX
+
+#else
+  #error Bad IMPL_
+#endif
+
+
+#if defined IMPL_CFA_HL
+  #include <string.hfa>
+#elif defined IMPL_CFA_LL
+  #include <string_res.hfa>
+  #include "not_string_res.hfa"
+#endif
+
+#if defined CFA_NOSHARE
+  #include <string_sharectx.hfa>
+  #define STRING_SHARING_CONTROL \
+    string_sharectx c = { NO_SHARING };
+#else 
+  #define STRING_SHARING_CONTROL
+#endif
+
+#if defined IMPL_CFA
+  #include <math.hfa>
+  extern "C" {
+    void malloc_stats( void );
+  }
+#elif defined IMPL_CXX
+  #include <algorithm>
+  using std::min;
+  #include <malloc.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h> // atoi
+#include <string.h> // strlen, only during setup
+#include <limits.h> // LONG_MAX
+
+#if defined IMPL_STL || defined IMPL_BUHR94
+    #define PRINT(s) std::cout << s << std::endl
+#elif defined IMPL_CFA_HL || defined IMPL_CFA_LL
+    #define PRINT(s) sout | s;
+#else
+    #error Unhandled print case
+#endif
+
+#if defined IMPL_CFA_LL
+    #define STRING_T string_res
+    #define ASSIGN_CHAR(str, idx, val) assignAt(str, idx, val)
+#else
+    #define STRING_T string
+    #define ASSIGN_CHAR(str, idx, val) str[idx] = val
+#endif
+
+double meanLen(int N, char ** strings) {
+    int totalLen = 0;
+    for (int i = 0 ; i < N; i ++) {
+        totalLen += strlen(strings[i]);
+    }
+    return (double)totalLen / (double)N;
+}
+
+volatile int checkthis = 0;
+#define MAYBE( op ) if (checkthis) { op; }
+
+
+int main( int argc, char ** argv ) {
+
+    STRING_SHARING_CONTROL
+
+
+    const char * usage_args[] = {"(Ignored)    ExecTimeSecs   Corpus...",
+                                 "(Ignored) -w WorkAllocCount Corpus..."};
+
+    const int static_arg_posns = 3;
+    int used_arg_posns = static_arg_posns;
+
+    int execTimeSecs = -1;
+
+    long int iterationCountTarget = -1;
+
+    switch (min(argc, static_arg_posns)) {
+      case 3: if ( strcmp(argv[2], "-w") == 0 ) {
+                used_arg_posns ++;
+                execTimeSecs = 0;
+                iterationCountTarget = atoi(argv[3]);
+              } else {
+                execTimeSecs = atoi(argv[2]);
+                iterationCountTarget = LONG_MAX;
+              }
+    }
+
+    int corpuslen = argc - used_arg_posns;
+    char ** corpus = argv + used_arg_posns;
+
+    if ((execTimeSecs < 1 && iterationCountTarget < 1)  || corpuslen < 1) {
+      for (int u = 0; u < sizeof(usage_args) / sizeof(*usage_args); u++) {
+        printf("usage: %s %s\n", argv[0], usage_args[u]);
+      }
+      printf("output:\nxxx,corpusItemCount,corpusMeanLenChars,callDoneActualCount,execTimeActualSec\n");
+      exit(1);
+    }
+
+    double meanCorpusLen = meanLen(corpuslen, corpus);
+
+    clock_t start, end_target, end_actual;
+
+    STRING_T corpus_imported[corpuslen];
+
+    for (int i = 0; i < corpuslen; i++) {
+        corpus_imported[i] = corpus[i];
+        // if the callee ever modifies, then we will drive GCs, which will visit the entire corpus
+    }
+
+    start = clock();
+    if (execTimeSecs != 0) {
+      end_target = start + CLOCKS_PER_SEC * execTimeSecs;
+    } else {
+      end_target = start + CLOCKS_PER_SEC * 3600;
+    }
+
+    unsigned int t = 0;
+    for ( ; t < iterationCountTarget && ((t+1) % 10000 != 0 || clock() < end_target) ; t += 1 ) {
+            #if defined OP_PFI
+              size_t foundAt =
+                #if defined IMPL_CFA
+                   find( corpus_imported[t % corpuslen], ' ')
+                #elif defined IMPL_STL
+                   corpus_imported[t % corpuslen].find(' ')
+                #else
+                  #error Bad IMPL
+                #endif
+                ;
+            #else
+              #error Bad OP_
+            #endif
+            MAYBE( PRINT( foundAt ) );
+    }
+    end_actual = clock();
+    unsigned int callsDone = t;
+    double elapsed = ((double) (end_actual - start)) / CLOCKS_PER_SEC;
+    printf("xxx,%d,%f,%d,%f\n", corpuslen, meanCorpusLen, t, elapsed);
+
+    // malloc_stats();
+
+    return 0;
+}
Index: tests/zombies/string-perf/prog-normalize.cfa
===================================================================
--- tests/zombies/string-perf/prog-normalize.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/prog-normalize.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,264 @@
+#if defined IMPL_STL_NA_NA
+  #define IMPL_STL
+#endif
+
+#if defined IMPL_BUHR94_NA_NA
+  #define IMPL_BUHR94
+#endif
+
+#if defined IMPL_STL
+  #include <string>
+  #include <iostream>
+  #include <cstdio>
+  using namespace std;
+  #define IMPL_CXX
+
+#elif defined IMPL_CFA_HL_SHARE
+  #define IMPL_CFA_HL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_SHARE
+  #define IMPL_CFA_LL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_HL_NOSHARE
+  #define IMPL_CFA_HL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_NOSHARE
+  #define IMPL_CFA_LL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_BUHR94
+  #include <iostream>
+  #include <cstdio>
+  #include "/u0/mlbrooks/usys1/sm/string/StringSharing/src/string.h"
+  #define IMPL_CXX
+
+#else
+  #error Bad IMPL_
+#endif
+
+
+#if defined IMPL_CFA_HL
+  #include <string.hfa>
+#elif defined IMPL_CFA_LL
+  #include <string_res.hfa>
+#endif
+
+#if defined CFA_NOSHARE
+  #include <string_sharectx.hfa>
+  #define STRING_SHARING_CONTROL \
+    string_sharectx c = { NO_SHARING };
+#else 
+  #define STRING_SHARING_CONTROL
+#endif
+
+#if defined IMPL_CFA
+  #include <math.hfa>
+  extern "C" {
+    void malloc_stats( void );
+  }
+#elif defined IMPL_CXX
+  #include <algorithm>
+  using std::min;
+  #include <malloc.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h> // atoi
+#include <string.h> // strlen, only during setup
+
+#if defined IMPL_STL || defined IMPL_BUHR94
+    #define PRINT(s) std::cout << s << std::endl
+#elif defined IMPL_CFA_HL || defined IMPL_CFA_LL
+    #define PRINT(s) sout | s;
+#else
+    #error Unhandled print case
+#endif
+
+#if defined IMPL_CFA_LL
+    #define STRING_T string_res
+    #define ASSIGN_CHAR(str, idx, val) assignAt(str, idx, val)
+#else
+    #define STRING_T string
+    #define ASSIGN_CHAR(str, idx, val) str[idx] = val
+#endif
+
+#if defined IMPL_CFA
+    #define LEN(str) size(str)
+#elif defined IMPL_STL 
+    #define LEN(str) str.length()
+#else
+    #error need LEN definition for this IMPL_
+#endif
+
+double meanLen(int N, char ** strings) {
+    int totalLen = 0;
+    for (int i = 0 ; i < N; i ++) {
+        totalLen += strlen(strings[i]);
+    }
+    return (double)totalLen / (double)N;
+}
+
+volatile int checkthis = 0;
+#define MAYBE( op ) if (checkthis) { op; }
+
+// setup, not being timed, nor judged for aesthetics
+void makeSuperCorpus( STRING_T & target, int corpusLen, char ** corpus, int scSize, char scDelimiter ) {
+    char delimiterStr[2] = { scDelimiter, '\0' };
+    for ( int i = 0;  i < scSize; i++ ) {
+        target += corpus[ i % corpusLen ];
+        target += delimiterStr;
+    }
+}
+
+// the function at issue
+
+#if defined IMPL_CFA_HL
+void processThing( string & thing, char magicChar ) {
+    MAYBE(PRINT(thing));
+    size_t foundPos;
+    for (;;) {
+        size_t size_thing = size(thing);
+        foundPos = find(thing, magicChar);
+        if( foundPos == size_thing ) break;
+        string mcOccur = thing(foundPos, foundPos+1)`shareEdits;
+        mcOccur = "";
+    }
+    return thing;
+}
+
+#elif defined IMPL_CFA_LL
+void processThing( string_res & thing, char magicChar ) {
+    MAYBE(PRINT(thing));
+    size_t foundPos;
+    for (;;) {
+        size_t size_thing = size(thing);
+        foundPos = find(thing, magicChar);
+        if( foundPos == size_thing ) break;
+        string_res mcOccur = { thing, SHARE_EDITS, foundPos, foundPos+1 };
+        mcOccur = "";
+    }
+}
+
+#elif defined IMPL_STL
+void processThing( string & thing, char magicChar ) {
+    MAYBE(PRINT(thing));
+    size_t foundPos;
+    for (;;) {
+        size_t size_thing = thing.length();
+        foundPos = thing.find(magicChar);
+        if (foundPos == string::npos) break;
+        thing.erase(foundPos, 1);
+    }
+}
+
+#endif
+
+/*
+void runCorrectnessDemo(char** corpus, int corpusLen) {
+    STRING_T item = "asdf";    PRINT( processThing( item, '-' ) );
+    item = "as-df";            PRINT( processThing( item, '-' ) );
+    item = "-asdf-";           PRINT( processThing( item, '-' ) );
+    item = "-";                PRINT( processThing( item, '-' ) );
+    for ( int i = 0; i < corpusLen; i ++ ) {
+        item = corpus[i];      PRINT( processThing( item, '-' ) );
+    }
+
+    STRING_T supercorpus;
+    makeSuperCorpus( supercorpus, corpusLen, corpus, 30, ',');
+    PRINT( supercorpus );
+}
+*/
+
+int main( int argc, char ** argv ) {
+
+    STRING_SHARING_CONTROL
+
+    int corpuslen = 0;
+    char ** corpus = (char**) 0;
+
+    clock_t start, endTarget, end_actual;
+
+    const char * usage_args = "SCsize MagicChar ExecTimeSecs Corpus...";
+    const int static_arg_posns = 4;
+
+    int scSize = -1;
+    char magicChar = '\0';
+    int execTimeSecs = -1;
+
+    switch (min(argc, static_arg_posns)) {
+      case 4: execTimeSecs = atoi(argv[3]);
+      case 3: magicChar = argv[2][0];
+      case 2: scSize = atoi(argv[1]);
+    }
+
+    corpuslen = argc - static_arg_posns;
+    corpus = argv + static_arg_posns;
+
+    if (scSize < 1 || magicChar == '\0' || execTimeSecs < 1 || corpuslen < 1) {
+      printf("usage: %s %s\n", argv[0], usage_args);
+      printf("output:\nxxx,corpusItemCount,corpusMeanLenChars,invcationCountActual,execTimeActualSec\n");
+      exit(1);
+    }
+
+    double meanCorpusLen = meanLen(corpuslen, corpus);
+
+//    runCorrectnessDemo(corpus, corpuslen);
+
+
+    STRING_T supercorpus;
+    makeSuperCorpus( supercorpus, corpuslen, corpus, scSize, ',');
+
+    size_t sc_charlen = LEN(supercorpus);
+
+    start = clock();
+    endTarget = start + CLOCKS_PER_SEC * execTimeSecs;
+
+    volatile unsigned int t = 0;
+    size_t lastChunkEnd = -1;
+    for ( ; t % 10000 != 0 || clock() < endTarget ; t += 1 ) {
+            #if defined OP_PNO
+
+                lastChunkEnd++;
+                if ( lastChunkEnd >= sc_charlen ) {
+                    lastChunkEnd = 0;
+                }
+
+#if defined IMPL_CFA_HL
+                size_t thisChunkEnd = findFrom( supercorpus, lastChunkEnd, ',' );
+                //if (thisChunkEnd == string::npos) throw 1;
+                string chunkProcessed = supercorpus(lastChunkEnd, thisChunkEnd);
+                processThing(chunkProcessed, '-');
+#elif defined IMPL_CFA_LL
+                size_t thisChunkEnd = findFrom( supercorpus, lastChunkEnd, ',' );
+                //if (thisChunkEnd == string::npos) throw 1;
+                
+                string_res chunkProcessed = { supercorpus, COPY_VALUE, lastChunkEnd, thisChunkEnd };
+                processThing( chunkProcessed, '-' );
+#elif defined IMPL_STL
+                size_t thisChunkEnd = supercorpus.find( ',', lastChunkEnd );
+                if (thisChunkEnd == string::npos) throw 1;
+                string chunkProcessed = supercorpus.substr(lastChunkEnd, thisChunkEnd-lastChunkEnd);
+                processThing(chunkProcessed, '-');
+#else 
+#error Bad IMPL_
+#endif
+                MAYBE( PRINT(chunkProcessed) );
+
+                lastChunkEnd = thisChunkEnd;
+            #else
+                #error Bad OP_
+            #endif
+    }
+    end_actual = clock();
+    double elapsed = ((double) (end_actual - start)) / CLOCKS_PER_SEC;
+    printf("xxx,%d,%f,%d,%f\n", corpuslen, meanCorpusLen, t, elapsed);
+
+    // malloc_stats();
+
+    return 0;
+}
Index: tests/zombies/string-perf/prog-passbyX.cfa
===================================================================
--- tests/zombies/string-perf/prog-passbyX.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/prog-passbyX.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,210 @@
+#if defined IMPL_STL_NA_NA
+  #define IMPL_STL
+#endif
+
+#if defined IMPL_BUHR94_NA_NA
+  #define IMPL_BUHR94
+#endif
+
+#if defined IMPL_STL
+  #include <string>
+  #include <iostream>
+  #include <cstdio>
+  using namespace std;
+  #define IMPL_CXX
+
+#elif defined IMPL_CFA_HL_SHARE
+  #define IMPL_CFA_HL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_SHARE
+  #define IMPL_CFA_LL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_HL_NOSHARE
+  #define IMPL_CFA_HL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_NOSHARE
+  #define IMPL_CFA_LL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_BUHR94
+  #include <iostream>
+  #include <cstdio>
+  #include "/u0/mlbrooks/usys1/sm/string/StringSharing/src/string.h"
+  #define IMPL_CXX
+
+#else
+  #error Bad IMPL_
+#endif
+
+
+#if defined IMPL_CFA_HL
+  #include <string.hfa>
+#elif defined IMPL_CFA_LL
+  #include <string_res.hfa>
+  #include "not_string_res.hfa"
+#endif
+
+#if defined CFA_NOSHARE
+  #include <string_sharectx.hfa>
+  #define STRING_SHARING_CONTROL \
+    string_sharectx c = { NO_SHARING };
+#else 
+  #define STRING_SHARING_CONTROL
+#endif
+
+#if defined IMPL_CFA
+  #include <math.hfa>
+  extern "C" {
+    void malloc_stats( void );
+  }
+#elif defined IMPL_CXX
+  #include <algorithm>
+  using std::min;
+  #include <malloc.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h> // atoi
+#include <string.h> // strlen, only during setup
+#include <limits.h> // LONG_MAX
+
+#if defined IMPL_STL || defined IMPL_BUHR94
+    #define PRINT(s) std::cout << s << std::endl
+#elif defined IMPL_CFA_HL || defined IMPL_CFA_LL
+    #define PRINT(s) sout | s;
+#else
+    #error Unhandled print case
+#endif
+
+#if defined IMPL_CFA_LL
+    #define STRING_T string_res
+    #define ASSIGN_CHAR(str, idx, val) assignAt(str, idx, val)
+#else
+    #define STRING_T string
+    #define ASSIGN_CHAR(str, idx, val) str[idx] = val
+#endif
+
+double meanLen(int N, char ** strings) {
+    int totalLen = 0;
+    for (int i = 0 ; i < N; i ++) {
+        totalLen += strlen(strings[i]);
+    }
+    return (double)totalLen / (double)N;
+}
+
+volatile int checkthis = 0;
+#define MAYBE( op ) if (checkthis) { op; }
+
+
+#if defined IMPL_CFA_LL
+void helper( string_res & q ) {
+#else
+  #error bad IMPL_
+#endif
+    #if defined OP_PB1X || defined OP_PB2X || defined OP_PB3X || defined OP_PB4X || defined OP_PB5X || defined OP_PB6X
+        ASSIGN_CHAR(q, 0, '@');
+    #else
+        MAYBE(ASSIGN_CHAR(q, 0, '@'));
+    #endif
+    MAYBE(PRINT(q));
+}
+
+void not_helper( not_string_res & q ) {
+    MAYBE( printf("%ld", q.junk[3]) );
+    MAYBE( q.junk[3] = 17 );
+}
+
+int main( int argc, char ** argv ) {
+
+    STRING_SHARING_CONTROL
+
+
+    const char * usage_args[] = {"(Ignored)    ExecTimeSecs   Corpus...",
+                                 "(Ignored) -w WorkAllocCount Corpus..."};
+
+    const int static_arg_posns = 3;
+    int used_arg_posns = static_arg_posns;
+
+    int execTimeSecs = -1;
+
+    long int iterationCountTarget = -1;
+
+    switch (min(argc, static_arg_posns)) {
+      case 3: if ( strcmp(argv[2], "-w") == 0 ) {
+                used_arg_posns ++;
+                execTimeSecs = 0;
+                iterationCountTarget = atoi(argv[3]);
+              } else {
+                execTimeSecs = atoi(argv[2]);
+                iterationCountTarget = LONG_MAX;
+              }
+    }
+
+    int corpuslen = argc - used_arg_posns;
+    char ** corpus = argv + used_arg_posns;
+
+    if ((execTimeSecs < 1 && iterationCountTarget < 1)  || corpuslen < 1) {
+      for (int u = 0; u < sizeof(usage_args) / sizeof(*usage_args); u++) {
+        printf("usage: %s %s\n", argv[0], usage_args[u]);
+      }
+      printf("output:\nxxx,corpusItemCount,corpusMeanLenChars,callDoneActualCount,execTimeActualSec\n");
+      exit(1);
+    }
+
+    double meanCorpusLen = meanLen(corpuslen, corpus);
+
+    clock_t start, end_target, end_actual;
+
+    STRING_T corpus_imported[corpuslen];
+
+    for (int i = 0; i < corpuslen; i++) {
+        corpus_imported[i] = corpus[i];
+        // if the callee ever modifies, then we will drive GCs, which will visit the entire corpus
+    }
+
+    start = clock();
+    if (execTimeSecs != 0) {
+      end_target = start + CLOCKS_PER_SEC * execTimeSecs;
+    } else {
+      end_target = start + CLOCKS_PER_SEC * 3600;
+    }
+
+    unsigned int t = 0;
+    for ( ; t < iterationCountTarget && ((t+1) % 10000 != 0 || clock() < end_target) ; t += 1 ) {
+            string_res & src = corpus_imported[t % corpuslen];
+            size_t srclen = size(src);
+            if (srclen < 2) {
+              printf("need string lengths >= 2");
+            }
+            #if defined OP_PB1 || defined OP_PB1X
+              helper( (string_res){ src, COPY_VALUE, 1, srclen-1 } ); 
+            #elif defined OP_PB2 || defined OP_PB2X
+              helper( (string_res){ src, SHARE_EDITS, 1, srclen-1 } );
+            #elif defined OP_PB3 || defined OP_PB3X
+              helper( (string_res){ src, COPY_VALUE, 0, srclen } );
+            #elif defined OP_PB4 || defined OP_PB4X
+              helper( (string_res){ src, SHARE_EDITS, 0, srclen } );
+            #elif defined OP_PB5 || defined OP_PB5X
+              helper( (string_res){ src, COPY_VALUE } );
+            #elif defined OP_PB6 || defined OP_PB6X
+              helper( src ); 
+            #elif defined OP_PB9
+              not_helper( (not_string_res){ src, SHARE_EDITS, 0, srclen } );
+            #else
+                #error Bad OP_
+            #endif
+    }
+    end_actual = clock();
+    unsigned int callsDone = t;
+    double elapsed = ((double) (end_actual - start)) / CLOCKS_PER_SEC;
+    printf("xxx,%d,%f,%d,%f\n", corpuslen, meanCorpusLen, t, elapsed);
+
+    // malloc_stats();
+
+    return 0;
+}
Index: tests/zombies/string-perf/prog-passbyval.cfa
===================================================================
--- tests/zombies/string-perf/prog-passbyval.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/prog-passbyval.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,164 @@
+#if defined IMPL_STL_NA_NA
+  #define IMPL_STL
+#endif
+
+#if defined IMPL_BUHR94_NA_NA
+  #define IMPL_BUHR94
+#endif
+
+#if defined IMPL_STL
+  #include <string>
+  #include <iostream>
+  #include <cstdio>
+  using namespace std;
+  #define IMPL_CXX
+
+#elif defined IMPL_CFA_HL_SHARE
+  #define IMPL_CFA_HL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_SHARE
+  #define IMPL_CFA_LL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_HL_NOSHARE
+  #define IMPL_CFA_HL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_NOSHARE
+  #define IMPL_CFA_LL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_BUHR94
+  #include <iostream>
+  #include <cstdio>
+  #include "/u0/mlbrooks/usys1/sm/string/StringSharing/src/string.h"
+  #define IMPL_CXX
+
+#else
+  #error Bad IMPL_
+#endif
+
+
+#if defined IMPL_CFA_HL
+  #include <string.hfa>
+#elif defined IMPL_CFA_LL
+  #include <string_res.hfa>
+#endif
+
+#if defined CFA_NOSHARE
+  #include <string_sharectx.hfa>
+  #define STRING_SHARING_CONTROL \
+    string_sharectx c = { NO_SHARING };
+#else 
+  #define STRING_SHARING_CONTROL
+#endif
+
+#if defined IMPL_CFA
+  #include <math.hfa>
+  extern "C" {
+    void malloc_stats( void );
+  }
+#elif defined IMPL_CXX
+  #include <algorithm>
+  using std::min;
+  #include <malloc.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h> // atoi
+#include <string.h> // strlen, only during setup
+
+#if defined IMPL_STL || defined IMPL_BUHR94
+    #define PRINT(s) std::cout << s << std::endl
+#elif defined IMPL_CFA_HL || defined IMPL_CFA_LL
+    #define PRINT(s) sout | s;
+#else
+    #error Unhandled print case
+#endif
+
+#if defined IMPL_CFA_LL
+    #define STRING_T string_res
+    #define ASSIGN_CHAR(str, idx, val) assignAt(str, idx, val)
+#else
+    #define STRING_T string
+    #define ASSIGN_CHAR(str, idx, val) str[idx] = val
+#endif
+
+double meanLen(int N, char ** strings) {
+    int totalLen = 0;
+    for (int i = 0 ; i < N; i ++) {
+        totalLen += strlen(strings[i]);
+    }
+    return (double)totalLen / (double)N;
+}
+
+volatile int checkthis = 0;
+#define MAYBE( op ) if (checkthis) { op; }
+
+
+#if defined IMPL_CFA_LL
+void helper( string_res & qref ) {
+    string_res q = { qref, COPY_VALUE };
+#else
+void helper( string q ) {
+#endif
+    MAYBE(ASSIGN_CHAR(q, 0, '@'));
+    MAYBE(PRINT(q));
+}
+
+int main( int argc, char ** argv ) {
+
+    STRING_SHARING_CONTROL
+
+
+    const char * usage_args = "(Ignored) ExecTimeSecs Corpus...";
+    const int static_arg_posns = 3;
+
+    int execTimeSecs = -1;
+
+    switch (min(argc, static_arg_posns)) {
+      case 3: execTimeSecs = atoi(argv[2]);
+    }
+
+    int corpuslen = argc - static_arg_posns;
+    char ** corpus = argv + static_arg_posns;
+
+    if (execTimeSecs < 1 || corpuslen < 1) {
+      printf("usage: %s %s\n", argv[0], usage_args);
+      printf("output:\nxxx,corpusItemCount,corpusMeanLenChars,callDoneActualCount,execTimeActualSec\n");
+      exit(1);
+    }
+
+    double meanCorpusLen = meanLen(corpuslen, corpus);
+
+    clock_t start, end_target, end_actual;
+
+    STRING_T corpus_imported[corpuslen];
+
+    for (int i = 0; i < corpuslen; i++) {
+        corpus_imported[i] = corpus[i];
+        // if the callee ever modifies, then we will drive GCs, which will visit the entire corpus
+    }
+
+    start = clock();
+    end_target = start + CLOCKS_PER_SEC * execTimeSecs;
+    unsigned int t = 0;
+    for ( ; t % 10000 != 0 || clock() < end_target ; t += 1 ) {
+            #if defined OP_PBV
+            helper( corpus_imported[t % corpuslen] );
+            #else
+                #error Bad OP_
+            #endif
+    }
+    end_actual = clock();
+    unsigned int callsDone = t;
+    double elapsed = ((double) (end_actual - start)) / CLOCKS_PER_SEC;
+    printf("xxx,%d,%f,%d,%f\n", corpuslen, meanCorpusLen, t, elapsed);
+
+    // malloc_stats();
+
+    return 0;
+}
Index: tests/zombies/string-perf/prog.cfa
===================================================================
--- tests/zombies/string-perf/prog.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/prog.cfa	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,175 @@
+#if defined IMPL_STL_NA_NA
+  #define IMPL_STL
+#endif
+
+#if defined IMPL_BUHR94_NA_NA
+  #define IMPL_BUHR94
+#endif
+
+#if defined IMPL_STL
+  #include <string>
+  #include <iostream>
+  #include <cstdio>
+  using namespace std;
+  #define IMPL_CXX
+
+#elif defined IMPL_CFA_HL_SHARE
+  #define IMPL_CFA_HL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_SHARE
+  #define IMPL_CFA_LL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_HL_NOSHARE
+  #define IMPL_CFA_HL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_NOSHARE
+  #define IMPL_CFA_LL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_BUHR94
+  #include <iostream>
+  #include <cstdio>
+  #include "/u0/mlbrooks/usys1/sm/string/StringSharing/src/string.h"
+  #define IMPL_CXX
+
+#else
+  #error Bad IMPL_
+#endif
+
+
+#if defined IMPL_CFA_HL
+  #include <string.hfa>
+#elif defined IMPL_CFA_LL
+  #include <string_res.hfa>
+#endif
+
+#if defined CFA_NOSHARE
+  #include <string_sharectx.hfa>
+  #define STRING_SHARING_CONTROL \
+    string_sharectx c = { NO_SHARING };
+#else 
+  #define STRING_SHARING_CONTROL
+#endif
+
+#if defined IMPL_CFA
+  #include <math.hfa>
+  extern "C" {
+    void malloc_stats( void );
+  }
+#elif defined IMPL_CXX
+  #include <algorithm>
+  using std::min;
+  #include <malloc.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h> // atoi
+#include <string.h> // strlen, only during setup
+
+#if defined IMPL_STL || defined IMPL_BUHR94
+    #define PRINT(s) std::cout << s << std::endl
+#elif defined IMPL_CFA_HL || defined IMPL_CFA_LL
+    #define PRINT(s) sout | s;
+#else
+    #error Unhandled print case
+#endif
+
+double meanLen(int N, char ** strings) {
+    int totalLen = 0;
+    for (int i = 0 ; i < N; i ++) {
+        totalLen += strlen(strings[i]);
+    }
+    return (double)totalLen / (double)N;
+}
+
+volatile int checkthis = 0;
+#define MAYBE( op ) if (checkthis) { op; }
+
+int main( int argc, char ** argv ) {
+
+    STRING_SHARING_CONTROL
+
+
+    const char * usage_args = "ConcatsPerReset ExecTimeSecs Corpus...";
+    const int static_arg_posns = 3;
+
+    int concatsPerReset = -1, execTimeSecs = -1;
+
+    switch (min(argc, static_arg_posns)) {
+      case 3: execTimeSecs = atoi(argv[2]);
+      case 2: concatsPerReset = atoi(argv[1]);
+    }
+
+    int corpuslen = argc - static_arg_posns;
+    char ** corpus = argv + static_arg_posns;
+
+    if (execTimeSecs < 1 || concatsPerReset < 1 || corpuslen < 1) {
+      printf("usage: %s %s\n", argv[0], usage_args);
+      printf("output:\nconcatsPerReset,corpusItemCount,corpusMeanLenChars,concatDoneActualCount,execTimeActualSec\n");
+      exit(1);
+    }
+
+    double meanCorpusLen = meanLen(corpuslen, corpus);
+
+    clock_t start, end_target, end_actual;
+
+    #if defined IMPL_CFA_LL && defined OP_PTA
+        string_res pta_ll_temp;
+    #endif
+
+    #if defined IMPL_CFA_LL
+      #define DECLS \
+        const char* initval = "starter"; \
+        string_res accum = initval;
+    #else
+      #define DECLS \
+        const char* initval = "starter"; \
+        string accum = initval;
+    #endif
+
+    #if defined ALLOC_REUSE
+      DECLS
+      #define RESET \
+        accum = initval;
+    #elif defined ALLOC_FRESH
+      #define RESET \
+        DECLS
+    #else
+      #error bad alloc
+    #endif
+
+    start = clock();
+    end_target = start + CLOCKS_PER_SEC * execTimeSecs;
+    volatile unsigned int t = 0;
+    for ( ; t % 100 != 0 || clock() < end_target ; t += 1 ) {
+            RESET
+            for ( volatile unsigned int i = 0; i < concatsPerReset; i += 1 ) {
+              MAYBE( PRINT(accum) )
+              char *toAppend = corpus[i % corpuslen]; // ? corpus[rand() % corpuslen]
+              #if defined OP_PTA && defined IMPL_CFA_LL
+                 pta_ll_temp = accum;
+                 pta_ll_temp += toAppend;
+                 accum = pta_ll_temp;
+              #elif defined OP_PTA
+                 accum = accum + toAppend;
+              #elif defined OP_PEQ
+                 accum += toAppend;
+              #else
+                 #error Bad OP_
+              #endif
+            }
+    }
+    end_actual = clock();
+    unsigned int concatsDone = t * concatsPerReset;
+    double elapsed = ((double) (end_actual - start)) / CLOCKS_PER_SEC;
+    printf("%d,%d,%f,%d,%f\n", concatsPerReset, corpuslen, meanCorpusLen, concatsDone, elapsed);
+
+    // malloc_stats();
+
+    return 0;
+}
Index: tests/zombies/string-perf/qanal.py
===================================================================
--- tests/zombies/string-perf/qanal.py	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/qanal.py	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,34 @@
+#! /usr/bin/python3
+
+import glob
+import os
+import re
+
+print("corpuslen", "expansion", "elapsed_whole_test", "elapsed_last_alloc", "seclast_req_mem", sep=",")
+
+thepath = "preload_dump--qrun1*"
+
+for mypath in glob.glob(thepath):
+    pathparsed=re.match(r'preload_dump--qrun1--corpus-1-(\d+)-1.txt--expansion-(0\.\d+).txt', mypath)
+    corpuslen=pathparsed.group(1)
+    expansion=pathparsed.group(2)
+
+    with open(mypath) as file:
+        lines = file.readlines()
+
+        nAllocs = len(lines)
+
+        epoch_timestamp_bp = lines[0].find("epoch_timestamp(ms)")
+        epoch_timestamp_ep = epoch_timestamp_bp + len("epoch_timestamp(ms)")
+        current_req_mem_bp = lines[0].find("current_req_mem(B)")
+        current_req_mem_ep = current_req_mem_bp + len("current_req_mem(B)")
+        
+        first_timestamp   = lines[        1][epoch_timestamp_bp:epoch_timestamp_ep].strip()
+        seclast_req_mem   = lines[nAllocs-2][current_req_mem_bp:current_req_mem_ep].strip()
+        seclast_timestamp = lines[nAllocs-2][epoch_timestamp_bp:epoch_timestamp_ep].strip()
+        last_timestamp    = lines[nAllocs-1][epoch_timestamp_bp:epoch_timestamp_ep].strip()
+
+        elapsed_whole_test = int(last_timestamp) - int(first_timestamp)
+        elapsed_last_alloc = int(last_timestamp) - int(seclast_timestamp)
+
+        print(corpuslen, expansion, elapsed_whole_test, elapsed_last_alloc, seclast_req_mem, sep=",")
Index: tests/zombies/string-perf/qrun.sh
===================================================================
--- tests/zombies/string-perf/qrun.sh	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
+++ tests/zombies/string-perf/qrun.sh	(revision d6723509775af3c6dbc33d09aec0168bb8e82989)
@@ -0,0 +1,10 @@
+
+set SIZES='20 50 100 200 500'
+set CFA_EXPANSIONS='0.02 0.05 0.1 0.2 0.5 0.9'
+
+for size in $SIZES ; do
+    echo a
+    for expansion in $CFA_EXPANSIONS ; do
+       echo LD_PRELOAD=~/plg2/mubeen-stat-shim/malloc/mallocWrappers.so ~/plg2/cfa2/cfa-cc/tests/zombies/string-perf/perfexp-cfa-pall-ll-share-na 1000 1.006 $expansion 1 caaaat ~/plg2/cfa2/cfa-cc/tests/zombies/string-perf/corpus-1-$size-1.txt
+    done ;
+done
