Index: trunk/kernel/libk/remote_mutex.c
===================================================================
--- trunk/kernel/libk/remote_mutex.c	(revision 457)
+++ trunk/kernel/libk/remote_mutex.c	(revision 563)
@@ -1,6 +1,6 @@
 /*
- * remote_mutex.c - Access a POSIX mutex.
+ * remote_mutex.c - POSIX mutex implementation.
  * 
- * Authors   Alain   Greiner (2016)
+ * Authors   Alain   Greiner (2016,2017,2018)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -22,12 +22,13 @@
  */
 
+#include <kernel_config.h>
 #include <hal_kernel_types.h>
 #include <hal_remote.h>
-#include <hal_special.h>
-#include <hal_irqmask.h>
 #include <thread.h>
-#include <cluster.h>
+#include <xlist.h>
 #include <scheduler.h>
+#include <remote_busylock.h>
 #include <remote_mutex.h>
+
 
 /////////////////////////////////////////////////
@@ -44,7 +45,11 @@
     process_t    * ref_ptr = (process_t *)GET_PTR( ref_xp );
 
-    // get extended pointer on root of mutex list 
+    // get extended pointers on mutexes list  
     xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->mutex_root );
-   
+    xptr_t lock_xp = XPTR( ref_cxy , &ref_ptr->sync_lock );
+
+    // get lock protecting synchro lists
+    remote_queuelock_acquire( lock_xp );
+ 
     // scan reference process mutex list
     xptr_t           iter_xp;
@@ -68,4 +73,7 @@
     }
 
+    // relese lock protecting synchros lists
+    remote_queuelock_release( lock_xp );
+ 
     if( found == false )  return XPTR_NULL;
     else                  return mutex_xp;
@@ -89,5 +97,5 @@
     process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
 
-    // allocate memory for barrier descriptor
+    // allocate memory for mutex descriptor
     if( ref_cxy == local_cxy )                  // local cluster is the reference 
     {
@@ -101,25 +109,37 @@
     {
         rpc_kcm_alloc_client( ref_cxy , KMEM_MUTEX , &mutex_xp );
-        mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
-    }
-
-    if( mutex_ptr == NULL ) return ENOMEM;
+        mutex_ptr = GET_PTR( mutex_xp );
+    }
+
+    if( mutex_ptr == NULL ) return 0xFFFFFFFF;
 
     // initialise mutex
-    hal_remote_sw ( XPTR( ref_cxy , &mutex_ptr->value )   , 0 );
+    hal_remote_s32 ( XPTR( ref_cxy , &mutex_ptr->taken )   , 0 );
     hal_remote_spt( XPTR( ref_cxy , &mutex_ptr->ident )   , (void *)ident );
-    hal_remote_swd( XPTR( ref_cxy , &mutex_ptr->owner )   , XPTR_NULL );
-
     xlist_entry_init( XPTR( ref_cxy , &mutex_ptr->list ) );
     xlist_root_init( XPTR( ref_cxy , &mutex_ptr->root ) );
-    remote_spinlock_init( XPTR( ref_cxy , &mutex_ptr->lock ) );
-
-    // register mutex in reference process xlist
+    hal_remote_s64( XPTR( ref_cxy , &mutex_ptr->owner ) , XPTR_NULL );
+    remote_busylock_init( XPTR( ref_cxy , &mutex_ptr->lock ), LOCK_MUTEX_STATE );
+
+    // get root of mutexes list in process, and list_entry in mutex
     xptr_t root_xp = XPTR( ref_cxy , &ref_ptr->mutex_root );
     xptr_t xp_list = XPTR( ref_cxy , &mutex_ptr->list );
 
-    remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
+    // get lock protecting user synchros lists
+    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
+
+    // register mutex in process descriptor 
     xlist_add_first( root_xp , xp_list );
-    remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
+
+    // release lock protecting user synchros lists
+    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
+
+#if DEBUG_MUTEX
+thread_t * this = CURRENT_THREAD;
+if( (uint32_t)hal_get_cycles() > DEBUG_QUEUELOCK )
+printk("\n[DBG] %s : thread %x in %x process / mutex(%x,%x)\n",
+__FUNCTION__, this->trdid, this->process->pid, local_cxy, mutex_ptr );
+#endif
+
 
     return 0;
