Commit 5bc78089 authored by Alexandre Julliard's avatar Alexandre Julliard

Made server communication faster by using a shared memory block.

A few other optimizations in request processing in the server. Moved automatically generated request definitions to server.h and removed include/server/request.h.
parent 0a860a01
......@@ -43,7 +43,6 @@
#include "wincon.h"
#include "debug.h"
#include "server/request.h"
#include "server.h"
DEFAULT_DEBUG_CHANNEL(file)
......
......@@ -15,11 +15,10 @@ struct header
{
unsigned int len; /* total msg length (including this header) */
unsigned int type; /* msg type */
unsigned int seq; /* sequence number */
};
/* max msg length (not including the header) */
#define MAX_MSG_LENGTH (16384 - sizeof(struct header))
/* max msg length (including the header) */
#define MAX_MSG_LENGTH 16384
/* data structure used to pass an fd with sendmsg/recvmsg */
struct cmsg_fd
......@@ -30,10 +29,6 @@ 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 */
/* following are the definitions of all the client<->server */
......@@ -855,13 +850,104 @@ struct debug_process_request
};
/* requests definitions */
#include "server/request.h"
/* Everything below this line is generated automatically by tools/make_requests */
/* ### make_requests begin ### */
enum request
{
REQ_NEW_PROCESS,
REQ_NEW_THREAD,
REQ_SET_DEBUG,
REQ_INIT_PROCESS,
REQ_INIT_THREAD,
REQ_TERMINATE_PROCESS,
REQ_TERMINATE_THREAD,
REQ_GET_PROCESS_INFO,
REQ_SET_PROCESS_INFO,
REQ_GET_THREAD_INFO,
REQ_SET_THREAD_INFO,
REQ_SUSPEND_THREAD,
REQ_RESUME_THREAD,
REQ_DEBUGGER,
REQ_QUEUE_APC,
REQ_CLOSE_HANDLE,
REQ_GET_HANDLE_INFO,
REQ_SET_HANDLE_INFO,
REQ_DUP_HANDLE,
REQ_OPEN_PROCESS,
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_SEMAPHORE,
REQ_CREATE_FILE,
REQ_GET_READ_FD,
REQ_GET_WRITE_FD,
REQ_SET_FILE_POINTER,
REQ_TRUNCATE_FILE,
REQ_SET_FILE_TIME,
REQ_FLUSH_FILE,
REQ_GET_FILE_INFO,
REQ_LOCK_FILE,
REQ_UNLOCK_FILE,
REQ_CREATE_PIPE,
REQ_ALLOC_CONSOLE,
REQ_FREE_CONSOLE,
REQ_OPEN_CONSOLE,
REQ_SET_CONSOLE_FD,
REQ_GET_CONSOLE_MODE,
REQ_SET_CONSOLE_MODE,
REQ_SET_CONSOLE_INFO,
REQ_GET_CONSOLE_INFO,
REQ_WRITE_CONSOLE_INPUT,
REQ_READ_CONSOLE_INPUT,
REQ_CREATE_CHANGE_NOTIFICATION,
REQ_CREATE_MAPPING,
REQ_OPEN_MAPPING,
REQ_GET_MAPPING_INFO,
REQ_CREATE_DEVICE,
REQ_CREATE_SNAPSHOT,
REQ_NEXT_PROCESS,
REQ_WAIT_DEBUG_EVENT,
REQ_SEND_DEBUG_EVENT,
REQ_CONTINUE_DEBUG_EVENT,
REQ_DEBUG_PROCESS,
REQ_NB_REQUESTS
};
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
/* client-side functions */
#ifndef __WINE_SERVER__
#include "thread.h"
/* make space for some data in the server arguments buffer */
static inline void *server_add_data( int len )
{
void *old = NtCurrentTeb()->buffer_args;
NtCurrentTeb()->buffer_args = (char *)old + len;
return old;
}
/* maximum remaining size in the server arguments buffer */
static inline int server_remaining(void)
{
TEB *teb = NtCurrentTeb();
return (char *)teb->buffer + teb->buffer_size - (char *)teb->buffer_args;
}
extern unsigned int server_call( enum request req );
extern unsigned int server_call_fd( enum request req, int *fd );
/* client communication functions */
extern void CLIENT_ProtocolError( const char *err, ... );
extern void CLIENT_SendRequest( enum request req, int pass_fd,
......
......@@ -34,13 +34,13 @@ typedef struct _TEB
WORD pad1; /* 2a */
LPVOID *tls_ptr; /* 2c Pointer to TLS array */
struct _PDB *process; /* 30 owning process (used by NT3.51 applets)*/
void *buffer; /* 34 Buffer shared with server */
int socket; /* 34 Socket for server communication */
DWORD exit_code; /* 38 Termination status */
WORD teb_sel; /* 3c Selector to TEB */
WORD emu_sel; /* 3e 80387 emulator selector */
void *buffer_args; /* 40 Current position of arguments in server buffer */
void *buffer_res; /* 44 Current position of result in server buffer */
void *buffer_end; /* 48 End of server buffer */
void *buffer; /* 40 Buffer shared with server */
void *buffer_args; /* 44 Current position of arguments in server buffer */
int buffer_size; /* 48 Size of server buffer */
int thread_errno; /* 4c Per-thread errno (was: ring0_thread) */
int thread_h_errno; /* 50 Per-thread h_errno (was: ptr to tdbx structure) */
void *stack_base; /* 54 Base of the stack */
......@@ -69,7 +69,6 @@ typedef struct _TEB
SYSLEVEL *sys_mutex[4]; /* 1d8 Syslevel mutex pointers */
DWORD unknown6[2]; /* 1e8 Unknown */
/* The following are Wine-specific fields */
int socket; /* Socket for server communication */
unsigned int seq; /* Server sequence number */
void (*startup)(void); /* Thread startup routine */
struct _TEB *next; /* Global thread list */
......
......@@ -1074,6 +1074,7 @@ HANDLE WINAPI CreateFileMappingA(
/* Create the server object */
if (!name) name = "";
req.handle = hFile;
req.size_high = size_high;
req.size_low = size_low;
......@@ -1081,7 +1082,7 @@ HANDLE WINAPI CreateFileMappingA(
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
CLIENT_SendRequest( REQ_CREATE_MAPPING, -1, 2,
&req, sizeof(req),
name, name ? strlen(name) + 1 : 0 );
name, strlen(name) + 1 );
SetLastError(0);
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
if (reply.handle == -1) return 0;
......
......@@ -61,7 +61,6 @@
#include "heap.h"
#include "options.h"
#include "server/request.h"
#include "server.h"
#include "process.h"
#include "winerror.h"
......
......@@ -6,7 +6,6 @@
#include "process.h"
#include "thread.h"
#include "server/request.h"
#include "server.h"
#include "debugtools.h"
......
......@@ -9,7 +9,6 @@
#include "winerror.h"
#include "heap.h"
#include "syslevel.h"
#include "server/request.h"
#include "server.h"
......@@ -21,12 +20,12 @@ HANDLE WINAPI CreateEventA( SECURITY_ATTRIBUTES *sa, BOOL manual_reset,
{
struct create_event_request req;
struct create_event_reply reply;
int len = name ? strlen(name) + 1 : 0;
if (!name) name = "";
req.manual_reset = manual_reset;
req.initial_state = initial_state;
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
CLIENT_SendRequest( REQ_CREATE_EVENT, -1, 2, &req, sizeof(req), name, len );
CLIENT_SendRequest( REQ_CREATE_EVENT, -1, 2, &req, sizeof(req), name, strlen(name)+1 );
SetLastError(0);
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
if (reply.handle == -1) return 0;
......
......@@ -8,7 +8,6 @@
#include <string.h>
#include "winerror.h"
#include "heap.h"
#include "server/request.h"
#include "server.h"
......@@ -19,11 +18,11 @@ HANDLE WINAPI CreateMutexA( SECURITY_ATTRIBUTES *sa, BOOL owner, LPCSTR name )
{
struct create_mutex_request req;
struct create_mutex_reply reply;
int len = name ? strlen(name) + 1 : 0;
if (!name) name = "";
req.owned = owner;
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
CLIENT_SendRequest( REQ_CREATE_MUTEX, -1, 2, &req, sizeof(req), name, len );
CLIENT_SendRequest( REQ_CREATE_MUTEX, -1, 2, &req, sizeof(req), name, strlen(name)+1 );
SetLastError(0);
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
if (reply.handle == -1) return 0;
......
......@@ -7,7 +7,6 @@
#include <assert.h>
#include "winerror.h"
#include "winbase.h"
#include "server/request.h"
#include "server.h"
......
......@@ -8,19 +8,16 @@
#include <string.h>
#include "winerror.h"
#include "heap.h"
#include "server/request.h"
#include "server.h"
/***********************************************************************
* CreateSemaphore32A (KERNEL32.174)
*/
HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial,
LONG max, LPCSTR name )
HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial, LONG max, LPCSTR name )
{
struct create_semaphore_request req;
struct create_semaphore_reply reply;
int len = name ? strlen(name) + 1 : 0;
/* Check parameters */
......@@ -30,11 +27,12 @@ HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial,
return 0;
}
if (!name) name = "";
req.initial = (unsigned int)initial;
req.max = (unsigned int)max;
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
CLIENT_SendRequest( REQ_CREATE_SEMAPHORE, -1, 2, &req, sizeof(req), name, len );
CLIENT_SendRequest( REQ_CREATE_SEMAPHORE, -1, 2, &req, sizeof(req), name, strlen(name)+1 );
SetLastError(0);
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
if (reply.handle == -1) return 0;
......
......@@ -154,8 +154,7 @@ void CALLBACK THREAD_FreeTEB( ULONG_PTR arg )
if (teb->stack_sel) SELECTOR_FreeBlock( teb->stack_sel, 1 );
SELECTOR_FreeBlock( teb->teb_sel, 1 );
close( teb->socket );
if (teb->buffer)
munmap( teb->buffer, (char *)teb->buffer_end - (char *)teb->buffer );
if (teb->buffer) munmap( teb->buffer, teb->buffer_size );
VirtualFree( teb->stack_base, 0, MEM_RELEASE );
HeapFree( SystemHeap, 0, teb );
}
......
......@@ -13,6 +13,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
struct change
{
......@@ -23,10 +24,10 @@ struct change
static void change_dump( struct object *obj, int verbose );
static int change_signaled( struct object *obj, struct thread *thread );
static void change_destroy( struct object *obj );
static const struct object_ops change_ops =
{
sizeof(struct change),
change_dump,
add_queue,
remove_queue,
......@@ -36,15 +37,14 @@ static const struct object_ops change_ops =
no_write_fd,
no_flush,
no_get_file_info,
change_destroy
no_destroy
};
static struct object *create_change_notification( int subtree, int filter )
{
struct change *change;
if (!(change = mem_alloc( sizeof(*change) ))) return NULL;
init_object( &change->obj, &change_ops, NULL );
if (!(change = alloc_object( &change_ops ))) return NULL;
change->subtree = subtree;
change->filter = filter;
return &change->obj;
......@@ -65,24 +65,16 @@ static int change_signaled( struct object *obj, struct thread *thread )
return 0; /* never signaled for now */
}
static void change_destroy( struct object *obj )
{
struct change *change = (struct change *)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 };
struct create_change_notification_reply *reply = push_reply_data( current, sizeof(*reply) );
if ((obj = create_change_notification( req->subtree, req->filter )))
{
reply.handle = alloc_handle( current->process, obj,
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
reply->handle = alloc_handle( current->process, obj,
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
release_object( obj );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
}
......@@ -8,11 +8,10 @@
#include "winbase.h"
#include "winerror.h"
#include "server.h"
#include "handle.h"
#include "process.h"
#include "thread.h"
#include "request.h"
struct debug_event
{
......@@ -143,20 +142,20 @@ static void link_event( struct debug_ctx *debug_ctx, struct debug_event *event )
}
/* send the first queue event as a reply */
static void send_event_reply( struct debug_ctx *debug_ctx )
static void build_event_reply( struct debug_ctx *debug_ctx )
{
struct wait_debug_event_reply reply;
struct debug_event *event = debug_ctx->event_head;
struct thread *thread = event->thread;
struct wait_debug_event_reply *reply = push_reply_data( debug_ctx->owner, sizeof(*reply) );
assert( event );
assert( debug_ctx->waiting );
unlink_event( debug_ctx, event );
event->sent = 1;
reply.code = event->code;
reply.pid = thread->process;
reply.tid = thread;
reply->code = event->code;
reply->pid = thread->process;
reply->tid = thread;
debug_ctx->waiting = 0;
if (debug_ctx->timeout)
{
......@@ -164,25 +163,24 @@ static void send_event_reply( struct debug_ctx *debug_ctx )
debug_ctx->timeout = NULL;
}
debug_ctx->owner->error = 0;
send_reply( debug_ctx->owner, -1, 2, &reply, sizeof(reply),
&event->data, event_sizes[event->code] );
add_reply_data( debug_ctx->owner, &event->data, event_sizes[event->code] );
}
/* timeout callback while waiting for a debug event */
static void wait_event_timeout( void *ctx )
{
struct debug_ctx *debug_ctx = (struct debug_ctx *)ctx;
struct wait_debug_event_reply reply;
struct wait_debug_event_reply *reply = push_reply_data( debug_ctx->owner, sizeof(*reply) );
assert( debug_ctx->waiting );
reply.code = 0;
reply.pid = 0;
reply.tid = 0;
reply->code = 0;
reply->pid = 0;
reply->tid = 0;
debug_ctx->waiting = 0;
debug_ctx->timeout = NULL;
debug_ctx->owner->error = WAIT_TIMEOUT;
send_reply( debug_ctx->owner, -1, 1, &reply, sizeof(reply) );
send_reply( debug_ctx->owner );
}
/* wait for a debug event (or send a reply at once if one is pending) */
......@@ -193,19 +191,19 @@ static int wait_for_debug_event( int timeout )
if (!debug_ctx) /* current thread is not a debugger */
{
SET_ERROR( ERROR_ACCESS_DENIED ); /* FIXME */
set_error( ERROR_ACCESS_DENIED ); /* FIXME */
return 0;
}
assert( !debug_ctx->waiting );
if (debug_ctx->event_head) /* already have a pending event */
{
debug_ctx->waiting = 1;
send_event_reply( debug_ctx );
build_event_reply( debug_ctx );
return 1;
}
if (!timeout) /* no event and we don't want to wait */
{
SET_ERROR( WAIT_TIMEOUT );
set_error( WAIT_TIMEOUT );
return 0;
}
if (timeout != -1) /* start the timeout */
......@@ -215,6 +213,7 @@ static int wait_for_debug_event( int timeout )
return 0;
}
debug_ctx->waiting = 1;
current->state = SLEEPING;
return 1;
}
......@@ -226,16 +225,16 @@ static int continue_debug_event( struct process *process, struct thread *thread,
if (process->debugger != current || !event || !event->sent)
{
/* not debugging this process, or no event pending */
SET_ERROR( ERROR_ACCESS_DENIED ); /* FIXME */
set_error( ERROR_ACCESS_DENIED ); /* FIXME */
return 0;
}
if (thread->state != TERMINATED)
{
/* only send a reply if the thread is still there */
/* (we can get a continue on an exit thread/process event) */
struct send_debug_event_reply reply;
reply.status = status;
send_reply( thread, -1, 1, &reply, sizeof(reply) );
struct send_debug_event_reply *reply = push_reply_data( thread, sizeof(*reply) );
reply->status = status;
send_reply( thread );
}
free_event( event );
resume_process( process );
......@@ -279,7 +278,11 @@ static struct debug_event *queue_debug_event( struct thread *debugger, struct th
link_event( debug_ctx, event );
thread->debug_event = event;
suspend_process( thread->process );
if (debug_ctx->waiting) send_event_reply( debug_ctx );
if (debug_ctx->waiting)
{
build_event_reply( debug_ctx );
send_reply( debug_ctx->owner );
}
return event;
}
......@@ -291,14 +294,14 @@ int debugger_attach( struct process *process, struct thread *debugger )
if (process->debugger) /* already being debugged */
{
SET_ERROR( ERROR_ACCESS_DENIED );
set_error( ERROR_ACCESS_DENIED );
return 0;
}
/* make sure we don't create a debugging loop */
for (thread = debugger; thread; thread = thread->process->debugger)
if (thread->process == process)
{
SET_ERROR( ERROR_ACCESS_DENIED );
set_error( ERROR_ACCESS_DENIED );
return 0;
}
......@@ -375,14 +378,12 @@ void debug_exit_thread( struct thread *thread, int exit_code )
/* Wait for a debug event */
DECL_HANDLER(wait_debug_event)
{
struct wait_debug_event_reply reply;
if (!wait_for_debug_event( req->timeout ))
{
reply.code = 0;
reply.pid = NULL;
reply.tid = NULL;
send_reply( current, -1, 1, &reply, sizeof(reply) );
struct wait_debug_event_reply *reply = push_reply_data( current, sizeof(*reply) );
reply->code = 0;
reply->pid = NULL;
reply->tid = NULL;
}
}
......@@ -400,7 +401,6 @@ DECL_HANDLER(continue_debug_event)
}
release_object( process );
}
send_reply( current, -1, 0 );
}
/* Start debugging an existing process */
......@@ -413,26 +413,33 @@ DECL_HANDLER(debug_process)
/* FIXME: should notice the debugged process somehow */
release_object( process );
}
send_reply( current, -1, 0 );
}
/* Send a debug event */
DECL_HANDLER(send_debug_event)
{
struct thread *debugger = current->process->debugger;
struct send_debug_event_reply reply;
if ((req->code <= 0) || (req->code > RIP_EVENT))
fatal_protocol_error( "send_debug_event: bad event code %d\n", req->code );
if (len != event_sizes[req->code])
fatal_protocol_error( "send_debug_event: bad event length %d/%d\n",
len, event_sizes[req->code] );
assert( !current->debug_event );
reply.status = 0;
if (debugger)
if ((req->code <= 0) || (req->code > RIP_EVENT))
{
fatal_protocol_error( "send_debug_event: bad event code" );
return;
}
if (!check_req_data( event_sizes[req->code] ))
{
fatal_protocol_error( "send_debug_event: bad length" );
return;
}
if (debugger && queue_debug_event( debugger, current, req->code,
get_req_data( event_sizes[req->code] )))
{
/* wait for continue_debug_event */
current->state = SLEEPING;
}
else
{
if (queue_debug_event( debugger, current, req->code, data ))
return; /* don't reply now, wait for continue_debug_event */
struct send_debug_event_reply *reply = push_reply_data( current, sizeof(*reply) );
reply->status = 0;
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
}
......@@ -21,6 +21,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
struct device
{
......@@ -30,10 +31,10 @@ struct device
static void device_dump( struct object *obj, int verbose );
static int device_get_info( struct object *obj, struct get_file_info_reply *reply );
static void device_destroy( struct object *obj );
static const struct object_ops device_ops =
{
sizeof(struct device),
device_dump,
no_add_queue,
NULL, /* should never get called */
......@@ -43,17 +44,17 @@ static const struct object_ops device_ops =
no_write_fd,
no_flush,
device_get_info,
device_destroy
no_destroy
};
static struct object *create_device( int id )
static struct device *create_device( int id )
{
struct device *dev;
if (!(dev = mem_alloc(sizeof(*dev)))) return NULL;
init_object( &dev->obj, &device_ops, NULL );
dev->id = id;
return &dev->obj;
if ((dev = alloc_object( &device_ops )))
{
dev->id = id;
}
return dev;
}
static void device_dump( struct object *obj, int verbose )
......@@ -73,24 +74,16 @@ static int device_get_info( struct object *obj, struct get_file_info_reply *repl
return 1;
}
static void device_destroy( struct object *obj )
{
struct device *dev = (struct device *)obj;
assert( obj->ops == &device_ops );
free( dev );
}
/* create a device */
DECL_HANDLER(create_device)
{
struct object *obj;
struct create_device_reply reply = { -1 };
struct device *dev;
struct create_device_reply *reply = push_reply_data( current, sizeof(*reply) );
if ((obj = create_device( req->id )))
if ((dev = create_device( req->id )))
{
reply.handle = alloc_handle( current->process, obj,
req->access, req->inherit );
release_object( obj );
reply->handle = alloc_handle( current->process, dev, req->access, req->inherit );
release_object( dev );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
else reply->handle = -1;
}
......@@ -13,6 +13,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
struct event
{
......@@ -24,10 +25,10 @@ struct event
static void event_dump( struct object *obj, int verbose );
static int event_signaled( struct object *obj, struct thread *thread );
static int event_satisfied( struct object *obj, struct thread *thread );
static void event_destroy( struct object *obj );
static const struct object_ops event_ops =
{
sizeof(struct event),
event_dump,
add_queue,
remove_queue,
......@@ -37,23 +38,25 @@ static const struct object_ops event_ops =
no_write_fd,
no_flush,
no_get_file_info,
event_destroy
no_destroy
};
static struct object *create_event( const char *name, int manual_reset, int initial_state )
static struct event *create_event( const char *name, size_t len,
int manual_reset, int initial_state )
{
struct event *event;
if (!(event = (struct event *)create_named_object( name, &event_ops, sizeof(*event) )))
return NULL;
if (GET_ERROR() != ERROR_ALREADY_EXISTS)
if ((event = create_named_object( &event_ops, name, len )))
{
/* initialize it if it didn't already exist */
event->manual_reset = manual_reset;
event->signaled = initial_state;
if (get_error() != ERROR_ALREADY_EXISTS)
{
/* initialize it if it didn't already exist */
event->manual_reset = manual_reset;
event->signaled = initial_state;
}
}
return &event->obj;
return event;
}
static int pulse_event( int handle )
......@@ -122,41 +125,28 @@ static int event_satisfied( struct object *obj, struct thread *thread )
return 0; /* Not abandoned */
}
static void event_destroy( struct object *obj )
{
struct event *event = (struct event *)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)
size_t len = get_req_strlen();
struct create_event_reply *reply = push_reply_data( current, sizeof(*reply) );
struct event *event;
if ((event = create_event( get_req_data(len+1), len, req->manual_reset, req->initial_state )))
{
reply.handle = alloc_handle( current->process, obj, EVENT_ALL_ACCESS, req->inherit );
release_object( obj );
reply->handle = alloc_handle( current->process, event, EVENT_ALL_ACCESS, req->inherit );
release_object( event );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
else reply->handle = -1;
}
/* 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) );
size_t len = get_req_strlen();
struct open_event_reply *reply = push_reply_data( current, sizeof(*reply) );
reply->handle = open_object( get_req_data( len + 1 ), len, &event_ops,
req->access, req->inherit );
}
/* do an event operation */
......@@ -174,7 +164,6 @@ DECL_HANDLER(event_op)
reset_event( req->handle );
break;
default:
fatal_protocol_error( "event_op: invalid operation %d\n", req->op );
fatal_protocol_error( "event_op: invalid operation" );
}
send_reply( current, -1, 0 );
}
......@@ -16,6 +16,7 @@
#include "handle.h"
#include "process.h"
#include "thread.h"
#include "request.h"
struct handle_entry
{
......@@ -55,6 +56,7 @@ static void handle_table_destroy( struct object *obj );
static const struct object_ops handle_table_ops =
{
sizeof(struct handle_table),
handle_table_dump,
no_add_queue,
NULL, /* should never get called */
......@@ -104,7 +106,6 @@ static void handle_table_destroy( struct object *obj )
if (obj) release_object( obj );
}
free( table->entries );
free( table );
}
/* allocate a new handle table */
......@@ -113,7 +114,7 @@ struct object *alloc_handle_table( struct process *process, int count )
struct handle_table *table;
if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
if (!(table = alloc_object( sizeof(*table), &handle_table_ops, NULL )))
if (!(table = alloc_object( &handle_table_ops )))
return NULL;
table->process = process;
table->count = count;
......@@ -134,7 +135,7 @@ static int grow_handle_table( struct handle_table *table )
count *= 2;
if (!(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
{
SET_ERROR( ERROR_OUTOFMEMORY );
set_error( ERROR_OUTOFMEMORY );
return 0;
}
table->entries = new_entries;
......@@ -216,7 +217,7 @@ static struct handle_entry *get_handle( struct process *process, int handle )
return entry;
error:
SET_ERROR( ERROR_INVALID_HANDLE );
set_error( ERROR_INVALID_HANDLE );
return NULL;
}
......@@ -319,7 +320,7 @@ struct object *get_handle_obj( struct process *process, int handle,
if (!(entry = get_handle( process, handle ))) return NULL;
if ((entry->access & access) != access)
{
SET_ERROR( ERROR_ACCESS_DENIED );
set_error( ERROR_ACCESS_DENIED );
return NULL;
}
obj = entry->ptr;
......@@ -327,7 +328,7 @@ struct object *get_handle_obj( struct process *process, int handle,
}
if (ops && (obj->ops != ops))
{
SET_ERROR( ERROR_INVALID_HANDLE ); /* not the right type */
set_error( ERROR_INVALID_HANDLE ); /* not the right type */
return NULL;
}
return grab_object( obj );
......@@ -362,7 +363,7 @@ int duplicate_handle( struct process *src, int src_handle, struct process *dst,
else /* pseudo-handle, give it full access */
{
access = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
CLEAR_ERROR();
clear_error();
}
}
access &= ~RESERVED_ALL;
......@@ -375,19 +376,19 @@ int duplicate_handle( struct process *src, int src_handle, struct process *dst,
}
/* open a new handle to an existing object */
int open_object( const char *name, const struct object_ops *ops,
int open_object( const char *name, size_t len, const struct object_ops *ops,
unsigned int access, int inherit )
{
struct object *obj = find_object( name );
struct object *obj = find_object( name, len );
if (!obj)
{
SET_ERROR( ERROR_FILE_NOT_FOUND );
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 */
set_error( ERROR_INVALID_HANDLE ); /* FIXME: not the right type */
return -1;
}
return alloc_handle( current->process, obj, access, inherit );
......@@ -397,22 +398,19 @@ int open_object( const char *name, const struct object_ops *ops,
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) );
struct get_handle_info_reply *reply = push_reply_data( current, sizeof(*reply) );
reply->flags = set_handle_info( current->process, req->handle, 0, 0 );
}
/* 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 */
......@@ -439,5 +437,5 @@ DECL_HANDLER(dup_handle)
close_handle( src, req->src_handle );
release_object( src );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
add_reply_data( current, &reply, sizeof(reply) );
}
......@@ -11,6 +11,8 @@
#error This file can only be used in the Wine server
#endif
#include <stdlib.h>
struct process;
struct object_ops;
......@@ -25,7 +27,7 @@ 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,
extern int open_object( const char *name, size_t len, const struct object_ops *ops,
unsigned int access, int inherit );
extern struct object *alloc_handle_table( struct process *process, int count );
extern struct object *copy_handle_table( struct process *process, struct process *parent );
......
......@@ -10,7 +10,6 @@
#include <stdlib.h>
#include <unistd.h>
#include "server.h"
#include "object.h"
#include "thread.h"
......
......@@ -16,6 +16,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
struct mapping
{
......@@ -31,6 +32,7 @@ static void mapping_destroy( struct object *obj );
static const struct object_ops mapping_ops =
{
sizeof(struct mapping),
mapping_dump,
no_add_queue,
NULL, /* should never get called */
......@@ -82,17 +84,16 @@ static void init_page_size(void)
static struct object *create_mapping( int size_high, int size_low, int protect,
int handle, const char *name )
int handle, const char *name, size_t len )
{
struct mapping *mapping;
int access = 0;
if (!page_mask) init_page_size();
if (!(mapping = (struct mapping *)create_named_object( name, &mapping_ops,
sizeof(*mapping) )))
if (!(mapping = create_named_object( &mapping_ops, name, len )))
return NULL;
if (GET_ERROR() == ERROR_ALREADY_EXISTS)
if (get_error() == ERROR_ALREADY_EXISTS)
return &mapping->obj; /* Nothing else to do */
if (protect & VPROT_READ) access |= GENERIC_READ;
......@@ -115,7 +116,7 @@ static struct object *create_mapping( int size_high, int size_low, int protect,
{
if (!size_high && !size_low)
{
SET_ERROR( ERROR_INVALID_PARAMETER );
set_error( ERROR_INVALID_PARAMETER );
mapping->file = NULL;
goto error;
}
......@@ -163,45 +164,39 @@ static void mapping_destroy( struct object *obj )
struct mapping *mapping = (struct mapping *)obj;
assert( obj->ops == &mapping_ops );
if (mapping->file) release_object( mapping->file );
free( mapping );
}
/* create a file mapping */
DECL_HANDLER(create_mapping)
{
size_t len = get_req_strlen();
struct create_mapping_reply *reply = push_reply_data( current, sizeof(*reply) );
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 )))
req->protect, req->handle, get_req_data( len + 1 ), len )))
{
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 );
reply->handle = alloc_handle( current->process, obj, access, req->inherit );
release_object( obj );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
else reply->handle = -1;
}
/* 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) );
size_t len = get_req_strlen();
struct open_mapping_reply *reply = push_reply_data( current, sizeof(*reply) );
reply->handle = open_object( get_req_data( len + 1 ), len, &mapping_ops,
req->access, req->inherit );
}
/* 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) );
struct get_mapping_info_reply *reply = push_reply_data( current, sizeof(*reply) );
int map_fd = get_mapping_info( req->handle, reply );
set_reply_fd( current, map_fd );
}
......@@ -13,6 +13,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
struct mutex
{
......@@ -27,10 +28,10 @@ struct mutex
static void mutex_dump( struct object *obj, int verbose );
static int mutex_signaled( struct object *obj, struct thread *thread );
static int mutex_satisfied( struct object *obj, struct thread *thread );
static void mutex_destroy( struct object *obj );
static const struct object_ops mutex_ops =
{
sizeof(struct mutex),
mutex_dump,
add_queue,
remove_queue,
......@@ -40,26 +41,27 @@ static const struct object_ops mutex_ops =
no_write_fd,
no_flush,
no_get_file_info,
mutex_destroy
no_destroy
};
static struct object *create_mutex( const char *name, int owned )
static struct mutex *create_mutex( const char *name, size_t len, int owned )
{
struct mutex *mutex;
if (!(mutex = (struct mutex *)create_named_object( name, &mutex_ops, sizeof(*mutex) )))
return NULL;
if (GET_ERROR() != ERROR_ALREADY_EXISTS)
if ((mutex = create_named_object( &mutex_ops, name, len )))
{
/* initialize it if it didn't already exist */
mutex->count = 0;
mutex->owner = NULL;
mutex->abandoned = 0;
mutex->next = mutex->prev = NULL;
if (owned) mutex_satisfied( &mutex->obj, current );
if (get_error() != ERROR_ALREADY_EXISTS)
{
/* initialize it if it didn't already exist */
mutex->count = 0;
mutex->owner = NULL;
mutex->abandoned = 0;
mutex->next = mutex->prev = NULL;
if (owned) mutex_satisfied( &mutex->obj, current );
}
}
return &mutex->obj;
return mutex;
}
/* release a mutex once the recursion count is 0 */
......@@ -75,23 +77,6 @@ static void do_release( struct mutex *mutex, struct thread *thread )
wake_up( &mutex->obj, 0 );
}
static int release_mutex( int handle )
{
struct mutex *mutex;
if (!(mutex = (struct mutex *)get_handle_obj( current->process, handle,
MUTEX_MODIFY_STATE, &mutex_ops )))
return 0;
if (!mutex->count || (mutex->owner != current))
{
SET_ERROR( ERROR_NOT_OWNER );
return 0;
}
if (!--mutex->count) do_release( mutex, current );
release_object( mutex );
return 1;
}
void abandon_mutexes( struct thread *thread )
{
while (thread->mutex)
......@@ -138,46 +123,40 @@ static int mutex_satisfied( struct object *obj, struct thread *thread )
return 1;
}
static void mutex_destroy( struct object *obj )
{
struct mutex *mutex = (struct mutex *)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)
size_t len = get_req_strlen();
struct create_mutex_reply *reply = push_reply_data( current, sizeof(*reply) );
struct mutex *mutex;
if ((mutex = create_mutex( get_req_data( len + 1 ), len, req->owned )))
{
reply.handle = alloc_handle( current->process, obj, MUTEX_ALL_ACCESS, req->inherit );
release_object( obj );
reply->handle = alloc_handle( current->process, mutex, MUTEX_ALL_ACCESS, req->inherit );
release_object( mutex );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
else reply->handle = -1;
}
/* 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) );
size_t len = get_req_strlen();
struct open_mutex_reply *reply = push_reply_data( current, sizeof(*reply) );
reply->handle = open_object( get_req_data( len + 1 ), len, &mutex_ops,
req->access, req->inherit );
}
/* release a mutex */
DECL_HANDLER(release_mutex)
{
if (release_mutex( req->handle )) CLEAR_ERROR();
send_reply( current, -1, 0 );
struct mutex *mutex;
if ((mutex = (struct mutex *)get_handle_obj( current->process, req->handle,
MUTEX_MODIFY_STATE, &mutex_ops )))
{
if (!mutex->count || (mutex->owner != current)) set_error( ERROR_NOT_OWNER );
else if (!--mutex->count) do_release( mutex, current );
release_object( mutex );
}
}
......@@ -19,8 +19,9 @@ int debug_level = 0;
struct object_name
{
struct object_name *next;
struct object_name *prev;
struct object *obj;
int len;
size_t len;
char name[1];
};
......@@ -45,96 +46,115 @@ void dump_objects(void)
/*****************************************************************/
/* malloc replacement */
void *mem_alloc( size_t size )
{
void *ptr = malloc( size );
if (ptr) memset( ptr, 0x55, size );
else if (current) SET_ERROR( ERROR_OUTOFMEMORY );
else if (current) set_error( ERROR_OUTOFMEMORY );
return ptr;
}
/*****************************************************************/
static int get_name_hash( const char *name )
static int get_name_hash( const char *name, size_t len )
{
int hash = 0;
while (*name) hash ^= *name++;
char hash = 0;
while (len--) hash ^= *name++;
return hash % NAME_HASH_SIZE;
}
static struct object_name *add_name( struct object *obj, const char *name )
/* allocate a name for an object */
static struct object_name *alloc_name( const char *name, size_t len )
{
struct object_name *ptr;
int hash = get_name_hash( name );
int len = strlen( name );
if (!(ptr = (struct object_name *)mem_alloc( sizeof(*ptr) + len )))
return NULL;
ptr->next = names[hash];
ptr->obj = obj;
ptr->len = len;
strcpy( ptr->name, name );
names[hash] = ptr;
if ((ptr = mem_alloc( sizeof(*ptr) + len )))
{
ptr->len = len;
memcpy( ptr->name, name, len );
ptr->name[len] = 0;
}
return ptr;
}
/* free the name of an object */
static void free_name( struct object *obj )
{
int hash = get_name_hash( obj->name->name );
struct object_name **pptr = &names[hash];
while (*pptr && *pptr != obj->name) pptr = &(*pptr)->next;
assert( *pptr );
*pptr = (*pptr)->next;
free( obj->name );
}
/* initialize an already allocated object */
/* return 1 if OK, 0 on error */
int init_object( struct object *obj, const struct object_ops *ops,
const char *name )
{
obj->refcount = 1;
obj->ops = ops;
obj->head = NULL;
obj->tail = NULL;
if (!name) obj->name = NULL;
else if (!(obj->name = add_name( obj, name ))) return 0;
#ifdef DEBUG_OBJECTS
obj->prev = NULL;
if ((obj->next = first) != NULL) obj->next->prev = obj;
first = obj;
#endif
return 1;
struct object_name *ptr = obj->name;
if (ptr->next) ptr->next->prev = ptr->prev;
if (ptr->prev) ptr->prev->next = ptr->next;
else
{
int hash;
for (hash = 0; hash < NAME_HASH_SIZE; hash++)
if (names[hash] == ptr)
{
names[hash] = ptr->next;
break;
}
}
free( ptr );
}
/* set the name of an existing object */
static void set_object_name( struct object *obj, struct object_name *ptr )
{
int hash = get_name_hash( ptr->name, ptr->len );
if ((ptr->next = names[hash]) != NULL) ptr->next->prev = ptr;
ptr->obj = obj;
ptr->prev = NULL;
names[hash] = ptr;
assert( !obj->name );
obj->name = ptr;
}
/* allocate and initialize an object */
void *alloc_object( size_t size, const struct object_ops *ops, const char *name )
void *alloc_object( const struct object_ops *ops )
{
struct object *obj = mem_alloc( size );
if (obj) init_object( obj, ops, name );
struct object *obj = mem_alloc( ops->size );
if (obj)
{
obj->refcount = 1;
obj->ops = ops;
obj->head = NULL;
obj->tail = NULL;
obj->name = NULL;
#ifdef DEBUG_OBJECTS
obj->prev = NULL;
if ((obj->next = first) != NULL) obj->next->prev = obj;
first = obj;
#endif
}
return obj;
}
struct object *create_named_object( const char *name, const struct object_ops *ops, size_t size )
void *create_named_object( const struct object_ops *ops, const char *name, size_t len )
{
struct object *obj;
if ((obj = find_object( name )))
struct object_name *name_ptr;
if (!name || !len) return alloc_object( ops );
if (!(name_ptr = alloc_name( name, len ))) return NULL;
if ((obj = find_object( name_ptr->name, name_ptr->len )))
{
free( name_ptr ); /* we no longer need it */
if (obj->ops == ops)
{
SET_ERROR( ERROR_ALREADY_EXISTS );
set_error( ERROR_ALREADY_EXISTS );
return obj;
}
SET_ERROR( ERROR_INVALID_HANDLE );
set_error( ERROR_INVALID_HANDLE );
return NULL;
}
if (!(obj = mem_alloc( size ))) return NULL;
if (!init_object( obj, ops, name ))
if ((obj = alloc_object( ops )))
{
free( obj );
return NULL;
set_object_name( obj, name_ptr );
clear_error();
}
CLEAR_ERROR();
else free( name_ptr );
return obj;
}
......@@ -171,25 +191,29 @@ void release_object( void *ptr )
else first = obj->next;
#endif
obj->ops->destroy( obj );
memset( obj, 0xaa, obj->ops->size );
free( obj );
}
}
/* find an object by its name; the refcount is incremented */
struct object *find_object( const char *name )
struct object *find_object( const char *name, size_t len )
{
struct object_name *ptr;
if (!name) return NULL;
ptr = names[ get_name_hash( name ) ];
while (ptr && strcmp( ptr->name, name )) ptr = ptr->next;
if (!ptr) return NULL;
return grab_object( ptr->obj );
if (!name || !len) return NULL;
for (ptr = names[ get_name_hash( name, len ) ]; ptr; ptr = ptr->next)
{
if (ptr->len != len) continue;
if (!memcmp( ptr->name, name, len )) return grab_object( ptr->obj );
}
return NULL;
}
/* functions for unimplemented object operations */
int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
{
SET_ERROR( ERROR_INVALID_HANDLE );
set_error( ERROR_INVALID_HANDLE );
return 0;
}
......@@ -200,28 +224,32 @@ int no_satisfied( struct object *obj, struct thread *thread )
int no_read_fd( struct object *obj )
{
SET_ERROR( ERROR_INVALID_HANDLE );
set_error( ERROR_INVALID_HANDLE );
return -1;
}
int no_write_fd( struct object *obj )
{
SET_ERROR( ERROR_INVALID_HANDLE );
set_error( ERROR_INVALID_HANDLE );
return -1;
}
int no_flush( struct object *obj )
{
SET_ERROR( ERROR_INVALID_HANDLE );
set_error( ERROR_INVALID_HANDLE );
return 0;
}
int no_get_file_info( struct object *obj, struct get_file_info_reply *info )
{
SET_ERROR( ERROR_INVALID_HANDLE );
set_error( ERROR_INVALID_HANDLE );
return 0;
}
void no_destroy( struct object *obj )
{
}
void default_select_event( int event, void *private )
{
struct object *obj = (struct object *)private;
......
......@@ -13,7 +13,6 @@
#include <sys/time.h>
#include "server.h"
#include "server/request.h"
#define DEBUG_OBJECTS
......@@ -29,6 +28,8 @@ struct wait_queue_entry;
/* operations valid on all objects */
struct object_ops
{
/* size of this object type */
size_t size;
/* dump the object (for debugging) */
void (*dump)(struct object *,int);
/* add a thread to the object wait queue */
......@@ -65,49 +66,27 @@ struct object
};
extern void *mem_alloc( size_t size ); /* malloc wrapper */
extern void *alloc_object( size_t size, const struct object_ops *ops, const char *name );
extern struct object *create_named_object( const char *name, const struct object_ops *ops,
size_t size );
extern int init_object( struct object *obj, const struct object_ops *ops, const char *name );
extern char *mem_strdup( const char *str );
extern void *alloc_object( const struct object_ops *ops );
extern const char *get_object_name( struct object *obj );
extern void *create_named_object( const struct object_ops *ops, const char *name, size_t len );
/* grab/release_object can take any pointer, but you better make sure */
/* that the thing pointed to starts with a struct object... */
extern struct object *grab_object( void *obj );
extern void release_object( void *obj );
extern struct object *find_object( const char *name );
extern struct object *find_object( const char *name, size_t len );
extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
extern int no_satisfied( struct object *obj, struct thread *thread );
extern int no_read_fd( struct object *obj );
extern int no_write_fd( struct object *obj );
extern int no_flush( struct object *obj );
extern int no_get_file_info( struct object *obj, struct get_file_info_reply *info );
extern void no_destroy( struct object *obj );
extern void default_select_event( int event, void *private );
#ifdef DEBUG_OBJECTS
extern void dump_objects(void);
#endif
/* request handlers */
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( void *thread );
extern void call_kill_handler( struct thread *thread, int exit_code );
extern void trace_request( enum request req, void *data, int len, int fd );
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 */
#define READ_EVENT 1
......@@ -143,8 +122,8 @@ struct client;
extern struct client *add_client( int client_fd, struct thread *self );
extern void remove_client( struct client *client, int exit_code );
extern int send_reply_v( struct client *client, int type, int pass_fd,
struct iovec *vec, int veclen );
extern void client_pass_fd( struct client *client, int pass_fd );
extern void client_reply( struct client *client );
/* mutex functions */
......@@ -156,6 +135,7 @@ 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 grow_file( struct file *file, int size_high, int size_low );
extern int create_anonymous_file(void);
extern struct file *create_temp_file( int access );
extern void file_set_error(void);
......
......@@ -21,6 +21,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
enum side { READ_SIDE, WRITE_SIDE };
......@@ -43,6 +44,7 @@ static void pipe_destroy( struct object *obj );
static const struct object_ops pipe_ops =
{
sizeof(struct pipe),
pipe_dump,
pipe_add_queue,
pipe_remove_queue,
......@@ -56,9 +58,26 @@ static const struct object_ops pipe_ops =
};
static struct pipe *create_pipe_side( int fd, int side )
{
struct pipe *pipe;
if ((pipe = alloc_object( &pipe_ops )))
{
pipe->select.fd = fd;
pipe->select.func = default_select_event;
pipe->select.private = pipe;
pipe->other = NULL;
pipe->side = side;
register_select_user( &pipe->select );
}
return pipe;
}
static int create_pipe( struct object *obj[2] )
{
struct pipe *newpipe[2];
struct pipe *read_pipe;
struct pipe *write_pipe;
int fd[2];
if (pipe( fd ) == -1)
......@@ -66,37 +85,21 @@ static int create_pipe( struct object *obj[2] )
file_set_error();
return 0;
}
if (!(newpipe[0] = mem_alloc( sizeof(struct pipe) )))
if ((read_pipe = create_pipe_side( fd[0], READ_SIDE )))
{
close( fd[0] );
close( fd[1] );
return 0;
}
if (!(newpipe[1] = mem_alloc( sizeof(struct pipe) )))
{
close( fd[0] );
close( fd[1] );
free( newpipe[0] );
return 0;
if ((write_pipe = create_pipe_side( fd[1], WRITE_SIDE )))
{
write_pipe->other = read_pipe;
read_pipe->other = write_pipe;
obj[0] = &read_pipe->obj;
obj[1] = &write_pipe->obj;
return 1;
}
release_object( read_pipe );
}
init_object( &newpipe[0]->obj, &pipe_ops, NULL );
init_object( &newpipe[1]->obj, &pipe_ops, NULL );
newpipe[0]->select.fd = fd[0];
newpipe[0]->select.func = default_select_event;
newpipe[0]->select.private = newpipe[0];
newpipe[0]->other = newpipe[1];
newpipe[0]->side = READ_SIDE;
newpipe[1]->select.fd = fd[1];
newpipe[1]->select.func = default_select_event;
newpipe[1]->select.private = newpipe[1];
newpipe[1]->other = newpipe[0];
newpipe[1]->side = WRITE_SIDE;
obj[0] = &newpipe[0]->obj;
obj[1] = &newpipe[1]->obj;
register_select_user( &newpipe[0]->select );
register_select_user( &newpipe[1]->select );
CLEAR_ERROR();
return 1;
close( fd[0] );
close( fd[1] );
return 0;
}
static void pipe_dump( struct object *obj, int verbose )
......@@ -157,12 +160,12 @@ static int pipe_get_read_fd( struct object *obj )
if (!pipe->other)
{
SET_ERROR( ERROR_BROKEN_PIPE );
set_error( ERROR_BROKEN_PIPE );
return -1;
}
if (pipe->side != READ_SIDE) /* FIXME: should not be necessary */
{
SET_ERROR( ERROR_ACCESS_DENIED );
set_error( ERROR_ACCESS_DENIED );
return -1;
}
return dup( pipe->select.fd );
......@@ -175,12 +178,12 @@ static int pipe_get_write_fd( struct object *obj )
if (!pipe->other)
{
SET_ERROR( ERROR_BROKEN_PIPE );
set_error( ERROR_BROKEN_PIPE );
return -1;
}
if (pipe->side != WRITE_SIDE) /* FIXME: should not be necessary */
{
SET_ERROR( ERROR_ACCESS_DENIED );
set_error( ERROR_ACCESS_DENIED );
return -1;
}
return dup( pipe->select.fd );
......@@ -201,7 +204,6 @@ static void pipe_destroy( struct object *obj )
if (pipe->other) pipe->other->other = NULL;
unregister_select_user( &pipe->select );
close( pipe->select.fd );
free( pipe );
}
/* create an anonymous pipe */
......@@ -225,5 +227,5 @@ DECL_HANDLER(create_pipe)
release_object( obj[0] );
release_object( obj[1] );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
add_reply_data( current, &reply, sizeof(reply) );
}
......@@ -17,10 +17,10 @@
#include "winbase.h"
#include "winnt.h"
#include "server.h"
#include "handle.h"
#include "process.h"
#include "thread.h"
#include "request.h"
/* process structure */
......@@ -35,6 +35,7 @@ static void process_destroy( struct object *obj );
static const struct object_ops process_ops =
{
sizeof(struct process),
process_dump,
add_queue,
remove_queue,
......@@ -49,12 +50,12 @@ static const struct object_ops process_ops =
/* create a new process */
static struct process *create_process( struct process *parent,
struct new_process_request *req, const char *cmd_line )
static struct process *create_process( struct process *parent, struct new_process_request *req,
const char *cmd_line, size_t len )
{
struct process *process;
if (!(process = alloc_object( sizeof(*process), &process_ops, NULL ))) return NULL;
if (!(process = alloc_object( &process_ops ))) return NULL;
process->next = NULL;
process->prev = NULL;
process->thread_list = NULL;
......@@ -81,9 +82,10 @@ static struct process *create_process( struct process *parent,
/* alloc a handle for the process itself */
alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
if (!(process->info = mem_alloc( sizeof(*process->info) + strlen(cmd_line) + 1 ))) goto error;
if (!(process->info = mem_alloc( sizeof(*process->info) + len + 1 ))) goto error;
memcpy( process->info, req, sizeof(*req) );
strcpy( process->info->cmd_line, cmd_line );
memcpy( process->info->cmd_line, cmd_line, len );
process->info->cmd_line[len] = 0;
/* set the process console */
if (req->create_flags & CREATE_NEW_CONSOLE)
......@@ -139,7 +141,7 @@ struct process *create_initial_process(void)
req.hstderr = -1;
req.cmd_show = 0;
req.env_ptr = NULL;
if ((process = create_process( NULL, &req, "" )))
if ((process = create_process( NULL, &req, "", 1 )))
{
process->info->hstdin = alloc_handle( process, process->console_in,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
......@@ -163,8 +165,6 @@ static void process_destroy( struct object *obj )
if (process->prev) process->prev->next = process->next;
else first_process = process->next;
if (process->info) free( process->info );
if (debug_level) memset( process, 0xbb, sizeof(process) ); /* catch errors */
free( process );
}
/* dump a process on stdout for debugging purposes */
......@@ -191,7 +191,7 @@ struct process *get_process_from_id( void *id )
struct process *p = first_process;
while (p && (p != id)) p = p->next;
if (p) grab_object( p );
else SET_ERROR( ERROR_INVALID_PARAMETER );
else set_error( ERROR_INVALID_PARAMETER );
return p;
}
......@@ -303,7 +303,7 @@ static void set_process_info( struct process *process,
process->priority = req->priority;
if (req->mask & SET_PROCESS_INFO_AFFINITY)
{
if (req->affinity != 1) SET_ERROR( ERROR_INVALID_PARAMETER );
if (req->affinity != 1) set_error( ERROR_INVALID_PARAMETER );
else process->affinity = req->affinity;
}
}
......@@ -333,33 +333,31 @@ struct process_snapshot *process_snap( int *count )
/* create a new process */
DECL_HANDLER(new_process)
{
struct new_process_reply reply;
struct new_process_reply *reply = push_reply_data( current, sizeof(*reply) );
size_t len = get_req_strlen();
struct process *process;
char *cmd_line = (char *)data;
CHECK_STRING( "new_process", cmd_line, len );
if ((process = create_process( current->process, req, cmd_line )))
if ((process = create_process( current->process, req, get_req_data( len + 1 ), len )))
{
reply.pid = process;
reply.handle = alloc_handle( current->process, process,
PROCESS_ALL_ACCESS, req->inherit );
reply->handle = alloc_handle( current->process, process,
PROCESS_ALL_ACCESS, req->inherit );
reply->pid = process;
release_object( process );
}
else
{
reply.handle = -1;
reply.pid = NULL;
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;
struct init_process_reply *reply = push_reply_data( current, sizeof(*reply) );
struct new_process_request *info;
if (current->state != RUNNING)
if (current->state == STARTING)
{
fatal_protocol_error( "init_process: init_thread not called yet\n" );
return;
......@@ -370,29 +368,27 @@ DECL_HANDLER(init_process)
return;
}
current->process->info = NULL;
reply.start_flags = info->start_flags;
reply.hstdin = info->hstdin;
reply.hstdout = info->hstdout;
reply.hstderr = info->hstderr;
reply.cmd_show = info->cmd_show;
reply.env_ptr = info->env_ptr;
send_reply( current, -1, 2, &reply, sizeof(reply),
info->cmd_line, strlen(info->cmd_line) + 1 );
reply->start_flags = info->start_flags;
reply->hstdin = info->hstdin;
reply->hstdout = info->hstdout;
reply->hstderr = info->hstderr;
reply->cmd_show = info->cmd_show;
reply->env_ptr = info->env_ptr;
add_reply_data( current, info->cmd_line, strlen(info->cmd_line) + 1 );
free( info );
}
/* open a handle to a process */
DECL_HANDLER(open_process)
{
struct open_process_reply reply = { -1 };
struct open_process_reply *reply = push_reply_data( current, sizeof(*reply) );
struct process *process = get_process_from_id( req->pid );
if (process)
{
reply.handle = alloc_handle( current->process, process,
req->access, req->inherit );
reply->handle = alloc_handle( current->process, process, req->access, req->inherit );
release_object( process );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
else reply->handle = -1;
}
/* terminate a process */
......@@ -405,21 +401,19 @@ DECL_HANDLER(terminate_process)
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 };
struct get_process_info_reply *reply = push_reply_data( current, sizeof(*reply) );
if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
{
get_process_info( process, &reply );
get_process_info( process, reply );
release_object( process );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
}
/* set information about a process */
......@@ -432,5 +426,4 @@ DECL_HANDLER(set_process_info)
set_process_info( process, req );
release_object( process );
}
send_reply( current, -1, 0 );
}
......@@ -18,54 +18,63 @@
#include "winnt.h"
#include "winbase.h"
#include "wincon.h"
#define WANT_REQUEST_HANDLERS
#include "server.h"
#include "thread.h"
#include "server.h"
#define WANT_REQUEST_HANDLERS
#include "request.h"
struct thread *current = NULL; /* thread handling the current request */
/* complain about a protocol error and terminate the client connection */
void fatal_protocol_error( const char *err, ... )
void fatal_protocol_error( const char *err )
{
va_list args;
unsigned char *p;
va_start( args, err );
fprintf( stderr, "Protocol error:%p: ", current );
vfprintf( stderr, err, args );
va_end( args );
fprintf( stderr, "Protocol error:%p: %s\n request:", current, err );
for (p = (unsigned char *)current->buffer; p < (unsigned char *)current->req_end; p++)
fprintf( stderr, " %02x", *p );
fprintf( stderr, "\n" );
remove_client( current->client, -2 );
}
/* call a request handler */
void call_req_handler( struct thread *thread, enum request req,
void *data, int len, int fd )
void call_req_handler( struct thread *thread, int fd )
{
const struct handler *handler = &req_handlers[req];
char *ptr;
const struct handler *handler;
struct header *head;
unsigned int req, len;
current = thread;
if ((req < 0) || (req >= REQ_NB_REQUESTS))
{
fatal_protocol_error( "unknown request %d\n", req );
return;
}
assert (current);
if (len < handler->min_size)
{
fatal_protocol_error( "req %d bad length %d < %d\n", req, len, handler->min_size );
return;
}
head = (struct header *)current->buffer;
req = head->type;
len = head->len;
/* set the buffer pointers */
current->req_pos = current->reply_pos = (char *)current->buffer + sizeof(struct header);
current->req_end = (char *)current->buffer + len;
clear_error();
if ((len < sizeof(struct header)) || (len > MAX_MSG_LENGTH)) goto bad_header;
if (req >= REQ_NB_REQUESTS) goto bad_header;
if (debug_level) trace_request( req, fd );
/* now call the handler */
if (current)
{
CLEAR_ERROR();
if (debug_level) trace_request( req, data, len, fd );
}
len -= handler->min_size;
ptr = (char *)data + handler->min_size;
handler->handler( data, ptr, len, fd );
handler = &req_handlers[req];
if (!check_req_data( handler->min_size )) goto bad_request;
handler->handler( get_req_data( handler->min_size ), fd );
if (current && current->state != SLEEPING) send_reply( current );
current = NULL;
return;
bad_header:
/* dump only the header */
current->req_end = (char *)current->buffer + sizeof(struct header);
bad_request:
fatal_protocol_error( "bad request" );
}
/* handle a client timeout */
......@@ -73,7 +82,7 @@ void call_timeout_handler( void *thread )
{
current = (struct thread *)thread;
if (debug_level) trace_timeout();
CLEAR_ERROR();
clear_error();
thread_timeout();
current = NULL;
}
......@@ -92,14 +101,32 @@ void call_kill_handler( struct thread *thread, int exit_code )
current = (old_current != thread) ? old_current : NULL;
}
/* set the fd to pass to the thread */
void set_reply_fd( struct thread *thread, int pass_fd )
{
client_pass_fd( thread->client, pass_fd );
}
/* send a reply to a thread */
void send_reply( struct thread *thread )
{
struct header *head = thread->buffer;
int len = (char *)thread->reply_pos - (char *)thread->buffer;
assert( len < MAX_MSG_LENGTH );
head->len = len;
head->type = thread->error;
if (thread->state == SLEEPING) thread->state = RUNNING;
client_reply( thread->client );
}
/* set the debug level */
DECL_HANDLER(set_debug)
{
debug_level = req->level;
/* Make sure last_req is initialized */
current->last_req = REQ_SET_DEBUG;
CLEAR_ERROR();
send_reply( current, -1, 0 );
}
/* debugger support operations */
......@@ -115,6 +142,4 @@ DECL_HANDLER(debugger)
resume_all_threads();
break;
}
send_reply( current, -1, 0 );
}
/* File generated automatically by tools/make_requests; DO NOT EDIT!! */
/*
* Wine server requests
*
* Copyright (C) 1999 Alexandre Julliard
*/
#ifndef __WINE_SERVER_REQUEST_H
#define __WINE_SERVER_REQUEST_H
enum request
#ifndef __WINE_SERVER__
#error This file can only be used in the Wine server
#endif
#include "thread.h"
/* request handler definition */
#define DECL_HANDLER(name) void req_##name( struct name##_request *req, int fd )
/* request functions */
extern void fatal_protocol_error( const char *err );
extern void call_req_handler( struct thread *thread, int fd );
extern void call_timeout_handler( void *thread );
extern void call_kill_handler( struct thread *thread, int exit_code );
extern void set_reply_fd( struct thread *thread, int pass_fd );
extern void send_reply( struct thread *thread );
extern void trace_request( enum request req, int fd );
extern void trace_timeout(void);
extern void trace_kill( int exit_code );
extern void trace_reply( struct thread *thread, int pass_fd );
/* Warning: the buffer is shared between request and reply,
* so make sure you are finished using the request before starting
* to add data for the reply.
*/
/* remove some data from the current request */
static inline void *get_req_data( size_t len )
{
REQ_NEW_PROCESS,
REQ_NEW_THREAD,
REQ_SET_DEBUG,
REQ_INIT_PROCESS,
REQ_INIT_THREAD,
REQ_TERMINATE_PROCESS,
REQ_TERMINATE_THREAD,
REQ_GET_PROCESS_INFO,
REQ_SET_PROCESS_INFO,
REQ_GET_THREAD_INFO,
REQ_SET_THREAD_INFO,
REQ_SUSPEND_THREAD,
REQ_RESUME_THREAD,
REQ_DEBUGGER,
REQ_QUEUE_APC,
REQ_CLOSE_HANDLE,
REQ_GET_HANDLE_INFO,
REQ_SET_HANDLE_INFO,
REQ_DUP_HANDLE,
REQ_OPEN_PROCESS,
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_SEMAPHORE,
REQ_CREATE_FILE,
REQ_GET_READ_FD,
REQ_GET_WRITE_FD,
REQ_SET_FILE_POINTER,
REQ_TRUNCATE_FILE,
REQ_SET_FILE_TIME,
REQ_FLUSH_FILE,
REQ_GET_FILE_INFO,
REQ_LOCK_FILE,
REQ_UNLOCK_FILE,
REQ_CREATE_PIPE,
REQ_ALLOC_CONSOLE,
REQ_FREE_CONSOLE,
REQ_OPEN_CONSOLE,
REQ_SET_CONSOLE_FD,
REQ_GET_CONSOLE_MODE,
REQ_SET_CONSOLE_MODE,
REQ_SET_CONSOLE_INFO,
REQ_GET_CONSOLE_INFO,
REQ_WRITE_CONSOLE_INPUT,
REQ_READ_CONSOLE_INPUT,
REQ_CREATE_CHANGE_NOTIFICATION,
REQ_CREATE_MAPPING,
REQ_OPEN_MAPPING,
REQ_GET_MAPPING_INFO,
REQ_CREATE_DEVICE,
REQ_CREATE_SNAPSHOT,
REQ_NEXT_PROCESS,
REQ_WAIT_DEBUG_EVENT,
REQ_SEND_DEBUG_EVENT,
REQ_CONTINUE_DEBUG_EVENT,
REQ_DEBUG_PROCESS,
REQ_NB_REQUESTS
};
void *old = current->req_pos;
current->req_pos = (char *)old + len;
return old;
}
#ifdef WANT_REQUEST_HANDLERS
/* check that there is enough data available in the current request */
static inline int check_req_data( size_t len )
{
return (char *)current->req_pos + len <= (char *)current->req_end;
}
/* get the length of a request string, without going past the end of the request */
static inline size_t get_req_strlen(void)
{
char *p = current->req_pos;
while (*p && (p < (char *)current->req_end - 1)) p++;
return p - (char *)current->req_pos;
}
/* make space for some data in the current reply */
static inline void *push_reply_data( struct thread *thread, size_t len )
{
void *old = thread->reply_pos;
thread->reply_pos = (char *)old + len;
return old;
}
/* add some data to the current reply */
static inline void add_reply_data( struct thread *thread, const void *data, size_t len )
{
memcpy( push_reply_data( thread, len ), data, len );
}
/* Everything below this line is generated automatically by tools/make_requests */
/* ### make_requests begin ### */
DECL_HANDLER(new_process);
DECL_HANDLER(new_thread);
......@@ -135,8 +139,10 @@ DECL_HANDLER(send_debug_event);
DECL_HANDLER(continue_debug_event);
DECL_HANDLER(debug_process);
#ifdef WANT_REQUEST_HANDLERS
static const struct handler {
void (*handler)();
void (*handler)( void *req, int fd );
unsigned int min_size;
} req_handlers[REQ_NB_REQUESTS] = {
{ (void(*)())req_new_process, sizeof(struct new_process_request) },
......@@ -204,4 +210,7 @@ static const struct handler {
};
#endif /* WANT_REQUEST_HANDLERS */
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
#endif /* __WINE_SERVER_REQUEST_H */
......@@ -13,6 +13,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
struct semaphore
{
......@@ -24,10 +25,10 @@ struct semaphore
static void semaphore_dump( struct object *obj, int verbose );
static int semaphore_signaled( struct object *obj, struct thread *thread );
static int semaphore_satisfied( struct object *obj, struct thread *thread );
static void semaphore_destroy( struct object *obj );
static const struct object_ops semaphore_ops =
{
sizeof(struct semaphore),
semaphore_dump,
add_queue,
remove_queue,
......@@ -37,45 +38,46 @@ static const struct object_ops semaphore_ops =
no_write_fd,
no_flush,
no_get_file_info,
semaphore_destroy
no_destroy
};
static struct object *create_semaphore( const char *name, unsigned int initial, unsigned int max )
static struct semaphore *create_semaphore( const char *name, size_t len,
unsigned int initial, unsigned int max )
{
struct semaphore *sem;
if (!max || (initial > max))
{
SET_ERROR( ERROR_INVALID_PARAMETER );
set_error( ERROR_INVALID_PARAMETER );
return NULL;
}
if (!(sem = (struct semaphore *)create_named_object( name, &semaphore_ops, sizeof(*sem) )))
return NULL;
if (GET_ERROR() != ERROR_ALREADY_EXISTS)
if ((sem = create_named_object( &semaphore_ops, name, len )))
{
/* initialize it if it didn't already exist */
sem->count = initial;
sem->max = max;
if (get_error() != ERROR_ALREADY_EXISTS)
{
/* initialize it if it didn't already exist */
sem->count = initial;
sem->max = max;
}
}
return &sem->obj;
return sem;
}
static int release_semaphore( int handle, unsigned int count, unsigned int *prev_count )
static void release_semaphore( int handle, unsigned int count, unsigned int *prev_count )
{
struct semaphore *sem;
if (!(sem = (struct semaphore *)get_handle_obj( current->process, handle,
SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
return 0;
return;
*prev_count = sem->count;
if (sem->count + count < sem->count || sem->count + count > sem->max)
{
SET_ERROR( ERROR_TOO_MANY_POSTS );
return 0;
set_error( ERROR_TOO_MANY_POSTS );
}
if (sem->count)
else if (sem->count)
{
/* there cannot be any thread waiting if the count is != 0 */
assert( !sem->obj.head );
......@@ -87,7 +89,6 @@ static int release_semaphore( int handle, unsigned int count, unsigned int *prev
wake_up( &sem->obj, count );
}
release_object( sem );
return 1;
}
static void semaphore_dump( struct object *obj, int verbose )
......@@ -114,47 +115,33 @@ static int semaphore_satisfied( struct object *obj, struct thread *thread )
return 0; /* not abandoned */
}
static void semaphore_destroy( struct object *obj )
{
struct semaphore *sem = (struct semaphore *)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)
size_t len = get_req_strlen();
struct create_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
struct semaphore *sem;
if ((sem = create_semaphore( get_req_data( len + 1 ), len, req->initial, req->max )))
{
reply.handle = alloc_handle( current->process, obj, SEMAPHORE_ALL_ACCESS, req->inherit );
release_object( obj );
reply->handle = alloc_handle( current->process, sem, SEMAPHORE_ALL_ACCESS, req->inherit );
release_object( sem );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
else reply->handle = -1;
}
/* 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) );
size_t len = get_req_strlen();
struct open_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
reply->handle = open_object( get_req_data( len + 1 ), len, &semaphore_ops,
req->access, req->inherit );
}
/* 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) );
struct release_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
release_semaphore( req->handle, req->count, &reply->prev_count );
}
......@@ -17,6 +17,7 @@
#include "handle.h"
#include "process.h"
#include "thread.h"
#include "request.h"
struct snapshot
......@@ -32,6 +33,7 @@ static void snapshot_destroy( struct object *obj );
static const struct object_ops snapshot_ops =
{
sizeof(struct snapshot),
snapshot_dump,
no_add_queue,
NULL, /* should never get called */
......@@ -46,18 +48,19 @@ static const struct object_ops snapshot_ops =
/* create a new snapshot */
static struct object *create_snapshot( int flags )
static struct snapshot *create_snapshot( int flags )
{
struct snapshot *snapshot;
if (!(snapshot = mem_alloc( sizeof(*snapshot) ))) return NULL;
init_object( &snapshot->obj, &snapshot_ops, NULL );
if (flags & TH32CS_SNAPPROCESS)
snapshot->process = process_snap( &snapshot->process_count );
else
snapshot->process_count = 0;
snapshot->process_pos = 0;
return &snapshot->obj;
if ((snapshot = alloc_object( &snapshot_ops )))
{
if (flags & TH32CS_SNAPPROCESS)
snapshot->process = process_snap( &snapshot->process_count );
else
snapshot->process_count = 0;
snapshot->process_pos = 0;
}
return snapshot;
}
/* get the next process in the snapshot */
......@@ -70,14 +73,14 @@ static int snapshot_next_process( int handle, int reset, struct next_process_rep
return 0;
if (!snapshot->process_count)
{
SET_ERROR( ERROR_INVALID_PARAMETER ); /* FIXME */
set_error( ERROR_INVALID_PARAMETER ); /* FIXME */
release_object( snapshot );
return 0;
}
if (reset) snapshot->process_pos = 0;
else if (snapshot->process_pos >= snapshot->process_count)
{
SET_ERROR( ERROR_NO_MORE_FILES );
set_error( ERROR_NO_MORE_FILES );
release_object( snapshot );
return 0;
}
......@@ -108,27 +111,25 @@ static void snapshot_destroy( struct object *obj )
release_object( snapshot->process[i].process );
free( snapshot->process );
}
free( snapshot );
}
/* create a snapshot */
DECL_HANDLER(create_snapshot)
{
struct object *obj;
struct create_snapshot_reply reply = { -1 };
struct snapshot *snapshot;
struct create_snapshot_reply *reply = push_reply_data( current, sizeof(*reply) );
if ((obj = create_snapshot( req->flags )))
if ((snapshot = create_snapshot( req->flags )))
{
reply.handle = alloc_handle( current->process, obj, 0, req->inherit );
release_object( obj );
reply->handle = alloc_handle( current->process, snapshot, 0, req->inherit );
release_object( snapshot );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
else reply->handle = -1;
}
/* 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) );
struct next_process_reply *reply = push_reply_data( current, sizeof(*reply) );
snapshot_next_process( req->handle, req->reset, reply );
}
......@@ -22,7 +22,7 @@ struct mutex;
struct debug_ctx;
struct debug_event;
enum run_state { STARTING, RUNNING, TERMINATED };
enum run_state { STARTING, RUNNING, SLEEPING, TERMINATED };
struct thread
{
......@@ -48,6 +48,10 @@ struct thread
int priority; /* priority level */
int affinity; /* affinity mask */
int suspend; /* suspend count */
void *buffer; /* buffer for communication with the client */
void *req_pos; /* current request position in buffer */
void *req_end; /* ptr to end of current request */
void *reply_pos; /* current reply position in buffer */
enum request last_req; /* last request received (for debugging) */
};
......@@ -60,8 +64,6 @@ extern struct thread *get_thread_from_id( void *id );
extern struct thread *get_thread_from_handle( int handle, unsigned int access );
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 void kill_thread( struct thread *thread, int exit_code );
......@@ -69,8 +71,8 @@ extern void thread_killed( struct thread *thread, int exit_code );
extern void thread_timeout(void);
extern void wake_up( struct object *obj, int max );
#define GET_ERROR() (current->error)
#define SET_ERROR(err) (current->error = (err))
#define CLEAR_ERROR() (current->error = 0)
static inline int get_error(void) { return current->error; }
static inline void set_error( int err ) { current->error = err; }
static inline void clear_error(void) { set_error(0); }
#endif /* __WINE_SERVER_THREAD_H */
/* File generated automatically by tools/make_requests; DO NOT EDIT!! */
/*
* Server request tracing
*
* Copyright (C) 1999 Alexandre Julliard
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include "server.h"
#include "thread.h"
#include "request.h"
static int dump_chars( void *ptr, int len )
{
......@@ -40,6 +43,11 @@ static int dump_ptrs( void *ptr, int len )
return len * sizeof(void*);
}
typedef int (*dump_func)( const void *req, int len );
/* Everything below this line is generated automatically by tools/make_requests */
/* ### make_requests begin ### */
static int dump_new_process_request( struct new_process_request *req, int len )
{
fprintf( stderr, " inherit=%d,", req->inherit );
......@@ -770,7 +778,6 @@ static int dump_debug_process_request( struct debug_process_request *req, int le
fprintf( stderr, " pid=%p", req->pid );
return (int)sizeof(*req);
}
typedef int (*dump_func)( void *req, int len );
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
......@@ -902,8 +909,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)0,
};
static const char * const req_names[REQ_NB_REQUESTS] =
{
static const char * const req_names[REQ_NB_REQUESTS] = {
"new_process",
"new_thread",
"set_debug",
......@@ -968,15 +974,19 @@ static const char * const req_names[REQ_NB_REQUESTS] =
"debug_process",
};
void trace_request( enum request req, void *data, int len, int fd )
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
void trace_request( enum request req, int fd )
{
int size;
int size, len;
current->last_req = req;
fprintf( stderr, "%08x: %s(", (unsigned int)current, req_names[req] );
size = req_dumpers[req]( data, len );
len = (char *)current->req_end - (char *)current->req_pos;
size = req_dumpers[req]( current->req_pos, len );
if ((len -= size) > 0)
{
unsigned char *ptr = (unsigned char *)data + size;
unsigned char *ptr = (unsigned char *)current->req_pos + size;
while (len--) fprintf( stderr, ", %02x", *ptr++ );
}
if (fd != -1) fprintf( stderr, " ) fd=%d\n", fd );
......@@ -994,29 +1004,22 @@ void trace_kill( int exit_code )
(unsigned int)current, exit_code );
}
void trace_reply( struct thread *thread, int type, int pass_fd,
struct iovec *vec, int veclen )
void trace_reply( struct thread *thread, int pass_fd )
{
static unsigned char buffer[MAX_MSG_LENGTH];
if (!thread) return;
struct header *head = thread->buffer;
int len = head->len - sizeof(*head);
fprintf( stderr, "%08x: %s() = %d",
(unsigned int)thread, req_names[thread->last_req], type );
if (veclen)
(unsigned int)thread, req_names[thread->last_req], head->type );
if (len)
{
unsigned char *p = buffer;
int len;
for (; veclen; veclen--, vec++)
{
memcpy( p, vec->iov_base, vec->iov_len );
p += vec->iov_len;
}
const unsigned char *data = (unsigned char *)(head + 1);
int res = 0;
fprintf( stderr, " {" );
len = p - buffer;
if (reply_dumpers[thread->last_req])
len -= reply_dumpers[thread->last_req]( buffer, len );
p -= len;
while (len--) fprintf( stderr, ", %02x", *p++ );
res = reply_dumpers[thread->last_req]( data, len );
len -= res;
data += res;
while (len--) fprintf( stderr, ", %02x", *data++ );
fprintf( stderr, " }" );
}
if (pass_fd != -1) fprintf( stderr, " fd=%d\n", pass_fd );
......
#! /usr/bin/perl -w
#
# Build the server/trace.c and include/server/request.h files
# Build the server/trace.c and server/request.h files
# from the contents of include/server.h.
#
# Copyright (C) 1998 Alexandre Julliard
......@@ -23,57 +23,11 @@ my @requests = ();
my %replies = ();
open(SERVER,"include/server.h") or die "Can't open include/server.h";
open(TRACE,">server/trace.c") or die "Can't create server/trace.c";
open(REQUESTS,">include/server/request.h") or die "Can't create include/server/request.h";
### Generate the header
print TRACE <<EOF;
/* File generated automatically by $0; DO NOT EDIT!! */
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include "server.h"
#include "thread.h"
static int dump_chars( void *ptr, int len )
{
fprintf( stderr, "\\\"%.*s\\\"", len, (char *)ptr );
return len;
}
static int dump_ints( void *ptr, int len )
{
int i;
if (!(len /= sizeof(int)))
{
fprintf( stderr, "{}" );
return 0;
}
for (i = 0; i < len; i++)
fprintf( stderr, "%c%d", i ? ',' : '{', *((int *)ptr + i) );
fprintf( stderr, "}" );
return len * sizeof(int);
}
static int dump_ptrs( void *ptr, int len )
{
int i;
if (!(len /= sizeof(void*)))
{
fprintf( stderr, "{}" );
return 0;
}
for (i = 0; i < len; i++)
fprintf( stderr, "%c%p", i ? ',' : '{', *((void **)ptr + i) );
fprintf( stderr, "}" );
return len * sizeof(void*);
}
EOF
### Parse server.h to find request/reply structure definitions
my @trace_lines = ();
while (<SERVER>)
{
if (/^struct +(\w+)_request/) { &DO_REQUEST($1); }
......@@ -82,137 +36,56 @@ while (<SERVER>)
### Output the dumping function tables
print TRACE "typedef int (*dump_func)( void *req, int len );\n\n";
print TRACE "static const dump_func req_dumpers[REQ_NB_REQUESTS] = {\n";
push @trace_lines, "static const dump_func req_dumpers[REQ_NB_REQUESTS] = {\n";
foreach $req (@requests)
{
print TRACE " (dump_func)dump_${req}_request,\n";
push @trace_lines, " (dump_func)dump_${req}_request,\n";
}
print TRACE "};\n\n";
push @trace_lines, "};\n\n";
print TRACE "static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {\n";
push @trace_lines, "static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {\n";
foreach $req (@requests)
{
print TRACE " (dump_func)", $replies{$req} ? "dump_${req}_reply,\n" : "0,\n";
push @trace_lines, " (dump_func)", $replies{$req} ? "dump_${req}_reply,\n" : "0,\n";
}
print TRACE "};\n\n";
push @trace_lines, "};\n\n";
print TRACE <<EOF;
static const char * const req_names[REQ_NB_REQUESTS] =
{
EOF
push @trace_lines, "static const char * const req_names[REQ_NB_REQUESTS] = {\n";
foreach $req (@requests)
{
print TRACE " \"$req\",\n";
}
### Output the tracing functions
print TRACE <<EOF;
};
void trace_request( enum request req, void *data, int len, int fd )
{
int size;
current->last_req = req;
fprintf( stderr, "%08x: %s(", (unsigned int)current, req_names[req] );
size = req_dumpers[req]( data, len );
if ((len -= size) > 0)
{
unsigned char *ptr = (unsigned char *)data + size;
while (len--) fprintf( stderr, ", %02x", *ptr++ );
}
if (fd != -1) fprintf( stderr, " ) fd=%d\\n", fd );
else fprintf( stderr, " )\\n" );
}
void trace_timeout(void)
{
fprintf( stderr, "%08x: *timeout*\\n", (unsigned int)current );
push @trace_lines, " \"$req\",\n";
}
push @trace_lines, "};\n";
void trace_kill( int exit_code )
{
fprintf( stderr,"%08x: *killed* exit_code=%d\\n",
(unsigned int)current, exit_code );
}
void trace_reply( struct thread *thread, int type, int pass_fd,
struct iovec *vec, int veclen )
{
static unsigned char buffer[MAX_MSG_LENGTH];
if (!thread) return;
fprintf( stderr, "%08x: %s() = %d",
(unsigned int)thread, req_names[thread->last_req], type );
if (veclen)
{
unsigned char *p = buffer;
int len;
for (; veclen; veclen--, vec++)
{
memcpy( p, vec->iov_base, vec->iov_len );
p += vec->iov_len;
}
fprintf( stderr, " {" );
len = p - buffer;
if (reply_dumpers[thread->last_req])
len -= reply_dumpers[thread->last_req]( buffer, len );
p -= len;
while (len--) fprintf( stderr, ", %02x", *p++ );
fprintf( stderr, " }" );
}
if (pass_fd != -1) fprintf( stderr, " fd=%d\\n", pass_fd );
else fprintf( stderr, "\\n" );
}
EOF
### Output the requests list
print REQUESTS <<EOF;
/* File generated automatically by $0; DO NOT EDIT!! */
#ifndef __WINE_SERVER_REQUEST_H
#define __WINE_SERVER_REQUEST_H
enum request
{
EOF
REPLACE_IN_FILE( "server/trace.c", @trace_lines );
foreach $req (@requests)
{
print REQUESTS " REQ_\U$req,\n";
}
print REQUESTS <<EOF;
REQ_NB_REQUESTS
};
### Replace the request list in server.h by the new values
#ifdef WANT_REQUEST_HANDLERS
my @server_lines = ();
EOF
push @server_lines, "enum request\n{\n";
foreach $req (@requests) { push @server_lines, " REQ_\U$req,\n"; }
push @server_lines, " REQ_NB_REQUESTS\n};\n";
foreach $req (@requests) { print REQUESTS "DECL_HANDLER($req);\n"; }
REPLACE_IN_FILE( "include/server.h", @server_lines );
print REQUESTS <<EOF;
### Output the request handlers list
static const struct handler {
void (*handler)();
unsigned int min_size;
} req_handlers[REQ_NB_REQUESTS] = {
EOF
my @request_lines = ();
foreach $req (@requests) { push @request_lines, "DECL_HANDLER($req);\n"; }
push @request_lines, "\n#ifdef WANT_REQUEST_HANDLERS\n\n";
push @request_lines, "static const struct handler {\n";
push @request_lines, " void (*handler)( void *req, int fd );\n";
push @request_lines, " unsigned int min_size;\n";
push @request_lines, "} req_handlers[REQ_NB_REQUESTS] = {\n";
foreach $req (@requests)
{
print REQUESTS " { (void(*)())req_$req, sizeof(struct ${req}_request) },\n";
push @request_lines, " { (void(*)())req_$req, sizeof(struct ${req}_request) },\n";
}
push @request_lines, "};\n#endif /* WANT_REQUEST_HANDLERS */\n";
print REQUESTS <<EOF;
};
#endif /* WANT_REQUEST_HANDLERS */
#endif /* __WINE_SERVER_REQUEST_H */
EOF
REPLACE_IN_FILE( "server/request.h", @request_lines );
### Handle a request structure definition
......@@ -264,7 +137,7 @@ sub DO_DUMP_FUNC
{
my $vararg = 0;
my $name = shift;
print TRACE "\nstatic int dump_$name( struct $name *req, int len )\n{\n";
push @trace_lines, "static int dump_$name( struct $name *req, int len )\n{\n";
while ($#_ >= 0)
{
my $type = shift;
......@@ -272,17 +145,41 @@ sub DO_DUMP_FUNC
if ($type =~ /\[0\]$/) # vararg type?
{
$vararg = 1;
print TRACE " fprintf( stderr, \" $var=\" );\n";
print TRACE " return $formats{$type}( req+1, len - (int)sizeof(*req) ) + sizeof(*req);\n";
push @trace_lines, " fprintf( stderr, \" $var=\" );\n";
push @trace_lines, " return $formats{$type}( req+1, len - (int)sizeof(*req) ) + sizeof(*req);\n";
}
else
{
print TRACE " fprintf( stderr, \" $var=$formats{$type}";
print TRACE "," if ($#_ > 0);
print TRACE "\", ";
print TRACE "req->$var );\n";
push @trace_lines, " fprintf( stderr, \" $var=$formats{$type}";
push @trace_lines, "," if ($#_ > 0);
push @trace_lines, "\", ";
push @trace_lines, "req->$var );\n";
}
}
print TRACE " return (int)sizeof(*req);\n" unless $vararg;
print TRACE "}\n";
push @trace_lines, " return (int)sizeof(*req);\n" unless $vararg;
push @trace_lines, "}\n\n";
}
### Replace the contents of a file between ### make_requests ### marks
sub REPLACE_IN_FILE
{
my $name = shift;
my @data = @_;
my @lines = ();
open(FILE,$name) or die "Can't open $name";
while (<FILE>)
{
push @lines, $_;
last if /\#\#\# make_requests begin \#\#\#/;
}
push @lines, "\n", @data;
while (<FILE>)
{
if (/\#\#\# make_requests end \#\#\#/) { push @lines, "\n", $_; last; }
}
push @lines, <FILE>;
open(FILE,">$name") or die "Can't modify $name";
print FILE @lines;
close(FILE);
}
......@@ -43,10 +43,8 @@
#include "winerror.h"
#include "wincon.h"
#include "heap.h"
#include "debugtools.h"
#include "server/request.h"
#include "server.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(console)
......@@ -65,7 +63,7 @@ static BOOL CONSOLE_GetInfo( HANDLE handle, struct get_console_info_reply *reply
req.handle = handle;
CLIENT_SendRequest( REQ_GET_CONSOLE_INFO, -1, 1, &req, sizeof(req) );
return !CLIENT_WaitSimpleReply( reply, sizeof(*reply), NULL );
return !CLIENT_WaitReply( NULL, NULL, 1, reply, sizeof(*reply) );
}
/****************************************************************************
......@@ -451,8 +449,8 @@ HANDLE CONSOLE_OpenHandle( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
CLIENT_SendRequest( REQ_OPEN_CONSOLE, -1, 1, &req, sizeof(req) );
SetLastError(0);
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
return reply.handle;
if (!CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return reply.handle;
return -1;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment