Index: trunk/kernel/syscalls/sys_thread_join.c
===================================================================
--- trunk/kernel/syscalls/sys_thread_join.c	(revision 637)
+++ trunk/kernel/syscalls/sys_thread_join.c	(revision 651)
@@ -1,4 +1,4 @@
 /*
- * sys_thread_join.c - passive wait on the end of a given thread.
+ * sys_thread_join.c - wait termination of of an attached thread.
  * 
  * Authors    Alain Greiner (2016,2017,2018,2019)
@@ -26,4 +26,5 @@
 #include <hal_special.h>
 #include <hal_irqmask.h>
+#include <hal_uspace.h>
 #include <thread.h>
 #include <vmm.h>
@@ -37,6 +38,7 @@
 ///////////////////////////////////////
 int sys_thread_join ( trdid_t    trdid,
-                      void    ** exit_value )
+                      void    ** exit_status )
 {
+    error_t       error;
     reg_t         save_sr;
     xptr_t        target_xp;
@@ -47,8 +49,11 @@
     xptr_t        target_flags_xp;
     xptr_t        target_join_xp_xp;
+    xptr_t        target_exit_status_xp;
     xptr_t        killer_xp;
     xptr_t        joining_xp;
     thread_t    * joining_ptr;
     process_t   * process;
+    vseg_t      * vseg;
+    void        * status;
 
     // get joining thread pointers
@@ -62,9 +67,7 @@
 
 #if DEBUG_SYS_THREAD_JOIN
-uint64_t     tm_start;
-uint64_t     tm_end;
-tm_start = hal_get_cycles();
+uint64_t  tm_start = hal_get_cycles();
 if( DEBUG_SYS_THREAD_JOIN < tm_start )
-printk("\n[DBG] %s : joining thread[%x,%x] enter / target thread[%x,%x] / cycle %d\n",
+printk("\n[%s] joining thread[%x,%x] enter / target thread[%x,%x] / cycle %d\n",
 __FUNCTION__ , process->pid, joining_ptr->trdid,
 process->pid, trdid, (uint32_t)tm_start );
@@ -77,6 +80,6 @@
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : illegal trdid argument %x\n",
-__FUNCTION__, trdid );
+printk("\n[ERROR] in %s : illegal trdid argument %x / joining thread[%x,%x]\n",
+__FUNCTION__, trdid, joining_ptr->process->pid, joining_ptr-trdid );
 #endif
 		joining_ptr->errno = EINVAL;
@@ -84,11 +87,12 @@
 	}
 
-    // check exit_value argument
-	if( exit_value != NULL )
+    // check exit_value argument in user space
+    error = vmm_get_vseg( process , (intptr_t)exit_status  , &vseg );
+	if( error )
 	{
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : exit_value argument must be NULL\n",
-__FUNCTION__ );
+printk("\n[ERROR] in %s : exit_status argument %x not mapped / joining thread[%x,%x]\n",
+__FUNCTION__, exit_status, joining_ptr->process->pid, joining_ptr-trdid );
 #endif
 		joining_ptr->errno = EINVAL;
@@ -101,6 +105,6 @@
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : this thread (%x) == target thread(%x)\n",
-__FUNCTION__, joining_ptr->trdid, trdid );
+printk("\n[ERROR] in %s : joinig thread[%x,%x] == target thread\n",
+__FUNCTION__, joining_ptr->process->pid, joining_ptr->trdid );
 #endif
         joining_ptr->errno = EDEADLK;
@@ -116,6 +120,6 @@
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : target thread %x not found\n",
-__FUNCTION__, trdid );
+printk("\n[ERROR] in %s : target thread[%x,%x] not found / joining_thread[%x,%x]\n",
+__FUNCTION__, process->pid, trdid, joining_ptr->process->pid, joining_ptr-trdid );
 #endif
         joining_ptr->errno = ESRCH;
@@ -124,7 +128,8 @@
 
     // 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_join_xp_xp   = XPTR( target_cxy , &target_ptr->join_xp );
+    target_join_lock_xp   = XPTR( target_cxy , &target_ptr->join_lock );
+    target_flags_xp       = XPTR( target_cxy , &target_ptr->flags );
+    target_join_xp_xp     = XPTR( target_cxy , &target_ptr->join_xp );
+    target_exit_status_xp = XPTR( target_cxy , &target_ptr->exit_status );
 
     // check target thread joinable
@@ -133,5 +138,6 @@
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : target thread %x not joinable\n", __FUNCTION__, trdid );
+printk("\n[ERROR] in %s : target thread[%x,‰x] not attached / joining thread[%x,%x]\n",
+__FUNCTION__, process->pid, trdid, joining_ptr->process->pid, joining_ptr-trdid );
 #endif
         joining_ptr->errno = EINVAL; 
@@ -146,6 +152,9 @@
 
     // test the kill_done flag from the target thread
-    if( hal_remote_l32( target_flags_xp ) & THREAD_FLAG_KILL_DONE )  // killer thread is first
-    {
+    if( hal_remote_l32( target_flags_xp ) & THREAD_FLAG_KILL_DONE )  // killer is first
+    {
+        // get exit_status from target thread
+        status = (void*)hal_remote_lpt( target_exit_status_xp );
+
         // get pointers on killer thread
         killer_xp  = (xptr_t)hal_remote_l64( target_join_xp_xp );
@@ -159,14 +168,6 @@
         // release the lock protecting join      
         remote_busylock_release( target_join_lock_xp );
-
-#if DEBUG_SYS_THREAD_JOIN
-tm_end = hal_get_cycles();
-if( DEBUG_SYS_THREAD_JOIN < tm_end )
-printk("\n[DBG] %s : joining thread[%x,%x] exit / target thread[%x,%x] completed / cycle %d\n",
-__FUNCTION__, process->pid, joining_ptr->trdid, process->pid, trdid, (uint32_t)tm_end );
-#endif
-
-    }
-    else                                                          // joining thread is first
+    }
+    else                                                          // joining is first
     {
         // set the join_done flag in target thread
@@ -184,22 +185,40 @@
 #if DEBUG_SYS_THREAD_JOIN 
 if( DEBUG_SYS_THREAD_JOIN < tm_start )
-printk("\n[DBG] %s : joining thread[%x,%x] deschedules / target thread[%x,%x] not completed\n",
+printk("\n[%s] joining thread[%x,%x] deschedules / target thread[%x,%x] not completed\n",
 __FUNCTION__ , process->pid, joining_ptr->trdid, process->pid, trdid );
 #endif
         // deschedule
         sched_yield( "joining thread waiting killer thread" );
+
+        // returns exit_status from joining thread
+        status = joining_ptr->exit_status;
+    }
     
+    // returns exit_status to user space
+    hal_copy_to_uspace( exit_status,
+                        XPTR( local_cxy , &status ),
+                        sizeof( void* ) );
+
+    // restore IRQs
+    hal_restore_irq( save_sr );
+
+    hal_fence();
+
+#if (DEBUG_SYS_THREAD_JOIN || CONFIG_INSTRUMENTATION_SYSCALLS)
+uint64_t     tm_end = hal_get_cycles();
+#endif
+
+#if CONFIG_INSTRUMENTATION_SYSCALLS
+hal_atomic_add( &syscalls_cumul_cost[SYS_THREAD_JOIN] , tm_end - tm_start );
+hal_atomic_add( &syscalls_occurences[SYS_THREAD_JOIN] , 1 );
+#endif
+
 #if DEBUG_SYS_THREAD_JOIN 
 tm_end = hal_get_cycles();
 if( DEBUG_SYS_THREAD_JOIN < tm_end )
-printk("\n[DBG] %s : joining thread[%x,%x] exit / target thread[%x,%x] completed / cycle %d\n",
+printk("\n[%s] joining thread[%x,%x] exit / target thread[%x,%x] completed / cycle %d\n",
 __FUNCTION__ , process->pid, joining_ptr->trdid, process->pid, trdid, (uint32_t)tm_end );
 #endif
 
-    }
-
-    // restore IRQs
-    hal_restore_irq( save_sr );
-
     return 0;
 
