Index: trunk/kernel/kern/process.c
===================================================================
--- trunk/kernel/kern/process.c	(revision 662)
+++ trunk/kernel/kern/process.c	(revision 669)
@@ -41,4 +41,5 @@
 #include <thread.h>
 #include <chdev.h>
+#include <ksocket.h>
 #include <list.h>
 #include <string.h>
@@ -72,10 +73,13 @@
 process_t * process_alloc( void )
 {
+
+assert( __FUNCTION__, (sizeof(process_t) < CONFIG_PPM_PAGE_SIZE),
+"process descriptor exceeds 1 page" );
+
 	kmem_req_t req;
 
-    req.type  = KMEM_KCM;
-	req.order = bits_log2( sizeof(process_t) );
-	req.flags = AF_KERNEL;
-
+    req.type  = KMEM_PPM;
+	req.order = 0;
+	req.flags = AF_KERNEL | AF_ZERO;
     return kmem_alloc( &req );
 }
@@ -86,5 +90,5 @@
     kmem_req_t  req;
 
-	req.type = KMEM_KCM;
+	req.type = KMEM_PPM;
 	req.ptr  = process;
 	kmem_free( &req );
@@ -109,8 +113,4 @@
     char        rx_path[40];
     char        tx_path[40];
-    xptr_t      file_xp;
-    xptr_t      chdev_xp;
-    chdev_t   * chdev_ptr;
-    cxy_t       chdev_cxy;
     pid_t       parent_pid;
     vmm_t     * vmm;
@@ -211,5 +211,5 @@
 
         // attach process to TXT
-        process_txt_attach( process , txt_id ); 
+        process_txt_attach( process_xp , txt_id ); 
 
 #if (DEBUG_PROCESS_REFERENCE_INIT & 1)
@@ -220,6 +220,6 @@
 #endif
         // build path to TXT_RX[i] and TXT_TX[i] chdevs
-        snprintf( rx_path , 40 , "/dev/external/txt%d_rx", txt_id );
-        snprintf( tx_path , 40 , "/dev/external/txt%d_tx", txt_id );
+        snprintk( rx_path , 40 , "/dev/external/txt%d_rx", txt_id );
+        snprintk( tx_path , 40 , "/dev/external/txt%d_tx", txt_id );
 
         // create stdin pseudo file          
@@ -237,5 +237,5 @@
         }
 
-assert( (stdin_id == 0) , "stdin index must be 0" );
+assert( __FUNCTION__, (stdin_id == 0) , "stdin index must be 0" );
 
 #if (DEBUG_PROCESS_REFERENCE_INIT & 1)
@@ -260,5 +260,5 @@
         }
 
-assert( (stdout_id == 1) , "stdout index must be 1" );
+assert( __FUNCTION__, (stdout_id == 1) , "stdout index must be 1" );
 
 #if (DEBUG_PROCESS_REFERENCE_INIT & 1)
@@ -283,5 +283,5 @@
         }
 
-assert( (stderr_id == 2) , "stderr index must be 2" );
+assert( __FUNCTION__, (stderr_id == 2) , "stderr index must be 2" );
 
 #if (DEBUG_PROCESS_REFERENCE_INIT & 1)
@@ -295,29 +295,16 @@
     else                                            // normal user process 
     {
-        // get extended pointer on stdin pseudo file in parent process
-        file_xp = (xptr_t)hal_remote_l64( XPTR( parent_cxy,
-                                                &parent_ptr->fd_array.array[0] ) );
-
-        // get extended pointer on parent process TXT chdev
-        chdev_xp = chdev_from_file( file_xp );
- 
-        // get cluster and local pointer on chdev
-        chdev_cxy = GET_CXY( chdev_xp );
-        chdev_ptr = GET_PTR( chdev_xp );
- 
-        // get parent process TXT terminal index
-        txt_id = hal_remote_l32( XPTR( chdev_cxy , &chdev_ptr->channel ) );
-
-        // attach child process to parent process TXT terminal
-        process_txt_attach( process , txt_id ); 
-
-        // copy all open files from parent process fd_array to this process
-        process_fd_remote_copy( XPTR( local_cxy , &process->fd_array ),
-                                XPTR( parent_cxy , &parent_ptr->fd_array ) );
+        // get parent process TXT index
+        txt_id = process_txt_get_index( parent_xp );
+
+        // attach child process to same TXT terminal as parent
+        process_txt_attach( process_xp , txt_id ); 
+
+        // recreate all open files from parent process fd_array to child process fd_array
+        process_fd_replicate( process_xp , parent_xp );
     }
 
     // initialize lock protecting CWD changes
-    remote_busylock_init( XPTR( local_cxy , 
-                                &process->cwd_lock ), LOCK_PROCESS_CWD );
+    remote_busylock_init( XPTR( local_cxy , &process->cwd_lock ), LOCK_PROCESS_CWD );
 
 #if (DEBUG_PROCESS_REFERENCE_INIT & 1)
@@ -415,5 +402,5 @@
 
 // check user process
-assert( (local_process->pid != 0), "LPID cannot be 0" );
+assert( __FUNCTION__, (local_process->pid != 0), "LPID cannot be 0" );
 
     // initialize VSL as empty
@@ -520,5 +507,5 @@
 
 // check no more threads
-assert( (process->th_nr == 0),
+assert( __FUNCTION__, (process->th_nr == 0),
 "process %x in cluster %x contains threads", pid , local_cxy );
 
@@ -616,5 +603,5 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_DESTROY < cycle )
-printk("\n[%s] thread[%x,%x] exit / process %x in cluster %x / cycle %d\n",
+printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
 __FUNCTION__, this->process->pid, this->trdid, pid, local_cxy, cycle );
 #endif
@@ -683,5 +670,5 @@
 
 // check action type