@@ -144,8 +164,12 @@
     remote_mutex_t * mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
 
+    // get lock protecting user synchros lists
+    remote_queuelock_acquire( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
+
     // remove mutex from reference process xlist
-    remote_spinlock_lock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
     xlist_unlink( XPTR( mutex_cxy , &mutex_ptr->list ) );
-    remote_spinlock_unlock( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
+
+    // release lock protecting user synchros lists
+    remote_queuelock_release( XPTR( ref_cxy , &ref_ptr->sync_lock ) );
 
     // release memory allocated for mutexaphore descriptor
@@ -167,105 +191,206 @@
 void remote_mutex_lock( xptr_t mutex_xp )
 { 
-    bool_t    success;
-    reg_t     irq_state;
-
-    // get cluster and local pointer on remote mutex
-    remote_mutex_t * mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
+    // get cluster and local pointer on mutex
+    remote_mutex_t * mutex_ptr = GET_PTR( mutex_xp );
     cxy_t            mutex_cxy = GET_CXY( mutex_xp );
 
-    // get cluster and local pointer on calling thread
-    cxy_t            thread_cxy = local_cxy;
-    thread_t       * thread_ptr = CURRENT_THREAD;
-
-    // get extended pointers on mutex value
-    xptr_t           value_xp = XPTR( mutex_cxy , &mutex_ptr->value );
-
-    // Try to take the mutex
-    success = hal_remote_atomic_cas( value_xp , 0 , 1 );
-
-    if( success )  // take the lock
-    {
-        // register calling thread as mutex owner
-        xptr_t owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
-        hal_remote_swd( owner_xp , XPTR( thread_cxy , thread_ptr ) );
-
-        // increment calling thread remote_locks
-        hal_remote_atomic_add( XPTR( thread_cxy , &thread_ptr->remote_locks ) , 1 );
-    }
-    else           // deschedule and register calling thread in queue
-    {
-        // disable interrupts
-	    hal_disable_irq( &irq_state );
-  
-        // register calling thread in mutex waiting queue
-        xptr_t root_xp  = XPTR( mutex_cxy  , &mutex_ptr->root );
-        xptr_t entry_xp = XPTR( thread_cxy , &thread_ptr->wait_list );
-
-        remote_spinlock_lock( XPTR( mutex_cxy , &mutex_ptr->lock ) ); 
-        xlist_add_last( root_xp , entry_xp );
-        remote_spinlock_unlock( XPTR( mutex_cxy , &mutex_ptr->lock ) ); 
-
-        // block & deschedule the calling thread   
-        thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_USERSYNC );
-        sched_yield("blocked on mutex");
-
-        // restore interrupts
-        hal_restore_irq( irq_state );
-    }  
-
-    hal_fence();
-
-}  // end remote_mutex_lock()
-
-///////////////////////////////////////////
-void remote_mutex_unlock( xptr_t mutex_xp )
-{
-	reg_t               irq_state;
-
-    // get cluster and local pointer on remote mutex
-    remote_mutex_t * mutex_ptr = (remote_mutex_t *)GET_PTR( mutex_xp );
-    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
-
-    // get cluster and local pointer on calling thread
-    cxy_t            thread_cxy = local_cxy;
-    thread_t       * thread_ptr = CURRENT_THREAD;
-
-    // get extended pointers on mutex value, root, lock & owner fields 
-    xptr_t           value_xp = XPTR( mutex_cxy , &mutex_ptr->value );
+    // get extended pointers on mutex fields 
+    xptr_t           taken_xp = XPTR( mutex_cxy , &mutex_ptr->taken );
     xptr_t           owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
     xptr_t           root_xp  = XPTR( mutex_cxy , &mutex_ptr->root );
+    xptr_t           lock_xp  = XPTR( mutex_cxy , &mutex_ptr->lock );
+
+    // get cluster and pointers on calling thread
+    cxy_t            caller_cxy = local_cxy;
+    thread_t       * caller_ptr = CURRENT_THREAD;
+    xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
+
+// check calling thread can yield
+assert( (caller_ptr->busylocks == 0),
+"cannot yield : busylocks = %d\n", caller_ptr->busylocks );
+
+    while( 1 )
+    {
+        // get busylock protecting mutex state
+        remote_busylock_acquire( lock_xp );
+
+        // test mutex state
+        if( hal_remote_l32( taken_xp ) == 0 )                 // success
+        {
+            // register calling thread as mutex owner
+            hal_remote_s64( owner_xp , caller_xp );
+
+            // update mutex state
+            hal_remote_s32( taken_xp , 1 );
+
+#if DEBUG_MUTEX
+thread_t * this = CURRENT_THREAD;
+if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
+printk("\n[DBG] %s : thread %x in process %x SUCCESS on mutex(%x,%x)\n",
+__FUNCTION__, this->trdid, this->process->pid, mutex_cxy, mutex_ptr );
+#endif
+
+            // release busylock protecting mutex state
+            remote_busylock_release( lock_xp ); 
+
+             return;
+        }
+        else                                                 //  already taken
+        {
+            // block the calling thread   
+            thread_block( caller_xp , THREAD_BLOCKED_USERSYNC );
+
+            // register calling thread in mutex waiting queue
+            xptr_t entry_xp = XPTR( caller_cxy , &caller_ptr->wait_xlist );
+            xlist_add_last( root_xp , entry_xp );
+
+#if DEBUG_MUTEX
+thread_t * this = CURRENT_THREAD;
+if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
+printk("\n[DBG] %s : thread %x in process %x BLOCKED on mutex(%x,%x)\n",
+__FUNCTION__, this->trdid, this->process->pid, mutex_cxy, mutex_ptr );
+#endif
+
+            // release busylock protecting mutex state
+            remote_busylock_release( lock_xp ); 
+
+            // deschedule calling thread
+            sched_yield("blocked on mutex");
+        }
+    }  
+}  // end remote_mutex_lock()
+
+//////////////////////////////////////////////
+error_t remote_mutex_unlock( xptr_t mutex_xp )
+{
+    // memory barrier before mutex release
+    hal_fence();
+
+    // get cluster and local pointer on mutex
+    remote_mutex_t * mutex_ptr = GET_PTR( mutex_xp );
+    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
+
+    // get cluster and pointers on calling thread
+    cxy_t            caller_cxy = local_cxy;
+    thread_t       * caller_ptr = CURRENT_THREAD;
+    xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
+
+    // get extended pointers on mutex fields 
+    xptr_t           taken_xp = XPTR( mutex_cxy , &mutex_ptr->taken );
+    xptr_t           owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
+    xptr_t           root_xp  = XPTR( mutex_cxy , &mutex_ptr->root );
+    xptr_t           lock_xp  = XPTR( mutex_cxy , &mutex_ptr->lock );
+
+    // get busylock protecting mutex state
+    remote_busylock_acquire( lock_xp );
     
-    // disable interrupts
-	hal_disable_irq( &irq_state );
-  
-    // unregister owner thread, 
-    hal_remote_swd( owner_xp , XPTR_NULL );
-
-    // decrement calling thread remote_locks
-	hal_remote_atomic_add( XPTR( thread_cxy , &thread_ptr->remote_locks ) , -1 );
-
-    // activate first waiting thread if required
-    if( xlist_is_empty( root_xp ) == false )        // one waiiting thread
+    // check calling thread is mutex owner
+    if( hal_remote_l64( owner_xp ) != caller_xp )
+    {
+        // release busylock protecting mutex state
+        remote_busylock_release( lock_xp );
+
+        return 0xFFFFFFFF;
+    }
+
+#if DEBUG_MUTEX
+thread_t * this = CURRENT_THREAD;
+if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
+printk("\n[DBG] %s : thread %x in %x process EXIT / mutex(%x,%x)\n",
+__FUNCTION__, this->trdid, this->process->pid, mutex_cxy, mutex_ptr );
+#endif
+
+    // update owner field, 
+    hal_remote_s64( owner_xp , XPTR_NULL );
+
+    // update taken field
+    hal_remote_s32( taken_xp , 0 );
+
+    // unblock first waiting thread if waiting list non empty
+    if( xlist_is_empty( root_xp ) == false )
     {
         // get extended pointer on first waiting thread
-        xptr_t thread_xp = XLIST_FIRST_ELEMENT( root_xp , thread_t , wait_list );
-
-        // remove first waiting thread from queue
-        remote_spinlock_lock( XPTR( mutex_cxy , &mutex_ptr->lock ) );
-        xlist_unlink( XPTR( mutex_cxy , &mutex_ptr->list ) );
-        remote_spinlock_unlock( XPTR( mutex_cxy , &mutex_ptr->lock ) );
+        xptr_t     thread_xp  = XLIST_FIRST( root_xp , thread_t , wait_xlist );
+        thread_t * thread_ptr = GET_PTR( thread_xp );
+        cxy_t      thread_cxy = GET_CXY( thread_xp );
+
+#if DEBUG_MUTEX
+if( (uint32_t)hal_get_cycles() > DEBUG_MUTEX )
+{
+trdid_t     trdid   = hal_remote_l32( XPTR( thread_cxy , &thread_ptr->trdid ) );
+process_t * process = hal_remote_lpt( XPTR( thread_cxy , &thread_ptr->process ) );
+pid_t       pid     = hal_remote_l32( XPTR( thread_cxy , &process->pid ) );
+printk("\n[DBG] %s : thread %x in process %x UNBLOCK thread %x in process %d / mutex(%x,%x)\n",
+__FUNCTION__, this->trdid, this->process->pid, trdid, pid, mutex_cxy, mutex_ptr );
+}
+#endif
+
+        // remove this thread from waiting queue
+        xlist_unlink( XPTR( thread_cxy , &thread_ptr->wait_xlist ) );
 
         // unblock first waiting thread
         thread_unblock( thread_xp , THREAD_BLOCKED_USERSYNC ); 
     }
-    else                                            // no waiting thread 
-    {
-        // release mutex
-        hal_remote_sw( value_xp , 0 );
-    }
-
-    // restore interrupts
-	hal_restore_irq( irq_state );
+    
+    // release busylock protecting mutex state
+    remote_busylock_release( lock_xp );
+
+    return 0;
 
 }  // end remote_mutex_unlock()
 
+///////////////////////////////////////////////
+error_t remote_mutex_trylock( xptr_t mutex_xp )
+{
+    // get cluster and local pointer on mutex
+    remote_mutex_t * mutex_ptr = GET_PTR( mutex_xp );
+    cxy_t            mutex_cxy = GET_CXY( mutex_xp );
+
+    // get cluster and pointers on calling thread
+    cxy_t            caller_cxy = local_cxy;
+    thread_t       * caller_ptr = CURRENT_THREAD;
+    xptr_t           caller_xp  = XPTR( caller_cxy , caller_ptr );
+
+    // get extended pointers on mutex fields 
+    xptr_t           taken_xp = XPTR( mutex_cxy , &mutex_ptr->taken );
+    xptr_t           owner_xp = XPTR( mutex_cxy , &mutex_ptr->owner );
+    xptr_t           lock_xp  = XPTR( mutex_cxy , &mutex_ptr->lock );
+
+    // get busylock protecting mutex state
+    remote_busylock_acquire( lock_xp );
+
+    // test mutex state
+    if( hal_remote_l32( taken_xp ) == 0 )                 // success
+    {
+        // register calling thread as mutex owner
+        hal_remote_s64( owner_xp , caller_xp );
+
+        // update mutex state
+        hal_remote_s32( taken_xp , 1 );
+
+#if DEBUG_MUTEX
+thread_t * this = CURRENT_THREAD;
+if( (uint32_t)hal_get_cycles() > DEBUG_QUEUELOCK )
+printk("\n[DBG] %s : SUCCESS for thread %x in process %x / mutex(%x,%x)\n",
+__FUNCTION__, this->trdid, this->process->pid, mutex_cxy, mutex_ptr );
+#endif
+        // release busylock protecting mutex state
+        remote_busylock_release( lock_xp ); 
+
+        return 0;
+    }
+    else                                                 //  already taken
+    {
+
+#if DEBUG_MUTEX
+thread_t * this = CURRENT_THREAD;
+if( (uint32_t)hal_get_cycles() > DEBUG_QUEUELOCK )
+printk("\n[DBG] %s : FAILURE for thread %x in process %x / mutex(%x,%x)\n",
+__FUNCTION__, this->trdid, this->process->pid, mutex_cxy, mutex_ptr );
+#endif
+        // release busylock protecting mutex state
+        remote_busylock_release( lock_xp ); 
+
+        return 0xFFFFFFFF;
+    }
+}  // end remote_mutex_trylock()
