Index: trunk/kernel/kern/process.c
===================================================================
--- trunk/kernel/kern/process.c	(revision 651)
+++ trunk/kernel/kern/process.c	(revision 657)
@@ -4,5 +4,5 @@
  * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
  *          Mohamed Lamine Karaoui (2015)
- *          Alain Greiner (2016,2017,2018,2019)
+ *          Alain Greiner (2016,2017,2018,2019,2020)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -1103,9 +1103,9 @@
     xptr_t    xp;
 
-    // get reference process cluster and local pointer
+    // get target process cluster and local pointer
     process_t * process_ptr = GET_PTR( process_xp );
     cxy_t       process_cxy = GET_CXY( process_xp );
 
-// check client process is reference process
+// check target process is reference process
 assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->ref_xp ) ) ),
 "client process must be reference process\n" );
@@ -1158,4 +1158,85 @@
 
 }  // end process_fd_register()
+
+/////////////////////////////////////////////
+void process_fd_remove( xptr_t    process_xp,
+                        uint32_t  fdid )
+{
+    pid_t       pid;           // target process PID 
+    lpid_t      lpid;          // target process LPID
+    xptr_t      iter_xp;       // iterator for list of process copies
+    xptr_t      copy_xp;       // extended pointer on process copy
+    process_t * copy_ptr;      // local pointer on process copy  
+    cxy_t       copy_cxy;      // process copy cluster identifier
+
+// check process_xp argument
+assert( (process_xp != XPTR_NULL), "process_xp argument cannot be XPTR_NULL");
+
+    // get target process cluster and local pointer
+    process_t * process_ptr = GET_PTR( process_xp );
+    cxy_t       process_cxy = GET_CXY( process_xp );
+
+    // get target process pid and lpid
+    pid  = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid) );
+    lpid = LPID_FROM_PID( pid );
+
+    // get process descriptor in owner cluster and in reference cluster
+    xptr_t  owner_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ));
+    xptr_t  ref_xp   = hal_remote_l64( XPTR( process_cxy , &process_ptr->ref_xp   ));
+
+// check target process in in owner cluster 
+assert( (process_xp == owner_xp), "target process must be in owner process\n" );
+
+#if DEBUG_PROCESS_FD_REMOVE
+uint32_t    cycle = (uint32_t)hal_get_cycles();
+thread_t  * this  = CURRENT_THREAD;
+if( DEBUG_PROCESS_FD_REMOVE < cycle )
+printk("\n[%s] thread[%x,%x] enter for fdid %d in process %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, fdid, pid, cycle );
+#endif
+
+    // build extended pointers on list_of_copies root and lock (in owner cluster)
+    xptr_t copies_root_xp = XPTR( process_cxy , &LOCAL_CLUSTER->pmgr.copies_root[lpid] );
+    xptr_t copies_lock_xp = XPTR( process_cxy , &LOCAL_CLUSTER->pmgr.copies_lock[lpid] );
+ 
+    // get reference process cluster and local pointer
+    process_t * ref_ptr = GET_PTR( ref_xp );
+    cxy_t       ref_cxy = GET_CXY( ref_xp );
+
+    // build extended pointer on lock protecting reference fd_array
+    xptr_t fd_lock_xp = XPTR( ref_cxy , &ref_ptr->fd_array.lock );
+
+    // take lock protecting reference fd_array
+	remote_queuelock_acquire( fd_lock_xp );
+
+    // take the lock protecting the list of copies
+    remote_queuelock_acquire( copies_lock_xp );
+
+    // loop on list of process copies
+    XLIST_FOREACH( copies_root_xp , iter_xp )
+    {
+        // get pointers on process copy
+        copy_xp  = XLIST_ELEMENT( iter_xp , process_t , copies_list );
+        copy_ptr = GET_PTR( copy_xp );
+        copy_cxy = GET_CXY( copy_xp );
+
+        // release the fd_array entry in process copy
+        hal_remote_s64( XPTR( copy_cxy , &copy_ptr->fd_array.array[fdid] ), XPTR_NULL );
+    }
+
+    // release the lock protecting reference fd_array
+	remote_queuelock_release( fd_lock_xp );
+
+    // release the lock protecting the list of copies
+    remote_queuelock_release( copies_lock_xp );
+
+#if DEBUG_PROCESS_FD_REMOVE
+cycle = (uint32_t)hal_get_cycles();
+if( DEBUG_PROCESS_FD_REMOVE < cycle )
+printk("\n[%s] thread[%x,%x] exit for fdid %d in process %x / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, fdid, pid, cycle );
+#endif
+
+}  // end process_fd_remove()
 
 ////////////////////////////////////////////////
