Server reorganization:
- moved request handlers to the specific C files - moved handle management to handle.c - moved server private includes to server/ instead of include/server/
This commit is contained in:
parent
51662375c5
commit
43c190e7ba
|
@ -30,6 +30,9 @@ struct cmsg_fd
|
|||
int fd; /* fd to pass */
|
||||
};
|
||||
|
||||
/* request handler definition */
|
||||
#define DECL_HANDLER(name) \
|
||||
void req_##name( struct name##_request *req, void *data, int len, int fd )
|
||||
|
||||
/* Request structures */
|
||||
|
||||
|
@ -314,6 +317,19 @@ struct event_op_request
|
|||
enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
|
||||
|
||||
|
||||
/* Open an event */
|
||||
struct open_event_request
|
||||
{
|
||||
unsigned int access; /* wanted access rights */
|
||||
int inherit; /* inherit flag */
|
||||
char name[0]; /* object name */
|
||||
};
|
||||
struct open_event_reply
|
||||
{
|
||||
int handle; /* handle to the event */
|
||||
};
|
||||
|
||||
|
||||
/* Create a mutex */
|
||||
struct create_mutex_request
|
||||
{
|
||||
|
@ -334,6 +350,19 @@ struct release_mutex_request
|
|||
};
|
||||
|
||||
|
||||
/* Open a mutex */
|
||||
struct open_mutex_request
|
||||
{
|
||||
unsigned int access; /* wanted access rights */
|
||||
int inherit; /* inherit flag */
|
||||
char name[0]; /* object name */
|
||||
};
|
||||
struct open_mutex_reply
|
||||
{
|
||||
int handle; /* handle to the mutex */
|
||||
};
|
||||
|
||||
|
||||
/* Create a semaphore */
|
||||
struct create_semaphore_request
|
||||
{
|
||||
|
@ -360,19 +389,16 @@ struct release_semaphore_reply
|
|||
};
|
||||
|
||||
|
||||
/* Open a named object (event, mutex, semaphore) */
|
||||
struct open_named_obj_request
|
||||
/* Open a semaphore */
|
||||
struct open_semaphore_request
|
||||
{
|
||||
int type; /* object type (see below) */
|
||||
unsigned int access; /* wanted access rights */
|
||||
int inherit; /* inherit flag */
|
||||
char name[0]; /* object name */
|
||||
};
|
||||
enum open_named_obj { OPEN_EVENT, OPEN_MUTEX, OPEN_SEMAPHORE, OPEN_MAPPING };
|
||||
|
||||
struct open_named_obj_reply
|
||||
struct open_semaphore_reply
|
||||
{
|
||||
int handle; /* handle to the object */
|
||||
int handle; /* handle to the semaphore */
|
||||
};
|
||||
|
||||
|
||||
|
@ -640,6 +666,19 @@ struct create_mapping_reply
|
|||
#define VPROT_COMMITTED 0x40
|
||||
|
||||
|
||||
/* Open a mapping */
|
||||
struct open_mapping_request
|
||||
{
|
||||
unsigned int access; /* wanted access rights */
|
||||
int inherit; /* inherit flag */
|
||||
char name[0]; /* object name */
|
||||
};
|
||||
struct open_mapping_reply
|
||||
{
|
||||
int handle; /* handle to the mapping */
|
||||
};
|
||||
|
||||
|
||||
/* Get information about a file mapping */
|
||||
struct get_mapping_info_request
|
||||
{
|
||||
|
@ -692,12 +731,13 @@ struct next_process_reply
|
|||
};
|
||||
|
||||
|
||||
/* requests definitions */
|
||||
#include "server/request.h"
|
||||
|
||||
/* client-side functions */
|
||||
|
||||
#ifndef __WINE_SERVER__
|
||||
|
||||
#include "server/request.h"
|
||||
|
||||
/* client communication functions */
|
||||
extern void CLIENT_SendRequest( enum request req, int pass_fd,
|
||||
int n, ... /* arg_1, len_1, etc. */ );
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Wine server processes
|
||||
*
|
||||
* Copyright (C) 1999 Alexandre Julliard
|
||||
*/
|
||||
|
||||
#ifndef __WINE_SERVER_PROCESS_H
|
||||
#define __WINE_SERVER_PROCESS_H
|
||||
|
||||
#ifndef __WINE_SERVER__
|
||||
#error This file can only be used in the Wine server
|
||||
#endif
|
||||
|
||||
#include "server/object.h"
|
||||
|
||||
/* process structures */
|
||||
|
||||
struct process;
|
||||
|
||||
struct process_snapshot
|
||||
{
|
||||
struct process *process; /* process ptr */
|
||||
struct process *parent; /* process parent */
|
||||
int threads; /* number of threads */
|
||||
int priority; /* priority class */
|
||||
};
|
||||
|
||||
/* process functions */
|
||||
|
||||
extern struct process *create_initial_process(void);
|
||||
extern struct process *create_process( struct new_process_request *req );
|
||||
extern struct process *get_process_from_id( void *id );
|
||||
extern struct process *get_process_from_handle( int handle, unsigned int access );
|
||||
extern int get_process_init_info( struct process *process, struct init_process_reply *reply );
|
||||
extern void add_process_thread( struct process *process,
|
||||
struct thread *thread );
|
||||
extern void remove_process_thread( struct process *process,
|
||||
struct thread *thread );
|
||||
extern void kill_process( struct process *process, int exit_code );
|
||||
extern void get_process_info( struct process *process,
|
||||
struct get_process_info_reply *reply );
|
||||
extern void set_process_info( struct process *process,
|
||||
struct set_process_info_request *req );
|
||||
extern int alloc_console( struct process *process );
|
||||
extern int free_console( struct process *process );
|
||||
extern struct object *get_console( struct process *process, int output );
|
||||
extern struct process_snapshot *process_snap( int *count );
|
||||
|
||||
/* handle functions */
|
||||
|
||||
/* alloc_handle takes a void *obj for convenience, but you better make sure */
|
||||
/* that the thing pointed to starts with a struct object... */
|
||||
extern int alloc_handle( struct process *process, void *obj,
|
||||
unsigned int access, int inherit );
|
||||
extern int close_handle( struct process *process, int handle );
|
||||
extern int set_handle_info( struct process *process, int handle,
|
||||
int mask, int flags );
|
||||
extern struct object *get_handle_obj( struct process *process, int handle,
|
||||
unsigned int access, const struct object_ops *ops );
|
||||
extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
|
||||
unsigned int access, int inherit, int options );
|
||||
extern int open_object( const char *name, const struct object_ops *ops,
|
||||
unsigned int access, int inherit );
|
||||
|
||||
#endif /* __WINE_SERVER_PROCESS_H */
|
|
@ -28,11 +28,13 @@ enum request
|
|||
REQ_SELECT,
|
||||
REQ_CREATE_EVENT,
|
||||
REQ_EVENT_OP,
|
||||
REQ_OPEN_EVENT,
|
||||
REQ_CREATE_MUTEX,
|
||||
REQ_RELEASE_MUTEX,
|
||||
REQ_OPEN_MUTEX,
|
||||
REQ_CREATE_SEMAPHORE,
|
||||
REQ_RELEASE_SEMAPHORE,
|
||||
REQ_OPEN_NAMED_OBJ,
|
||||
REQ_OPEN_SEMAPHORE,
|
||||
REQ_CREATE_FILE,
|
||||
REQ_GET_READ_FD,
|
||||
REQ_GET_WRITE_FD,
|
||||
|
@ -56,6 +58,7 @@ enum request
|
|||
REQ_READ_CONSOLE_INPUT,
|
||||
REQ_CREATE_CHANGE_NOTIFICATION,
|
||||
REQ_CREATE_MAPPING,
|
||||
REQ_OPEN_MAPPING,
|
||||
REQ_GET_MAPPING_INFO,
|
||||
REQ_CREATE_DEVICE,
|
||||
REQ_CREATE_SNAPSHOT,
|
||||
|
@ -65,9 +68,6 @@ enum request
|
|||
|
||||
#ifdef WANT_REQUEST_HANDLERS
|
||||
|
||||
#define DECL_HANDLER(name) \
|
||||
static void req_##name( struct name##_request *req, void *data, int len, int fd )
|
||||
|
||||
DECL_HANDLER(new_process);
|
||||
DECL_HANDLER(new_thread);
|
||||
DECL_HANDLER(set_debug);
|
||||
|
@ -91,11 +91,13 @@ DECL_HANDLER(open_process);
|
|||
DECL_HANDLER(select);
|
||||
DECL_HANDLER(create_event);
|
||||
DECL_HANDLER(event_op);
|
||||
DECL_HANDLER(open_event);
|
||||
DECL_HANDLER(create_mutex);
|
||||
DECL_HANDLER(release_mutex);
|
||||
DECL_HANDLER(open_mutex);
|
||||
DECL_HANDLER(create_semaphore);
|
||||
DECL_HANDLER(release_semaphore);
|
||||
DECL_HANDLER(open_named_obj);
|
||||
DECL_HANDLER(open_semaphore);
|
||||
DECL_HANDLER(create_file);
|
||||
DECL_HANDLER(get_read_fd);
|
||||
DECL_HANDLER(get_write_fd);
|
||||
|
@ -119,6 +121,7 @@ DECL_HANDLER(write_console_input);
|
|||
DECL_HANDLER(read_console_input);
|
||||
DECL_HANDLER(create_change_notification);
|
||||
DECL_HANDLER(create_mapping);
|
||||
DECL_HANDLER(open_mapping);
|
||||
DECL_HANDLER(get_mapping_info);
|
||||
DECL_HANDLER(create_device);
|
||||
DECL_HANDLER(create_snapshot);
|
||||
|
@ -151,11 +154,13 @@ static const struct handler {
|
|||
{ (void(*)())req_select, sizeof(struct select_request) },
|
||||
{ (void(*)())req_create_event, sizeof(struct create_event_request) },
|
||||
{ (void(*)())req_event_op, sizeof(struct event_op_request) },
|
||||
{ (void(*)())req_open_event, sizeof(struct open_event_request) },
|
||||
{ (void(*)())req_create_mutex, sizeof(struct create_mutex_request) },
|
||||
{ (void(*)())req_release_mutex, sizeof(struct release_mutex_request) },
|
||||
{ (void(*)())req_open_mutex, sizeof(struct open_mutex_request) },
|
||||
{ (void(*)())req_create_semaphore, sizeof(struct create_semaphore_request) },
|
||||
{ (void(*)())req_release_semaphore, sizeof(struct release_semaphore_request) },
|
||||
{ (void(*)())req_open_named_obj, sizeof(struct open_named_obj_request) },
|
||||
{ (void(*)())req_open_semaphore, sizeof(struct open_semaphore_request) },
|
||||
{ (void(*)())req_create_file, sizeof(struct create_file_request) },
|
||||
{ (void(*)())req_get_read_fd, sizeof(struct get_read_fd_request) },
|
||||
{ (void(*)())req_get_write_fd, sizeof(struct get_write_fd_request) },
|
||||
|
@ -179,6 +184,7 @@ static const struct handler {
|
|||
{ (void(*)())req_read_console_input, sizeof(struct read_console_input_request) },
|
||||
{ (void(*)())req_create_change_notification, sizeof(struct create_change_notification_request) },
|
||||
{ (void(*)())req_create_mapping, sizeof(struct create_mapping_request) },
|
||||
{ (void(*)())req_open_mapping, sizeof(struct open_mapping_request) },
|
||||
{ (void(*)())req_get_mapping_info, sizeof(struct get_mapping_info_request) },
|
||||
{ (void(*)())req_create_device, sizeof(struct create_device_request) },
|
||||
{ (void(*)())req_create_snapshot, sizeof(struct create_snapshot_request) },
|
||||
|
|
|
@ -1118,14 +1118,13 @@ HANDLE WINAPI OpenFileMappingA(
|
|||
BOOL inherit, /* [in] Inherit flag */
|
||||
LPCSTR name ) /* [in] Name of file-mapping object */
|
||||
{
|
||||
struct open_named_obj_request req;
|
||||
struct open_named_obj_reply reply;
|
||||
struct open_mapping_request req;
|
||||
struct open_mapping_reply reply;
|
||||
int len = name ? strlen(name) + 1 : 0;
|
||||
|
||||
req.type = OPEN_MAPPING;
|
||||
req.access = access;
|
||||
req.inherit = inherit;
|
||||
CLIENT_SendRequest( REQ_OPEN_NAMED_OBJ, -1, 2, &req, sizeof(req), name, len );
|
||||
CLIENT_SendRequest( REQ_OPEN_MAPPING, -1, 2, &req, sizeof(req), name, len );
|
||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
||||
if (reply.handle == -1) return 0; /* must return 0 on failure, not -1 */
|
||||
return reply.handle;
|
||||
|
|
|
@ -60,14 +60,13 @@ HANDLE WINAPI WIN16_CreateEvent( BOOL manual_reset, BOOL initial_state )
|
|||
*/
|
||||
HANDLE WINAPI OpenEventA( DWORD access, BOOL inherit, LPCSTR name )
|
||||
{
|
||||
struct open_named_obj_request req;
|
||||
struct open_named_obj_reply reply;
|
||||
struct open_event_request req;
|
||||
struct open_event_reply reply;
|
||||
int len = name ? strlen(name) + 1 : 0;
|
||||
|
||||
req.type = OPEN_EVENT;
|
||||
req.access = access;
|
||||
req.inherit = inherit;
|
||||
CLIENT_SendRequest( REQ_OPEN_NAMED_OBJ, -1, 2, &req, sizeof(req), name, len );
|
||||
CLIENT_SendRequest( REQ_OPEN_EVENT, -1, 2, &req, sizeof(req), name, len );
|
||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
||||
if (reply.handle == -1) return 0; /* must return 0 on failure, not -1 */
|
||||
return (HANDLE)reply.handle;
|
||||
|
|
|
@ -49,14 +49,13 @@ HANDLE WINAPI CreateMutexW( SECURITY_ATTRIBUTES *sa, BOOL owner,
|
|||
*/
|
||||
HANDLE WINAPI OpenMutexA( DWORD access, BOOL inherit, LPCSTR name )
|
||||
{
|
||||
struct open_named_obj_request req;
|
||||
struct open_named_obj_reply reply;
|
||||
struct open_mutex_request req;
|
||||
struct open_mutex_reply reply;
|
||||
int len = name ? strlen(name) + 1 : 0;
|
||||
|
||||
req.type = OPEN_MUTEX;
|
||||
req.access = access;
|
||||
req.inherit = inherit;
|
||||
CLIENT_SendRequest( REQ_OPEN_NAMED_OBJ, -1, 2, &req, sizeof(req), name, len );
|
||||
CLIENT_SendRequest( REQ_OPEN_MUTEX, -1, 2, &req, sizeof(req), name, len );
|
||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
||||
if (reply.handle == -1) return 0; /* must return 0 on failure, not -1 */
|
||||
return reply.handle;
|
||||
|
|
|
@ -60,14 +60,13 @@ HANDLE WINAPI CreateSemaphoreW( SECURITY_ATTRIBUTES *sa, LONG initial,
|
|||
*/
|
||||
HANDLE WINAPI OpenSemaphoreA( DWORD access, BOOL inherit, LPCSTR name )
|
||||
{
|
||||
struct open_named_obj_request req;
|
||||
struct open_named_obj_reply reply;
|
||||
struct open_semaphore_request req;
|
||||
struct open_semaphore_reply reply;
|
||||
int len = name ? strlen(name) + 1 : 0;
|
||||
|
||||
req.type = OPEN_SEMAPHORE;
|
||||
req.access = access;
|
||||
req.inherit = inherit;
|
||||
CLIENT_SendRequest( REQ_OPEN_NAMED_OBJ, -1, 2, &req, sizeof(req), name, len );
|
||||
CLIENT_SendRequest( REQ_OPEN_SEMAPHORE, -1, 2, &req, sizeof(req), name, len );
|
||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
||||
if (reply.handle == -1) return 0; /* must return 0 on failure, not -1 */
|
||||
return reply.handle;
|
||||
|
|
|
@ -11,6 +11,7 @@ C_SRCS = \
|
|||
device.c \
|
||||
event.c \
|
||||
file.c \
|
||||
handle.c \
|
||||
mapping.c \
|
||||
mutex.c \
|
||||
object.c \
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
|
||||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct change
|
||||
{
|
||||
|
@ -38,7 +40,7 @@ static const struct object_ops change_ops =
|
|||
};
|
||||
|
||||
|
||||
struct object *create_change_notification( int subtree, int filter )
|
||||
static struct object *create_change_notification( int subtree, int filter )
|
||||
{
|
||||
struct change *change;
|
||||
if (!(change = mem_alloc( sizeof(*change) ))) return NULL;
|
||||
|
@ -69,3 +71,18 @@ static void change_destroy( struct object *obj )
|
|||
assert( obj->ops == &change_ops );
|
||||
free( change );
|
||||
}
|
||||
|
||||
/* create a change notification */
|
||||
DECL_HANDLER(create_change_notification)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_change_notification_reply reply = { -1 };
|
||||
|
||||
if ((obj = create_change_notification( req->subtree, req->filter )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj,
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
|
108
server/console.c
108
server/console.c
|
@ -23,8 +23,10 @@
|
|||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "wincon.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "process.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct screen_buffer;
|
||||
|
||||
|
@ -153,7 +155,7 @@ int create_console( int fd, struct object *obj[2] )
|
|||
return 1;
|
||||
}
|
||||
|
||||
int set_console_fd( int handle, int fd, int pid )
|
||||
static int set_console_fd( int handle, int fd, int pid )
|
||||
{
|
||||
struct console_input *input;
|
||||
struct screen_buffer *output;
|
||||
|
@ -206,7 +208,7 @@ int set_console_fd( int handle, int fd, int pid )
|
|||
return 1;
|
||||
}
|
||||
|
||||
int get_console_mode( int handle, int *mode )
|
||||
static int get_console_mode( int handle, int *mode )
|
||||
{
|
||||
struct object *obj;
|
||||
int ret = 0;
|
||||
|
@ -228,7 +230,7 @@ int get_console_mode( int handle, int *mode )
|
|||
return ret;
|
||||
}
|
||||
|
||||
int set_console_mode( int handle, int mode )
|
||||
static int set_console_mode( int handle, int mode )
|
||||
{
|
||||
struct object *obj;
|
||||
int ret = 0;
|
||||
|
@ -251,7 +253,7 @@ int set_console_mode( int handle, int mode )
|
|||
}
|
||||
|
||||
/* set misc console information (output handle only) */
|
||||
int set_console_info( int handle, struct set_console_info_request *req, const char *title )
|
||||
static int set_console_info( int handle, struct set_console_info_request *req, const char *title )
|
||||
{
|
||||
struct screen_buffer *console;
|
||||
if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
|
||||
|
@ -272,7 +274,7 @@ int set_console_info( int handle, struct set_console_info_request *req, const ch
|
|||
}
|
||||
|
||||
/* get misc console information (output handle only) */
|
||||
int get_console_info( int handle, struct get_console_info_reply *reply, const char **title )
|
||||
static int get_console_info( int handle, struct get_console_info_reply *reply, const char **title )
|
||||
{
|
||||
struct screen_buffer *console;
|
||||
if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
|
||||
|
@ -287,7 +289,7 @@ int get_console_info( int handle, struct get_console_info_reply *reply, const ch
|
|||
}
|
||||
|
||||
/* add input events to a console input queue */
|
||||
int write_console_input( int handle, int count, INPUT_RECORD *records )
|
||||
static int write_console_input( int handle, int count, INPUT_RECORD *records )
|
||||
{
|
||||
INPUT_RECORD *new_rec;
|
||||
struct console_input *console;
|
||||
|
@ -310,7 +312,7 @@ int write_console_input( int handle, int count, INPUT_RECORD *records )
|
|||
}
|
||||
|
||||
/* retrieve a pointer to the console input records */
|
||||
int read_console_input( int handle, int count, int flush )
|
||||
static int read_console_input( int handle, int count, int flush )
|
||||
{
|
||||
struct console_input *console;
|
||||
|
||||
|
@ -472,3 +474,91 @@ static void screen_buffer_destroy( struct object *obj )
|
|||
if (console->title) free( console->title );
|
||||
free( console );
|
||||
}
|
||||
|
||||
/* allocate a console for the current process */
|
||||
DECL_HANDLER(alloc_console)
|
||||
{
|
||||
alloc_console( current->process );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* free the console of the current process */
|
||||
DECL_HANDLER(free_console)
|
||||
{
|
||||
free_console( current->process );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* open a handle to the process console */
|
||||
DECL_HANDLER(open_console)
|
||||
{
|
||||
struct object *obj;
|
||||
struct open_console_reply reply = { -1 };
|
||||
if ((obj = get_console( current->process, req->output )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set info about a console (output only) */
|
||||
DECL_HANDLER(set_console_info)
|
||||
{
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "set_console_info", name, len );
|
||||
set_console_info( req->handle, req, name );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get info about a console (output only) */
|
||||
DECL_HANDLER(get_console_info)
|
||||
{
|
||||
struct get_console_info_reply reply;
|
||||
const char *title;
|
||||
get_console_info( req->handle, &reply, &title );
|
||||
send_reply( current, -1, 2, &reply, sizeof(reply),
|
||||
title, title ? strlen(title)+1 : 0 );
|
||||
}
|
||||
|
||||
/* set a console fd */
|
||||
DECL_HANDLER(set_console_fd)
|
||||
{
|
||||
set_console_fd( req->handle, fd, req->pid );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get a console mode (input or output) */
|
||||
DECL_HANDLER(get_console_mode)
|
||||
{
|
||||
struct get_console_mode_reply reply;
|
||||
get_console_mode( req->handle, &reply.mode );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set a console mode (input or output) */
|
||||
DECL_HANDLER(set_console_mode)
|
||||
{
|
||||
set_console_mode( req->handle, req->mode );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* add input records to a console input queue */
|
||||
DECL_HANDLER(write_console_input)
|
||||
{
|
||||
struct write_console_input_reply reply;
|
||||
INPUT_RECORD *records = (INPUT_RECORD *)data;
|
||||
|
||||
if (len != req->count * sizeof(INPUT_RECORD))
|
||||
fatal_protocol_error( "write_console_input: bad length %d for %d records\n",
|
||||
len, req->count );
|
||||
reply.written = write_console_input( req->handle, req->count, records );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* fetch input records from a console input queue */
|
||||
DECL_HANDLER(read_console_input)
|
||||
{
|
||||
read_console_input( req->handle, req->count, req->flush );
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
#include "winerror.h"
|
||||
#include "winbase.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct device
|
||||
{
|
||||
|
@ -44,7 +46,7 @@ static const struct object_ops device_ops =
|
|||
device_destroy
|
||||
};
|
||||
|
||||
struct object *create_device( int id )
|
||||
static struct object *create_device( int id )
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
|
@ -77,3 +79,18 @@ static void device_destroy( struct object *obj )
|
|||
assert( obj->ops == &device_ops );
|
||||
free( dev );
|
||||
}
|
||||
|
||||
/* create a device */
|
||||
DECL_HANDLER(create_device)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_device_reply reply = { -1 };
|
||||
|
||||
if ((obj = create_device( req->id )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj,
|
||||
req->access, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct event
|
||||
{
|
||||
|
@ -40,7 +41,7 @@ static const struct object_ops event_ops =
|
|||
};
|
||||
|
||||
|
||||
struct object *create_event( const char *name, int manual_reset, int initial_state )
|
||||
static struct object *create_event( const char *name, int manual_reset, int initial_state )
|
||||
{
|
||||
struct event *event;
|
||||
|
||||
|
@ -55,12 +56,7 @@ struct object *create_event( const char *name, int manual_reset, int initial_sta
|
|||
return &event->obj;
|
||||
}
|
||||
|
||||
int open_event( unsigned int access, int inherit, const char *name )
|
||||
{
|
||||
return open_object( name, &event_ops, access, inherit );
|
||||
}
|
||||
|
||||
int pulse_event( int handle )
|
||||
static int pulse_event( int handle )
|
||||
{
|
||||
struct event *event;
|
||||
|
||||
|
@ -75,7 +71,7 @@ int pulse_event( int handle )
|
|||
return 1;
|
||||
}
|
||||
|
||||
int set_event( int handle )
|
||||
static int set_event( int handle )
|
||||
{
|
||||
struct event *event;
|
||||
|
||||
|
@ -89,7 +85,7 @@ int set_event( int handle )
|
|||
return 1;
|
||||
}
|
||||
|
||||
int reset_event( int handle )
|
||||
static int reset_event( int handle )
|
||||
{
|
||||
struct event *event;
|
||||
|
||||
|
@ -132,3 +128,53 @@ static void event_destroy( struct object *obj )
|
|||
assert( obj->ops == &event_ops );
|
||||
free( event );
|
||||
}
|
||||
|
||||
/* create an event */
|
||||
DECL_HANDLER(create_event)
|
||||
{
|
||||
struct create_event_reply reply = { -1 };
|
||||
struct object *obj;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_event", name, len );
|
||||
|
||||
obj = create_event( name, req->manual_reset, req->initial_state );
|
||||
if (obj)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, EVENT_ALL_ACCESS, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* open a handle to an event */
|
||||
DECL_HANDLER(open_event)
|
||||
{
|
||||
struct open_event_reply reply;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "open_event", name, len );
|
||||
|
||||
reply.handle = open_object( name, &event_ops, req->access, req->inherit );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* do an event operation */
|
||||
DECL_HANDLER(event_op)
|
||||
{
|
||||
switch(req->op)
|
||||
{
|
||||
case PULSE_EVENT:
|
||||
pulse_event( req->handle );
|
||||
break;
|
||||
case SET_EVENT:
|
||||
set_event( req->handle );
|
||||
break;
|
||||
case RESET_EVENT:
|
||||
reset_event( req->handle );
|
||||
break;
|
||||
default:
|
||||
fatal_protocol_error( "event_op: invalid operation %d\n", req->op );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
|
149
server/file.c
149
server/file.c
|
@ -20,8 +20,9 @@
|
|||
|
||||
#include "winerror.h"
|
||||
#include "winbase.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct file
|
||||
{
|
||||
|
@ -98,8 +99,8 @@ static int check_sharing( const char *name, int hash, unsigned int access,
|
|||
return 1;
|
||||
}
|
||||
|
||||
struct object *create_file( int fd, const char *name, unsigned int access,
|
||||
unsigned int sharing, int create, unsigned int attrs )
|
||||
static struct object *create_file( int fd, const char *name, unsigned int access,
|
||||
unsigned int sharing, int create, unsigned int attrs )
|
||||
{
|
||||
struct file *file;
|
||||
int hash = 0;
|
||||
|
@ -399,7 +400,7 @@ int file_get_mmap_fd( struct file *file )
|
|||
return dup( file->fd );
|
||||
}
|
||||
|
||||
int set_file_pointer( int handle, int *low, int *high, int whence )
|
||||
static int set_file_pointer( int handle, int *low, int *high, int whence )
|
||||
{
|
||||
struct file *file;
|
||||
int result;
|
||||
|
@ -428,7 +429,7 @@ int set_file_pointer( int handle, int *low, int *high, int whence )
|
|||
return 1;
|
||||
}
|
||||
|
||||
int truncate_file( int handle )
|
||||
static int truncate_file( int handle )
|
||||
{
|
||||
struct file *file;
|
||||
int result;
|
||||
|
@ -468,7 +469,7 @@ int grow_file( struct file *file, int size_high, int size_low )
|
|||
return 0;
|
||||
}
|
||||
|
||||
int set_file_time( int handle, time_t access_time, time_t write_time )
|
||||
static int set_file_time( int handle, time_t access_time, time_t write_time )
|
||||
{
|
||||
struct file *file;
|
||||
struct utimbuf utimbuf;
|
||||
|
@ -493,16 +494,142 @@ int set_file_time( int handle, time_t access_time, time_t write_time )
|
|||
return 0;
|
||||
}
|
||||
|
||||
int file_lock( struct file *file, int offset_high, int offset_low,
|
||||
int count_high, int count_low )
|
||||
static int file_lock( struct file *file, int offset_high, int offset_low,
|
||||
int count_high, int count_low )
|
||||
{
|
||||
/* FIXME: implement this */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int file_unlock( struct file *file, int offset_high, int offset_low,
|
||||
int count_high, int count_low )
|
||||
static int file_unlock( struct file *file, int offset_high, int offset_low,
|
||||
int count_high, int count_low )
|
||||
{
|
||||
/* FIXME: implement this */
|
||||
return 1;
|
||||
}
|
||||
/* create a file */
|
||||
DECL_HANDLER(create_file)
|
||||
{
|
||||
struct create_file_reply reply = { -1 };
|
||||
struct object *obj;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_file", name, len );
|
||||
|
||||
if ((obj = create_file( fd, name, req->access,
|
||||
req->sharing, req->create, req->attrs )) != NULL)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* get a Unix fd to read from a file */
|
||||
DECL_HANDLER(get_read_fd)
|
||||
{
|
||||
struct object *obj;
|
||||
int read_fd;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_READ, NULL )))
|
||||
{
|
||||
read_fd = obj->ops->get_read_fd( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
else read_fd = -1;
|
||||
send_reply( current, read_fd, 0 );
|
||||
}
|
||||
|
||||
/* get a Unix fd to write to a file */
|
||||
DECL_HANDLER(get_write_fd)
|
||||
{
|
||||
struct object *obj;
|
||||
int write_fd;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_WRITE, NULL )))
|
||||
{
|
||||
write_fd = obj->ops->get_write_fd( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
else write_fd = -1;
|
||||
send_reply( current, write_fd, 0 );
|
||||
}
|
||||
|
||||
/* set a file current position */
|
||||
DECL_HANDLER(set_file_pointer)
|
||||
{
|
||||
struct set_file_pointer_reply reply;
|
||||
reply.low = req->low;
|
||||
reply.high = req->high;
|
||||
set_file_pointer( req->handle, &reply.low, &reply.high, req->whence );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* truncate (or extend) a file */
|
||||
DECL_HANDLER(truncate_file)
|
||||
{
|
||||
truncate_file( req->handle );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* flush a file buffers */
|
||||
DECL_HANDLER(flush_file)
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_WRITE, NULL )))
|
||||
{
|
||||
obj->ops->flush( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* set a file access and modification times */
|
||||
DECL_HANDLER(set_file_time)
|
||||
{
|
||||
set_file_time( req->handle, req->access_time, req->write_time );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get a file information */
|
||||
DECL_HANDLER(get_file_info)
|
||||
{
|
||||
struct object *obj;
|
||||
struct get_file_info_reply reply;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, 0, NULL )))
|
||||
{
|
||||
obj->ops->get_file_info( obj, &reply );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* lock a region of a file */
|
||||
DECL_HANDLER(lock_file)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
if ((file = get_file_obj( current->process, req->handle, 0 )))
|
||||
{
|
||||
file_lock( file, req->offset_high, req->offset_low,
|
||||
req->count_high, req->count_low );
|
||||
release_object( file );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* unlock a region of a file */
|
||||
DECL_HANDLER(unlock_file)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
if ((file = get_file_obj( current->process, req->handle, 0 )))
|
||||
{
|
||||
file_unlock( file, req->offset_high, req->offset_low,
|
||||
req->count_high, req->count_low );
|
||||
release_object( file );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* Server-side handle management
|
||||
*
|
||||
* Copyright (C) 1998 Alexandre Julliard
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "winerror.h"
|
||||
#include "winbase.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "process.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct handle_entry
|
||||
{
|
||||
struct object *ptr;
|
||||
unsigned int access;
|
||||
};
|
||||
|
||||
static struct process *initial_process;
|
||||
|
||||
/* reserved handle access rights */
|
||||
#define RESERVED_SHIFT 25
|
||||
#define RESERVED_INHERIT (HANDLE_FLAG_INHERIT << RESERVED_SHIFT)
|
||||
#define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
|
||||
#define RESERVED_ALL (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
|
||||
|
||||
/* global handle macros */
|
||||
#define HANDLE_OBFUSCATOR 0x544a4def
|
||||
#define HANDLE_IS_GLOBAL(h) (((h) ^ HANDLE_OBFUSCATOR) < 0x10000)
|
||||
#define HANDLE_LOCAL_TO_GLOBAL(h) ((h) ^ HANDLE_OBFUSCATOR)
|
||||
#define HANDLE_GLOBAL_TO_LOCAL(h) ((h) ^ HANDLE_OBFUSCATOR)
|
||||
|
||||
#define MIN_HANDLE_ENTRIES 32
|
||||
|
||||
/* grow a handle table */
|
||||
/* return 1 if OK, 0 on error */
|
||||
static int grow_handle_table( struct handle_table *table )
|
||||
{
|
||||
struct handle_entry *new_entries;
|
||||
int count = table->count;
|
||||
|
||||
if (count >= INT_MAX / 2) return 0;
|
||||
count *= 2;
|
||||
if (!(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
|
||||
{
|
||||
SET_ERROR( ERROR_OUTOFMEMORY );
|
||||
return 0;
|
||||
}
|
||||
table->count = count;
|
||||
table->entries = new_entries;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* allocate a handle for an object, incrementing its refcount */
|
||||
/* return the handle, or -1 on error */
|
||||
int alloc_handle( struct process *process, void *obj, unsigned int access,
|
||||
int inherit )
|
||||
{
|
||||
struct handle_table *table = get_process_handles( process );
|
||||
struct handle_entry *entry;
|
||||
int handle;
|
||||
|
||||
assert( !(access & RESERVED_ALL) );
|
||||
if (inherit) access |= RESERVED_INHERIT;
|
||||
|
||||
/* find the first free entry */
|
||||
|
||||
if (!(entry = table->entries)) return -1;
|
||||
for (handle = 0; handle <= table->last; handle++, entry++)
|
||||
if (!entry->ptr) goto found;
|
||||
|
||||
if (handle >= table->count)
|
||||
{
|
||||
if (!grow_handle_table( table )) return -1;
|
||||
entry = table->entries + handle; /* the table may have moved */
|
||||
}
|
||||
table->last = handle;
|
||||
|
||||
found:
|
||||
entry->ptr = grab_object( obj );
|
||||
entry->access = access;
|
||||
return handle + 1; /* avoid handle 0 */
|
||||
}
|
||||
|
||||
/* return an handle entry, or NULL if the handle is invalid */
|
||||
static struct handle_entry *get_handle( struct process *process, int handle )
|
||||
{
|
||||
struct handle_table *table;
|
||||
struct handle_entry *entry;
|
||||
|
||||
if (HANDLE_IS_GLOBAL(handle))
|
||||
{
|
||||
handle = HANDLE_GLOBAL_TO_LOCAL(handle);
|
||||
process = initial_process;
|
||||
}
|
||||
table = get_process_handles( process );
|
||||
handle--; /* handles start at 1 */
|
||||
if ((handle < 0) || (handle > table->last)) goto error;
|
||||
entry = table->entries + handle;
|
||||
if (!entry->ptr) goto error;
|
||||
return entry;
|
||||
|
||||
error:
|
||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* attempt to shrink a table */
|
||||
/* return 1 if OK, 0 on error */
|
||||
static int shrink_handle_table( struct handle_table *table )
|
||||
{
|
||||
struct handle_entry *new_entries;
|
||||
struct handle_entry *entry = table->entries + table->last;
|
||||
int count = table->count;
|
||||
|
||||
while (table->last >= 0)
|
||||
{
|
||||
if (entry->ptr) break;
|
||||
table->last--;
|
||||
entry--;
|
||||
}
|
||||
if (table->last >= count / 4) return 1; /* no need to shrink */
|
||||
if (count < MIN_HANDLE_ENTRIES * 2) return 1; /* too small to shrink */
|
||||
count /= 2;
|
||||
if (!(new_entries = realloc( table->entries,
|
||||
count * sizeof(struct handle_entry) )))
|
||||
return 0;
|
||||
table->count = count;
|
||||
table->entries = new_entries;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* copy the handle table of the parent process */
|
||||
/* return 1 if OK, 0 on error */
|
||||
int copy_handle_table( struct process *process, struct process *parent )
|
||||
{
|
||||
struct handle_table *parent_table;
|
||||
struct handle_table *table = get_process_handles( process );
|
||||
struct handle_entry *ptr;
|
||||
int i, count, last;
|
||||
|
||||
if (!parent) /* first process */
|
||||
{
|
||||
if (!initial_process) initial_process = process;
|
||||
parent_table = NULL;
|
||||
count = MIN_HANDLE_ENTRIES;
|
||||
last = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent_table = get_process_handles( parent );
|
||||
assert( parent_table->entries );
|
||||
count = parent_table->count;
|
||||
last = parent_table->last;
|
||||
}
|
||||
|
||||
if (!(ptr = mem_alloc( count * sizeof(struct handle_entry)))) return 0;
|
||||
table->entries = ptr;
|
||||
table->count = count;
|
||||
table->last = last;
|
||||
|
||||
if (last >= 0)
|
||||
{
|
||||
memcpy( ptr, parent_table->entries, (last + 1) * sizeof(struct handle_entry) );
|
||||
for (i = 0; i <= last; i++, ptr++)
|
||||
{
|
||||
if (!ptr->ptr) continue;
|
||||
if (ptr->access & RESERVED_INHERIT) grab_object( ptr->ptr );
|
||||
else ptr->ptr = NULL; /* don't inherit this entry */
|
||||
}
|
||||
}
|
||||
/* attempt to shrink the table */
|
||||
shrink_handle_table( table );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* close a handle and decrement the refcount of the associated object */
|
||||
/* return 1 if OK, 0 on error */
|
||||
int close_handle( struct process *process, int handle )
|
||||
{
|
||||
struct handle_table *table;
|
||||
struct handle_entry *entry;
|
||||
struct object *obj;
|
||||
|
||||
if (HANDLE_IS_GLOBAL(handle))
|
||||
{
|
||||
handle = HANDLE_GLOBAL_TO_LOCAL(handle);
|
||||
process = initial_process;
|
||||
}
|
||||
table = get_process_handles( process );
|
||||
if (!(entry = get_handle( process, handle ))) return 0;
|
||||
if (entry->access & RESERVED_CLOSE_PROTECT) return 0; /* FIXME: error code */
|
||||
obj = entry->ptr;
|
||||
entry->ptr = NULL;
|
||||
if (handle-1 == table->last) shrink_handle_table( table );
|
||||
release_object( obj );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* retrieve the object corresponding to a handle, incrementing its refcount */
|
||||
struct object *get_handle_obj( struct process *process, int handle,
|
||||
unsigned int access, const struct object_ops *ops )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
struct object *obj;
|
||||
|
||||
switch( handle )
|
||||
{
|
||||
case 0xfffffffe: /* current thread pseudo-handle */
|
||||
obj = ¤t->obj;
|
||||
break;
|
||||
case 0x7fffffff: /* current process pseudo-handle */
|
||||
obj = (struct object *)current->process;
|
||||
break;
|
||||
default:
|
||||
if (!(entry = get_handle( process, handle ))) return NULL;
|
||||
if ((entry->access & access) != access)
|
||||
{
|
||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
||||
return NULL;
|
||||
}
|
||||
obj = entry->ptr;
|
||||
break;
|
||||
}
|
||||
if (ops && (obj->ops != ops))
|
||||
{
|
||||
SET_ERROR( ERROR_INVALID_HANDLE ); /* not the right type */
|
||||
return NULL;
|
||||
}
|
||||
return grab_object( obj );
|
||||
}
|
||||
|
||||
/* get/set the handle reserved flags */
|
||||
/* return the new flags (or -1 on error) */
|
||||
static int set_handle_info( struct process *process, int handle, int mask, int flags )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
|
||||
if (!(entry = get_handle( process, handle ))) return -1;
|
||||
mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
|
||||
flags = (flags << RESERVED_SHIFT) & mask;
|
||||
entry->access = (entry->access & ~mask) | flags;
|
||||
return (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
|
||||
}
|
||||
|
||||
/* duplicate a handle */
|
||||
int duplicate_handle( struct process *src, int src_handle, struct process *dst,
|
||||
unsigned int access, int inherit, int options )
|
||||
{
|
||||
int res;
|
||||
struct handle_entry *entry = get_handle( src, src_handle );
|
||||
if (!entry) return -1;
|
||||
|
||||
if (options & DUP_HANDLE_SAME_ACCESS) access = entry->access;
|
||||
if (options & DUP_HANDLE_MAKE_GLOBAL) dst = initial_process;
|
||||
access &= ~RESERVED_ALL;
|
||||
res = alloc_handle( dst, entry->ptr, access, inherit );
|
||||
if (options & DUP_HANDLE_MAKE_GLOBAL) res = HANDLE_LOCAL_TO_GLOBAL(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* free the process handle entries */
|
||||
void free_handles( struct process *process )
|
||||
{
|
||||
struct handle_table *table = get_process_handles( process );
|
||||
struct handle_entry *entry;
|
||||
int handle;
|
||||
|
||||
if (!(entry = table->entries)) return;
|
||||
for (handle = 0; handle <= table->last; handle++, entry++)
|
||||
{
|
||||
struct object *obj = entry->ptr;
|
||||
entry->ptr = NULL;
|
||||
if (obj) release_object( obj );
|
||||
}
|
||||
free( table->entries );
|
||||
table->count = 0;
|
||||
table->last = -1;
|
||||
table->entries = NULL;
|
||||
}
|
||||
|
||||
/* open a new handle to an existing object */
|
||||
int open_object( const char *name, const struct object_ops *ops,
|
||||
unsigned int access, int inherit )
|
||||
{
|
||||
struct object *obj = find_object( name );
|
||||
if (!obj)
|
||||
{
|
||||
SET_ERROR( ERROR_FILE_NOT_FOUND );
|
||||
return -1;
|
||||
}
|
||||
if (ops && obj->ops != ops)
|
||||
{
|
||||
release_object( obj );
|
||||
SET_ERROR( ERROR_INVALID_HANDLE ); /* FIXME: not the right type */
|
||||
return -1;
|
||||
}
|
||||
return alloc_handle( current->process, obj, access, inherit );
|
||||
}
|
||||
|
||||
/* dump a handle table on stdout */
|
||||
void dump_handles( struct process *process )
|
||||
{
|
||||
struct handle_table *table = get_process_handles( process );
|
||||
struct handle_entry *entry;
|
||||
int i;
|
||||
|
||||
if (!table->entries) return;
|
||||
entry = table->entries;
|
||||
for (i = 0; i <= table->last; i++, entry++)
|
||||
{
|
||||
if (!entry->ptr) continue;
|
||||
printf( "%5d: %p %08x ", i + 1, entry->ptr, entry->access );
|
||||
entry->ptr->ops->dump( entry->ptr, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* close a handle */
|
||||
DECL_HANDLER(close_handle)
|
||||
{
|
||||
close_handle( current->process, req->handle );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get information about a handle */
|
||||
DECL_HANDLER(get_handle_info)
|
||||
{
|
||||
struct get_handle_info_reply reply;
|
||||
reply.flags = set_handle_info( current->process, req->handle, 0, 0 );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set a handle information */
|
||||
DECL_HANDLER(set_handle_info)
|
||||
{
|
||||
set_handle_info( current->process, req->handle, req->mask, req->flags );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* duplicate a handle */
|
||||
DECL_HANDLER(dup_handle)
|
||||
{
|
||||
struct dup_handle_reply reply = { -1 };
|
||||
struct process *src, *dst;
|
||||
|
||||
if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
|
||||
{
|
||||
if (req->options & DUP_HANDLE_MAKE_GLOBAL)
|
||||
{
|
||||
reply.handle = duplicate_handle( src, req->src_handle, NULL,
|
||||
req->access, req->inherit, req->options );
|
||||
}
|
||||
else if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
|
||||
{
|
||||
reply.handle = duplicate_handle( src, req->src_handle, dst,
|
||||
req->access, req->inherit, req->options );
|
||||
release_object( dst );
|
||||
}
|
||||
/* close the handle no matter what happened */
|
||||
if (req->options & DUP_HANDLE_CLOSE_SOURCE)
|
||||
close_handle( src, req->src_handle );
|
||||
release_object( src );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Server-side handle definitions
|
||||
*
|
||||
* Copyright (C) 1999 Alexandre Julliard
|
||||
*/
|
||||
|
||||
#ifndef __WINE_SERVER_HANDLE_H
|
||||
#define __WINE_SERVER_HANDLE_H
|
||||
|
||||
#ifndef __WINE_SERVER__
|
||||
#error This file can only be used in the Wine server
|
||||
#endif
|
||||
|
||||
struct process;
|
||||
struct object_ops;
|
||||
struct handle_entry;
|
||||
|
||||
/* handle structures */
|
||||
|
||||
struct handle_table
|
||||
{
|
||||
int count;
|
||||
int last;
|
||||
struct handle_entry *entries;
|
||||
};
|
||||
|
||||
/* handle functions */
|
||||
|
||||
/* alloc_handle takes a void *obj for convenience, but you better make sure */
|
||||
/* that the thing pointed to starts with a struct object... */
|
||||
extern int alloc_handle( struct process *process, void *obj,
|
||||
unsigned int access, int inherit );
|
||||
extern int close_handle( struct process *process, int handle );
|
||||
extern struct object *get_handle_obj( struct process *process, int handle,
|
||||
unsigned int access, const struct object_ops *ops );
|
||||
extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
|
||||
unsigned int access, int inherit, int options );
|
||||
extern int open_object( const char *name, const struct object_ops *ops,
|
||||
unsigned int access, int inherit );
|
||||
extern int copy_handle_table( struct process *process, struct process *parent );
|
||||
extern void free_handles( struct process *process );
|
||||
|
||||
#endif /* __WINE_SERVER_HANDLE_H */
|
|
@ -11,8 +11,8 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "server.h"
|
||||
#include "server/object.h"
|
||||
#include "server/thread.h"
|
||||
#include "object.h"
|
||||
#include "thread.h"
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
#include "config.h"
|
||||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
#include "winbase.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct mapping
|
||||
{
|
||||
|
@ -79,8 +81,8 @@ static void init_page_size(void)
|
|||
(((int)(size) + ((int)(addr) & page_mask) + page_mask) & ~page_mask)
|
||||
|
||||
|
||||
struct object *create_mapping( int size_high, int size_low, int protect,
|
||||
int handle, const char *name )
|
||||
static struct object *create_mapping( int size_high, int size_low, int protect,
|
||||
int handle, const char *name )
|
||||
{
|
||||
struct mapping *mapping;
|
||||
int access = 0;
|
||||
|
@ -131,12 +133,7 @@ struct object *create_mapping( int size_high, int size_low, int protect,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int open_mapping( unsigned int access, int inherit, const char *name )
|
||||
{
|
||||
return open_object( name, &mapping_ops, access, inherit );
|
||||
}
|
||||
|
||||
int get_mapping_info( int handle, struct get_mapping_info_reply *reply )
|
||||
static int get_mapping_info( int handle, struct get_mapping_info_reply *reply )
|
||||
{
|
||||
struct mapping *mapping;
|
||||
int fd;
|
||||
|
@ -169,3 +166,43 @@ static void mapping_destroy( struct object *obj )
|
|||
if (mapping->file) release_object( mapping->file );
|
||||
free( mapping );
|
||||
}
|
||||
|
||||
/* create a file mapping */
|
||||
DECL_HANDLER(create_mapping)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_mapping_reply reply = { -1 };
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_mapping", name, len );
|
||||
|
||||
if ((obj = create_mapping( req->size_high, req->size_low,
|
||||
req->protect, req->handle, name )))
|
||||
{
|
||||
int access = FILE_MAP_ALL_ACCESS;
|
||||
if (!(req->protect & VPROT_WRITE)) access &= ~FILE_MAP_WRITE;
|
||||
reply.handle = alloc_handle( current->process, obj, access, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* open a handle to a mapping */
|
||||
DECL_HANDLER(open_mapping)
|
||||
{
|
||||
struct open_mapping_reply reply;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "open_mapping", name, len );
|
||||
|
||||
reply.handle = open_object( name, &mapping_ops, req->access, req->inherit );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* get a mapping information */
|
||||
DECL_HANDLER(get_mapping_info)
|
||||
{
|
||||
struct get_mapping_info_reply reply;
|
||||
int map_fd = get_mapping_info( req->handle, &reply );
|
||||
send_reply( current, map_fd, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct mutex
|
||||
{
|
||||
|
@ -43,7 +44,7 @@ static const struct object_ops mutex_ops =
|
|||
};
|
||||
|
||||
|
||||
struct object *create_mutex( const char *name, int owned )
|
||||
static struct object *create_mutex( const char *name, int owned )
|
||||
{
|
||||
struct mutex *mutex;
|
||||
|
||||
|
@ -61,11 +62,6 @@ struct object *create_mutex( const char *name, int owned )
|
|||
return &mutex->obj;
|
||||
}
|
||||
|
||||
int open_mutex( unsigned int access, int inherit, const char *name )
|
||||
{
|
||||
return open_object( name, &mutex_ops, access, inherit );
|
||||
}
|
||||
|
||||
/* release a mutex once the recursion count is 0 */
|
||||
static void do_release( struct mutex *mutex, struct thread *thread )
|
||||
{
|
||||
|
@ -79,7 +75,7 @@ static void do_release( struct mutex *mutex, struct thread *thread )
|
|||
wake_up( &mutex->obj, 0 );
|
||||
}
|
||||
|
||||
int release_mutex( int handle )
|
||||
static int release_mutex( int handle )
|
||||
{
|
||||
struct mutex *mutex;
|
||||
|
||||
|
@ -148,3 +144,40 @@ static void mutex_destroy( struct object *obj )
|
|||
assert( obj->ops == &mutex_ops );
|
||||
free( mutex );
|
||||
}
|
||||
|
||||
/* create a mutex */
|
||||
DECL_HANDLER(create_mutex)
|
||||
{
|
||||
struct create_mutex_reply reply = { -1 };
|
||||
struct object *obj;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_mutex", name, len );
|
||||
|
||||
obj = create_mutex( name, req->owned );
|
||||
if (obj)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, MUTEX_ALL_ACCESS, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* open a handle to a mutex */
|
||||
DECL_HANDLER(open_mutex)
|
||||
{
|
||||
struct open_mutex_reply reply;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "open_mutex", name, len );
|
||||
|
||||
reply.handle = open_object( name, &mutex_ops, req->access, req->inherit );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* release a mutex */
|
||||
DECL_HANDLER(release_mutex)
|
||||
{
|
||||
if (release_mutex( req->handle )) CLEAR_ERROR();
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
|
|
@ -11,8 +11,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "winerror.h"
|
||||
#include "server.h"
|
||||
#include "server/thread.h"
|
||||
#include "thread.h"
|
||||
|
||||
int debug_level = 0;
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ extern void default_select_event( int fd, int event, void *private );
|
|||
struct iovec;
|
||||
struct thread;
|
||||
|
||||
extern void fatal_protocol_error( const char *err, ... );
|
||||
extern void call_req_handler( struct thread *thread, enum request req,
|
||||
void *data, int len, int fd );
|
||||
extern void call_timeout_handler( struct thread *thread );
|
||||
|
@ -91,6 +92,11 @@ extern void trace_timeout(void);
|
|||
extern void trace_kill( int exit_code );
|
||||
extern void trace_reply( struct thread *thread, int type, int pass_fd,
|
||||
struct iovec *vec, int veclen );
|
||||
/* check that the string is NULL-terminated and that the len is correct */
|
||||
#define CHECK_STRING(func,str,len) \
|
||||
do { if (((str)[(len)-1] || strlen(str) != (len)-1)) \
|
||||
fatal_protocol_error( "%s: invalid string '%.*s'\n", (func), (len), (str) ); \
|
||||
} while(0)
|
||||
|
||||
/* select functions */
|
||||
|
||||
|
@ -118,88 +124,22 @@ extern void set_timeout( int client_fd, struct timeval *when );
|
|||
extern int send_reply_v( int client_fd, int type, int pass_fd,
|
||||
struct iovec *vec, int veclen );
|
||||
|
||||
/* event functions */
|
||||
|
||||
extern struct object *create_event( const char *name, int manual_reset, int initial_state );
|
||||
extern int open_event( unsigned int access, int inherit, const char *name );
|
||||
extern int pulse_event( int handle );
|
||||
extern int set_event( int handle );
|
||||
extern int reset_event( int handle );
|
||||
|
||||
|
||||
/* mutex functions */
|
||||
|
||||
extern struct object *create_mutex( const char *name, int owned );
|
||||
extern int open_mutex( unsigned int access, int inherit, const char *name );
|
||||
extern int release_mutex( int handle );
|
||||
extern void abandon_mutexes( struct thread *thread );
|
||||
|
||||
|
||||
/* semaphore functions */
|
||||
|
||||
extern struct object *create_semaphore( const char *name, unsigned int initial, unsigned int max );
|
||||
extern int open_semaphore( unsigned int access, int inherit, const char *name );
|
||||
extern int release_semaphore( int handle, unsigned int count, unsigned int *prev_count );
|
||||
|
||||
|
||||
/* file functions */
|
||||
|
||||
extern struct object *create_file( int fd, const char *name, unsigned int access,
|
||||
unsigned int sharing, int create, unsigned int attrs );
|
||||
extern struct file *get_file_obj( struct process *process, int handle,
|
||||
unsigned int access );
|
||||
extern int file_get_mmap_fd( struct file *file );
|
||||
extern int set_file_pointer( int handle, int *low, int *high, int whence );
|
||||
extern int truncate_file( int handle );
|
||||
extern int grow_file( struct file *file, int size_high, int size_low );
|
||||
extern struct file *create_temp_file( int access );
|
||||
extern int set_file_time( int handle, time_t access_time, time_t write_time );
|
||||
extern int file_lock( struct file *file, int offset_high, int offset_low,
|
||||
int count_high, int count_low );
|
||||
extern int file_unlock( struct file *file, int offset_high, int offset_low,
|
||||
int count_high, int count_low );
|
||||
extern void file_set_error(void);
|
||||
|
||||
|
||||
/* pipe functions */
|
||||
|
||||
extern int create_pipe( struct object *obj[2] );
|
||||
|
||||
|
||||
/* console functions */
|
||||
|
||||
struct tagINPUT_RECORD;
|
||||
extern int create_console( int fd, struct object *obj[2] );
|
||||
extern int set_console_fd( int handle, int fd, int pid );
|
||||
extern int get_console_mode( int handle, int *mode );
|
||||
extern int set_console_mode( int handle, int mode );
|
||||
extern int set_console_info( int handle, struct set_console_info_request *req,
|
||||
const char *title );
|
||||
extern int get_console_info( int handle, struct get_console_info_reply *reply,
|
||||
const char **title );
|
||||
extern int write_console_input( int handle, int count, struct tagINPUT_RECORD *records );
|
||||
extern int read_console_input( int handle, int count, int flush );
|
||||
|
||||
|
||||
/* change notification functions */
|
||||
|
||||
extern struct object *create_change_notification( int subtree, int filter );
|
||||
|
||||
|
||||
/* file mapping functions */
|
||||
extern struct object *create_mapping( int size_high, int size_low, int protect,
|
||||
int handle, const char *name );
|
||||
extern int open_mapping( unsigned int access, int inherit, const char *name );
|
||||
extern int get_mapping_info( int handle, struct get_mapping_info_reply *reply );
|
||||
|
||||
|
||||
/* device functions */
|
||||
extern struct object *create_device( int id );
|
||||
|
||||
|
||||
/* snapshot functions */
|
||||
extern struct object *create_snapshot( int flags );
|
||||
extern int snapshot_next_process( int handle, int reset, struct next_process_reply *reply );
|
||||
|
||||
extern int debug_level;
|
||||
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
#include "winerror.h"
|
||||
#include "winbase.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "thread.h"
|
||||
|
||||
enum side { READ_SIDE, WRITE_SIDE };
|
||||
|
||||
|
@ -59,7 +61,7 @@ static const struct select_ops select_ops =
|
|||
NULL /* we never set a timeout on a pipe */
|
||||
};
|
||||
|
||||
int create_pipe( struct object *obj[2] )
|
||||
static int create_pipe( struct object *obj[2] )
|
||||
{
|
||||
struct pipe *newpipe[2];
|
||||
int fd[2];
|
||||
|
@ -200,3 +202,27 @@ static void pipe_destroy( struct object *obj )
|
|||
close( pipe->fd );
|
||||
free( pipe );
|
||||
}
|
||||
|
||||
/* create an anonymous pipe */
|
||||
DECL_HANDLER(create_pipe)
|
||||
{
|
||||
struct create_pipe_reply reply = { -1, -1 };
|
||||
struct object *obj[2];
|
||||
if (create_pipe( obj ))
|
||||
{
|
||||
reply.handle_read = alloc_handle( current->process, obj[0],
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_READ,
|
||||
req->inherit );
|
||||
if (reply.handle_read != -1)
|
||||
{
|
||||
reply.handle_write = alloc_handle( current->process, obj[1],
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_WRITE,
|
||||
req->inherit );
|
||||
if (reply.handle_write == -1)
|
||||
close_handle( current->process, reply.handle_read );
|
||||
}
|
||||
release_object( obj[0] );
|
||||
release_object( obj[1] );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
|
416
server/process.c
416
server/process.c
|
@ -17,37 +17,19 @@
|
|||
#include "winnt.h"
|
||||
|
||||
#include "server.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
/* reserved handle access rights */
|
||||
#define RESERVED_SHIFT 25
|
||||
#define RESERVED_INHERIT (HANDLE_FLAG_INHERIT << RESERVED_SHIFT)
|
||||
#define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
|
||||
#define RESERVED_ALL (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
|
||||
|
||||
/* global handle macros */
|
||||
#define HANDLE_OBFUSCATOR 0x544a4def
|
||||
#define HANDLE_IS_GLOBAL(h) (((h) ^ HANDLE_OBFUSCATOR) < 0x10000)
|
||||
#define HANDLE_LOCAL_TO_GLOBAL(h) ((h) ^ HANDLE_OBFUSCATOR)
|
||||
#define HANDLE_GLOBAL_TO_LOCAL(h) ((h) ^ HANDLE_OBFUSCATOR)
|
||||
|
||||
struct handle_entry
|
||||
{
|
||||
struct object *ptr;
|
||||
unsigned int access;
|
||||
};
|
||||
#include "handle.h"
|
||||
#include "process.h"
|
||||
#include "thread.h"
|
||||
|
||||
/* process structure */
|
||||
|
||||
struct process
|
||||
{
|
||||
struct object obj; /* object header */
|
||||
struct process *next; /* system-wide process list */
|
||||
struct process *prev;
|
||||
struct thread *thread_list; /* head of the thread list */
|
||||
struct handle_entry *entries; /* handle entry table */
|
||||
int handle_count; /* nb of allocated handle entries */
|
||||
int handle_last; /* last used handle entry */
|
||||
struct handle_table handles; /* handle table */
|
||||
int exit_code; /* process exit code */
|
||||
int running_threads; /* number of threads running in this process */
|
||||
struct timeval start_time; /* absolute time at process start */
|
||||
|
@ -59,20 +41,15 @@ struct process
|
|||
struct new_process_request *info; /* startup info (freed after startup) */
|
||||
};
|
||||
|
||||
|
||||
static struct process initial_process;
|
||||
static struct process *first_process = &initial_process;
|
||||
static int running_processes;
|
||||
|
||||
#define MIN_HANDLE_ENTRIES 32
|
||||
|
||||
/* process operations */
|
||||
|
||||
static void process_dump( struct object *obj, int verbose );
|
||||
static int process_signaled( struct object *obj, struct thread *thread );
|
||||
static void process_destroy( struct object *obj );
|
||||
static void free_handles( struct process *process );
|
||||
static int copy_handle_table( struct process *process, struct process *parent );
|
||||
|
||||
static const struct object_ops process_ops =
|
||||
{
|
||||
|
@ -133,7 +110,7 @@ struct process *create_initial_process(void)
|
|||
}
|
||||
|
||||
/* create a new process */
|
||||
struct process *create_process( struct new_process_request *req )
|
||||
static struct process *create_process( struct new_process_request *req )
|
||||
{
|
||||
struct process *process = NULL;
|
||||
struct process *parent = current->process;
|
||||
|
@ -223,8 +200,14 @@ struct process *get_process_from_handle( int handle, unsigned int access )
|
|||
access, &process_ops );
|
||||
}
|
||||
|
||||
/* get a pointer to the process handle table */
|
||||
struct handle_table *get_process_handles( struct process *process )
|
||||
{
|
||||
return &process->handles;
|
||||
}
|
||||
|
||||
/* retrieve the initialization info for a new process */
|
||||
int get_process_init_info( struct process *process, struct init_process_reply *reply )
|
||||
static int get_process_init_info( struct process *process, struct init_process_reply *reply )
|
||||
{
|
||||
struct new_process_request *info;
|
||||
if (!(info = process->info)) return 0;
|
||||
|
@ -248,25 +231,6 @@ static void process_killed( struct process *process, int exit_code )
|
|||
free_handles( process );
|
||||
}
|
||||
|
||||
/* free the process handle entries */
|
||||
static void free_handles( struct process *process )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
int handle;
|
||||
|
||||
if (!(entry = process->entries)) return;
|
||||
for (handle = 0; handle <= process->handle_last; handle++, entry++)
|
||||
{
|
||||
struct object *obj = entry->ptr;
|
||||
entry->ptr = NULL;
|
||||
if (obj) release_object( obj );
|
||||
}
|
||||
free( process->entries );
|
||||
process->handle_count = 0;
|
||||
process->handle_last = -1;
|
||||
process->entries = NULL;
|
||||
}
|
||||
|
||||
/* add a thread to a process running threads list */
|
||||
void add_process_thread( struct process *process, struct thread *thread )
|
||||
{
|
||||
|
@ -297,268 +261,16 @@ void remove_process_thread( struct process *process, struct thread *thread )
|
|||
release_object( thread );
|
||||
}
|
||||
|
||||
/* grow a handle table */
|
||||
/* return 1 if OK, 0 on error */
|
||||
static int grow_handle_table( struct process *process )
|
||||
{
|
||||
struct handle_entry *new_entries;
|
||||
int count = process->handle_count;
|
||||
|
||||
if (count >= INT_MAX / 2) return 0;
|
||||
count *= 2;
|
||||
if (!(new_entries = realloc( process->entries, count * sizeof(struct handle_entry) )))
|
||||
{
|
||||
SET_ERROR( ERROR_OUTOFMEMORY );
|
||||
return 0;
|
||||
}
|
||||
process->handle_count = count;
|
||||
process->entries = new_entries;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* allocate a handle for an object, incrementing its refcount */
|
||||
/* return the handle, or -1 on error */
|
||||
int alloc_handle( struct process *process, void *obj, unsigned int access,
|
||||
int inherit )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
int handle;
|
||||
|
||||
assert( !(access & RESERVED_ALL) );
|
||||
if (inherit) access |= RESERVED_INHERIT;
|
||||
|
||||
/* find the first free entry */
|
||||
|
||||
if (!(entry = process->entries)) return -1;
|
||||
for (handle = 0; handle <= process->handle_last; handle++, entry++)
|
||||
if (!entry->ptr) goto found;
|
||||
|
||||
if (handle >= process->handle_count)
|
||||
{
|
||||
if (!grow_handle_table( process )) return -1;
|
||||
entry = process->entries + handle; /* the table may have moved */
|
||||
}
|
||||
process->handle_last = handle;
|
||||
|
||||
found:
|
||||
entry->ptr = grab_object( obj );
|
||||
entry->access = access;
|
||||
return handle + 1; /* avoid handle 0 */
|
||||
}
|
||||
|
||||
/* return an handle entry, or NULL if the handle is invalid */
|
||||
static struct handle_entry *get_handle( struct process *process, int handle )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
|
||||
if (HANDLE_IS_GLOBAL(handle))
|
||||
{
|
||||
handle = HANDLE_GLOBAL_TO_LOCAL(handle);
|
||||
process = &initial_process;
|
||||
}
|
||||
handle--; /* handles start at 1 */
|
||||
if ((handle < 0) || (handle > process->handle_last)) goto error;
|
||||
entry = process->entries + handle;
|
||||
if (!entry->ptr) goto error;
|
||||
return entry;
|
||||
|
||||
error:
|
||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* attempt to shrink a table */
|
||||
/* return 1 if OK, 0 on error */
|
||||
static int shrink_handle_table( struct process *process )
|
||||
{
|
||||
struct handle_entry *new_entries;
|
||||
struct handle_entry *entry = process->entries + process->handle_last;
|
||||
int count = process->handle_count;
|
||||
|
||||
while (process->handle_last >= 0)
|
||||
{
|
||||
if (entry->ptr) break;
|
||||
process->handle_last--;
|
||||
entry--;
|
||||
}
|
||||
if (process->handle_last >= count / 4) return 1; /* no need to shrink */
|
||||
if (count < MIN_HANDLE_ENTRIES * 2) return 1; /* too small to shrink */
|
||||
count /= 2;
|
||||
if (!(new_entries = realloc( process->entries,
|
||||
count * sizeof(struct handle_entry) )))
|
||||
return 0;
|
||||
process->handle_count = count;
|
||||
process->entries = new_entries;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* copy the handle table of the parent process */
|
||||
/* return 1 if OK, 0 on error */
|
||||
static int copy_handle_table( struct process *process, struct process *parent )
|
||||
{
|
||||
struct handle_entry *ptr;
|
||||
int i, count, last;
|
||||
|
||||
if (!parent) /* first process */
|
||||
{
|
||||
count = MIN_HANDLE_ENTRIES;
|
||||
last = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( parent->entries );
|
||||
count = parent->handle_count;
|
||||
last = parent->handle_last;
|
||||
}
|
||||
|
||||
if (!(ptr = mem_alloc( count * sizeof(struct handle_entry)))) return 0;
|
||||
process->entries = ptr;
|
||||
process->handle_count = count;
|
||||
process->handle_last = last;
|
||||
|
||||
if (last >= 0)
|
||||
{
|
||||
memcpy( ptr, parent->entries, (last + 1) * sizeof(struct handle_entry) );
|
||||
for (i = 0; i <= last; i++, ptr++)
|
||||
{
|
||||
if (!ptr->ptr) continue;
|
||||
if (ptr->access & RESERVED_INHERIT) grab_object( ptr->ptr );
|
||||
else ptr->ptr = NULL; /* don't inherit this entry */
|
||||
}
|
||||
}
|
||||
/* attempt to shrink the table */
|
||||
shrink_handle_table( process );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* close a handle and decrement the refcount of the associated object */
|
||||
/* return 1 if OK, 0 on error */
|
||||
int close_handle( struct process *process, int handle )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
struct object *obj;
|
||||
|
||||
if (HANDLE_IS_GLOBAL(handle))
|
||||
{
|
||||
handle = HANDLE_GLOBAL_TO_LOCAL(handle);
|
||||
process = &initial_process;
|
||||
}
|
||||
if (!(entry = get_handle( process, handle ))) return 0;
|
||||
if (entry->access & RESERVED_CLOSE_PROTECT) return 0; /* FIXME: error code */
|
||||
obj = entry->ptr;
|
||||
entry->ptr = NULL;
|
||||
if (handle-1 == process->handle_last) shrink_handle_table( process );
|
||||
release_object( obj );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* retrieve the object corresponding to a handle, incrementing its refcount */
|
||||
struct object *get_handle_obj( struct process *process, int handle,
|
||||
unsigned int access, const struct object_ops *ops )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
struct object *obj;
|
||||
|
||||
switch( handle )
|
||||
{
|
||||
case 0xfffffffe: /* current thread pseudo-handle */
|
||||
obj = ¤t->obj;
|
||||
break;
|
||||
case 0x7fffffff: /* current process pseudo-handle */
|
||||
obj = (struct object *)current->process;
|
||||
break;
|
||||
default:
|
||||
if (!(entry = get_handle( process, handle ))) return NULL;
|
||||
if ((entry->access & access) != access)
|
||||
{
|
||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
||||
return NULL;
|
||||
}
|
||||
obj = entry->ptr;
|
||||
break;
|
||||
}
|
||||
if (ops && (obj->ops != ops))
|
||||
{
|
||||
SET_ERROR( ERROR_INVALID_HANDLE ); /* not the right type */
|
||||
return NULL;
|
||||
}
|
||||
return grab_object( obj );
|
||||
}
|
||||
|
||||
/* get/set the handle reserved flags */
|
||||
/* return the new flags (or -1 on error) */
|
||||
int set_handle_info( struct process *process, int handle, int mask, int flags )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
|
||||
if (!(entry = get_handle( process, handle ))) return -1;
|
||||
mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
|
||||
flags = (flags << RESERVED_SHIFT) & mask;
|
||||
entry->access = (entry->access & ~mask) | flags;
|
||||
return (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
|
||||
}
|
||||
|
||||
/* duplicate a handle */
|
||||
int duplicate_handle( struct process *src, int src_handle, struct process *dst,
|
||||
unsigned int access, int inherit, int options )
|
||||
{
|
||||
int res;
|
||||
struct handle_entry *entry = get_handle( src, src_handle );
|
||||
if (!entry) return -1;
|
||||
|
||||
if (options & DUP_HANDLE_SAME_ACCESS) access = entry->access;
|
||||
if (options & DUP_HANDLE_MAKE_GLOBAL) dst = &initial_process;
|
||||
access &= ~RESERVED_ALL;
|
||||
res = alloc_handle( dst, entry->ptr, access, inherit );
|
||||
if (options & DUP_HANDLE_MAKE_GLOBAL) res = HANDLE_LOCAL_TO_GLOBAL(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* open a new handle to an existing object */
|
||||
int open_object( const char *name, const struct object_ops *ops,
|
||||
unsigned int access, int inherit )
|
||||
{
|
||||
struct object *obj = find_object( name );
|
||||
if (!obj)
|
||||
{
|
||||
SET_ERROR( ERROR_FILE_NOT_FOUND );
|
||||
return -1;
|
||||
}
|
||||
if (ops && obj->ops != ops)
|
||||
{
|
||||
release_object( obj );
|
||||
SET_ERROR( ERROR_INVALID_HANDLE ); /* FIXME: not the right type */
|
||||
return -1;
|
||||
}
|
||||
return alloc_handle( current->process, obj, access, inherit );
|
||||
}
|
||||
|
||||
/* dump a handle table on stdout */
|
||||
void dump_handles( struct process *process )
|
||||
{
|
||||
struct handle_entry *entry;
|
||||
int i;
|
||||
|
||||
if (!process->entries) return;
|
||||
entry = process->entries;
|
||||
for (i = 0; i <= process->handle_last; i++, entry++)
|
||||
{
|
||||
if (!entry->ptr) continue;
|
||||
printf( "%5d: %p %08x ", i + 1, entry->ptr, entry->access );
|
||||
entry->ptr->ops->dump( entry->ptr, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* kill a process on the spot */
|
||||
void kill_process( struct process *process, int exit_code )
|
||||
static void kill_process( struct process *process, int exit_code )
|
||||
{
|
||||
while (process->thread_list)
|
||||
kill_thread( process->thread_list, exit_code );
|
||||
}
|
||||
|
||||
/* get all information about a process */
|
||||
void get_process_info( struct process *process,
|
||||
struct get_process_info_reply *reply )
|
||||
static void get_process_info( struct process *process,
|
||||
struct get_process_info_reply *reply )
|
||||
{
|
||||
reply->pid = process;
|
||||
reply->exit_code = process->exit_code;
|
||||
|
@ -568,8 +280,8 @@ void get_process_info( struct process *process,
|
|||
}
|
||||
|
||||
/* set all information about a process */
|
||||
void set_process_info( struct process *process,
|
||||
struct set_process_info_request *req )
|
||||
static void set_process_info( struct process *process,
|
||||
struct set_process_info_request *req )
|
||||
{
|
||||
if (req->mask & SET_PROCESS_INFO_PRIORITY)
|
||||
process->priority = req->priority;
|
||||
|
@ -634,3 +346,95 @@ struct process_snapshot *process_snap( int *count )
|
|||
*count = running_processes;
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/* create a new process */
|
||||
DECL_HANDLER(new_process)
|
||||
{
|
||||
struct new_process_reply reply;
|
||||
struct process *process;
|
||||
|
||||
if ((process = create_process( req )))
|
||||
{
|
||||
reply.pid = process;
|
||||
reply.handle = alloc_handle( current->process, process,
|
||||
PROCESS_ALL_ACCESS, req->inherit );
|
||||
release_object( process );
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.handle = -1;
|
||||
reply.pid = NULL;
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* initialize a new process */
|
||||
DECL_HANDLER(init_process)
|
||||
{
|
||||
struct init_process_reply reply;
|
||||
if (current->state != RUNNING)
|
||||
{
|
||||
fatal_protocol_error( "init_process: init_thread not called yet\n" );
|
||||
return;
|
||||
}
|
||||
if (!get_process_init_info( current->process, &reply ))
|
||||
{
|
||||
fatal_protocol_error( "init_process: called twice\n" );
|
||||
return;
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* open a handle to a process */
|
||||
DECL_HANDLER(open_process)
|
||||
{
|
||||
struct open_process_reply reply = { -1 };
|
||||
struct process *process = get_process_from_id( req->pid );
|
||||
if (process)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, process,
|
||||
req->access, req->inherit );
|
||||
release_object( process );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* terminate a process */
|
||||
DECL_HANDLER(terminate_process)
|
||||
{
|
||||
struct process *process;
|
||||
|
||||
if ((process = get_process_from_handle( req->handle, PROCESS_TERMINATE )))
|
||||
{
|
||||
kill_process( process, req->exit_code );
|
||||
release_object( process );
|
||||
}
|
||||
if (current) send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* fetch information about a process */
|
||||
DECL_HANDLER(get_process_info)
|
||||
{
|
||||
struct process *process;
|
||||
struct get_process_info_reply reply = { 0, 0, 0 };
|
||||
|
||||
if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
|
||||
{
|
||||
get_process_info( process, &reply );
|
||||
release_object( process );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set information about a process */
|
||||
DECL_HANDLER(set_process_info)
|
||||
{
|
||||
struct process *process;
|
||||
|
||||
if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION )))
|
||||
{
|
||||
set_process_info( process, req );
|
||||
release_object( process );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Wine server processes
|
||||
*
|
||||
* Copyright (C) 1999 Alexandre Julliard
|
||||
*/
|
||||
|
||||
#ifndef __WINE_SERVER_PROCESS_H
|
||||
#define __WINE_SERVER_PROCESS_H
|
||||
|
||||
#ifndef __WINE_SERVER__
|
||||
#error This file can only be used in the Wine server
|
||||
#endif
|
||||
|
||||
#include "object.h"
|
||||
|
||||
/* process structures */
|
||||
|
||||
struct process;
|
||||
struct handle_table;
|
||||
|
||||
struct process_snapshot
|
||||
{
|
||||
struct process *process; /* process ptr */
|
||||
struct process *parent; /* process parent */
|
||||
int threads; /* number of threads */
|
||||
int priority; /* priority class */
|
||||
};
|
||||
|
||||
/* process functions */
|
||||
|
||||
extern struct process *create_initial_process(void);
|
||||
extern struct process *get_process_from_id( void *id );
|
||||
extern struct process *get_process_from_handle( int handle, unsigned int access );
|
||||
extern struct handle_table *get_process_handles( struct process *process );
|
||||
extern void add_process_thread( struct process *process,
|
||||
struct thread *thread );
|
||||
extern void remove_process_thread( struct process *process,
|
||||
struct thread *thread );
|
||||
extern int alloc_console( struct process *process );
|
||||
extern int free_console( struct process *process );
|
||||
extern struct object *get_console( struct process *process, int output );
|
||||
extern struct process_snapshot *process_snap( int *count );
|
||||
|
||||
#endif /* __WINE_SERVER_PROCESS_H */
|
721
server/request.c
721
server/request.c
|
@ -20,20 +20,12 @@
|
|||
#include "wincon.h"
|
||||
#define WANT_REQUEST_HANDLERS
|
||||
#include "server.h"
|
||||
#include "server/request.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
/* check that the string is NULL-terminated and that the len is correct */
|
||||
#define CHECK_STRING(func,str,len) \
|
||||
do { if (((str)[(len)-1] || strlen(str) != (len)-1)) \
|
||||
fatal_protocol_error( "%s: invalid string '%.*s'\n", (func), (len), (str) ); \
|
||||
} while(0)
|
||||
#include "thread.h"
|
||||
|
||||
struct thread *current = NULL; /* thread handling the current request */
|
||||
|
||||
/* complain about a protocol error and terminate the client connection */
|
||||
static void fatal_protocol_error( const char *err, ... )
|
||||
void fatal_protocol_error( const char *err, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
|
@ -60,7 +52,7 @@ void call_req_handler( struct thread *thread, enum request req,
|
|||
|
||||
if (len < handler->min_size)
|
||||
{
|
||||
fatal_protocol_error( "req %d bad length %d < %d)\n", req, len, handler->min_size );
|
||||
fatal_protocol_error( "req %d bad length %d < %d\n", req, len, handler->min_size );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -100,82 +92,6 @@ void call_kill_handler( struct thread *thread, int exit_code )
|
|||
current = (old_current != thread) ? old_current : NULL;
|
||||
}
|
||||
|
||||
|
||||
/* create a new process */
|
||||
DECL_HANDLER(new_process)
|
||||
{
|
||||
struct new_process_reply reply;
|
||||
struct process *process;
|
||||
|
||||
if ((process = create_process( req )))
|
||||
{
|
||||
reply.pid = process;
|
||||
reply.handle = alloc_handle( current->process, process,
|
||||
PROCESS_ALL_ACCESS, req->inherit );
|
||||
release_object( process );
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.handle = -1;
|
||||
reply.pid = NULL;
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* create a new thread */
|
||||
DECL_HANDLER(new_thread)
|
||||
{
|
||||
struct new_thread_reply reply;
|
||||
int new_fd;
|
||||
|
||||
if ((new_fd = dup(fd)) != -1)
|
||||
{
|
||||
reply.tid = create_thread( new_fd, req->pid, req->suspend,
|
||||
req->inherit, &reply.handle );
|
||||
if (!reply.tid) close( new_fd );
|
||||
}
|
||||
else
|
||||
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
|
||||
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* initialize a new process */
|
||||
DECL_HANDLER(init_process)
|
||||
{
|
||||
struct init_process_reply reply;
|
||||
if (current->state != RUNNING)
|
||||
{
|
||||
fatal_protocol_error( "init_process: init_thread not called yet\n" );
|
||||
return;
|
||||
}
|
||||
if (!get_process_init_info( current->process, &reply ))
|
||||
{
|
||||
fatal_protocol_error( "init_process: called twice\n" );
|
||||
return;
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* initialize a new thread */
|
||||
DECL_HANDLER(init_thread)
|
||||
{
|
||||
struct init_thread_reply reply;
|
||||
|
||||
if (current->state != STARTING)
|
||||
{
|
||||
fatal_protocol_error( "init_thread: already running\n" );
|
||||
return;
|
||||
}
|
||||
current->state = RUNNING;
|
||||
current->unix_pid = req->unix_pid;
|
||||
if (current->suspend > 0)
|
||||
kill( current->unix_pid, SIGSTOP );
|
||||
reply.pid = current->process;
|
||||
reply.tid = current;
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set the debug level */
|
||||
DECL_HANDLER(set_debug)
|
||||
{
|
||||
|
@ -186,135 +102,6 @@ DECL_HANDLER(set_debug)
|
|||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* terminate a process */
|
||||
DECL_HANDLER(terminate_process)
|
||||
{
|
||||
struct process *process;
|
||||
|
||||
if ((process = get_process_from_handle( req->handle, PROCESS_TERMINATE )))
|
||||
{
|
||||
kill_process( process, req->exit_code );
|
||||
release_object( process );
|
||||
}
|
||||
if (current) send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* terminate a thread */
|
||||
DECL_HANDLER(terminate_thread)
|
||||
{
|
||||
struct thread *thread;
|
||||
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_TERMINATE )))
|
||||
{
|
||||
kill_thread( thread, req->exit_code );
|
||||
release_object( thread );
|
||||
}
|
||||
if (current) send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* close a handle */
|
||||
DECL_HANDLER(close_handle)
|
||||
{
|
||||
close_handle( current->process, req->handle );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get information about a handle */
|
||||
DECL_HANDLER(get_handle_info)
|
||||
{
|
||||
struct get_handle_info_reply reply;
|
||||
reply.flags = set_handle_info( current->process, req->handle, 0, 0 );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set a handle information */
|
||||
DECL_HANDLER(set_handle_info)
|
||||
{
|
||||
set_handle_info( current->process, req->handle, req->mask, req->flags );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* duplicate a handle */
|
||||
DECL_HANDLER(dup_handle)
|
||||
{
|
||||
struct dup_handle_reply reply = { -1 };
|
||||
struct process *src, *dst;
|
||||
|
||||
if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
|
||||
{
|
||||
if (req->options & DUP_HANDLE_MAKE_GLOBAL)
|
||||
{
|
||||
reply.handle = duplicate_handle( src, req->src_handle, NULL,
|
||||
req->access, req->inherit, req->options );
|
||||
}
|
||||
else if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
|
||||
{
|
||||
reply.handle = duplicate_handle( src, req->src_handle, dst,
|
||||
req->access, req->inherit, req->options );
|
||||
release_object( dst );
|
||||
}
|
||||
/* close the handle no matter what happened */
|
||||
if (req->options & DUP_HANDLE_CLOSE_SOURCE)
|
||||
close_handle( src, req->src_handle );
|
||||
release_object( src );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* fetch information about a process */
|
||||
DECL_HANDLER(get_process_info)
|
||||
{
|
||||
struct process *process;
|
||||
struct get_process_info_reply reply = { 0, 0, 0 };
|
||||
|
||||
if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
|
||||
{
|
||||
get_process_info( process, &reply );
|
||||
release_object( process );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set information about a process */
|
||||
DECL_HANDLER(set_process_info)
|
||||
{
|
||||
struct process *process;
|
||||
|
||||
if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION )))
|
||||
{
|
||||
set_process_info( process, req );
|
||||
release_object( process );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* fetch information about a thread */
|
||||
DECL_HANDLER(get_thread_info)
|
||||
{
|
||||
struct thread *thread;
|
||||
struct get_thread_info_reply reply = { 0, 0 };
|
||||
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
|
||||
{
|
||||
get_thread_info( thread, &reply );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set information about a thread */
|
||||
DECL_HANDLER(set_thread_info)
|
||||
{
|
||||
struct thread *thread;
|
||||
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_INFORMATION )))
|
||||
{
|
||||
set_thread_info( thread, req );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* debugger support operations */
|
||||
DECL_HANDLER(debugger)
|
||||
{
|
||||
|
@ -331,505 +118,3 @@ DECL_HANDLER(debugger)
|
|||
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* suspend a thread */
|
||||
DECL_HANDLER(suspend_thread)
|
||||
{
|
||||
struct thread *thread;
|
||||
struct suspend_thread_reply reply = { -1 };
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
|
||||
{
|
||||
reply.count = suspend_thread( thread );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
|
||||
}
|
||||
|
||||
/* resume a thread */
|
||||
DECL_HANDLER(resume_thread)
|
||||
{
|
||||
struct thread *thread;
|
||||
struct resume_thread_reply reply = { -1 };
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
|
||||
{
|
||||
reply.count = resume_thread( thread );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
|
||||
}
|
||||
|
||||
/* queue an APC for a thread */
|
||||
DECL_HANDLER(queue_apc)
|
||||
{
|
||||
struct thread *thread;
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
|
||||
{
|
||||
thread_queue_apc( thread, req->func, req->param );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* open a handle to a process */
|
||||
DECL_HANDLER(open_process)
|
||||
{
|
||||
struct open_process_reply reply = { -1 };
|
||||
struct process *process = get_process_from_id( req->pid );
|
||||
if (process)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, process,
|
||||
req->access, req->inherit );
|
||||
release_object( process );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* select on a handle list */
|
||||
DECL_HANDLER(select)
|
||||
{
|
||||
if (len != req->count * sizeof(int))
|
||||
fatal_protocol_error( "select: bad length %d for %d handles\n",
|
||||
len, req->count );
|
||||
sleep_on( current, req->count, (int *)data, req->flags, req->timeout );
|
||||
}
|
||||
|
||||
/* create an event */
|
||||
DECL_HANDLER(create_event)
|
||||
{
|
||||
struct create_event_reply reply = { -1 };
|
||||
struct object *obj;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_event", name, len );
|
||||
|
||||
obj = create_event( name, req->manual_reset, req->initial_state );
|
||||
if (obj)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, EVENT_ALL_ACCESS, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* do an event operation */
|
||||
DECL_HANDLER(event_op)
|
||||
{
|
||||
switch(req->op)
|
||||
{
|
||||
case PULSE_EVENT:
|
||||
pulse_event( req->handle );
|
||||
break;
|
||||
case SET_EVENT:
|
||||
set_event( req->handle );
|
||||
break;
|
||||
case RESET_EVENT:
|
||||
reset_event( req->handle );
|
||||
break;
|
||||
default:
|
||||
fatal_protocol_error( "event_op: invalid operation %d\n", req->op );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* create a mutex */
|
||||
DECL_HANDLER(create_mutex)
|
||||
{
|
||||
struct create_mutex_reply reply = { -1 };
|
||||
struct object *obj;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_mutex", name, len );
|
||||
|
||||
obj = create_mutex( name, req->owned );
|
||||
if (obj)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, MUTEX_ALL_ACCESS, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* release a mutex */
|
||||
DECL_HANDLER(release_mutex)
|
||||
{
|
||||
if (release_mutex( req->handle )) CLEAR_ERROR();
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* create a semaphore */
|
||||
DECL_HANDLER(create_semaphore)
|
||||
{
|
||||
struct create_semaphore_reply reply = { -1 };
|
||||
struct object *obj;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_semaphore", name, len );
|
||||
|
||||
obj = create_semaphore( name, req->initial, req->max );
|
||||
if (obj)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, SEMAPHORE_ALL_ACCESS, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* release a semaphore */
|
||||
DECL_HANDLER(release_semaphore)
|
||||
{
|
||||
struct release_semaphore_reply reply;
|
||||
if (release_semaphore( req->handle, req->count, &reply.prev_count )) CLEAR_ERROR();
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* open a handle to a named object (event, mutex, semaphore) */
|
||||
DECL_HANDLER(open_named_obj)
|
||||
{
|
||||
struct open_named_obj_reply reply;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "open_named_obj", name, len );
|
||||
|
||||
switch(req->type)
|
||||
{
|
||||
case OPEN_EVENT:
|
||||
reply.handle = open_event( req->access, req->inherit, name );
|
||||
break;
|
||||
case OPEN_MUTEX:
|
||||
reply.handle = open_mutex( req->access, req->inherit, name );
|
||||
break;
|
||||
case OPEN_SEMAPHORE:
|
||||
reply.handle = open_semaphore( req->access, req->inherit, name );
|
||||
break;
|
||||
case OPEN_MAPPING:
|
||||
reply.handle = open_mapping( req->access, req->inherit, name );
|
||||
break;
|
||||
default:
|
||||
fatal_protocol_error( "open_named_obj: invalid type %d\n", req->type );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* create a file */
|
||||
DECL_HANDLER(create_file)
|
||||
{
|
||||
struct create_file_reply reply = { -1 };
|
||||
struct object *obj;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_file", name, len );
|
||||
|
||||
if ((obj = create_file( fd, name, req->access,
|
||||
req->sharing, req->create, req->attrs )) != NULL)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* get a Unix fd to read from a file */
|
||||
DECL_HANDLER(get_read_fd)
|
||||
{
|
||||
struct object *obj;
|
||||
int read_fd;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_READ, NULL )))
|
||||
{
|
||||
read_fd = obj->ops->get_read_fd( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
else read_fd = -1;
|
||||
send_reply( current, read_fd, 0 );
|
||||
}
|
||||
|
||||
/* get a Unix fd to write to a file */
|
||||
DECL_HANDLER(get_write_fd)
|
||||
{
|
||||
struct object *obj;
|
||||
int write_fd;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_WRITE, NULL )))
|
||||
{
|
||||
write_fd = obj->ops->get_write_fd( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
else write_fd = -1;
|
||||
send_reply( current, write_fd, 0 );
|
||||
}
|
||||
|
||||
/* set a file current position */
|
||||
DECL_HANDLER(set_file_pointer)
|
||||
{
|
||||
struct set_file_pointer_reply reply;
|
||||
reply.low = req->low;
|
||||
reply.high = req->high;
|
||||
set_file_pointer( req->handle, &reply.low, &reply.high, req->whence );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* truncate (or extend) a file */
|
||||
DECL_HANDLER(truncate_file)
|
||||
{
|
||||
truncate_file( req->handle );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* flush a file buffers */
|
||||
DECL_HANDLER(flush_file)
|
||||
{
|
||||
struct object *obj;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, GENERIC_WRITE, NULL )))
|
||||
{
|
||||
obj->ops->flush( obj );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* set a file access and modification times */
|
||||
DECL_HANDLER(set_file_time)
|
||||
{
|
||||
set_file_time( req->handle, req->access_time, req->write_time );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get a file information */
|
||||
DECL_HANDLER(get_file_info)
|
||||
{
|
||||
struct object *obj;
|
||||
struct get_file_info_reply reply;
|
||||
|
||||
if ((obj = get_handle_obj( current->process, req->handle, 0, NULL )))
|
||||
{
|
||||
obj->ops->get_file_info( obj, &reply );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* lock a region of a file */
|
||||
DECL_HANDLER(lock_file)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
if ((file = get_file_obj( current->process, req->handle, 0 )))
|
||||
{
|
||||
file_lock( file, req->offset_high, req->offset_low,
|
||||
req->count_high, req->count_low );
|
||||
release_object( file );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
|
||||
/* unlock a region of a file */
|
||||
DECL_HANDLER(unlock_file)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
if ((file = get_file_obj( current->process, req->handle, 0 )))
|
||||
{
|
||||
file_unlock( file, req->offset_high, req->offset_low,
|
||||
req->count_high, req->count_low );
|
||||
release_object( file );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
|
||||
/* create an anonymous pipe */
|
||||
DECL_HANDLER(create_pipe)
|
||||
{
|
||||
struct create_pipe_reply reply = { -1, -1 };
|
||||
struct object *obj[2];
|
||||
if (create_pipe( obj ))
|
||||
{
|
||||
reply.handle_read = alloc_handle( current->process, obj[0],
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_READ,
|
||||
req->inherit );
|
||||
if (reply.handle_read != -1)
|
||||
{
|
||||
reply.handle_write = alloc_handle( current->process, obj[1],
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_WRITE,
|
||||
req->inherit );
|
||||
if (reply.handle_write == -1)
|
||||
close_handle( current->process, reply.handle_read );
|
||||
}
|
||||
release_object( obj[0] );
|
||||
release_object( obj[1] );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* allocate a console for the current process */
|
||||
DECL_HANDLER(alloc_console)
|
||||
{
|
||||
alloc_console( current->process );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* free the console of the current process */
|
||||
DECL_HANDLER(free_console)
|
||||
{
|
||||
free_console( current->process );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* open a handle to the process console */
|
||||
DECL_HANDLER(open_console)
|
||||
{
|
||||
struct object *obj;
|
||||
struct open_console_reply reply = { -1 };
|
||||
if ((obj = get_console( current->process, req->output )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set info about a console (output only) */
|
||||
DECL_HANDLER(set_console_info)
|
||||
{
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "set_console_info", name, len );
|
||||
set_console_info( req->handle, req, name );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get info about a console (output only) */
|
||||
DECL_HANDLER(get_console_info)
|
||||
{
|
||||
struct get_console_info_reply reply;
|
||||
const char *title;
|
||||
get_console_info( req->handle, &reply, &title );
|
||||
send_reply( current, -1, 2, &reply, sizeof(reply),
|
||||
title, title ? strlen(title)+1 : 0 );
|
||||
}
|
||||
|
||||
/* set a console fd */
|
||||
DECL_HANDLER(set_console_fd)
|
||||
{
|
||||
set_console_fd( req->handle, fd, req->pid );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* get a console mode (input or output) */
|
||||
DECL_HANDLER(get_console_mode)
|
||||
{
|
||||
struct get_console_mode_reply reply;
|
||||
get_console_mode( req->handle, &reply.mode );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set a console mode (input or output) */
|
||||
DECL_HANDLER(set_console_mode)
|
||||
{
|
||||
set_console_mode( req->handle, req->mode );
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* add input records to a console input queue */
|
||||
DECL_HANDLER(write_console_input)
|
||||
{
|
||||
struct write_console_input_reply reply;
|
||||
INPUT_RECORD *records = (INPUT_RECORD *)data;
|
||||
|
||||
if (len != req->count * sizeof(INPUT_RECORD))
|
||||
fatal_protocol_error( "write_console_input: bad length %d for %d records\n",
|
||||
len, req->count );
|
||||
reply.written = write_console_input( req->handle, req->count, records );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* fetch input records from a console input queue */
|
||||
DECL_HANDLER(read_console_input)
|
||||
{
|
||||
read_console_input( req->handle, req->count, req->flush );
|
||||
}
|
||||
|
||||
/* create a change notification */
|
||||
DECL_HANDLER(create_change_notification)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_change_notification_reply reply = { -1 };
|
||||
|
||||
if ((obj = create_change_notification( req->subtree, req->filter )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj,
|
||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* create a file mapping */
|
||||
DECL_HANDLER(create_mapping)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_mapping_reply reply = { -1 };
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_mapping", name, len );
|
||||
|
||||
if ((obj = create_mapping( req->size_high, req->size_low,
|
||||
req->protect, req->handle, name )))
|
||||
{
|
||||
int access = FILE_MAP_ALL_ACCESS;
|
||||
if (!(req->protect & VPROT_WRITE)) access &= ~FILE_MAP_WRITE;
|
||||
reply.handle = alloc_handle( current->process, obj, access, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* get a mapping information */
|
||||
DECL_HANDLER(get_mapping_info)
|
||||
{
|
||||
struct get_mapping_info_reply reply;
|
||||
int map_fd = get_mapping_info( req->handle, &reply );
|
||||
send_reply( current, map_fd, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* create a device */
|
||||
DECL_HANDLER(create_device)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_device_reply reply = { -1 };
|
||||
|
||||
if ((obj = create_device( req->id )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj,
|
||||
req->access, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* create a snapshot */
|
||||
DECL_HANDLER(create_snapshot)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_snapshot_reply reply = { -1 };
|
||||
|
||||
if ((obj = create_snapshot( req->flags )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, 0, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* get the next process from a snapshot */
|
||||
DECL_HANDLER(next_process)
|
||||
{
|
||||
struct next_process_reply reply;
|
||||
snapshot_next_process( req->handle, req->reset, &reply );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "server/object.h"
|
||||
#include "object.h"
|
||||
|
||||
/* select user fd */
|
||||
struct user
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "thread.h"
|
||||
|
||||
struct semaphore
|
||||
{
|
||||
|
@ -40,7 +41,7 @@ static const struct object_ops semaphore_ops =
|
|||
};
|
||||
|
||||
|
||||
struct object *create_semaphore( const char *name, unsigned int initial, unsigned int max )
|
||||
static struct object *create_semaphore( const char *name, unsigned int initial, unsigned int max )
|
||||
{
|
||||
struct semaphore *sem;
|
||||
|
||||
|
@ -60,12 +61,7 @@ struct object *create_semaphore( const char *name, unsigned int initial, unsigne
|
|||
return &sem->obj;
|
||||
}
|
||||
|
||||
int open_semaphore( unsigned int access, int inherit, const char *name )
|
||||
{
|
||||
return open_object( name, &semaphore_ops, access, inherit );
|
||||
}
|
||||
|
||||
int release_semaphore( int handle, unsigned int count, unsigned int *prev_count )
|
||||
static int release_semaphore( int handle, unsigned int count, unsigned int *prev_count )
|
||||
{
|
||||
struct semaphore *sem;
|
||||
|
||||
|
@ -124,3 +120,41 @@ static void semaphore_destroy( struct object *obj )
|
|||
assert( obj->ops == &semaphore_ops );
|
||||
free( sem );
|
||||
}
|
||||
|
||||
/* create a semaphore */
|
||||
DECL_HANDLER(create_semaphore)
|
||||
{
|
||||
struct create_semaphore_reply reply = { -1 };
|
||||
struct object *obj;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "create_semaphore", name, len );
|
||||
|
||||
obj = create_semaphore( name, req->initial, req->max );
|
||||
if (obj)
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, SEMAPHORE_ALL_ACCESS, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* open a handle to a semaphore */
|
||||
DECL_HANDLER(open_semaphore)
|
||||
{
|
||||
struct open_semaphore_reply reply;
|
||||
char *name = (char *)data;
|
||||
if (!len) name = NULL;
|
||||
else CHECK_STRING( "open_semaphore", name, len );
|
||||
|
||||
reply.handle = open_object( name, &semaphore_ops, req->access, req->inherit );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* release a semaphore */
|
||||
DECL_HANDLER(release_semaphore)
|
||||
{
|
||||
struct release_semaphore_reply reply;
|
||||
if (release_semaphore( req->handle, req->count, &reply.prev_count )) CLEAR_ERROR();
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "tlhelp32.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "process.h"
|
||||
#include "thread.h"
|
||||
|
||||
|
||||
struct snapshot
|
||||
|
@ -44,7 +46,7 @@ static const struct object_ops snapshot_ops =
|
|||
|
||||
|
||||
/* create a new snapshot */
|
||||
struct object *create_snapshot( int flags )
|
||||
static struct object *create_snapshot( int flags )
|
||||
{
|
||||
struct snapshot *snapshot;
|
||||
if (!(snapshot = mem_alloc( sizeof(*snapshot) ))) return NULL;
|
||||
|
@ -59,7 +61,7 @@ struct object *create_snapshot( int flags )
|
|||
}
|
||||
|
||||
/* get the next process in the snapshot */
|
||||
int snapshot_next_process( int handle, int reset, struct next_process_reply *reply )
|
||||
static int snapshot_next_process( int handle, int reset, struct next_process_reply *reply )
|
||||
{
|
||||
struct snapshot *snapshot;
|
||||
struct process_snapshot *ptr;
|
||||
|
@ -108,3 +110,25 @@ static void snapshot_destroy( struct object *obj )
|
|||
}
|
||||
free( snapshot );
|
||||
}
|
||||
|
||||
/* create a snapshot */
|
||||
DECL_HANDLER(create_snapshot)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_snapshot_reply reply = { -1 };
|
||||
|
||||
if ((obj = create_snapshot( req->flags )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, 0, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* get the next process from a snapshot */
|
||||
DECL_HANDLER(next_process)
|
||||
{
|
||||
struct next_process_reply reply;
|
||||
snapshot_next_process( req->handle, req->reset, &reply );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "server.h"
|
||||
|
||||
#include "server/object.h"
|
||||
#include "object.h"
|
||||
|
||||
/* Some versions of glibc don't define this */
|
||||
#ifndef SCM_RIGHTS
|
||||
|
|
158
server/thread.c
158
server/thread.c
|
@ -18,9 +18,11 @@
|
|||
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
|
||||
#include "handle.h"
|
||||
#include "server.h"
|
||||
#include "server/thread.h"
|
||||
#include "server/process.h"
|
||||
#include "process.h"
|
||||
#include "thread.h"
|
||||
|
||||
|
||||
/* thread queues */
|
||||
|
@ -81,6 +83,7 @@ static void init_thread( struct thread *thread, int fd )
|
|||
thread->client_fd = fd;
|
||||
thread->unix_pid = 0; /* not known yet */
|
||||
thread->mutex = NULL;
|
||||
thread->debugger = NULL;
|
||||
thread->wait = NULL;
|
||||
thread->apc = NULL;
|
||||
thread->apc_count = 0;
|
||||
|
@ -107,7 +110,7 @@ void create_initial_thread( int fd )
|
|||
}
|
||||
|
||||
/* create a new thread */
|
||||
struct thread *create_thread( int fd, void *pid, int suspend, int inherit, int *handle )
|
||||
static struct thread *create_thread( int fd, void *pid, int suspend, int inherit, int *handle )
|
||||
{
|
||||
struct thread *thread;
|
||||
struct process *process;
|
||||
|
@ -192,19 +195,9 @@ struct thread *get_thread_from_handle( int handle, unsigned int access )
|
|||
access, &thread_ops );
|
||||
}
|
||||
|
||||
/* get all information about a thread */
|
||||
void get_thread_info( struct thread *thread,
|
||||
struct get_thread_info_reply *reply )
|
||||
{
|
||||
reply->tid = thread;
|
||||
reply->exit_code = thread->exit_code;
|
||||
reply->priority = thread->priority;
|
||||
}
|
||||
|
||||
|
||||
/* set all information about a thread */
|
||||
void set_thread_info( struct thread *thread,
|
||||
struct set_thread_info_request *req )
|
||||
static void set_thread_info( struct thread *thread,
|
||||
struct set_thread_info_request *req )
|
||||
{
|
||||
if (req->mask & SET_THREAD_INFO_PRIORITY)
|
||||
thread->priority = req->priority;
|
||||
|
@ -216,7 +209,7 @@ void set_thread_info( struct thread *thread,
|
|||
}
|
||||
|
||||
/* suspend a thread */
|
||||
int suspend_thread( struct thread *thread )
|
||||
static int suspend_thread( struct thread *thread )
|
||||
{
|
||||
int old_count = thread->suspend;
|
||||
if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
|
||||
|
@ -230,7 +223,7 @@ int suspend_thread( struct thread *thread )
|
|||
}
|
||||
|
||||
/* resume a thread */
|
||||
int resume_thread( struct thread *thread )
|
||||
static int resume_thread( struct thread *thread )
|
||||
{
|
||||
int old_count = thread->suspend;
|
||||
if (thread->suspend > 0)
|
||||
|
@ -456,7 +449,7 @@ static int wake_thread( struct thread *thread )
|
|||
}
|
||||
|
||||
/* sleep on a list of objects */
|
||||
void sleep_on( struct thread *thread, int count, int *handles, int flags, int timeout )
|
||||
static void sleep_on( struct thread *thread, int count, int *handles, int flags, int timeout )
|
||||
{
|
||||
assert( !thread->wait );
|
||||
if (!wait_on( thread, count, handles, flags, timeout ))
|
||||
|
@ -498,7 +491,7 @@ void wake_up( struct object *obj, int max )
|
|||
}
|
||||
|
||||
/* queue an async procedure call */
|
||||
int thread_queue_apc( struct thread *thread, void *func, void *param )
|
||||
static int thread_queue_apc( struct thread *thread, void *func, void *param )
|
||||
{
|
||||
struct thread_apc *apc;
|
||||
if (!thread->apc)
|
||||
|
@ -534,3 +527,130 @@ void thread_killed( struct thread *thread, int exit_code )
|
|||
wake_up( &thread->obj, 0 );
|
||||
release_object( thread );
|
||||
}
|
||||
|
||||
/* create a new thread */
|
||||
DECL_HANDLER(new_thread)
|
||||
{
|
||||
struct new_thread_reply reply;
|
||||
int new_fd;
|
||||
|
||||
if ((new_fd = dup(fd)) != -1)
|
||||
{
|
||||
reply.tid = create_thread( new_fd, req->pid, req->suspend,
|
||||
req->inherit, &reply.handle );
|
||||
if (!reply.tid) close( new_fd );
|
||||
}
|
||||
else
|
||||
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
|
||||
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* initialize a new thread */
|
||||
DECL_HANDLER(init_thread)
|
||||
{
|
||||
struct init_thread_reply reply;
|
||||
|
||||
if (current->state != STARTING)
|
||||
{
|
||||
fatal_protocol_error( "init_thread: already running\n" );
|
||||
return;
|
||||
}
|
||||
current->state = RUNNING;
|
||||
current->unix_pid = req->unix_pid;
|
||||
if (current->suspend > 0) kill( current->unix_pid, SIGSTOP );
|
||||
reply.pid = current->process;
|
||||
reply.tid = current;
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* terminate a thread */
|
||||
DECL_HANDLER(terminate_thread)
|
||||
{
|
||||
struct thread *thread;
|
||||
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_TERMINATE )))
|
||||
{
|
||||
kill_thread( thread, req->exit_code );
|
||||
release_object( thread );
|
||||
}
|
||||
if (current) send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* fetch information about a thread */
|
||||
DECL_HANDLER(get_thread_info)
|
||||
{
|
||||
struct thread *thread;
|
||||
struct get_thread_info_reply reply = { 0, 0, 0 };
|
||||
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
|
||||
{
|
||||
reply.tid = thread;
|
||||
reply.exit_code = thread->exit_code;
|
||||
reply.priority = thread->priority;
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* set information about a thread */
|
||||
DECL_HANDLER(set_thread_info)
|
||||
{
|
||||
struct thread *thread;
|
||||
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_INFORMATION )))
|
||||
{
|
||||
set_thread_info( thread, req );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
||||
/* suspend a thread */
|
||||
DECL_HANDLER(suspend_thread)
|
||||
{
|
||||
struct thread *thread;
|
||||
struct suspend_thread_reply reply = { -1 };
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
|
||||
{
|
||||
reply.count = suspend_thread( thread );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
|
||||
}
|
||||
|
||||
/* resume a thread */
|
||||
DECL_HANDLER(resume_thread)
|
||||
{
|
||||
struct thread *thread;
|
||||
struct resume_thread_reply reply = { -1 };
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
|
||||
{
|
||||
reply.count = resume_thread( thread );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
|
||||
}
|
||||
|
||||
/* select on a handle list */
|
||||
DECL_HANDLER(select)
|
||||
{
|
||||
if (len != req->count * sizeof(int))
|
||||
fatal_protocol_error( "select: bad length %d for %d handles\n",
|
||||
len, req->count );
|
||||
sleep_on( current, req->count, (int *)data, req->flags, req->timeout );
|
||||
}
|
||||
|
||||
/* queue an APC for a thread */
|
||||
DECL_HANDLER(queue_apc)
|
||||
{
|
||||
struct thread *thread;
|
||||
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT )))
|
||||
{
|
||||
thread_queue_apc( thread, req->func, req->param );
|
||||
release_object( thread );
|
||||
}
|
||||
send_reply( current, -1, 0 );
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#error This file can only be used in the Wine server
|
||||
#endif
|
||||
|
||||
#include "server/object.h"
|
||||
#include "object.h"
|
||||
|
||||
/* thread structure */
|
||||
|
||||
|
@ -19,6 +19,7 @@ struct process;
|
|||
struct thread_wait;
|
||||
struct thread_apc;
|
||||
struct mutex;
|
||||
struct debugger;
|
||||
|
||||
enum run_state { STARTING, RUNNING, TERMINATED };
|
||||
|
||||
|
@ -31,6 +32,7 @@ struct thread
|
|||
struct thread *proc_prev;
|
||||
struct process *process;
|
||||
struct mutex *mutex; /* list of currently owned mutexes */
|
||||
struct debugger *debugger; /* debugger info if this thread is a debugger */
|
||||
struct thread_wait *wait; /* current wait condition if sleeping */
|
||||
struct thread_apc *apc; /* list of async procedure calls */
|
||||
int apc_count; /* number of outstanding APCs */
|
||||
|
@ -50,27 +52,17 @@ extern struct thread *current;
|
|||
/* thread functions */
|
||||
|
||||
extern void create_initial_thread( int fd );
|
||||
extern struct thread *create_thread( int fd, void *pid, int suspend, int inherit, int *handle );
|
||||
extern struct thread *get_thread_from_id( void *id );
|
||||
extern struct thread *get_thread_from_handle( int handle, unsigned int access );
|
||||
extern void get_thread_info( struct thread *thread,
|
||||
struct get_thread_info_reply *reply );
|
||||
extern void set_thread_info( struct thread *thread,
|
||||
struct set_thread_info_request *req );
|
||||
extern int suspend_thread( struct thread *thread );
|
||||
extern int resume_thread( struct thread *thread );
|
||||
extern void suspend_all_threads( void );
|
||||
extern void resume_all_threads( void );
|
||||
extern int send_reply( struct thread *thread, int pass_fd,
|
||||
int n, ... /* arg_1, len_1, ..., arg_n, len_n */ );
|
||||
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||
extern int thread_queue_apc( struct thread *thread, void *func, void *param );
|
||||
extern void kill_thread( struct thread *thread, int exit_code );
|
||||
extern void thread_killed( struct thread *thread, int exit_code );
|
||||
extern void thread_timeout(void);
|
||||
extern void sleep_on( struct thread *thread, int count, int *handles,
|
||||
int flags, int timeout );
|
||||
extern void wake_up( struct object *obj, int max );
|
||||
|
||||
#define GET_ERROR() (current->error)
|
|
@ -4,7 +4,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include "server.h"
|
||||
#include "server/thread.h"
|
||||
#include "thread.h"
|
||||
|
||||
static int dump_new_process_request( struct new_process_request *req, int len )
|
||||
{
|
||||
|
@ -269,6 +269,20 @@ static int dump_event_op_request( struct event_op_request *req, int len )
|
|||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_open_event_request( struct open_event_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " access=%08x,", req->access );
|
||||
fprintf( stderr, " inherit=%d,", req->inherit );
|
||||
fprintf( stderr, " name=\"%.*s\"", len - (int)sizeof(*req), (char *)(req+1) );
|
||||
return len;
|
||||
}
|
||||
|
||||
static int dump_open_event_reply( struct open_event_reply *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_mutex_request( struct create_mutex_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " owned=%d,", req->owned );
|
||||
|
@ -289,6 +303,20 @@ static int dump_release_mutex_request( struct release_mutex_request *req, int le
|
|||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_open_mutex_request( struct open_mutex_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " access=%08x,", req->access );
|
||||
fprintf( stderr, " inherit=%d,", req->inherit );
|
||||
fprintf( stderr, " name=\"%.*s\"", len - (int)sizeof(*req), (char *)(req+1) );
|
||||
return len;
|
||||
}
|
||||
|
||||
static int dump_open_mutex_reply( struct open_mutex_reply *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_semaphore_request( struct create_semaphore_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " initial=%08x,", req->initial );
|
||||
|
@ -317,16 +345,15 @@ static int dump_release_semaphore_reply( struct release_semaphore_reply *req, in
|
|||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_open_named_obj_request( struct open_named_obj_request *req, int len )
|
||||
static int dump_open_semaphore_request( struct open_semaphore_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " type=%d,", req->type );
|
||||
fprintf( stderr, " access=%08x,", req->access );
|
||||
fprintf( stderr, " inherit=%d,", req->inherit );
|
||||
fprintf( stderr, " name=\"%.*s\"", len - (int)sizeof(*req), (char *)(req+1) );
|
||||
return len;
|
||||
}
|
||||
|
||||
static int dump_open_named_obj_reply( struct open_named_obj_reply *req, int len )
|
||||
static int dump_open_semaphore_reply( struct open_semaphore_reply *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
|
@ -584,6 +611,20 @@ static int dump_create_mapping_reply( struct create_mapping_reply *req, int len
|
|||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_open_mapping_request( struct open_mapping_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " access=%08x,", req->access );
|
||||
fprintf( stderr, " inherit=%d,", req->inherit );
|
||||
fprintf( stderr, " name=\"%.*s\"", len - (int)sizeof(*req), (char *)(req+1) );
|
||||
return len;
|
||||
}
|
||||
|
||||
static int dump_open_mapping_reply( struct open_mapping_reply *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_get_mapping_info_request( struct get_mapping_info_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d", req->handle );
|
||||
|
@ -694,16 +735,20 @@ static const struct dumper dumpers[REQ_NB_REQUESTS] =
|
|||
(void(*)())dump_create_event_reply },
|
||||
{ (int(*)(void *,int))dump_event_op_request,
|
||||
(void(*)())0 },
|
||||
{ (int(*)(void *,int))dump_open_event_request,
|
||||
(void(*)())dump_open_event_reply },
|
||||
{ (int(*)(void *,int))dump_create_mutex_request,
|
||||
(void(*)())dump_create_mutex_reply },
|
||||
{ (int(*)(void *,int))dump_release_mutex_request,
|
||||
(void(*)())0 },
|
||||
{ (int(*)(void *,int))dump_open_mutex_request,
|
||||
(void(*)())dump_open_mutex_reply },
|
||||
{ (int(*)(void *,int))dump_create_semaphore_request,
|
||||
(void(*)())dump_create_semaphore_reply },
|
||||
{ (int(*)(void *,int))dump_release_semaphore_request,
|
||||
(void(*)())dump_release_semaphore_reply },
|
||||
{ (int(*)(void *,int))dump_open_named_obj_request,
|
||||
(void(*)())dump_open_named_obj_reply },
|
||||
{ (int(*)(void *,int))dump_open_semaphore_request,
|
||||
(void(*)())dump_open_semaphore_reply },
|
||||
{ (int(*)(void *,int))dump_create_file_request,
|
||||
(void(*)())dump_create_file_reply },
|
||||
{ (int(*)(void *,int))dump_get_read_fd_request,
|
||||
|
@ -750,6 +795,8 @@ static const struct dumper dumpers[REQ_NB_REQUESTS] =
|
|||
(void(*)())dump_create_change_notification_reply },
|
||||
{ (int(*)(void *,int))dump_create_mapping_request,
|
||||
(void(*)())dump_create_mapping_reply },
|
||||
{ (int(*)(void *,int))dump_open_mapping_request,
|
||||
(void(*)())dump_open_mapping_reply },
|
||||
{ (int(*)(void *,int))dump_get_mapping_info_request,
|
||||
(void(*)())dump_get_mapping_info_reply },
|
||||
{ (int(*)(void *,int))dump_create_device_request,
|
||||
|
@ -785,11 +832,13 @@ static const char * const req_names[REQ_NB_REQUESTS] =
|
|||
"select",
|
||||
"create_event",
|
||||
"event_op",
|
||||
"open_event",
|
||||
"create_mutex",
|
||||
"release_mutex",
|
||||
"open_mutex",
|
||||
"create_semaphore",
|
||||
"release_semaphore",
|
||||
"open_named_obj",
|
||||
"open_semaphore",
|
||||
"create_file",
|
||||
"get_read_fd",
|
||||
"get_write_fd",
|
||||
|
@ -813,6 +862,7 @@ static const char * const req_names[REQ_NB_REQUESTS] =
|
|||
"read_console_input",
|
||||
"create_change_notification",
|
||||
"create_mapping",
|
||||
"open_mapping",
|
||||
"get_mapping_info",
|
||||
"create_device",
|
||||
"create_snapshot",
|
||||
|
|
|
@ -33,7 +33,7 @@ print TRACE <<EOF;
|
|||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include "server.h"
|
||||
#include "server/thread.h"
|
||||
#include "thread.h"
|
||||
EOF
|
||||
|
||||
### Parse server.h to find request/reply structure definitions
|
||||
|
@ -159,9 +159,6 @@ print REQUESTS <<EOF;
|
|||
|
||||
#ifdef WANT_REQUEST_HANDLERS
|
||||
|
||||
#define DECL_HANDLER(name) \\
|
||||
static void req_##name( struct name##_request *req, void *data, int len, int fd )
|
||||
|
||||
EOF
|
||||
|
||||
foreach $req (@requests) { print REQUESTS "DECL_HANDLER($req);\n"; }
|
||||
|
|
Loading…
Reference in New Issue