/*
 * Wine server objects
 *
 * Copyright (C) 1998 Alexandre Julliard
 */

#ifndef __WINE_SERVER_OBJECT_H
#define __WINE_SERVER_OBJECT_H

#include "config.h"

#include <sys/poll.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include "wine/server_protocol.h"

#define DEBUG_OBJECTS

/* kernel objects */

struct object;
struct object_name;
struct thread;
struct process;
struct file;
struct wait_queue_entry;
struct async;
struct async_queue;
struct token;

#define CONTEXTUAL_FD
#define CONTEXTUAL_OBJECT_FD

struct context_entry
{
  int valid;             /* Is this entry valid? */
  int fd;                /* What value is it? */
  unsigned int refcount; /* ref count on entry */
};

typedef unsigned int context_fd; /* In shared memory. This is the index. */
#define INVALID_CTX_FD ((context_fd)-1)

/* operations valid on all objects */
struct object_ops
{
    /* size of this object type */
    size_t size;
    /* dump the object (for debugging) */
    void (*dump)(struct object *,int);
    /* add a thread to the object wait queue */
    int  (*add_queue)(struct object *,struct wait_queue_entry *);
    /* remove a thread from the object wait queue */
    void (*remove_queue)(struct object *,struct wait_queue_entry *);
    /* is object signaled? */
    int  (*signaled)(struct object *,struct wait_queue_entry *entry);
    /* wait satisfied; return 1 if abandoned */
    int  (*satisfied)(struct object *,struct thread *);
    /* get the events we want to poll() for on this object */
    int  (*get_poll_events)(struct object *);
    /* a poll() event occured */
    void (*poll_event)(struct object *,int event);
    /* return a Unix fd that can be used to read/write from the object */
    int  (*get_fd)(struct object *);
#if defined( CONTEXTUAL_FD )
    /* return the contextual fd associated with the fd */
    context_fd (*get_ctx_fd)(struct object*);
#endif   
    /* flush the object buffers */
    int  (*flush)(struct object *);
    /* get file information */
    int  (*get_file_info)(struct object *,struct get_file_info_reply *, int *flags);
    /* queue an async operation - see register_async handler in async.c*/
    void (*queue_async)(struct object *, void* ptr, unsigned int status, int type, int count);
    /* destroy on refcount == 0 */
    void (*destroy)(struct object *);
};

struct object
{
    unsigned int              refcount;    /* reference count */
#if defined( CONTEXTUAL_OBJECT_FD )
    context_fd                fd;
#else
    int                       fd;          /* file descriptor */
#endif
    int                       select;      /* select() user id */
    const struct object_ops  *ops;
    struct wait_queue_entry  *head;
    struct wait_queue_entry  *tail;
    struct object_name       *name;
#ifdef DEBUG_OBJECTS
    struct object            *prev;
    struct object            *next;
#endif
};


struct wait_queue_entry
{
    struct wait_queue_entry *next;
    struct wait_queue_entry *prev;
    struct object           *obj;
    struct thread           *thread;

    struct thread           *poll_thread; /* Who's polling */
};

extern void* mem_alloc( size_t size );  /* malloc wrapper */
extern void* mem_alloc_no_init( size_t size );  /* malloc wrapper */
extern void  mem_free( void* ptr ); /* free wrapper */
extern void* mem_realloc( void* ptr, size_t size ); /* realloc wrapper */
extern void* mem_calloc( size_t nmemb, size_t size ); /* calloc wrapper */
extern char* mem_strdup( const char* s ); /* strdup wrapper */
extern void* mem_dup( const void *data, size_t len );

extern void *alloc_object( const struct object_ops *ops, int fd );
extern void dump_object_name( struct object *obj );
extern void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len );
/* grab/release_object can take any pointer, but you better make sure */
/* that the thing pointed to starts with a struct object... */
extern struct object *grab_object( void *obj );
extern unsigned int release_object( void *obj );
extern struct object *find_object( const WCHAR *name, size_t len );
extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
extern int no_satisfied( struct object *obj, struct thread *thread );
extern int no_get_fd( struct object *obj );
extern context_fd no_get_ctx_fd( struct object *obj );
extern int no_flush( struct object *obj );
extern int no_get_file_info( struct object *obj, struct get_file_info_reply *info, int *flags );
extern void no_destroy( struct object *obj );
extern int default_poll_add_queue( struct object *obj, struct wait_queue_entry *entry );
extern void default_poll_remove_queue( struct object *obj, struct wait_queue_entry *entry );
extern int default_poll_signaled( struct object *obj, struct wait_queue_entry *entry );
extern void default_poll_event( struct object *obj, int event );
#ifdef DEBUG_OBJECTS
extern void dump_objects(void);
#endif

int get_object_fd( const struct object* obj );
int get_object_untranslated_fd( const struct object* obj );
int get_object_fd_for_server( const struct object* obj );
int get_object_fd_for_client( const struct object* obj );
void set_object_fd( struct object* obj, int fd );
void close_object_fd( struct object* obj );

