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.
This commit is contained in:
Alexandre Julliard 1999-06-22 17:26:53 +00:00
parent 0a860a01f9
commit 5bc78089db
37 changed files with 1404 additions and 1525 deletions

View File

@ -43,7 +43,6 @@
#include "wincon.h"
#include "debug.h"
#include "server/request.h"
#include "server.h"
DEFAULT_DEBUG_CHANNEL(file)

View 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,

View File

@ -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 */

View File

@ -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;

View File

@ -61,7 +61,6 @@
#include "heap.h"
#include "options.h"
#include "server/request.h"
#include "server.h"
#include "process.h"
#include "winerror.h"

View File

@ -11,13 +11,13 @@
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdarg.h>
#include "process.h"
#include "thread.h"
#include "server/request.h"
#include "server.h"
#include "winerror.h"
@ -54,120 +54,139 @@ void CLIENT_ProtocolError( const char *err, ... )
/***********************************************************************
* CLIENT_SendRequest_v
* CLIENT_perror
*/
void CLIENT_perror( const char *err )
{
fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
perror( err );
CLIENT_Die();
}
/***********************************************************************
* send_request
*
* Send a request to the server.
*/
static void CLIENT_SendRequest_v( enum request req, int pass_fd,
struct iovec *vec, int veclen )
static void send_request( enum request req )
{
struct header *head = NtCurrentTeb()->buffer;
int ret, seq = NtCurrentTeb()->seq++;
assert( server_remaining() >= 0 );
head->type = req;
head->len = (char *)NtCurrentTeb()->buffer_args - (char *)NtCurrentTeb()->buffer;
NtCurrentTeb()->buffer_args = head + 1; /* reset the args buffer */
if ((ret = write( NtCurrentTeb()->socket, &seq, sizeof(seq) )) == sizeof(seq))
return;
if (ret == -1)
{
if (errno == EPIPE) CLIENT_Die();
CLIENT_perror( "sendmsg" );
}
CLIENT_ProtocolError( "partial seq sent %d/%d\n", ret, sizeof(seq) );
}
/***********************************************************************
* send_request_fd
*
* Send a request to the server, passing a file descriptor.
*/
static void send_request_fd( enum request req, int fd )
{
struct header *head = NtCurrentTeb()->buffer;
int ret, seq = NtCurrentTeb()->seq++;
#ifndef HAVE_MSGHDR_ACCRIGHTS
struct cmsg_fd cmsg;
#endif
struct msghdr msghdr;
struct header head;
int i, ret, len;
struct iovec vec;
assert( veclen > 0 );
vec[0].iov_base = &head;
vec[0].iov_len = sizeof(head);
for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
assert( server_remaining() >= 0 );
assert( len <= MAX_MSG_LENGTH );
head.type = req;
head.len = len;
head.seq = NtCurrentTeb()->seq++;
head->type = req;
head->len = (char *)NtCurrentTeb()->buffer_args - (char *)NtCurrentTeb()->buffer;
NtCurrentTeb()->buffer_args = head + 1; /* reset the args buffer */
vec.iov_base = &seq;
vec.iov_len = sizeof(seq);
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = vec;
msghdr.msg_iovlen = veclen;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
#ifdef HAVE_MSGHDR_ACCRIGHTS
if (pass_fd != -1) /* we have an fd to send */
{
msghdr.msg_accrights = (void *)&pass_fd;
msghdr.msg_accrightslen = sizeof(pass_fd);
}
else
{
msghdr.msg_accrights = NULL;
msghdr.msg_accrightslen = 0;
}
msghdr.msg_accrights = (void *)&fd;
msghdr.msg_accrightslen = sizeof(fd);
#else /* HAVE_MSGHDR_ACCRIGHTS */
if (pass_fd != -1) /* we have an fd to send */
{
cmsg.len = sizeof(cmsg);
cmsg.level = SOL_SOCKET;
cmsg.type = SCM_RIGHTS;
cmsg.fd = pass_fd;
msghdr.msg_control = &cmsg;
msghdr.msg_controllen = sizeof(cmsg);
}
else
{
msghdr.msg_control = NULL;
msghdr.msg_controllen = 0;
}
msghdr.msg_flags = 0;
cmsg.len = sizeof(cmsg);
cmsg.level = SOL_SOCKET;
cmsg.type = SCM_RIGHTS;
cmsg.fd = fd;
msghdr.msg_control = &cmsg;
msghdr.msg_controllen = sizeof(cmsg);
msghdr.msg_flags = 0;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) < len)
if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(seq)) return;
if (ret == -1)
{
if (ret == -1)
{
if (errno == EPIPE) CLIENT_Die();
perror( "sendmsg" );
}
CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret, len );
if (errno == EPIPE) CLIENT_Die();
CLIENT_perror( "sendmsg" );
}
/* we passed the fd now we can close it */
if (pass_fd != -1) close( pass_fd );
CLIENT_ProtocolError( "partial seq sent %d/%d\n", ret, sizeof(seq) );
}
/***********************************************************************
* CLIENT_SendRequest
*
* Send a request to the server.
*/
void CLIENT_SendRequest( enum request req, int pass_fd,
int n, ... /* arg_1, len_1, etc. */ )
{
struct iovec vec[16];
va_list args;
int i;
n++; /* for vec[0] */
assert( n < 16 );
va_start( args, n );
for (i = 1; i < n; i++)
{
vec[i].iov_base = va_arg( args, void * );
vec[i].iov_len = va_arg( args, int );
}
va_end( args );
CLIENT_SendRequest_v( req, pass_fd, vec, n );
}
/***********************************************************************
* CLIENT_WaitReply_v
* wait_reply
*
* Wait for a reply from the server.
* Returns the error code (or 0 if OK).
*/
static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
struct iovec *vec, int veclen )
static void wait_reply(void)
{
int pass_fd = -1;
struct header head;
int ret, remaining;
int seq, ret;
for (;;)
{
if ((ret = read( NtCurrentTeb()->socket, &seq, sizeof(seq) )) == sizeof(seq))
{
if (seq != NtCurrentTeb()->seq++)
CLIENT_ProtocolError( "sequence %08x instead of %08x\n", seq, NtCurrentTeb()->seq - 1 );
return;
}
if (ret == -1)
{
if (errno == EINTR) continue;
if (errno == EPIPE) CLIENT_Die();
CLIENT_perror("read");
}
if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
CLIENT_ProtocolError( "partial seq received %d/%d\n", ret, sizeof(seq) );
}
}
/***********************************************************************
* wait_reply_fd
*
* Wait for a reply from the server, when a file descriptor is passed.
*/
static int wait_reply_fd(void)
{
struct iovec vec;
int seq, ret;
#ifdef HAVE_MSGHDR_ACCRIGHTS
struct msghdr msghdr;
int fd = -1;
msghdr.msg_accrights = (void *)&pass_fd;
msghdr.msg_accrights = (void *)&fd;
msghdr.msg_accrightslen = sizeof(int);
#else /* HAVE_MSGHDR_ACCRIGHTS */
struct msghdr msghdr;
@ -184,88 +203,136 @@ static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = vec;
msghdr.msg_iovlen = veclen;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
vec.iov_base = &seq;
vec.iov_len = sizeof(seq);
assert( veclen > 0 );
vec[0].iov_base = &head;
vec[0].iov_len = sizeof(head);
while ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == -1)
for (;;)
{
if (errno == EINTR) continue;
if (errno == EPIPE) CLIENT_Die();
perror("recvmsg");
CLIENT_ProtocolError( "recvmsg\n" );
}
if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
/* sanity checks */
if (ret < sizeof(head))
CLIENT_ProtocolError( "partial header received %d/%d\n", ret, sizeof(head) );
if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
CLIENT_ProtocolError( "header length %d\n", head.len );
if (head.seq != NtCurrentTeb()->seq++)
CLIENT_ProtocolError( "sequence %08x instead of %08x\n",
head.seq, NtCurrentTeb()->seq - 1 );
#ifndef HAVE_MSGHDR_ACCRIGHTS
pass_fd = cmsg.fd;
#endif
if (passed_fd)
{
*passed_fd = pass_fd;
pass_fd = -1;
}
if (len) *len = ret - sizeof(head);
if (pass_fd != -1) close( pass_fd );
remaining = head.len - ret;
while (remaining > 0) /* get remaining data */
{
char *bufp, buffer[1024];
int addlen, i, iovtot = 0;
/* see if any iovs are still incomplete, otherwise drop the rest */
for (i = 0; i < veclen && remaining > 0; i++)
{
if (iovtot + vec[i].iov_len > head.len - remaining)
{
addlen = iovtot + vec[i].iov_len - (head.len - remaining);
bufp = (char *)vec[i].iov_base + (vec[i].iov_len - addlen);
if (addlen > remaining) addlen = remaining;
if ((addlen = recv( NtCurrentTeb()->socket, bufp, addlen, 0 )) == -1)
{
perror( "recv" );
CLIENT_ProtocolError( "recv\n" );
}
if (!addlen) CLIENT_Die(); /* the server closed the connection; time to die... */
if (len) *len += addlen;
remaining -= addlen;
}
iovtot += vec[i].iov_len;
}
if (remaining > 0)
addlen = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
else
break;
if ((addlen = recv( NtCurrentTeb()->socket, buffer, addlen, 0 )) == -1)
if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(seq))
{
perror( "recv" );
CLIENT_ProtocolError( "recv\n" );
if (seq != NtCurrentTeb()->seq++)
CLIENT_ProtocolError( "sequence %08x instead of %08x\n", seq, NtCurrentTeb()->seq - 1 );
#ifdef HAVE_MSGHDR_ACCRIGHTS
return fd;
#else
return cmsg.fd;
#endif
}
if (!addlen) CLIENT_Die(); /* the server closed the connection; time to die... */
remaining -= addlen;
if (ret == -1)
{
if (errno == EINTR) continue;
if (errno == EPIPE) CLIENT_Die();
CLIENT_perror("recvmsg");
}
if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
CLIENT_ProtocolError( "partial seq received %d/%d\n", ret, sizeof(seq) );
}
}
if (head.type) SetLastError( head.type );
return head.type; /* error code */
/***********************************************************************
* server_call
*
* Perform a server call.
*/
unsigned int server_call( enum request req )
{
struct header *head;
send_request( req );
wait_reply();
head = (struct header *)NtCurrentTeb()->buffer;
if ((head->len < sizeof(*head)) || (head->len > NtCurrentTeb()->buffer_size))
CLIENT_ProtocolError( "header length %d\n", head->len );
if (head->type) SetLastError( head->type );
return head->type; /* error code */
}
/***********************************************************************
* server_call_fd
*
* Perform a server call, passing a file descriptor.
* If *fd is != -1, it will be passed to the server.
* If the server passes an fd, it will be stored into *fd.
*/
unsigned int server_call_fd( enum request req, int *fd )
{
struct header *head;
if (*fd == -1) send_request( req );
else send_request_fd( req, *fd );
*fd = wait_reply_fd();
head = (struct header *)NtCurrentTeb()->buffer;
if ((head->len < sizeof(*head)) || (head->len > NtCurrentTeb()->buffer_size))
CLIENT_ProtocolError( "header length %d\n", head->len );
if (head->type) SetLastError( head->type );
return head->type; /* error code */
}
/***********************************************************************
* CLIENT_SendRequest
*
* Send a request to the server.
*/
void CLIENT_SendRequest( enum request req, int pass_fd,
int n, ... /* arg_1, len_1, etc. */ )
{
va_list args;
va_start( args, n );
while (n--)
{
void *ptr = va_arg( args, void * );
int len = va_arg( args, int );
memcpy( server_add_data( len ), ptr, len );
}
va_end( args );
if (pass_fd == -1) send_request( req );
else
{
send_request_fd( req, pass_fd );
close( pass_fd ); /* we passed the fd now we can close it */
}
}
/***********************************************************************
* CLIENT_WaitReply_v
*
* Wait for a reply from the server.
* Returns the error code (or 0 if OK).
*/
static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
struct iovec *vec, int veclen )
{
struct header *head;
char *ptr;
int i, remaining;
if (passed_fd) *passed_fd = wait_reply_fd();
else wait_reply();
head = (struct header *)NtCurrentTeb()->buffer;
if ((head->len < sizeof(*head)) || (head->len > NtCurrentTeb()->buffer_size))
CLIENT_ProtocolError( "header length %d\n", head->len );
remaining = head->len - sizeof(*head);
ptr = (char *)(head + 1);
for (i = 0; i < veclen; i++, vec++)
{
int len = MIN( remaining, vec->iov_len );
memcpy( vec->iov_base, ptr, len );
ptr += len;
if (!(remaining -= len)) break;
}
if (len) *len = head->len - sizeof(*head);
if (head->type) SetLastError( head->type );
return head->type; /* error code */
}
@ -281,10 +348,9 @@ unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
va_list args;
int i;
n++; /* for vec[0] */
assert( n < 16 );
va_start( args, n );
for (i = 1; i < n; i++)
for (i = 0; i < n; i++)
{
vec[i].iov_base = va_arg( args, void * );
vec[i].iov_len = va_arg( args, int );
@ -301,13 +367,13 @@ unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
*/
unsigned int CLIENT_WaitSimpleReply( void *reply, int len, int *passed_fd )
{
struct iovec vec[2];
struct iovec vec;
unsigned int ret;
int got;
vec[1].iov_base = reply;
vec[1].iov_len = len;
ret = CLIENT_WaitReply_v( &got, passed_fd, vec, 2 );
vec.iov_base = reply;
vec.iov_len = len;
ret = CLIENT_WaitReply_v( &got, passed_fd, &vec, 1 );
if (got != len)
CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len, got );
return ret;
@ -363,13 +429,22 @@ int CLIENT_InitThread(void)
{
struct init_thread_request req;
struct init_thread_reply reply;
TEB *teb = NtCurrentTeb();
int fd = wait_reply_fd();
if (fd == -1) CLIENT_ProtocolError( "no fd passed on first request\n" );
if ((teb->buffer_size = lseek( fd, 0, SEEK_END )) == -1) CLIENT_perror( "lseek" );
teb->buffer = mmap( 0, teb->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
close( fd );
if (teb->buffer == (void*)-1) CLIENT_perror( "mmap" );
teb->buffer_args = (char *)teb->buffer + sizeof(struct header);
req.unix_pid = getpid();
req.teb = NtCurrentTeb();
req.teb = teb;
CLIENT_SendRequest( REQ_INIT_THREAD, -1, 1, &req, sizeof(req) );
if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return -1;
NtCurrentTeb()->process->server_pid = reply.pid;
NtCurrentTeb()->tid = reply.tid;
teb->process->server_pid = reply.pid;
teb->tid = reply.tid;
return 0;
}

View File

@ -6,7 +6,6 @@
#include "process.h"
#include "thread.h"
#include "server/request.h"
#include "server.h"
#include "debugtools.h"

View File

@ -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;

View File

@ -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;

View File

@ -7,7 +7,6 @@
#include <assert.h>
#include "winerror.h"
#include "winbase.h"
#include "server/request.h"
#include "server.h"

View File

@ -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;

View File

@ -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 );
}

