Index: trunk/kernel/mm/vmm.c
===================================================================
--- trunk/kernel/mm/vmm.c	(revision 625)
+++ trunk/kernel/mm/vmm.c	(revision 629)
@@ -741,6 +741,5 @@
     child_vmm  = &child_process->vmm;
 
-    // initialize the locks protecting the child VSL and GPT
-    remote_rwlock_init( XPTR( local_cxy , &child_vmm->gpt_lock ) , LOCK_VMM_GPT );
+    // initialize the lock protecting the child VSL 
 	remote_rwlock_init( XPTR( local_cxy , &child_vmm->vsl_lock ) , LOCK_VMM_VSL );
 
@@ -952,5 +951,4 @@
     xptr_t   vsl_root_xp = XPTR( local_cxy , &vmm->vsegs_root );
     xptr_t   vsl_lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
-    xptr_t   gpt_lock_xp = XPTR( local_cxy , &vmm->gpt_lock );
 
     // take the VSL lock
@@ -1022,12 +1020,6 @@
     }
 
-    // take the GPT lock
-    remote_rwlock_wr_acquire( gpt_lock_xp );
-
     // release memory allocated to the GPT itself
     hal_gpt_destroy( &vmm->gpt );
-
-    // release the GPT lock
-    remote_rwlock_wr_release( gpt_lock_xp );
 
 #if DEBUG_VMM_DESTROY
