Index: trunk/kernel/kern/thread.c
===================================================================
--- trunk/kernel/kern/thread.c	(revision 624)
+++ trunk/kernel/kern/thread.c	(revision 625)
@@ -3,5 +3,5 @@
  *
  * Author  Ghassan Almaless (2008,2009,2010,2011,2012)
- *         Alain Greiner (2016,2017,2018)
+ *         Alain Greiner (2016,2017,2018,2019)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -29,4 +29,5 @@
 #include <hal_special.h>
 #include <hal_remote.h>
+#include <hal_vmm.h>
 #include <memcpy.h>
 #include <printk.h>
@@ -96,24 +97,4 @@
 
 /////////////////////////////////////////////////////////////////////////////////////
-// This static function releases the physical memory for a thread descriptor.
-// It is called by the three functions:
-// - thread_user_create()
-// - thread_user_fork()
-// - thread_kernel_create()
-/////////////////////////////////////////////////////////////////////////////////////
-// @ thread  : pointer on thread descriptor.
-/////////////////////////////////////////////////////////////////////////////////////
-static void thread_release( thread_t * thread )
-{
-    kmem_req_t   req;
-
-    xptr_t base_xp = ppm_base2page( XPTR(local_cxy , thread ) );
-
-    req.type  = KMEM_PAGE;
-    req.ptr   = GET_PTR( base_xp );
-    kmem_free( &req );
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
 // This static function initializes a thread descriptor (kernel or user).
 // It can be called by the four functions:
@@ -122,28 +103,29 @@
 // - thread_kernel_create()
 // - thread_idle_init()
+// The "type" and "trdid" fields must have been previously set.
 // It updates the local DQDT.
 /////////////////////////////////////////////////////////////////////////////////////
-// @ thread       : pointer on local thread descriptor
-// @ process      : pointer on local process descriptor.
-// @ type         : thread type.
-// @ func         : pointer on thread entry function.
-// @ args         : pointer on thread entry function arguments.
-// @ core_lid     : target core local index.
-// @ u_stack_base : stack base (user thread only)
-// @ u_stack_size : stack base (user thread only)
+// @ thread          : pointer on local thread descriptor
+// @ process         : pointer on local process descriptor.
+// @ type            : thread type.
+// @ trdid           : thread identifier
+// @ func            : pointer on thread entry function.
+// @ args            : pointer on thread entry function arguments.
+// @ core_lid        : target core local index.
+// @ user_stack_vseg : local pointer on user stack vseg (user thread only)
 /////////////////////////////////////////////////////////////////////////////////////
 static error_t thread_init( thread_t      * thread,
                             process_t     * process,
                             thread_type_t   type,
+                            trdid_t         trdid,
                             void          * func,
                             void          * args,
                             lid_t           core_lid,
-                            intptr_t        u_stack_base,
-                            uint32_t        u_stack_size )
-{
-    error_t        error;
-    trdid_t        trdid;      // allocated thread identifier
-
-	cluster_t    * local_cluster = LOCAL_CLUSTER;
+                            vseg_t        * user_stack_vseg )
+{
+
+// check type and trdid fields initialized
+assert( (thread->type == type)   , "bad type argument" );
+assert( (thread->trdid == trdid) , "bad trdid argument" );
 
 #if DEBUG_THREAD_INIT
@@ -152,5 +134,5 @@
 if( DEBUG_THREAD_INIT < cycle )
 printk("\n[%s] thread[%x,%x] enter for thread %x in process %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, thread, process->pid , cycle );
+__FUNCTION__, this->process->pid, this->trdid, thread->trdid, process->pid , cycle );
 #endif
 
@@ -159,11 +141,9 @@
 
 	// Initialize new thread descriptor
-	thread->type            = type;
     thread->quantum         = 0;            // TODO
     thread->ticks_nr        = 0;            // TODO
     thread->time_last_check = 0;            // TODO
-	thread->core            = &local_cluster->core_tbl[core_lid];
+	thread->core            = &LOCAL_CLUSTER->core_tbl[core_lid];
 	thread->process         = process;
-
     thread->busylocks       = 0;
 
@@ -172,9 +152,7 @@
 #endif
 
-    thread->u_stack_base    = u_stack_base;
-    thread->u_stack_size    = u_stack_size;
+    thread->user_stack_vseg = user_stack_vseg;
     thread->k_stack_base    = (intptr_t)thread + desc_size;
     thread->k_stack_size    = CONFIG_THREAD_DESC_SIZE - desc_size;
-
     thread->entry_func      = func;         // thread entry point
     thread->entry_args      = args;         // thread function arguments
@@ -185,19 +163,4 @@
     thread->blocked         = THREAD_BLOCKED_GLOBAL;
 
-    // register new thread in process descriptor, and get a TRDID
-    error = process_register_thread( process, thread , &trdid );
-
-    if( error )
-    {
-        printk("\n[ERROR] in %s : thread %x in process %x cannot get TRDID in cluster %x\n"
-        "    for thread %s in process %x / cycle %d\n",
-        __FUNCTION__, CURRENT_THREAD->trdid, CURRENT_THREAD->process->pid,
-        local_cxy, thread_type_str(type), process->pid, (uint32_t)hal_get_cycles() );
-        return EINVAL;
-    }
-
-    // initialize trdid 
-    thread->trdid           = trdid;
-
     // initialize sched list
     list_entry_init( &thread->sched_list );
@@ -237,5 +200,5 @@
 } // end thread_init()
 
-/////////////////////////////////////////////////////////
+//////////////////////////////////////////////////
 error_t thread_user_create( pid_t             pid,
                             void            * start_func,
@@ -246,7 +209,8 @@
     error_t        error;
 	thread_t     * thread;       // pointer on created thread descriptor
+    trdid_t        trdid;        // created thred identifier
     process_t    * process;      // pointer to local process descriptor
     lid_t          core_lid;     // selected core local index
-    vseg_t       * vseg;         // stack vseg
+    vseg_t       * us_vseg;      // user stack vseg
 
 assert( (attr != NULL) , "pthread attributes must be defined" );
@@ -266,6 +230,6 @@
     {
 		printk("\n[ERROR] in %s : cannot get process descriptor %x\n",
-               __FUNCTION__ , pid );
-        return ENOMEM;
+        __FUNCTION__ , pid );
+        return -1;
     }
 
@@ -284,5 +248,5 @@
 	        printk("\n[ERROR] in %s : illegal core index attribute = %d\n",
             __FUNCTION__ , core_lid );
-            return EINVAL;
+            return -1;
         }
     }