View File

@ -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) );
}

View File

@ -27,6 +27,7 @@
#include "handle.h"
#include "process.h"
#include "thread.h"
#include "request.h"
struct screen_buffer;
@ -72,6 +73,7 @@ static int console_get_info( struct object *obj, struct get_file_info_reply *rep
static const struct object_ops console_input_ops =
{
sizeof(struct console_input),
console_input_dump,
console_input_add_queue,
console_input_remove_queue,
@ -86,6 +88,7 @@ static const struct object_ops console_input_ops =
static const struct object_ops screen_buffer_ops =
{
sizeof(struct screen_buffer),
screen_buffer_dump,
screen_buffer_add_queue,
screen_buffer_remove_queue,
@ -99,76 +102,76 @@ static const struct object_ops screen_buffer_ops =
};
static int create_console( int fd, struct object *obj[2] )
static struct object *create_console_input( int fd )
{
struct console_input *console_input;
struct screen_buffer *screen_buffer;
int read_fd, write_fd;
if ((read_fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
if ((fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
{
file_set_error();
return 0;
return NULL;
}
if ((write_fd = (fd != -1) ? dup(fd) : dup(1)) == -1)
if ((console_input = alloc_object( &console_input_ops )))
{
console_input->select.fd = fd;
console_input->select.func = default_select_event;
console_input->select.private = console_input;
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
console_input->output = NULL;
console_input->recnum = 0;
console_input->records = NULL;
register_select_user( &console_input->select );
return &console_input->obj;
}
close( fd );
return NULL;
}
static struct object *create_console_output( int fd, struct object *input )
{
struct console_input *console_input = (struct console_input *)input;
struct screen_buffer *screen_buffer;
if ((fd = (fd != -1) ? dup(fd) : dup(1)) == -1)
{
file_set_error();
close( read_fd );
return 0;
return NULL;
}
if (!(console_input = mem_alloc( sizeof(struct console_input) )))
if ((screen_buffer = alloc_object( &screen_buffer_ops )))
{
close( read_fd );
close( write_fd );
return 0;
screen_buffer->select.fd = fd;
screen_buffer->select.func = default_select_event;
screen_buffer->select.private = screen_buffer;
screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
screen_buffer->input = console_input;
screen_buffer->cursor_size = 100;
screen_buffer->cursor_visible = 1;
screen_buffer->pid = 0;
screen_buffer->title = strdup( "Wine console" );
register_select_user( &screen_buffer->select );
console_input->output = screen_buffer;
return &screen_buffer->obj;
}
if (!(screen_buffer = mem_alloc( sizeof(struct screen_buffer) )))
{
close( read_fd );
close( write_fd );
free( console_input );
return 0;
}
init_object( &console_input->obj, &console_input_ops, NULL );
init_object( &screen_buffer->obj, &screen_buffer_ops, NULL );
console_input->select.fd = read_fd;
console_input->select.func = default_select_event;
console_input->select.private = console_input;
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
console_input->output = screen_buffer;
console_input->recnum = 0;
console_input->records = NULL;
screen_buffer->select.fd = write_fd;
screen_buffer->select.func = default_select_event;
screen_buffer->select.private = screen_buffer;
screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
screen_buffer->input = console_input;
screen_buffer->cursor_size = 100;
screen_buffer->cursor_visible = 1;
screen_buffer->pid = 0;
screen_buffer->title = strdup( "Wine console" );
register_select_user( &console_input->select );
register_select_user( &screen_buffer->select );
CLEAR_ERROR();
obj[0] = &console_input->obj;
obj[1] = &screen_buffer->obj;
return 1;
close( fd );
return NULL;
}
/* allocate a console for this process */
int alloc_console( struct process *process )
{
struct object *obj[2];
if (process->console_in || process->console_out)
{
SET_ERROR( ERROR_ACCESS_DENIED );
set_error( ERROR_ACCESS_DENIED );
return 0;
}
if (!create_console( -1, obj )) return 0;
process->console_in = obj[0];
process->console_out = obj[1];
return 1;
if ((process->console_in = create_console_input( -1 )))
{
if ((process->console_out = create_console_output( -1, process->console_in )))
return 1;
release_object( process->console_in );
}
return 0;
}
/* free the console for this process */
@ -203,7 +206,7 @@ static int set_console_fd( int handle, int fd, int pid )
}
else
{
SET_ERROR( ERROR_INVALID_HANDLE );
set_error( ERROR_INVALID_HANDLE );
release_object( obj );
return 0;
}
@ -258,7 +261,7 @@ static int get_console_mode( int handle, int *mode )
*mode = ((struct screen_buffer *)obj)->mode;
ret = 1;
}
else SET_ERROR( ERROR_INVALID_HANDLE );
else set_error( ERROR_INVALID_HANDLE );
release_object( obj );
return ret;
}
@ -280,13 +283,14 @@ static int set_console_mode( int handle, int mode )
((struct screen_buffer *)obj)->mode = mode;
ret = 1;
}
else SET_ERROR( ERROR_INVALID_HANDLE );
else set_error( ERROR_INVALID_HANDLE );
release_object( obj );
return ret;
}
/* set misc console information (output handle only) */
static 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, size_t len )
{
struct screen_buffer *console;
if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
@ -299,8 +303,14 @@ static int set_console_info( int handle, struct set_console_info_request *req, c
}
if (req->mask & SET_CONSOLE_INFO_TITLE)
{
if (console->title) free( console->title );
console->title = strdup( title );
char *new_title = mem_alloc( len + 1 );
if (new_title)
{
memcpy( new_title, title, len );
new_title[len] = 0;
if (console->title) free( console->title );
console->title = new_title;
}
}
release_object( console );
return 1;
@ -333,7 +343,7 @@ static int write_console_input( int handle, int count, INPUT_RECORD *records )
if (!(new_rec = realloc( console->records,
(console->recnum + count) * sizeof(INPUT_RECORD) )))
{
SET_ERROR( ERROR_NOT_ENOUGH_MEMORY );
set_error( ERROR_NOT_ENOUGH_MEMORY );
release_object( console );
return -1;
}
@ -348,14 +358,13 @@ static int write_console_input( int handle, int count, INPUT_RECORD *records )
static int read_console_input( int handle, int count, int flush )
{
struct console_input *console;
struct read_console_input_reply reply;
struct read_console_input_reply *reply = push_reply_data( current, sizeof(*reply) );
if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
GENERIC_READ, &console_input_ops )))
return -1;
if ((count < 0) || (count > console->recnum)) count = console->recnum;
send_reply( current, -1, 2, &reply, sizeof(reply),
console->records, count * sizeof(INPUT_RECORD) );
add_reply_data( current, console->records, count * sizeof(INPUT_RECORD) );
if (flush)
{
int i;
@ -445,7 +454,6 @@ static void console_input_destroy( struct object *obj )
unregister_select_user( &console->select );
close( console->select.fd );
if (console->output) console->output->input = NULL;
free( console );
}
static void screen_buffer_dump( struct object *obj, int verbose )
@ -511,101 +519,94 @@ static void screen_buffer_destroy( struct object *obj )
if (console->input) console->input->output = NULL;
if (console->pid) kill( console->pid, SIGTERM );
if (console->title) free( console->title );
free( console );
}
/* allocate a console for the current process */
DECL_HANDLER(alloc_console)
{
struct alloc_console_reply reply = { -1, -1 };
struct alloc_console_reply *reply = push_reply_data( current, sizeof(*reply) );
int in = -1, out = -1;
if (!alloc_console( current->process )) goto done;
if ((reply.handle_in = alloc_handle( current->process, current->process->console_in,
req->access, req->inherit )) != -1)
if ((in = alloc_handle( current->process, current->process->console_in,
req->access, req->inherit )) != -1)
{
if ((reply.handle_out = alloc_handle( current->process, current->process->console_out,
req->access, req->inherit )) != -1)
if ((out = alloc_handle( current->process, current->process->console_out,
req->access, req->inherit )) != -1)
goto done; /* everything is fine */
close_handle( current->process, reply.handle_in );
reply.handle_in = -1;
close_handle( current->process, in );
in = -1;
}
free_console( current->process );
done:
send_reply( current, -1, 1, &reply, sizeof(reply) );
reply->handle_in = in;
reply->handle_out = out;
}
/* 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 open_console_reply reply = { -1 };
struct open_console_reply *reply = push_reply_data( current, sizeof(*reply) );
struct object *obj= req->output ? current->process->console_out : current->process->console_in;
if (obj) reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
send_reply( current, -1, 1, &reply, sizeof(reply) );
if (obj) reply->handle = alloc_handle( current->process, obj, req->access, req->inherit );
else set_error( ERROR_ACCESS_DENIED );
}
/* 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 );
size_t len = get_req_strlen();
set_console_info( req->handle, req, get_req_data( len + 1 ), len );
}
/* get info about a console (output only) */
DECL_HANDLER(get_console_info)
{
struct get_console_info_reply reply;
struct get_console_info_reply *reply = push_reply_data( current, sizeof(*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 );
get_console_info( req->handle, reply, &title );
if (title) add_reply_data( current, title, strlen(title) + 1 );
}
/* 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) );
struct get_console_mode_reply *reply = push_reply_data( current, sizeof(*reply) );
get_console_mode( req->handle, &reply->mode );
}
/* 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;
struct write_console_input_reply *reply = push_reply_data( current, sizeof(*reply) );
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) );
if (check_req_data( req->count * sizeof(INPUT_RECORD)))
{
INPUT_RECORD *records = get_req_data( req->count * sizeof(INPUT_RECORD) );
reply->written = write_console_input( req->handle, req->count, records );
}
else fatal_protocol_error( "write_console_input: bad length" );
}
/* fetch input records from a console input queue */

View File

@ -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))
{
if (queue_debug_event( debugger, current, req->code, data ))
return; /* don't reply now, wait for continue_debug_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
{
struct send_debug_event_reply *reply = push_reply_data( current, sizeof(*reply) );
reply->status = 0;
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
}

View File

@ -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;
}

View File

@ -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 );
size_t len = get_req_strlen();
struct create_event_reply *reply = push_reply_data( current, sizeof(*reply) );
struct event *event;
obj = create_event( name, req->manual_reset, req->initial_state );
if (obj)
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 );
}

View File

@ -23,6 +23,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
struct file
{
@ -51,6 +52,7 @@ static void file_destroy( struct object *obj );
static const struct object_ops file_ops =
{
sizeof(struct file),
file_dump,
file_add_queue,
file_remove_queue,
@ -86,123 +88,99 @@ static int check_sharing( const char *name, int hash, unsigned int access,
existing_sharing &= file->sharing;
existing_access |= file->access;
}
if ((access & GENERIC_READ) && !(existing_sharing & FILE_SHARE_READ)) return 0;
if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) return 0;
if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) return 0;
if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) return 0;
if ((access & GENERIC_READ) && !(existing_sharing & FILE_SHARE_READ)) goto error;
if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) goto error;
if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) goto error;
if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) goto error;
return 1;
error:
set_error( ERROR_SHARING_VIOLATION );
return 0;
}
static struct object *create_file( int fd, const char *name, unsigned int access,
unsigned int sharing, int create, unsigned int attrs )
static struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing,
unsigned int attrs )
{
struct file *file;
int hash = 0;
if (fd == -1)
if ((file = alloc_object( &file_ops )))
{
int flags;
struct stat st;
if (!name)
{
SET_ERROR( ERROR_INVALID_PARAMETER );
return NULL;
}
/* check sharing mode */
hash = get_name_hash( name );
if (!check_sharing( name, hash, access, sharing ))
{
SET_ERROR( ERROR_SHARING_VIOLATION );
return NULL;
}
switch(create)
{
case CREATE_NEW: flags = O_CREAT | O_EXCL; break;
case CREATE_ALWAYS: flags = O_CREAT | O_TRUNC; break;
case OPEN_ALWAYS: flags = O_CREAT; break;
case TRUNCATE_EXISTING: flags = O_TRUNC; break;
case OPEN_EXISTING: flags = 0; break;
default: SET_ERROR( ERROR_INVALID_PARAMETER ); return NULL;
}
switch(access & (GENERIC_READ | GENERIC_WRITE))
{
case 0: break;
case GENERIC_READ: flags |= O_RDONLY; break;
case GENERIC_WRITE: flags |= O_WRONLY; break;
case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;
}
/* FIXME: should set error to ERROR_ALREADY_EXISTS if file existed before */
if ((fd = open( name, flags | O_NONBLOCK,
(attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666 )) == -1)
{
file_set_error();
return NULL;
}
/* Refuse to open a directory */
if (fstat( fd, &st ) == -1)
{
file_set_error();
close( fd );
return NULL;
}
if (S_ISDIR(st.st_mode))
{
SET_ERROR( ERROR_ACCESS_DENIED );
close( fd );
return NULL;
}
file->name = NULL;
file->next = NULL;
file->select.fd = fd;
file->select.func = default_select_event;
file->select.private = file;
file->access = access;
file->flags = attrs;
file->sharing = sharing;
register_select_user( &file->select );
}
else
{
if ((fd = dup(fd)) == -1)
{
file_set_error();
return NULL;
}
}
if (!(file = mem_alloc( sizeof(*file) )))
{
close( fd );
return NULL;
}
if (name)
{
if (!(file->name = mem_alloc( strlen(name) + 1 )))
{
close( fd );
free( file );
return NULL;
}
strcpy( file->name, name );
file->next = file_hash[hash];
file_hash[hash] = file;
}
else
{
file->name = NULL;
file->next = NULL;
}
init_object( &file->obj, &file_ops, NULL );
file->select.fd = fd;
file->select.func = default_select_event;
file->select.private = file;
file->access = access;
file->flags = attrs;
file->sharing = sharing;
register_select_user( &file->select );
CLEAR_ERROR();
return &file->obj;
return file;
}
/* Create a temp file for anonymous mappings */
struct file *create_temp_file( int access )
static struct file *create_file( const char *nameptr, size_t len, unsigned int access,
unsigned int sharing, int create, unsigned int attrs )
{
struct file *file;
int hash, flags;
struct stat st;
char *name;
int fd = -1;
if (!(name = mem_alloc( len + 1 ))) return NULL;
memcpy( name, nameptr, len );
name[len] = 0;
/* check sharing mode */
hash = get_name_hash( name );
if (!check_sharing( name, hash, access, sharing )) goto error;
switch(create)
{
case CREATE_NEW: flags = O_CREAT | O_EXCL; break;
case CREATE_ALWAYS: flags = O_CREAT | O_TRUNC; break;
case OPEN_ALWAYS: flags = O_CREAT; break;
case TRUNCATE_EXISTING: flags = O_TRUNC; break;
case OPEN_EXISTING: flags = 0; break;
default: set_error( ERROR_INVALID_PARAMETER ); goto error;
}
switch(access & (GENERIC_READ | GENERIC_WRITE))
{
case 0: break;
case GENERIC_READ: flags |= O_RDONLY; break;
case GENERIC_WRITE: flags |= O_WRONLY; break;
case GENERIC_READ|GENERIC_WRITE: flags |= O_RDWR; break;
}
/* FIXME: should set error to ERROR_ALREADY_EXISTS if file existed before */
if ((fd = open( name, flags | O_NONBLOCK,
(attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666 )) == -1)
goto file_error;
/* refuse to open a directory */
if (fstat( fd, &st ) == -1) goto file_error;
if (S_ISDIR(st.st_mode))
{
set_error( ERROR_ACCESS_DENIED );
goto error;
}
if (!(file = create_file_for_fd( fd, access, sharing, attrs ))) goto error;
file->name = name;
file->next = file_hash[hash];
file_hash[hash] = file;
return file;
file_error:
file_set_error();
error:
if (fd != -1) close( fd );
free( name );
return NULL;
}
/* Create an anonymous Unix file */
int create_anonymous_file(void)
{
char *name;
int fd;
@ -210,34 +188,28 @@ struct file *create_temp_file( int access )
{
if (!(name = tmpnam(NULL)))
{
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
return NULL;
set_error( ERROR_TOO_MANY_OPEN_FILES );
return -1;
}
fd = open( name, O_CREAT | O_EXCL | O_RDWR, 0600 );
} while ((fd == -1) && (errno == EEXIST));
if (fd == -1)
{
file_set_error();
return NULL;
return -1;
}
unlink( name );
return fd;
}
if (!(file = mem_alloc( sizeof(*file) )))
{
close( fd );
return NULL;
}
init_object( &file->obj, &file_ops, NULL );
file->name = NULL;
file->next = NULL;
file->select.fd = fd;
file->select.func = default_select_event;
file->select.private = file;
file->access = access;
file->flags = 0;
file->sharing = 0;
register_select_user( &file->select );
CLEAR_ERROR();
/* Create a temp file for anonymous mappings */
struct file *create_temp_file( int access )
{
struct file *file;
int fd;
if ((fd = create_anonymous_file()) != -1) return NULL;
if (!(file = create_file_for_fd( fd, access, 0, 0 ))) close( fd );
return file;
}
@ -245,8 +217,8 @@ static void file_dump( struct object *obj, int verbose )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
printf( "File fd=%d flags=%08x name='%s'\n",
file->select.fd, file->flags, file->name );
fprintf( stderr, "File fd=%d flags=%08x name='%s'\n",
file->select.fd, file->flags, file->name );
}
static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
@ -368,7 +340,6 @@ static void file_destroy( struct object *obj )
}
unregister_select_user( &file->select );
close( file->select.fd );
free( file );
}
/* set the last error depending on errno */
@ -376,22 +347,22 @@ void file_set_error(void)
{
switch (errno)
{
case EAGAIN: SET_ERROR( ERROR_SHARING_VIOLATION ); break;
case EBADF: SET_ERROR( ERROR_INVALID_HANDLE ); break;
case ENOSPC: SET_ERROR( ERROR_HANDLE_DISK_FULL ); break;
case EAGAIN: set_error( ERROR_SHARING_VIOLATION ); break;
case EBADF: set_error( ERROR_INVALID_HANDLE ); break;
case ENOSPC: set_error( ERROR_HANDLE_DISK_FULL ); break;
case EACCES:
case EPERM: SET_ERROR( ERROR_ACCESS_DENIED ); break;
case EROFS: SET_ERROR( ERROR_WRITE_PROTECT ); break;
case EBUSY: SET_ERROR( ERROR_LOCK_VIOLATION ); break;
case ENOENT: SET_ERROR( ERROR_FILE_NOT_FOUND ); break;
case EISDIR: SET_ERROR( ERROR_CANNOT_MAKE ); break;
case EPERM: set_error( ERROR_ACCESS_DENIED ); break;
case EROFS: set_error( ERROR_WRITE_PROTECT ); break;
case EBUSY: set_error( ERROR_LOCK_VIOLATION ); break;
case ENOENT: set_error( ERROR_FILE_NOT_FOUND ); break;
case EISDIR: set_error( ERROR_CANNOT_MAKE ); break;
case ENFILE:
case EMFILE: SET_ERROR( ERROR_NO_MORE_FILES ); break;
case EEXIST: SET_ERROR( ERROR_FILE_EXISTS ); break;
case EINVAL: SET_ERROR( ERROR_INVALID_PARAMETER ); break;
case ESPIPE: SET_ERROR( ERROR_SEEK ); break;
case ENOTEMPTY: SET_ERROR( ERROR_DIR_NOT_EMPTY ); break;
default: perror("file_set_error"); SET_ERROR( ERROR_UNKNOWN ); break;
case EMFILE: set_error( ERROR_NO_MORE_FILES ); break;
case EEXIST: set_error( ERROR_FILE_EXISTS ); break;
case EINVAL: set_error( ERROR_INVALID_PARAMETER ); break;
case ESPIPE: set_error( ERROR_SEEK ); break;
case ENOTEMPTY: set_error( ERROR_DIR_NOT_EMPTY ); break;
default: perror("file_set_error"); set_error( ERROR_UNKNOWN ); break;
}
}
@ -415,7 +386,7 @@ static int set_file_pointer( int handle, int *low, int *high, int whence )
if (*high)
{
fprintf( stderr, "set_file_pointer: offset > 4Gb not supported yet\n" );
SET_ERROR( ERROR_INVALID_PARAMETER );
set_error( ERROR_INVALID_PARAMETER );
return 0;
}
@ -425,7 +396,7 @@ static int set_file_pointer( int handle, int *low, int *high, int whence )
{
/* Check for seek before start of file */
if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
SET_ERROR( ERROR_NEGATIVE_SEEK );
set_error( ERROR_NEGATIVE_SEEK );
else
file_set_error();
release_object( file );
@ -462,7 +433,7 @@ int grow_file( struct file *file, int size_high, int size_low )
if (size_high)
{
SET_ERROR( ERROR_INVALID_PARAMETER );
set_error( ERROR_INVALID_PARAMETER );
return 0;
}
if (fstat( file->select.fd, &st ) == -1)
@ -517,19 +488,28 @@ static int file_unlock( struct file *file, int offset_high, int offset_low,
/* 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 );
struct create_file_reply *reply = push_reply_data( current, sizeof(*reply) );
struct file *file = NULL;
if ((obj = create_file( fd, name, req->access,
req->sharing, req->create, req->attrs )) != NULL)
if (fd == -1)
{
reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
release_object( obj );
size_t len = get_req_strlen();
file = create_file( get_req_data( len + 1), len, req->access,
req->sharing, req->create, req->attrs );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
else
{
if ((fd = dup(fd)) == -1)
file_set_error();
else
file = create_file_for_fd( fd, req->access, req->sharing, req->attrs );
}
if (file)
{
reply->handle = alloc_handle( current->process, file, req->access, req->inherit );
release_object( file );
}
else reply->handle = -1;
}
/* get a Unix fd to read from a file */
@ -544,7 +524,7 @@ DECL_HANDLER(get_read_fd)
release_object( obj );
}
else read_fd = -1;
send_reply( current, read_fd, 0 );
set_reply_fd( current, read_fd );
}
/* get a Unix fd to write to a file */
@ -559,7 +539,7 @@ DECL_HANDLER(get_write_fd)
release_object( obj );
}
else write_fd = -1;
send_reply( current, write_fd, 0 );
set_reply_fd( current, write_fd );
}
/* set a file current position */
@ -569,14 +549,13 @@ DECL_HANDLER(set_file_pointer)
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) );
add_reply_data( current, &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 */
@ -589,28 +568,25 @@ DECL_HANDLER(flush_file)
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;
struct get_file_info_reply *reply = push_reply_data( current, sizeof(*reply) );
if ((obj = get_handle_obj( current->process, req->handle, 0, NULL )))
{
obj->ops->get_file_info( obj, &reply );
obj->ops->get_file_info( obj, reply );
release_object( obj );
}
send_reply( current, -1, 1, &reply, sizeof(reply) );
}
/* lock a region of a file */
@ -624,7 +600,6 @@ DECL_HANDLER(lock_file)
req->count_high, req->count_low );
release_object( file );
}
send_reply( current, -1, 0 );
}
/* unlock a region of a file */
@ -638,5 +613,4 @@ DECL_HANDLER(unlock_file)
req->count_high, req->count_low );
release_object( file );
}
send_reply( current, -1, 0 );
}