int get_context_fd( context_fd ctx_fd );
int get_context_untranslated_fd( context_fd ctx_fd, struct process* process );
void set_context_fd( context_fd* ctx_fd, int fd );
void set_context_fd_for_process( context_fd ctx_fd, int fd, struct process* process );
void init_context_fd( context_fd* ctx_fd, int fd );
void close_context_fd( context_fd* ctx_fd );
void grab_context_fd( context_fd ctx_fd, struct process* process );
void release_context_fd( context_fd ctx_fd, struct process* process, int* fd );

/* select functions */

struct shm_pollfd
{
    struct pollfd  fd_array[MAXIMUM_WAIT_OBJECTS+1];
    struct object* objects[MAXIMUM_WAIT_OBJECTS+1];
};

extern int add_select_user( struct object *obj );
extern void remove_select_user( struct object *obj );
extern void change_select_fd( struct object *obj, int fd, int events );
extern void set_select_events( struct object *obj, int events, struct thread* thread );
extern int check_select_events( int fd, int events );
extern void select_loop(void);
extern void update_pollfd_for_thread( void* pollfd, int* pollfds, int count );
extern void shm_poll_hit( const struct shm_pollfd* pollfd_copy,  unsigned int hits, unsigned int size );


/* timeout functions */

struct timeout_user;

typedef void (*timeout_callback)( void *private );

extern struct timeout_user *add_timeout_user( struct timeval *when,
                                              timeout_callback func, void *private );
extern void remove_timeout_user( struct timeout_user *user );
extern void add_timeout( struct timeval *when, int timeout );
extern int shm_handle_timeout(void);
/* return 1 if t1 is before t2 */
static inline int time_before( const struct timeval *t1, const struct timeval *t2 )
{
    return ((t1->tv_sec < t2->tv_sec) ||
            ((t1->tv_sec == t2->tv_sec) && (t1->tv_usec < t2->tv_usec)));
}

/* event functions */

struct event;

extern struct event *create_event( const WCHAR *name, size_t len,
                                   int manual_reset, int initial_state );
extern struct event *get_event_obj( struct process *process, handle_t handle, unsigned int access );
extern void pulse_event( struct event *event );
extern void set_event( struct event *event );
extern void reset_event( struct event *event );

/* mutex functions */

extern void abandon_mutexes( struct thread *thread );

/* file functions */

extern struct file *get_file_obj( struct process *process, handle_t handle,
                                  unsigned int access );
extern int is_same_file( struct file *file1, struct file *file2 );
extern int get_file_drive_type( struct file *file );
extern int grow_file( struct file *file, int size_high, int size_low );
extern int create_anonymous_file(void);
extern struct file *create_temp_file( int access );
extern void file_set_error(void);

/* serial functions */

int get_serial_async_timeout(struct object *obj, int type, int count);

/* socket functions */

extern void sock_init(void);

/* debugger functions */

extern int set_process_debugger( struct process *process, struct thread *debugger );
extern void generate_debug_event( struct thread *thread, int code, void *arg );
extern void generate_startup_debug_events( struct process *process, void *entry );
extern void debug_exit_thread( struct thread *thread );

/* mapping functions */

extern int get_page_size(void);

/* registry functions */

extern int get_registry_size(void);
extern void init_registry(void);
extern void close_registry(void);

/* atom functions */

extern void close_atom_table(void);
extern int grab_global_atom( atom_t atom );
extern void release_global_atom( atom_t atom );

/* token functions */

extern struct token *create_token( struct object *obj );

/* global variables */

/* command-line options */
extern int debug_level;
extern int persistent_server;
extern int wineserver_is_daemon;

/* PH: FIXME: Remove me */
extern int is_wineserver;

/* server start time used for GetTickCount() */
extern unsigned int server_start_ticks;

/* Since with the shared memory model the code segments might not be mapped to the
   same location, we can't use this "virtual" dispatch technique so we basically have
   to do a double dispatch.
 */