@@ -298,26 +262,4 @@
 #endif
 
-    // allocate a stack from local VMM
-    vseg = vmm_create_vseg( process,
-                            VSEG_TYPE_STACK,
-                            0,                 // size unused
-                            0,                 // length unused
-                            0,                 // file_offset unused
-                            0,                 // file_size unused
-                            XPTR_NULL,         // mapper_xp unused
-                            local_cxy );
-
-    if( vseg == NULL )
-    {
-	    printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ );
-		return ENOMEM;
-    }
-
-#if( DEBUG_THREAD_USER_CREATE & 1)
-if( DEBUG_THREAD_USER_CREATE < cycle )
-printk("\n[%s] stack vseg created / vpn_base %x / %d pages\n",
-__FUNCTION__, vseg->vpn_base, vseg->vpn_size );
-#endif
-
     // allocate memory for thread descriptor
     thread = thread_alloc();
@@ -325,7 +267,7 @@
     if( thread == NULL )
     {
-	    printk("\n[ERROR] in %s : cannot create new thread\n", __FUNCTION__ );
-        vmm_delete_vseg( process->pid , vseg->min );
-        return ENOMEM;
+	    printk("\n[ERROR] in %s : cannot create new thread in cluster %x\n",
+        __FUNCTION__, local_cxy );
+        return -1;
     }
 
@@ -336,25 +278,73 @@
 #endif
 
