Index: libcfa/configure.ac
===================================================================
--- libcfa/configure.ac	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ libcfa/configure.ac	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -181,4 +181,5 @@
 AH_TEMPLATE([CFA_HAVE_SPLICE_F_FD_IN_FIXED],[Defined if io_uring support is present when compiling libcfathread and supports the flag SPLICE_F_FD_IN_FIXED.])
 AH_TEMPLATE([CFA_HAVE_IORING_SETUP_ATTACH_WQ],[Defined if io_uring support is present when compiling libcfathread and supports the flag IORING_SETUP_ATTACH_WQ.])
+AH_TEMPLATE([CFA_HAVE_IORING_REGISTER_IOWQ_MAX_WORKERS],[Defined if io_uring support is present when compiling libcfathread and supports the flag IORING_REGISTER_IOWQ_MAX_WORKERS.])
 AH_TEMPLATE([CFA_HAVE_PREADV2],[Defined if preadv2 support is present when compiling libcfathread.])
 AH_TEMPLATE([CFA_HAVE_PWRITEV2],[Defined if pwritev2 support is present when compiling libcfathread.])
@@ -189,5 +190,5 @@
 
 define(ioring_ops, [IORING_OP_NOP,IORING_OP_READV,IORING_OP_WRITEV,IORING_OP_FSYNC,IORING_OP_READ_FIXED,IORING_OP_WRITE_FIXED,IORING_OP_POLL_ADD,IORING_OP_POLL_REMOVE,IORING_OP_SYNC_FILE_RANGE,IORING_OP_SENDMSG,IORING_OP_RECVMSG,IORING_OP_TIMEOUT,IORING_OP_TIMEOUT_REMOVE,IORING_OP_ACCEPT,IORING_OP_ASYNC_CANCEL,IORING_OP_LINK_TIMEOUT,IORING_OP_CONNECT,IORING_OP_FALLOCATE,IORING_OP_OPENAT,IORING_OP_CLOSE,IORING_OP_FILES_UPDATE,IORING_OP_STATX,IORING_OP_READ,IORING_OP_WRITE,IORING_OP_FADVISE,IORING_OP_MADVISE,IORING_OP_SEND,IORING_OP_RECV,IORING_OP_OPENAT2,IORING_OP_EPOLL_CTL,IORING_OP_SPLICE,IORING_OP_PROVIDE_BUFFERS,IORING_OP_REMOVE_BUFFER,IORING_OP_TEE])