View File

@ -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) );
}

View File

@ -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 );

View File

@ -10,7 +10,6 @@
#include <stdlib.h>
#include <unistd.h>
#include "server.h"
#include "object.h"
#include "thread.h"

View File

@ -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 );
}

View File

@ -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 );
size_t len = get_req_strlen();
struct create_mutex_reply *reply = push_reply_data( current, sizeof(*reply) );
struct mutex *mutex;
obj = create_mutex( name, req->owned );
if (obj)
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 );
}
}

View File

@ -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 );
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 );
}
/* 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 )
/* set the name of an existing object */
static void set_object_name( struct object *obj, struct object_name *ptr )
{
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;
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;

View File

@ -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);

View File

@ -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 ((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 );
}
if (!(newpipe[1] = mem_alloc( sizeof(struct pipe) )))
{
close( fd[0] );
close( fd[1] );
free( newpipe[0] );
return 0;
}
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) );
}

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -1,76 +1,80 @@
/* 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
{
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
};
#ifndef __WINE_SERVER__
#error This file can only be used in the Wine server
#endif
#ifdef WANT_REQUEST_HANDLERS
#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 )
{
void *old = current->req_pos;
current->req_pos = (char *)old + len;
return old;
}
/* 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 */

View File

@ -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 );
size_t len = get_req_strlen();
struct create_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
struct semaphore *sem;
obj = create_semaphore( name, req->initial, req->max );
if (obj)
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 );
}

