/*
 * page.h - physical page descriptor and related operations
 *
 * Authors Ghassan Almalles (2008,2009,2010,2011,2012)
 *         Alain Greiner    (2016)
 *
 * Copyright (c) UPMC Sorbonne Universites
 *
 * This file is part of ALMOS-MKH.
 *
 * ALMOS-MKH is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-MKH is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _PAGE_H_
#define _PAGE_H_

#include <almos_config.h>
#include <hal_types.h>
#include <spinlock.h>
#include <list.h>
#include <slist.h>
#include <xlist.h>

/***   Forward declarations   ***/

struct mapper_s;
 
/*************************************************************************************
 * This  defines the flags that can be attached to a physical page.
 ************************************************************************************/

#define PG_INIT		    0x0001     // page descriptor has been initialised
#define PG_RESERVED	    0x0002     // cannot be allocated by PPM
#define PG_FREE		    0x0004     // page can be allocated by PPM
#define PG_INLOAD	    0x0008     // on-going load from disk 
#define PG_IO_ERR	    0x0010     // mapper signals a read/write access error
#define PG_BUFFER	    0x0020     // used in blockio.c
#define PG_DIRTY	    0x0040     // page has been written
#define PG_LOCKED       0x0080     // page is locked

#define PG_ALL          0xFFFF     // All flags

/*************************************************************************************
 * This structure defines a physical page descriptor.
 * Size is 60 bytes for a 32 bits core...
 ************************************************************************************/

typedef struct page_s
{
    uint16_t          flags;          /*! flags defined above                  (2)  */
    uint16_t          order;          /*! log2( number of 4Kbytes pages)       (2)  */

    struct mapper_s * mapper;         /*! local pointer on associated mapper   (4)  */
    uint32_t          index;          /*! page index in mapper                 (4)  */
 
	union                             /*!                                      (4)  */
	{
		uint32_t      private;        /*! TODO ??? [AG]                             */
		void        * data;           /*! TODO ??? [AG]                             */
		slist_entry_t root;           /*! TODO ??? [AG]                             */
	};

	list_entry_t      list;           /*! for both dirty pages and free pages  (8)  */ 

    xlist_entry_t     wait_root;      /*! root of list of waiting threads      (16) */

	uint32_t          refcount;       /*! reference counter                    (4)  */
	spinlock_t        lock;           /*! only used to set the PG_LOCKED flag  (16) */
}
page_t;

/*************************************************************************************
 * This function initializes one page descriptor.
 * @ page    : pointer to page descriptor
 ************************************************************************************/
inline void page_init( page_t * page );

/*************************************************************************************
 * This function set one or several flags in page descriptor flags.
 * @ page    : pointer to page descriptor.
 * @ value   : all non zero bits in value will be set. 
 ************************************************************************************/
inline void page_set_flag( page_t   * page,
                           uint16_t   value );

/*************************************************************************************
 * This function reset one or several flags in page descriptor flags.
 * @ page    : pointer to page descriptor.
 * @ value   : all non zero bits in value will be cleared. 
 ************************************************************************************/
inline void page_clear_flag( page_t   * page,
                             uint16_t   value );

/*************************************************************************************
 * This function test the value of one or several flags in page descriptor flags.
 * @ page    : pointer to page descriptor.
 * @ value   : all non zero bits will be tested.
 * @ returns true if at least one non zero bit in value is set / false otherwise. 
 ************************************************************************************/
inline bool_t page_is_flag( page_t   * page,
                            uint16_t   value );

/*************************************************************************************
 * This function synchronizes (i.e. update the disk) all dirty pages in a cluster.
 * It scan the PPM dirty list, that should be empty when this operation is completed. 
 ************************************************************************************/
void sync_all_pages();

/*************************************************************************************
 * This function set the PG_DIRTY flag in the page descriptor,
 * and register the page in the dirty list in PPM.
 * @ page     : pointer on page descriptor.
 * @ returns true if page was not dirty / returns false if page was dirty
 ************************************************************************************/
bool_t page_do_dirty( page_t * page );

/*************************************************************************************
 * This function reset the PG_DIRTY flag in the page descriptor,
 * and remove the page from the dirty list in PPM.
 * @ page     : pointer on page descriptor.
 * @ returns true if page was dirty / returns false if page was not dirty 
 ************************************************************************************/
bool_t page_undo_dirty( page_t * page );

/*************************************************************************************
 * This function makes a local copy of the content of a src page  to a dst page.
 * @ dst      : pointer on destination page descriptor.
 * @ src      : pointer on source page descriptor.
 ************************************************************************************/
void page_copy( page_t * dst,
                page_t * src );

/*************************************************************************************
 * This function reset to 0 all bytes in a given page. 
 * @ page     : pointer on page descriptor.
 ************************************************************************************/
void page_zero( page_t * page );

/*************************************************************************************
 * This blocking function set the PG_LOCKED flag on the page.
 * It deschedule if the page has already been locked by another thread,
 * and returns only when the flag has been successfully set. 
 * @ page     : pointer on page descriptor.
 ************************************************************************************/
void page_lock( page_t * page );

/*************************************************************************************
 * This blocking function reset the PG_LOCKED flag on the page, if there is no
 * other waiting thread. IF there is waiting thread(s), it activates the first
 * waiting thread without modifying the PG_LOCKED flag.
 * @ page     : pointer on page descriptor.
 ************************************************************************************/
void page_unlock( page_t * page );

/*************************************************************************************
 * This blocking function atomically increment the page refcount.
 * @ page     : pointer on page descriptor.
 ************************************************************************************/
inline void page_refcount_up( page_t * page );

/*************************************************************************************
 * This blocking function atomically decrement the page refcount.
 * @ page     : pointer on page descriptor.
 ************************************************************************************/
inline void page_refcount_down( page_t * page );

/*************************************************************************************
 * This function display the values contained in a page descriptor.
 ************************************************************************************/
void page_print( page_t * page );


#endif	/* _PAGE_H_ */