-assert( ((type == DELETE_ALL_THREADS ) ||
+assert( __FUNCTION__, ((type == DELETE_ALL_THREADS ) ||
          (type == BLOCK_ALL_THREADS )  ||
          (type == UNBLOCK_ALL_THREADS )), "illegal action type" );
@@ -809,5 +796,5 @@
 
 // check target process is an user process
-assert( (LPID_FROM_PID( process->pid ) != 0 ),
+assert( __FUNCTION__, (LPID_FROM_PID( process->pid ) != 0 ),
 "process %x is not an user process\n", process->pid );
 
@@ -894,5 +881,5 @@
 
 // check target process is an user process
-assert( (LPID_FROM_PID( process->pid ) != 0),
+assert( __FUNCTION__, (LPID_FROM_PID( process->pid ) != 0),
 "process %x is not an user process\n", process->pid );
 
@@ -916,5 +903,5 @@
             {
                 // mark target thread for delete and block it
-                thread_delete( target_xp , true );                   // forced 
+                thread_delete_request( target_xp , true );                   // forced 
             }
         }
@@ -950,5 +937,5 @@
 
 // check target process is an user process
-assert( ( LPID_FROM_PID( process->pid ) != 0 ),
+assert( __FUNCTION__, ( LPID_FROM_PID( process->pid ) != 0 ),
 "process %x is not an user process\n", process->pid );
 
@@ -1027,5 +1014,5 @@
         xptr_t ref_xp = cluster_get_reference_process_from_pid( pid );
 
-        assert( (ref_xp != XPTR_NULL) , "illegal pid\n" );
+        assert( __FUNCTION__, (ref_xp != XPTR_NULL) , "illegal pid\n" );
 
         // allocate memory for local process descriptor
@@ -1081,12 +1068,12 @@
     switch( type )
     {
-        case INODE_TYPE_FILE : return "FILE";
-        case INODE_TYPE_DIR  : return "DIR";
-        case INODE_TYPE_FIFO : return "FIFO";
-        case INODE_TYPE_PIPE : return "PIPE";
-        case INODE_TYPE_SOCK : return "SOCK";
-        case INODE_TYPE_DEV  : return "DEV";
-        case INODE_TYPE_BLK  : return "BLK";
-        case INODE_TYPE_SYML : return "SYML";
+        case FILE_TYPE_REG : return "FILE";
+        case FILE_TYPE_DIR  : return "DIR";
+        case FILE_TYPE_FIFO : return "FIFO";
+        case FILE_TYPE_PIPE : return "PIPE";
+        case FILE_TYPE_SOCK : return "SOCK";
+        case FILE_TYPE_DEV  : return "DEV";
+        case FILE_TYPE_BLK  : return "BLK";
+        case FILE_TYPE_SYML : return "SYML";
         
         default              : return "undefined";
@@ -1129,5 +1116,5 @@
 
 // check target process is owner process
-assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) ) ),
+assert( __FUNCTION__, (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) ) ),
 "process must be owner process\n" );
 
@@ -1145,5 +1132,5 @@
     max_xp  = XPTR( process_cxy , &process_ptr->fd_array.max );
 
-    // take lock protecting reference fd_array
+    // take lock protecting fd_array
 	remote_queuelock_acquire( lock_xp );
 
@@ -1158,4 +1145,5 @@
         entry_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) );
         
+        // take the first empty slot
         if ( entry_xp == XPTR_NULL )
         {
@@ -1165,7 +1153,4 @@
             // update max when required
             if( id > max ) hal_remote_s32( max_xp , id );
-
-            // increase file refcount
-            vfs_file_count_up( file_xp );
 
             // exit loop
@@ -1208,5 +1193,5 @@
 
 // check target process is owner process
-assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) ) ),
+assert( __FUNCTION__, (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) ) ),
 "process must be owner process\n" );
 
@@ -1253,7 +1238,4 @@
         // release the fd_array entry in process copy
         hal_remote_s64( XPTR( copy_cxy , &copy_ptr->fd_array.array[fdid] ), XPTR_NULL );
-
-        // decrease file refcount
-        vfs_file_count_down( file_xp );
     }
 
@@ -1261,5 +1243,5 @@
     if( fdid == max ) hal_remote_s32( fd_max_xp , max-1 );
 
-    // release the lock protecting reference fd_array
+    // release the lock protecting fd_array
 	remote_queuelock_release( fd_lock_xp );
 
@@ -1279,17 +1261,15 @@
 void process_fd_clean_all( xptr_t process_xp )
 {
-    uint32_t  id;
+    uint32_t  fdid;
     xptr_t    file_xp;         // one fd_array entry
     xptr_t    lock_xp;         // extendad pointer on lock protecting fd_array
     uint32_t  max;             // number of registered files
-    error_t   error;
 
     // get process cluster, local pointer and PID
     process_t * process_ptr = GET_PTR( process_xp );
     cxy_t       process_cxy = GET_CXY( process_xp );
-    pid_t       pid         = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid) );
 
 // check target process is owner process
-assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp )) ),
+assert( __FUNCTION__, (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp )) ),
 "process must be owner process\n" );
 
@@ -1298,6 +1278,6 @@
 uint32_t   cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_FD_CLEAN_ALL < cycle )
-printk("\n[%s] thread[%x,%x] enter for process %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, cycle );
+printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, cycle );
 
 process_fd_display( process_xp );
@@ -1313,17 +1293,25 @@
 	remote_queuelock_acquire( lock_xp );
 
-    for ( id = 0; id <= max ; id++ )
+    for( fdid = 0 ; fdid <= max ; fdid++ )
     {
         // get fd_array entry
-        file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) );
+        file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[fdid] ) );
         
         if ( file_xp != XPTR_NULL )
         {
-            // close the file or socket
-            error = sys_close( id );
-
-            if( error )
-            printk("/n[ERROR] in %s : cannot close the file %d for process %x\n",
-            __FUNCTION__, id, pid );
+            vfs_file_t * file_ptr = GET_PTR( file_xp );
+            cxy_t        file_cxy = GET_CXY( file_xp );
+
+            // get file type
+            uint32_t file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ));
+ 
+            if( file_type == FILE_TYPE_REG )
+            {
+                vfs_close( file_xp , fdid );
+            }
+            if( file_type == FILE_TYPE_SOCK )
+            {
+                socket_close( file_xp , fdid );
+            }
         }
     }
