Index: libcfa/src/concurrency/thread.cfa
===================================================================
--- libcfa/src/concurrency/thread.cfa	(revision 8b74fa74db327a2cce113add048683b58496f6f5)
+++ libcfa/src/concurrency/thread.cfa	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
@@ -178,4 +178,50 @@
 
 //-----------------------------------------------------------------------------
+bool migrate( thread$ * thrd, struct cluster & cl ) {
+
+	monitor$ * tmon = get_monitor(thrd);
+	monitor$ * __monitors[] = { tmon };
+	monitor_guard_t __guard = { __monitors, 1 };
+
+
+	{
+		// if nothing needs to be done, return false
+		if( thrd->curr_cluster == &cl ) return false;
+
+		// are we migrating ourself?
+		const bool local = thrd == active_thread();
+
+		/* paranoid */ verify( !local || &cl != active_cluster() );
+		/* paranoid */ verify( !local || thrd->curr_cluster == active_cluster() );
+		/* paranoid */ verify( !local || thrd->curr_cluster == active_processor()->cltr );
+		/* paranoid */ verify( local || tmon->signal_stack.top->owner->waiting_thread == thrd );
+		/* paranoid */ verify( local || tmon->signal_stack.top );
+
+		// make sure we aren't interrupted while doing this
+		// not as important if we aren't local
+		disable_interrupts();
+
+		// actually move the thread
+		unregister( thrd->curr_cluster, *thrd );
+		thrd->curr_cluster = &cl;
+		doregister( thrd->curr_cluster, *thrd );
+
+		// restore interrupts
+		enable_interrupts();
+
+		// if this is the local thread, we are still running on the old cluster
+		if(local) yield();
+
+		/* paranoid */ verify( !local || &cl == active_cluster() );
+		/* paranoid */ verify( !local || thrd->curr_cluster == active_cluster() );
+		/* paranoid */ verify( !local || thrd->curr_cluster == active_processor()->cltr );
+		/* paranoid */ verify(  local || tmon->signal_stack.top );
+		/* paranoid */ verify(  local || tmon->signal_stack.top->owner->waiting_thread == thrd );
+
+		return true;
+	}
+}
+
+//-----------------------------------------------------------------------------
 #define GENERATOR LCG
 
Index: libcfa/src/concurrency/thread.hfa
===================================================================
--- libcfa/src/concurrency/thread.hfa	(revision 8b74fa74db327a2cce113add048683b58496f6f5)
+++ libcfa/src/concurrency/thread.hfa	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
@@ -132,4 +132,12 @@
 
 //----------
+// misc
+bool migrate( thread$ * thrd, struct cluster & cl );
+
+forall( T & | is_thread(T) )
+static inline bool migrate( T & mutex thrd, struct cluster & cl ) { return migrate( &(thread&)thrd, cl ); }
+
+
+//----------
 // prng
 static inline {
Index: tests/concurrent/.expect/migrate.txt
===================================================================
--- tests/concurrent/.expect/migrate.txt	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
+++ tests/concurrent/.expect/migrate.txt	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
@@ -0,0 +1,1 @@
+done
Index: tests/concurrent/migrate.cfa
===================================================================
--- tests/concurrent/migrate.cfa	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
+++ tests/concurrent/migrate.cfa	(revision a167c70c7fa1e05fd7fb5472f69e13eba33b22b7)
@@ -0,0 +1,85 @@
+#include <fstream.hfa>
+#include <kernel.hfa>
+#include <thread.hfa>
+
+#include <stdatomic.h>
+#include <assert.h>
+
+struct cluster_wrapper {
+	cluster self;
+	const uint64_t canary;
+	struct {
+		volatile uint64_t want;
+		volatile uint64_t have;
+	} checksum;
+};
+
+void ?{}( cluster_wrapper & this ) {
+	(this.self){};
+	(*(uint64_t *)&this.canary) = 0xDEAD2BADDEAD2BAD;
+	this.checksum.want = 0;
+	this.checksum.have = 0;
+}
+
+void ^?{}( cluster_wrapper & this ) {
+	assert(this.canary == 0xDEAD2BADDEAD2BAD);
+}
+
+static cluster_wrapper * the_clusters;
+static unsigned cluster_cnt;
+
+thread MyThread {
+
+};
+
+void ?{}( MyThread & this ) {}
+
+void checkcl( MyThread & this, cluster * cl) {
+	if(((thread&)this).curr_cluster != cl) {
+		abort | "Thread has unexpected cluster";
+	}
+}
+
+void main( MyThread & this ) {
+	waitfor( migrate : this ) {
+		assert( ((thread&)this).curr_cluster == active_cluster() );
+		assert( ((thread&)this).curr_cluster == active_processor()->cltr );
+	}
+
+	struct cluster_wrapper * curr = (struct cluster_wrapper *)&the_clusters[0];
+
+	for(100) {
+		unsigned idx = prng( this, cluster_cnt );
+
+		struct cluster_wrapper * next = &the_clusters[ idx ];
+		assert(next->canary == 0xDEAD2BADDEAD2BAD);
+
+		// next->
+
+		migrate( this, next->self );
+
+		assert( active_cluster() == &next->self );
+		assert( ((thread&)this).curr_cluster == active_cluster() );
+		assert( ((thread&)this).curr_cluster == active_processor()->cltr );
+	}
+}
+
+int main() {
+	cluster_cnt = 3;
+	cluster_wrapper cl[cluster_cnt];
+	the_clusters = cl;
+
+	{
+		set_concurrency( cl[0].self, 2 );
+		set_concurrency( cl[1].self, 2 );
+		set_concurrency( cl[2].self, 1 );
+
+		MyThread threads[17];
+		for(i;17) {
+			migrate( threads[i], cl[0].self );
+		}
+
+	}
+	// non-empty .expect file
+	printf( "done\n" );
+}