View File

@ -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 );
}

View File

@ -18,32 +18,19 @@
#include <unistd.h>
#include "config.h"
#include "server.h"
#include "object.h"
#include "request.h"
/* Some versions of glibc don't define this */
#ifndef SCM_RIGHTS
#define SCM_RIGHTS 1
#endif
/* client state */
enum state
{
RUNNING, /* running normally */
SENDING, /* sending us a request */
WAITING, /* waiting for us to reply */
READING /* reading our reply */
};
/* client structure */
struct client
{
enum state state; /* client state */
struct select_user select; /* select user */
unsigned int seq; /* current sequence number */
struct header head; /* current msg header */
char *data; /* current msg data */
int count; /* bytes sent/received so far */
int pass_fd; /* fd to pass to and from the client */
struct thread *self; /* client thread (opaque pointer) */
struct timeout_user *timeout; /* current timeout (opaque pointer) */
@ -62,110 +49,81 @@ static void protocol_error( struct client *client, const char *err, ... )
va_list args;
va_start( args, err );
fprintf( stderr, "Protocol error:%d: ", client->select.fd );
fprintf( stderr, "Protocol error:%p: ", client->self );
vfprintf( stderr, err, args );
va_end( args );
remove_client( client, PROTOCOL_ERROR );
}
/* send a message to a client that is ready to receive something */
static void do_write( struct client *client, int client_fd )
static void do_write( struct client *client )
{
struct iovec vec[2];
#ifndef HAVE_MSGHDR_ACCRIGHTS
struct cmsg_fd cmsg;
#endif
struct msghdr msghdr;
int ret;
/* make sure we have something to send */
assert( client->count < client->head.len );
/* make sure the client is listening */
assert( client->state == READING );
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = vec;
if (client->count < sizeof(client->head))
if (client->pass_fd == -1)
{
vec[0].iov_base = (char *)&client->head + client->count;
vec[0].iov_len = sizeof(client->head) - client->count;
vec[1].iov_base = client->data;
vec[1].iov_len = client->head.len - sizeof(client->head);
msghdr.msg_iovlen = 2;
ret = write( client->select.fd, &client->seq, sizeof(client->seq) );
}
else
else /* we have an fd to send */
{
vec[0].iov_base = client->data + client->count - sizeof(client->head);
vec[0].iov_len = client->head.len - client->count;
msghdr.msg_iovlen = 1;
}
struct iovec vec;
struct msghdr msghdr;
#ifdef HAVE_MSGHDR_ACCRIGHTS
if (client->pass_fd != -1) /* we have an fd to send */
{
msghdr.msg_accrights = (void *)&client->pass_fd;
msghdr.msg_accrightslen = sizeof(client->pass_fd);
}
else
{
msghdr.msg_accrights = NULL;
msghdr.msg_accrightslen = 0;
}
#else /* HAVE_MSGHDR_ACCRIGHTS */
if (client->pass_fd != -1) /* we have an fd to send */
{
cmsg.len = sizeof(cmsg);
struct cmsg_fd cmsg;
cmsg.len = sizeof(cmsg);
cmsg.level = SOL_SOCKET;
cmsg.type = SCM_RIGHTS;
cmsg.fd = client->pass_fd;
msghdr.msg_control = &cmsg;
cmsg.type = SCM_RIGHTS;
cmsg.fd = client->pass_fd;
msghdr.msg_control = &cmsg;
msghdr.msg_controllen = sizeof(cmsg);
}
else
{
msghdr.msg_control = NULL;
msghdr.msg_controllen = 0;
}
msghdr.msg_flags = 0;
msghdr.msg_flags = 0;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
ret = sendmsg( client_fd, &msghdr, 0 );
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
vec.iov_base = (char *)&client->seq;
vec.iov_len = sizeof(client->seq);
ret = sendmsg( client->select.fd, &msghdr, 0 );
close( client->pass_fd );
client->pass_fd = -1;
}
if (ret == sizeof(client->seq))
{
/* everything OK */
client->seq++;
set_select_events( &client->select, READ_EVENT );
return;
}
if (ret == -1)
{
if (errno != EPIPE) perror("sendmsg");
remove_client( client, BROKEN_PIPE );
return;
}
if (client->pass_fd != -1) /* We sent the fd, now we can close it */
{
close( client->pass_fd );
client->pass_fd = -1;
}
if ((client->count += ret) < client->head.len) return;
/* we have finished with this message */
if (client->data) free( client->data );
client->data = NULL;
client->count = 0;
client->state = RUNNING;
client->seq++;
set_select_events( &client->select, READ_EVENT );
fprintf( stderr, "Partial sequence sent (%d)\n", ret );
remove_client( client, BROKEN_PIPE );
}
/* read a message from a client that has something to say */
static void do_read( struct client *client, int client_fd )
static void do_read( struct client *client )
{
struct iovec vec;
int pass_fd = -1;
int ret;
int ret, seq;
#ifdef HAVE_MSGHDR_ACCRIGHTS
struct msghdr msghdr;
msghdr.msg_accrights = (void *)&pass_fd;
msghdr.msg_accrightslen = sizeof(int);
msghdr.msg_accrights = (void *)&client->pass_fd;
msghdr.msg_accrightslen = sizeof(client->pass_fd);
#else /* HAVE_MSGHDR_ACCRIGHTS */
struct msghdr msghdr;
struct cmsg_fd cmsg;
@ -179,109 +137,57 @@ static void do_read( struct client *client, int client_fd )
msghdr.msg_flags = 0;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
assert( client->pass_fd == -1 );
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
if (client->count < sizeof(client->head))
vec.iov_base = &seq;
vec.iov_len = sizeof(seq);
ret = recvmsg( client->select.fd, &msghdr, 0 );
#ifndef HAVE_MSGHDR_ACCRIGHTS
client->pass_fd = cmsg.fd;
#endif
if (ret == sizeof(seq))
{
vec.iov_base = (char *)&client->head + client->count;
vec.iov_len = sizeof(client->head) - client->count;
}
else
{
if (!client->data &&
!(client->data = malloc(client->head.len-sizeof(client->head))))
int pass_fd = client->pass_fd;
if (seq != client->seq++)
{
remove_client( client, OUT_OF_MEMORY );
protocol_error( client, "bad sequence %08x instead of %08x\n",
seq, client->seq - 1 );
return;
}
vec.iov_base = client->data + client->count - sizeof(client->head);
vec.iov_len = client->head.len - client->count;
client->pass_fd = -1;
call_req_handler( client->self, pass_fd );
if (pass_fd != -1) close( pass_fd );
return;
}
ret = recvmsg( client_fd, &msghdr, 0 );
if (ret == -1)
{
perror("recvmsg");
remove_client( client, BROKEN_PIPE );
return;
}
#ifndef HAVE_MSGHDR_ACCRIGHTS
pass_fd = cmsg.fd;
#endif
if (pass_fd != -1)
{
/* can only receive one fd per message */
if (client->pass_fd != -1) close( client->pass_fd );
client->pass_fd = pass_fd;
}
else if (!ret) /* closed pipe */
if (!ret) /* closed pipe */
{
remove_client( client, BROKEN_PIPE );
return;
}
if (client->state == RUNNING) client->state = SENDING;
assert( client->state == SENDING );
client->count += ret;
/* received the complete header yet? */
if (client->count < sizeof(client->head)) return;
/* sanity checks */
if (client->head.seq != client->seq)
{
protocol_error( client, "bad sequence %08x instead of %08x\n",
client->head.seq, client->seq );
remove_client( client, PROTOCOL_ERROR );
return;
}
if ((client->head.len < sizeof(client->head)) ||
(client->head.len > MAX_MSG_LENGTH + sizeof(client->head)))
{
protocol_error( client, "bad header length %08x\n",
client->head.len );
remove_client( client, PROTOCOL_ERROR );
return;
}
/* received the whole message? */
if (client->count == client->head.len)
{
/* done reading the data, call the callback function */
int len = client->head.len - sizeof(client->head);
char *data = client->data;
int passed_fd = client->pass_fd;
enum request type = client->head.type;
/* clear the info now, as the client may be deleted by the callback */
client->head.len = 0;
client->head.type = 0;
client->count = 0;
client->data = NULL;
client->pass_fd = -1;
client->state = WAITING;
client->seq++;
call_req_handler( client->self, type, data, len, passed_fd );
if (passed_fd != -1) close( passed_fd );
if (data) free( data );
}
protocol_error( client, "partial sequence received %d/%d\n", ret, sizeof(seq) );
}
/* handle a client event */
static void client_event( int event, void *private )
{
struct client *client = (struct client *)private;
if (event & WRITE_EVENT) do_write( client, client->select.fd );
if (event & READ_EVENT) do_read( client, client->select.fd );
if (event & WRITE_EVENT) do_write( client );
if (event & READ_EVENT) do_read( client );
}
/*******************************************************************/
/* server-side exported functions */
@ -295,15 +201,10 @@ struct client *add_client( int fd, struct thread *self )
flags = fcntl( fd, F_GETFL, 0 );
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
client->state = RUNNING;
client->select.fd = fd;
client->select.func = client_event;
client->select.private = client;
client->seq = 0;
client->head.len = 0;
client->head.type = 0;
client->count = 0;
client->data = NULL;
client->self = self;
client->timeout = NULL;
client->pass_fd = -1;
@ -324,42 +225,20 @@ void remove_client( struct client *client, int exit_code )
close( client->select.fd );
/* Purge messages */
if (client->data) free( client->data );
if (client->pass_fd != -1) close( client->pass_fd );
free( client );
}
/* send a reply to a client */
int send_reply_v( struct client *client, int type, int pass_fd,
struct iovec *vec, int veclen )
/* set the fd to pass to the client */
void client_pass_fd( struct client *client, int pass_fd )
{
int i;
unsigned int len;
char *p;
assert( client );
assert( client->state == WAITING );
assert( !client->data );
if (debug_level) trace_reply( client->self, type, pass_fd, vec, veclen );
for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
assert( len < MAX_MSG_LENGTH );
if (len && !(client->data = malloc( len ))) return -1;
client->count = 0;
client->head.len = len + sizeof(client->head);
client->head.type = type;
client->head.seq = client->seq;
client->pass_fd = pass_fd;
for (i = 0, p = client->data; i < veclen; i++)
{
memcpy( p, vec[i].iov_base, vec[i].iov_len );
p += vec[i].iov_len;
}
client->state = READING;
set_select_events( &client->select, WRITE_EVENT );
return 0;
assert( client->pass_fd == -1 );
client->pass_fd = pass_fd;
}
/* send a reply to a client */
void client_reply( struct client *client )
{
if (debug_level) trace_reply( client->self, client->pass_fd );
set_select_events( &client->select, WRITE_EVENT );
}

