Index: libcfa/prelude/Makefile.am
===================================================================
--- libcfa/prelude/Makefile.am	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/prelude/Makefile.am	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -11,6 +11,6 @@
 ## Created On       : Sun May 31 08:54:01 2015
 ## Last Modified By : Peter A. Buhr
-## Last Modified On : Mon Feb  3 21:27:18 2020
-## Update Count     : 208
+## Last Modified On : Thu Jan 13 17:06:27 2022
+## Update Count     : 215
 ###############################################################################
 
@@ -37,17 +37,19 @@
 # create extra forward types/declarations to reduce inclusion of library files
 extras.cf : ${srcdir}/extras.regx ${srcdir}/extras.c
-	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx > extras.cf
-	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -zo -f ${srcdir}/extras.regx2 | tr '\0' '\n' >> extras.cf
+	@echo '# 2 "${@}"  // needed for error messages from this file' > ${@}
+	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -f ${srcdir}/extras.regx >> ${@}
+	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${srcdir}/extras.c | grep -zo -f ${srcdir}/extras.regx2 | tr '\0' '\n' >> ${@}
 
 # create forward declarations for gcc builtins
 gcc-builtins.cf : gcc-builtins.c ${srcdir}/prototypes.sed
-	${AM_V_GEN}gcc -I${srcdir} -E -P $< | sed -r -f ${srcdir}/prototypes.sed > $@
+	@echo '# 2 "${@}"  // needed for error messages from this file' > ${@}
+	${AM_V_GEN}gcc -I${srcdir} -E -P $< | sed -r -f ${srcdir}/prototypes.sed >> ${@}
 
 gcc-builtins.c : ${srcdir}/builtins.def ${srcdir}/prototypes.awk ${srcdir}/sync-builtins.cf ${srcdir}/prototypes.c
-	${AM_V_GEN}gcc -I${srcdir} -E ${srcdir}/prototypes.c | awk -f ${srcdir}/prototypes.awk > $@
+	${AM_V_GEN}gcc -I${srcdir} -E ${srcdir}/prototypes.c | awk -f ${srcdir}/prototypes.awk > ${@}
 
 prelude.cfa : prelude-gen.cc
 	${AM_V_GEN}${CXX} ${AM_CXXFLAGS} ${CXXFLAGS} ${AM_CFLAGS} ${<} -o prelude-gen -Wall -Wextra -O2 -g -std=c++14
-	@./prelude-gen > $@
+	@./prelude-gen > ${@}
 	@rm ./prelude-gen
 
@@ -58,5 +60,5 @@
 # create forward declarations for cfa builtins
 builtins.cf : builtins.c @LOCAL_CFACC@
-	${AM_V_GEN}gcc ${AM_CFLAGS} -E -P ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po -D__cforall
+	${AM_V_GEN}gcc ${AM_CFLAGS} -E ${<} -o ${@} -MD -MP -MF $(DEPDIR)/builtins.Po -D__cforall
 	${AM_V_at}sed -i 's/builtins.o/builtins.cf/g' $(DEPDIR)/builtins.Po
 
@@ -64,5 +66,5 @@
 
 bootloader.c : ${srcdir}/bootloader.cf prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACPP@
-	${AM_V_GEN}@CFACPP@ --prelude-dir=${builddir} -tpm ${srcdir}/bootloader.cf $@  # use src/cfa-cpp as not in lib until after install
+	${AM_V_GEN}@CFACPP@ --prelude-dir=${builddir} -tpm ${srcdir}/bootloader.cf ${@}  # use src/cfa-cpp as not in lib until after install
 
 maintainer-clean-local :
Index: libcfa/src/bits/locks.hfa
===================================================================
--- libcfa/src/bits/locks.hfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/bits/locks.hfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -31,4 +31,6 @@
 		// previous thread to acquire the lock
 		void* prev_thrd;
+		// keep track of number of times we had to spin, just in case the number is unexpectedly huge
+		size_t spin_count;
 	#endif
 };
@@ -48,4 +50,7 @@
 	static inline void ?{}( __spinlock_t & this ) {
 		this.lock = 0;
+		#ifdef __CFA_DEBUG__
+			this.spin_count = 0;
+		#endif
 	}
 