-define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,IOSQE_ASYNC,IOSQE_BUFFER_SELECT,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ])
+define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,IOSQE_ASYNC,IOSQE_BUFFER_SELECT,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ,IORING_REGISTER_IOWQ_MAX_WORKERS])
 
 define(ioring_from_decls, [
Index: libcfa/src/concurrency/ready_subqueue.hfa
===================================================================
--- libcfa/src/concurrency/ready_subqueue.hfa	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ libcfa/src/concurrency/ready_subqueue.hfa	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -49,5 +49,5 @@
 	// Get the relevant nodes locally
 	this.prev->link.next = node;
-	this.prev->link.ts   = rdtscl();
+	__atomic_store_n(&this.prev->link.ts, rdtscl(), __ATOMIC_RELAXED);
 	this.prev = node;
 	#if !defined(__CFA_NO_STATISTICS__)
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/AST/Pass.impl.hpp	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -648,4 +648,5 @@
 	if ( __visit_children() ) {
 		// unlike structs, traits, and unions, enums inject their members into the global scope
+		maybe_accept( node, &EnumDecl::base );
 		maybe_accept( node, &EnumDecl::params     );
 		maybe_accept( node, &EnumDecl::members    );
Index: src/Common/ResolvProtoDump.cpp
===================================================================
--- src/Common/ResolvProtoDump.cpp	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/Common/ResolvProtoDump.cpp	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -227,5 +227,5 @@
 	}
 
-	void previsit( const ast::EnumInstType * enumInst) {
+	void previsit( const ast::EnumInstType * ) {
 		// TODO: Add the meaningful text representation of typed enum
 		ss << (int)ast::BasicType::SignedInt;
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/GenPoly/GenPoly.cc	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -64,5 +64,5 @@
 		}
 
-		__attribute__((ununsed))
+		__attribute__((unused))
 		bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
 			for (auto &param : params) {
Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/InitTweak/GenInit.cc	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -642,22 +642,22 @@
 
 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) {
-	// call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each 
+	// call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each
 	// constructable object
 	InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
 	ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
-	
-	ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall( 
+
+	ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
 		srcParam, dstParam, loc, "?{}", objDecl );
-	ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall( 
-		nullParam, dstParam, loc, "^?{}", objDecl, 
+	ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
+		nullParam, dstParam, loc, "^?{}", objDecl,
 		SymTab::LoopBackward );
-	
+
 	// check that either both ctor and dtor are present, or neither
 	assert( (bool)ctor == (bool)dtor );
 
 	if ( ctor ) {
-		// need to remember init expression, in case no ctors exist. If ctor does exist, want to 
+		// need to remember init expression, in case no ctors exist. If ctor does exist, want to
 		// use ctor expression instead of init.
-		ctor.strict_as< ast::ImplicitCtorDtorStmt >(); 
+		ctor.strict_as< ast::ImplicitCtorDtorStmt >();
 		dtor.strict_as< ast::ImplicitCtorDtorStmt >();
 
Index: src/Parser/lex.ll
===================================================================
--- src/Parser/lex.ll	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/Parser/lex.ll	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -82,4 +82,7 @@
 // Stop warning due to incorrectly generated flex code.
 #pragma GCC diagnostic ignored "-Wsign-compare"
+
+// lex uses __null in a boolean context, it's fine.
+#pragma GCC diagnostic ignored "-Wnull-conversion"
 %}
 
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/Parser/parser.yy	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -56,4 +56,7 @@
 
 #include "SynTree/Attribute.h"     // for Attribute
+
+// lex uses __null in a boolean context, it's fine.
+#pragma GCC diagnostic ignored "-Wparentheses-equality"
 
 extern DeclarationNode * parseTree;
@@ -1240,5 +1243,5 @@
 		{
 			$$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) );
-			SemanticWarning( yylloc, Warning::SuperfluousElse );
+			SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
 		}
 	| WHILE '(' conditional_declaration ')' statement	%prec THEN
@@ -1251,5 +1254,5 @@
 		{
 			$$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) );
-			SemanticWarning( yylloc, Warning::SuperfluousElse );
+			SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
 		}
 	| DO statement WHILE '(' comma_expression ')' ';'
@@ -1262,5 +1265,5 @@
 		{
 			$$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );
-			SemanticWarning( yylloc, Warning::SuperfluousElse );
+			SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
 		}
 	| FOR '(' for_control_expression_list ')' statement	%prec THEN
@@ -2394,5 +2397,5 @@
 	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
 	 	{
-			if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) 
+			if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 )
 			{ SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
 
@@ -2841,5 +2844,5 @@
 			linkage = LinkageSpec::update( yylloc, linkage, $2 );
 		}
-	  up external_definition down 
+	  up external_definition down
 		{
 			linkage = linkageStack.top();
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/ResolvExpr/CurrentObject.cc	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -73,5 +73,5 @@
 		virtual void setPosition( std::list< Expression * > & designators ) = 0;
 
-		/// retrieve the list of possible Type/Designaton pairs for the current position in the currect object
+		/// retrieve the list of possible Type/Designation pairs for the current position in the currect object
 		virtual std::list<InitAlternative> operator*() const = 0;
 
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/SymTab/Mangler.cc	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -537,4 +537,5 @@
 		}
 
