Index: trunk/kernel/kern/rpc.c
===================================================================
--- trunk/kernel/kern/rpc.c	(revision 407)
+++ trunk/kernel/kern/rpc.c	(revision 408)
@@ -49,6 +49,6 @@
 {
     &rpc_pmem_get_pages_server,         // 0
-    &rpc_process_pid_alloc_server,      // 1
-    &rpc_process_exec_server,           // 2
+    &rpc_process_make_exec_server,      // 1
+    &rpc_process_make_fork_server,      // 2
     &rpc_process_kill_server,           // 3
     &rpc_thread_user_create_server,     // 4
@@ -78,5 +78,5 @@
     &rpc_vmm_create_vseg_server,        // 26
     &rpc_sched_display_server,          // 27
-    &rpc_undefined,                     // 28
+    &rpc_vmm_set_cow_server,            // 28
     &rpc_undefined,                     // 29
 };
@@ -148,89 +148,21 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
-// [1]           Marshaling functions attached to RPC_PROCESS_PID_ALLOC
-/////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////
-void rpc_process_pid_alloc_client( cxy_t       cxy, 
-                                   process_t * process,  // in
-                                   error_t   * error,    // out
-                                   pid_t     * pid )     // out
-{
-    rpc_dmsg("\n[DBG] %s : enter / thread %x on core[%x,%d] / cycle %d\n",
-    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
-    CURRENT_THREAD->core->lid , hal_time_stamp() );
-
-    assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n");
-
-    // initialise RPC descriptor header 
-    rpc_desc_t  rpc;
-    rpc.index    = RPC_PROCESS_PID_ALLOC;
-    rpc.response = 1;
-
-    // set input arguments in RPC descriptor 
-    rpc.args[0] = (uint64_t)(intptr_t)process;
-
-    // register RPC request in remote RPC fifo (blocking function)
-    rpc_send_sync( cxy , &rpc );
-
-    // get output arguments RPC descriptor
-    *pid    = (pid_t)rpc.args[1];
-    *error  = (error_t)rpc.args[2];     
-
-    rpc_dmsg("\n[DBG] %s : exit / thread %x on core[%x,%d] / cycle %d\n",
-    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
-    CURRENT_THREAD->core->lid , hal_time_stamp() );
-}
-
-//////////////////////////////////////////////
-void rpc_process_pid_alloc_server( xptr_t xp )
-{
-    process_t * process;   // input  : client process descriptor
-    error_t     error;     // output : error status
-    pid_t       pid;       // output : process identifier
-
-    rpc_dmsg("\n[DBG] %s : enter / thread %x on core[%x,%d] / cycle %d\n",
-    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
-    CURRENT_THREAD->core->lid , hal_time_stamp() );
-
-    // get client cluster identifier and pointer on RPC descriptor
-    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
-    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
-
-    // get input argument from client RPC descriptor
-    process = (process_t*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
-    
-    // call local pid allocator 
-    xptr_t xp_process = XPTR( client_cxy , process );
-    error = cluster_pid_alloc( xp_process , &pid ); 
-
-    // set output arguments into client RPC descriptor
-    hal_remote_sw( XPTR( client_cxy , &desc->args[0] ) , (uint64_t)error );
-    hal_remote_sw( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)pid );
-
-    rpc_dmsg("\n[DBG] %s : exit / thread %x on core[%x,%d] / cycle %d\n",
-    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
-    CURRENT_THREAD->core->lid , hal_time_stamp() );
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// [2]           Marshaling functions attached to RPC_PROCESS_EXEC 
-/////////////////////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////
-void rpc_process_exec_client( cxy_t         cxy,
-                              exec_info_t * info,     // in
-                              error_t     * error )   // out
-{
-    rpc_dmsg("\n[DBG] %s : enter / thread %x on core[%x,%d] / cycle %d\n",
-    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
-    CURRENT_THREAD->core->lid , hal_time_stamp() );
-
-    assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n");
-
-    // initialise RPC descriptor header 
-    rpc_desc_t  rpc;
-    rpc.index    = RPC_PROCESS_EXEC;
+// [1]           Marshaling functions attached to RPC_PROCESS_MAKE_EXEC
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////
+void rpc_process_make_exec_client( cxy_t         cxy,
+                                   exec_info_t * info,     // in
+                                   error_t     * error )   // out
+{
+    rpc_dmsg("\n[DBG] %s : enter / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+
+    assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n");
+
+    // initialise RPC descriptor header 
+    rpc_desc_t  rpc;
+    rpc.index    = RPC_PROCESS_MAKE_EXEC;
     rpc.response = 1;
 
@@ -249,6 +181,6 @@
 }
 
-/////////////////////////////////////////
-void rpc_process_exec_server( xptr_t xp )
+//////////////////////////////////////////////
+void rpc_process_make_exec_server( xptr_t xp )
 {
     exec_info_t * ptr;       // local pointer on remote exec_info structure
@@ -283,4 +215,80 @@
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+// [2]           Marshaling functions attached to RPC_PROCESS_MAKE_FORK 
+/////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////
+void rpc_process_make_fork_client( cxy_t       cxy,
+                                   xptr_t      ref_process_xp,      // in
+                                   xptr_t      parent_thread_xp,    // in
+                                   pid_t     * child_pid,           // out
+                                   thread_t ** child_thread_ptr,    // out     
+                                   error_t   * error )              // out
+{
+    rpc_dmsg("\n[DBG] %s : enter / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+
+    assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n");
+
+    // initialise RPC descriptor header 
+    rpc_desc_t  rpc;
+    rpc.index    = RPC_PROCESS_MAKE_FORK;
+    rpc.response = 1;
+
+    // set input arguments in RPC descriptor  
+    rpc.args[0] = (uint64_t)(intptr_t)ref_process_xp;
+    rpc.args[1] = (uint64_t)(intptr_t)parent_thread_xp;
+
+    // register RPC request in remote RPC fifo (blocking function)
+    rpc_send_sync( cxy , &rpc );
+
+    // get output arguments from RPC descriptor
+    *child_pid         = (pid_t)rpc.args[2];
+    *child_thread_ptr  = (thread_t *)(intptr_t)rpc.args[3];
+    *error             = (error_t)rpc.args[4];     
+
+    rpc_dmsg("\n[DBG] %s : exit / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+}
+
+//////////////////////////////////////////////
+void rpc_process_make_fork_server( xptr_t xp )
+{
+    xptr_t     ref_process_xp;     // extended pointer on reference parent process
+    xptr_t     parent_thread_xp;   // extended pointer on parent thread
+    pid_t      child_pid;          // child process identifier
+    thread_t * child_thread_ptr;   // local copy of exec_info structure
+    error_t    error;              // local error status
+
+    rpc_dmsg("\n[DBG] %s : enter / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+
+    // get client cluster identifier and pointer on RPC descriptor
+    cxy_t        client_cxy  = (cxy_t)GET_CXY( xp );
+    rpc_desc_t * desc        = (rpc_desc_t *)GET_PTR( xp );
+
+    // get input arguments from cient RPC descriptor
+    ref_process_xp   = (xptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) );
+    parent_thread_xp = (xptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) );
+
+    // call local kernel function
+    error = process_make_fork( ref_process_xp,
+                               parent_thread_xp,
+                               &child_pid,
+                               &child_thread_ptr ); 
+
+    // set output argument into client RPC descriptor
+    hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)child_pid );
+    hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)(intptr_t)child_thread_ptr );
+    hal_remote_swd( XPTR( client_cxy , &desc->args[4] ) , (uint64_t)error );
+
+    rpc_dmsg("\n[DBG] %s : exit / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+}
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -1800,4 +1808,58 @@
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+// [28]          Marshaling functions attached to RPC_VMM_SET_COW
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////
+void rpc_vmm_set_cow_client( cxy_t       cxy,
+                             process_t * process )
+{
+    rpc_dmsg("\n[DBG] %s : enter / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+
+    assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n");
+
+    // initialise RPC descriptor header 
+    rpc_desc_t  rpc;
+    rpc.index    = RPC_VMM_SET_COW;
+    rpc.response = 1;
+
+    // set input arguments in RPC descriptor 
+    rpc.args[0] = (uint64_t)(intptr_t)process;
+
+    // register RPC request in remote RPC fifo (blocking function)
+    rpc_send_sync( cxy , &rpc );
+
+    rpc_dmsg("\n[DBG] %s : exit / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+}
+
+////////////////////////////////////////
+void rpc_vmm_set_cow_server( xptr_t xp )
+{
+    rpc_dmsg("\n[DBG] %s : enter / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+
+    process_t * process;
+
+    // get client cluster identifier and pointer on RPC descriptor
+    cxy_t        cxy  = (cxy_t)GET_CXY( xp );
+    rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp );
+
+    // get input arguments from client RPC descriptor
+    process = (process_t *)(intptr_t)hal_remote_lpt( XPTR(cxy , &desc->args[0]));
+    
+    // call local kernel function
+    vmm_set_cow( process );
+
+    rpc_dmsg("\n[DBG] %s : exit / thread %x on core[%x,%d] / cycle %d\n",
+    __FUNCTION__ , CURRENT_THREAD->trdid , local_cxy, 
+    CURRENT_THREAD->core->lid , hal_time_stamp() );
+}
+
 /***************************************************************************************/
 /************ Generic functions supporting RPCs : client side **************************/
@@ -1835,5 +1897,5 @@
             __FUNCTION__ , local_cxy , server_cxy );
 
-            if( thread_can_yield() ) sched_yield();
+            if( thread_can_yield() ) sched_yield("RPC fifo full");
         }
     }
@@ -1872,5 +1934,5 @@
 
         thread_block( this , THREAD_BLOCKED_RPC );
-        sched_yield();
+        sched_yield("client blocked on RPC");
 
 grpc_dmsg("\n[DBG] %s : core[%x,%d] / thread %s resumes after RPC completion\n",
@@ -1959,5 +2021,5 @@
 
     // interrupted thread deschedule always           
-	sched_yield();
+	sched_yield("IPI received");
 
 grpc_dmsg("\n[DBG] %s : core[%x,%d] / interrupted thread %s resume / cycle %d\n", 
@@ -2079,5 +2141,5 @@
 
         // deschedule without blocking
-        sched_yield();
+        sched_yield("RPC fifo empty or too much work");
 
 grpc_dmsg("\n[DBG] %s : core[%x,%d] (RPC thread %x) resumes / cycle %d\n", 
@@ -2089,198 +2151,2 @@
 
 
-
-
-
-
-
-
-
-/* deprecated [AG] 29/09/2017
-
-////////////////////////////////////////////////////
-error_t rpc_activate_thread( remote_fifo_t * rpc_fifo )
-{
-	core_t      * core;
-	thread_t    * thread;
-	thread_t    * this;
-    scheduler_t * sched;
-	error_t       error;
-    bool_t        found;
-    reg_t         sr_save;
-
-    
-	this   = CURRENT_THREAD;
-    core   = this->core;
-    sched  = &core->scheduler;
-    found  = false;
-
-    assert( (this->trdid == rpc_fifo->owner) , __FUNCTION__ ,
-    "calling thread is not RPC_FIFO owner\n" );
-
-    // makes the calling thread not preemptable
-    // during activation / creation of the RPC thread
-	hal_disable_irq( &sr_save );
-
-grpc_dmsg("\n[DBG] %s : core[%x,%d] enter at cycle %d\n",
-__FUNCTION__ , local_cxy , core->lid , hal_time_stamp() );
-
-    // search one non blocked RPC thread   
-    list_entry_t * iter;
-    LIST_FOREACH( &sched->k_root , iter )
-    {
-        thread = LIST_ELEMENT( iter , thread_t , sched_list );
-        if( (thread->type == THREAD_RPC) && (thread->blocked == 0 ) ) 
-        {
-            found = true;
-            break;
-        }
-    }
-
-    if( found == false )                    // create new RPC thread      
-    {
-        error = thread_kernel_create( &thread,
-                                      THREAD_RPC, 
-			                          &rpc_thread_func, 
-                                      NULL,
-			                          core->lid );
-	    if( error ) 
-        {
-	        hal_restore_irq( sr_save );
-            printk("\n[ERROR] in %s : no memory for new RPC thread in cluster %x\n",
-                   __FUNCTION__ , local_cxy );
-            return ENOMEM;
-        }
-
-        // unblock thread
-        thread->blocked = 0;
-
-        // update core descriptor counter  
-	    hal_atomic_add( &LOCAL_CLUSTER->rpc_threads , 1 );
-
-grpc_dmsg("\n[DBG] %s : core [%x,%d] creates RPC thread %x at cycle %d\n", 
-__FUNCTION__ , local_cxy , core->lid , thread->trdid , hal_time_stamp() );
-
-    }
-    else                           // create a new RPC thread
-    {
-
-grpc_dmsg("\n[DBG] %s : core[%x,%d] activates RPC thread %x at cycle %d\n", 
-__FUNCTION__ , local_cxy , core->lid , thread->trdid , hal_time_stamp() );
-
-    }
-
-    // update rpc_fifo owner
-    rpc_fifo->owner = thread->trdid;
-
-    // current thread deschedule            
-	sched_yield();
-
-    // restore IRQs for the calling thread 
-	hal_restore_irq( sr_save );
-
-    // return success
-	return 0;
-
-}  // end rpc_activate_thread()
-
-////////////////
-void rpc_check()
-{
-	thread_t   * this     = CURRENT_THREAD;
-	remote_fifo_t * rpc_fifo = &LOCAL_CLUSTER->rpc_fifo;
-    error_t      error;
-
-grpc_dmsg("\n[DBG] %s : core[%x,%d] / thread %x / enter at cycle %d\n",
-__FUNCTION__ , local_cxy , this->core->lid , this->trdid , hal_time_stamp() );
-
-    // calling thread does nothing if light lock already taken or FIFO empty  
-	if( (rpc_fifo->owner != 0) || (local_fifo_is_empty( &rpc_fifo->fifo )) )
-    {
-
-grpc_dmsg("\n[DBG] %s : core[%x,%d] / thread %x / exit do nothing at cycle %d\n",
-__FUNCTION__ , local_cxy , this->core->lid , this->trdid , hal_time_stamp() );
-
-        return;
-    }
-
-	// try to take the light lock, and activates an RPC thread if success
-    if( hal_atomic_test_set( &rpc_fifo->owner , this->trdid ) )
-	{
-        error = rpc_activate_thread( rpc_fifo );
-
-        if( error )    // cannot activate an RPC_THREAD 
-        {
-            rpc_fifo->owner = 0;
-
-            printk("\n[ERROR] in %s : no memory to create a RPC thread for core %d"
-            " in cluster %x => do nothing\n",
-            __FUNCTION__ , CURRENT_CORE->lid , local_cxy );
-        }
-
-        return;
-    }
-    else  // light lock taken by another thread
-    {
-
-grpc_dmsg("\n[DBG] %s : core[%x,%d] / thread %x / exit do nothing at cycle %d\n",
-__FUNCTION__ , local_cxy , this->core->lid , this->trdid , hal_time_stamp() );
-
-        return;
-    }
-} // end rpc_check()
-
-
-//////////////////////
-void rpc_thread_func()
-{
-    // makes the RPC thread not preemptable
-	hal_disable_irq( NULL );
-  
-	thread_t   * this     = CURRENT_THREAD;
-	remote_fifo_t * rpc_fifo = &LOCAL_CLUSTER->rpc_fifo;
-
-	while(1)
-	{
-        // check fifo ownership (ownership should be given by rpc_activate()
-        assert( (this->trdid == rpc_fifo->owner) , __FUNCTION__ ,
-        "thread %x on core[%x,%d] not owner of RPC_FIFO / owner = %x\n",
-        this->trdid, local_cxy, this->core->lid , rpc_fifo->owner );
- 
-        // executes pending RPC(s) 
-        rpc_execute_all( rpc_fifo );
-
-        // release rpc_fifo ownership if required
-        // (this ownership can be lost during RPC execution)
-        if( rpc_fifo->owner == this->trdid ) rpc_fifo->owner = 0;
-
-        //  deschedule or sucide
-		if( LOCAL_CLUSTER->rpc_threads >= CONFIG_RPC_THREADS_MAX )  // suicide
-		{
-
-grpc_dmsg("\n[DBG] %s : core[%x,%d] / thread %x / suicide at cycle %d\n", 
-__FUNCTION__, local_cxy, this->core->lid, this->trdid, hal_time_stamp() );
-
-            // update core descriptor counter
-	        hal_atomic_add( &LOCAL_CLUSTER->rpc_threads , -1 );
-
-            // suicide
-			thread_exit();
-		}
-        else                                                       // deschedule
-        {
-
-grpc_dmsg("\n[DBG] %s : core[%x,%d] / thread %x / deschedule at cycle %d\n", 
-__FUNCTION__, local_cxy, this->core->lid, this->trdid, hal_time_stamp() );
-
-            sched_yield();
-
-grpc_dmsg("\n[DBG] %s : core[%x,%d] / thread %x / wake up at cycle %d\n", 
-__FUNCTION__, local_cxy, this->core->lid, this->trdid, hal_time_stamp() );
-
-        }
-	} // end while
-} // end rpc_thread_func()
-
-*/
-
-