+    // set type in thread descriptor
+    thread->type = THREAD_USER;
+
+    // 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 register new thread in process %x\n",
+        __FUNCTION__, pid );
+        thread_destroy( thread );
+        return -1;
+    }
+
+    // set trdid in thread descriptor 
+    thread->trdid = trdid;
+
+#if( DEBUG_THREAD_USER_CREATE & 1)
+if( DEBUG_THREAD_USER_CREATE < cycle )
+printk("\n[%s] new thread %x registered in process %x\n",
+__FUNCTION__, trdid, pid );
+#endif
+
+    // allocate a stack from local VMM
+    us_vseg = vmm_create_vseg( process,
+                               VSEG_TYPE_STACK,
+                               LTID_FROM_TRDID( trdid ),
+                               0,                         // size unused
+                               0,                         // file_offset unused
+                               0,                         // file_size unused
+                               XPTR_NULL,                 // mapper_xp unused
+                               local_cxy );
+
+    if( us_vseg == NULL )
+    {
+	    printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ );
+        process_remove_thread( thread );
+        thread_destroy( thread );
+		return -1;
+    }
+
+#if( DEBUG_THREAD_USER_CREATE & 1)
+if( DEBUG_THREAD_USER_CREATE < cycle )
+printk("\n[%s] stack vseg created / vpn_base %x / %d pages\n",
+__FUNCTION__, us_vseg->vpn_base, us_vseg->vpn_size );
+#endif
+
     // initialize thread descriptor
     error = thread_init( thread,
                          process,
                          THREAD_USER,
+                         trdid,
                          start_func,
                          start_arg,
                          core_lid,
-                         vseg->min,
-                         vseg->max - vseg->min );
+                         us_vseg );
     if( error )
     {
 	    printk("\n[ERROR] in %s : cannot initialize new thread\n", __FUNCTION__ );
-        vmm_delete_vseg( process->pid , vseg->min );
-        thread_release( thread );
-        return EINVAL;
+        vmm_remove_vseg( process , us_vseg );
+        process_remove_thread( thread );
+        thread_destroy( thread );
+        return -1;
     }
 
 #if( DEBUG_THREAD_USER_CREATE & 1)
 if( DEBUG_THREAD_USER_CREATE < cycle )
-printk("\n[%s] new thread descriptor initialised / trdid %x\n",
-__FUNCTION__, thread->trdid );
+printk("\n[%s] new thread %x in process %x initialised\n",
+__FUNCTION__, thread->trdid, process->pid );
 #endif
 
@@ -369,7 +359,8 @@
     {
 	    printk("\n[ERROR] in %s : cannot create CPU context\n", __FUNCTION__ );
-        vmm_delete_vseg( process->pid , vseg->min );
-        thread_release( thread );
-        return ENOMEM;
+        vmm_remove_vseg( process , us_vseg );
+        process_remove_thread( thread );
+        thread_destroy( thread );
+        return -1;
     }
     hal_cpu_context_init( thread );
@@ -379,7 +370,8 @@
     {
 	    printk("\n[ERROR] in %s : cannot create FPU context\n", __FUNCTION__ );
-        vmm_delete_vseg( process->pid , vseg->min );
-        thread_release( thread );
-        return ENOMEM;
+        vmm_remove_vseg( process , us_vseg );
+        process_remove_thread( thread );
+        thread_destroy( thread );
+        return -1;
     }
     hal_fpu_context_init( thread );