@@ -1226,4 +1218,5 @@
 {
     vmm_t     * vmm;        // local pointer on process VMM
+    xptr_t      gpt_xp;     // extended pointer on GPT
     bool_t      is_ref;     // local process is reference process
     uint32_t    vseg_type;  // vseg type
@@ -1250,4 +1243,7 @@
     vmm = &process->vmm;
 
+    // build extended pointer on GPT
+    gpt_xp = XPTR( local_cxy , &vmm->gpt );
+
     // get relevant vseg infos
     vseg_type = vseg->type;
@@ -1268,5 +1264,5 @@
     {
         // get ppn and attr
-        hal_gpt_get_pte( XPTR( local_cxy , &vmm->gpt ) , vpn , &attr , &ppn );
+        hal_gpt_get_pte( gpt_xp , vpn , &attr , &ppn );
 
         if( attr & GPT_MAPPED )  // PTE is mapped
@@ -1278,5 +1274,5 @@
 #endif
             // unmap GPT entry in local GPT
-            hal_gpt_reset_pte( &vmm->gpt , vpn );
+            hal_gpt_reset_pte( gpt_xp , vpn );
 
             // get pointers on physical page descriptor
@@ -1915,6 +1911,6 @@
 {
     vseg_t         * vseg;            // vseg containing vpn
-    uint32_t         new_attr;        // new PTE_ATTR value
-    ppn_t            new_ppn;         // new PTE_PPN value
+    uint32_t         attr;            // PTE_ATTR value
+    ppn_t            ppn;             // PTE_PPN value
     uint32_t         ref_attr;        // PTE_ATTR value in reference GPT
     ppn_t            ref_ppn;         // PTE_PPN value in reference GPT
@@ -1922,16 +1918,21 @@
     process_t      * ref_ptr;         // reference process for missing vpn
     xptr_t           local_gpt_xp;    // extended pointer on local GPT
-    xptr_t           local_lock_xp;   // extended pointer on local GPT lock
     xptr_t           ref_gpt_xp;      // extended pointer on reference GPT
-    xptr_t           ref_lock_xp;     // extended pointer on reference GPT lock
     error_t          error;           // value returned by called functions
 
+    thread_t * this  = CURRENT_THREAD;
+
+#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
+uint32_t start_cycle = (uint32_t)hal_get_cycles();
+#endif
+
 #if DEBUG_VMM_HANDLE_PAGE_FAULT
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-thread_t * this  = CURRENT_THREAD;
-if( DEBUG_VMM_HANDLE_PAGE_FAULT < cycle )
+if( DEBUG_VMM_HANDLE_PAGE_FAULT < start_cycle )
 printk("\n[%s] thread[%x,%x] enter for vpn %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn, cycle );
-hal_vmm_display( process , true );
+__FUNCTION__, this->process->pid, this->trdid, vpn, start_cycle );
+#endif
+
+#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
+hal_vmm_display( this->process , false );
 #endif
 
@@ -1942,6 +1943,6 @@
     if( error )
     {
-        printk("\n[ERROR] in %s : vpn %x in process %x not in registered vseg / cycle %d\n",
-        __FUNCTION__ , vpn , process->pid, (uint32_t)hal_get_cycles() );
+        printk("\n[ERROR] in %s : vpn %x in thread[%x,%x] not in registered vseg\n",
+        __FUNCTION__ , vpn , process->pid, this->trdid );
         
         return EXCP_USER_ERROR;
@@ -1949,83 +1950,27 @@
 
 #if DEBUG_VMM_HANDLE_PAGE_FAULT
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_HANDLE_PAGE_FAULT < cycle )
-printk("\n[%s] threadr[%x,%x] found vseg %s / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(vseg->type), cycle );
-#endif
-
-    //////////////// private vseg => access only the local GPT 
-    if( (vseg->type == VSEG_TYPE_STACK) || (vseg->type == VSEG_TYPE_CODE) )
-    {
-        // build extended pointer on local GPT and local GPT lock
-        local_gpt_xp  = XPTR( local_cxy , &process->vmm.gpt );
-        local_lock_xp = XPTR( local_cxy , &process->vmm.gpt_lock );
-
-        // take local GPT lock in write mode
-        remote_rwlock_wr_acquire( local_lock_xp );
-
-        // check VPN still unmapped in local GPT
-
-        // do nothing if VPN has been mapped by a a concurrent page_fault
-        hal_gpt_get_pte( local_gpt_xp,
-                         vpn,
-                         &new_attr,
-                         &new_ppn );
-
-        if( (new_attr & GPT_MAPPED) == 0 )       // VPN still unmapped
-        { 
-            // allocate and initialise a physical page depending on the vseg type
-            error = vmm_get_one_ppn( vseg , vpn , &new_ppn );
-
-            if( error )
-            {
-                printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
-                __FUNCTION__ , process->pid , vpn );
-
-                // release local GPT lock in write mode
-                remote_rwlock_wr_release( local_lock_xp );
-
-                return EXCP_KERNEL_PANIC;
-            }
-
-            // define new_attr from vseg flags 
-            new_attr = GPT_MAPPED | GPT_SMALL;
-            if( vseg->flags & VSEG_USER  ) new_attr |= GPT_USER;
-            if( vseg->flags & VSEG_WRITE ) new_attr |= GPT_WRITABLE;
-            if( vseg->flags & VSEG_EXEC  ) new_attr |= GPT_EXECUTABLE;
-            if( vseg->flags & VSEG_CACHE ) new_attr |= GPT_CACHABLE;
-
-            // set PTE (PPN & attribute) to local GPT
-            error = hal_gpt_set_pte( local_gpt_xp,
-                                     vpn,
-                                     new_attr,
-                                     new_ppn );
-            if ( error )
-            {
-                printk("\n[ERROR] in %s : cannot update local GPT / process %x / vpn = %x\n",
-                __FUNCTION__ , process->pid , vpn );
-
-                // release local GPT lock in write mode
-                remote_rwlock_wr_release( local_lock_xp );
-
-                return EXCP_KERNEL_PANIC;
-            }
-        }
-
-        // release local GPT lock in write mode
-        remote_rwlock_wr_release( local_lock_xp );
-
-#if DEBUG_VMM_HANDLE_PAGE_FAULT
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_HANDLE_PAGE_FAULT < cycle )
-printk("\n[%s] private page fault handled / vpn %x / ppn %x / attr %x / cycle %d\n",
-__FUNCTION__, vpn, new_ppn, new_attr, cycle );
-#endif
-        return EXCP_NON_FATAL;
-
-    }   // end local GPT access 
-
-    //////////// public vseg => access reference GPT
-    else                                
+if( DEBUG_VMM_HANDLE_PAGE_FAULT < start_cycle )
+printk("\n[%s] thread[%x,%x] found vseg %s\n",
+__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(vseg->type) );
+#endif
+
+    // build extended pointer on local GPT
+    local_gpt_xp  = XPTR( local_cxy , &process->vmm.gpt );
+
+    // lock target PTE in local GPT and get current PPN and attributes
+    error = hal_gpt_lock_pte( local_gpt_xp,
+                              vpn,
+                              &attr,
+                              &ppn );
+    if( error )
+    {
+        printk("\n[PANIC] in %s : cannot lock PTE in local GPT / vpn %x / process %x\n",
+        __FUNCTION__ , vpn , process->pid );
+        
+        return EXCP_KERNEL_PANIC;
+    }
+
+    // handle page fault only if PTE still unmapped after lock
+    if( (attr & GPT_MAPPED) == 0 )
     {
         // get reference process cluster and local pointer
@@ -2033,79 +1978,61 @@
         ref_ptr = GET_PTR( process->ref_xp );
 
-        // build extended pointer on reference GPT and reference GPT lock
-        ref_gpt_xp  = XPTR( ref_cxy , &ref_ptr->vmm.gpt );
-        ref_lock_xp = XPTR( ref_cxy , &ref_ptr->vmm.gpt_lock );
-
-        // build extended pointer on local GPT and local GPT lock
-        local_gpt_xp  = XPTR( local_cxy , &process->vmm.gpt );
-        local_lock_xp = XPTR( local_cxy , &process->vmm.gpt_lock );
-
-        // take reference GPT lock in read mode 
-        remote_rwlock_rd_acquire( ref_lock_xp );
-
-        // get directly PPN & attributes from reference GPT
-        // this can avoids a costly RPC for a false page fault
-        hal_gpt_get_pte( ref_gpt_xp,
-                         vpn,
-                         &ref_attr,
-                         &ref_ppn );
-
-        // release reference GPT lock in read mode 
-        remote_rwlock_rd_release( ref_lock_xp );
-
-        if( ref_attr & GPT_MAPPED )        // false page fault => update local GPT
+        // private vseg or (local == reference) => access only the local GPT 
+        if( (vseg->type == VSEG_TYPE_STACK) ||
+            (vseg->type == VSEG_TYPE_CODE)  ||
+            (ref_cxy    == local_cxy ) )
         {
-            // take local GPT lock in write mode
-            remote_rwlock_wr_acquire( local_lock_xp );
-            
-            // check VPN still unmapped in local GPT
-            hal_gpt_get_pte( local_gpt_xp,
+            // allocate and initialise a physical page depending on the vseg type
+            error = vmm_get_one_ppn( vseg , vpn , &ppn );
+
+            if( error )
+            {
+                printk("\n[ERROR] in %s : no physical page / process = %x / vpn = %x\n",
+                __FUNCTION__ , process->pid , vpn );
+
+                // unlock PTE in local GPT 
+                hal_gpt_unlock_pte( local_gpt_xp , vpn );
+
+                return EXCP_KERNEL_PANIC;
+            }
+
+            // define attr from vseg flags 
+            attr = GPT_MAPPED | GPT_SMALL;
+            if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
+            if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
+            if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
+            if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
+
+            // set PTE to local GPT 
+            hal_gpt_set_pte( local_gpt_xp,
                              vpn,
-                             &new_attr,
-                             &new_ppn );
-
-            if( (new_attr & GPT_MAPPED) == 0 )       // VPN still unmapped
-            { 
-                // update local GPT from reference GPT
-                error = hal_gpt_set_pte( local_gpt_xp,
-                                         vpn,
-                                         ref_attr,
-                                         ref_ppn );
-                if( error )
-                {
-                    printk("\n[ERROR] in %s : cannot update local GPT / process %x / vpn %x\n",
-                    __FUNCTION__ , process->pid , vpn );
-
-                    // release local GPT lock in write mode
-                    remote_rwlock_wr_release( local_lock_xp );
-            
-                    return EXCP_KERNEL_PANIC;
-                }
-            }
-            else    // VPN has been mapped by a a concurrent page_fault 
-            {
-                // keep PTE from local GPT
-                ref_attr = new_attr;
-                ref_ppn  = new_ppn;
-            }
-
-            // release local GPT lock in write mode
-            remote_rwlock_wr_release( local_lock_xp );
-            
+                             attr,
+                             ppn );
+
+#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
+uint32_t end_cycle = (uint32_t)hal_get_cycles();
+#endif
+
 #if DEBUG_VMM_HANDLE_PAGE_FAULT
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_HANDLE_PAGE_FAULT < cycle )
-printk("\n[%s] false page fault handled / vpn %x / ppn %x / attr %x / cycle %d\n",
-__FUNCTION__, vpn, ref_ppn, ref_attr, cycle );
+if( DEBUG_VMM_HANDLE_PAGE_FAULT < end_cycle )
+printk("\n[%s] local page fault handled / vpn %x / ppn %x / attr %x / cycle %d\n",
+__FUNCTION__, vpn, ppn, attr, end_cycle );
+#endif
+
+#if CONFIG_INSTRUMENTATION_PGFAULTS 
+this->info.local_pgfault_nr++;
+this->info.local_pgfault_cost += (end_cycle - start_cycle);
 #endif
             return EXCP_NON_FATAL;
-        }
-        else                            // true page fault => update reference GPT
+
+        }   // end local GPT access 
+
+        // public vseg and (local != reference) => access ref GPT to update local GPT
+        else                                
         {
-            // take reference GPT lock in write mode
-            remote_rwlock_wr_acquire( ref_lock_xp );
-            
-            // check VPN still unmapped in reference GPT
-            // do nothing if VPN has been mapped by a a concurrent page_fault
+            // build extended pointer on reference GPT
+            ref_gpt_xp = XPTR( ref_cxy , &ref_ptr->vmm.gpt );
+
+            // get current PPN and attributes from reference GPT
             hal_gpt_get_pte( ref_gpt_xp,
                              vpn,
@@ -2113,8 +2040,32 @@
                              &ref_ppn );
 
-            if( (ref_attr & GPT_MAPPED) == 0 )       // VPN actually unmapped
-            { 
+            if( ref_attr & GPT_MAPPED )        // false page fault => update local GPT
+            {
+                // update local GPT from reference GPT values
+                hal_gpt_set_pte( local_gpt_xp,
+                                 vpn,
+                                 ref_attr,
+                                 ref_ppn );
+
+#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
+uint32_t end_cycle = (uint32_t)hal_get_cycles();
+#endif
+
+#if DEBUG_VMM_HANDLE_PAGE_FAULT
+if( DEBUG_VMM_HANDLE_PAGE_FAULT < end_cycle )
+printk("\n[%s] false page fault handled / vpn %x / ppn %x / attr %x / cycle %d\n",
+__FUNCTION__, vpn, ref_ppn, ref_attr, end_cycle );
+#endif
+
+#if CONFIG_INSTRUMENTATION_PGFAULTS 
+this->info.false_pgfault_nr++;
+this->info.false_pgfault_cost += (end_cycle - start_cycle);
+#endif
+                return EXCP_NON_FATAL;
+            }
+            else                            // true page fault => update both GPTs
+            {
                 // allocate and initialise a physical page depending on the vseg type
-                error = vmm_get_one_ppn( vseg , vpn , &new_ppn );
+                error = vmm_get_one_ppn( vseg , vpn , &ppn );
 
                 if( error )
@@ -2123,53 +2074,71 @@
                     __FUNCTION__ , process->pid , vpn );
 
-                   // release reference GPT lock in write mode
-                   remote_rwlock_wr_release( ref_lock_xp );
+                    // unlock PTE in local GPT
+                    hal_gpt_unlock_pte( local_gpt_xp , vpn );
                     
-                   return EXCP_KERNEL_PANIC;
+                    return EXCP_KERNEL_PANIC;
                 }
 
-                // define new_attr from vseg flags 
-                new_attr = GPT_MAPPED | GPT_SMALL;
-                if( vseg->flags & VSEG_USER  ) new_attr |= GPT_USER;
-                if( vseg->flags & VSEG_WRITE ) new_attr |= GPT_WRITABLE;
-                if( vseg->flags & VSEG_EXEC  ) new_attr |= GPT_EXECUTABLE;
-                if( vseg->flags & VSEG_CACHE ) new_attr |= GPT_CACHABLE;
-
-                // update reference GPT
-                error = hal_gpt_set_pte( ref_gpt_xp,
-                                         vpn,
-                                         new_attr,
-                                         new_ppn );
-
-                // update local GPT (protected by reference GPT lock)
-                error |= hal_gpt_set_pte( local_gpt_xp,
+                // lock PTE in reference GPT
+                error = hal_gpt_lock_pte( ref_gpt_xp,
                                           vpn,
-                                          new_attr,
-                                          new_ppn );
-
+                                          &ref_attr,
+                                          &ref_ppn );
                 if( error )
                 {
-                    printk("\n[ERROR] in %s : cannot update GPT / process %x / vpn = %x\n",
-                    __FUNCTION__ , process->pid , vpn );
-
-                    // release reference GPT lock in write mode
-                    remote_rwlock_wr_release( ref_lock_xp );
-
+                    printk("\n[PANIC] in %s : cannot lock PTE in ref GPT / vpn %x / process %x\n",
+                    __FUNCTION__ , vpn , process->pid );
+        
+                    // unlock PTE in local GPT
+                    hal_gpt_unlock_pte( local_gpt_xp , vpn );
+                    
                     return EXCP_KERNEL_PANIC;
                 }
+
+                // define attr from vseg flags 
+                attr = GPT_MAPPED | GPT_SMALL;
+                if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
+                if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
+                if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
+                if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
+
+                // set PTE in reference GPT
+                hal_gpt_set_pte( ref_gpt_xp,
+                                 vpn,
+                                 attr,
+                                 ppn );
+
+                // set PTE in local GPT 
+                hal_gpt_set_pte( local_gpt_xp,
+                                 vpn,
+                                 attr,
+                                 ppn );
+
+#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
+uint32_t end_cycle = (uint32_t)hal_get_cycles();
+#endif
+
+#if DEBUG_VMM_HANDLE_PAGE_FAULT
+if( DEBUG_VMM_HANDLE_PAGE_FAULT < end_cycle )
+printk("\n[%s] global page fault handled / vpn %x / ppn %x / attr %x / cycle %d\n",
+__FUNCTION__, vpn, ppn, attr, end_cycle );
+#endif
+
+#if CONFIG_INSTRUMENTATION_PGFAULTS 
+this->info.global_pgfault_nr++;
+this->info.global_pgfault_cost += (end_cycle - start_cycle);
+#endif
+                return EXCP_NON_FATAL;
             }
-
-            // release reference GPT lock in write mode
-            remote_rwlock_wr_release( ref_lock_xp );
-
-#if DEBUG_VMM_HANDLE_PAGE_FAULT
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_VMM_HANDLE_PAGE_FAULT < cycle )
-printk("\n[%s] true page fault handled / vpn %x / ppn %x / attr %x / cycle %d\n",
-__FUNCTION__, vpn, new_ppn, new_attr, cycle );
-#endif
-            return EXCP_NON_FATAL;
         }
     }