@@ -1348,5 +1336,5 @@
     process_t * process_ptr = GET_PTR( process_xp );
 
-assert( (hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp )) == process_xp),
+assert( __FUNCTION__, (hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp )) == process_xp),
 "process_xp argument must be the owner process" );
 
@@ -1379,5 +1367,5 @@
 	    remote_queuelock_acquire( lock_xp );
 
-        // access reference process descriptor
+        // access owner process descriptor
         file_xp = hal_remote_l64( XPTR( owner_cxy , &owner_ptr->fd_array.array[fdid] ) );
 
@@ -1386,7 +1374,4 @@
            // update local fd_array 
             process->fd_array.array[fdid] = file_xp;
-        
-            // increase file refcount
-            vfs_file_count_up( file_xp );
         }
 
@@ -1399,41 +1384,68 @@
 }  // end process_fd_get_xptr_from_local()
 
-///////////////////////////////////////////
-void process_fd_remote_copy( xptr_t dst_xp,
-                             xptr_t src_xp )
-{
-    uint32_t fd;
-    xptr_t   entry;
-
-    // get cluster and local pointer for src fd_array
-    cxy_t        src_cxy = GET_CXY( src_xp );
-    fd_array_t * src_ptr = GET_PTR( src_xp );
-
-    // get cluster and local pointer for dst fd_array
-    cxy_t        dst_cxy = GET_CXY( dst_xp );
-    fd_array_t * dst_ptr = GET_PTR( dst_xp );
+/////////////////////////////////////////
+void process_fd_replicate( xptr_t dst_xp,
+                           xptr_t src_xp )
+{
+    uint32_t fdid;      // current file descriptor index
+    xptr_t   old_xp;    // extended pointer on a file descriptor (stored in SRC fd_array) 
+    xptr_t   new_xp;    // extended pointer on a file descriptor (stored in DST fd_array)
+    error_t  error;
+
+    // get cluster and local pointer for SRC process
+    cxy_t       src_cxy = GET_CXY( src_xp );
+    process_t * src_ptr = GET_PTR( src_xp );
+
+assert( __FUNCTION__, (src_xp == hal_remote_l64( XPTR( src_cxy , &src_ptr->owner_xp ))),
+"src_xp process not in owner cluster" );
+
+    // get cluster and local pointer for DST fd_array
+    cxy_t       dst_cxy = GET_CXY( dst_xp );
+    process_t * dst_ptr = GET_PTR( dst_xp );
+
+assert( __FUNCTION__, (dst_xp == hal_remote_l64( XPTR( dst_cxy , &dst_ptr->owner_xp ))),
+"dst_xp process not in owner cluster" );
+
+    // build extende pointers on SRC fd_array lock and max fields
+    xptr_t  src_lock_xp = XPTR( src_cxy , &src_ptr->fd_array.lock );
+    xptr_t  src_max_xp  = XPTR( src_cxy , &src_ptr->fd_array.max );
 
     // get the remote lock protecting the src fd_array
-	remote_queuelock_acquire( XPTR( src_cxy , &src_ptr->lock ) );
-
-    // loop on all fd_array entries
-    for( fd = 0 ; fd < CONFIG_PROCESS_FILE_MAX_NR ; fd++ )
+	remote_queuelock_acquire( src_lock_xp );
+ 
+    // loop on fd_array entries
+    for( fdid = 0 ; fdid <= hal_remote_l32( src_max_xp ) ; fdid++ )
 	{
-		entry = (xptr_t)hal_remote_l64( XPTR( src_cxy , &src_ptr->array[fd] ) );
-
-		if( entry != XPTR_NULL )
+		old_xp = (xptr_t)hal_remote_l64( XPTR( src_cxy , &src_ptr->fd_array.array[fdid] ) );
+
+		if( old_xp != XPTR_NULL )
 		{
-            // increment file descriptor refcount
-            vfs_file_count_up( entry );
-
-			// copy entry in destination process fd_array
-			hal_remote_s64( XPTR( dst_cxy , &dst_ptr->array[fd] ) , entry );
+            // get the existing file descriptor cluster and local pointer
+            vfs_file_t * old_ptr = GET_PTR( old_xp );
+            cxy_t        old_cxy = GET_CXY( old_xp );
+
+            // get existing file attributes and local pointer on inode
+            uint32_t      attr      = hal_remote_l32( XPTR( old_cxy , &old_ptr->attr ) );
+            vfs_inode_t * inode_ptr = hal_remote_lpt( XPTR( old_cxy , &old_ptr->inode ) );
+
+            // create a new file descriptor in same cluster as the existing one
+            error = vfs_file_create( XPTR( old_cxy , inode_ptr ),
+                                     attr,
+                                     &new_xp );
+            if( error )
+            {
+                printk("\n[ERROR] in %s : cannot create new file\n", __FUNCTION__ );
+                return;
+            }
+
+			// register new_xp in DST fd_array
+			hal_remote_s64( XPTR( dst_cxy , &dst_ptr->fd_array.array[fdid] ) , new_xp );
 		}
 	}
 
     // release lock on source process fd_array
-	remote_queuelock_release( XPTR( src_cxy , &src_ptr->lock ) );
-
-}  // end process_fd_remote_copy()
+	remote_queuelock_release( src_lock_xp );
+
+}  // end process_fd_replicate()
 
 
@@ -1497,6 +1509,6 @@
             file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type )); 
 
-            // get file name for a true file
-            if( file_type == INODE_TYPE_FILE )
+            // get file name if inode exist
+            if( (file_type != FILE_TYPE_PIPE) && (file_type != FILE_TYPE_SOCK) )
             {
                 // get inode pointers 
@@ -1507,18 +1519,17 @@
                 vfs_inode_get_name( inode_xp , name );
 
-                // display relevant file decriptor info
-                printk(" - %d : type %s (%s)\n",
-                fdid , process_fd_type_str(file_type), name );
+                // display relevant file descriptor info
+                printk(" - %d : type %s / ptr %x (%s)\n",
+                fdid, process_fd_type_str(file_type), file_ptr, name );
             }