@@ -410,22 +402,16 @@
 {
     error_t        error;
-	thread_t     * child_ptr;        // local pointer on local child thread
+	thread_t     * child_ptr;        // local pointer on child thread
+    trdid_t        child_trdid;      // child thread identifier
     lid_t          core_lid;         // selected core local index
-
     thread_t     * parent_ptr;       // local pointer on remote parent thread
     cxy_t          parent_cxy;       // parent thread cluster
     process_t    * parent_process;   // local pointer on parent process
     xptr_t         parent_gpt_xp;    // extended pointer on parent thread GPT
-
-    void         * func;             // parent thread entry_func
-    void         * args;             // parent thread entry_args
-    intptr_t       base;             // parent thread u_stack_base
-    uint32_t       size;             // parent thread u_stack_size
-    uint32_t       flags;            // parent_thread flags
-    vpn_t          vpn_base;         // parent thread stack vpn_base
-    vpn_t          vpn_size;         // parent thread stack vpn_size
-    reg_t        * uzone;            // parent thread pointer on uzone  
-
-    vseg_t       * vseg;             // child thread STACK vseg
+    void         * parent_func;      // parent thread entry_func
+    void         * parent_args;      // parent thread entry_args
+    uint32_t       parent_flags;     // parent_thread flags
+    vseg_t       * parent_us_vseg;   // parent thread user stack vseg
+    vseg_t       * child_us_vseg;    // child thread user stack vseg
 
 #if DEBUG_THREAD_USER_FORK
@@ -433,5 +419,5 @@
 thread_t * this  = CURRENT_THREAD;
 if( DEBUG_THREAD_USER_FORK < cycle )
-printk("\n[%s] thread[%x,%x] enter / child_process %x / cycle %d\n",
+printk("\n[%s] thread[%x,%x] enter for child_process %x / cycle %d\n",
 __FUNCTION__, this->process->pid, this->trdid, child_process->pid, cycle );
 #endif
@@ -439,4 +425,10 @@
     // select a target core in local cluster
     core_lid = cluster_select_local_core();
+
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[%s] thread[%x,%x] selected core [%x,%d]\n",
+__FUNCTION__, this->process->pid, this->trdid, local_cxy, core_lid );
+#endif
 
     // get cluster and local pointer on parent thread descriptor
@@ -444,14 +436,9 @@
     parent_ptr = GET_PTR( parent_thread_xp );
 
-    // get relevant fields from parent thread 
-    func  = (void *)  hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->entry_func    ));
-    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_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 ));
-
-    vpn_base = base >> CONFIG_PPM_PAGE_SHIFT;
-    vpn_size = size >> CONFIG_PPM_PAGE_SHIFT;
+    // get relevant infos from parent thread 
+    parent_func    = (void *)  hal_remote_lpt( XPTR(parent_cxy,&parent_ptr->entry_func ));
+    parent_args    = (void *)  hal_remote_lpt( XPTR(parent_cxy,&parent_ptr->entry_args ));
+    parent_flags   = (uint32_t)hal_remote_l32( XPTR(parent_cxy,&parent_ptr->flags ));
+    parent_us_vseg = (vseg_t *)hal_remote_lpt( XPTR(parent_cxy,&parent_ptr->user_stack_vseg ));
 
     // get pointer on parent process in parent thread cluster
@@ -459,14 +446,75 @@
                                                         &parent_ptr->process ) );
  
-    // get extended pointer on parent GPT in parent thread cluster
+    // build extended pointer on parent GPT in parent thread cluster
     parent_gpt_xp = XPTR( parent_cxy , &parent_process->vmm.gpt );
+
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[%s] thread[%x,%x] get parent GPT\n",
+__FUNCTION__, this->process->pid, this->trdid );
+#endif
 
     // allocate memory for child thread descriptor
     child_ptr = thread_alloc();
+
     if( child_ptr == NULL )
     {
-        printk("\n[ERROR] in %s : cannot allocate new thread\n", __FUNCTION__ );
+        printk("\n[ERROR] in %s : cannot allocate new thread\n",
+        __FUNCTION__ );
         return -1;
     }
+
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[%s] thread[%x,%x] allocated new thread descriptor %x\n",
+__FUNCTION__, this->process->pid, this->trdid, child_ptr );
+#endif
+
+    // set type in thread descriptor
+    child_ptr->type = THREAD_USER;
+
+    // register new thread in process descriptor, and get a TRDID
+    error = process_register_thread( child_process, child_ptr , &child_trdid );
+
+    if( error )
+    {
+        printk("\n[ERROR] in %s : cannot register new thread in process %x\n",
+        __FUNCTION__, child_process->pid );
+        thread_destroy( child_ptr );
+        return -1;
+    }
+
+    // set trdid in thread descriptor
+    child_ptr->trdid = child_trdid;
+
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[%s] thread[%x,%x] registered child thread %x in child process %x\n",
+__FUNCTION__, this->process->pid, this->trdid, child_trdid, child_process->pid );
+#endif
+
+    // get an user stack vseg from local VMM allocator
+    child_us_vseg = vmm_create_vseg( child_process,
+                                     VSEG_TYPE_STACK,
+                                     LTID_FROM_TRDID( child_trdid ),  
+                                     0,                               // size unused
+                                     0,                               // file_offset unused
+                                     0,                               // file_size unused
+                                     XPTR_NULL,                       // mapper_xp unused
+                                     local_cxy );
+    if( child_us_vseg == NULL )
+    {
+	    printk("\n[ERROR] in %s : cannot create stack vseg\n", __FUNCTION__ );
+        process_remove_thread( child_ptr );
+        thread_destroy( child_ptr );
+        return -1;
+    }
+
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[%s] thread[%x,%x] created an user stack vseg / vpn_base %x / %d pages\n",
+__FUNCTION__, this->process->pid, this->trdid,
+child_us_vseg->vpn_base, child_us_vseg->vpn_size );
+#endif
 
     // initialize thread descriptor