+    else   // page has been locally mapped by another concurrent thread
+    {
+        // unlock PTE in local GPT
+        hal_gpt_unlock_pte( local_gpt_xp , vpn );
+
+        return EXCP_NON_FATAL;
+    }
+
 }   // end vmm_handle_page_fault()
 
@@ -2179,28 +2148,27 @@
 {
     vseg_t         * vseg;            // vseg containing vpn
-    cxy_t            ref_cxy;         // reference cluster for missing vpn
-    process_t      * ref_ptr;         // reference process for missing vpn
-    xptr_t           gpt_xp;          // extended pointer on GPT
-    xptr_t           gpt_lock_xp;     // extended pointer on GPT lock
+    xptr_t           gpt_xp;          // extended pointer on GPT (local or reference)
+    gpt_t          * gpt_ptr;         // local pointer on GPT (local or reference)
+    cxy_t            gpt_cxy;         // GPT cluster identifier
     uint32_t         old_attr;        // current PTE_ATTR value
     ppn_t            old_ppn;         // current PTE_PPN value
     uint32_t         new_attr;        // new PTE_ATTR value
     ppn_t            new_ppn;         // new PTE_PPN value
+    cxy_t            ref_cxy;         // reference process cluster
+    process_t      * ref_ptr;         // local pointer on reference process
     error_t          error;
 
-    thread_t * this = CURRENT_THREAD;
+    thread_t * this  = CURRENT_THREAD;
 
 #if DEBUG_VMM_HANDLE_COW
-uint32_t   cycle   = (uint32_t)hal_get_cycles();
+uint32_t   cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_VMM_HANDLE_COW < cycle )
 printk("\n[%s] thread[%x,%x] enter for vpn %x / core[%x,%d] / cycle %d\n",
 __FUNCTION__, this->process->pid, this->trdid, vpn, local_cxy, this->core->lid, cycle );
