Index: trunk/kernel/mm/page.c
===================================================================
--- trunk/kernel/mm/page.c	(revision 690)
+++ trunk/kernel/mm/page.c	(revision 1)
@@ -3,5 +3,5 @@
  *
  * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
- *          Alain Greiner    (2016,2017)
+ *          Alain Greiner    (2016)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -23,10 +23,15 @@
  */
 
-#include <hal_kernel_types.h>
+#include <hal_types.h>
 #include <hal_special.h>
 #include <hal_atomic.h>
 #include <list.h>
-#include <queuelock.h>
+#include <xlist.h>
 #include <memcpy.h>
+#include <thread.h>
+#include <scheduler.h>
+#include <cluster.h>
+#include <ppm.h>
+#include <mapper.h>
 #include <printk.h>
 #include <vfs.h>
@@ -35,4 +40,5 @@
 
 
+
 ////////////////////////////////////////
 inline void page_init( page_t   * page )
@@ -40,31 +46,181 @@
 	page->flags    = 0;
 	page->order    = 0;
+	page->index    = 0;
 	page->mapper   = NULL;
-	page->index    = 0;
-	page->refcount = 0;
-	page->forks    = 0;
-
-	remote_busylock_init( XPTR( local_cxy , &page->lock ), LOCK_PAGE_STATE );
+	page->private  = 0;
+    page->refcount = 0;
+	spinlock_init( &page->lock );
+	list_entry_init( &page->list );
 }
 
 ////////////////////////////////////////////
 inline void page_set_flag( page_t   * page,
-                           uint32_t   value )
-{
-	hal_atomic_or( (uint32_t *)&page->flags , (uint32_t)value );
+                           uint16_t   value )
+{
+    hal_atomic_or( (uint32_t *)&page->flags , (uint32_t)value );
 }
 
 //////////////////////////////////////////////
 inline void page_clear_flag( page_t   * page,
-                             uint32_t   value )
-{
-	hal_atomic_and( (uint32_t *)&page->flags , ~value );
+                             uint16_t   value )
+{
+    hal_atomic_and( (uint32_t *)&page->flags , ~((uint32_t)value) );
 }
 
 //////////////////////////////////////////////
 inline bool_t page_is_flag( page_t   * page,
-                            uint32_t   value )
-{
-    return ( (page->flags & value) ? 1 : 0 );
+                            uint16_t   value )
+{
+    return (bool_t)(page->flags & value);
+}
+
+//////////////////////////////////////
+bool_t page_do_dirty( page_t * page )
+{
+	bool_t done = false;
+
+    ppm_t * ppm = &LOCAL_CLUSTER->ppm;
+
+    // lock the PPM dirty_list
+	spinlock_lock( &ppm->dirty_lock );
+
+	if( !page_is_flag( page , PG_DIRTY ) )
+	{
+        // set dirty flag in page descriptor
+		page_set_flag( page , PG_DIRTY );
+  
+        // register page in PPM dirty list
+		list_add_first( &ppm->dirty_root , &page->list );
+		done = true;
+	}
+
+    // unlock the PPM dirty_list
+	spinlock_unlock( &ppm->dirty_lock );
+  
+	return done;
+}
+
+////////////////////////////////////////
+bool_t page_undo_dirty( page_t * page )
+{
+	bool_t done = false;
+
+    ppm_t * ppm = &LOCAL_CLUSTER->ppm;
+
+    // lock the dirty_list
+	spinlock_lock( &ppm->dirty_lock );
+
+	if( page_is_flag( page , PG_DIRTY) )
+	{
+        // clear dirty flag in page descriptor
+		page_clear_flag( page , PG_DIRTY );
+
+        // remove page from PPM dirty list
+		list_unlink( &page->list );
+		done = true;
+	}
+
+    // unlock the dirty_list
+	spinlock_unlock( &ppm->dirty_lock );
+
+	return done;
+}
+
+/////////////////////
+void sync_all_pages() 
+{
+	page_t   * page;
+	mapper_t * mapper;
+    uint32_t   index;
+    ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
+
+    // lock the dirty_list
+	spinlock_lock( &ppm->dirty_lock );
+
+	while( !list_is_empty( &ppm->dirty_root ) ) 
+	{
+		page = LIST_FIRST( &ppm->dirty_root ,  page_t , list );
+
+        // unlock the dirty_list
+	    spinlock_unlock( &ppm->dirty_lock );
+
+		mapper = page->mapper;
+        index  = page->index;
+ 
+        // lock the page
+		page_lock( page );
+
+        // sync the page
+		mapper_sync_page( mapper , index , page );
+
+        // unlock the page
+		page_unlock( page );
+
+        // lock the dirty_list
+	    spinlock_lock( &ppm->dirty_lock );
+	}
+
+    // unlock the dirty_list
+	spinlock_unlock( &ppm->dirty_lock );
+
+} // end sync_all_pages()
+
+///////////////////////////////
+void page_lock( page_t * page )
+{
+    // take the spinlock protecting the PG_LOCKED flag
+	spinlock_lock( &page->lock );
+
+	if( page_is_flag( page , PG_LOCKED ) )  // page is already locked
+	{
+        // get pointer on calling thread
+        thread_t * thread = CURRENT_THREAD;
+
+        // register thread in the page waiting queue
+        xlist_add_last( XPTR( local_cxy , &page->wait_root ),
+                        XPTR( local_cxy , &thread->wait_list ) );
+
+        // release the spinlock
+		spinlock_unlock( &page->lock );
+
+        // deschedule the calling thread
+        thread_block( thread , THREAD_BLOCKED_PAGE );
+		sched_yield();
+	}
+	else                                    // page is not locked
+	{
+        // set the PG_LOCKED flag
+		page_set_flag( page , PG_LOCKED );
+
+        // release the spinlock
+		spinlock_unlock( &page->lock );
+	}
+}
+
+/////////////////////////////////
+void page_unlock( page_t * page )
+{
+    // take the spinlock protecting the PG_LOCKED flag
+	spinlock_lock( &page->lock );
+  
+    // check the page waiting list
+	bool_t is_empty = xlist_is_empty( XPTR( local_cxy , &page->wait_root ) );
+
+	if( is_empty == false )    // at least one waiting thread => resume it
+    {
+        // get an extended pointer on the first waiting thread
+        xptr_t root_xp   = XPTR( local_cxy , &page->wait_root ); 
+        xptr_t thread_xp = XLIST_FIRST_ELEMENT( root_xp , thread_t , wait_list );
+
+        // reactivate the first waiting thread
+        thread_unblock( thread_xp , THREAD_BLOCKED_PAGE );
+    }
+	else                      // no waiting thread => clear the PG_LOCKED flag
+	{
+        page_clear_flag( page , PG_LOCKED );
+    }
+
+    // release the spinlock
+	spinlock_unlock( &page->lock );
 }
 