-            else
+            else    // PIPE or SOCK types
             {
                 // display relevant file decriptor info
-                printk(" - %d : type %s\n",
-                fdid , process_fd_type_str(file_type) );
+                printk(" - %d : type %s / ptr %x\n",
+                fdid , process_fd_type_str(file_type), file_ptr );
             }
         }
         else
         {
-            // display relevant file decriptor info
             printk(" - %d : empty slot\n",
             fdid );
@@ -1540,6 +1551,6 @@
  
 // check arguments
-assert( (process != NULL) , "process argument is NULL" );
-assert( (thread != NULL) , "thread argument is NULL" );
+assert( __FUNCTION__, (process != NULL) , "process argument is NULL" );
+assert( __FUNCTION__, (thread != NULL) , "thread argument is NULL" );
 
     // get the lock protecting th_tbl for all threads
@@ -1580,5 +1591,5 @@
 
 // check thread
-assert( (thread != NULL) , "thread argument is NULL" );
+assert( __FUNCTION__, (thread != NULL) , "thread argument is NULL" );
 
     process_t * process = thread->process;
@@ -1594,5 +1605,5 @@
 
 // check th_nr value
-assert( (count > 0) , "process th_nr cannot be 0" );
+assert( __FUNCTION__, (count > 0) , "process th_nr cannot be 0" );
 
     // remove thread from th_tbl[]
@@ -1633,5 +1644,5 @@
 
 // check parent process is the reference process
-assert( (parent_process_xp == ref_xp ) ,
+assert( __FUNCTION__, (parent_process_xp == ref_xp ) ,
 "parent process must be the reference process" );
 
@@ -1711,7 +1722,9 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_MAKE_FORK < cycle )
-printk("\n[%s] thread[%x,%x] copied VMM from parent to child / cycle %d\n",
-__FUNCTION__, pid, trdid, cycle );
-hal_vmm_display( XPTR( local_cxy , process ) , true );
+{
+    printk("\n[%s] thread[%x,%x] copied VMM from parent to child / cycle %d\n",
+    __FUNCTION__, pid, trdid, cycle );
+    hal_vmm_display( XPTR( local_cxy , process ) , true );
+}
 #endif
 
@@ -1748,5 +1761,5 @@
 
 // check main thread LTID
-assert( (LTID_FROM_TRDID(thread->trdid) == 0) ,
+assert( __FUNCTION__, (LTID_FROM_TRDID(thread->trdid) == 0) ,
 "main thread must have LTID == 0" );
 
@@ -1806,41 +1819,210 @@
 }   // end process_make_fork()
 
-/////////////////////////////////////////////////////
-error_t process_make_exec( exec_info_t  * exec_info )
-{
-    thread_t       * thread;                  // local pointer on this thread
+////////////////////////////////////////////////i//////////////////////////////////////
+// This static function is called by the thread_user_exec() function :
+// - to register the main() arguments (args) in the <exec_info> structure.
+// - to register the environment variables (envs) in the <exec_info> structure.
+// In both cases the input is an array of NULL terminated string pointers in user
+// space, and the strings can be dispatched anywhere in the user process space.
+// This array of pointers is defined by the <u_pointers> argument. The empty slots 
+// contain the NULL value, and the N non-empty slots are indexed from 0 to (N-1).
+// - The max number of envs, and the max number of args are defined by the
+//   CONFIG_PROCESS_ARGS_NR and CONFIG_PROCESS_ENVS_MAX_NR parameters. 
+// - The numbers of pages to store the (args) and (envs) strings are defined by the
+//   CONFIG_VMM_ENVS_SIZE and CONFIG_VMM_STACK_SIZE parameters.
+///////////////////////////////////////////////////////////////////////////////////////
+// Implementation note:
+// It allocates a kernel buffer to store a kernel copy of both the array of pointers,
+// and the strings. It set the pointers and copies the strings in this kernel buffer.
+// Finally, it registers the buffer & the actual number of strings in the process
+// exec_info structure  (defined in the <process.h> file).
+///////////////////////////////////////////////////////////////////////////////////////
+// @ is_args     : [in]    true if called for (args) / false if called for (envs).
+// @ u_pointers  : [in]    array of pointers on the strings (in user space).
+// @ exec_info   : [out]   pointer on the exec_info structure.
+// @ return 0 if success / non-zero if too many strings or no memory.
+///////////////////////////////////////////////////////////////////////////////////////
+error_t process_exec_get_strings( bool_t         is_args,
+                                  char        ** u_pointers,
+                                  exec_info_t  * exec_info )
+{
+    uint32_t     index;           // slot index in pointers array
+    uint32_t     length;          // string length (in bytes)
+    uint32_t     pointers_bytes;  // number of bytes to store pointers
+    uint32_t     max_index;       // max size of pointers array
+    char      ** k_pointers;      // base of kernel array of pointers
+    char       * k_buf_ptr;       // pointer on first empty slot in strings buffer
+    uint32_t     k_buf_space;     // number of bytes available in string buffer
+    kmem_req_t   req;             // kernel memory allocator request
+    char       * k_buf;           // kernel buffer for both pointers & strings 
+
+#if DEBUG_PROCESS_EXEC_GET_STRINGS 
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+#endif
+
+    // Allocate one block of physical memory for both the pointers and the strings
+    // as defined by the CONFIG_VMM_ARGS_SIZE and CONFIG_VMM_ENVS_SIZE parameters
+    // - the array of pointers is stored in the first bytes of the kernel buffer
+    // - the strings themselve are stored in the next bytes of this buffer
+    // Set the k_pointers, k_buf_ptr, k_buf_space, and max_index
+
+    if( is_args )
+    {
+        req.type   = KMEM_PPM;
+        req.order  = bits_log2( CONFIG_VMM_ARGS_SIZE );
+        req.flags  = AF_KERNEL | AF_ZERO;
+        k_buf      = kmem_alloc( &req );
+
+        pointers_bytes = CONFIG_PROCESS_ARGS_MAX_NR * sizeof(char *);
+        k_pointers     = (char **)k_buf;
+        k_buf_ptr      = k_buf + pointers_bytes;
+        k_buf_space    = (CONFIG_VMM_ARGS_SIZE * CONFIG_PPM_PAGE_SIZE) - pointers_bytes;
+        max_index      = CONFIG_PROCESS_ARGS_MAX_NR;
+
+#if DEBUG_PROCESS_EXEC_GET_STRINGS 
+if( DEBUG_PROCESS_EXEC_GET_STRINGS < cycle )
+printk("\n[%s] thread[%x,%x] for args / u_buf %x / k_buf %x\n",
+__FUNCTION__, this->process->pid, this->trdid, u_pointers, k_buf );
+#endif
+
+    }
+    else
+    {
+        req.type   = KMEM_PPM;
+        req.order  = bits_log2( CONFIG_VMM_ENVS_SIZE );
+        req.flags  = AF_KERNEL | AF_ZERO;
+        k_buf      = kmem_alloc( &req );
+
+        pointers_bytes = CONFIG_PROCESS_ENVS_MAX_NR * sizeof(char *);
+        k_pointers     = (char **)k_buf;
+        k_buf_ptr      = k_buf + pointers_bytes;
+        k_buf_space    = (CONFIG_VMM_ENVS_SIZE * CONFIG_PPM_PAGE_SIZE) - pointers_bytes;
+        max_index      = CONFIG_PROCESS_ENVS_MAX_NR;
+
+#if DEBUG_PROCESS_EXEC_GET_STRINGS 
+if( DEBUG_PROCESS_EXEC_GET_STRINGS < cycle )
+printk("\n[%s] thread[%x,%x] for envs / u_buf %x / k_buf %x\n",
+__FUNCTION__, this->process->pid, this->trdid, u_pointers, k_buf );
+#endif
+
+    }
+
+    // copy the user array of pointers to kernel buffer
+    hal_copy_from_uspace( XPTR( local_cxy , k_pointers ),
+                          u_pointers,
+                          pointers_bytes );
+
+    // WARNING : the pointers copied in the k_pointers[] array are user pointers,
+    // after the loop below, the k_pointers[] array contains kernel pointers.
+
+#if DEBUG_PROCESS_EXEC_GET_STRINGS 
+if( DEBUG_PROCESS_EXEC_GET_STRINGS < cycle )
+printk("\n[%s] thread[%x,%x] copied u_ptr array to k_ptr array\n"
+"    p0 = %x / p1 = %x / p2 = %x / p3 = %x\n",
+__FUNCTION__, this->process->pid, this->trdid,
+k_pointers[0], k_pointers[1], k_pointers[2], k_pointers[3] );
+#endif
+
+    // scan kernel array of pointers to copy strings to kernel buffer
+    for( index = 0 ; index < max_index ; index++ )
+    {
+        // exit loop if (k_pointers[] == NUll)
+        if( k_pointers[index] == NULL ) break;
+
+        // compute string length 
+        length = hal_strlen_from_uspace( k_pointers[index] ) + 1;
+
+        // return error if overflow in kernel buffer
+        if( length > k_buf_space ) return -1;
+
+        // copy the string to kernel buffer
+        hal_copy_from_uspace( XPTR( local_cxy , k_buf_ptr ),
+                              k_pointers[index],
+                              length );
+
+#if DEBUG_PROCESS_EXEC_GET_STRINGS 
+if( DEBUG_PROCESS_EXEC_GET_STRINGS < cycle )
+printk("\n[%s] thread[%x,%x] copied string[%d] <%s> to kernel buffer / length %d\n",
+__FUNCTION__, this->process->pid, this->trdid, index, k_buf_ptr, length );
+#endif
+
+        // replace the user pointer by a kernel pointer in the k_pointer[] array
+        k_pointers[index] = k_buf_ptr;
+
+        // increment loop variables
+        k_buf_ptr   += length;
+        k_buf_space -= length;
+
+    }  // end loop on index
+
+    // update into exec_info structure
+    if( is_args )
+    {
+        exec_info->args_pointers  =  k_pointers;
+        exec_info->args_nr        =  index;
+    }
+    else
+    {
+        exec_info->envs_pointers  =  k_pointers;
+        exec_info->envs_buf_free  =  k_buf_ptr;
+        exec_info->envs_nr        =  index;
+    }
+
+#if DEBUG_PROCESS_EXEC_GET_STRINGS 
+if( DEBUG_PROCESS_EXEC_GET_STRINGS < cycle )
+printk("\n[%s] thread[%x,%x] copied %d strings to kernel buffer\n",
+__FUNCTION__, this->process->pid, this->trdid, index );
+#endif
+
+    return 0;
+
+} // end process_exec_get_strings()
+
+/////////////////////////////////
+error_t process_make_exec( void )
+{
+    thread_t       * this;                    // local pointer on this thread
     process_t      * process;                 // local pointer on this process
     pid_t            pid;                     // this process identifier
+    trdid_t          trdid;                   // this thread identifier
     xptr_t           ref_xp;                  // reference process for this process
 	error_t          error;                   // value returned by called functions
-    char           * path;                    // path to .elf file
+    char           * elf_path;                // path to .elf file
     xptr_t           file_xp;                 // extended pointer on .elf file descriptor
     uint32_t         file_id;                 // file index in fd_array
-    uint32_t         args_nr;                 // number of main thread arguments
-    char          ** args_pointers;           // array of pointers on main thread arguments
-
-    // get calling thread, process, pid and ref_xp 
-    thread  = CURRENT_THREAD;
-    process = thread->process;
+    vseg_t         * vseg;                    // local pointer on created vseg(s)
+    uint32_t         n;                       // index for loops
+
+    uint32_t         args_nr;                 // actual number of args (from exec_info)
+    intptr_t         args_base;               // args vseg base address in user space
+    uint32_t         args_size;               // args vseg size (bytes)
+
+    uint32_t         envs_nr;                 // actual number of envs (from exec_info)
+    intptr_t         envs_base;               // envs vseg base address in user space
+    uint32_t         envs_size;               // envs vseg size (bytes)
+
+    // get calling thread, process, pid, trdid, and ref_xp 
+    this    = CURRENT_THREAD;
+    process = this->process;
     pid     = process->pid;
+    trdid   = this->trdid;
     ref_xp  = process->ref_xp;
 
-	// get relevant infos from exec_info
-	path          = exec_info->path;
-    args_nr       = exec_info->args_nr;
-    args_pointers = exec_info->args_pointers;
+	// get .elf pathname from exec_info structure
+	elf_path      = process->exec_info.path;
 
 #if DEBUG_PROCESS_MAKE_EXEC
 uint32_t cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_MAKE_EXEC < cycle )
-printk("\n[%s] thread[%x,%x] enters for %s / cycle %d\n",
-__FUNCTION__, pid, thread->trdid, path, cycle );
-#endif
-
-    // open the file identified by <path>
+printk("\n[%s] thread[%x,%x] enters for <%s> / cycle %d\n",
+__FUNCTION__, pid, trdid, elf_path, cycle );
+#endif
+
+    // 1. open the file identified by <path>
     file_xp = XPTR_NULL;
     file_id = 0xFFFFFFFF;
 	error   = vfs_open( process->vfs_root_xp,
-	                    path,
+	                    elf_path,
                         ref_xp,
 	                    O_RDONLY,
@@ -1850,84 +2032,182 @@
 	if( error )
 	{
-		printk("\n[ERROR] in %s : failed to open file <%s>\n", __FUNCTION__ , path );
+		printk("\n[ERROR] in %s : thread[%x,%x] failed to open file <%s>\n",
+        __FUNCTION__, pid, trdid, elf_path );
 		return -1;
 	}
 
 #if (DEBUG_PROCESS_MAKE_EXEC & 1)
-cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_MAKE_EXEC < cycle )
-printk("\n[%s] thread[%x,%x] opened file <%s> / cycle %d\n",
-__FUNCTION__, pid, thread->trdid, path, cycle );
-#endif
-
-    // delete all threads other than this main thread in all clusters
+printk("\n[%s] thread[%x,%x] opened file <%s>\n",
+__FUNCTION__, pid, trdid, elf_path );
+#endif
+
+    // 2. delete all threads other than this main thread in all clusters
     process_sigaction( pid , DELETE_ALL_THREADS );
 
 #if (DEBUG_PROCESS_MAKE_EXEC & 1)
-cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_MAKE_EXEC < cycle )
-printk("\n[%s] thread[%x,%x] deleted existing threads / cycle %d\n",
-__FUNCTION__, pid, thread->trdid, cycle );
-#endif
-
-    // reset calling process VMM
+printk("\n[%s] thread[%x,%x] deleted existing threads\n",
+__FUNCTION__, pid, trdid );
+#endif
+
+    // 3. reset calling process VMM
     vmm_user_reset( process );
 
 #if( DEBUG_PROCESS_MAKE_EXEC & 1 )
-cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_MAKE_EXEC < cycle )
-printk("\n[%s] thread[%x,%x] completed VMM reset / cycle %d\n",
-__FUNCTION__, pid, thread->trdid, cycle );
-#endif
-
-    // re-initialize the VMM (args/envs vsegs registration)
-    error = vmm_user_init( process );
-    if( error )
-    {
-        printk("\n[ERROR] in %s : cannot initialise VMM for %s\n", __FUNCTION__ , path );
-        vfs_close( file_xp , file_id );
-        // FIXME restore old process VMM [AG]
-        return -1;
-    }
-    
+{
+    printk("\n[%s] thread[%x,%x] completed VMM reset\n",
+    __FUNCTION__, pid, trdid );
+    hal_vmm_display( ref_xp , true );
+}
+#endif
+
+    // 4. register the "args" vseg in VSL and map it in GPT, if required
+    // this vseg contains both the array of pointers and the strings
+    args_nr = process->exec_info.args_nr;
+
+    if( args_nr > 0 )
+    {
+        // get args vseg base and size in user space
+        args_base = CONFIG_VMM_UTILS_BASE << CONFIG_PPM_PAGE_SHIFT;
+        args_size = CONFIG_VMM_ARGS_SIZE << CONFIG_PPM_PAGE_SHIFT;
+
+        // create and register args vseg in VMM
+        vseg = vmm_create_vseg( process,
+                                VSEG_TYPE_DATA,
+                                args_base,
+                                args_size,
+                                0,                 // file_offset unused for DATA type
+                                0,                 // file_size unused for DATA type
+                                XPTR_NULL,         // mapper_xp unused for DATA type
+                                0 );               // cxy unused for DATA type
+        if( vseg == NULL )
+        {
+	         printk("\n[ERROR] in %s : thread[%x,%x] cannot get args vseg for <%s>\n",
+             __FUNCTION__, pid, trdid, elf_path );
+		     return -1;
+        }
+
 #if( DEBUG_PROCESS_MAKE_EXEC & 1 )
-cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_MAKE_EXEC < cycle )
-printk("\n[%s] thread[%x,%x] registered args/envs vsegs / cycle %d\n",
-__FUNCTION__, pid, thread->trdid, cycle );
-#endif
-
-    // register code & data vsegs as well as entry-point in process VMM,
-    // and register extended pointer on .elf file in process descriptor
+{
+    printk("\n[%s] thread[%x,%x] args vseg registered in new process VSL\n",
+    __FUNCTION__, pid, trdid );
+    hal_vmm_display( ref_xp , true );
+}
+#endif
+        // map all pages for this "args" vseg
+        uint32_t fake_attr;   // required for hal_gpt_lock_pte()
+        ppn_t    fake_ppn;    // required for hal_gpt_lock_pte()
+
+        xptr_t   gpt  = XPTR( local_cxy , &process->vmm.gpt );
+        uint32_t attr = GPT_MAPPED | GPT_SMALL | GPT_READABLE | GPT_USER | GPT_CACHABLE;
+        vpn_t    vpn  = CONFIG_VMM_UTILS_BASE;
+        ppn_t    ppn  = ((ppn_t)process->exec_info.args_pointers >> CONFIG_PPM_PAGE_SHIFT);
+
+        for( n = 0 ; n < CONFIG_VMM_ARGS_SIZE ; n++ )  
+        {
+            // lock the PTE
+            if (hal_gpt_lock_pte( gpt , vpn , &fake_attr , &fake_ppn ) )
+            {
+                printk("\n[ERROR] in %s : thread[%x,%x] cannot map args vpn %x for <%s>\n",
+                __FUNCTION__, pid, trdid, vpn, elf_path );
+		        return -1;
+            }
+
+            // map and unlock the PTE
+            hal_gpt_set_pte( gpt , vpn + n , attr , ppn + n );
+        }
+
+#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
+if( DEBUG_PROCESS_MAKE_EXEC < cycle )
+{
+    printk("\n[%s] thread[%x,%x] args vseg mapped in new process GPT\n",
+    __FUNCTION__, pid, trdid );
+    hal_vmm_display( ref_xp , true );
+}
+#endif
+
+        // set user space pointers in array of pointers
+        char  ** ptr    = process->exec_info.args_pointers;
+
+        for( n = 0 ; n < args_nr ; n++ )
+        {
+            ptr[n] = ptr[n] + args_base - (intptr_t)ptr;
+        } 
+    }
+
+    // 5. register the "envs" vseg in VSL and map it in GPT, if required
+    // this vseg contains both the array of pointers and the strings
+    envs_nr = process->exec_info.envs_nr;
+
+    if( envs_nr > 0 )
+    {
+        // get envs vseg base and size in user space from config
+        envs_base = (CONFIG_VMM_UTILS_BASE + CONFIG_VMM_ARGS_SIZE) << CONFIG_PPM_PAGE_SHIFT;
+        envs_size = CONFIG_VMM_ENVS_SIZE << CONFIG_PPM_PAGE_SHIFT;
+
+        // TODO (inspired from args)
+    }
+
+
+    // 6. register code & data vsegs, and entry-point in process VMM,
+    // register extended pointer on .elf file in process descriptor
 	error = elf_load_process( file_xp , process );
     if( error )
 	{
-		printk("\n[ERROR] in %s : failed to access <%s>\n", __FUNCTION__ , path );
-        vfs_close( file_xp , file_id );
-        // FIXME restore old process VMM [AG]
+		printk("\n[ERROR] in %s : thread[%x,%x] failed to access <%s>\n",
+        __FUNCTION__, pid, trdid, elf_path );
         return -1;
 	}
 
 #if( DEBUG_PROCESS_MAKE_EXEC & 1 )
-cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_PROCESS_MAKE_EXEC < cycle )
-printk("\n[%s] thread[%x,%x] registered code/data vsegs / cycle %d\n",
-__FUNCTION__, pid, thread->trdid, cycle );
-#endif
-
-    // update the existing main thread descriptor... and jump to user code 
-    error = thread_user_exec( (void *)process->vmm.entry_point,
-                              args_nr,
-                              args_pointers );
+{
+    printk("\n[%s] thread[%x,%x] registered code/data vsegs / entry %x\n",
+    __FUNCTION__, pid, trdid, process->vmm.entry_point );
+    hal_vmm_display( ref_xp , true );
+}
+#endif
+
+    // 7. allocate an user stack vseg for main thread
+    vseg = vmm_create_vseg( process,
+                            VSEG_TYPE_STACK,
+                            LTID_FROM_TRDID( trdid ),
+                            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 : thread[%x,%x] cannot set u_stack vseg for <%s>\n",
+        __FUNCTION__, pid, trdid, elf_path );
+		return -1;
+    }
+
+#if( DEBUG_PROCESS_MAKE_EXEC & 1 )
+if( DEBUG_PROCESS_MAKE_EXEC < cycle )
+{
+    printk("\n[%s] thread[%x,%x] registered stack vseg\n",
+    __FUNCTION__, pid, trdid );
+    hal_vmm_display( ref_xp , true );
+}
+#endif
+
+    // update user stack in thread descriptor
+    this->user_stack_vseg = vseg;
+
+    // 8. update the main thread descriptor ... and jumps (one way) to user code 
+    thread_user_exec( args_nr , args_base );
+
     if( error )
     {
-        printk("\n[ERROR] in %s : cannot update main thread for %s\n", __FUNCTION__ , path );
-        vfs_close( file_xp , file_id );
-        // FIXME restore old process VMM 
+        printk("\n[ERROR] in %s : thread[%x,%x] cannot update thread for <%s>\n",
+        __FUNCTION__ , pid, trdid, elf_path );
         return -1;
     }
 