+#endif
+
+#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
 hal_vmm_display( process , true );
 #endif
-
-    // access local GPT to get GPT_COW flag
-    bool_t cow = hal_gpt_pte_is_cow( &(process->vmm.gpt), vpn );
-
-    if( cow == false ) return EXCP_USER_ERROR;
 
     // get local vseg
@@ -2210,44 +2178,50 @@
     if( error )
     {
-        printk("\n[PANIC] in %s vpn %x in thread[%x,%x] not in a registered vseg\n",
+        printk("\n[ERROR] in %s : vpn %x in thread[%x,%x] not in a registered vseg\n",
         __FUNCTION__, vpn, process->pid, this->trdid );
 
-        return EXCP_KERNEL_PANIC;
-    }
-
-#if( DEBUG_VMM_HANDLE_COW & 1)
+        return EXCP_USER_ERROR;
+    }
+
+#if DEBUG_VMM_HANDLE_COW 
 if( DEBUG_VMM_HANDLE_COW < cycle )
-printk("\n[%s] thread[%x,%x] get vseg for vpn %x\n",
-__FUNCTION__, this->process->pid, this->trdid, vpn );
-#endif
-
-    // get reference GPT cluster and local pointer
+printk("\n[%s] thread[%x,%x] get vseg %s\n",
+__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(vseg->type) );
+#endif
+
+    // get reference process cluster and local pointer
     ref_cxy = GET_CXY( process->ref_xp );
     ref_ptr = GET_PTR( process->ref_xp );
 