@@ -474,14 +522,16 @@
                          child_process,
                          THREAD_USER,
-                         func,
-                         args,
+                         child_trdid,
+                         parent_func,
+                         parent_args,
                          core_lid,
-                         base,
-                         size );
+                         child_us_vseg );
     if( error )
     {
 	    printk("\n[ERROR] in %s : cannot initialize child thread\n", __FUNCTION__ );
-        thread_release( child_ptr );
-        return EINVAL;
+        vmm_remove_vseg( child_process , child_us_vseg ); 
+        process_remove_thread( child_ptr );
+        thread_destroy( child_ptr );
+        return -1;
     }
 
@@ -492,29 +542,24 @@
 #endif
 
-    // return child pointer
-    *child_thread = child_ptr;
-
     // set detached flag if required
-    if( flags & THREAD_FLAG_DETACHED ) child_ptr->flags = THREAD_FLAG_DETACHED;
-
-    // update uzone pointer in child thread descriptor
-    child_ptr->uzone_current = (char *)((intptr_t)uzone +
-                                        (intptr_t)child_ptr - 
-                                        (intptr_t)parent_ptr );
- 
-
-    // allocate CPU context for child thread
+    if( parent_flags & THREAD_FLAG_DETACHED ) child_ptr->flags = THREAD_FLAG_DETACHED;
+
+    // allocate a CPU context for child thread
 	if( hal_cpu_context_alloc( child_ptr ) )
     {
 	    printk("\n[ERROR] in %s : cannot allocate CPU context\n", __FUNCTION__ );
-        thread_release( child_ptr );
+        vmm_remove_vseg( child_process , child_us_vseg );
+        process_remove_thread( child_ptr );
+        thread_destroy( child_ptr );
         return -1;
     }
 
-    // allocate FPU context for child thread
+    // allocate a FPU context for child thread
 	if( hal_fpu_context_alloc( child_ptr ) )
     {
 	    printk("\n[ERROR] in %s : cannot allocate FPU context\n", __FUNCTION__ );
-        thread_release( child_ptr );
+        vmm_remove_vseg( child_process , child_us_vseg );
+        process_remove_thread( child_ptr );
+        thread_destroy( child_ptr );
         return -1;
     }
@@ -526,33 +571,21 @@
 #endif
 
