Index: trunk/kernel/kern/thread.c
===================================================================
--- trunk/kernel/kern/thread.c	(revision 531)
+++ trunk/kernel/kern/thread.c	(revision 564)
@@ -1,7 +1,7 @@
 /*
- * thread.c -  implementation of thread operations (user & kernel)
+ * thread.c -   thread operations implementation (user & kernel)
  *
  * Author  Ghassan Almaless (2008,2009,2010,2011,2012)
- *         Alain Greiner (2016,2017)
+ *         Alain Greiner (2016,2017,2018)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -48,5 +48,7 @@
 //////////////////////////////////////////////////////////////////////////////////////
 
-extern process_t      process_zero;
+extern process_t            process_zero;       // allocated in kernel_init.c
+extern char               * lock_type_str[];    // allocated in kernel_init.c
+extern chdev_directory_t    chdev_dir;          // allocated in kernel_init.c
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -145,20 +147,11 @@
 	cluster_t    * local_cluster = LOCAL_CLUSTER;
 
-#if DEBUG_THREAD_USER_INIT
+#if DEBUG_THREAD_INIT
 uint32_t cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_THREAD_USER_INIT < cycle )
-printk("\n[DBG] %s : thread %x enter to init thread %x in process %x / cycle %d\n",
-__FUNCTION__, CURRENT_THREAD, thread, process->pid , cycle );
-#endif
-
-    // register new thread in process descriptor, and get a TRDID
-    thread->type = type; // needed by process_register_thread.
-    error = process_register_thread( process, thread , &trdid );
-
-    if( error )
-    {
-        printk("\n[ERROR] in %s : cannot get TRDID\n", __FUNCTION__ );
-        return EINVAL;
-    }
+if( DEBUG_THREAD_INIT < cycle )
+printk("\n[DBG] %s : thread %x in process %x enter fot thread %x in process %x / cycle %d\n",
+__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid,
+ thread, process->pid , cycle );
+#endif
 
     // compute thread descriptor size without kernel stack
@@ -166,5 +159,5 @@
 
 	// Initialize new thread descriptor
-    thread->trdid           = trdid;
+	thread->type            = type;
     thread->quantum         = 0;            // TODO
     thread->ticks_nr        = 0;            // TODO
@@ -173,10 +166,8 @@
 	thread->process         = process;
 
-    thread->local_locks     = 0;
-    thread->remote_locks    = 0;
-
-#if CONFIG_LOCKS_DEBUG 
-    list_root_init( &thread->locks_root );  
-    xlist_root_init( XPTR( local_cxy , &thread->xlocks_root ) );
+    thread->busylocks       = 0;
+
+#if DEBUG_BUSYLOCK
+    xlist_root_init( XPTR( local_cxy , &thread->busylocks_root ) );
 #endif
 
@@ -194,12 +185,28 @@
     thread->blocked         = THREAD_BLOCKED_GLOBAL;
 
-    // reset sched list
+    // register new thread in process descriptor, and get a TRDID
+    error = process_register_thread( process, thread , &trdid );
+
+    if( error )
+    {
+        printk("\n[ERROR] in %s : cannot get TRDID\n", __FUNCTION__ );
+        return EINVAL;
+    }
+
+    // initialize trdid 
+    thread->trdid           = trdid;
+
+    // initialize sched list
     list_entry_init( &thread->sched_list );
 
-    // reset thread info
+    // initialize waiting queue entries
+    list_entry_init( &thread->wait_list );
+    xlist_entry_init( XPTR( local_cxy , &thread->wait_xlist ) );
+
+    // initialize thread info
     memset( &thread->info , 0 , sizeof(thread_info_t) );
 
-    // initializes join_lock
-    remote_spinlock_init( XPTR( local_cxy , &thread->join_lock ) );
+    // initialize join_lock
+    remote_busylock_init( XPTR( local_cxy , &thread->join_lock ), LOCK_THREAD_JOIN );
 
     // initialise signature
@@ -216,9 +223,10 @@
     dqdt_update_threads( 1 );
 
-#if DEBUG_THREAD_USER_INIT
+#if DEBUG_THREAD_INIT
 cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_THREAD_USER_INIT < cycle )
-printk("\n[DBG] %s : thread %x exit  after init of thread %x in process %x / cycle %d\n",
-__FUNCTION__, CURRENT_THREAD, thread, process->pid , cycle );
+if( DEBUG_THREAD_INIT < cycle )
+printk("\n[DBG] %s : thread %x in process %x exit for thread %x in process %x / cycle %d\n",
+__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid,
+thread, process->pid , cycle );
 #endif
 
@@ -436,6 +444,6 @@
     args  = (void *)  hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->entry_args    ));
     base  = (intptr_t)hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->u_stack_base  ));
-    size  = (uint32_t)hal_remote_lw ( XPTR( parent_cxy , &parent_ptr->u_stack_size  ));
-    flags =           hal_remote_lw ( XPTR( parent_cxy , &parent_ptr->flags         ));
+    size  = (uint32_t)hal_remote_l32 ( XPTR( parent_cxy , &parent_ptr->u_stack_size  ));
+    flags =           hal_remote_l32 ( XPTR( parent_cxy , &parent_ptr->flags         ));
     uzone = (reg_t *) hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->uzone_current ));
 
@@ -474,4 +482,11 @@
     }
 
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[DBG] %s : thread %x in process %x / initialised thread %x in process %x\n",
+__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid,
+child_ptr->trdid, child_process->pid );
+#endif
+
     // return child pointer
     *child_thread = child_ptr;
@@ -502,5 +517,11 @@
     }
 
-    // create and initialize STACK vseg 
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[DBG] %s : thread %x in process %x / created CPU & FPU contexts\n",
+__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid );
+#endif
+
+   // create and initialize STACK vseg 
     vseg = vseg_alloc();
     vseg_init( vseg,
@@ -514,5 +535,11 @@
 
     // register STACK vseg in local child VSL
-    vseg_attach( &child_process->vmm , vseg );
+    vmm_vseg_attach( &child_process->vmm , vseg );
+
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[DBG] %s : thread %x in process %x / created stack vseg\n",
+__FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid );
+#endif
 
     // copy all valid STACK GPT entries   
@@ -530,5 +557,5 @@
         if( error )
         {
-            vseg_detach( vseg );
+            vmm_vseg_detach( &child_process->vmm , vseg );
             vseg_free( vseg );
             thread_release( child_ptr );
@@ -549,8 +576,12 @@
             xptr_t lock_xp  = XPTR( page_cxy , &page_ptr->lock );
 
-            // increment the forks counter
-            remote_spinlock_lock( lock_xp );  
+            // get lock protecting page
+            remote_busylock_acquire( lock_xp );  
+
+            // increment the forks counter in page descriptor
             hal_remote_atomic_add( forks_xp , 1 );
-            remote_spinlock_unlock( lock_xp );  
+
+            // release lock protecting page
+            remote_busylock_release( lock_xp );  
 
 #if (DEBUG_THREAD_USER_FORK & 1)
@@ -559,5 +590,5 @@
 printk("\n[DBG] %s : thread %x in process %x copied one PTE to child GPT : vpn %x / forks %d\n",
 __FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid, vpn,
-hal_remote_lw( XPTR( page_cxy , &page_ptr->forks) ) );
+hal_remote_l32( XPTR( page_cxy , &page_ptr->forks) ) );
 #endif
 
@@ -596,8 +627,8 @@
 #endif
 
-	assert( (thread->type == THREAD_USER )          , "bad type" );
-	assert( (thread->signature == THREAD_SIGNATURE) , "bad signature" );
-	assert( (thread->local_locks == 0)              , "bad local locks" );
-	assert( (thread->remote_locks == 0)             , "bad remote locks" );
+// check parent thread attributes
+assert( (thread->type == THREAD_USER )          , "bad type" );
+assert( (thread->signature == THREAD_SIGNATURE) , "bad signature" );
+assert( (thread->busylocks == 0)                , "bad busylocks" );
 
 	// re-initialize various thread descriptor fields
@@ -605,9 +636,4 @@
     thread->ticks_nr        = 0;            // TODO
     thread->time_last_check = 0;            // TODO
-
-#if CONFIG_LOCKS_DEBUG 
-    list_root_init( &thread->locks_root );  
-    xlist_root_init( XPTR( local_cxy , &thread->xlocks_root ) );
-#endif
 
     thread->entry_func      = entry_func;
@@ -622,9 +648,12 @@
     thread->fork_cxy        = 0;    // not inherited
 
+    // re-initialize busylocks counters
+    thread->busylocks       = 0;
+
     // reset thread info
     memset( &thread->info , 0 , sizeof(thread_info_t) );
 
-    // initialize join_lock
-    remote_spinlock_init( XPTR( local_cxy , &thread->join_lock ) );
+    // re-initialize join_lock
+    remote_busylock_init( XPTR( local_cxy , &thread->join_lock ), LOCK_THREAD_JOIN );
 
     // allocate an user stack vseg for main thread
@@ -664,5 +693,5 @@
 	hal_cpu_context_exec( thread );
 
-    assert( false, "we should execute this code");
+    assert( false, "we should not execute this code");
  
     return 0;
@@ -742,6 +771,8 @@
 	                   lid_t           core_lid )
 {
-    assert( (type == THREAD_IDLE) , "illegal thread type" );
-    assert( (core_lid < LOCAL_CLUSTER->cores_nr) , "illegal core index" );
+
+// check arguments
+assert( (type == THREAD_IDLE) , "illegal thread type" );
+assert( (core_lid < LOCAL_CLUSTER->cores_nr) , "illegal core index" );
 
     // initialize thread descriptor
@@ -784,9 +815,7 @@
 #endif
 
-    assert( (thread->local_locks == 0) ,
-    "local lock not released for thread %x in process %x", thread->trdid, process->pid );
-
-    assert( (thread->remote_locks == 0) ,
-    "remote lock not released for thread %x in process %x", thread->trdid, process->pid );
+// check busylocks counter
+assert( (thread->busylocks == 0) ,
+"busylock not released for thread %x in process %x", thread->trdid, process->pid );
 
     // update intrumentation values
@@ -890,26 +919,4 @@
 }  // thread_reset_req_ack()
 
-////////////////////////////////
-inline bool_t thread_can_yield( void )
-{
-    thread_t * this = CURRENT_THREAD;
-    return (this->local_locks == 0) && (this->remote_locks == 0);
-}
-
-/////////////////////////
-void thread_check_sched( void )
-{
-    thread_t * this = CURRENT_THREAD;
-
-	if( (this->local_locks == 0) && 
-        (this->remote_locks == 0) &&
-        (this->flags & THREAD_FLAG_SCHED) ) 
-    {
-        this->flags &= ~THREAD_FLAG_SCHED;
-        sched_yield( "delayed scheduling" );
-    }
-
-}  // end thread_check_sched()
-
 //////////////////////////////////////
 void thread_block( xptr_t   thread_xp,
@@ -930,5 +937,5 @@
 printk("\n[DBG] %s : thread %x in process %x blocked thread %x in process %x / cause %x\n",
 __FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid,
-ptr->trdid, hal_remote_lw(XPTR( cxy , &process->pid )), cause );
+ptr->trdid, hal_remote_l32(XPTR( cxy , &process->pid )), cause );
 #endif
 
@@ -953,5 +960,5 @@
 printk("\n[DBG] %s : thread %x in process %x unblocked thread %x in process %x / cause %x\n",
 __FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid,
-ptr->trdid, hal_remote_lw(XPTR( cxy , &process->pid )), cause );
+ptr->trdid, hal_remote_l32(XPTR( cxy , &process->pid )), cause );
 #endif
 
@@ -974,5 +981,4 @@
     thread_t  * target_ptr;             // pointer on target thread
     xptr_t      target_flags_xp;        // extended pointer on target thread <flags>
-    uint32_t    target_flags;           // target thread <flags> value
     xptr_t      target_join_lock_xp;    // extended pointer on target thread <join_lock>
     xptr_t      target_join_xp_xp;      // extended pointer on target thread <join_xp>
@@ -982,14 +988,14 @@
     thread_t  * joining_ptr;            // pointer on joining thread
     cxy_t       joining_cxy;            // joining thread cluster
-    cxy_t       owner_cxy;              // process owner cluster
-
-
-    // get target thread pointers, identifiers, and flags
+
+    // get target thread cluster and local pointer
     target_cxy      = GET_CXY( target_xp );
     target_ptr      = GET_PTR( target_xp );
-    target_trdid    = hal_remote_lw( XPTR( target_cxy , &target_ptr->trdid ) );
+
+    // get target thread identifiers, and attached flag
+    target_trdid    = hal_remote_l32( XPTR( target_cxy , &target_ptr->trdid ) );
     target_ltid     = LTID_FROM_TRDID( target_trdid );
     target_flags_xp = XPTR( target_cxy , &target_ptr->flags ); 
-    target_flags    = hal_remote_lw( target_flags_xp );
+    target_attached = ( (hal_remote_l32( target_flags_xp ) & THREAD_FLAG_DETACHED) == 0 );
 
     // get killer thread pointers
@@ -998,25 +1004,31 @@
 
 #if DEBUG_THREAD_DELETE
-uint32_t cycle  = (uint32_t)hal_get_cycles;
+uint32_t cycle  = (uint32_t)hal_get_cycles();
 if( DEBUG_THREAD_DELETE < cycle )
-printk("\n[DBG] %s : killer thread %x enter for target thread %x / cycle %d\n",
-__FUNCTION__, killer_ptr, target_ptr, cycle );
-#endif
-
-    // target thread cannot be the main thread, because the main thread
-    // must be deleted by the parent process sys_wait() function
-    owner_cxy = CXY_FROM_PID( pid );
-    assert( ((owner_cxy != target_cxy) || (target_ltid != 0)),
-    "tharget thread cannot be the main thread\n" );
+printk("\n[DBG] %s : thread %x in process %x enters / target thread %x / cycle %d\n",
+__FUNCTION__, killer_ptr->trdid, killer_ptr->process->pid, target_ptr->trdid, cycle );
+#endif
+
+// check killer thread can yield 
+assert( (killer_ptr->busylocks == 0), 
+"cannot yield : busylocks = %d\n", killer_ptr->busylocks );
+
+// check target thread is not the main thread, because the main thread
+// must be deleted by the parent process sys_wait() function
+assert( ((CXY_FROM_PID( pid ) != target_cxy) || (target_ltid != 0)),
+"tharget thread cannot be the main thread\n" );
 
     // block the target thread 
     thread_block( target_xp , THREAD_BLOCKED_GLOBAL );
 
-    // get attached from target flag descriptor
-    target_attached = ((hal_remote_lw( target_flags_xp ) & THREAD_FLAG_DETACHED) != 0);
-
-    // synchronize with the joining thread if the target thread is attached 
-    if( target_attached && (is_forced == false) )
-    {
+    // synchronize with the joining thread if attached
+    if( target_attached && (is_forced == false) ) 
+    {
+
+#if (DEBUG_THREAD_DELETE & 1)
+if( DEBUG_THREAD_DELETE < cycle )
+printk("\n[DBG] %s : thread %x in process %x / target thread is attached\n",
+__FUNCTION__, killer_ptr->trdid, killer_ptr->process->pid );
+#endif
         // build extended pointers on target thread join fields
         target_join_lock_xp  = XPTR( target_cxy , &target_ptr->join_lock );
@@ -1027,13 +1039,19 @@
 
         // take the join_lock in target thread descriptor
-        remote_spinlock_lock( target_join_lock_xp );
+        remote_busylock_acquire( target_join_lock_xp );
 
         // get join_done from target thread descriptor
-        target_join_done = ((hal_remote_lw( target_flags_xp ) & THREAD_FLAG_JOIN_DONE) != 0);
+        target_join_done = ((hal_remote_l32( target_flags_xp ) & THREAD_FLAG_JOIN_DONE) != 0);
     
         if( target_join_done )  // joining thread arrived first => unblock the joining thread
         {
+
+#if (DEBUG_THREAD_DELETE & 1)
+if( DEBUG_THREAD_DELETE < cycle )
+printk("\n[DBG] %s : thread %x in process %x / joining thread arrived first\n",
+__FUNCTION__, killer_ptr->trdid, killer_ptr->process->pid );
+#endif
             // get extended pointer on joining thread
-            joining_xp  = (xptr_t)hal_remote_lwd( target_join_xp_xp );
+            joining_xp  = (xptr_t)hal_remote_l64( target_join_xp_xp );
             joining_ptr = GET_PTR( joining_xp );
             joining_cxy = GET_CXY( joining_xp );
@@ -1046,11 +1064,20 @@
 
             // release the join_lock in target thread descriptor
-            remote_spinlock_unlock( target_join_lock_xp );
+            remote_busylock_release( target_join_lock_xp );
+
+            // set the REQ_DELETE flag in target thread descriptor
+            hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_REQ_DELETE );
 
             // restore IRQs
             hal_restore_irq( save_sr );
         }
-        else                // this thread arrived first => register flags and deschedule
+        else                // killer thread arrived first => register flags and deschedule
         {
+
+#if (DEBUG_THREAD_DELETE & 1)
+if( DEBUG_THREAD_DELETE < cycle )
+printk("\n[DBG] %s : thread %x in process %x / killer thread arrived first\n",
+__FUNCTION__, killer_ptr->trdid, killer_ptr->process->pid );
+#endif
             // set the kill_done flag in target thread
             hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_KILL_DONE );
@@ -1060,25 +1087,40 @@
 
             // set extended pointer on killer thread in target thread
-            hal_remote_swd( target_join_xp_xp , killer_xp );
+            hal_remote_s64( target_join_xp_xp , killer_xp );
 
             // release the join_lock in target thread descriptor
-            remote_spinlock_unlock( target_join_lock_xp );
-
+            remote_busylock_release( target_join_lock_xp );
+
+#if (DEBUG_THREAD_DELETE & 1)
+if( DEBUG_THREAD_DELETE < cycle )
+printk("\n[DBG] %s : thread %x in process %x / killer thread deschedule\n",
+__FUNCTION__, killer_ptr->trdid, killer_ptr->process->pid );
+#endif
             // deschedule
             sched_yield( "killer thread wait joining thread" );
+
+#if (DEBUG_THREAD_DELETE & 1)
+if( DEBUG_THREAD_DELETE < cycle )
+printk("\n[DBG] %s : thread %x in process %x / killer thread resume\n",
+__FUNCTION__, killer_ptr->trdid, killer_ptr->process->pid );
+#endif
+            // set the REQ_DELETE flag in target thread descriptor
+            hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_REQ_DELETE );
 
             // restore IRQs
             hal_restore_irq( save_sr );
         }
-    }  // end if attached
-
-    // set the REQ_DELETE flag in target thread descriptor
-    hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_REQ_DELETE );
+    }
+    else                                                   // target thread not attached
+    {
+        // set the REQ_DELETE flag in target thread descriptor
+        hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_REQ_DELETE );
+    }
 
 #if DEBUG_THREAD_DELETE
 cycle  = (uint32_t)hal_get_cycles;
 if( DEBUG_THREAD_DELETE < cycle )
-printk("\n[DBG] %s : killer thread %x exit for target thread %x / cycle %d\n",
-__FUNCTION__, killer_ptr, target_ptr, cycle );
+printk("\n[DBG] %s : thread %x in process %x exit / target thread %x / cycle %d\n",
+__FUNCTION__, killer_ptr->trdid, killer_ptr->process->pid, target_ptr->trdid, cycle );
 #endif
 
@@ -1087,12 +1129,7 @@
 
 
-///////////////////////
+/////////////////////////////
 void thread_idle_func( void )
 {
-
-#if DEBUG_THREAD_IDLE
-uint32_t cycle;
-#endif
-
     while( 1 )
     {
@@ -1104,18 +1141,22 @@
         {
 
-#if (DEBUG_THREAD_IDLE & 1)
-cycle  = (uint32_t)hal_get_cycles;
+#if DEBUG_THREAD_IDLE
+{ 
+uint32_t cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_THREAD_IDLE < cycle )
 printk("\n[DBG] %s : idle thread on core[%x,%d] goes to sleep / cycle %d\n",
 __FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, cycle );
+}
 #endif
 
             hal_core_sleep();
 
-#if (DEBUG_THREAD_IDLE & 1)
-cycle  = (uint32_t)hal_get_cycles;
+#if DEBUG_THREAD_IDLE
+{
+uint32_t cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_THREAD_IDLE < cycle )
 printk("\n[DBG] %s : idle thread on core[%x,%d] wake up / cycle %d\n",
 __FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, cycle );
+}
 #endif
 
@@ -1123,10 +1164,15 @@
 
 #if DEBUG_THREAD_IDLE
+{
+uint32_t cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_THREAD_IDLE < cycle )
 sched_display( CURRENT_THREAD->core->lid );
+}
 #endif     
-
         // search a runable thread
-        sched_yield( "IDLE" );
-    }
+        sched_yield( "running idle thread" );
+
+    } // end while
+
 }  // end thread_idle()
 
@@ -1134,5 +1180,5 @@
 ///////////////////////////////////////////
 void thread_time_update( thread_t * thread,
-                         uint32_t   is_user )
+                         bool_t     is_user )
 {
     cycle_t current_cycle;   // current cycle counter value
@@ -1154,5 +1200,6 @@
     if( is_user ) info->usr_cycles += (current_cycle - last_cycle);
     else          info->sys_cycles += (current_cycle - last_cycle);
-}
+
+}  // end thread_time_update()
 
 /////////////////////////////////////
@@ -1174,5 +1221,5 @@
 
     // check trdid argument
-	if( (target_thread_ltid >= CONFIG_THREAD_MAX_PER_CLUSTER) || 
+	if( (target_thread_ltid >= CONFIG_THREADS_MAX_PER_CLUSTER) || 
         cluster_is_undefined( target_cxy ) )         return XPTR_NULL;
 
@@ -1182,11 +1229,11 @@
                        sizeof(xlist_entry_t) );
 
-    // get extended pointer on lock protecting the list of processes
+    // get extended pointer on lock protecting the list of local processes
     lock_xp = XPTR( target_cxy , &LOCAL_CLUSTER->pmgr.local_lock );
 
     // take the lock protecting the list of processes in target cluster
-    remote_spinlock_lock( lock_xp );
-
-    // loop on list of process in target cluster to find the PID process
+    remote_queuelock_acquire( lock_xp );
+
+    // scan the list of local processes in target cluster
     xptr_t  iter;
     bool_t  found = false;
@@ -1195,5 +1242,5 @@
         target_process_xp  = XLIST_ELEMENT( iter , process_t , local_list );
         target_process_ptr = GET_PTR( target_process_xp );
-        target_process_pid = hal_remote_lw( XPTR( target_cxy , &target_process_ptr->pid ) );
+        target_process_pid = hal_remote_l32( XPTR( target_cxy , &target_process_ptr->pid ) );
         if( target_process_pid == pid )
         {
@@ -1204,5 +1251,5 @@
 
     // release the lock protecting the list of processes in target cluster
-    remote_spinlock_unlock( lock_xp );
+    remote_queuelock_release( lock_xp );
 
     // check PID found
@@ -1216,4 +1263,109 @@
 
     return XPTR( target_cxy , target_thread_ptr );
+
+}  // end thread_get_xptr()
+
+///////////////////////////////////////////////////
+void thread_assert_can_yield( thread_t    * thread,
+                              const char  * func_str )
+{
+    // does nothing if thread does not hold any busylock
+
+    if( thread->busylocks )
+    {
+        // get pointers on TXT0 chdev
+        xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
+        cxy_t     txt0_cxy = GET_CXY( txt0_xp );
+        chdev_t * txt0_ptr = GET_PTR( txt0_xp );
+
+        // get extended pointer on TXT0 lock
+        xptr_t  txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
+
+        // get TXT0 lock 
+        remote_busylock_acquire( txt0_lock_xp );
+
+        // display error message on TXT0
+        nolock_printk("\n[PANIC] in %s / thread %x in process %x [%x] cannot yield : "
+        "%d busylock(s) / cycle %d\n",
+        func_str, thread->trdid, thread->process->pid, thread,
+        thread->busylocks, (uint32_t)hal_get_cycles() );
+
+#if DEBUG_BUSYLOCK
+if( XPTR( local_cxy , thread ) == DEBUG_BUSYLOCK_THREAD_XP )
+{
+    // get root of list of taken busylocks
+    xptr_t    root_xp  = XPTR( local_cxy , &thread->busylocks_root );
+    xptr_t    iter_xp;
+
+    // scan list of busylocks
+    XLIST_FOREACH( root_xp , iter_xp )
+    {
+        xptr_t       lock_xp   = XLIST_ELEMENT( iter_xp , busylock_t , xlist );
+        cxy_t        lock_cxy  = GET_CXY( lock_xp );
+        busylock_t * lock_ptr  = GET_PTR( lock_xp );
+        uint32_t     lock_type = hal_remote_l32( XPTR( lock_cxy , &lock_ptr->type ) );
+        nolock_printk(" - %s in cluster %x\n", lock_type_str[lock_type] , lock_cxy );
+    }
 }
-
+#endif
+
+        // release TXT0 lock 
+        remote_busylock_release( txt0_lock_xp );
+
+        // suicide
+        hal_core_sleep();
+    }
+}  // end thread_assert_can yield()
+
+#if DEBUG_BUSYLOCK
+
+////////////////////////////////////////////////////
+void thread_display_busylocks( uint32_t   lock_type,
+                               bool_t     is_acquire )
+{
+    xptr_t    iter_xp;
+
+    // get cluster and local pointer of target thread
+    cxy_t      thread_cxy = GET_CXY( DEBUG_BUSYLOCK_THREAD_XP );
+    thread_t * thread_ptr = GET_PTR( DEBUG_BUSYLOCK_THREAD_XP );
+
+    // get extended pointer on root of busylocks
+    xptr_t    root_xp = XPTR( thread_cxy , &thread_ptr->busylocks_root );
+
+   // get pointers on TXT0 chdev
+    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
+    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
+    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
+
+    // get extended pointer on remote TXT0 lock
+    xptr_t  txt0_lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
+
+    // get TXT0 lock 
+    remote_busylock_acquire( txt0_lock_xp );
+
+    if( is_acquire )
+    {
+        nolock_printk("\n### thread [%x,%x] ACQUIRE lock %s / root %x / locks :\n",
+        thread_cxy, thread_ptr, lock_type_str[lock_type], GET_PTR(root_xp) );
+    }
+    else
+    {
+        nolock_printk("\n### thread [%x,%x] RELEASE lock %s / root %x / locks :\n",
+        thread_cxy, thread_ptr, lock_type_str[lock_type], GET_PTR(root_xp) );
+    }
+
+    int i;
+
+    XLIST_FOREACH( root_xp , iter_xp )
+    {
+        xptr_t       ilock_xp   = XLIST_ELEMENT( iter_xp , busylock_t , xlist );
+        cxy_t        ilock_cxy  = GET_CXY( ilock_xp );
+        busylock_t * ilock_ptr  = GET_PTR( ilock_xp );
+        uint32_t     ilock_type = hal_remote_l32( XPTR( ilock_cxy , &ilock_ptr->type ) );
+        nolock_printk(" - %s in cluster %x\n", lock_type_str[ilock_type] , ilock_cxy );
+    }
+
+    // release TXT0 lock
+    remote_busylock_release( txt0_lock_xp );
+}
+#endif
