#ifndef SERVER_MEMORY_H_INCLUDED
#define SERVER_MEMORY_H_INCLUDED

#include <object.h> /* For mem_alloc */


#define HAVE_STATIC_MEMORY_FOR_FILE(file) void* __server_static_holder_for_##file

/* Use these to access the global memory area */
#define SERVER_GLOBAL_VARIABLE( var_name ) server_memory_block->var_name

/* FIXME: This should magically be able to extract filename from somewhere and only take 1 parameter */
#define SERVER_STATIC_VARIABLE( file, var_name ) ((__server_static_memory_area_struct_for_file*)server_memory_block->__server_static_holder_for_##file)->var_name

/* Use these to define a variable static to a particular file */
#define STATIC_INITIALIZER_FUNCTION_DECLARATION( file ) void __server_init_static_memory_for_##file(void)
#define STATIC_INITIALIZER_FUNCTION_CALL(file) \
/* STATIC_INITIALIZER_FUNCTION_DECLARATION(file); older gcc has problem with this */\
__server_init_static_memory_for_##file()

#define STATIC_INITIALIZER_FUNCTION_DEFINITION(file) \
STATIC_INITIALIZER_FUNCTION_DECLARATION(file) { \
  server_memory_block->__server_static_holder_for_##file = mem_alloc( sizeof( __server_static_memory_area_struct_for_file ) ); \
  memset( server_memory_block->__server_static_holder_for_##file, 0, sizeof( __server_static_memory_area_struct_for_file ) ); \
}


#define START_FILE_STATIC_VARIABLES(file) typedef struct __server_static_memory_area_struct_for_file { 
#define END_FILE_STATIC_VARIABLES(file) } __server_static_memory_area_struct_for_file; \
STATIC_INITIALIZER_FUNCTION_DEFINITION(file)
#define END_FILE_STATIC_VARIABLES_NO_AUTO_INIT(file) } __server_static_memory_area_struct_for_file;


/* Initialized by init_memory_block() called in the wineserver context only */
typedef struct server_memory_area
{
  /* GLOBAL VARIABLES */
  /* server start time used for GetTickCount() */
  unsigned int server_start_ticks;

  /* List of threads in the system. Should figure a way to make it not global. */
  struct thread *first_thread;

  /* List of mappings between thread ids and thread structures  */
  struct thread_process_id_list *threadids;
  /* First entry in free list of thread ids */
  struct thread_process_id_list *first_free_threadid;
  /* Last entry in free list of thread ids */
  struct thread_process_id_list *last_free_threadid;

#if 0
  /* FIXME MOOF NOTE: Currently the threads and processes won't
     share the same IDs. ie. they come from the same pool. */
   /* List of mappings between process ids and process structures  */
  struct thread_process_id_list *processids;
  /* First entry in free list of process ids */
  struct thread_process_id_list *first_free_processid;
  /* Last entry in free list of process ids */
  struct thread_process_id_list *last_free_processid;
#endif
 
  /* global error code for when no thread is current */
  unsigned int global_error;

  /* Is the server using shared memory */
  int shared_memory_server;
  size_t shared_memory_server_size;
  void *shared_memory_server_addr;

  /* serverdir */
  char* serverdir;
  
  HAVE_STATIC_MEMORY_FOR_FILE( atom );
  HAVE_STATIC_MEMORY_FOR_FILE( cdrom_eject );
  HAVE_STATIC_MEMORY_FOR_FILE( console );
  HAVE_STATIC_MEMORY_FOR_FILE( distributed );
  HAVE_STATIC_MEMORY_FOR_FILE( file );
  HAVE_STATIC_MEMORY_FOR_FILE( handle );
  HAVE_STATIC_MEMORY_FOR_FILE( mapping );
  HAVE_STATIC_MEMORY_FOR_FILE( object );
  HAVE_STATIC_MEMORY_FOR_FILE( process );
  HAVE_STATIC_MEMORY_FOR_FILE( registry );
  HAVE_STATIC_MEMORY_FOR_FILE( rpc_epmap );
  HAVE_STATIC_MEMORY_FOR_FILE( select );
  HAVE_STATIC_MEMORY_FOR_FILE( thread );
  HAVE_STATIC_MEMORY_FOR_FILE( user );
  HAVE_STATIC_MEMORY_FOR_FILE( window );
  
  HAVE_STATIC_MEMORY_FOR_FILE( mem_global ); /* Does not need explict initializing */
  
  /* Global memory semaphore information */
  LONG sema_lock_count;
  pid_t sema_owning_tid;
  unsigned int sema_recursion_count;

  
} server_memory_area;

STATIC_INITIALIZER_FUNCTION_DECLARATION( atom );
STATIC_INITIALIZER_FUNCTION_DECLARATION( cdrom_eject );
STATIC_INITIALIZER_FUNCTION_DECLARATION( console );
STATIC_INITIALIZER_FUNCTION_DECLARATION( distributed );
STATIC_INITIALIZER_FUNCTION_DECLARATION( file );
STATIC_INITIALIZER_FUNCTION_DECLARATION( handle );
STATIC_INITIALIZER_FUNCTION_DECLARATION( mapping );
STATIC_INITIALIZER_FUNCTION_DECLARATION( object );
STATIC_INITIALIZER_FUNCTION_DECLARATION( process );
STATIC_INITIALIZER_FUNCTION_DECLARATION( registry );
STATIC_INITIALIZER_FUNCTION_DECLARATION( rpc_epmap );
STATIC_INITIALIZER_FUNCTION_DECLARATION( select );
STATIC_INITIALIZER_FUNCTION_DECLARATION( thread );
STATIC_INITIALIZER_FUNCTION_DECLARATION( user );
STATIC_INITIALIZER_FUNCTION_DECLARATION( window );
 

extern server_memory_area* server_memory_block;



/* PH: FIXME: Should actually provide full no shared memory versions for everything. */
#if defined(NO_SHARED_MEMORY)

  static inline void acquire_shm_server_semaphore_exclusive() {}
  static inline void acquire_shm_server_semaphore_shared( const void* locking_entity ) {}
  static inline void release_shm_server_semaphore(void) {}
  
#else

  extern void acquire_shm_server_semaphore_exclusive();
  extern void acquire_shm_server_semaphore_shared( const void* locking_entity );
  extern void release_shm_server_semaphore(void);

#endif

extern void* alloc_server_memory( size_t size );
extern void free_server_memory( void* ptr );

extern void set_shm_reserved(void *addr, const size_t size);

extern void* create_server_shared_memory_area( const char* pathname, int reg_size );
extern void* regular_memory_alloc( const char* pathname, int reg_size );
extern void init_memory_block( int shm );

extern int translate_server_fd( context_fd fd );
extern int send_timeout_to_wineserver( struct timeval *when, timeout_callback func,
                                 void *private);
extern int send_select_change_to_wineserver( struct object* obj, int events );
extern int send_remove_select_to_wineserver( struct object* obj );

#endif /* SERVER_MEMORY_H_INCLUDED */