-   // create and initialize STACK vseg 
-    vseg = vseg_alloc();
-    vseg_init( vseg,
-               VSEG_TYPE_STACK,
-               base,
-               size,
-               vpn_base,
-               vpn_size,
-               0, 0, XPTR_NULL,                         // not a file vseg
-               local_cxy );
-
-    // register STACK vseg in local child VSL
-    vmm_attach_vseg_to_vsl( &child_process->vmm , vseg );
-
-#if (DEBUG_THREAD_USER_FORK & 1)
-if( DEBUG_THREAD_USER_FORK < cycle )
-printk("\n[%s] thread[%x,%x] created stack vseg for thread %x in process %x\n",
-__FUNCTION__, this->process->pid, this->trdid, child_ptr->trdid, child_process->pid );
-#endif
-
-    // copy all valid STACK GPT entries   
-    vpn_t          vpn;
-    bool_t         mapped;
-    ppn_t          ppn;
-    for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
+    // scan parent GPT, and copy all valid entries
+    // associated to user stack vseg into child GPT
+    vpn_t  parent_vpn;
+    vpn_t  child_vpn;
+    bool_t mapped;
+    ppn_t  ppn;
+    vpn_t  parent_vpn_base = hal_remote_l32( XPTR( parent_cxy, &parent_us_vseg->vpn_base ) );
+    vpn_t  parent_vpn_size = hal_remote_l32( XPTR( parent_cxy, &parent_us_vseg->vpn_size ) );
+    vpn_t  child_vpn_base  = child_us_vseg->vpn_base;
+    for( parent_vpn = parent_vpn_base , child_vpn = child_vpn_base ; 
+         parent_vpn < (parent_vpn_base + parent_vpn_size) ;
+         parent_vpn++ , child_vpn++ )
     {
         error = hal_gpt_pte_copy( &child_process->vmm.gpt,
+                                  child_vpn,
                                   parent_gpt_xp,
-                                  vpn,
+                                  parent_vpn,
                                   true,                 // set cow
                                   &ppn,
@@ -560,11 +593,12 @@
         if( error )
         {
-            vmm_detach_vseg_from_vsl( &child_process->vmm , vseg );
-            thread_release( child_ptr );
             printk("\n[ERROR] in %s : cannot update child GPT\n", __FUNCTION__ );
+            vmm_remove_vseg( child_process , child_us_vseg );
+            process_remove_thread( child_ptr );
+            thread_destroy( child_ptr );
             return -1;
         }
 
-        // increment pending forks counter for the page if mapped
+        // increment pending forks counter for a mapped page 
         if( mapped )
         {
@@ -574,5 +608,5 @@
             page_t * page_ptr = GET_PTR( page_xp );
 
-            // get extended pointers on forks and lock fields
+            // build extended pointers on forks and lock fields
             xptr_t forks_xp = XPTR( page_cxy , &page_ptr->forks );
             xptr_t lock_xp  = XPTR( page_cxy , &page_ptr->lock );
@@ -586,26 +620,33 @@
             // release lock protecting page
             remote_busylock_release( lock_xp );  
+        }
+    }
 
 #if (DEBUG_THREAD_USER_FORK & 1)
-cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_THREAD_USER_FORK < cycle )
-printk("\n[%s] thread[%x,%x] copied one PTE to child GPT : vpn %x / forks %d\n",
-__FUNCTION__, this->process->pid, this->trdid, 
-vpn, hal_remote_l32( XPTR( page_cxy , &page_ptr->forks) ) );
-#endif
-
-        }
-    }
-
-    // set COW flag for all mapped entries of STAK vseg in parent thread GPT 
+printk("\n[%s] thread[%x,%x] copied all stack vseg PTEs to child GPT\n",
+__FUNCTION__, this->process->pid, this->trdid );
+#endif
+
+    // set COW flag for all mapped entries of user stack vseg in parent GPT 
     hal_gpt_set_cow( parent_gpt_xp,
-                     vpn_base,
-                     vpn_size );
- 
+                     parent_vpn_base,
+                     parent_vpn_size );
+
+#if (DEBUG_THREAD_USER_FORK & 1)
+if( DEBUG_THREAD_USER_FORK < cycle )
+printk("\n[%s] thread[%x,%x] set the COW flag for stack vseg in parent GPT\n",
+__FUNCTION__, this->process->pid, this->trdid );
+#endif
+
+    // return child pointer
+    *child_thread = child_ptr;
+
 #if DEBUG_THREAD_USER_FORK
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_THREAD_USER_FORK < cycle )
-printk("\n[%s] thread[%x,%x] exit / child_thread %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, child_ptr, cycle );
+printk("\n[%s] thread[%x,%x] exit / created thread[%x,%x] / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid,
+child_ptr->process->pid, child_ptr->trdid, cycle );
 #endif
 
@@ -660,13 +701,13 @@
 
     // allocate an user stack vseg for main thread
-    vseg_t * vseg = vmm_create_vseg( process,
-                                     VSEG_TYPE_STACK,
-                                     0,                 // size unused
-                                     0,                 // length unused
-                                     0,                 // file_offset unused
-                                     0,                 // file_size unused
-                                     XPTR_NULL,         // mapper_xp unused
-                                     local_cxy );
-    if( vseg == NULL )
+    vseg_t * us_vseg = vmm_create_vseg( process,
+                                        VSEG_TYPE_STACK,
+                                        LTID_FROM_TRDID( thread->trdid ),
+                                        0,                 // length unused
+                                        0,                 // file_offset unused
+                                        0,                 // file_size unused
+                                        XPTR_NULL,         // mapper_xp unused
+                                        local_cxy );
+    if( us_vseg == NULL )
     {
 	    printk("\n[ERROR] in %s : cannot create stack vseg for main thread\n", __FUNCTION__ );
@@ -675,6 +716,5 @@
 
     // update user stack in thread descriptor
-    thread->u_stack_base = vseg->min;
-    thread->u_stack_size = vseg->max - vseg->min;
+    thread->user_stack_vseg = us_vseg;
     
     // release FPU ownership if required
@@ -710,4 +750,5 @@
     error_t        error;
 	thread_t     * thread;       // pointer on new thread descriptor
+    trdid_t        trdid;        // new thread identifier
 
     thread_t * this = CURRENT_THREAD; 
@@ -737,19 +778,33 @@
     }
 
+    // set type in thread descriptor
+    thread->type = type;
+
+    // register new thread in local kernel process descriptor, and get a TRDID
+    error = process_register_thread( &process_zero , thread , &trdid );
+
+    if( error )
+    {
+        printk("\n[ERROR] in %s : cannot register thread in kernel process\n", __FUNCTION__ );
+        return -1;
+    }
+
+    // set trdid in thread descriptor
+    thread->trdid = trdid;
+
     // initialize thread descriptor
     error = thread_init( thread,
                          &process_zero,
                          type,
+                         trdid,
                          func,
                          args,
                          core_lid,
-                         0 , 0 );  // no user stack for a kernel thread
+                         NULL );  // no user stack for a kernel thread
 
     if( error ) // release allocated memory for thread descriptor
     {
-        printk("\n[ERROR] in %s : thread %x in process %x\n"
-        "   cannot initialize thread descriptor\n",
-        __FUNCTION__, this->trdid, this->process->pid );
-        thread_release( thread );
+        printk("\n[ERROR] in %s : cannot initialize thread descriptor\n", __FUNCTION__ );
+        thread_destroy( thread );
         return ENOMEM;
     }