@@ -72,4 +77,7 @@
 		for ( unsigned int i = 1;; i += 1 ) {
 			if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;
+			#ifdef __CFA_DEBUG__
+				this.spin_count++;
+			#endif
 			#ifndef NOEXPBACK
 				// exponential spin
Index: libcfa/src/bits/random.hfa
===================================================================
--- libcfa/src/bits/random.hfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/bits/random.hfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -3,15 +3,17 @@
 #include <stdint.h>
 
+// Pipelined to allow out-of-order overlap with reduced dependencies. Critically, return the current value, and compute
+// and store the next value.
+
 //--------------------------------------------------
 #if defined(__SIZEOF_INT128__)
-	typedef __uint128_t __lehmer64_state_t;
-	static inline uint64_t __lehmer64( __lehmer64_state_t & state ) {
+	static inline uint64_t lehmer64( __uint128_t & state ) {
+		__uint128_t ret = state;
 		state *= 0xda942042e4dd58b5;
-		return state >> 64;
+		return ret >> 64;
 	}
 
 //--------------------------------------------------
-	typedef uint64_t __wyhash64_state_t;
-	static inline uint64_t __wyhash64( __wyhash64_state_t & state ) {
+	static inline uint64_t wyhash64( uint64_t & state ) {
 		state += 0x60bee2bee120fc15;
 		__uint128_t tmp;
@@ -25,12 +27,20 @@
 
 //--------------------------------------------------
-typedef uint64_t __xorshift64_state_t;
-static inline uint64_t __xorshift64( __xorshift64_state_t & state ) {
-	uint64_t x = state;
-	x ^= x << 13;
-	x ^= x >> 7;
-	x ^= x << 17;
-	return state = x;
+static inline uint64_t xorshift_13_7_17( uint64_t & state ) {
+	uint64_t ret = state;
+	state ^= state << 13;
+	state ^= state >> 7;
+	state ^= state << 17;
+	return ret;
 }
+
+//--------------------------------------------------
+static inline uint32_t xorshift_6_21_7( uint32_t & state ) {
+	uint32_t ret = state;
+	state ^= state << 6;
+	state ^= state >> 21;
+	state ^= state << 7;
+	return ret;
+} // xorshift_6_21_7
 
 //--------------------------------------------------
@@ -38,9 +48,10 @@
   uint32_t a, b, c, d;
   uint32_t counter;
-} __xorwow__state_t;
+} xorwow__state_t;
 
 /* The state array must be initialized to not be all zero in the first four words */
-static inline uint32_t __xorwow( __xorwow__state_t & state ) {
+static inline uint32_t xorwow( xorwow__state_t & state ) {
 	/* Algorithm "xorwow" from p. 5 of Marsaglia, "Xorshift RNGs" */
+	uint32_t ret = state.a + state.counter;
 	uint32_t t = state.d;
 
@@ -56,4 +67,35 @@
 
 	state.counter += 362437;
-	return t + state.counter;
+	return ret;
 }
+
+//--------------------------------------------------
+static inline uint32_t LCG( uint32_t & state ) {		// linear congruential generator
+	uint32_t ret = state;
+	state = 36969 * (state & 65535) + (state >> 16);	// 36969 is NOT prime! No not change it!
+	return ret;
+} // LCG
+
+//--------------------------------------------------
+#define M  (1_l64u << 48_l64u)
+#define A  (25214903917_l64u)
+#define AI (18446708753438544741_l64u)
+#define C  (11_l64u)
+#define D  (16_l64u)
+
+static inline uint32_t LCGBI_fwd( uint64_t & state ) {
+	state = (A * state + C) & (M - 1);
+	return state >> D;
+}
+
+static inline uint32_t LCGBI_bck( uint64_t & state ) {
+	unsigned int r = state >> D;
+	state = AI * (state - C) & (M - 1);
+	return r;
+}
+
+#undef M
+#undef A
+#undef AI
+#undef C
+#undef D
Index: libcfa/src/common.hfa
===================================================================
--- libcfa/src/common.hfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/common.hfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -1,10 +1,10 @@
-// 
+//
 // 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.
-// 
-// common -- 
-// 
+//
+// common.hfa --
+//
 // Author           : Peter A. Buhr
 // Created On       : Wed Jul 11 17:54:36 2018
@@ -12,5 +12,5 @@
 // Last Modified On : Wed May  5 14:02:04 2021
 // Update Count     : 18
-// 
+//
 
 #pragma once
Index: libcfa/src/concurrency/clib/cfathread.cfa
===================================================================
--- libcfa/src/concurrency/clib/cfathread.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/clib/cfathread.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -22,4 +22,5 @@
 #include "thread.hfa"
 #include "time.hfa"
+#include "stdlib.hfa"
 
 #include "cfathread.h"
@@ -195,5 +196,5 @@
 				eevent.data.u64 = (uint64_t)active_thread();
 
-				int id = thread_rand() % poller_cnt;
+				int id = prng() % poller_cnt;
 				if(0 != epoll_ctl(poller_fds[id], EPOLL_CTL_ADD, fd, &eevent))
 				{
Index: libcfa/src/concurrency/invoke.h
===================================================================
--- libcfa/src/concurrency/invoke.h	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/invoke.h	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -10,6 +10,6 @@
 // Created On       : Tue Jan 17 12:27:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jan  6 16:37:40 2022
-// Update Count     : 47
+// Last Modified On : Sun Jan  9 19:06:45 2022
+// Update Count     : 48
 //
 
@@ -211,4 +211,6 @@
 		struct processor * last_proc;
 
+		uint32_t random_state;							// fast random numbers
+
 		#if defined( __CFA_WITH_VERIFY__ )
 			void * canary;
Index: libcfa/src/concurrency/io.cfa
===================================================================
--- libcfa/src/concurrency/io.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/io.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -552,4 +552,6 @@
 			/* paranoid */ verify( proc == __cfaabi_tls.this_processor );
 			/* paranoid */ verify( ! __preemption_enabled() );
+
+			return true;
 		}
 	#endif
Index: libcfa/src/concurrency/kernel.cfa
===================================================================
--- libcfa/src/concurrency/kernel.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/kernel.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -554,5 +554,4 @@
 	/* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd->canary );
 
-	const bool local = thrd->state != Start;
 	if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
 
Index: libcfa/src/concurrency/kernel.hfa
===================================================================
--- libcfa/src/concurrency/kernel.hfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/kernel.hfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -67,6 +67,5 @@
 		unsigned target;
 		unsigned last;
-		unsigned cnt;
-		unsigned long long int cutoff;
+		signed   cpu;
 	} rdq;
 
@@ -152,4 +151,8 @@
 	volatile unsigned long long tv;
 	volatile unsigned long long ma;
+};
+
+struct __attribute__((aligned(16))) __cache_id_t {
+	volatile unsigned id;
 };
 
@@ -164,6 +167,10 @@
 static inline void ^?{}(__timestamp_t & this) {}
 
+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 relaxed ready queue
+// Structure holding the ready queue
 struct __ready_queue_t {
 	// Data tracking the actual lanes
@@ -177,4 +184,6 @@
 		// Array of times
 		__timestamp_t * volatile tscs;
+
+		__cache_id_t * volatile caches;
 
 		// Array of stats
Index: libcfa/src/concurrency/kernel/fwd.hfa
===================================================================
--- libcfa/src/concurrency/kernel/fwd.hfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/kernel/fwd.hfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -77,34 +77,19 @@
 
 		static inline uint64_t __tls_rand() {
+			return
 			#if defined(__SIZEOF_INT128__)
-				return __lehmer64( kernelTLS().rand_seed );
+				lehmer64( kernelTLS().rand_seed );
 			#else
-				return __xorshift64( kernelTLS().rand_seed );
+				xorshift_13_7_17( kernelTLS().rand_seed );
 			#endif
 		}
 
-		#define M  (1_l64u << 48_l64u)
-		#define A  (25214903917_l64u)
-		#define AI (18446708753438544741_l64u)
-		#define C  (11_l64u)
-		#define D  (16_l64u)
-
 		static inline unsigned __tls_rand_fwd() {
-
-			kernelTLS().ready_rng.fwd_seed = (A * kernelTLS().ready_rng.fwd_seed + C) & (M - 1);
-			return kernelTLS().ready_rng.fwd_seed >> D;
+			return LCGBI_fwd( kernelTLS().ready_rng.fwd_seed );
 		}
 
 		static inline unsigned __tls_rand_bck() {
-			unsigned int r = kernelTLS().ready_rng.bck_seed >> D;
-			kernelTLS().ready_rng.bck_seed = AI * (kernelTLS().ready_rng.bck_seed - C) & (M - 1);
-			return r;
-		}
-
-		#undef M
-		#undef A
-		#undef AI
-		#undef C
-		#undef D
+			return LCGBI_bck( kernelTLS().ready_rng.bck_seed );
+		}
 
 		static inline void __tls_rand_advance_bck(void) {
@@ -112,6 +97,4 @@
 		}
 	}
-
-
 
 	extern void disable_interrupts();
@@ -142,6 +125,4 @@
 			}
 		}
-
-		extern uint64_t thread_rand();
 
 		// Semaphore which only supports a single thread
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -34,4 +34,5 @@
 #include "kernel_private.hfa"
 #include "startup.hfa"          // STARTUP_PRIORITY_XXX
+#include "limits.hfa"
 #include "math.hfa"
 
@@ -101,4 +102,5 @@
 extern void __wake_proc(processor *);
 extern int cfa_main_returned;							// from interpose.cfa
+extern uint32_t __global_random_seed;
 
 //-----------------------------------------------------------------------------
@@ -174,5 +176,4 @@
 	this.context = &storage_mainThreadCtx;
 }
-
 
 
@@ -489,4 +490,5 @@
 	preferred = ready_queue_new_preferred();
 	last_proc = 0p;
+	random_state = __global_random_seed;
 	#if defined( __CFA_WITH_VERIFY__ )
 		canary = 0x0D15EA5E0D15EA5Ep;
@@ -513,8 +515,9 @@
 	this.rdq.its = 0;
 	this.rdq.itr = 0;
-	this.rdq.id  = -1u;
-	this.rdq.target = -1u;
-	this.rdq.last = -1u;
-	this.rdq.cutoff = 0ull;
+	this.rdq.id  = MAX;
+	this.rdq.target = MAX;
+	this.rdq.last = MAX;
+	this.rdq.cpu = 0;
+	// this.rdq.cutoff = 0ull;
 	do_terminate = false;
 	preemption_alarm = 0p;
@@ -684,4 +687,6 @@
 	uint_fast32_t last_size;
 	[this->unique_id, last_size] = ready_mutate_register();
+
+		this->rdq.cpu = __kernel_getcpu();
 
 		this->cltr->procs.total += 1u;
Index: libcfa/src/concurrency/locks.hfa
===================================================================
--- libcfa/src/concurrency/locks.hfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/locks.hfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -29,103 +29,4 @@
 #include "time_t.hfa"
 #include "time.hfa"
-
-//-----------------------------------------------------------------------------
-// Semaphores
-
-// '0-nary' semaphore
-// Similar to a counting semaphore except the value of one is never reached
-// as a consequence, a V() that would bring the value to 1 *spins* until
-// a P consumes it
-struct Semaphore0nary {
-	__spinlock_t lock; // needed to protect
-	mpsc_queue(thread$) queue;
-};
-
-static inline bool P(Semaphore0nary & this, thread$ * thrd) {
-	/* paranoid */ verify(!thrd`next);
-	/* paranoid */ verify(!(&(*thrd)`next));
-
-	push(this.queue, thrd);
-	return true;
-}
-
-static inline bool P(Semaphore0nary & this) {
-    thread$ * thrd = active_thread();
-    P(this, thrd);
-    park();
-    return true;
-}
-
-static inline thread$ * V(Semaphore0nary & this, bool doUnpark = true) {
-	thread$ * next;
-	lock(this.lock __cfaabi_dbg_ctx2);
-		for (;;) {
-			next = pop(this.queue);
-			if (next) break;
-			Pause();
-		}
-	unlock(this.lock);
-
-	if (doUnpark) unpark(next);
-	return next;
-}
-
-// Wrapper used on top of any sempahore to avoid potential locking
-struct BinaryBenaphore {
-	volatile ssize_t counter;
-};
-
-static inline {
-	void ?{}(BinaryBenaphore & this) { this.counter = 0; }
-	void ?{}(BinaryBenaphore & this, zero_t) { this.counter = 0; }
-	void ?{}(BinaryBenaphore & this, one_t ) { this.counter = 1; }
-
-	// returns true if no blocking needed
-	bool P(BinaryBenaphore & this) {
-		return __atomic_fetch_sub(&this.counter, 1, __ATOMIC_SEQ_CST) > 0;
-	}
-
-	bool tryP(BinaryBenaphore & this) {
-		ssize_t c = this.counter;
-		/* paranoid */ verify( c > MIN );
-		return (c >= 1) && __atomic_compare_exchange_n(&this.counter, &c, c-1, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
-	}
-
-	// returns true if notify needed
-	bool V(BinaryBenaphore & this) {
-		ssize_t c = 0;
-		for () {
-			/* paranoid */ verify( this.counter < MAX );
-			if (__atomic_compare_exchange_n(&this.counter, &c, c+1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
-				if (c == 0) return true;
-				/* paranoid */ verify(c < 0);
-				return false;
-			} else {
-				if (c == 1) return true;
-				/* paranoid */ verify(c < 1);
-				Pause();
-			}
-		}
-	}
-}
-
-// Binary Semaphore based on the BinaryBenaphore on top of the 0-nary Semaphore
-struct ThreadBenaphore {
-	BinaryBenaphore ben;
-	Semaphore0nary  sem;
-};
-
-static inline void ?{}(ThreadBenaphore & this) {}
-static inline void ?{}(ThreadBenaphore & this, zero_t) { (this.ben){ 0 }; }
-static inline void ?{}(ThreadBenaphore & this, one_t ) { (this.ben){ 1 }; }
-
-static inline bool P(ThreadBenaphore & this)              { return P(this.ben) ? false : P(this.sem); }
-static inline bool tryP(ThreadBenaphore & this)           { return tryP(this.ben); }
-static inline bool P(ThreadBenaphore & this, bool wait)   { return wait ? P(this) : tryP(this); }
-
-static inline thread$ * V(ThreadBenaphore & this, bool doUnpark = true) {
-	if (V(this.ben)) return 0p;
-	return V(this.sem, doUnpark);
-}
 
 //-----------------------------------------------------------------------------
@@ -171,51 +72,4 @@
 static inline void   on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
 static inline void   on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
-
-struct fast_lock {
-	thread$ * volatile owner;
-	ThreadBenaphore sem;
-};
-
-static inline void ?{}(fast_lock & this) __attribute__((deprecated("use linear_backoff_then_block_lock instead")));
-static inline void ?{}(fast_lock & this) { this.owner = 0p; }
-
-static inline bool $try_lock(fast_lock & this, thread$ * thrd) {
-    thread$ * exp = 0p;
-    return __atomic_compare_exchange_n(&this.owner, &exp, thrd, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
-}
-
-static inline void lock( fast_lock & this ) __attribute__((deprecated("use linear_backoff_then_block_lock instead"), artificial));
-static inline void lock( fast_lock & this ) {
-	thread$ * thrd = active_thread();
-	/* paranoid */verify(thrd != this.owner);
-
-	for (;;) {
-		if ($try_lock(this, thrd)) return;
-		P(this.sem);
-	}
-}
-
-static inline bool try_lock( fast_lock & this ) __attribute__((deprecated("use linear_backoff_then_block_lock instead"), artificial));
-static inline bool try_lock ( fast_lock & this ) {
-	thread$ * thrd = active_thread();
-	/* paranoid */ verify(thrd != this.owner);
-	return $try_lock(this, thrd);
-}
-
-static inline thread$ * unlock( fast_lock & this ) __attribute__((deprecated("use linear_backoff_then_block_lock instead"), artificial));
-static inline thread$ * unlock( fast_lock & this ) {
-	/* paranoid */ verify(active_thread() == this.owner);
-
-	// open 'owner' before unlocking anyone
-	// so new and unlocked threads don't park incorrectly.
-	// This may require additional fencing on ARM.
-	this.owner = 0p;
-
-	return V(this.sem);
-}
-
-static inline size_t on_wait( fast_lock & this ) { unlock(this); return 0; }
-static inline void on_wakeup( fast_lock & this, size_t ) { lock(this); }
-static inline void on_notify( fast_lock &, struct thread$ * t ) { unpark(t); }
 
 struct mcs_node {
Index: libcfa/src/concurrency/ready_queue.cfa
===================================================================
--- libcfa/src/concurrency/ready_queue.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/ready_queue.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -20,7 +20,8 @@
 
 
-#define USE_RELAXED_FIFO
+// #define USE_RELAXED_FIFO
 // #define USE_WORK_STEALING
 // #define USE_CPU_WORK_STEALING
+#define USE_AWARE_STEALING
 
 #include "bits/defs.hfa"
@@ -29,4 +30,5 @@
 
 #include "stdlib.hfa"
+#include "limits.hfa"
 #include "math.hfa"
 
@@ -54,5 +56,8 @@
 #endif
 
-#if   defined(USE_CPU_WORK_STEALING)
+#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)
@@ -138,5 +143,4 @@
 	__kernel_rseq_register();
 
-	__cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
 	bool * handle = (bool *)&kernelTLS().sched_lock;
 
@@ -174,6 +178,4 @@
 	}
 
-	__cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p done, id %lu\n", proc, n);
-
 	// Return new spot.
 	/* paranoid */ verify(n < ready);
@@ -190,6 +192,4 @@
 
 	__atomic_store_n(cell, 0p, __ATOMIC_RELEASE);
-
-	__cfadbg_print_safe(ready_queue, "Kernel : Unregister proc %p\n", proc);
 
 	__kernel_rseq_unregister();
@@ -244,11 +244,45 @@
 
 //=======================================================================
+// 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 nval, unsigned long long oval) {
-	const unsigned long long tw = 16;
-	const unsigned long long nw = 4;
-	const unsigned long long ow = tw - nw;
-	return ((nw * nval) + (ow * oval)) / tw;
+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;
 }
 
@@ -271,8 +305,9 @@
 		}
 	#else
-		lanes.data  = 0p;
-		lanes.tscs  = 0p;
-		lanes.help  = 0p;
-		lanes.count = 0;
+		lanes.data   = 0p;
+		lanes.tscs   = 0p;
+		lanes.caches = 0p;
+		lanes.help   = 0p;
+		lanes.count  = 0;
 	#endif
 }
@@ -285,8 +320,133 @@
 	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 ) );