-    assert( false, "we should not execute this code");
- 
 	return 0;
 
@@ -2153,10 +2433,9 @@
 #if(DEBUG_PROCESS_INIT_CREATE & 1)
 if( DEBUG_PROCESS_INIT_CREATE < cycle )
-printk("\n[%s] thread[%x,%x] registered code/data vsegs in VMM\n",
-__FUNCTION__, this->process->pid, this->trdid );
-#endif
-
-#if (DEBUG_PROCESS_INIT_CREATE & 1)
-hal_vmm_display( XPTR( local_cxy , process ) , true );
+{
+    printk("\n[%s] thread[%x,%x] registered code/data vsegs in VMM\n",
+    __FUNCTION__, this->process->pid, this->trdid );
+    hal_vmm_display( XPTR( local_cxy , process ) , true );
+}
 #endif
 
@@ -2291,5 +2570,5 @@
         txt_file_xp = hal_remote_l64( XPTR( owner_cxy , &owner_ptr->fd_array.array[0] ) );
 
-        assert( (txt_file_xp != XPTR_NULL) ,
+        assert( __FUNCTION__, (txt_file_xp != XPTR_NULL) ,
         "process must be attached to one TXT terminal" ); 
 
@@ -2363,5 +2642,5 @@
     }
 
-    assert( false , "no free TXT terminal found" );
+    assert( __FUNCTION__, false , "no free TXT terminal found" );
 
     return -1;
