Index: trunk/kernel/syscalls/sys_thread_join.c
===================================================================
--- trunk/kernel/syscalls/sys_thread_join.c	(revision 421)
+++ trunk/kernel/syscalls/sys_thread_join.c	(revision 436)
@@ -25,4 +25,5 @@
 #include <hal_remote.h>
 #include <hal_special.h>
+#include <hal_irqmask.h>
 #include <thread.h>
 #include <vmm.h>
@@ -36,14 +37,22 @@
                       void    ** exit_value )
 {
+    reg_t         save_sr;
     xptr_t        target_xp;
     thread_t    * target_ptr;
     cxy_t         target_cxy;
     ltid_t        target_ltid;
-	uint32_t      target_blocked;   // target thread blocked bit-vector
-    uint32_t      target_flags;     // target thread flags bit-bector
-    paddr_t       paddr;            // required for vmm_v2p_translate()
+    xptr_t        target_join_lock_xp;
+    xptr_t        target_flags_xp;
+    xptr_t        target_blocked_xp;
+    xptr_t        target_join_xp_xp;
+    xptr_t        killer_xp;
+    xptr_t        joining_xp;
+    thread_t    * joining_ptr;
+    process_t   * process;
 
-	thread_t    * this    = CURRENT_THREAD;
-    process_t   * process = this->process;
+    // get joining thread pointers
+	joining_ptr = CURRENT_THREAD;
+    joining_xp  = XPTR( local_cxy , joining_ptr );
+    process     = joining_ptr->process;
 
     // get target thread ltid and cxy
@@ -51,95 +60,128 @@
     target_cxy  = CXY_FROM_TRDID( trdid );
 
+#if CONFIG_DEBUG_SYS_THREAD_JOIN
+uint64_t     tm_start;
+uint64_t     tm_end;
+tm_start = hal_get_cycles();
+if( CONFIG_DEBUG_SYS_THREAD_JOIN < tm_start )
+printk("\n[DBG] %s : parent thread %x enter / process %x / target trdid %x / cycle %d\n",
+__FUNCTION__ , joining_ptr , process->pid , trdid , (uint32_t)tm_start );
+#endif
+
     // check trdid argument
 	if( (target_ltid >= CONFIG_THREAD_MAX_PER_CLUSTER) || cluster_is_undefined( target_cxy ) )  
 	{
-        printk("\n[ERROR] in %s : illegal trdid argument\n", __FUNCTION__ );
-		this->errno = EINVAL;
+
+#if CONFIG_DEBUG_SYSCALLS_ERROR
+printk("\n[ERROR] in %s : illegal trdid argument %x\n", __FUNCTION__, trdid );
+#endif
+		joining_ptr->errno = EINVAL;
 		return -1;
 	}
 
     // check exit_value argument
-	if( (exit_value != NULL) && (vmm_v2p_translate( false , exit_value , &paddr ) != 0 ) )
+	if( exit_value != NULL )
 	{
-        printk("\n[ERROR] in %s : illegal exit_value argument\n", __FUNCTION__ );
-		this->errno = EINVAL;
+
+#if CONFIG_DEBUG_SYSCALLS_ERROR
+printk("\n[ERROR] in %s : exit_value argument must be NULL\n", __FUNCTION__ );
+#endif
+		joining_ptr->errno = EINVAL;
 		return -1;
 	}
 
     // check target thread != this thread
-    if( this->trdid == trdid )
+    if( joining_ptr->trdid == trdid )
     {
-        printk("\n[ERROR] in %s : this thread == target thread\n", __FUNCTION__ );
-        this->errno = EDEADLK;
+
+#if CONFIG_DEBUG_SYSCALLS_ERROR
+printk("\n[ERROR] in %s : this thread == target thread\n", __FUNCTION__ );
+#endif
+        joining_ptr->errno = EDEADLK;
         return -1;
     }
 
-    // get extended pointer on target thread
+    // get pointers on target thread
 	target_xp  = thread_get_xptr( process->pid , trdid );
+    target_ptr = GET_PTR( target_xp );
 
     if( target_xp == XPTR_NULL )
     {
-        printk("\n[ERROR] in %s : target thread not found\n", __FUNCTION__ );
-        this->errno = ESRCH;
+
+#if CONFIG_DEBUG_SYSCALLS_ERROR
+printk("\n[ERROR] in %s : target thread %x not found\n", __FUNCTION__, trdid );
+#endif
+        joining_ptr->errno = ESRCH;
         return -1;
     }
 
-    // get cluster and local pointer on target thread
-    target_ptr = (thread_t *)GET_PTR( target_xp );
+    // get extended pointers on various fields in target thread
+    target_join_lock_xp = XPTR( target_cxy , &target_ptr->join_lock );
+    target_flags_xp     = XPTR( target_cxy , &target_ptr->flags );
+    target_blocked_xp   = XPTR( target_cxy , &target_ptr->blocked );
+    target_join_xp_xp   = XPTR( target_cxy , &target_ptr->join_xp );
 
     // check target thread joinable
-    target_flags = hal_remote_lw( XPTR( target_cxy , &target_ptr->flags ) );
-    if( target_flags & THREAD_FLAG_DETACHED )
+    if( (hal_remote_lw( target_flags_xp ) & THREAD_FLAG_DETACHED) == 0 )
     {
-        printk("\n[ERROR] in %s : target thread not joinable\n", __FUNCTION__ );
-        this->errno = EINVAL; 
+
+#if CONFIG_DEBUG_SYSCALLS_ERROR
+printk("\n[ERROR] in %s : target thread %x not joinable\n", __FUNCTION__, trdid );
+#endif
+        joining_ptr->errno = EINVAL; 
         return -1;
     }
 
-    // check kernel stack overflow
-    if( target_ptr->signature != THREAD_SIGNATURE )
+    // mask IRQs
+    hal_disable_irq( &save_sr );
+
+    // get the lock protecting the join in target thread
+    remote_spinlock_lock( target_join_lock_xp );
+
+    // test the kill_done flag from the target thread
+    if( hal_remote_lw( target_flags_xp ) & THREAD_FLAG_KILL_DONE )  // killer thread is first
     {
-        assert( false , __FUNCTION__ , "kernel stack overflow\n" );
+        // get pointers on killer thread
+        killer_xp  = (xptr_t)hal_remote_lwd( target_join_xp_xp );
+
+        // reset the kill_done flag in target thread
+        hal_remote_atomic_and( target_flags_xp , ~THREAD_FLAG_KILL_DONE );
+
+        // unblock the killer thread
+        thread_unblock( killer_xp , THREAD_BLOCKED_JOIN );
+
+        // release the lock protecting join      
+        remote_spinlock_unlock( target_join_lock_xp );
+
+        // restore IRQs
+        hal_restore_irq( save_sr );
+    }
+    else                                                          // joining thread is first
+    {
+        // set the join_done flag in target thread
+        hal_remote_atomic_or( target_flags_xp , THREAD_FLAG_JOIN_DONE );
+
+        // block joining thread on BLOCKED_JOIN
+        thread_block( joining_xp , THREAD_BLOCKED_JOIN );
+
+        // register the joining thread extended pointer in target thread
+        hal_remote_swd( target_join_xp_xp , joining_xp );
+
+        // release the lock protecting the join      
+        remote_spinlock_unlock( target_join_lock_xp );
+
+        // deschedule
+        sched_yield( "joining thread waiting killer thread" );
+    
+        // restore IRQs
+        hal_restore_irq( save_sr );
     }
 
-    // get the lock protecting the join in target thread
-    remote_spinlock_lock( XPTR( target_cxy , &target_ptr->join_lock ) );
-
-    // get the blocked bit_vector from the target thread
-    target_blocked = hal_remote_lw( XPTR( target_cxy , &target_ptr->blocked ) );
-
-    if( target_blocked & THREAD_BLOCKED_JOIN )    // target thread arrived first
-    {
-        // unblock the target thread
-        thread_unblock( target_xp , THREAD_BLOCKED_JOIN );
-
-        // release the lock protecting flags      
-        remote_spinlock_unlock( XPTR( target_cxy , &target_ptr->join_lock ) );
-
-        // get the exit value from target thread
-        *exit_value = hal_remote_lpt( XPTR( target_cxy , &target_ptr->join_value ) );
-    }
-    else                                          // this thread arrived first
-    {
-        // register this thread extended pointer in target thread
-        hal_remote_swd( XPTR( target_cxy , &target_ptr->join_xp ) , 
-                              XPTR( local_cxy , this ) );
-
-        // set the JOIN_DONE flag in target thread
-        hal_remote_atomic_or( XPTR( target_cxy , &target_ptr->flags ) ,
-                              THREAD_FLAG_JOIN_DONE );
-
-        // block this thread on BLOCKED_EXIT
-        thread_block( this , THREAD_BLOCKED_EXIT ); 
-
-        // release the lock protecting flags      
-        remote_spinlock_unlock( XPTR( target_cxy , &target_ptr->join_lock ) );
-
-        // deschedule
-        sched_yield( "WAITING_EXIT" );
-    
-        // get the exit value from target thread when resume
-        *exit_value = hal_remote_lpt( XPTR( target_cxy , &target_ptr->join_value ) );
-    }
+#if CONFIG_DEBUG_SYS_THREAD_JOIN
+tm_end = hal_get_cycles();
+if( CONFIG_DEBUG_SYS_THREAD_JOIN < tm_end )
+printk("\n[DBG] %s : parent thread %x exit / process %x / target trdid %x / cycle %d\n",
+__FUNCTION__, joining_ptr, process->pid, trdid, (uint32_t)tm_end );
+#endif
 
     return 0;