+			}
+		} 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) {
@@ -350,4 +510,5 @@
 		/* paranoid */ verify( kernelTLS().this_processor );
 
+		processor * const proc = kernelTLS().this_processor;
 		const int cpu = __kernel_getcpu();
 		/* paranoid */ verify(cpu >= 0);
@@ -360,16 +521,15 @@
 		/* 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);
 
-		processor * const proc = kernelTLS().this_processor;
 		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 == -1u) {
+		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);
+				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;
+			//  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.
@@ -384,10 +544,10 @@
 			}
 
-			/* paranoid */ verify(proc->rdq.target != -1u);
+			/* 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);
+				unsigned long long tsc = moving_average(ctsc, ts(lanes.data[start + i]), lanes.tscs[start + i].ma);
 				if(tsc > max) max = tsc;
 			}
@@ -395,22 +555,21 @@
 			{
 				unsigned target = proc->rdq.target;
-				proc->rdq.target = -1u;
+				proc->rdq.target = MAX;
 				lanes.help[target / READYQ_SHARD_FACTOR].tri++;
-				if(moving_average(ctsc - lanes.tscs[target].tv, lanes.tscs[target].ma) > cutoff) {
+				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;
-					else proc->rdq.target = -1u;
 				}
-				else proc->rdq.target = -1u;
+				proc->rdq.target = MAX;
 			}
 
 			unsigned last = proc->rdq.last;
-			if(last != -1u && lanes.tscs[last].tv < cutoff && ts(lanes.data[last]) < cutoff) {
+			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 = -1u;
+				proc->rdq.last = MAX;
 			}
 		}
@@ -428,8 +587,8 @@
 		processor * const proc = kernelTLS().this_processor;
 		unsigned last = proc->rdq.last;
-		if(last != -1u) {
+		if(last != MAX) {
 			struct thread$ * t = try_pop(cltr, last __STATS(, __tls_stats()->ready.pop.steal));
 			if(t) return t;
-			proc->rdq.last = -1u;
+			proc->rdq.last = MAX;
 		}
 
@@ -560,5 +719,5 @@
 		#else
 			unsigned preferred = thrd->preferred;
-			const bool external = (hint != UNPARK_LOCAL) || (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr;
+			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 );
 
@@ -612,5 +771,5 @@
 		processor * proc = kernelTLS().this_processor;
 
-		if(proc->rdq.target == -1u) {
+		if(proc->rdq.target == MAX) {
 			unsigned long long min = ts(lanes.data[proc->rdq.id]);
 			for(int i = 0; i < READYQ_SHARD_FACTOR; i++) {
@@ -623,5 +782,5 @@
 		else {
 			unsigned target = proc->rdq.target;
-			proc->rdq.target = -1u;
+			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;
@@ -658,4 +817,5 @@
 // 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 );
 	__STATS( stats.attempt++; )
 
@@ -681,5 +841,7 @@
 	// Actually pop the list
 	struct thread$ * thrd;
-	unsigned long long tsc_before = ts(lane);
+	#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 tsv;
 	[thrd, tsv] = pop(lane);
@@ -695,11 +857,14 @@
 	__STATS( stats.success++; )
 
-	#if defined(USE_WORK_STEALING) || defined(USE_CPU_WORK_STEALING)
-		unsigned long long now = rdtscl();
-		lanes.tscs[w].tv = tsv;
-		lanes.tscs[w].ma = moving_average(now > tsc_before ? now - tsc_before : 0, lanes.tscs[w].ma);
+	#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_CPU_WORK_STEALING)
+	#if defined(USE_AWARE_STEALING) || defined(USE_CPU_WORK_STEALING)
 		thrd->preferred = w / READYQ_SHARD_FACTOR;
 	#else
@@ -800,5 +965,5 @@
 		/* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
 		it->rdq.id = value;
-		it->rdq.target = -1u;
+		it->rdq.target = MAX;
 		value += READYQ_SHARD_FACTOR;
 		it = &(*it)`next;
@@ -813,10 +978,9 @@
 
 static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) {
-	#if defined(USE_WORK_STEALING)
+	#if defined(USE_AWARE_STEALING) || defined(USE_WORK_STEALING)
 		lanes.tscs = alloc(lanes.count, lanes.tscs`realloc);
 		for(i; lanes.count) {
-			unsigned long long tsc1 = ts(lanes.data[i]);
-			unsigned long long tsc2 = rdtscl();
-			lanes.tscs[i].tv = min(tsc1, tsc2);
+			lanes.tscs[i].tv = rdtscl();
+			lanes.tscs[i].ma = 0;
 		}
 	#endif
@@ -864,4 +1028,6 @@
 			// Update original
 			lanes.count = ncount;
+
+			lanes.caches = alloc( target, lanes.caches`realloc );
 		}
 
@@ -940,7 +1106,10 @@
 				fix(lanes.data[idx]);
 			}
+
+			lanes.caches = alloc( target, lanes.caches`realloc );
 		}
 
 		fix_times(cltr);
+
 
 		reassign_cltr_id(cltr);
Index: libcfa/src/concurrency/thread.cfa
===================================================================
--- libcfa/src/concurrency/thread.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/concurrency/thread.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -10,6 +10,6 @@
 // Created On       : Tue Jan 17 12:27:26 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Dec  4 09:17:49 2019
-// Update Count     : 9
+// Last Modified On : Thu Jan 13 20:11:55 2022
+// Update Count     : 42
 //
 
@@ -25,9 +25,9 @@
 #include "invoke.h"
 
-uint64_t thread_rand();
+extern uint32_t __global_random_seed;
 
 //-----------------------------------------------------------------------------
 // Thread ctors and dtors
-void ?{}(thread$ & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
+void ?{}( thread$ & this, const char * const name, cluster & cl, void * storage, size_t storageSize ) with( this ) {
 	context{ 0p, 0p };
 	self_cor{ name, storage, storageSize };
@@ -45,4 +45,5 @@
 	preferred = ready_queue_new_preferred();
 	last_proc = 0p;
+	random_state = __global_random_seed;
 	#if defined( __CFA_WITH_VERIFY__ )
 		canary = 0x0D15EA5E0D15EA5Ep;
@@ -171,10 +172,12 @@
 }
 
-uint64_t thread_rand() {
-	disable_interrupts();
-	uint64_t ret = __tls_rand();
-	enable_interrupts();
-	return ret;
-}
+//-----------------------------------------------------------------------------
+#define GENERATOR LCG
+
+void set_seed( uint32_t seed ) {
+ 	active_thread()->random_state = __global_random_seed = seed;
+	GENERATOR( active_thread()->random_state );
+} // set_seed
+uint32_t prng( void ) { return GENERATOR( active_thread()->random_state ); } // [0,UINT_MAX]
 
 // Local Variables: //
Index: libcfa/src/device/cpu.cfa
===================================================================
--- libcfa/src/device/cpu.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/device/cpu.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -427,10 +427,9 @@
 			unsigned c = pairings[i].cpu;
 			unsigned llc_id = pairings[i].id;
-			unsigned width = maps[llc_id].raw->width;
 			unsigned start = maps[llc_id].start;
-			unsigned self  = start + (maps[llc_id].count++);
-			entries[c].count = width;
+			entries[c].count = maps[llc_id].raw->width;
 			entries[c].start = start;
-			entries[c].self  = self;
+			entries[c].self  = start + (maps[llc_id].count++);
+			entries[c].cache = llc_id;
 		}
 
Index: libcfa/src/device/cpu.hfa
===================================================================
--- libcfa/src/device/cpu.hfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/device/cpu.hfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -16,8 +16,19 @@
 #include <stddef.h>
 
+// Map from cpu entry to a structure detailling cpus with common topologies
+// Note that the cpu-groups are contiguous so the indexing is different from
+// the cpu indexing
 struct cpu_map_entry_t {
+	// Where this particular cpu is in the group
 	unsigned self;
+
+	// Starting index of the cpus with the same topology
 	unsigned start;
+
+	// Number of cpus with the same topology
 	unsigned count;
+
+	// Index of the cache this entry describes
+	unsigned cache;
 };
 
Index: libcfa/src/fstream.cfa
===================================================================
--- libcfa/src/fstream.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/fstream.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Oct 10 11:23:05 2021
-// Update Count     : 512
+// Last Modified On : Mon Jan 10 08:45:05 2022
+// Update Count     : 513
 //
 
@@ -52,5 +52,5 @@
 inline void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
 
-inline void lock( ofstream & os ) with( os ) {	lock( os.lock$ ); }
+inline void lock( ofstream & os ) with( os ) { lock( os.lock$ ); }
 inline void unlock( ofstream & os ) { unlock( os.lock$ ); }
 
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/iostream.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Oct 10 09:28:17 2021
-// Update Count     : 1345
+// Last Modified On : Mon Jan 17 16:38:32 2022
+// Update Count     : 1349
 //
 
@@ -57,5 +57,5 @@
 	ostype & ?|?( ostype & os, signed char sc ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%hhd", sc );
+		fmt( os, "%'hhd", sc );
 		return os;
 	} // ?|?
@@ -66,5 +66,5 @@
 	ostype & ?|?( ostype & os, unsigned char usc ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%hhu", usc );
+		fmt( os, "%'hhu", usc );
 		return os;
 	} // ?|?
@@ -75,5 +75,5 @@
 	ostype & ?|?( ostype & os, short int si ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%hd", si );
+		fmt( os, "%'hd", si );
 		return os;
 	} // ?|?
@@ -84,5 +84,5 @@
 	ostype & ?|?( ostype & os, unsigned short int usi ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%hu", usi );
+		fmt( os, "%'hu", usi );
 		return os;
 	} // ?|?
@@ -93,5 +93,5 @@
 	ostype & ?|?( ostype & os, int i ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%d", i );
+		fmt( os, "%'d", i );
 		return os;
 	} // ?|?
@@ -102,5 +102,5 @@
 	ostype & ?|?( ostype & os, unsigned int ui ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%u", ui );
+		fmt( os, "%'u", ui );
 		return os;
 	} // ?|?
@@ -111,5 +111,5 @@
 	ostype & ?|?( ostype & os, long int li ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%ld", li );
+		fmt( os, "%'ld", li );
 		return os;
 	} // ?|?
@@ -120,5 +120,5 @@
 	ostype & ?|?( ostype & os, unsigned long int uli ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%lu", uli );
+		fmt( os, "%'lu", uli );
 		return os;
 	} // ?|?
@@ -129,5 +129,5 @@
 	ostype & ?|?( ostype & os, long long int lli ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%lld", lli );
+		fmt( os, "%'lld", lli );
 		return os;
 	} // ?|?
@@ -138,5 +138,5 @@
 	ostype & ?|?( ostype & os, unsigned long long int ulli ) {
 		if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
-		fmt( os, "%llu", ulli );
+		fmt( os, "%'llu", ulli );
 		return os;
 	} // ?|?
@@ -496,5 +496,5 @@
 		if ( ! f.flags.pc ) memcpy( &fmtstr, IFMTNP, sizeof(IFMTNP) ); \
 		else memcpy( &fmtstr, IFMTP, sizeof(IFMTP) ); \
-		int star = 4;									/* position before first '*' */ \
+		int star = 5;									/* position before first '*' */ \
 \
 		/* Insert flags into spaces before '*', from right to left. */ \
@@ -503,4 +503,5 @@
 		if ( f.flags.sign ) { fmtstr[star] = '+'; star -= 1; } \
 		if ( f.flags.pad0 && ! f.flags.pc ) { fmtstr[star] = '0'; star -= 1; } \
+		fmtstr[star] = '\''; star -= 1;					/* locale */ \
 		fmtstr[star] = '%'; \
 \
@@ -521,14 +522,14 @@
 } // distribution
 