View File

@ -10,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
@ -20,9 +21,9 @@
#include "winerror.h"
#include "handle.h"
#include "server.h"
#include "process.h"
#include "thread.h"
#include "request.h"
/* thread queues */
@ -62,6 +63,7 @@ static void destroy_thread( struct object *obj );
static const struct object_ops thread_ops =
{
sizeof(struct thread),
dump_thread,
add_queue,
remove_queue,
@ -76,10 +78,32 @@ static const struct object_ops thread_ops =
static struct thread *first_thread;
/* initialization of a thread structure */
static void init_thread( struct thread *thread, int fd )
/* allocate the buffer for the communication with the client */
static int alloc_client_buffer( struct thread *thread )
{
init_object( &thread->obj, &thread_ops, NULL );
int fd;
if ((fd = create_anonymous_file()) == -1) return -1;
if (ftruncate( fd, MAX_MSG_LENGTH ) == -1) goto error;
if ((thread->buffer = mmap( 0, MAX_MSG_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0 )) == (void*)-1) goto error;
thread->req_pos = thread->reply_pos = thread->buffer;
return fd;
error:
file_set_error();
if (fd != -1) close( fd );
return -1;
}
/* create a new thread */
static struct thread *create_thread( int fd, struct process *process, int suspend )
{
struct thread *thread;
int buf_fd;
if (!(thread = alloc_object( &thread_ops ))) return NULL;
thread->client = NULL;
thread->unix_pid = 0; /* not known yet */
thread->teb = NULL;
@ -97,61 +121,46 @@ static void init_thread( struct thread *thread, int fd )
thread->prev = NULL;
thread->priority = THREAD_PRIORITY_NORMAL;
thread->affinity = 1;
thread->suspend = 0;
}
thread->suspend = (suspend != 0);
thread->buffer = (void *)-1;
thread->last_req = 0;
/* create the initial thread and start the main server loop */
void create_initial_thread( int fd )
{
first_thread = mem_alloc( sizeof(*first_thread) );
assert( first_thread );
current = first_thread;
init_thread( first_thread, fd );
first_thread->process = create_initial_process();
add_process_thread( first_thread->process, first_thread );
first_thread->client = add_client( fd, first_thread );
select_loop();
}
/* create a new thread */
static struct thread *create_thread( int fd, void *pid, int suspend, int inherit, int *handle )
{
struct thread *thread;
struct process *process;
if (!(thread = mem_alloc( sizeof(*thread) ))) return NULL;
if (!(process = get_process_from_id( pid )))
if (!first_thread) /* creating the first thread */
{
free( thread );
return NULL;
current = thread;
thread->process = process = create_initial_process();
assert( process );
}
init_thread( thread, fd );
thread->process = process;
if (suspend) thread->suspend++;
else thread->process = (struct process *)grab_object( process );
if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
first_thread = thread;
add_process_thread( process, thread );
if ((*handle = alloc_handle( current->process, thread,
THREAD_ALL_ACCESS, inherit )) == -1) goto error;
if ((buf_fd = alloc_client_buffer( thread )) == -1) goto error;
if (!(thread->client = add_client( fd, thread )))
{
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
close( buf_fd );
goto error;
}
push_reply_data( thread, sizeof(struct header) );
set_reply_fd( thread, buf_fd ); /* send the fd to the client */
send_reply( thread );
return thread;
error:
close_handle( current->process, *handle );
remove_process_thread( process, thread );
release_object( thread );
return NULL;
}
/* create the initial thread and start the main server loop */
void create_initial_thread( int fd )
{
create_thread( fd, NULL, 0 );
select_loop();
}
/* destroy a thread when its refcount is 0 */
static void destroy_thread( struct object *obj )
{
@ -164,8 +173,7 @@ static void destroy_thread( struct object *obj )
if (thread->prev) thread->prev->next = thread->next;
else first_thread = thread->next;
if (thread->apc) free( thread->apc );
if (debug_level) memset( thread, 0xaa, sizeof(thread) ); /* catch errors */
free( thread );
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_MSG_LENGTH );
}
/* dump a thread on stdout for debugging purposes */
@ -208,7 +216,7 @@ static void set_thread_info( struct thread *thread,
thread->priority = req->priority;
if (req->mask & SET_THREAD_INFO_AFFINITY)
{
if (req->affinity != 1) SET_ERROR( ERROR_INVALID_PARAMETER );
if (req->affinity != 1) set_error( ERROR_INVALID_PARAMETER );
else thread->affinity = req->affinity;
}
}
@ -259,25 +267,6 @@ void resume_all_threads( void )
resume_thread( thread );
}
/* send a reply to a thread */
int send_reply( struct thread *thread, int pass_fd, int n,
... /* arg_1, len_1, ..., arg_n, len_n */ )
{
struct iovec vec[16];
va_list args;
int i;
assert( n < 16 );
va_start( args, n );
for (i = 0; i < n; i++)
{
vec[i].iov_base = va_arg( args, void * );
vec[i].iov_len = va_arg( args, int );
}
va_end( args );
return send_reply_v( thread->client, thread->error, pass_fd, vec, n );
}
/* add a thread to an object wait queue; return 1 if OK, 0 on error */
int add_queue( struct object *obj, struct wait_queue_entry *entry )
{
@ -327,7 +316,7 @@ static int wait_on( struct thread *thread, int count,
if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS))
{
SET_ERROR( ERROR_INVALID_PARAMETER );
set_error( ERROR_INVALID_PARAMETER );
return 0;
}
if (!(wait = mem_alloc( sizeof(*wait) + (count-1) * sizeof(*entry) ))) return 0;
@ -415,22 +404,18 @@ static int check_wait( struct thread *thread, int *signaled )
return 0;
}
/* send the select reply to wake up the client */
static void send_select_reply( struct thread *thread, int signaled )
/* build a select reply to wake up the client */
static void build_select_reply( struct thread *thread, int signaled )
{
struct select_reply reply;
reply.signaled = signaled;
struct select_reply *reply = push_reply_data( thread, sizeof(*reply) );
reply->signaled = signaled;
if ((signaled == STATUS_USER_APC) && thread->apc)
{
struct thread_apc *apc = thread->apc;
int len = thread->apc_count * sizeof(*apc);
add_reply_data( thread, thread->apc, thread->apc_count * sizeof(*thread->apc) );
free( thread->apc );
thread->apc = NULL;
thread->apc_count = 0;
send_reply( thread, -1, 2, &reply, sizeof(reply),
apc, len );
free( apc );
}
else send_reply( thread, -1, 1, &reply, sizeof(reply) );
}
/* attempt to wake up a thread */
@ -441,7 +426,7 @@ static int wake_thread( struct thread *thread )
if (!check_wait( thread, &signaled )) return 0;
end_wait( thread );
send_select_reply( thread, signaled );
build_select_reply( thread, signaled );
return 1;
}
@ -451,8 +436,7 @@ static void sleep_on( struct thread *thread, int count, int *handles, int flags,
assert( !thread->wait );
if (!wait_on( thread, count, handles, flags, timeout ))
{
/* return an error */
send_select_reply( thread, -1 );
build_select_reply( thread, -1 );
return;
}
if (wake_thread( thread )) return;
@ -462,9 +446,11 @@ static void sleep_on( struct thread *thread, int count, int *handles, int flags,
if (!(thread->wait->user = add_timeout_user( &thread->wait->timeout,
call_timeout_handler, thread )))
{
send_select_reply( thread, -1 );
build_select_reply( thread, -1 );
return;
}
}
thread->state = SLEEPING;
}
/* timeout for the current thread */
@ -473,7 +459,8 @@ void thread_timeout(void)
assert( current->wait );
current->wait->user = NULL;
end_wait( current );
send_select_reply( current, STATUS_TIMEOUT );
build_select_reply( current, STATUS_TIMEOUT );
send_reply( current );
}
/* attempt to wake threads sleeping on the object wait queue */
@ -483,12 +470,13 @@ void wake_up( struct object *obj, int max )
while (entry)
{
struct wait_queue_entry *next = entry->next;
if (wake_thread( entry->thread ))
struct thread *thread = entry->thread;
entry = entry->next;
if (wake_thread( thread ))
{
send_reply( thread );
if (max && !--max) break;
}
entry = next;
}
}
@ -506,7 +494,10 @@ static int thread_queue_apc( struct thread *thread, void *func, void *param )
thread->apc[thread->apc_count].func = func;
thread->apc[thread->apc_count].param = param;
thread->apc_count++;
if (thread->wait) wake_thread( thread );
if (thread->wait)
{
if (wake_thread( thread )) send_reply( thread );
}
return 1;
}
@ -535,24 +526,34 @@ void thread_killed( struct thread *thread, int exit_code )
DECL_HANDLER(new_thread)
{
struct new_thread_reply reply;
struct thread *thread;
struct process *process;
int new_fd;
if ((new_fd = dup(fd)) != -1)
if ((process = get_process_from_id( req->pid )))
{
reply.tid = create_thread( new_fd, req->pid, req->suspend,
req->inherit, &reply.handle );
if (!reply.tid) close( new_fd );
if ((new_fd = dup(fd)) != -1)
{
if ((thread = create_thread( new_fd, process, req->suspend )))
{
reply.tid = thread;
reply.handle = alloc_handle( current->process, thread,
THREAD_ALL_ACCESS, req->inherit );
if (reply.handle == -1) release_object( thread );
/* else will be released when the thread gets killed */
}
else close( new_fd );
}
else set_error( ERROR_TOO_MANY_OPEN_FILES );
release_object( process );
}
else
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
send_reply( current, -1, 1, &reply, sizeof(reply) );
add_reply_data( current, &reply, sizeof(reply) );
}
/* initialize a new thread */
DECL_HANDLER(init_thread)
{
struct init_thread_reply reply;
struct init_thread_reply *reply = push_reply_data( current, sizeof(*reply) );
if (current->state != STARTING)
{
@ -564,9 +565,8 @@ DECL_HANDLER(init_thread)
current->teb = req->teb;
if (current->suspend + current->process->suspend > 0)
kill( current->unix_pid, SIGSTOP );
reply.pid = current->process;
reply.tid = current;
send_reply( current, -1, 1, &reply, sizeof(reply) );
reply->pid = current->process;
reply->tid = current;
}
/* terminate a thread */
@ -579,23 +579,21 @@ DECL_HANDLER(terminate_thread)
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 };
struct get_thread_info_reply *reply = push_reply_data( current, sizeof(*reply) );
if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
{
reply.tid = thread;
reply.exit_code = thread->exit_code;
reply.priority = thread->priority;
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 */
@ -608,44 +606,41 @@ DECL_HANDLER(set_thread_info)
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 };
struct suspend_thread_reply *reply = push_reply_data( current, sizeof(*reply) );
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
{
reply.count = suspend_thread( thread );
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 };
struct resume_thread_reply *reply = push_reply_data( current, sizeof(*reply) );
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
{
reply.count = resume_thread( thread );
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 );
if (check_req_data( req->count * sizeof(int) ))
{
sleep_on( current, req->count, get_req_data( req->count * sizeof(int) ),
req->flags, req->timeout );
}
else fatal_protocol_error( "select: bad length" );
}
/* queue an APC for a thread */
@ -657,5 +652,4 @@ DECL_HANDLER(queue_apc)
thread_queue_apc( thread, req->func, req->param );
release_object( thread );
}
send_reply( current, -1, 0 );
}