+		__attribute__((unused))
 		inline std::vector< ast::ptr< ast::Type > > getTypes( const std::vector< ast::ptr< ast::DeclWithType > > & decls ) {
 			std::vector< ast::ptr< ast::Type > > ret;
Index: src/SymTab/ValidateType.cc
===================================================================
--- src/SymTab/ValidateType.cc	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/SymTab/ValidateType.cc	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -222,11 +222,19 @@
 	// visit enum members first so that the types of self-referencing members are updated properly
 	// Replace the enum base; right now it works only for StructEnum
-	if ( enumDecl->base && dynamic_cast<TypeInstType*>(enumDecl->base) ) {
-		std::string baseName = static_cast<TypeInstType*>(enumDecl->base)->name;
-		const StructDecl * st = local_indexer->lookupStruct( baseName );
-		if ( st ) {
-			enumDecl->base = new StructInstType(Type::Qualifiers(),const_cast<StructDecl *>(st)); // Just linking in the node
+	if ( enumDecl->base ) {
+		if ( const TypeInstType * base = dynamic_cast< TypeInstType * >(enumDecl->base) ) {
+			if ( const StructDecl * decl = local_indexer->lookupStruct( base->name ) ) {
+				enumDecl->base = new StructInstType( Type::Qualifiers(), const_cast< StructDecl * >( decl ) ); // Just linking in the node
+			}
+		} else if ( const PointerType * ptr = dynamic_cast< PointerType * >(enumDecl->base) ) {
+			if ( const TypeInstType * ptrBase = dynamic_cast< TypeInstType * >( ptr->base ) ) {
+				if ( const StructDecl * decl = local_indexer->lookupStruct( ptrBase->name ) ) {
+					enumDecl->base = new PointerType( Type::Qualifiers(),
+						new StructInstType( Type::Qualifiers(), const_cast< StructDecl * >( decl ) ) );
+				}
+			}
 		}
 	}
+	
 	if ( enumDecl->body ) {
 		ForwardEnumsType::iterator fwds = forwardEnums.find( enumDecl->name );
Index: src/SynTree/Type.h
===================================================================
--- src/SynTree/Type.h	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ src/SynTree/Type.h	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -274,5 +274,5 @@
 class PointerType : public Type {
   public:
-	Type *base;
+	Type * base;
 
 	// In C99, pointer types can be qualified in many ways e.g., int f( int a[ static 3 ] )
@@ -516,6 +516,6 @@
 	typedef ReferenceToType Parent;
   public:
-	// this decl is not "owned" by the union inst; it is merely a pointer to elsewhere in the tree,
-	// where the union used in this type is actually defined
+	// this decl is not "owned" by the enum inst; it is merely a pointer to elsewhere in the tree,
+	// where the enum used in this type is actually defined
 	EnumDecl *baseEnum = nullptr;
 
Index: tests/pybin/tools.py
===================================================================
--- tests/pybin/tools.py	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ tests/pybin/tools.py	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -46,5 +46,5 @@
 
 			print(cmd)
-			return 0, None
+			return 0, None, None
 
 		with contextlib.ExitStack() as onexit:
@@ -291,5 +291,5 @@
 ################################################################################
 def jobserver_version():
-	make_ret, out, err = sh('make', '.test_makeflags', '-j2', output_file=subprocess.PIPE, error=subprocess.PIPE)
+	make_ret, out, err = sh('make', '.test_makeflags', '-j2', ignore_dry_run = True, output_file=subprocess.PIPE, error=subprocess.PIPE)
 	if make_ret != 0:
 		print("ERROR: cannot find Makefile jobserver version", file=sys.stderr)
Index: tools/gdb/utils-gdb.py
===================================================================
--- tools/gdb/utils-gdb.py	(revision 4e83bb73307a616bea9e819e1d7680a4fff893e1)
+++ tools/gdb/utils-gdb.py	(revision d28524acb9d28e8dcfccd23c41645b70dbaf38c2)
@@ -89,62 +89,105 @@
 	return argv
 
-def get_cluster_root():
-	"""
-	Return: gdb.Value of globalClusters.root (is an address)
-	"""
+class ClusterIter:
+	def __init__(self, root):
+		self.curr = None
+		self.root = root
+
+	def __iter__(self):
+		return self
+
+	def __next__(self):
+		# Clusters form a cycle
+		# If we haven't seen the root yet, then the root is the first
+		if not self.curr:
+			self.curr = self.root
+			return self.curr
+
+		# if we already saw the root, then go forward
+		self.curr = self.curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
+
+		# if we reached the root again, then we are done
+		if self.curr == self.root:
+			raise StopIteration
+
+		# otherwise return the next
+		return self.curr
+
+def all_clusters():
+	"""
+	Return: a list of all the clusters as an iterator.
+	obtained from gdb.Value of globalClusters.root (is an address)
+	"""
+	if not is_cforall():
+		return []
+
 	cluster_root = gdb.parse_and_eval('_X11mainClusterPS7cluster_1')
 	if cluster_root.address == 0x0:
 		print('No clusters, program terminated')
-	return cluster_root
-
-def get_sched_lock():
-	"""
-	Return: gdb.Value of __scheduler_lock
-	"""
-	lock = gdb.parse_and_eval('_X16__scheduler_lockPS20__scheduler_RWLock_t_1')
-	if lock.address == 0x0:
-		print('No scheduler lock, program terminated')
-	return lock
-
-def all_clusters():
-	if not is_cforall():
-		return None
-
-	cluster_root = get_cluster_root()
-	if cluster_root.address == 0x0:
-		return
-
-	curr = cluster_root
-	ret = [curr]
-
-	while True:
-		curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
-		if curr == cluster_root:
-			break
-
-		ret.append(curr)
-
-	return ret
+		return []
+
+	return ClusterIter(cluster_root)
+
+class ProcIter:
+	def __init__(self, root):
+		self.curr = None
+		self.root = root
+
+	def __iter__(self):
+		return self
+
+	def check(self):
+		# check if this is the last value
+		addr = int(self.curr)
+		mask = 1 << ((8 * int(gdb.parse_and_eval('sizeof(void*)'))) - 1)
+		if 0 != (mask & addr):
+			raise StopIteration
+
+	def __next__(self):
+		cfa_t = get_cfa_types()
+
+		# Processors form a cycle
+		# If we haven't seen the root yet, then the root is the first
+		if not self.curr:
+			my_next = self.root
+			self.curr = my_next.cast(cfa_t.processor_ptr)
+
+			#check if this is an empty list
+			self.check()
+
+			return self.curr
+
+		# if we already saw the root, then go forward
+		my_next = self.curr['__anonymous_object2225']['_X4nextPY13__tE_generic__1']
+		self.curr = my_next.cast(cfa_t.processor_ptr)
+
+		#check if we reached the end
+		self.check()
+
+		# otherwise return the next
+		return self.curr
+
+def proc_list(cluster):
+	"""
+	Return: for a given processor, return the active and idle processors, as 2 iterators
+	"""
+	cfa_t = get_cfa_types()
+	proclist = cluster['_X5procsS19__cluster_proc_list_1']
+	idle = proclist['_X5idlesS5dlist_S9processorS5dlink_S9processor___1']['__anonymous_object2167']['_X4nextPY13__tE_generic__1']
+	active = proclist['_X7activesS5dlist_S9processorS5dlink_S9processor___1']['__anonymous_object2167']['_X4nextPY13__tE_generic__1']
+	return ProcIter(active.cast(cfa_t.processor_ptr)), ProcIter(idle.cast(cfa_t.processor_ptr))
 
 def all_processors():
-	if not is_cforall():
-		return None
-
-	cfa_t = get_cfa_types()
-
-	# get processors from registration to the RWlock
-	lock = get_sched_lock()
-
-	#get number of elements
-	count = lock['_X5readyVj_1']
-
-	#find all the procs
-	raw_procs = [lock['_X4dataPS21__scheduler_lock_id_t_1'][i]['_X6handleVPS16__processor_id_t_1'] for i in range(count)]
-
-	# pre cast full procs
-	procs = [p.cast(cfa_t.processor_ptr) for p in raw_procs if p['_X9full_procb_1']]
-
-	# sort procs by clusters
-	return sorted(procs, key=lambda p: p['_X4cltrPS7cluster_1'])
+	procs = []
+	for c in all_clusters():
+		active, idle = proc_list(c)
+		for p in active:
+			procs.append(p)
+
+		for p in idle:
+			procs.append(p)
+
+	print(procs)
+	return procs
 
 def tls_for_pthread(pthrd):
@@ -160,5 +203,5 @@
 
 def tls_for_proc(proc):
-	return tls_for_pthread(proc['_X13kernel_threadm_1'])
+	return proc['_X10local_dataPS16KernelThreadData_1']
 
 def thread_for_pthread(pthrd):
@@ -180,5 +223,5 @@
 def lookup_cluster(name = None):
 	"""
-	Look up a cluster given its ID
+	Look up one or more cluster given a name
 	@name: str
 	Return: gdb.Value
@@ -187,27 +230,20 @@
 		return None
 
-	root = get_cluster_root()
-	if root.address == 0x0:
+	clusters = all_clusters()
+	if not clusters:
 		return None
 
 	if not name:
-		return root
+		return clusters.root
 
 	# lookup for the task associated with the id
-	cluster = None
-	curr = root
-	while True:
-		if curr['_X4namePKc_1'].string() == name:
-			cluster = curr.address
-			break
-		curr = curr['_X4nodeS26__cluster____dbg_node_cltr_1']['_X4nextPS7cluster_1']
-		if curr == root or curr == 0x0:
-			break
-
-	if not cluster:
+	found = [c for c in clusters if c['_X4namePKc_1'].string() == name]
+
+	if not found:
 		print("Cannot find a cluster with the name: {}.".format(name))
 		return None
 
-	return cluster
+	return found
+
 
 def lookup_threads_by_cluster(cluster):
@@ -294,11 +330,8 @@
 		super(Processors, self).__init__('info processors', gdb.COMMAND_USER)
 
-	def print_processor(self, processor):
+	def print_processor(self, processor, in_stats):
 		should_stop = processor['_X12do_terminateVb_1']
 		if not should_stop:
-			midle = processor['_X6$linksS7$dlinks_S9processor__1']['_X4nextS9$mgd_link_Y13__tE_generic___1']['_X4elemPY13__tE_generic__1'] != 0x0
-			end   = processor['_X6$linksS7$dlinks_S9processor__1']['_X4nextS9$mgd_link_Y13__tE_generic___1']['_X10terminatorPv_1'] != 0x0
-
-			status = 'Idle' if midle or end else 'Active'
+			status = in_stats
 		else:
 			stop_count  = processor['_X10terminatedS9semaphore_1']['_X5counti_1']
@@ -336,19 +369,18 @@
 			return
 
-		procs = all_processors()
-
 		print('{:>20}  {:>11}  {:<7}  {}'.format('Processor', '', 'Pending', 'Object'))
 		print('{:>20}  {:>11}  {:<7}  {}'.format('Name', 'Status', 'Yield', 'Address'))
-		cl = None
-		for p in procs:
-			# if this is a different cluster print it
-			if cl != p['_X4cltrPS7cluster_1']:
-				if cl:
-					print()
-				cl = p['_X4cltrPS7cluster_1']
-				print('Cluster {}'.format(cl['_X4namePKc_1'].string()))
-
+		for c in clusters:
+			print('Cluster {}'.format(c['_X4namePKc_1'].string()))
+
+			active, idle = proc_list(c)
 			# print the processor information
-			self.print_processor(p)
+			for p in active:
+				self.print_processor(p, 'Active')
+
+			for p in idle:
+				self.print_processor(p, 'Idle')
+
+			print()
 
 		print()
@@ -433,5 +465,5 @@
 			cluster = lookup_cluster(arg)
 			if not cluster:
-				print("Could not find cluster '{}'".format(arg))
+				print("No matching cluster")
 				return
 