// PH: FIXME: Enum type?
extern const struct object_ops* get_ops( const struct object_ops* ops );
#define first_ops_tag_value 0xdeadf000
#define atom_table_ops_tag (const struct object_ops*)first_ops_tag_value
#define change_ops_tag (const struct object_ops*)0xdeadf001
#define console_input_ops_tag (const struct object_ops*)0xdeadf002
#define console_input_events_ops_tag (const struct object_ops*)0xdeadf003
#define screen_buffer_ops_tag (const struct object_ops*)0xdeadf004
#define debug_event_ops_tag (const struct object_ops*)0xdeadf005
#define debug_ctx_ops_tag (const struct object_ops*)0xdeadf006
#define device_ops_tag (const struct object_ops*)0xdeadf007
#define event_ops_tag (const struct object_ops*)0xdeadf008
#define file_ops_tag (const struct object_ops*)0xdeadf009
#define handle_table_ops_tag (const struct object_ops*)0xdeadf00b
#define mapping_ops_tag (const struct object_ops*)0xdeadf00c
#define mutex_ops_tag (const struct object_ops*)0xdeadf00d
#define named_pipe_ops_tag (const struct object_ops*)0xdeadf00e
#define pipe_user_ops_tag (const struct object_ops*)0xdeadf00f
#define process_ops_tag (const struct object_ops*)0xdeadf010
#define startup_info_ops_tag (const struct object_ops*)0xdeadf011
#define msg_queue_ops_tag (const struct object_ops*)0xdeadf012
#define key_ops_tag (const struct object_ops*)0xdeadf013
#define master_socket_ops_tag (const struct object_ops*)0xdeadf014
#define semaphore_ops_tag (const struct object_ops*)0xdeadf015
#define serial_ops_tag (const struct object_ops*)0xdeadf016
#define snapshot_ops_tag (const struct object_ops*)0xdeadf017
#define sock_ops_tag (const struct object_ops*)0xdeadf018
#define thread_ops_tag (const struct object_ops*)0xdeadf019
#define timer_ops_tag (const struct object_ops*)0xdeadf01a
#define fd_server_ops_tag (const struct object_ops*)0xdeadf01b
#define distributed_commands_ops_tag (const struct object_ops*)0xdeadf01c
#define last_ops_tag_value 0xdeadf01d
#define token_ops_tag (const struct object_ops*)last_ops_tag_value


typedef const struct object_ops* (*ops_function)(void);
extern const struct object_ops* get_this_process_atom_table_ops(void);
extern const struct object_ops* get_this_process_change_ops(void);
extern const struct object_ops* get_this_process_console_input_ops(void);
extern const struct object_ops* get_this_process_console_input_events_ops(void);
extern const struct object_ops* get_this_process_screen_buffer_ops(void);
extern const struct object_ops* get_this_process_debug_event_ops(void);
extern const struct object_ops* get_this_process_debug_ctx_ops(void);
extern const struct object_ops* get_this_process_device_ops(void);
extern const struct object_ops* get_this_process_event_ops(void);
extern const struct object_ops* get_this_process_file_ops(void);

#if ENABLE_GDB_REMOTE
extern const struct object_ops* get_this_process_remote_gdb_ops(void);
extern const struct object_ops* get_this_process_gdb_socket_ops(void);
#endif

extern const struct object_ops* get_this_process_handle_table_ops(void);
extern const struct object_ops* get_this_process_mapping_ops(void);
extern const struct object_ops* get_this_process_mutex_ops(void);
extern const struct object_ops* get_this_process_named_pipe_ops(void);
extern const struct object_ops* get_this_process_pipe_user_ops(void);
extern const struct object_ops* get_this_process_process_ops(void);
extern const struct object_ops* get_this_process_startup_info_ops(void);
extern const struct object_ops* get_this_process_msg_queue_ops(void);
extern const struct object_ops* get_this_process_key_ops(void);
extern const struct object_ops* get_this_process_master_socket_ops(void);
extern const struct object_ops* get_this_process_semaphore_ops(void);
extern const struct object_ops* get_this_process_serial_ops(void);
extern const struct object_ops* get_this_process_snapshot_ops(void);
extern const struct object_ops* get_this_process_sock_ops(void);
extern const struct object_ops* get_this_process_thread_ops(void);
extern const struct object_ops* get_this_process_timer_ops(void);
extern const struct object_ops* get_this_process_fd_server_ops(void);
extern const struct object_ops* get_this_process_distributed_commands_ops(void);
extern const struct object_ops* get_this_process_token_ops(void);

extern timeout_callback get_callback( timeout_callback cb );

// PH: FIXME: make enum?
#define first_callback_tag_value 0xdeade000                                                                                                                                                                      
#define queue_timer_timeout_callback_tag     (timeout_callback)first_callback_tag_value
#define timer_timer_timeout_callback_tag     (timeout_callback)0xdeade001
#define queue_result_timeout_callback_tag    (timeout_callback)0xdeade002
#define async_callback_tag                   (timeout_callback)0xdeade003
#define periodic_save_callback_tag           (timeout_callback)0xdeade004
#define cdrom_eject_callback_tag             (timeout_callback)0xdeade005
#define last_callback_tag_value 0xdeade006
#define thread_thread_timeout_callback_tag   (timeout_callback)last_callback_tag_value

                                                                                                                                                                      
typedef timeout_callback (*get_callback_function)(void);
extern timeout_callback get_queue_timer_timeout_callback(void);
extern timeout_callback get_timer_timer_timeout_callback(void);
extern timeout_callback get_queue_result_timeout_callback(void);
extern timeout_callback get_thread_thread_timeout_callback(void);
extern timeout_callback get_async_callback(void);
extern timeout_callback get_periodic_save_callback(void);
extern timeout_callback get_cdrom_eject_callback(void);
                                                                                                                                                                      
/* Timeout functions */
extern long perform_timeout_check(void);



#endif  /* __WINE_SERVER_OBJECT_H */