@@ -763,5 +818,5 @@
         "    cannot create CPU context\n",
         __FUNCTION__, this->trdid, this->process->pid );
-        thread_release( thread );
+        thread_destroy( thread );
         return EINVAL;
     }
@@ -791,4 +846,6 @@
 	                   lid_t           core_lid )
 {
+    trdid_t trdid;   
+    error_t error;
 
 // check arguments
@@ -796,19 +853,31 @@
 assert( (core_lid < LOCAL_CLUSTER->cores_nr) , "illegal core index" );
 
+    // set type in thread descriptor
+    thread->type = THREAD_IDLE;
+
+    // register idle thread in local kernel process descriptor, and get a TRDID
+    error = process_register_thread( &process_zero , thread , &trdid );
+
+assert( (error == 0), "cannot register idle_thread in kernel process" );
+
+    // set trdid in thread descriptor
+    thread->trdid = trdid;
+
     // initialize thread descriptor
-    error_t  error = thread_init( thread,
-                                  &process_zero,
-                                  type,
-                                  func,
-                                  args,
-                                  core_lid,
-                                  0 , 0 );   // no user stack for a kernel thread
-
-    assert( (error == 0), "cannot create thread idle" );
+    error = thread_init( thread,
+                         &process_zero,
+                         THREAD_IDLE,
+                         trdid,
+                         func,
+                         args,
+                         core_lid,
+                         NULL );   // no user stack for a kernel thread
+
+assert( (error == 0), "cannot initialize idle_thread" );
 
     // allocate & initialize CPU context if success
     error = hal_cpu_context_alloc( thread );
 
-    assert( (error == 0), "cannot allocate CPU context" );
+assert( (error == 0), "cannot allocate CPU context" );
 
     hal_cpu_context_init( thread );
@@ -816,14 +885,13 @@
 }  // end thread_idle_init()
 
