Index: trunk/kernel/syscalls/sys_fork.c
===================================================================
--- trunk/kernel/syscalls/sys_fork.c	(revision 407)
+++ trunk/kernel/syscalls/sys_fork.c	(revision 408)
@@ -41,165 +41,108 @@
 int sys_fork()
 {
-	process_t          * parent_process;  // pointer on parent process descriptor
-    pid_t                parent_pid;      // parent process identifier
-    thread_t           * parent_thread;   // pointer on parent thread descriptor
-	process_t          * child_process;   // pointer on child process descriptor
-    pid_t                child_pid;       // child process identifier
-	thread_t           * child_thread;    // pointer on child main thread descriptor
-    cxy_t                target_cxy;      // target cluster for forked child process 
-	error_t              error;
+	process_t       * parent_process_ptr;   // pointer on local parent process descriptor
+    xptr_t            parent_thread_xp;     // extended pointer on parent thread descriptor
+    pid_t             parent_pid;           // parent process identifier
+    thread_t        * parent_thread_ptr;    // local pointer on local parent thread descriptor
 
-	uint64_t      tm_start;
-	uint64_t      tm_end;
+    pid_t             child_pid;            // child process identifier
+    thread_t        * child_thread_ptr;     // local pointer on remote child thread descriptor
+    cxy_t             target_cxy;           // target cluster for forked child process 
+ 
+    xptr_t            ref_process_xp;       // extended pointer on reference parent process
+    cxy_t             ref_process_cxy;      // cluster of reference parent process
+    process_t       * ref_process_ptr;      // local pointer on reference parent process
+
+	error_t           error;
+    
+	uint64_t          tm_start;
+	uint64_t          tm_end;
 
 	tm_start = hal_get_cycles();
 
-    // get pointers on parent process and thread
-	parent_thread  = CURRENT_THREAD;
-	parent_process = parent_thread->process;
-    parent_pid     = parent_process->pid;
+    // get pointers on local parent process and thread
+	parent_thread_ptr  = CURRENT_THREAD;
+    parent_thread_xp   = XPTR( local_cxy , parent_thread_ptr );
+	parent_process_ptr = parent_thread_ptr->process;
+    parent_pid         = parent_process_ptr->pid;
 
-fork_dmsg("\n[DBG] %s : core[%x,%d] enters for process %x / cycle %d\n",
-__FUNCTION__ , local_cxy , parent_thread->core->lid , parent_pid , (uint32_t)tm_start );
+fork_dmsg("\n[DBG] %s : core[%x,%d] parent process %x enters / cycle %d\n",
+__FUNCTION__, local_cxy, parent_thread_ptr->core->lid, parent_pid, (uint32_t)tm_start );
 
-    // check parent process children number
-	if( hal_atomic_add( &parent_process->children_nr , 1 ) >= CONFIG_PROCESS_MAX_CHILDREN )
+    // get infos on reference process
+    ref_process_xp  = parent_process_ptr->ref_xp;
+    ref_process_cxy = GET_CXY( ref_process_xp );
+    ref_process_ptr = (process_t *)GET_PTR( ref_process_xp );
+
+    // check parent process children number from reference
+    xptr_t   children_xp = XPTR( ref_process_cxy , &ref_process_ptr->children_nr );
+    if( hal_remote_atomic_add( children_xp , 1 ) >= CONFIG_PROCESS_MAX_CHILDREN )
 	{
 	    printk("\n[ERROR] in %s : too much children processes\n", __FUNCTION__);
-	    hal_atomic_add ( &parent_process->children_nr , -1 );
-        return EAGAIN;
+	    hal_remote_atomic_add ( children_xp , -1 );
+        parent_thread_ptr->errno = EAGAIN;
+        return -1;
 	}
 
-    // Select target cluster for future migration of child process and main thread.
+    // Select target cluster for child process and main thread.
     // If placement is not user-defined, the placement is defined by the DQDT. 
-    // The two first processes ("init" and "sh") on boot cluster do not migrate. 
-
-	if( parent_thread->fork_user )
+	if( parent_thread_ptr->fork_user )    // user defined placement
 	{
-        // user defined placement
-        target_cxy = parent_thread->fork_cxy;
-        parent_thread->fork_user = false;
+        target_cxy = parent_thread_ptr->fork_cxy;
+        parent_thread_ptr->fork_user = false;
 	}
-    else if( (LPID_FROM_PID(parent_process->pid) < 2)  && (local_cxy == 0) )
-    {
-        // 2 first process stay in boot cluster
-        target_cxy = local_cxy;
-    }
-	else
+	else                                  // DQDT placement
 	{
-        // DQDT placement
 		target_cxy = dqdt_get_cluster_for_process();
 	}
 
-//printk("\n[DBG] %s : core[%x,%d] for process %x selects target_cluster = %x\n",
-//__FUNCTION__ , local_cxy , parent_thread->core->lid , parent_pid , target_cxy );
-
-    // allocates memory in local cluster for the child process descriptor 
-	child_process = process_alloc(); 
-
-	if( child_process == NULL )
-	{
-	    printk("\n[ERROR] in %s : cannot allocate child process\n", __FUNCTION__ );
-	    hal_atomic_add ( &parent_process->children_nr , -1 );
-        return EAGAIN;
-	}
-
-    // get a new PID for child process,
-    if( target_cxy == local_cxy )                // target cluster is local
+    // call process_make_fork in target cluster
+    if( target_cxy == local_cxy )
     {
-        error = cluster_pid_alloc( XPTR( target_cxy , child_process ) , &child_pid );
+        error = process_make_fork( ref_process_xp,
+                                   parent_thread_xp,
+                                   &child_pid,
+                                   &child_thread_ptr );
     }
-    else                                         // target cluster is remote
+    else
     {
-        rpc_process_pid_alloc_client( target_cxy , child_process , &error , &child_pid );
+        rpc_process_make_fork_client( target_cxy,
+                                      ref_process_xp,
+                                      parent_thread_xp,
+                                      &child_pid,
+                                      &child_thread_ptr,
+                                      &error );
     }
 
     if( error )
     {
-	    printk("\n[ERROR] in %s : cannot allocate PID\n", __FUNCTION__ );
-	    hal_atomic_add ( &parent_process->children_nr , -1 );
-        process_destroy( child_process );
-        return EAGAIN;
+        printk("\n[ERROR] in %s : cannot fork process %x in cluster %x\n",
+        __FUNCTION__, parent_pid, local_cxy );
+        parent_thread_ptr->errno = EAGAIN;
+        return -1;
     }
 
-    // initialize and register the child process descriptor
-    process_reference_init( child_process , child_pid , XPTR(local_cxy, parent_process) );
-
-    // initialises child process standard files structures
-    // ( root / cwd / bin ) from parent process descriptor
-
-	vfs_file_count_up( parent_process->vfs_root_xp );
-	child_process->vfs_root_xp = parent_process->vfs_root_xp;
-
-	vfs_file_count_up( parent_process->vfs_cwd_xp );
-	child_process->vfs_cwd_xp  = parent_process->vfs_cwd_xp;
-
-	vfs_file_count_up( parent_process->vfs_bin_xp );
-    child_process->vfs_bin_xp = parent_process->vfs_bin_xp;
-
-    // copy the parent process fd_array to the child process fd_array
-	process_fd_remote_copy( XPTR( local_cxy , &child_process->fd_array ),
-                            XPTR( local_cxy , &parent_process->fd_array ) );
-
-//printk("\n[DBG] %s : core[%x,%d] for process %x created child process %x\n",
-//__FUNCTION__ , local_cxy , parent_thread->core->lid , parent_pid , child_pid );
-
-    // replicate VMM
-	error = vmm_copy( child_process , parent_process );
-
-	if( error )
-    {
-	    printk("\n[ERROR] in %s : cannot duplicate VMM\n", __FUNCTION__ );
-	    hal_atomic_add ( &parent_process->children_nr , -1 );
-        process_destroy( child_process );
-        return ENOMEM;
-    }
-  
-//printk("\n[DBG] %s : core[%x,%d] for process %x duplicated vmm in child process\n",
-//__FUNCTION__ , local_cxy , parent_thread->core->lid , parent_pid );
-//vmm_display( parent_process , true );
-//vmm_display( child_process , true );
-
-    // create child main thread in local cluster 
-    error = thread_user_fork( child_process,
-                              parent_thread->u_stack_size,
-                              parent_thread->u_stack_base,
-                              &child_thread );
-	if( error )
-    {
-	    printk("\n[ERROR] in %s : cannot duplicate main thread\n", __FUNCTION__ );
-	    hal_atomic_add( &parent_process->children_nr , -1 );
-        process_destroy( child_process );
-        return ENOMEM;
-    }
-
-//printk("\n[DBG] %s : core[%x,%d] initialised child main thread\n",
-//__FUNCTION__ , local_cxy , parent_thread->core->lid );
-
-	// update DQDT for the child thread 
-    dqdt_local_update_threads( 1 );
-
-    // set child_thread FPU_context from parent_thread register values
-    // only when the parent process is the FPU owner
-	if( CURRENT_THREAD->core->fpu_owner == parent_thread )
+    // set remote child FPU_context from parent_thread register values
+    // only when the parent thread is the FPU owner
+	if( CURRENT_THREAD->core->fpu_owner == parent_thread_ptr )
 	{
-		hal_fpu_context_save( child_thread->fpu_context );
+		hal_fpu_context_save( XPTR( target_cxy , child_thread_ptr ) );
 	}
 
-    // set child_thread CPU context from parent_thread register values
-    hal_do_cpu_save( child_thread->cpu_context,
-                     child_thread,
-                     (int)((intptr_t)child_thread - (intptr_t)parent_thread) );
+    // set remote child CPU context from  parent_thread register values
+    hal_cpu_context_fork( XPTR( target_cxy , child_thread_ptr ) );
 
-
-    // from this point, both parent and child threads execute the following code
-    // but child execute it only when it has been unblocked by its parent
+    // From this point, both parent and child threads execute the following code.
+    // They can be distinguished by the CURRENT_THREAD value, and child will only 
+    // execute it when it is unblocked by parent.
+    // - parent unblock child, and return child PID to user application.
+    // - child thread does nothing, and return 0 to user pplication 
 
     thread_t * current = CURRENT_THREAD;
 
-    if( current == parent_thread )
+    if( current == parent_thread_ptr )    // current == parent thread
     {
         // parent_thread unblock child_thread
-        thread_unblock( XPTR( local_cxy , child_thread ) , THREAD_BLOCKED_GLOBAL );
+        thread_unblock( XPTR( target_cxy , child_thread_ptr ) , THREAD_BLOCKED_GLOBAL );
 
         tm_end = hal_get_cycles();
@@ -207,16 +150,16 @@
 fork_dmsg("\n[DBG] %s : core[%x,%d] parent_process %x exit / cycle %d\n"
 "     child_process %x / child_thread = %x / cost = %d\n",
-__FUNCTION__, local_cxy, parent_thread->core->lid,  parent_pid, (uint32_t)tm_start,
-child_pid, child_thread->trdid , (uint32_t)(tm_end - tm_start) );
+__FUNCTION__, local_cxy, parent_thread_ptr->core->lid,  parent_pid, (uint32_t)tm_end,
+child_pid, child_thread_ptr->trdid , (uint32_t)(tm_end - tm_start) );
 
         return child_pid;
     }
-	else  // current == child_thread
+	else                                   // current == child_thread
     {
-        assert( (current == child_thread) , __FUNCTION__ , 
-        "current thread %x is not the child thread %x\n", current , child_thread );
+
+        tm_end = hal_get_cycles();
 
 fork_dmsg("\n[DBG] %s : core[%x,%d] child process %x exit / cycle %d\n",
-__FUNCTION__, local_cxy, parent_thread->core->lid, child_pid, (uint32_t)hal_get_cycles() );
+__FUNCTION__, local_cxy, parent_thread_ptr->core->lid, child_pid, (uint32_t)tm_end );
 
         return 0;