@@ -72,5 +228,5 @@
 inline void page_refcount_up( page_t *page )
 {
-    hal_atomic_add( &page->refcount , +1 );
+    hal_atomic_inc( &page->refcount );
 }
 
@@ -78,5 +234,26 @@
 inline void page_refcount_down( page_t *page )
 {
-    hal_atomic_add( &page->refcount , -1 );
+    hal_atomic_dec( &page->refcount );
+}
+
+//////////////////////////////
+void page_copy(  page_t * dst,
+                 page_t * src )
+{
+	uint32_t  size;
+	void    * src_base;
+	void    * dst_base;
+  
+	if( dst->order != src->order )
+    {
+        printk("\n[PANIC] in %s : src size != dst size\n", __FUNCTION__ );
+        hal_core_sleep();
+    }
+
+	size = (1 << dst->order) * CONFIG_PPM_PAGE_SIZE;
+	src_base = ppm_page2base( src );
+	dst_base = ppm_page2base( dst );
+
+	memcpy( dst_base , src_base , size );
 }
 
@@ -84,91 +261,142 @@
 void page_zero( page_t * page )
 {
-	uint32_t   size = (1 << page->order) * CONFIG_PPM_PAGE_SIZE;
-
-	xptr_t base_xp = ppm_page2base( XPTR( local_cxy , page ) );
-
-	memset( GET_PTR( base_xp ) , 0 , size );
-}
-
-
-
-
-///////////////////////////////////////////////
-inline void page_remote_init( xptr_t  page_xp )
-{
-	hal_remote_memset( page_xp , 0 , sizeof(page_t) );
-
-    cxy_t    page_cxy = GET_CXY( page_xp );
-    page_t * page_ptr = GET_PTR( page_xp );
-
-	remote_busylock_init( XPTR( page_cxy , &page_ptr->lock ), LOCK_PAGE_STATE );
-}
-
-////////////////////////////////////////////////////
-inline void page_remote_set_flag( xptr_t    page_xp,
-                                  uint32_t  value )
-{
-    cxy_t    page_cxy = GET_CXY( page_xp );
-    page_t * page_ptr = GET_PTR( page_xp );
-
-	hal_remote_atomic_or( XPTR( page_cxy , &page_ptr->flags ) , value );
-}
-
-//////////////////////////////////////////////////////
-inline void page_remote_clear_flag( xptr_t    page_xp,
-                                    uint32_t  value )
-{
-    cxy_t    page_cxy = GET_CXY( page_xp );
-    page_t * page_ptr = GET_PTR( page_xp );
-
-	hal_remote_atomic_and( XPTR( page_cxy , &page_ptr->flags ) , ~value );
-}
-
-/////////////////////////////////////////////////////
-inline bool_t page_remote_is_flag( xptr_t    page_xp,
-                                   uint32_t  value )
-{
-    cxy_t    page_cxy = GET_CXY( page_xp );
-    page_t * page_ptr = GET_PTR( page_xp );
-
-    uint32_t flags = hal_remote_l32( XPTR( page_cxy , &page_ptr->flags ) );
-    
-    return (flags & value) ? 1 : 0;
-}
-
-/////////////////////////////////////////////////////
-inline void page_remote_refcount_up( xptr_t page_xp )
-{
-    cxy_t    page_cxy = GET_CXY( page_xp );
-    page_t * page_ptr = GET_PTR( page_xp );
-
-    hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->refcount ) , 1 );
-}
-
-///////////////////////////////////////////////////////
-inline void page_remote_refcount_down( xptr_t page_xp )
-{
-    cxy_t    page_cxy = GET_CXY( page_xp );
-    page_t * page_ptr = GET_PTR( page_xp );
-
-    hal_remote_atomic_add( XPTR( page_cxy , &page_ptr->refcount ) , -1 );
+	uint32_t   size;
+	void     * base;
+
+	size = (1 << page->order) * CONFIG_PPM_PAGE_SIZE;
+	base = ppm_page2base(page);
+
+	memset( base , 0 , size ); 
+}
+
+////////////////////////////////
+void page_print( page_t * page )
+{
+	printk("*** Page %d : base = %x / flags = %x / order = %d / count = %d\n",
+	        page->index, 
+	        ppm_page2base( page ),
+	        page->flags, 
+	        page->order, 
+	        page->refcount );
+}
+
+
+
+
+
+/*
+/////////////////////////////////////////
+static void page_to_free( page_t * page )
+{
+	assert((page->state == PGINVALID) || 
+	       (page->state == PGVALID)   ||
+	       (page->state == PGINIT));
+
+	if(page_refcount_get(page) != 0)
+	{
+		printk(ERROR, "ERROR: %s: cpu %d, pid %d, tid %x, page %x, state %x, count %d [%d]\n",
+		       __FUNCTION__,
+		       cpu_get_id(),
+		       current_task->pid,
+		       current_thread,
+		       page,
+		       page->state,
+		       page_refcount_get(page),
+		       cpu_time_stamp());
+	}
+	page->state = PGFREE;
+}
+
+////////////////////////////////////////////
+static void page_to_invalid( page_t * page )
+{
+	assert((page->state == PGFREE)  || 
+	       (page->state == PGVALID) ||
+	       (page->state == PGLOCKEDIO));
+  
+	if(page->state == PGLOCKEDIO)
+	{
+		page->state = PGINVALID; 
+		page_unlock(page);
+		return;
+	}
+ 
+	page->state = PGINVALID;
+}
+
+//////////////////////////////////////////
+static void page_to_valid( page_t * page )
+{
+	assert((page->state == PGINVALID) || 
+	       (page->state == PGLOCKED)  ||
+	       (page->state == PGLOCKEDIO));
+  
+	if(page->state == PGINVALID)
+	{
+		page->state = PGVALID;
+		return;
+	}
+
+	page->state = PGVALID;
+	page_unlock(page);
+}
+
+//////////////////////////////////////////////
+static void page_to_locked_io( page_t * page )
+{
+	assert((page->state == PGINVALID) || 
+	       (page->state == PGVALID));
+
+	page_lock(page);
+	page->state = PGLOCKEDIO;
 }
 
 ///////////////////////////////////////////
-void page_remote_display( xptr_t  page_xp )
-{
-    page_t  page;   // local copy of page decriptor
-
-    hal_remote_memcpy( XPTR( local_cxy , &page ) , page_xp , sizeof( page_t ) );
-                      
-	printk("*** Page %d in cluster %x : ppn %x / flags %x / order %d / refcount %d\n",
-	        page.index,
-            GET_CXY( page_xp ),
-	        ppm_page2ppn( page_xp ),
-	        page.flags,
-	        page.order,
-	        page.refcount );
-}
-
-
-
+static void page_to_locked( page_t * page )
+{
+	assert(page->state == PGVALID);
+	page_lock(page);
+	page->state = PGLOCKED;
+}
+
+/////////////////////////////////////////
+void page_state_set( page_t       * page,
+                     page_state_t   state )
+{
+	switch( state )
+	{
+	case PGFREE:
+		page_to_free(page);
+		return;
+
+	case PGINVALID:
+		page_to_invalid(page);
+		return;
+
+	case PGVALID:
+		page_to_valid(page);
+		return;
+
+	case PGLOCKEDIO:
+		page_to_locked_io(page);
+		return;
+
+	case PGLOCKED:
+		page_to_locked(page);
+		return;
+
+	case PGRESERVED:
+		refcount_set(&page->count,1);
+
+	case PGINIT:
+		page->state = new_state;
+		return;
+
+	default:
+		printk(ERROR, "ERROR: %s: Unknown Asked State %d\n", new_state);
+		return;
+	}
+}
+*/
+
+