-IntegralFMTImpl( signed char, "     *hh ", "     *.*hh " )
-IntegralFMTImpl( unsigned char, "     *hh ", "     *.*hh " )
-IntegralFMTImpl( signed short int, "     *h ", "     *.*h " )
-IntegralFMTImpl( unsigned short int, "     *h ", "     *.*h " )
-IntegralFMTImpl( signed int, "     * ", "     *.* " )
-IntegralFMTImpl( unsigned int, "     * ", "     *.* " )
-IntegralFMTImpl( signed long int, "     *l ", "     *.*l " )
-IntegralFMTImpl( unsigned long int, "     *l ", "     *.*l " )
-IntegralFMTImpl( signed long long int, "     *ll ", "     *.*ll " )
-IntegralFMTImpl( unsigned long long int, "     *ll ", "     *.*ll " )
+IntegralFMTImpl( signed char,            "      *hh ", "      *.*hh " )
+IntegralFMTImpl( unsigned char,          "      *hh ", "      *.*hh " )
+IntegralFMTImpl( signed short int,       "      *h ",  "      *.*h " )
+IntegralFMTImpl( unsigned short int,     "      *h ",  "      *.*h " )
+IntegralFMTImpl( signed int,             "      * ",   "      *.* " )
+IntegralFMTImpl( unsigned int,           "      * ",   "      *.* " )
+IntegralFMTImpl( signed long int,        "      *l ",  "      *.*l " )
+IntegralFMTImpl( unsigned long int,      "      *l ",  "      *.*l " )
+IntegralFMTImpl( signed long long int,   "      *ll ", "      *.*ll " )
+IntegralFMTImpl( unsigned long long int, "      *ll ", "      *.*ll " )
 
 
Index: libcfa/src/parseconfig.cfa
===================================================================
--- libcfa/src/parseconfig.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/parseconfig.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -1,2 +1,10 @@
+
+
+#pragma GCC diagnostic push
+//#pragma GCC diagnostic ignored "-Wunused-parameter"
+//#pragma GCC diagnostic ignored "-Wunused-function"
+//#pragma GCC diagnostic ignored "-Wuninitialized"
+//#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+
 #include <fstream.hfa>
 #include <parseargs.hfa>