@@ -2370,6 +2649,6 @@
 
 /////////////////////////////////////////////
-void process_txt_attach( process_t * process,
-                         uint32_t    txt_id )
+void process_txt_attach( xptr_t   process_xp,
+                         uint32_t txt_id )
 {
     xptr_t      chdev_xp;     // extended pointer on TXT_RX chdev
@@ -2379,10 +2658,13 @@
     xptr_t      lock_xp;      // extended pointer on list lock in chdev
 
+    process_t * process_ptr = GET_PTR(process_xp );
+    cxy_t       process_cxy = GET_CXY(process_xp );
+
 // check process is in owner cluster
-assert( (CXY_FROM_PID( process->pid ) == local_cxy) ,
+assert( __FUNCTION__, (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ))),
 "process descriptor not in owner cluster" );
 
 // check terminal index
-assert( (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
+assert( __FUNCTION__, (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
 "illegal TXT terminal index" );
 
@@ -2399,6 +2681,6 @@
     remote_busylock_acquire( lock_xp );
 
-    // insert process in attached process list
-    xlist_add_last( root_xp , XPTR( local_cxy , &process->txt_list ) );
+    // insert owner process in list of attached processes to same TXT
+    xlist_add_last( root_xp , XPTR( process_cxy , &process_ptr->txt_list ) );
 
     // release lock protecting list of processes attached to TXT
@@ -2410,5 +2692,6 @@
 if( DEBUG_PROCESS_TXT < cycle )
 printk("\n[%s] thread[%x,%x] attached process %x to TXT %d / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, process->pid, txt_id , cycle );
+__FUNCTION__, this->process->pid, this->trdid,
+hal_remote_l32( XPTR( process_cxy , &process_ptr->pid, txt_id , cycle );
 #endif
 
@@ -2433,5 +2716,5 @@
 
 // check process descriptor in owner cluster
-assert( (CXY_FROM_PID( process_pid ) == process_cxy ) ,
+assert( __FUNCTION__, (CXY_FROM_PID( process_pid ) == process_cxy ) ,
 "process descriptor not in owner cluster" );
 
@@ -2471,9 +2754,42 @@
 
 ///////////////////////////////////////////////////
+uint32_t process_txt_get_index( xptr_t process_xp )
+{
+
+    // get target process cluster and local pointer
+    process_t * process_ptr = GET_PTR( process_xp );
+    cxy_t       process_cxy = GET_CXY( process_xp );
+
+assert( __FUNCTION__, (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp))),
+"process descriptor not in owner cluster" );
+
+    // get extended pointer on STDIN pseudo file in owner process descriptor
+    xptr_t file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[0]));
+
+assert( __FUNCTION__, (file_xp != XPTR_NULL),
+"STDIN pseudo-file undefined in fd_array for process %x\n",
+hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) ) );
+
+    // get extended pointer on TXT chdev
+    xptr_t chdev_xp = chdev_from_file( file_xp );
+ 
+assert( __FUNCTION__, (chdev_xp != XPTR_NULL),
+"chdev undefined for STDIN pseudo-file of process %x\n",
+hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) ) );
+
+    // get cluster and local pointer on chdev
+   cxy_t     chdev_cxy = GET_CXY( chdev_xp );
+   chdev_t * chdev_ptr = GET_PTR( chdev_xp );
+ 
+   // get parent TXT terminal index
+   return hal_remote_l32( XPTR( chdev_cxy , &chdev_ptr->channel ) );
+
+}  // end process_txt_get_index()
+
+///////////////////////////////////////////////////
 void process_txt_set_ownership( xptr_t process_xp )
 {
     process_t * process_ptr;
     cxy_t       process_cxy;
-    pid_t       process_pid;
     xptr_t      file_xp;
     xptr_t      txt_xp;     
@@ -2484,8 +2800,7 @@
     process_cxy = GET_CXY( process_xp );
     process_ptr = GET_PTR( process_xp );
-    process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
 
     // check owner cluster
-    assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
+    assert( __FUNCTION__, (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ))),
     "process descriptor not in owner cluster" );
 