View File

@ -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 */

View File

@ -1,10 +1,13 @@
/* 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 );

View File

@ -1,6 +1,6 @@
#! /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";
push @trace_lines, " \"$req\",\n";
}
push @trace_lines, "};\n";
### Output the tracing functions
REPLACE_IN_FILE( "server/trace.c", @trace_lines );
print TRACE <<EOF;
};
### Replace the request list in server.h by the new values
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" );
}
my @server_lines = ();
void trace_timeout(void)
{
fprintf( stderr, "%08x: *timeout*\\n", (unsigned int)current );
}
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";
void trace_kill( int exit_code )
{
fprintf( stderr,"%08x: *killed* exit_code=%d\\n",
(unsigned int)current, exit_code );
}
REPLACE_IN_FILE( "include/server.h", @server_lines );
void trace_reply( struct thread *thread, int type, int pass_fd,
struct iovec *vec, int veclen )
{
static unsigned char buffer[MAX_MSG_LENGTH];
### Output the request handlers list
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
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 " REQ_\U$req,\n";
push @request_lines, " { (void(*)())req_$req, sizeof(struct ${req}_request) },\n";
}
push @request_lines, "};\n#endif /* WANT_REQUEST_HANDLERS */\n";
print REQUESTS <<EOF;
REQ_NB_REQUESTS
};
#ifdef WANT_REQUEST_HANDLERS
EOF
foreach $req (@requests) { print REQUESTS "DECL_HANDLER($req);\n"; }
print REQUESTS <<EOF;
static const struct handler {
void (*handler)();
unsigned int min_size;
} req_handlers[REQ_NB_REQUESTS] = {
EOF
foreach $req (@requests)
{
print REQUESTS " { (void(*)())req_$req, sizeof(struct ${req}_request) },\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);
}

View 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;
}