@@ -19,12 +27,5 @@
 // TODO: use string interface when it's ready (and implement exception msg protocol)
 [ void ] msg( * Missing_Config_Entries ex ) {
-	serr | nlOff;
-	serr | "The config file is missing " | ex->num_missing;
-	serr | nlOn;
-	if ( ex->num_missing == 1 ) {
-		serr | " entry.";
-	} else {
-		serr | " entries.";
-	}
+	serr | "The config file is missing " | ex->num_missing | "entr" | sepOff | (ex->num_missing == 1 ? "y." : "ies.");
 } // msg
 
@@ -223,4 +224,5 @@
 	return value < zero_val;
 }
+#pragma GCC diagnostic pop
 
 
Index: libcfa/src/startup.cfa
===================================================================
--- libcfa/src/startup.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/startup.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -10,6 +10,6 @@
 // Created On       : Tue Jul 24 16:21:57 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jan  9 23:18:23 2021
-// Update Count     : 34
+// Last Modified On : Mon Jan 17 16:41:54 2022
+// Update Count     : 55
 //
 
@@ -17,5 +17,9 @@
 #include <locale.h>										// setlocale
 #include <stdlib.h>										// getenv
+#include "bits/defs.hfa"								// rdtscl
 #include "startup.hfa"
+
+extern uint32_t __global_random_seed;					// sequential/concurrent
+extern uint32_t __global_random_state;					// sequential
 
 extern "C" {
@@ -23,5 +27,4 @@
 	void __cfaabi_appready_startup( void ) {
 		tzset();										// initialize time global variables
-		setlocale( LC_NUMERIC, getenv("LANG") );
 		#ifdef __CFA_DEBUG__
 		extern void heapAppStart();
@@ -48,4 +51,5 @@
 	void __cfaabi_core_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_CORE ) ));
 	void __cfaabi_core_startup( void ) {
+		__global_random_state = __global_random_seed = rdtscl();
 		__cfaabi_interpose_startup();
 		__cfaabi_device_startup();
Index: libcfa/src/stdlib.cfa
===================================================================
--- libcfa/src/stdlib.cfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/stdlib.cfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -10,9 +10,11 @@
 // Created On       : Thu Jan 28 17:10:29 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Jan  3 09:36:27 2022
-// Update Count     : 519
+// Last Modified On : Thu Jan 13 21:38:30 2022
+// Update Count     : 593
 //
 
 #include "stdlib.hfa"
+#include "bits/random.hfa"
+#include "concurrency/invoke.h"							// random_state
 
 //---------------------------------------
@@ -221,30 +223,15 @@
 //---------------------------------------
 
-static uint32_t seed = 0;								// current seed
-static thread_local uint32_t state;						// random state
-
-void set_seed( uint32_t seed_ ) { state = seed = seed_; }
-uint32_t get_seed() { return seed; }
-
 #define GENERATOR LCG
 
-inline uint32_t MarsagliaXor( uint32_t & state ) {
-	if ( unlikely( seed == 0 ) ) set_seed( rdtscl() );
-	else if ( unlikely( state == 0 ) ) state = seed;
-	state ^= state << 6;
-	state ^= state >> 21;
-	state ^= state << 7;
-	return state;
-} // MarsagliaXor
-
-inline uint32_t LCG( uint32_t & state ) {				// linear congruential generator
-	if ( unlikely( seed == 0 ) ) set_seed( rdtscl() );
-	else if ( unlikely( state == 0 ) ) state = seed;
-	return state = 36969 * (state & 65535) + (state >> 16); // 36969 is NOT prime!
-} // LCG
-
+uint32_t __global_random_seed;							// sequential/concurrent
+uint32_t __global_random_state;						// sequential only
+
+void set_seed( PRNG & prng, uint32_t seed_ ) with( prng ) { state = seed = seed_; GENERATOR( state ); } // set seed
 uint32_t prng( PRNG & prng ) with( prng ) { callcnt += 1; return GENERATOR( state ); }
 
-uint32_t prng( void ) { return GENERATOR( state ); }
+void set_seed( uint32_t seed ) { __global_random_seed = seed; GENERATOR( __global_random_state ); }
+uint32_t get_seed() { return __global_random_seed; }
+uint32_t prng( void ) { return GENERATOR( __global_random_state ); } // [0,UINT_MAX]
 
 //---------------------------------------
Index: libcfa/src/stdlib.hfa
===================================================================
--- libcfa/src/stdlib.hfa	(revision 21a5bfb7aa47de48d1ceaac199ed25291ef03b83)
+++ libcfa/src/stdlib.hfa	(revision 175f9f442245bf2962d704caa69c27b31711d255)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:12:35 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jan  2 22:53:57 2022
-// Update Count     : 594
+// Last Modified On : Thu Jan 13 21:34:46 2022
+// Update Count     : 636
 //
 
@@ -21,4 +21,5 @@
 #include <stdlib.h>										// *alloc, strto*, ato*
 #include <heap.hfa>
+
 
 // Reduce includes by explicitly defining these routines.
@@ -207,5 +208,4 @@
 
 	forall( TT... | { T * alloc_internal$( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
-
 		T * alloc_internal$( void *       , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {
 	        return alloc_internal$( Resize, (T*)0p, Align, Dim, Fill, rest);
@@ -231,5 +231,4 @@
 	    	return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all);
 	    }
-
 	} // distribution TT
 } // distribution T
@@ -385,4 +384,23 @@
 //---------------------------------------
 
+// Sequential Pseudo Random-Number Generator : generate repeatable sequence of values that appear random.
+//
+// Declaration :
+//   PRNG sprng = { 1009 } - set starting seed versus random seed
+//   
+// Interface :
+//   set_seed( sprng, 1009 ) - set starting seed for ALL kernel threads versus random seed
+//   get_seed( sprng ) - read seed
+//   prng( sprng ) - generate random value in range [0,UINT_MAX]
+//   prng( sprng, u ) - generate random value in range [0,u)
+//   prng( sprng, l, u ) - generate random value in range [l,u]
+//   calls( sprng ) - number of generated random value so far
+//
+// Examples : generate random number between 5-21
+//   prng( sprng ) % 17 + 5;	values 0-16 + 5 = 5-21
+//   prng( sprng, 16 + 1 ) + 5;
+//   prng( sprng, 5, 21 );
+//   calls( sprng );
+
 struct PRNG {
 	uint32_t callcnt;									// call count
@@ -391,7 +409,7 @@
 }; // PRNG
 
-extern uint32_t prng( PRNG & prng ) __attribute__(( warn_unused_result )); // [0,UINT_MAX]
+void set_seed( PRNG & prng, uint32_t seed_ );
+uint32_t prng( PRNG & prng ) __attribute__(( warn_unused_result )); // [0,UINT_MAX]
 static inline {
-	void set_seed( PRNG & prng, uint32_t seed_ ) with( prng ) { state = seed = seed_; } // set seed
 	void ?{}( PRNG & prng ) { set_seed( prng, rdtscl() ); }	// random seed
 	void ?{}( PRNG & prng, uint32_t seed ) { set_seed( prng, seed ); } // fixed seed
@@ -402,12 +420,24 @@
 } // distribution
 
-extern void set_seed( uint32_t seed );					// set per thread seed
-extern uint32_t get_seed();								// get seed
-extern uint32_t prng( void ) __attribute__(( warn_unused_result )); // [0,UINT_MAX]
+// Concurrent Pseudo Random-Number Generator : generate repeatable sequence of values that appear random.
+//
+// Interface :
+//   set_seed( 1009 ) - fixed seed for all kernel threads versus random seed
+//   get_seed() - read seed
+//   prng() - generate random value in range [0,UINT_MAX]
+//   prng( u ) - generate random value in range [0,u)
+//   prng( l, u ) - generate random value in range [l,u]
+//
+// Examples : generate random number between 5-21
+//   prng() % 17 + 5;	values 0-16 + 5 = 5-21
+//   prng( 16 + 1 ) + 5;
+//   prng( 5, 21 );
+
+void set_seed( uint32_t seed_ ) OPTIONAL_THREAD;
+uint32_t get_seed() __attribute__(( warn_unused_result ));
+uint32_t prng( void ) __attribute__(( warn_unused_result )) OPTIONAL_THREAD; // [0,UINT_MAX]
 static inline {
-	uint32_t prng( uint32_t u ) __attribute__(( warn_unused_result ));
-	uint32_t prng( uint32_t u ) { return prng() % u; }	// [0,u)
-	uint32_t prng( uint32_t l, uint32_t u ) __attribute__(( warn_unused_result ));
-	uint32_t prng( uint32_t l, uint32_t u ) { return prng( u - l + 1 ) + l; } // [l,u]
+	uint32_t prng( uint32_t u ) __attribute__(( warn_unused_result )) { return prng() % u; } // [0,u)
+	uint32_t prng( uint32_t l, uint32_t u ) __attribute__(( warn_unused_result )) { return prng( u - l + 1 ) + l; } // [l,u]
 } // distribution
 
