Index: trunk/kernel/syscalls/sys_thread_exit.c
===================================================================
--- trunk/kernel/syscalls/sys_thread_exit.c	(revision 408)
+++ trunk/kernel/syscalls/sys_thread_exit.c	(revision 409)
@@ -1,7 +1,6 @@
 /*
- * sys_thread_exit.c - terminates the execution of current thread
+ * sys_thread_exit.c - terminates the execution of calling thread
  * 
- * Authors       Ghassan Almaless (2008,2009,2010,2011,2012)
- *               Alain Greiner (2016,2017)
+ * Authors   Alain Greiner (2016,2017)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -24,66 +23,88 @@
 
 #include <hal_types.h>
-#include <hal_irqmask.h>
 #include <thread.h>
 #include <core.h>
+#include <vmm.h>
 #include <scheduler.h>
 #include <printk.h>
-
 
 ////////////////////////////////////////
 int sys_thread_exit( void * exit_value )
 {
-	thread_t  * this = CURRENT_THREAD;
-    core_t    * core = this->core;
-    reg_t       irq_state;
+    paddr_t      paddr;
+    error_t	     error;
 
-    // register the exit_value pointer in thread descriptor
-    this->exit_value = exit_value;
+#if CONFIG_SYSCALL_DEBUG
+uint32_t     tm_start;
+uint32_t     tm_end;
+tm_start = hal_get_cycles();
+#endif
 
-    // enter the join loop to wait the join if thread is joinable
-    if( (this->flags & THREAD_FLAG_DETACHED) == 0 )
+	thread_t  * this    = CURRENT_THREAD;
+    process_t * process = this->process;
+
+    // check all locks released
+	if( !thread_can_yield() )
+	{
+        printk("\n[ERROR] in %s : locks not released / thread %x in process %x\n",
+        __FUNCTION__, this->trdid, process->pid );
+        this->errno = EINVAL;
+        return -1;
+    }
+
+    // register the exit_value pointer in this thread descriptor
+    this->join_value = exit_value;
+
+    if( (this->flags & THREAD_FLAG_DETACHED) == 0 )    // this thread is joinable
     {
-	    while( 1 ) 
-	    {
-            // take the lock protecting the flags
-	        remote_spinlock_lock( XPTR( local_cxy, &this->flags_lock ) );
+        // check exit_value in user space
+        error = vmm_v2p_translate( false , exit_value , &paddr );
+	    if( error )
+        {
+            printk("\n[ERROR] in %s : illegal pointer = %x / thread %x in process %x\n",
+            __FUNCTION__ , (intptr_t)exit_value, this->trdid , process->pid );
+            this->errno = EINVAL;
+            return -1;
+        }
 
-            // check the JOIN flag
-            if( this->flags & THREAD_FLAG_JOIN )       // parent made a join
-            {
-                // unblock the parent thread
-                thread_unblock( this->parent , THREAD_BLOCKED_JOIN );
+        // take the lock protecting the join 
+        remote_spinlock_lock( XPTR( local_cxy, &this->join_lock ) );
 
-                // release the lock protecting the flags
-	            remote_spinlock_unlock( XPTR( local_cxy, &this->flags_lock ) );
+        if( this->flags & THREAD_FLAG_JOIN_DONE )       // parent thread arrived first
+        {
+            // unblock the parent thread
+            thread_unblock( this->join_xp , THREAD_BLOCKED_EXIT );
 
-                // exit while
-                break;
-            }
-            else                                       // no join done by parent thread
-            {
-                // set the EXIT flag
-                this->flags |= THREAD_FLAG_EXIT;
+            // reset the JOIN_DONE flag in this thread
+            this->flags &= ~THREAD_FLAG_JOIN_DONE;
 
-                // block this thread
-                thread_block( this , THREAD_BLOCKED_EXIT );
+            // release the lock protecting the flags
+	        remote_spinlock_unlock( XPTR( local_cxy, &this->join_lock ) );
+        }
+        else                                           // this thread arrived first
+        {
+            // block this thread
+            thread_block( this , THREAD_BLOCKED_JOIN );
 
-                // release the lock protecting the flags
-	            remote_spinlock_unlock( XPTR( local_cxy, &this->flags_lock ) );
+            // release the lock protecting the flags
+	        remote_spinlock_unlock( XPTR( local_cxy, &this->join_lock ) );
 
-                // deschedule
-                sched_yield("waiting parent join");
-            }     
-        }
-	}
+            // deschedule
+            sched_yield( "WAITING JOIN" );
+        }     
+    }
 
-	// Release FPU if required
-	hal_disable_irq( &irq_state );
-	if( core->fpu_owner == this )  core->fpu_owner = NULL;
-	hal_restore_irq( irq_state );
+#if CONFIG_SYSCALL_DEBUG
+tm_end = hal_get_cycles();
+syscall_dmsg("\n[DBG] %s : core[%x,%d] / thread %x in process %x / cycle %d\n"
+"thread %x killed / cost = %d\n",
+__FUNCTION__ , local_cxy , this->core->lid , this->trdid , this->process->pid , tm_start ,
+this->trdid , (uint32_t)(tm_end - tm_start) );
+#endif
 
-	// suicide
-    thread_kill( this );
-	return 0;	
+    // suicide using a rpc because  a thread cannot kill itself
+    rpc_thread_kill_client( local_cxy , this );
 
-}  // end sys_thread_exit()
+    return 0;   // never executed but required by compiler
+
+}  // end sys_thread exit