-///////////////////////////////////////////////////////////////////////////////////////
-// TODO: check that all memory dynamically allocated during thread execution
-// has been released => check vmm destroy for MMAP vsegs  [AG]
-///////////////////////////////////////////////////////////////////////////////////////
-void thread_destroy( thread_t * thread )
-{
-    reg_t        save_sr;
-
-    process_t  * process    = thread->process;
-    core_t     * core       = thread->core;
+////////////////////////////////////////////
+uint32_t thread_destroy( thread_t * thread )
+{
+    reg_t           save_sr;
+    uint32_t        count;
+
+    thread_type_t   type    = thread->type;
+    process_t     * process = thread->process;
+    core_t        * core    = thread->core;
 
 #if DEBUG_THREAD_DESTROY
@@ -835,14 +903,20 @@
 #endif
 
-    // check busylocks counter
+    // check calling thread busylocks counter
     thread_assert_can_yield( thread , __FUNCTION__ );
 
-    // update intrumentation values
+    // update target process instrumentation counter
 	process->vmm.pgfault_nr += thread->info.pgfault_nr;
 
-    // release memory allocated for CPU context and FPU context
+    // remove thread from process th_tbl[]
+    count = process_remove_thread( thread );
+
+    // release memory allocated for CPU context and FPU context if required
 	hal_cpu_context_destroy( thread );
-	if ( thread->type == THREAD_USER ) hal_fpu_context_destroy( thread );
+	hal_fpu_context_destroy( thread );
 	
+    // release user stack vseg (for an user thread only)
+    if( type == THREAD_USER )  vmm_remove_vseg( process , thread->user_stack_vseg );
+
     // release FPU ownership if required
 	hal_disable_irq( &save_sr );
@@ -857,6 +931,11 @@
 	thread->signature = 0;
 
-    // release memory for thread descriptor
-    thread_release( thread );
+    // release memory for thread descriptor (including kernel stack)
+    kmem_req_t   req;
+    xptr_t       base_xp = ppm_base2page( XPTR(local_cxy , thread ) );
+
+    req.type  = KMEM_PAGE;
+    req.ptr   = GET_PTR( base_xp );
+    kmem_free( &req );
 
 #if DEBUG_THREAD_DESTROY
@@ -866,4 +945,6 @@
 __FUNCTION__, this->process->pid, this->trdid, process->pid, thread->trdid, cycle );
 #endif
+
+    return count;
 
 }   // end thread_destroy()
@@ -993,4 +1074,6 @@
     cxy_t       target_cxy;             // target thread cluster     
     thread_t  * target_ptr;             // pointer on target thread
+    process_t * target_process;         // pointer on arget process
+    pid_t       target_pid;             // target process identifier
     xptr_t      target_flags_xp;        // extended pointer on target thread <flags>
     xptr_t      target_join_lock_xp;    // extended pointer on target thread <join_lock>
@@ -1006,9 +1089,15 @@
     target_ptr      = GET_PTR( target_xp );
 
-    // get target thread identifiers, and attached flag
+    // get target thread identifier, attached flag, and process PID
     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_attached = ( (hal_remote_l32( target_flags_xp ) & THREAD_FLAG_DETACHED) == 0 );
+    target_process  = hal_remote_lpt( XPTR( target_cxy , &target_ptr->process ) );
+    target_pid      = hal_remote_l32( XPTR( target_cxy , &target_process->pid ) );
+
+// check target PID
+assert( (pid == target_pid),
+"unconsistent pid and target_xp arguments" );
 
     // get killer thread pointers
@@ -1027,5 +1116,5 @@
 // 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" );
+"target thread cannot be the main thread" );
 
     // check killer thread can yield 
@@ -1151,4 +1240,9 @@
 void thread_idle_func( void )
 {
+
+#if DEBUG_THREAD_IDLE
+uint32_t cycle;
+#endif
+
     while( 1 )
     {
@@ -1161,10 +1255,8 @@
 
 #if DEBUG_THREAD_IDLE
-{ 
-uint32_t cycle = (uint32_t)hal_get_cycles();
+cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_THREAD_IDLE < cycle )
 printk("\n[%s] idle thread on core[%x,%d] goes to sleep / cycle %d\n",
 __FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, cycle );
-}
 #endif
 
@@ -1172,10 +1264,8 @@
 
 #if DEBUG_THREAD_IDLE
-{
-uint32_t cycle = (uint32_t)hal_get_cycles();
+cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_THREAD_IDLE < cycle )
 printk("\n[%s] idle thread on core[%x,%d] wake up / cycle %d\n",
 __FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, cycle );
-}
 #endif
 
@@ -1183,9 +1273,7 @@
 
 #if DEBUG_THREAD_IDLE
-{
-uint32_t cycle = (uint32_t)hal_get_cycles();
+cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_THREAD_IDLE < cycle )
 sched_display( CURRENT_THREAD->core->lid );
-}
 #endif     
         // search a runable thread