@@ -2506,6 +2821,6 @@
 uint32_t txt_id = hal_remote_l32( XPTR( txt_cxy , &txt_ptr->channel ) );
 if( DEBUG_PROCESS_TXT < cycle )
-printk("\n[%s] thread[%x,%x] give TXT%d ownership to process %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, txt_id, process_pid, cycle );
+printk("\n[%s] thread[%x,%x] give TXT%d ownership to process / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, txt_id, cycle );
 #endif
 
@@ -2541,5 +2856,5 @@
 
 // check owner cluster
-assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
+assert( __FUNCTION__, (process_cxy == CXY_FROM_PID( process_pid )) ,
 "process descriptor not in owner cluster" );
 
@@ -2595,5 +2910,5 @@
 
 // It must exist a KSH process for each user TXT channel
-assert( (found == true), "KSH process not found for TXT%d", txt_id );
+assert( __FUNCTION__, (found == true), "KSH process not found for TXT%d", txt_id );
 
         }
@@ -2671,5 +2986,5 @@
 // check calling thread execute in target process owner cluster
 pid_t process_pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ) );
-assert( (process_cxy == CXY_FROM_PID( process_pid )) ,
+assert( __FUNCTION__, (process_cxy == CXY_FROM_PID( process_pid )) ,
 "process descriptor not in owner cluster" );
 
@@ -2715,5 +3030,5 @@
     xptr_t      txt0_lock_xp;
     
-    assert( (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
+    assert( __FUNCTION__, (txt_id < LOCAL_CLUSTER->nb_txt_channels) ,
     "illegal TXT terminal index" );
 