-    // build relevant extended pointers on  relevant GPT and  GPT lock
-    // - access local GPT for a private vseg  
-    // - access reference GPT for a public vseg
+    // build pointers on relevant GPT
+    // - access only local GPT for a private vseg  
+    // - access reference GPT and all copies for a public vseg
     if( (vseg->type == VSEG_TYPE_STACK) || (vseg->type == VSEG_TYPE_CODE) )
     {
-        gpt_xp      = XPTR( local_cxy , &process->vmm.gpt );
-        gpt_lock_xp = XPTR( local_cxy , &process->vmm.gpt_lock );
+        gpt_cxy = local_cxy;
+        gpt_ptr = &process->vmm.gpt;
+        gpt_xp  = XPTR( gpt_cxy , gpt_ptr );
     }
     else
     {
-        gpt_xp      = XPTR( ref_cxy , &ref_ptr->vmm.gpt );
-        gpt_lock_xp = XPTR( ref_cxy , &ref_ptr->vmm.gpt_lock );
-    }
-
-    // take GPT lock in write mode
-    remote_rwlock_wr_acquire( gpt_lock_xp );
-
-    // get current PTE from reference GPT
-    hal_gpt_get_pte( gpt_xp,
-                     vpn,
-                     &old_attr,
-                     &old_ppn );
-
-#if( DEBUG_VMM_HANDLE_COW & 1)
+        gpt_cxy = ref_cxy;
+        gpt_ptr = &ref_ptr->vmm.gpt;
+        gpt_xp  = XPTR( gpt_cxy , gpt_ptr );
+    }
+
+    // lock target PTE in relevant GPT (local or reference) 
+    error = hal_gpt_lock_pte( gpt_xp,
+                              vpn,
+                              &old_attr,
+                              &old_ppn );
+    if( error )
+    {
+        printk("\n[PANIC] in %s : cannot lock PTE in GPT / cxy %x / vpn %x / process %x\n",
+        __FUNCTION__ , gpt_cxy, vpn , process->pid );
+        
+        return EXCP_KERNEL_PANIC;
+    }
+
+#if DEBUG_VMM_HANDLE_COW 
 if( DEBUG_VMM_HANDLE_COW < cycle )
 printk("\n[%s] thread[%x,%x] get pte for vpn %x : ppn %x / attr %x\n",
@@ -2255,14 +2229,10 @@
 #endif
 
-    // the PTE must be mapped for a COW
-    if( (old_attr & GPT_MAPPED) == 0 )
-    {
-        printk("\n[PANIC] in %s : VPN %x in process %x unmapped\n",
-        __FUNCTION__, vpn, process->pid );
-
-        // release GPT lock in write mode
-        remote_rwlock_wr_release( gpt_lock_xp );
-
-        return EXCP_KERNEL_PANIC;
+    // return user error if COW attribute not set or PTE2 unmapped
+    if( ((old_attr & GPT_COW) == 0) || ((old_attr & GPT_MAPPED) == 0) )
+    {
+        hal_gpt_unlock_pte( gpt_xp , vpn );
+
+        return EXCP_USER_ERROR;
     }
 
@@ -2282,5 +2252,5 @@
     uint32_t forks = hal_remote_l32( forks_xp );
 
-#if( DEBUG_VMM_HANDLE_COW & 1)
+#if DEBUG_VMM_HANDLE_COW 
 if( DEBUG_VMM_HANDLE_COW < cycle )
 printk("\n[%s] thread[%x,%x] get forks = %d for vpn %x\n",
@@ -2296,5 +2266,5 @@
         remote_busylock_release( forks_lock_xp );
 
-        // allocate a new page
+        // allocate a new physical page depending on vseg type
         page_xp = vmm_page_allocate( vseg , vpn );
 
@@ -2304,6 +2274,5 @@
             __FUNCTION__ , vpn, process->pid );
 
-            // release GPT lock in write mode
-            remote_rwlock_wr_acquire( gpt_lock_xp );
+            hal_gpt_unlock_pte( gpt_xp , vpn ); 
 
             return EXCP_KERNEL_PANIC;
@@ -2313,5 +2282,5 @@
         new_ppn = ppm_page2ppn( page_xp );
 
-#if( DEBUG_VMM_HANDLE_COW & 1)
+#if DEBUG_VMM_HANDLE_COW 
 if( DEBUG_VMM_HANDLE_COW < cycle )
 printk("\n[%s] thread[%x,%x] get new ppn %x for vpn %x\n",
@@ -2324,5 +2293,5 @@
                            CONFIG_PPM_PAGE_SIZE );
 
-#if(DEBUG_VMM_HANDLE_COW & 1)
+#if DEBUG_VMM_HANDLE_COW
 if( DEBUG_VMM_HANDLE_COW < cycle )
 printk("\n[%s] thread[%x,%x] copied old page to new page\n",
@@ -2344,12 +2313,13 @@
     }
 
-    // build new_attr : reset COW and set WRITABLE,
-    new_attr = (old_attr | GPT_WRITABLE) & (~GPT_COW);
-
-    // update the relevant GPT
-    // - private vseg => update local GPT 
-    // - public vseg => update all GPT copies
+    // build new_attr : set WRITABLE, reset COW, reset LOCKED
+    new_attr = (((old_attr | GPT_WRITABLE) & (~GPT_COW)) & (~GPT_LOCKED));
+
+    // update the relevant GPT(s)
+    // - private vseg => update only the local GPT 
+    // - public vseg => update the reference GPT AND all the GPT copies
     if( (vseg->type == VSEG_TYPE_STACK) || (vseg->type == VSEG_TYPE_CODE) )
     {
+        // set the new PTE2
         hal_gpt_set_pte( gpt_xp,
                          vpn,
@@ -2376,7 +2346,4 @@
     }
 
-    // release GPT lock in write mode
-    remote_rwlock_wr_release( gpt_lock_xp );
-
 #if DEBUG_VMM_HANDLE_COW
 cycle = (uint32_t)hal_get_cycles();
