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:
parent
0a860a01f9
commit
5bc78089db
|
@ -43,7 +43,6 @@
|
||||||
#include "wincon.h"
|
#include "wincon.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
DEFAULT_DEBUG_CHANNEL(file)
|
DEFAULT_DEBUG_CHANNEL(file)
|
||||||
|
|
104
include/server.h
104
include/server.h
|
@ -15,11 +15,10 @@ struct header
|
||||||
{
|
{
|
||||||
unsigned int len; /* total msg length (including this header) */
|
unsigned int len; /* total msg length (including this header) */
|
||||||
unsigned int type; /* msg type */
|
unsigned int type; /* msg type */
|
||||||
unsigned int seq; /* sequence number */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* max msg length (not including the header) */
|
/* max msg length (including the header) */
|
||||||
#define MAX_MSG_LENGTH (16384 - sizeof(struct header))
|
#define MAX_MSG_LENGTH 16384
|
||||||
|
|
||||||
/* data structure used to pass an fd with sendmsg/recvmsg */
|
/* data structure used to pass an fd with sendmsg/recvmsg */
|
||||||
struct cmsg_fd
|
struct cmsg_fd
|
||||||
|
@ -30,10 +29,6 @@ struct cmsg_fd
|
||||||
int fd; /* fd to pass */
|
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 */
|
/* Request structures */
|
||||||
|
|
||||||
/* following are the definitions of all the client<->server */
|
/* following are the definitions of all the client<->server */
|
||||||
|
@ -855,13 +850,104 @@ struct debug_process_request
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* requests definitions */
|
/* Everything below this line is generated automatically by tools/make_requests */
|
||||||
#include "server/request.h"
|
/* ### 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 */
|
/* client-side functions */
|
||||||
|
|
||||||
#ifndef __WINE_SERVER__
|
#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 */
|
/* client communication functions */
|
||||||
extern void CLIENT_ProtocolError( const char *err, ... );
|
extern void CLIENT_ProtocolError( const char *err, ... );
|
||||||
extern void CLIENT_SendRequest( enum request req, int pass_fd,
|
extern void CLIENT_SendRequest( enum request req, int pass_fd,
|
||||||
|
|
|
@ -34,13 +34,13 @@ typedef struct _TEB
|
||||||
WORD pad1; /* 2a */
|
WORD pad1; /* 2a */
|
||||||
LPVOID *tls_ptr; /* 2c Pointer to TLS array */
|
LPVOID *tls_ptr; /* 2c Pointer to TLS array */
|
||||||
struct _PDB *process; /* 30 owning process (used by NT3.51 applets)*/
|
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 */
|
DWORD exit_code; /* 38 Termination status */
|
||||||
WORD teb_sel; /* 3c Selector to TEB */
|
WORD teb_sel; /* 3c Selector to TEB */
|
||||||
WORD emu_sel; /* 3e 80387 emulator selector */
|
WORD emu_sel; /* 3e 80387 emulator selector */
|
||||||
void *buffer_args; /* 40 Current position of arguments in server buffer */
|
void *buffer; /* 40 Buffer shared with server */
|
||||||
void *buffer_res; /* 44 Current position of result in server buffer */
|
void *buffer_args; /* 44 Current position of arguments in server buffer */
|
||||||
void *buffer_end; /* 48 End of server buffer */
|
int buffer_size; /* 48 Size of server buffer */
|
||||||
int thread_errno; /* 4c Per-thread errno (was: ring0_thread) */
|
int thread_errno; /* 4c Per-thread errno (was: ring0_thread) */
|
||||||
int thread_h_errno; /* 50 Per-thread h_errno (was: ptr to tdbx structure) */
|
int thread_h_errno; /* 50 Per-thread h_errno (was: ptr to tdbx structure) */
|
||||||
void *stack_base; /* 54 Base of the stack */
|
void *stack_base; /* 54 Base of the stack */
|
||||||
|
@ -69,7 +69,6 @@ typedef struct _TEB
|
||||||
SYSLEVEL *sys_mutex[4]; /* 1d8 Syslevel mutex pointers */
|
SYSLEVEL *sys_mutex[4]; /* 1d8 Syslevel mutex pointers */
|
||||||
DWORD unknown6[2]; /* 1e8 Unknown */
|
DWORD unknown6[2]; /* 1e8 Unknown */
|
||||||
/* The following are Wine-specific fields */
|
/* The following are Wine-specific fields */
|
||||||
int socket; /* Socket for server communication */
|
|
||||||
unsigned int seq; /* Server sequence number */
|
unsigned int seq; /* Server sequence number */
|
||||||
void (*startup)(void); /* Thread startup routine */
|
void (*startup)(void); /* Thread startup routine */
|
||||||
struct _TEB *next; /* Global thread list */
|
struct _TEB *next; /* Global thread list */
|
||||||
|
|
|
@ -1074,6 +1074,7 @@ HANDLE WINAPI CreateFileMappingA(
|
||||||
|
|
||||||
/* Create the server object */
|
/* Create the server object */
|
||||||
|
|
||||||
|
if (!name) name = "";
|
||||||
req.handle = hFile;
|
req.handle = hFile;
|
||||||
req.size_high = size_high;
|
req.size_high = size_high;
|
||||||
req.size_low = size_low;
|
req.size_low = size_low;
|
||||||
|
@ -1081,7 +1082,7 @@ HANDLE WINAPI CreateFileMappingA(
|
||||||
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
||||||
CLIENT_SendRequest( REQ_CREATE_MAPPING, -1, 2,
|
CLIENT_SendRequest( REQ_CREATE_MAPPING, -1, 2,
|
||||||
&req, sizeof(req),
|
&req, sizeof(req),
|
||||||
name, name ? strlen(name) + 1 : 0 );
|
name, strlen(name) + 1 );
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
||||||
if (reply.handle == -1) return 0;
|
if (reply.handle == -1) return 0;
|
||||||
|
|
|
@ -61,7 +61,6 @@
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "winerror.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.
|
* Send a request to the server.
|
||||||
*/
|
*/
|
||||||
static void CLIENT_SendRequest_v( enum request req, int pass_fd,
|
static void send_request( enum request req )
|
||||||
struct iovec *vec, int veclen )
|
|
||||||
{
|
{
|
||||||
|
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
|
#ifndef HAVE_MSGHDR_ACCRIGHTS
|
||||||
struct cmsg_fd cmsg;
|
struct cmsg_fd cmsg;
|
||||||
#endif
|
#endif
|
||||||
struct msghdr msghdr;
|
struct msghdr msghdr;
|
||||||
struct header head;
|
struct iovec vec;
|
||||||
int i, ret, len;
|
|
||||||
|
|
||||||
assert( veclen > 0 );
|
assert( server_remaining() >= 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( len <= MAX_MSG_LENGTH );
|
head->type = req;
|
||||||
head.type = req;
|
head->len = (char *)NtCurrentTeb()->buffer_args - (char *)NtCurrentTeb()->buffer;
|
||||||
head.len = len;
|
|
||||||
head.seq = NtCurrentTeb()->seq++;
|
NtCurrentTeb()->buffer_args = head + 1; /* reset the args buffer */
|
||||||
|
|
||||||
|
vec.iov_base = &seq;
|
||||||
|
vec.iov_len = sizeof(seq);
|
||||||
|
|
||||||
msghdr.msg_name = NULL;
|
msghdr.msg_name = NULL;
|
||||||
msghdr.msg_namelen = 0;
|
msghdr.msg_namelen = 0;
|
||||||
msghdr.msg_iov = vec;
|
msghdr.msg_iov = &vec;
|
||||||
msghdr.msg_iovlen = veclen;
|
msghdr.msg_iovlen = 1;
|
||||||
|
|
||||||
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
||||||
if (pass_fd != -1) /* we have an fd to send */
|
msghdr.msg_accrights = (void *)&fd;
|
||||||
{
|
msghdr.msg_accrightslen = sizeof(fd);
|
||||||
msghdr.msg_accrights = (void *)&pass_fd;
|
|
||||||
msghdr.msg_accrightslen = sizeof(pass_fd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msghdr.msg_accrights = NULL;
|
|
||||||
msghdr.msg_accrightslen = 0;
|
|
||||||
}
|
|
||||||
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
if (pass_fd != -1) /* we have an fd to send */
|
cmsg.len = sizeof(cmsg);
|
||||||
{
|
cmsg.level = SOL_SOCKET;
|
||||||
cmsg.len = sizeof(cmsg);
|
cmsg.type = SCM_RIGHTS;
|
||||||
cmsg.level = SOL_SOCKET;
|
cmsg.fd = fd;
|
||||||
cmsg.type = SCM_RIGHTS;
|
msghdr.msg_control = &cmsg;
|
||||||
cmsg.fd = pass_fd;
|
msghdr.msg_controllen = sizeof(cmsg);
|
||||||
msghdr.msg_control = &cmsg;
|
msghdr.msg_flags = 0;
|
||||||
msghdr.msg_controllen = sizeof(cmsg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msghdr.msg_control = NULL;
|
|
||||||
msghdr.msg_controllen = 0;
|
|
||||||
}
|
|
||||||
msghdr.msg_flags = 0;
|
|
||||||
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
#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();
|
||||||
{
|
CLIENT_perror( "sendmsg" );
|
||||||
if (errno == EPIPE) CLIENT_Die();
|
|
||||||
perror( "sendmsg" );
|
|
||||||
}
|
|
||||||
CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret, len );
|
|
||||||
}
|
}
|
||||||
/* we passed the fd now we can close it */
|
CLIENT_ProtocolError( "partial seq sent %d/%d\n", ret, sizeof(seq) );
|
||||||
if (pass_fd != -1) close( pass_fd );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* CLIENT_SendRequest
|
* wait_reply
|
||||||
*
|
|
||||||
* 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 for a reply from the server.
|
* 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,
|
static void wait_reply(void)
|
||||||
struct iovec *vec, int veclen )
|
|
||||||
{
|
{
|
||||||
int pass_fd = -1;
|
int seq, ret;
|
||||||
struct header head;
|
|
||||||
int ret, remaining;
|
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
|
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
||||||
struct msghdr msghdr;
|
struct msghdr msghdr;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
msghdr.msg_accrights = (void *)&pass_fd;
|
msghdr.msg_accrights = (void *)&fd;
|
||||||
msghdr.msg_accrightslen = sizeof(int);
|
msghdr.msg_accrightslen = sizeof(int);
|
||||||
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
struct msghdr msghdr;
|
struct msghdr msghdr;
|
||||||
|
@ -184,88 +203,136 @@ static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
|
||||||
|
|
||||||
msghdr.msg_name = NULL;
|
msghdr.msg_name = NULL;
|
||||||
msghdr.msg_namelen = 0;
|
msghdr.msg_namelen = 0;
|
||||||
msghdr.msg_iov = vec;
|
msghdr.msg_iov = &vec;
|
||||||
msghdr.msg_iovlen = veclen;
|
msghdr.msg_iovlen = 1;
|
||||||
|
vec.iov_base = &seq;
|
||||||
|
vec.iov_len = sizeof(seq);
|
||||||
|
|
||||||
assert( veclen > 0 );
|
for (;;)
|
||||||
vec[0].iov_base = &head;
|
|
||||||
vec[0].iov_len = sizeof(head);
|
|
||||||
|
|
||||||
while ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == -1)
|
|
||||||
{
|
{
|
||||||
if (errno == EINTR) continue;
|
if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(seq))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
perror( "recv" );
|
if (seq != NtCurrentTeb()->seq++)
|
||||||
CLIENT_ProtocolError( "recv\n" );
|
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... */
|
if (ret == -1)
|
||||||
remaining -= addlen;
|
{
|
||||||
|
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;
|
va_list args;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
n++; /* for vec[0] */
|
|
||||||
assert( n < 16 );
|
assert( n < 16 );
|
||||||
va_start( args, n );
|
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_base = va_arg( args, void * );
|
||||||
vec[i].iov_len = va_arg( args, int );
|
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 )
|
unsigned int CLIENT_WaitSimpleReply( void *reply, int len, int *passed_fd )
|
||||||
{
|
{
|
||||||
struct iovec vec[2];
|
struct iovec vec;
|
||||||
unsigned int ret;
|
unsigned int ret;
|
||||||
int got;
|
int got;
|
||||||
|
|
||||||
vec[1].iov_base = reply;
|
vec.iov_base = reply;
|
||||||
vec[1].iov_len = len;
|
vec.iov_len = len;
|
||||||
ret = CLIENT_WaitReply_v( &got, passed_fd, vec, 2 );
|
ret = CLIENT_WaitReply_v( &got, passed_fd, &vec, 1 );
|
||||||
if (got != len)
|
if (got != len)
|
||||||
CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len, got );
|
CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len, got );
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -363,13 +429,22 @@ int CLIENT_InitThread(void)
|
||||||
{
|
{
|
||||||
struct init_thread_request req;
|
struct init_thread_request req;
|
||||||
struct init_thread_reply reply;
|
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.unix_pid = getpid();
|
||||||
req.teb = NtCurrentTeb();
|
req.teb = teb;
|
||||||
CLIENT_SendRequest( REQ_INIT_THREAD, -1, 1, &req, sizeof(req) );
|
CLIENT_SendRequest( REQ_INIT_THREAD, -1, 1, &req, sizeof(req) );
|
||||||
if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return -1;
|
if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return -1;
|
||||||
NtCurrentTeb()->process->server_pid = reply.pid;
|
teb->process->server_pid = reply.pid;
|
||||||
NtCurrentTeb()->tid = reply.tid;
|
teb->tid = reply.tid;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "debugtools.h"
|
#include "debugtools.h"
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "syslevel.h"
|
#include "syslevel.h"
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.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_request req;
|
||||||
struct create_event_reply reply;
|
struct create_event_reply reply;
|
||||||
int len = name ? strlen(name) + 1 : 0;
|
|
||||||
|
|
||||||
|
if (!name) name = "";
|
||||||
req.manual_reset = manual_reset;
|
req.manual_reset = manual_reset;
|
||||||
req.initial_state = initial_state;
|
req.initial_state = initial_state;
|
||||||
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
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);
|
SetLastError(0);
|
||||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
||||||
if (reply.handle == -1) return 0;
|
if (reply.handle == -1) return 0;
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.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_request req;
|
||||||
struct create_mutex_reply reply;
|
struct create_mutex_reply reply;
|
||||||
int len = name ? strlen(name) + 1 : 0;
|
|
||||||
|
|
||||||
|
if (!name) name = "";
|
||||||
req.owned = owner;
|
req.owned = owner;
|
||||||
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
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);
|
SetLastError(0);
|
||||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
||||||
if (reply.handle == -1) return 0;
|
if (reply.handle == -1) return 0;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,19 +8,16 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* CreateSemaphore32A (KERNEL32.174)
|
* CreateSemaphore32A (KERNEL32.174)
|
||||||
*/
|
*/
|
||||||
HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial,
|
HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial, LONG max, LPCSTR name )
|
||||||
LONG max, LPCSTR name )
|
|
||||||
{
|
{
|
||||||
struct create_semaphore_request req;
|
struct create_semaphore_request req;
|
||||||
struct create_semaphore_reply reply;
|
struct create_semaphore_reply reply;
|
||||||
int len = name ? strlen(name) + 1 : 0;
|
|
||||||
|
|
||||||
/* Check parameters */
|
/* Check parameters */
|
||||||
|
|
||||||
|
@ -30,11 +27,12 @@ HANDLE WINAPI CreateSemaphoreA( SECURITY_ATTRIBUTES *sa, LONG initial,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!name) name = "";
|
||||||
req.initial = (unsigned int)initial;
|
req.initial = (unsigned int)initial;
|
||||||
req.max = (unsigned int)max;
|
req.max = (unsigned int)max;
|
||||||
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
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);
|
SetLastError(0);
|
||||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
||||||
if (reply.handle == -1) return 0;
|
if (reply.handle == -1) return 0;
|
||||||
|
|
|
@ -154,8 +154,7 @@ void CALLBACK THREAD_FreeTEB( ULONG_PTR arg )
|
||||||
if (teb->stack_sel) SELECTOR_FreeBlock( teb->stack_sel, 1 );
|
if (teb->stack_sel) SELECTOR_FreeBlock( teb->stack_sel, 1 );
|
||||||
SELECTOR_FreeBlock( teb->teb_sel, 1 );
|
SELECTOR_FreeBlock( teb->teb_sel, 1 );
|
||||||
close( teb->socket );
|
close( teb->socket );
|
||||||
if (teb->buffer)
|
if (teb->buffer) munmap( teb->buffer, teb->buffer_size );
|
||||||
munmap( teb->buffer, (char *)teb->buffer_end - (char *)teb->buffer );
|
|
||||||
VirtualFree( teb->stack_base, 0, MEM_RELEASE );
|
VirtualFree( teb->stack_base, 0, MEM_RELEASE );
|
||||||
HeapFree( SystemHeap, 0, teb );
|
HeapFree( SystemHeap, 0, teb );
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct change
|
struct change
|
||||||
{
|
{
|
||||||
|
@ -23,10 +24,10 @@ struct change
|
||||||
|
|
||||||
static void change_dump( struct object *obj, int verbose );
|
static void change_dump( struct object *obj, int verbose );
|
||||||
static int change_signaled( struct object *obj, struct thread *thread );
|
static int change_signaled( struct object *obj, struct thread *thread );
|
||||||
static void change_destroy( struct object *obj );
|
|
||||||
|
|
||||||
static const struct object_ops change_ops =
|
static const struct object_ops change_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct change),
|
||||||
change_dump,
|
change_dump,
|
||||||
add_queue,
|
add_queue,
|
||||||
remove_queue,
|
remove_queue,
|
||||||
|
@ -36,15 +37,14 @@ static const struct object_ops change_ops =
|
||||||
no_write_fd,
|
no_write_fd,
|
||||||
no_flush,
|
no_flush,
|
||||||
no_get_file_info,
|
no_get_file_info,
|
||||||
change_destroy
|
no_destroy
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct object *create_change_notification( int subtree, int filter )
|
static struct object *create_change_notification( int subtree, int filter )
|
||||||
{
|
{
|
||||||
struct change *change;
|
struct change *change;
|
||||||
if (!(change = mem_alloc( sizeof(*change) ))) return NULL;
|
if (!(change = alloc_object( &change_ops ))) return NULL;
|
||||||
init_object( &change->obj, &change_ops, NULL );
|
|
||||||
change->subtree = subtree;
|
change->subtree = subtree;
|
||||||
change->filter = filter;
|
change->filter = filter;
|
||||||
return &change->obj;
|
return &change->obj;
|
||||||
|
@ -65,24 +65,16 @@ static int change_signaled( struct object *obj, struct thread *thread )
|
||||||
return 0; /* never signaled for now */
|
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 */
|
/* create a change notification */
|
||||||
DECL_HANDLER(create_change_notification)
|
DECL_HANDLER(create_change_notification)
|
||||||
{
|
{
|
||||||
struct object *obj;
|
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 )))
|
if ((obj = create_change_notification( req->subtree, req->filter )))
|
||||||
{
|
{
|
||||||
reply.handle = alloc_handle( current->process, obj,
|
reply->handle = alloc_handle( current->process, obj,
|
||||||
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
|
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, 0 );
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
191
server/console.c
191
server/console.c
|
@ -27,6 +27,7 @@
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct screen_buffer;
|
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 =
|
static const struct object_ops console_input_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct console_input),
|
||||||
console_input_dump,
|
console_input_dump,
|
||||||
console_input_add_queue,
|
console_input_add_queue,
|
||||||
console_input_remove_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 =
|
static const struct object_ops screen_buffer_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct screen_buffer),
|
||||||
screen_buffer_dump,
|
screen_buffer_dump,
|
||||||
screen_buffer_add_queue,
|
screen_buffer_add_queue,
|
||||||
screen_buffer_remove_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 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();
|
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();
|
file_set_error();
|
||||||
close( read_fd );
|
return NULL;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (!(console_input = mem_alloc( sizeof(struct console_input) )))
|
if ((screen_buffer = alloc_object( &screen_buffer_ops )))
|
||||||
{
|
{
|
||||||
close( read_fd );
|
screen_buffer->select.fd = fd;
|
||||||
close( write_fd );
|
screen_buffer->select.func = default_select_event;
|
||||||
return 0;
|
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( fd );
|
||||||
{
|
return NULL;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate a console for this process */
|
/* allocate a console for this process */
|
||||||
int alloc_console( struct process *process )
|
int alloc_console( struct process *process )
|
||||||
{
|
{
|
||||||
struct object *obj[2];
|
|
||||||
if (process->console_in || process->console_out)
|
if (process->console_in || process->console_out)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
set_error( ERROR_ACCESS_DENIED );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!create_console( -1, obj )) return 0;
|
if ((process->console_in = create_console_input( -1 )))
|
||||||
process->console_in = obj[0];
|
{
|
||||||
process->console_out = obj[1];
|
if ((process->console_out = create_console_output( -1, process->console_in )))
|
||||||
return 1;
|
return 1;
|
||||||
|
release_object( process->console_in );
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free the console for this process */
|
/* free the console for this process */
|
||||||
|
@ -203,7 +206,7 @@ static int set_console_fd( int handle, int fd, int pid )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
set_error( ERROR_INVALID_HANDLE );
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -258,7 +261,7 @@ static int get_console_mode( int handle, int *mode )
|
||||||
*mode = ((struct screen_buffer *)obj)->mode;
|
*mode = ((struct screen_buffer *)obj)->mode;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
else SET_ERROR( ERROR_INVALID_HANDLE );
|
else set_error( ERROR_INVALID_HANDLE );
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -280,13 +283,14 @@ static int set_console_mode( int handle, int mode )
|
||||||
((struct screen_buffer *)obj)->mode = mode;
|
((struct screen_buffer *)obj)->mode = mode;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
else SET_ERROR( ERROR_INVALID_HANDLE );
|
else set_error( ERROR_INVALID_HANDLE );
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set misc console information (output handle only) */
|
/* 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;
|
struct screen_buffer *console;
|
||||||
if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
|
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 (req->mask & SET_CONSOLE_INFO_TITLE)
|
||||||
{
|
{
|
||||||
if (console->title) free( console->title );
|
char *new_title = mem_alloc( len + 1 );
|
||||||
console->title = strdup( title );
|
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 );
|
release_object( console );
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -333,7 +343,7 @@ static int write_console_input( int handle, int count, INPUT_RECORD *records )
|
||||||
if (!(new_rec = realloc( console->records,
|
if (!(new_rec = realloc( console->records,
|
||||||
(console->recnum + count) * sizeof(INPUT_RECORD) )))
|
(console->recnum + count) * sizeof(INPUT_RECORD) )))
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_NOT_ENOUGH_MEMORY );
|
set_error( ERROR_NOT_ENOUGH_MEMORY );
|
||||||
release_object( console );
|
release_object( console );
|
||||||
return -1;
|
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 )
|
static int read_console_input( int handle, int count, int flush )
|
||||||
{
|
{
|
||||||
struct console_input *console;
|
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,
|
if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
|
||||||
GENERIC_READ, &console_input_ops )))
|
GENERIC_READ, &console_input_ops )))
|
||||||
return -1;
|
return -1;
|
||||||
if ((count < 0) || (count > console->recnum)) count = console->recnum;
|
if ((count < 0) || (count > console->recnum)) count = console->recnum;
|
||||||
send_reply( current, -1, 2, &reply, sizeof(reply),
|
add_reply_data( current, console->records, count * sizeof(INPUT_RECORD) );
|
||||||
console->records, count * sizeof(INPUT_RECORD) );
|
|
||||||
if (flush)
|
if (flush)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -445,7 +454,6 @@ static void console_input_destroy( struct object *obj )
|
||||||
unregister_select_user( &console->select );
|
unregister_select_user( &console->select );
|
||||||
close( console->select.fd );
|
close( console->select.fd );
|
||||||
if (console->output) console->output->input = NULL;
|
if (console->output) console->output->input = NULL;
|
||||||
free( console );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void screen_buffer_dump( struct object *obj, int verbose )
|
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->input) console->input->output = NULL;
|
||||||
if (console->pid) kill( console->pid, SIGTERM );
|
if (console->pid) kill( console->pid, SIGTERM );
|
||||||
if (console->title) free( console->title );
|
if (console->title) free( console->title );
|
||||||
free( console );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate a console for the current process */
|
/* allocate a console for the current process */
|
||||||
DECL_HANDLER(alloc_console)
|
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 (!alloc_console( current->process )) goto done;
|
||||||
|
|
||||||
if ((reply.handle_in = alloc_handle( current->process, current->process->console_in,
|
if ((in = alloc_handle( current->process, current->process->console_in,
|
||||||
req->access, req->inherit )) != -1)
|
req->access, req->inherit )) != -1)
|
||||||
{
|
{
|
||||||
if ((reply.handle_out = alloc_handle( current->process, current->process->console_out,
|
if ((out = alloc_handle( current->process, current->process->console_out,
|
||||||
req->access, req->inherit )) != -1)
|
req->access, req->inherit )) != -1)
|
||||||
goto done; /* everything is fine */
|
goto done; /* everything is fine */
|
||||||
close_handle( current->process, reply.handle_in );
|
close_handle( current->process, in );
|
||||||
reply.handle_in = -1;
|
in = -1;
|
||||||
}
|
}
|
||||||
free_console( current->process );
|
free_console( current->process );
|
||||||
|
|
||||||
done:
|
done:
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
reply->handle_in = in;
|
||||||
|
reply->handle_out = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free the console of the current process */
|
/* free the console of the current process */
|
||||||
DECL_HANDLER(free_console)
|
DECL_HANDLER(free_console)
|
||||||
{
|
{
|
||||||
free_console( current->process );
|
free_console( current->process );
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open a handle to the process console */
|
/* open a handle to the process console */
|
||||||
DECL_HANDLER(open_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;
|
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 );
|
if (obj) reply->handle = alloc_handle( current->process, obj, req->access, req->inherit );
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
else set_error( ERROR_ACCESS_DENIED );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set info about a console (output only) */
|
/* set info about a console (output only) */
|
||||||
DECL_HANDLER(set_console_info)
|
DECL_HANDLER(set_console_info)
|
||||||
{
|
{
|
||||||
char *name = (char *)data;
|
size_t len = get_req_strlen();
|
||||||
if (!len) name = NULL;
|
set_console_info( req->handle, req, get_req_data( len + 1 ), len );
|
||||||
else CHECK_STRING( "set_console_info", name, len );
|
|
||||||
set_console_info( req->handle, req, name );
|
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get info about a console (output only) */
|
/* get info about a console (output only) */
|
||||||
DECL_HANDLER(get_console_info)
|
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;
|
const char *title;
|
||||||
get_console_info( req->handle, &reply, &title );
|
get_console_info( req->handle, reply, &title );
|
||||||
send_reply( current, -1, 2, &reply, sizeof(reply),
|
if (title) add_reply_data( current, title, strlen(title) + 1 );
|
||||||
title, title ? strlen(title)+1 : 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set a console fd */
|
/* set a console fd */
|
||||||
DECL_HANDLER(set_console_fd)
|
DECL_HANDLER(set_console_fd)
|
||||||
{
|
{
|
||||||
set_console_fd( req->handle, fd, req->pid );
|
set_console_fd( req->handle, fd, req->pid );
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get a console mode (input or output) */
|
/* get a console mode (input or output) */
|
||||||
DECL_HANDLER(get_console_mode)
|
DECL_HANDLER(get_console_mode)
|
||||||
{
|
{
|
||||||
struct get_console_mode_reply reply;
|
struct get_console_mode_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
get_console_mode( req->handle, &reply.mode );
|
get_console_mode( req->handle, &reply->mode );
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set a console mode (input or output) */
|
/* set a console mode (input or output) */
|
||||||
DECL_HANDLER(set_console_mode)
|
DECL_HANDLER(set_console_mode)
|
||||||
{
|
{
|
||||||
set_console_mode( req->handle, req->mode );
|
set_console_mode( req->handle, req->mode );
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add input records to a console input queue */
|
/* add input records to a console input queue */
|
||||||
DECL_HANDLER(write_console_input)
|
DECL_HANDLER(write_console_input)
|
||||||
{
|
{
|
||||||
struct write_console_input_reply reply;
|
struct write_console_input_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
INPUT_RECORD *records = (INPUT_RECORD *)data;
|
|
||||||
|
|
||||||
if (len != req->count * sizeof(INPUT_RECORD))
|
if (check_req_data( req->count * sizeof(INPUT_RECORD)))
|
||||||
fatal_protocol_error( "write_console_input: bad length %d for %d records\n",
|
{
|
||||||
len, req->count );
|
INPUT_RECORD *records = get_req_data( req->count * sizeof(INPUT_RECORD) );
|
||||||
reply.written = write_console_input( req->handle, req->count, records );
|
reply->written = write_console_input( req->handle, req->count, records );
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
}
|
||||||
|
else fatal_protocol_error( "write_console_input: bad length" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fetch input records from a console input queue */
|
/* fetch input records from a console input queue */
|
||||||
|
|
|
@ -8,11 +8,10 @@
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
|
|
||||||
#include "server.h"
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct debug_event
|
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 */
|
/* 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 debug_event *event = debug_ctx->event_head;
|
||||||
struct thread *thread = event->thread;
|
struct thread *thread = event->thread;
|
||||||
|
struct wait_debug_event_reply *reply = push_reply_data( debug_ctx->owner, sizeof(*reply) );
|
||||||
|
|
||||||
assert( event );
|
assert( event );
|
||||||
assert( debug_ctx->waiting );
|
assert( debug_ctx->waiting );
|
||||||
|
|
||||||
unlink_event( debug_ctx, event );
|
unlink_event( debug_ctx, event );
|
||||||
event->sent = 1;
|
event->sent = 1;
|
||||||
reply.code = event->code;
|
reply->code = event->code;
|
||||||
reply.pid = thread->process;
|
reply->pid = thread->process;
|
||||||
reply.tid = thread;
|
reply->tid = thread;
|
||||||
debug_ctx->waiting = 0;
|
debug_ctx->waiting = 0;
|
||||||
if (debug_ctx->timeout)
|
if (debug_ctx->timeout)
|
||||||
{
|
{
|
||||||
|
@ -164,25 +163,24 @@ static void send_event_reply( struct debug_ctx *debug_ctx )
|
||||||
debug_ctx->timeout = NULL;
|
debug_ctx->timeout = NULL;
|
||||||
}
|
}
|
||||||
debug_ctx->owner->error = 0;
|
debug_ctx->owner->error = 0;
|
||||||
send_reply( debug_ctx->owner, -1, 2, &reply, sizeof(reply),
|
add_reply_data( debug_ctx->owner, &event->data, event_sizes[event->code] );
|
||||||
&event->data, event_sizes[event->code] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* timeout callback while waiting for a debug event */
|
/* timeout callback while waiting for a debug event */
|
||||||
static void wait_event_timeout( void *ctx )
|
static void wait_event_timeout( void *ctx )
|
||||||
{
|
{
|
||||||
struct debug_ctx *debug_ctx = (struct debug_ctx *)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 );
|
assert( debug_ctx->waiting );
|
||||||
|
|
||||||
reply.code = 0;
|
reply->code = 0;
|
||||||
reply.pid = 0;
|
reply->pid = 0;
|
||||||
reply.tid = 0;
|
reply->tid = 0;
|
||||||
debug_ctx->waiting = 0;
|
debug_ctx->waiting = 0;
|
||||||
debug_ctx->timeout = NULL;
|
debug_ctx->timeout = NULL;
|
||||||
debug_ctx->owner->error = WAIT_TIMEOUT;
|
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) */
|
/* 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 */
|
if (!debug_ctx) /* current thread is not a debugger */
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_ACCESS_DENIED ); /* FIXME */
|
set_error( ERROR_ACCESS_DENIED ); /* FIXME */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
assert( !debug_ctx->waiting );
|
assert( !debug_ctx->waiting );
|
||||||
if (debug_ctx->event_head) /* already have a pending event */
|
if (debug_ctx->event_head) /* already have a pending event */
|
||||||
{
|
{
|
||||||
debug_ctx->waiting = 1;
|
debug_ctx->waiting = 1;
|
||||||
send_event_reply( debug_ctx );
|
build_event_reply( debug_ctx );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!timeout) /* no event and we don't want to wait */
|
if (!timeout) /* no event and we don't want to wait */
|
||||||
{
|
{
|
||||||
SET_ERROR( WAIT_TIMEOUT );
|
set_error( WAIT_TIMEOUT );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (timeout != -1) /* start the timeout */
|
if (timeout != -1) /* start the timeout */
|
||||||
|
@ -215,6 +213,7 @@ static int wait_for_debug_event( int timeout )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
debug_ctx->waiting = 1;
|
debug_ctx->waiting = 1;
|
||||||
|
current->state = SLEEPING;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,16 +225,16 @@ static int continue_debug_event( struct process *process, struct thread *thread,
|
||||||
if (process->debugger != current || !event || !event->sent)
|
if (process->debugger != current || !event || !event->sent)
|
||||||
{
|
{
|
||||||
/* not debugging this process, or no event pending */
|
/* not debugging this process, or no event pending */
|
||||||
SET_ERROR( ERROR_ACCESS_DENIED ); /* FIXME */
|
set_error( ERROR_ACCESS_DENIED ); /* FIXME */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (thread->state != TERMINATED)
|
if (thread->state != TERMINATED)
|
||||||
{
|
{
|
||||||
/* only send a reply if the thread is still there */
|
/* only send a reply if the thread is still there */
|
||||||
/* (we can get a continue on an exit thread/process event) */
|
/* (we can get a continue on an exit thread/process event) */
|
||||||
struct send_debug_event_reply reply;
|
struct send_debug_event_reply *reply = push_reply_data( thread, sizeof(*reply) );
|
||||||
reply.status = status;
|
reply->status = status;
|
||||||
send_reply( thread, -1, 1, &reply, sizeof(reply) );
|
send_reply( thread );
|
||||||
}
|
}
|
||||||
free_event( event );
|
free_event( event );
|
||||||
resume_process( process );
|
resume_process( process );
|
||||||
|
@ -279,7 +278,11 @@ static struct debug_event *queue_debug_event( struct thread *debugger, struct th
|
||||||
link_event( debug_ctx, event );
|
link_event( debug_ctx, event );
|
||||||
thread->debug_event = event;
|
thread->debug_event = event;
|
||||||
suspend_process( thread->process );
|
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;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,14 +294,14 @@ int debugger_attach( struct process *process, struct thread *debugger )
|
||||||
|
|
||||||
if (process->debugger) /* already being debugged */
|
if (process->debugger) /* already being debugged */
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
set_error( ERROR_ACCESS_DENIED );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* make sure we don't create a debugging loop */
|
/* make sure we don't create a debugging loop */
|
||||||
for (thread = debugger; thread; thread = thread->process->debugger)
|
for (thread = debugger; thread; thread = thread->process->debugger)
|
||||||
if (thread->process == process)
|
if (thread->process == process)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
set_error( ERROR_ACCESS_DENIED );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,14 +378,12 @@ void debug_exit_thread( struct thread *thread, int exit_code )
|
||||||
/* Wait for a debug event */
|
/* Wait for a debug event */
|
||||||
DECL_HANDLER(wait_debug_event)
|
DECL_HANDLER(wait_debug_event)
|
||||||
{
|
{
|
||||||
struct wait_debug_event_reply reply;
|
|
||||||
|
|
||||||
if (!wait_for_debug_event( req->timeout ))
|
if (!wait_for_debug_event( req->timeout ))
|
||||||
{
|
{
|
||||||
reply.code = 0;
|
struct wait_debug_event_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
reply.pid = NULL;
|
reply->code = 0;
|
||||||
reply.tid = NULL;
|
reply->pid = NULL;
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
reply->tid = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +401,6 @@ DECL_HANDLER(continue_debug_event)
|
||||||
}
|
}
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start debugging an existing process */
|
/* Start debugging an existing process */
|
||||||
|
@ -413,26 +413,33 @@ DECL_HANDLER(debug_process)
|
||||||
/* FIXME: should notice the debugged process somehow */
|
/* FIXME: should notice the debugged process somehow */
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send a debug event */
|
/* Send a debug event */
|
||||||
DECL_HANDLER(send_debug_event)
|
DECL_HANDLER(send_debug_event)
|
||||||
{
|
{
|
||||||
struct thread *debugger = current->process->debugger;
|
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 );
|
assert( !current->debug_event );
|
||||||
reply.status = 0;
|
if ((req->code <= 0) || (req->code > RIP_EVENT))
|
||||||
if (debugger)
|
|
||||||
{
|
{
|
||||||
if (queue_debug_event( debugger, current, req->code, data ))
|
fatal_protocol_error( "send_debug_event: bad event code" );
|
||||||
return; /* don't reply now, wait for continue_debug_event */
|
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) );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct device
|
struct device
|
||||||
{
|
{
|
||||||
|
@ -30,10 +31,10 @@ struct device
|
||||||
|
|
||||||
static void device_dump( struct object *obj, int verbose );
|
static void device_dump( struct object *obj, int verbose );
|
||||||
static int device_get_info( struct object *obj, struct get_file_info_reply *reply );
|
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 =
|
static const struct object_ops device_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct device),
|
||||||
device_dump,
|
device_dump,
|
||||||
no_add_queue,
|
no_add_queue,
|
||||||
NULL, /* should never get called */
|
NULL, /* should never get called */
|
||||||
|
@ -43,17 +44,17 @@ static const struct object_ops device_ops =
|
||||||
no_write_fd,
|
no_write_fd,
|
||||||
no_flush,
|
no_flush,
|
||||||
device_get_info,
|
device_get_info,
|
||||||
device_destroy
|
no_destroy
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct object *create_device( int id )
|
static struct device *create_device( int id )
|
||||||
{
|
{
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
if ((dev = alloc_object( &device_ops )))
|
||||||
if (!(dev = mem_alloc(sizeof(*dev)))) return NULL;
|
{
|
||||||
init_object( &dev->obj, &device_ops, NULL );
|
dev->id = id;
|
||||||
dev->id = id;
|
}
|
||||||
return &dev->obj;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_dump( struct object *obj, int verbose )
|
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;
|
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 */
|
/* create a device */
|
||||||
DECL_HANDLER(create_device)
|
DECL_HANDLER(create_device)
|
||||||
{
|
{
|
||||||
struct object *obj;
|
struct device *dev;
|
||||||
struct create_device_reply reply = { -1 };
|
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,
|
reply->handle = alloc_handle( current->process, dev, req->access, req->inherit );
|
||||||
req->access, req->inherit );
|
release_object( dev );
|
||||||
release_object( obj );
|
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
else reply->handle = -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct event
|
struct event
|
||||||
{
|
{
|
||||||
|
@ -24,10 +25,10 @@ struct event
|
||||||
static void event_dump( struct object *obj, int verbose );
|
static void event_dump( struct object *obj, int verbose );
|
||||||
static int event_signaled( struct object *obj, struct thread *thread );
|
static int event_signaled( struct object *obj, struct thread *thread );
|
||||||
static int event_satisfied( 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 =
|
static const struct object_ops event_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct event),
|
||||||
event_dump,
|
event_dump,
|
||||||
add_queue,
|
add_queue,
|
||||||
remove_queue,
|
remove_queue,
|
||||||
|
@ -37,23 +38,25 @@ static const struct object_ops event_ops =
|
||||||
no_write_fd,
|
no_write_fd,
|
||||||
no_flush,
|
no_flush,
|
||||||
no_get_file_info,
|
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;
|
struct event *event;
|
||||||
|
|
||||||
if (!(event = (struct event *)create_named_object( name, &event_ops, sizeof(*event) )))
|
if ((event = create_named_object( &event_ops, name, len )))
|
||||||
return NULL;
|
|
||||||
if (GET_ERROR() != ERROR_ALREADY_EXISTS)
|
|
||||||
{
|
{
|
||||||
/* initialize it if it didn't already exist */
|
if (get_error() != ERROR_ALREADY_EXISTS)
|
||||||
event->manual_reset = manual_reset;
|
{
|
||||||
event->signaled = initial_state;
|
/* 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 )
|
static int pulse_event( int handle )
|
||||||
|
@ -122,41 +125,28 @@ static int event_satisfied( struct object *obj, struct thread *thread )
|
||||||
return 0; /* Not abandoned */
|
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 */
|
/* create an event */
|
||||||
DECL_HANDLER(create_event)
|
DECL_HANDLER(create_event)
|
||||||
{
|
{
|
||||||
struct create_event_reply reply = { -1 };
|
size_t len = get_req_strlen();
|
||||||
struct object *obj;
|
struct create_event_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
char *name = (char *)data;
|
struct event *event;
|
||||||
if (!len) name = NULL;
|
|
||||||
else CHECK_STRING( "create_event", name, len );
|
|
||||||
|
|
||||||
obj = create_event( name, req->manual_reset, req->initial_state );
|
if ((event = create_event( get_req_data(len+1), len, req->manual_reset, req->initial_state )))
|
||||||
if (obj)
|
|
||||||
{
|
{
|
||||||
reply.handle = alloc_handle( current->process, obj, EVENT_ALL_ACCESS, req->inherit );
|
reply->handle = alloc_handle( current->process, event, EVENT_ALL_ACCESS, req->inherit );
|
||||||
release_object( obj );
|
release_object( event );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
else reply->handle = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open a handle to an event */
|
/* open a handle to an event */
|
||||||
DECL_HANDLER(open_event)
|
DECL_HANDLER(open_event)
|
||||||
{
|
{
|
||||||
struct open_event_reply reply;
|
size_t len = get_req_strlen();
|
||||||
char *name = (char *)data;
|
struct open_event_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
if (!len) name = NULL;
|
reply->handle = open_object( get_req_data( len + 1 ), len, &event_ops,
|
||||||
else CHECK_STRING( "open_event", name, len );
|
req->access, req->inherit );
|
||||||
|
|
||||||
reply.handle = open_object( name, &event_ops, req->access, req->inherit );
|
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do an event operation */
|
/* do an event operation */
|
||||||
|
@ -174,7 +164,6 @@ DECL_HANDLER(event_op)
|
||||||
reset_event( req->handle );
|
reset_event( req->handle );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal_protocol_error( "event_op: invalid operation %d\n", req->op );
|
fatal_protocol_error( "event_op: invalid operation" );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
306
server/file.c
306
server/file.c
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct file
|
struct file
|
||||||
{
|
{
|
||||||
|
@ -51,6 +52,7 @@ static void file_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops file_ops =
|
static const struct object_ops file_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct file),
|
||||||
file_dump,
|
file_dump,
|
||||||
file_add_queue,
|
file_add_queue,
|
||||||
file_remove_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_sharing &= file->sharing;
|
||||||
existing_access |= file->access;
|
existing_access |= file->access;
|
||||||
}
|
}
|
||||||
if ((access & GENERIC_READ) && !(existing_sharing & FILE_SHARE_READ)) return 0;
|
if ((access & GENERIC_READ) && !(existing_sharing & FILE_SHARE_READ)) goto error;
|
||||||
if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) return 0;
|
if ((access & GENERIC_WRITE) && !(existing_sharing & FILE_SHARE_WRITE)) goto error;
|
||||||
if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) return 0;
|
if ((existing_access & GENERIC_READ) && !(sharing & FILE_SHARE_READ)) goto error;
|
||||||
if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) return 0;
|
if ((existing_access & GENERIC_WRITE) && !(sharing & FILE_SHARE_WRITE)) goto error;
|
||||||
return 1;
|
return 1;
|
||||||
|
error:
|
||||||
|
set_error( ERROR_SHARING_VIOLATION );
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct object *create_file( int fd, const char *name, unsigned int access,
|
static struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing,
|
||||||
unsigned int sharing, int create, unsigned int attrs )
|
unsigned int attrs )
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct file *file;
|
||||||
int hash = 0;
|
if ((file = alloc_object( &file_ops )))
|
||||||
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
{
|
||||||
int flags;
|
file->name = NULL;
|
||||||
struct stat st;
|
file->next = NULL;
|
||||||
|
file->select.fd = fd;
|
||||||
if (!name)
|
file->select.func = default_select_event;
|
||||||
{
|
file->select.private = file;
|
||||||
SET_ERROR( ERROR_INVALID_PARAMETER );
|
file->access = access;
|
||||||
return NULL;
|
file->flags = attrs;
|
||||||
}
|
file->sharing = sharing;
|
||||||
|
register_select_user( &file->select );
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
return file;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
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;
|
char *name;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
@ -210,34 +188,28 @@ struct file *create_temp_file( int access )
|
||||||
{
|
{
|
||||||
if (!(name = tmpnam(NULL)))
|
if (!(name = tmpnam(NULL)))
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
|
set_error( ERROR_TOO_MANY_OPEN_FILES );
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
fd = open( name, O_CREAT | O_EXCL | O_RDWR, 0600 );
|
fd = open( name, O_CREAT | O_EXCL | O_RDWR, 0600 );
|
||||||
} while ((fd == -1) && (errno == EEXIST));
|
} while ((fd == -1) && (errno == EEXIST));
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
{
|
{
|
||||||
file_set_error();
|
file_set_error();
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
unlink( name );
|
unlink( name );
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(file = mem_alloc( sizeof(*file) )))
|
/* Create a temp file for anonymous mappings */
|
||||||
{
|
struct file *create_temp_file( int access )
|
||||||
close( fd );
|
{
|
||||||
return NULL;
|
struct file *file;
|
||||||
}
|
int fd;
|
||||||
init_object( &file->obj, &file_ops, NULL );
|
|
||||||
file->name = NULL;
|
if ((fd = create_anonymous_file()) != -1) return NULL;
|
||||||
file->next = NULL;
|
if (!(file = create_file_for_fd( fd, access, 0, 0 ))) close( fd );
|
||||||
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();
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +217,8 @@ static void file_dump( struct object *obj, int verbose )
|
||||||
{
|
{
|
||||||
struct file *file = (struct file *)obj;
|
struct file *file = (struct file *)obj;
|
||||||
assert( obj->ops == &file_ops );
|
assert( obj->ops == &file_ops );
|
||||||
printf( "File fd=%d flags=%08x name='%s'\n",
|
fprintf( stderr, "File fd=%d flags=%08x name='%s'\n",
|
||||||
file->select.fd, file->flags, file->name );
|
file->select.fd, file->flags, file->name );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
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 );
|
unregister_select_user( &file->select );
|
||||||
close( file->select.fd );
|
close( file->select.fd );
|
||||||
free( file );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the last error depending on errno */
|
/* set the last error depending on errno */
|
||||||
|
@ -376,22 +347,22 @@ void file_set_error(void)
|
||||||
{
|
{
|
||||||
switch (errno)
|
switch (errno)
|
||||||
{
|
{
|
||||||
case EAGAIN: SET_ERROR( ERROR_SHARING_VIOLATION ); break;
|
case EAGAIN: set_error( ERROR_SHARING_VIOLATION ); break;
|
||||||
case EBADF: SET_ERROR( ERROR_INVALID_HANDLE ); break;
|
case EBADF: set_error( ERROR_INVALID_HANDLE ); break;
|
||||||
case ENOSPC: SET_ERROR( ERROR_HANDLE_DISK_FULL ); break;
|
case ENOSPC: set_error( ERROR_HANDLE_DISK_FULL ); break;
|
||||||
case EACCES:
|
case EACCES:
|
||||||
case EPERM: SET_ERROR( ERROR_ACCESS_DENIED ); break;
|
case EPERM: set_error( ERROR_ACCESS_DENIED ); break;
|
||||||
case EROFS: SET_ERROR( ERROR_WRITE_PROTECT ); break;
|
case EROFS: set_error( ERROR_WRITE_PROTECT ); break;
|
||||||
case EBUSY: SET_ERROR( ERROR_LOCK_VIOLATION ); break;
|
case EBUSY: set_error( ERROR_LOCK_VIOLATION ); break;
|
||||||
case ENOENT: SET_ERROR( ERROR_FILE_NOT_FOUND ); break;
|
case ENOENT: set_error( ERROR_FILE_NOT_FOUND ); break;
|
||||||
case EISDIR: SET_ERROR( ERROR_CANNOT_MAKE ); break;
|
case EISDIR: set_error( ERROR_CANNOT_MAKE ); break;
|
||||||
case ENFILE:
|
case ENFILE:
|
||||||
case EMFILE: SET_ERROR( ERROR_NO_MORE_FILES ); break;
|
case EMFILE: set_error( ERROR_NO_MORE_FILES ); break;
|
||||||
case EEXIST: SET_ERROR( ERROR_FILE_EXISTS ); break;
|
case EEXIST: set_error( ERROR_FILE_EXISTS ); break;
|
||||||
case EINVAL: SET_ERROR( ERROR_INVALID_PARAMETER ); break;
|
case EINVAL: set_error( ERROR_INVALID_PARAMETER ); break;
|
||||||
case ESPIPE: SET_ERROR( ERROR_SEEK ); break;
|
case ESPIPE: set_error( ERROR_SEEK ); break;
|
||||||
case ENOTEMPTY: SET_ERROR( ERROR_DIR_NOT_EMPTY ); break;
|
case ENOTEMPTY: set_error( ERROR_DIR_NOT_EMPTY ); break;
|
||||||
default: perror("file_set_error"); SET_ERROR( ERROR_UNKNOWN ); 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)
|
if (*high)
|
||||||
{
|
{
|
||||||
fprintf( stderr, "set_file_pointer: offset > 4Gb not supported yet\n" );
|
fprintf( stderr, "set_file_pointer: offset > 4Gb not supported yet\n" );
|
||||||
SET_ERROR( ERROR_INVALID_PARAMETER );
|
set_error( ERROR_INVALID_PARAMETER );
|
||||||
return 0;
|
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 */
|
/* Check for seek before start of file */
|
||||||
if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
|
if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
|
||||||
SET_ERROR( ERROR_NEGATIVE_SEEK );
|
set_error( ERROR_NEGATIVE_SEEK );
|
||||||
else
|
else
|
||||||
file_set_error();
|
file_set_error();
|
||||||
release_object( file );
|
release_object( file );
|
||||||
|
@ -462,7 +433,7 @@ int grow_file( struct file *file, int size_high, int size_low )
|
||||||
|
|
||||||
if (size_high)
|
if (size_high)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_PARAMETER );
|
set_error( ERROR_INVALID_PARAMETER );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (fstat( file->select.fd, &st ) == -1)
|
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 */
|
/* create a file */
|
||||||
DECL_HANDLER(create_file)
|
DECL_HANDLER(create_file)
|
||||||
{
|
{
|
||||||
struct create_file_reply reply = { -1 };
|
struct create_file_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
struct object *obj;
|
struct file *file = NULL;
|
||||||
char *name = (char *)data;
|
|
||||||
if (!len) name = NULL;
|
|
||||||
else CHECK_STRING( "create_file", name, len );
|
|
||||||
|
|
||||||
if ((obj = create_file( fd, name, req->access,
|
if (fd == -1)
|
||||||
req->sharing, req->create, req->attrs )) != NULL)
|
|
||||||
{
|
{
|
||||||
reply.handle = alloc_handle( current->process, obj, req->access, req->inherit );
|
size_t len = get_req_strlen();
|
||||||
release_object( obj );
|
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 */
|
/* get a Unix fd to read from a file */
|
||||||
|
@ -544,7 +524,7 @@ DECL_HANDLER(get_read_fd)
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
}
|
}
|
||||||
else read_fd = -1;
|
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 */
|
/* get a Unix fd to write to a file */
|
||||||
|
@ -559,7 +539,7 @@ DECL_HANDLER(get_write_fd)
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
}
|
}
|
||||||
else write_fd = -1;
|
else write_fd = -1;
|
||||||
send_reply( current, write_fd, 0 );
|
set_reply_fd( current, write_fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set a file current position */
|
/* set a file current position */
|
||||||
|
@ -569,14 +549,13 @@ DECL_HANDLER(set_file_pointer)
|
||||||
reply.low = req->low;
|
reply.low = req->low;
|
||||||
reply.high = req->high;
|
reply.high = req->high;
|
||||||
set_file_pointer( req->handle, &reply.low, &reply.high, req->whence );
|
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 */
|
/* truncate (or extend) a file */
|
||||||
DECL_HANDLER(truncate_file)
|
DECL_HANDLER(truncate_file)
|
||||||
{
|
{
|
||||||
truncate_file( req->handle );
|
truncate_file( req->handle );
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* flush a file buffers */
|
/* flush a file buffers */
|
||||||
|
@ -589,28 +568,25 @@ DECL_HANDLER(flush_file)
|
||||||
obj->ops->flush( obj );
|
obj->ops->flush( obj );
|
||||||
release_object( obj );
|
release_object( obj );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set a file access and modification times */
|
/* set a file access and modification times */
|
||||||
DECL_HANDLER(set_file_time)
|
DECL_HANDLER(set_file_time)
|
||||||
{
|
{
|
||||||
set_file_time( req->handle, req->access_time, req->write_time );
|
set_file_time( req->handle, req->access_time, req->write_time );
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get a file information */
|
/* get a file information */
|
||||||
DECL_HANDLER(get_file_info)
|
DECL_HANDLER(get_file_info)
|
||||||
{
|
{
|
||||||
struct object *obj;
|
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 )))
|
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 );
|
release_object( obj );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lock a region of a file */
|
/* lock a region of a file */
|
||||||
|
@ -624,7 +600,6 @@ DECL_HANDLER(lock_file)
|
||||||
req->count_high, req->count_low );
|
req->count_high, req->count_low );
|
||||||
release_object( file );
|
release_object( file );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unlock a region of a file */
|
/* unlock a region of a file */
|
||||||
|
@ -638,5 +613,4 @@ DECL_HANDLER(unlock_file)
|
||||||
req->count_high, req->count_low );
|
req->count_high, req->count_low );
|
||||||
release_object( file );
|
release_object( file );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct handle_entry
|
struct handle_entry
|
||||||
{
|
{
|
||||||
|
@ -55,6 +56,7 @@ static void handle_table_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops handle_table_ops =
|
static const struct object_ops handle_table_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct handle_table),
|
||||||
handle_table_dump,
|
handle_table_dump,
|
||||||
no_add_queue,
|
no_add_queue,
|
||||||
NULL, /* should never get called */
|
NULL, /* should never get called */
|
||||||
|
@ -104,7 +106,6 @@ static void handle_table_destroy( struct object *obj )
|
||||||
if (obj) release_object( obj );
|
if (obj) release_object( obj );
|
||||||
}
|
}
|
||||||
free( table->entries );
|
free( table->entries );
|
||||||
free( table );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate a new handle table */
|
/* allocate a new handle table */
|
||||||
|
@ -113,7 +114,7 @@ struct object *alloc_handle_table( struct process *process, int count )
|
||||||
struct handle_table *table;
|
struct handle_table *table;
|
||||||
|
|
||||||
if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
|
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;
|
return NULL;
|
||||||
table->process = process;
|
table->process = process;
|
||||||
table->count = count;
|
table->count = count;
|
||||||
|
@ -134,7 +135,7 @@ static int grow_handle_table( struct handle_table *table )
|
||||||
count *= 2;
|
count *= 2;
|
||||||
if (!(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
|
if (!(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_OUTOFMEMORY );
|
set_error( ERROR_OUTOFMEMORY );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
table->entries = new_entries;
|
table->entries = new_entries;
|
||||||
|
@ -216,7 +217,7 @@ static struct handle_entry *get_handle( struct process *process, int handle )
|
||||||
return entry;
|
return entry;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
set_error( ERROR_INVALID_HANDLE );
|
||||||
return NULL;
|
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 = get_handle( process, handle ))) return NULL;
|
||||||
if ((entry->access & access) != access)
|
if ((entry->access & access) != access)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
set_error( ERROR_ACCESS_DENIED );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
obj = entry->ptr;
|
obj = entry->ptr;
|
||||||
|
@ -327,7 +328,7 @@ struct object *get_handle_obj( struct process *process, int handle,
|
||||||
}
|
}
|
||||||
if (ops && (obj->ops != ops))
|
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 NULL;
|
||||||
}
|
}
|
||||||
return grab_object( obj );
|
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 */
|
else /* pseudo-handle, give it full access */
|
||||||
{
|
{
|
||||||
access = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
|
access = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
|
||||||
CLEAR_ERROR();
|
clear_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
access &= ~RESERVED_ALL;
|
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 */
|
/* 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 )
|
unsigned int access, int inherit )
|
||||||
{
|
{
|
||||||
struct object *obj = find_object( name );
|
struct object *obj = find_object( name, len );
|
||||||
if (!obj)
|
if (!obj)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_FILE_NOT_FOUND );
|
set_error( ERROR_FILE_NOT_FOUND );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (ops && obj->ops != ops)
|
if (ops && obj->ops != ops)
|
||||||
{
|
{
|
||||||
release_object( obj );
|
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 -1;
|
||||||
}
|
}
|
||||||
return alloc_handle( current->process, obj, access, inherit );
|
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)
|
DECL_HANDLER(close_handle)
|
||||||
{
|
{
|
||||||
close_handle( current->process, req->handle );
|
close_handle( current->process, req->handle );
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get information about a handle */
|
/* get information about a handle */
|
||||||
DECL_HANDLER(get_handle_info)
|
DECL_HANDLER(get_handle_info)
|
||||||
{
|
{
|
||||||
struct get_handle_info_reply reply;
|
struct get_handle_info_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
reply.flags = set_handle_info( current->process, req->handle, 0, 0 );
|
reply->flags = set_handle_info( current->process, req->handle, 0, 0 );
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set a handle information */
|
/* set a handle information */
|
||||||
DECL_HANDLER(set_handle_info)
|
DECL_HANDLER(set_handle_info)
|
||||||
{
|
{
|
||||||
set_handle_info( current->process, req->handle, req->mask, req->flags );
|
set_handle_info( current->process, req->handle, req->mask, req->flags );
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* duplicate a handle */
|
/* duplicate a handle */
|
||||||
|
@ -439,5 +437,5 @@ DECL_HANDLER(dup_handle)
|
||||||
close_handle( src, req->src_handle );
|
close_handle( src, req->src_handle );
|
||||||
release_object( src );
|
release_object( src );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
add_reply_data( current, &reply, sizeof(reply) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#error This file can only be used in the Wine server
|
#error This file can only be used in the Wine server
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
struct process;
|
struct process;
|
||||||
struct object_ops;
|
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 );
|
unsigned int access, const struct object_ops *ops );
|
||||||
extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
|
extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
|
||||||
unsigned int access, int inherit, int options );
|
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 );
|
unsigned int access, int inherit );
|
||||||
extern struct object *alloc_handle_table( struct process *process, int count );
|
extern struct object *alloc_handle_table( struct process *process, int count );
|
||||||
extern struct object *copy_handle_table( struct process *process, struct process *parent );
|
extern struct object *copy_handle_table( struct process *process, struct process *parent );
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "server.h"
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct mapping
|
struct mapping
|
||||||
{
|
{
|
||||||
|
@ -31,6 +32,7 @@ static void mapping_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops mapping_ops =
|
static const struct object_ops mapping_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct mapping),
|
||||||
mapping_dump,
|
mapping_dump,
|
||||||
no_add_queue,
|
no_add_queue,
|
||||||
NULL, /* should never get called */
|
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,
|
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;
|
struct mapping *mapping;
|
||||||
int access = 0;
|
int access = 0;
|
||||||
|
|
||||||
if (!page_mask) init_page_size();
|
if (!page_mask) init_page_size();
|
||||||
|
|
||||||
if (!(mapping = (struct mapping *)create_named_object( name, &mapping_ops,
|
if (!(mapping = create_named_object( &mapping_ops, name, len )))
|
||||||
sizeof(*mapping) )))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
if (GET_ERROR() == ERROR_ALREADY_EXISTS)
|
if (get_error() == ERROR_ALREADY_EXISTS)
|
||||||
return &mapping->obj; /* Nothing else to do */
|
return &mapping->obj; /* Nothing else to do */
|
||||||
|
|
||||||
if (protect & VPROT_READ) access |= GENERIC_READ;
|
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)
|
if (!size_high && !size_low)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_PARAMETER );
|
set_error( ERROR_INVALID_PARAMETER );
|
||||||
mapping->file = NULL;
|
mapping->file = NULL;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -163,45 +164,39 @@ static void mapping_destroy( struct object *obj )
|
||||||
struct mapping *mapping = (struct mapping *)obj;
|
struct mapping *mapping = (struct mapping *)obj;
|
||||||
assert( obj->ops == &mapping_ops );
|
assert( obj->ops == &mapping_ops );
|
||||||
if (mapping->file) release_object( mapping->file );
|
if (mapping->file) release_object( mapping->file );
|
||||||
free( mapping );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a file mapping */
|
/* create a file mapping */
|
||||||
DECL_HANDLER(create_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 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,
|
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;
|
int access = FILE_MAP_ALL_ACCESS;
|
||||||
if (!(req->protect & VPROT_WRITE)) access &= ~FILE_MAP_WRITE;
|
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 );
|
release_object( obj );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
else reply->handle = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open a handle to a mapping */
|
/* open a handle to a mapping */
|
||||||
DECL_HANDLER(open_mapping)
|
DECL_HANDLER(open_mapping)
|
||||||
{
|
{
|
||||||
struct open_mapping_reply reply;
|
size_t len = get_req_strlen();
|
||||||
char *name = (char *)data;
|
struct open_mapping_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
if (!len) name = NULL;
|
reply->handle = open_object( get_req_data( len + 1 ), len, &mapping_ops,
|
||||||
else CHECK_STRING( "open_mapping", name, len );
|
req->access, req->inherit );
|
||||||
|
|
||||||
reply.handle = open_object( name, &mapping_ops, req->access, req->inherit );
|
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get a mapping information */
|
/* get a mapping information */
|
||||||
DECL_HANDLER(get_mapping_info)
|
DECL_HANDLER(get_mapping_info)
|
||||||
{
|
{
|
||||||
struct get_mapping_info_reply reply;
|
struct get_mapping_info_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
int map_fd = get_mapping_info( req->handle, &reply );
|
int map_fd = get_mapping_info( req->handle, reply );
|
||||||
send_reply( current, map_fd, 1, &reply, sizeof(reply) );
|
set_reply_fd( current, map_fd );
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct mutex
|
struct mutex
|
||||||
{
|
{
|
||||||
|
@ -27,10 +28,10 @@ struct mutex
|
||||||
static void mutex_dump( struct object *obj, int verbose );
|
static void mutex_dump( struct object *obj, int verbose );
|
||||||
static int mutex_signaled( struct object *obj, struct thread *thread );
|
static int mutex_signaled( struct object *obj, struct thread *thread );
|
||||||
static int mutex_satisfied( 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 =
|
static const struct object_ops mutex_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct mutex),
|
||||||
mutex_dump,
|
mutex_dump,
|
||||||
add_queue,
|
add_queue,
|
||||||
remove_queue,
|
remove_queue,
|
||||||
|
@ -40,26 +41,27 @@ static const struct object_ops mutex_ops =
|
||||||
no_write_fd,
|
no_write_fd,
|
||||||
no_flush,
|
no_flush,
|
||||||
no_get_file_info,
|
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;
|
struct mutex *mutex;
|
||||||
|
|
||||||
if (!(mutex = (struct mutex *)create_named_object( name, &mutex_ops, sizeof(*mutex) )))
|
if ((mutex = create_named_object( &mutex_ops, name, len )))
|
||||||
return NULL;
|
|
||||||
if (GET_ERROR() != ERROR_ALREADY_EXISTS)
|
|
||||||
{
|
{
|
||||||
/* initialize it if it didn't already exist */
|
if (get_error() != ERROR_ALREADY_EXISTS)
|
||||||
mutex->count = 0;
|
{
|
||||||
mutex->owner = NULL;
|
/* initialize it if it didn't already exist */
|
||||||
mutex->abandoned = 0;
|
mutex->count = 0;
|
||||||
mutex->next = mutex->prev = NULL;
|
mutex->owner = NULL;
|
||||||
if (owned) mutex_satisfied( &mutex->obj, current );
|
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 */
|
/* 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 );
|
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 )
|
void abandon_mutexes( struct thread *thread )
|
||||||
{
|
{
|
||||||
while (thread->mutex)
|
while (thread->mutex)
|
||||||
|
@ -138,46 +123,40 @@ static int mutex_satisfied( struct object *obj, struct thread *thread )
|
||||||
return 1;
|
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 */
|
/* create a mutex */
|
||||||
DECL_HANDLER(create_mutex)
|
DECL_HANDLER(create_mutex)
|
||||||
{
|
{
|
||||||
struct create_mutex_reply reply = { -1 };
|
size_t len = get_req_strlen();
|
||||||
struct object *obj;
|
struct create_mutex_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
char *name = (char *)data;
|
struct mutex *mutex;
|
||||||
if (!len) name = NULL;
|
|
||||||
else CHECK_STRING( "create_mutex", name, len );
|
|
||||||
|
|
||||||
obj = create_mutex( name, req->owned );
|
if ((mutex = create_mutex( get_req_data( len + 1 ), len, req->owned )))
|
||||||
if (obj)
|
|
||||||
{
|
{
|
||||||
reply.handle = alloc_handle( current->process, obj, MUTEX_ALL_ACCESS, req->inherit );
|
reply->handle = alloc_handle( current->process, mutex, MUTEX_ALL_ACCESS, req->inherit );
|
||||||
release_object( obj );
|
release_object( mutex );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
else reply->handle = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open a handle to a mutex */
|
/* open a handle to a mutex */
|
||||||
DECL_HANDLER(open_mutex)
|
DECL_HANDLER(open_mutex)
|
||||||
{
|
{
|
||||||
struct open_mutex_reply reply;
|
size_t len = get_req_strlen();
|
||||||
char *name = (char *)data;
|
struct open_mutex_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
if (!len) name = NULL;
|
reply->handle = open_object( get_req_data( len + 1 ), len, &mutex_ops,
|
||||||
else CHECK_STRING( "open_mutex", name, len );
|
req->access, req->inherit );
|
||||||
|
|
||||||
reply.handle = open_object( name, &mutex_ops, req->access, req->inherit );
|
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* release a mutex */
|
/* release a mutex */
|
||||||
DECL_HANDLER(release_mutex)
|
DECL_HANDLER(release_mutex)
|
||||||
{
|
{
|
||||||
if (release_mutex( req->handle )) CLEAR_ERROR();
|
struct mutex *mutex;
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
148
server/object.c
148
server/object.c
|
@ -19,8 +19,9 @@ int debug_level = 0;
|
||||||
struct object_name
|
struct object_name
|
||||||
{
|
{
|
||||||
struct object_name *next;
|
struct object_name *next;
|
||||||
|
struct object_name *prev;
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
int len;
|
size_t len;
|
||||||
char name[1];
|
char name[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,96 +46,115 @@ void dump_objects(void)
|
||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
|
|
||||||
|
/* malloc replacement */
|
||||||
void *mem_alloc( size_t size )
|
void *mem_alloc( size_t size )
|
||||||
{
|
{
|
||||||
void *ptr = malloc( size );
|
void *ptr = malloc( size );
|
||||||
if (ptr) memset( ptr, 0x55, size );
|
if (ptr) memset( ptr, 0x55, size );
|
||||||
else if (current) SET_ERROR( ERROR_OUTOFMEMORY );
|
else if (current) set_error( ERROR_OUTOFMEMORY );
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
|
|
||||||
static int get_name_hash( const char *name )
|
static int get_name_hash( const char *name, size_t len )
|
||||||
{
|
{
|
||||||
int hash = 0;
|
char hash = 0;
|
||||||
while (*name) hash ^= *name++;
|
while (len--) hash ^= *name++;
|
||||||
return hash % NAME_HASH_SIZE;
|
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;
|
struct object_name *ptr;
|
||||||
int hash = get_name_hash( name );
|
|
||||||
int len = strlen( name );
|
|
||||||
|
|
||||||
if (!(ptr = (struct object_name *)mem_alloc( sizeof(*ptr) + len )))
|
if ((ptr = mem_alloc( sizeof(*ptr) + len )))
|
||||||
return NULL;
|
{
|
||||||
ptr->next = names[hash];
|
ptr->len = len;
|
||||||
ptr->obj = obj;
|
memcpy( ptr->name, name, len );
|
||||||
ptr->len = len;
|
ptr->name[len] = 0;
|
||||||
strcpy( ptr->name, name );
|
}
|
||||||
names[hash] = ptr;
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free the name of an object */
|
||||||
static void free_name( struct object *obj )
|
static void free_name( struct object *obj )
|
||||||
{
|
{
|
||||||
int hash = get_name_hash( obj->name->name );
|
struct object_name *ptr = obj->name;
|
||||||
struct object_name **pptr = &names[hash];
|
if (ptr->next) ptr->next->prev = ptr->prev;
|
||||||
while (*pptr && *pptr != obj->name) pptr = &(*pptr)->next;
|
if (ptr->prev) ptr->prev->next = ptr->next;
|
||||||
assert( *pptr );
|
else
|
||||||
*pptr = (*pptr)->next;
|
{
|
||||||
free( obj->name );
|
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 */
|
/* set the name of an existing object */
|
||||||
/* return 1 if OK, 0 on error */
|
static void set_object_name( struct object *obj, struct object_name *ptr )
|
||||||
int init_object( struct object *obj, const struct object_ops *ops,
|
|
||||||
const char *name )
|
|
||||||
{
|
{
|
||||||
obj->refcount = 1;
|
int hash = get_name_hash( ptr->name, ptr->len );
|
||||||
obj->ops = ops;
|
|
||||||
obj->head = NULL;
|
if ((ptr->next = names[hash]) != NULL) ptr->next->prev = ptr;
|
||||||
obj->tail = NULL;
|
ptr->obj = obj;
|
||||||
if (!name) obj->name = NULL;
|
ptr->prev = NULL;
|
||||||
else if (!(obj->name = add_name( obj, name ))) return 0;
|
names[hash] = ptr;
|
||||||
#ifdef DEBUG_OBJECTS
|
assert( !obj->name );
|
||||||
obj->prev = NULL;
|
obj->name = ptr;
|
||||||
if ((obj->next = first) != NULL) obj->next->prev = obj;
|
|
||||||
first = obj;
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate and initialize an object */
|
/* 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 );
|
struct object *obj = mem_alloc( ops->size );
|
||||||
if (obj) init_object( obj, ops, name );
|
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;
|
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;
|
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)
|
if (obj->ops == ops)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_ALREADY_EXISTS );
|
set_error( ERROR_ALREADY_EXISTS );
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
set_error( ERROR_INVALID_HANDLE );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(obj = mem_alloc( size ))) return NULL;
|
if ((obj = alloc_object( ops )))
|
||||||
if (!init_object( obj, ops, name ))
|
|
||||||
{
|
{
|
||||||
free( obj );
|
set_object_name( obj, name_ptr );
|
||||||
return NULL;
|
clear_error();
|
||||||
}
|
}
|
||||||
CLEAR_ERROR();
|
else free( name_ptr );
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,25 +191,29 @@ void release_object( void *ptr )
|
||||||
else first = obj->next;
|
else first = obj->next;
|
||||||
#endif
|
#endif
|
||||||
obj->ops->destroy( obj );
|
obj->ops->destroy( obj );
|
||||||
|
memset( obj, 0xaa, obj->ops->size );
|
||||||
|
free( obj );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find an object by its name; the refcount is incremented */
|
/* 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;
|
struct object_name *ptr;
|
||||||
if (!name) return NULL;
|
if (!name || !len) return NULL;
|
||||||
ptr = names[ get_name_hash( name ) ];
|
for (ptr = names[ get_name_hash( name, len ) ]; ptr; ptr = ptr->next)
|
||||||
while (ptr && strcmp( ptr->name, name )) ptr = ptr->next;
|
{
|
||||||
if (!ptr) return NULL;
|
if (ptr->len != len) continue;
|
||||||
return grab_object( ptr->obj );
|
if (!memcmp( ptr->name, name, len )) return grab_object( ptr->obj );
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* functions for unimplemented object operations */
|
/* functions for unimplemented object operations */
|
||||||
|
|
||||||
int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
set_error( ERROR_INVALID_HANDLE );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,28 +224,32 @@ int no_satisfied( struct object *obj, struct thread *thread )
|
||||||
|
|
||||||
int no_read_fd( struct object *obj )
|
int no_read_fd( struct object *obj )
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
set_error( ERROR_INVALID_HANDLE );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int no_write_fd( struct object *obj )
|
int no_write_fd( struct object *obj )
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
set_error( ERROR_INVALID_HANDLE );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int no_flush( struct object *obj )
|
int no_flush( struct object *obj )
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_HANDLE );
|
set_error( ERROR_INVALID_HANDLE );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int no_get_file_info( struct object *obj, struct get_file_info_reply *info )
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void no_destroy( struct object *obj )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void default_select_event( int event, void *private )
|
void default_select_event( int event, void *private )
|
||||||
{
|
{
|
||||||
struct object *obj = (struct object *)private;
|
struct object *obj = (struct object *)private;
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "server/request.h"
|
|
||||||
|
|
||||||
#define DEBUG_OBJECTS
|
#define DEBUG_OBJECTS
|
||||||
|
|
||||||
|
@ -29,6 +28,8 @@ struct wait_queue_entry;
|
||||||
/* operations valid on all objects */
|
/* operations valid on all objects */
|
||||||
struct object_ops
|
struct object_ops
|
||||||
{
|
{
|
||||||
|
/* size of this object type */
|
||||||
|
size_t size;
|
||||||
/* dump the object (for debugging) */
|
/* dump the object (for debugging) */
|
||||||
void (*dump)(struct object *,int);
|
void (*dump)(struct object *,int);
|
||||||
/* add a thread to the object wait queue */
|
/* 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 *mem_alloc( size_t size ); /* malloc wrapper */
|
||||||
extern void *alloc_object( size_t size, const struct object_ops *ops, const char *name );
|
extern char *mem_strdup( const char *str );
|
||||||
extern struct object *create_named_object( const char *name, const struct object_ops *ops,
|
extern void *alloc_object( const struct object_ops *ops );
|
||||||
size_t size );
|
|
||||||
extern int init_object( struct object *obj, const struct object_ops *ops, const char *name );
|
|
||||||
extern const char *get_object_name( struct object *obj );
|
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 */
|
/* grab/release_object can take any pointer, but you better make sure */
|
||||||
/* that the thing pointed to starts with a struct object... */
|
/* that the thing pointed to starts with a struct object... */
|
||||||
extern struct object *grab_object( void *obj );
|
extern struct object *grab_object( void *obj );
|
||||||
extern void release_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_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
extern int no_satisfied( struct object *obj, struct thread *thread );
|
extern int no_satisfied( struct object *obj, struct thread *thread );
|
||||||
extern int no_read_fd( struct object *obj );
|
extern int no_read_fd( struct object *obj );
|
||||||
extern int no_write_fd( struct object *obj );
|
extern int no_write_fd( struct object *obj );
|
||||||
extern int no_flush( 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 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 );
|
extern void default_select_event( int event, void *private );
|
||||||
#ifdef DEBUG_OBJECTS
|
#ifdef DEBUG_OBJECTS
|
||||||
extern void dump_objects(void);
|
extern void dump_objects(void);
|
||||||
#endif
|
#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 */
|
/* select functions */
|
||||||
|
|
||||||
#define READ_EVENT 1
|
#define READ_EVENT 1
|
||||||
|
@ -143,8 +122,8 @@ struct client;
|
||||||
|
|
||||||
extern struct client *add_client( int client_fd, struct thread *self );
|
extern struct client *add_client( int client_fd, struct thread *self );
|
||||||
extern void remove_client( struct client *client, int exit_code );
|
extern void remove_client( struct client *client, int exit_code );
|
||||||
extern int send_reply_v( struct client *client, int type, int pass_fd,
|
extern void client_pass_fd( struct client *client, int pass_fd );
|
||||||
struct iovec *vec, int veclen );
|
extern void client_reply( struct client *client );
|
||||||
|
|
||||||
/* mutex functions */
|
/* mutex functions */
|
||||||
|
|
||||||
|
@ -156,6 +135,7 @@ extern struct file *get_file_obj( struct process *process, int handle,
|
||||||
unsigned int access );
|
unsigned int access );
|
||||||
extern int file_get_mmap_fd( struct file *file );
|
extern int file_get_mmap_fd( struct file *file );
|
||||||
extern int grow_file( struct file *file, int size_high, int size_low );
|
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 struct file *create_temp_file( int access );
|
||||||
extern void file_set_error(void);
|
extern void file_set_error(void);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
enum side { READ_SIDE, WRITE_SIDE };
|
enum side { READ_SIDE, WRITE_SIDE };
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ static void pipe_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops pipe_ops =
|
static const struct object_ops pipe_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct pipe),
|
||||||
pipe_dump,
|
pipe_dump,
|
||||||
pipe_add_queue,
|
pipe_add_queue,
|
||||||
pipe_remove_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] )
|
static int create_pipe( struct object *obj[2] )
|
||||||
{
|
{
|
||||||
struct pipe *newpipe[2];
|
struct pipe *read_pipe;
|
||||||
|
struct pipe *write_pipe;
|
||||||
int fd[2];
|
int fd[2];
|
||||||
|
|
||||||
if (pipe( fd ) == -1)
|
if (pipe( fd ) == -1)
|
||||||
|
@ -66,37 +85,21 @@ static int create_pipe( struct object *obj[2] )
|
||||||
file_set_error();
|
file_set_error();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!(newpipe[0] = mem_alloc( sizeof(struct pipe) )))
|
if ((read_pipe = create_pipe_side( fd[0], READ_SIDE )))
|
||||||
{
|
{
|
||||||
close( fd[0] );
|
if ((write_pipe = create_pipe_side( fd[1], WRITE_SIDE )))
|
||||||
close( fd[1] );
|
{
|
||||||
return 0;
|
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] );
|
||||||
close( fd[0] );
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pipe_dump( struct object *obj, int verbose )
|
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)
|
if (!pipe->other)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_BROKEN_PIPE );
|
set_error( ERROR_BROKEN_PIPE );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (pipe->side != READ_SIDE) /* FIXME: should not be necessary */
|
if (pipe->side != READ_SIDE) /* FIXME: should not be necessary */
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
set_error( ERROR_ACCESS_DENIED );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return dup( pipe->select.fd );
|
return dup( pipe->select.fd );
|
||||||
|
@ -175,12 +178,12 @@ static int pipe_get_write_fd( struct object *obj )
|
||||||
|
|
||||||
if (!pipe->other)
|
if (!pipe->other)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_BROKEN_PIPE );
|
set_error( ERROR_BROKEN_PIPE );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (pipe->side != WRITE_SIDE) /* FIXME: should not be necessary */
|
if (pipe->side != WRITE_SIDE) /* FIXME: should not be necessary */
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_ACCESS_DENIED );
|
set_error( ERROR_ACCESS_DENIED );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return dup( pipe->select.fd );
|
return dup( pipe->select.fd );
|
||||||
|
@ -201,7 +204,6 @@ static void pipe_destroy( struct object *obj )
|
||||||
if (pipe->other) pipe->other->other = NULL;
|
if (pipe->other) pipe->other->other = NULL;
|
||||||
unregister_select_user( &pipe->select );
|
unregister_select_user( &pipe->select );
|
||||||
close( pipe->select.fd );
|
close( pipe->select.fd );
|
||||||
free( pipe );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create an anonymous pipe */
|
/* create an anonymous pipe */
|
||||||
|
@ -225,5 +227,5 @@ DECL_HANDLER(create_pipe)
|
||||||
release_object( obj[0] );
|
release_object( obj[0] );
|
||||||
release_object( obj[1] );
|
release_object( obj[1] );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
add_reply_data( current, &reply, sizeof(reply) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winnt.h"
|
#include "winnt.h"
|
||||||
|
|
||||||
#include "server.h"
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
/* process structure */
|
/* process structure */
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ static void process_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops process_ops =
|
static const struct object_ops process_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct process),
|
||||||
process_dump,
|
process_dump,
|
||||||
add_queue,
|
add_queue,
|
||||||
remove_queue,
|
remove_queue,
|
||||||
|
@ -49,12 +50,12 @@ static const struct object_ops process_ops =
|
||||||
|
|
||||||
|
|
||||||
/* create a new process */
|
/* create a new process */
|
||||||
static struct process *create_process( struct process *parent,
|
static struct process *create_process( struct process *parent, struct new_process_request *req,
|
||||||
struct new_process_request *req, const char *cmd_line )
|
const char *cmd_line, size_t len )
|
||||||
{
|
{
|
||||||
struct process *process;
|
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->next = NULL;
|
||||||
process->prev = NULL;
|
process->prev = NULL;
|
||||||
process->thread_list = 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 a handle for the process itself */
|
||||||
alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
|
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) );
|
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 */
|
/* set the process console */
|
||||||
if (req->create_flags & CREATE_NEW_CONSOLE)
|
if (req->create_flags & CREATE_NEW_CONSOLE)
|
||||||
|
@ -139,7 +141,7 @@ struct process *create_initial_process(void)
|
||||||
req.hstderr = -1;
|
req.hstderr = -1;
|
||||||
req.cmd_show = 0;
|
req.cmd_show = 0;
|
||||||
req.env_ptr = NULL;
|
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,
|
process->info->hstdin = alloc_handle( process, process->console_in,
|
||||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
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;
|
if (process->prev) process->prev->next = process->next;
|
||||||
else first_process = process->next;
|
else first_process = process->next;
|
||||||
if (process->info) free( process->info );
|
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 */
|
/* 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;
|
struct process *p = first_process;
|
||||||
while (p && (p != id)) p = p->next;
|
while (p && (p != id)) p = p->next;
|
||||||
if (p) grab_object( p );
|
if (p) grab_object( p );
|
||||||
else SET_ERROR( ERROR_INVALID_PARAMETER );
|
else set_error( ERROR_INVALID_PARAMETER );
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ static void set_process_info( struct process *process,
|
||||||
process->priority = req->priority;
|
process->priority = req->priority;
|
||||||
if (req->mask & SET_PROCESS_INFO_AFFINITY)
|
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;
|
else process->affinity = req->affinity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,33 +333,31 @@ struct process_snapshot *process_snap( int *count )
|
||||||
/* create a new process */
|
/* create a new process */
|
||||||
DECL_HANDLER(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;
|
struct process *process;
|
||||||
char *cmd_line = (char *)data;
|
|
||||||
|
|
||||||
CHECK_STRING( "new_process", cmd_line, len );
|
if ((process = create_process( current->process, req, get_req_data( len + 1 ), len )))
|
||||||
if ((process = create_process( current->process, req, cmd_line )))
|
|
||||||
{
|
{
|
||||||
reply.pid = process;
|
reply->handle = alloc_handle( current->process, process,
|
||||||
reply.handle = alloc_handle( current->process, process,
|
PROCESS_ALL_ACCESS, req->inherit );
|
||||||
PROCESS_ALL_ACCESS, req->inherit );
|
reply->pid = process;
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reply.handle = -1;
|
reply->handle = -1;
|
||||||
reply.pid = NULL;
|
reply->pid = NULL;
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize a new process */
|
/* initialize a new process */
|
||||||
DECL_HANDLER(init_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;
|
struct new_process_request *info;
|
||||||
|
|
||||||
if (current->state != RUNNING)
|
if (current->state == STARTING)
|
||||||
{
|
{
|
||||||
fatal_protocol_error( "init_process: init_thread not called yet\n" );
|
fatal_protocol_error( "init_process: init_thread not called yet\n" );
|
||||||
return;
|
return;
|
||||||
|
@ -370,29 +368,27 @@ DECL_HANDLER(init_process)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
current->process->info = NULL;
|
current->process->info = NULL;
|
||||||
reply.start_flags = info->start_flags;
|
reply->start_flags = info->start_flags;
|
||||||
reply.hstdin = info->hstdin;
|
reply->hstdin = info->hstdin;
|
||||||
reply.hstdout = info->hstdout;
|
reply->hstdout = info->hstdout;
|
||||||
reply.hstderr = info->hstderr;
|
reply->hstderr = info->hstderr;
|
||||||
reply.cmd_show = info->cmd_show;
|
reply->cmd_show = info->cmd_show;
|
||||||
reply.env_ptr = info->env_ptr;
|
reply->env_ptr = info->env_ptr;
|
||||||
send_reply( current, -1, 2, &reply, sizeof(reply),
|
add_reply_data( current, info->cmd_line, strlen(info->cmd_line) + 1 );
|
||||||
info->cmd_line, strlen(info->cmd_line) + 1 );
|
|
||||||
free( info );
|
free( info );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open a handle to a process */
|
/* open a handle to a process */
|
||||||
DECL_HANDLER(open_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 );
|
struct process *process = get_process_from_id( req->pid );
|
||||||
if (process)
|
if (process)
|
||||||
{
|
{
|
||||||
reply.handle = alloc_handle( current->process, process,
|
reply->handle = alloc_handle( current->process, process, req->access, req->inherit );
|
||||||
req->access, req->inherit );
|
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
else reply->handle = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* terminate a process */
|
/* terminate a process */
|
||||||
|
@ -405,21 +401,19 @@ DECL_HANDLER(terminate_process)
|
||||||
kill_process( process, req->exit_code );
|
kill_process( process, req->exit_code );
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
if (current) send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fetch information about a process */
|
/* fetch information about a process */
|
||||||
DECL_HANDLER(get_process_info)
|
DECL_HANDLER(get_process_info)
|
||||||
{
|
{
|
||||||
struct process *process;
|
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 )))
|
if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
|
||||||
{
|
{
|
||||||
get_process_info( process, &reply );
|
get_process_info( process, reply );
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set information about a process */
|
/* set information about a process */
|
||||||
|
@ -432,5 +426,4 @@ DECL_HANDLER(set_process_info)
|
||||||
set_process_info( process, req );
|
set_process_info( process, req );
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,54 +18,63 @@
|
||||||
#include "winnt.h"
|
#include "winnt.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "wincon.h"
|
#include "wincon.h"
|
||||||
#define WANT_REQUEST_HANDLERS
|
|
||||||
#include "server.h"
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "server.h"
|
||||||
|
#define WANT_REQUEST_HANDLERS
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct thread *current = NULL; /* thread handling the current request */
|
struct thread *current = NULL; /* thread handling the current request */
|
||||||
|
|
||||||
/* complain about a protocol error and terminate the client connection */
|
/* 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: %s\n request:", current, err );
|
||||||
fprintf( stderr, "Protocol error:%p: ", current );
|
for (p = (unsigned char *)current->buffer; p < (unsigned char *)current->req_end; p++)
|
||||||
vfprintf( stderr, err, args );
|
fprintf( stderr, " %02x", *p );
|
||||||
va_end( args );
|
fprintf( stderr, "\n" );
|
||||||
remove_client( current->client, -2 );
|
remove_client( current->client, -2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call a request handler */
|
/* call a request handler */
|
||||||
void call_req_handler( struct thread *thread, enum request req,
|
void call_req_handler( struct thread *thread, int fd )
|
||||||
void *data, int len, int fd )
|
|
||||||
{
|
{
|
||||||
const struct handler *handler = &req_handlers[req];
|
const struct handler *handler;
|
||||||
char *ptr;
|
struct header *head;
|
||||||
|
unsigned int req, len;
|
||||||
|
|
||||||
current = thread;
|
current = thread;
|
||||||
if ((req < 0) || (req >= REQ_NB_REQUESTS))
|
assert (current);
|
||||||
{
|
|
||||||
fatal_protocol_error( "unknown request %d\n", req );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < handler->min_size)
|
head = (struct header *)current->buffer;
|
||||||
{
|
|
||||||
fatal_protocol_error( "req %d bad length %d < %d\n", req, len, handler->min_size );
|
req = head->type;
|
||||||
return;
|
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 */
|
/* now call the handler */
|
||||||
if (current)
|
handler = &req_handlers[req];
|
||||||
{
|
if (!check_req_data( handler->min_size )) goto bad_request;
|
||||||
CLEAR_ERROR();
|
handler->handler( get_req_data( handler->min_size ), fd );
|
||||||
if (debug_level) trace_request( req, data, len, fd );
|
if (current && current->state != SLEEPING) send_reply( current );
|
||||||
}
|
|
||||||
len -= handler->min_size;
|
|
||||||
ptr = (char *)data + handler->min_size;
|
|
||||||
handler->handler( data, ptr, len, fd );
|
|
||||||
current = NULL;
|
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 */
|
/* handle a client timeout */
|
||||||
|
@ -73,7 +82,7 @@ void call_timeout_handler( void *thread )
|
||||||
{
|
{
|
||||||
current = (struct thread *)thread;
|
current = (struct thread *)thread;
|
||||||
if (debug_level) trace_timeout();
|
if (debug_level) trace_timeout();
|
||||||
CLEAR_ERROR();
|
clear_error();
|
||||||
thread_timeout();
|
thread_timeout();
|
||||||
current = NULL;
|
current = NULL;
|
||||||
}
|
}
|
||||||
|
@ -92,14 +101,32 @@ void call_kill_handler( struct thread *thread, int exit_code )
|
||||||
current = (old_current != thread) ? old_current : NULL;
|
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 */
|
/* set the debug level */
|
||||||
DECL_HANDLER(set_debug)
|
DECL_HANDLER(set_debug)
|
||||||
{
|
{
|
||||||
debug_level = req->level;
|
debug_level = req->level;
|
||||||
/* Make sure last_req is initialized */
|
/* Make sure last_req is initialized */
|
||||||
current->last_req = REQ_SET_DEBUG;
|
current->last_req = REQ_SET_DEBUG;
|
||||||
CLEAR_ERROR();
|
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* debugger support operations */
|
/* debugger support operations */
|
||||||
|
@ -115,6 +142,4 @@ DECL_HANDLER(debugger)
|
||||||
resume_all_threads();
|
resume_all_threads();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
#ifndef __WINE_SERVER_REQUEST_H
|
||||||
#define __WINE_SERVER_REQUEST_H
|
#define __WINE_SERVER_REQUEST_H
|
||||||
|
|
||||||
enum request
|
#ifndef __WINE_SERVER__
|
||||||
{
|
#error This file can only be used in the Wine server
|
||||||
REQ_NEW_PROCESS,
|
#endif
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
#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_process);
|
||||||
DECL_HANDLER(new_thread);
|
DECL_HANDLER(new_thread);
|
||||||
|
@ -135,8 +139,10 @@ DECL_HANDLER(send_debug_event);
|
||||||
DECL_HANDLER(continue_debug_event);
|
DECL_HANDLER(continue_debug_event);
|
||||||
DECL_HANDLER(debug_process);
|
DECL_HANDLER(debug_process);
|
||||||
|
|
||||||
|
#ifdef WANT_REQUEST_HANDLERS
|
||||||
|
|
||||||
static const struct handler {
|
static const struct handler {
|
||||||
void (*handler)();
|
void (*handler)( void *req, int fd );
|
||||||
unsigned int min_size;
|
unsigned int min_size;
|
||||||
} req_handlers[REQ_NB_REQUESTS] = {
|
} req_handlers[REQ_NB_REQUESTS] = {
|
||||||
{ (void(*)())req_new_process, sizeof(struct new_process_request) },
|
{ (void(*)())req_new_process, sizeof(struct new_process_request) },
|
||||||
|
@ -204,4 +210,7 @@ static const struct handler {
|
||||||
};
|
};
|
||||||
#endif /* WANT_REQUEST_HANDLERS */
|
#endif /* WANT_REQUEST_HANDLERS */
|
||||||
|
|
||||||
|
/* ### make_requests end ### */
|
||||||
|
/* Everything above this line is generated automatically by tools/make_requests */
|
||||||
|
|
||||||
#endif /* __WINE_SERVER_REQUEST_H */
|
#endif /* __WINE_SERVER_REQUEST_H */
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
struct semaphore
|
struct semaphore
|
||||||
{
|
{
|
||||||
|
@ -24,10 +25,10 @@ struct semaphore
|
||||||
static void semaphore_dump( struct object *obj, int verbose );
|
static void semaphore_dump( struct object *obj, int verbose );
|
||||||
static int semaphore_signaled( struct object *obj, struct thread *thread );
|
static int semaphore_signaled( struct object *obj, struct thread *thread );
|
||||||
static int semaphore_satisfied( 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 =
|
static const struct object_ops semaphore_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct semaphore),
|
||||||
semaphore_dump,
|
semaphore_dump,
|
||||||
add_queue,
|
add_queue,
|
||||||
remove_queue,
|
remove_queue,
|
||||||
|
@ -37,45 +38,46 @@ static const struct object_ops semaphore_ops =
|
||||||
no_write_fd,
|
no_write_fd,
|
||||||
no_flush,
|
no_flush,
|
||||||
no_get_file_info,
|
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;
|
struct semaphore *sem;
|
||||||
|
|
||||||
if (!max || (initial > max))
|
if (!max || (initial > max))
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_PARAMETER );
|
set_error( ERROR_INVALID_PARAMETER );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(sem = (struct semaphore *)create_named_object( name, &semaphore_ops, sizeof(*sem) )))
|
if ((sem = create_named_object( &semaphore_ops, name, len )))
|
||||||
return NULL;
|
|
||||||
if (GET_ERROR() != ERROR_ALREADY_EXISTS)
|
|
||||||
{
|
{
|
||||||
/* initialize it if it didn't already exist */
|
if (get_error() != ERROR_ALREADY_EXISTS)
|
||||||
sem->count = initial;
|
{
|
||||||
sem->max = max;
|
/* 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;
|
struct semaphore *sem;
|
||||||
|
|
||||||
if (!(sem = (struct semaphore *)get_handle_obj( current->process, handle,
|
if (!(sem = (struct semaphore *)get_handle_obj( current->process, handle,
|
||||||
SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
|
SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
*prev_count = sem->count;
|
*prev_count = sem->count;
|
||||||
if (sem->count + count < sem->count || sem->count + count > sem->max)
|
if (sem->count + count < sem->count || sem->count + count > sem->max)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_TOO_MANY_POSTS );
|
set_error( ERROR_TOO_MANY_POSTS );
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (sem->count)
|
else if (sem->count)
|
||||||
{
|
{
|
||||||
/* there cannot be any thread waiting if the count is != 0 */
|
/* there cannot be any thread waiting if the count is != 0 */
|
||||||
assert( !sem->obj.head );
|
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 );
|
wake_up( &sem->obj, count );
|
||||||
}
|
}
|
||||||
release_object( sem );
|
release_object( sem );
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void semaphore_dump( struct object *obj, int verbose )
|
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 */
|
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 */
|
/* create a semaphore */
|
||||||
DECL_HANDLER(create_semaphore)
|
DECL_HANDLER(create_semaphore)
|
||||||
{
|
{
|
||||||
struct create_semaphore_reply reply = { -1 };
|
size_t len = get_req_strlen();
|
||||||
struct object *obj;
|
struct create_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
char *name = (char *)data;
|
struct semaphore *sem;
|
||||||
if (!len) name = NULL;
|
|
||||||
else CHECK_STRING( "create_semaphore", name, len );
|
|
||||||
|
|
||||||
obj = create_semaphore( name, req->initial, req->max );
|
if ((sem = create_semaphore( get_req_data( len + 1 ), len, req->initial, req->max )))
|
||||||
if (obj)
|
|
||||||
{
|
{
|
||||||
reply.handle = alloc_handle( current->process, obj, SEMAPHORE_ALL_ACCESS, req->inherit );
|
reply->handle = alloc_handle( current->process, sem, SEMAPHORE_ALL_ACCESS, req->inherit );
|
||||||
release_object( obj );
|
release_object( sem );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
else reply->handle = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open a handle to a semaphore */
|
/* open a handle to a semaphore */
|
||||||
DECL_HANDLER(open_semaphore)
|
DECL_HANDLER(open_semaphore)
|
||||||
{
|
{
|
||||||
struct open_semaphore_reply reply;
|
size_t len = get_req_strlen();
|
||||||
char *name = (char *)data;
|
struct open_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
if (!len) name = NULL;
|
reply->handle = open_object( get_req_data( len + 1 ), len, &semaphore_ops,
|
||||||
else CHECK_STRING( "open_semaphore", name, len );
|
req->access, req->inherit );
|
||||||
|
|
||||||
reply.handle = open_object( name, &semaphore_ops, req->access, req->inherit );
|
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* release a semaphore */
|
/* release a semaphore */
|
||||||
DECL_HANDLER(release_semaphore)
|
DECL_HANDLER(release_semaphore)
|
||||||
{
|
{
|
||||||
struct release_semaphore_reply reply;
|
struct release_semaphore_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
if (release_semaphore( req->handle, req->count, &reply.prev_count )) CLEAR_ERROR();
|
release_semaphore( req->handle, req->count, &reply->prev_count );
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
|
|
||||||
struct snapshot
|
struct snapshot
|
||||||
|
@ -32,6 +33,7 @@ static void snapshot_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops snapshot_ops =
|
static const struct object_ops snapshot_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct snapshot),
|
||||||
snapshot_dump,
|
snapshot_dump,
|
||||||
no_add_queue,
|
no_add_queue,
|
||||||
NULL, /* should never get called */
|
NULL, /* should never get called */
|
||||||
|
@ -46,18 +48,19 @@ static const struct object_ops snapshot_ops =
|
||||||
|
|
||||||
|
|
||||||
/* create a new snapshot */
|
/* create a new snapshot */
|
||||||
static struct object *create_snapshot( int flags )
|
static struct snapshot *create_snapshot( int flags )
|
||||||
{
|
{
|
||||||
struct snapshot *snapshot;
|
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;
|
if ((snapshot = alloc_object( &snapshot_ops )))
|
||||||
return &snapshot->obj;
|
{
|
||||||
|
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 */
|
/* 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;
|
return 0;
|
||||||
if (!snapshot->process_count)
|
if (!snapshot->process_count)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_PARAMETER ); /* FIXME */
|
set_error( ERROR_INVALID_PARAMETER ); /* FIXME */
|
||||||
release_object( snapshot );
|
release_object( snapshot );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (reset) snapshot->process_pos = 0;
|
if (reset) snapshot->process_pos = 0;
|
||||||
else if (snapshot->process_pos >= snapshot->process_count)
|
else if (snapshot->process_pos >= snapshot->process_count)
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_NO_MORE_FILES );
|
set_error( ERROR_NO_MORE_FILES );
|
||||||
release_object( snapshot );
|
release_object( snapshot );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -108,27 +111,25 @@ static void snapshot_destroy( struct object *obj )
|
||||||
release_object( snapshot->process[i].process );
|
release_object( snapshot->process[i].process );
|
||||||
free( snapshot->process );
|
free( snapshot->process );
|
||||||
}
|
}
|
||||||
free( snapshot );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a snapshot */
|
/* create a snapshot */
|
||||||
DECL_HANDLER(create_snapshot)
|
DECL_HANDLER(create_snapshot)
|
||||||
{
|
{
|
||||||
struct object *obj;
|
struct snapshot *snapshot;
|
||||||
struct create_snapshot_reply reply = { -1 };
|
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 );
|
reply->handle = alloc_handle( current->process, snapshot, 0, req->inherit );
|
||||||
release_object( obj );
|
release_object( snapshot );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
else reply->handle = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the next process from a snapshot */
|
/* get the next process from a snapshot */
|
||||||
DECL_HANDLER(next_process)
|
DECL_HANDLER(next_process)
|
||||||
{
|
{
|
||||||
struct next_process_reply reply;
|
struct next_process_reply *reply = push_reply_data( current, sizeof(*reply) );
|
||||||
snapshot_next_process( req->handle, req->reset, &reply );
|
snapshot_next_process( req->handle, req->reset, reply );
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
269
server/socket.c
269
server/socket.c
|
@ -18,32 +18,19 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "server.h"
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
/* Some versions of glibc don't define this */
|
/* Some versions of glibc don't define this */
|
||||||
#ifndef SCM_RIGHTS
|
#ifndef SCM_RIGHTS
|
||||||
#define SCM_RIGHTS 1
|
#define SCM_RIGHTS 1
|
||||||
#endif
|
#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 */
|
/* client structure */
|
||||||
struct client
|
struct client
|
||||||
{
|
{
|
||||||
enum state state; /* client state */
|
|
||||||
struct select_user select; /* select user */
|
struct select_user select; /* select user */
|
||||||
unsigned int seq; /* current sequence number */
|
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 */
|
int pass_fd; /* fd to pass to and from the client */
|
||||||
struct thread *self; /* client thread (opaque pointer) */
|
struct thread *self; /* client thread (opaque pointer) */
|
||||||
struct timeout_user *timeout; /* current timeout (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_list args;
|
||||||
|
|
||||||
va_start( args, err );
|
va_start( args, err );
|
||||||
fprintf( stderr, "Protocol error:%d: ", client->select.fd );
|
fprintf( stderr, "Protocol error:%p: ", client->self );
|
||||||
vfprintf( stderr, err, args );
|
vfprintf( stderr, err, args );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
remove_client( client, PROTOCOL_ERROR );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send a message to a client that is ready to receive something */
|
/* 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;
|
int ret;
|
||||||
|
|
||||||
/* make sure we have something to send */
|
if (client->pass_fd == -1)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
vec[0].iov_base = (char *)&client->head + client->count;
|
ret = write( client->select.fd, &client->seq, sizeof(client->seq) );
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else
|
else /* we have an fd to send */
|
||||||
{
|
{
|
||||||
vec[0].iov_base = client->data + client->count - sizeof(client->head);
|
struct iovec vec;
|
||||||
vec[0].iov_len = client->head.len - client->count;
|
struct msghdr msghdr;
|
||||||
msghdr.msg_iovlen = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
||||||
if (client->pass_fd != -1) /* we have an fd to send */
|
|
||||||
{
|
|
||||||
msghdr.msg_accrights = (void *)&client->pass_fd;
|
msghdr.msg_accrights = (void *)&client->pass_fd;
|
||||||
msghdr.msg_accrightslen = sizeof(client->pass_fd);
|
msghdr.msg_accrightslen = sizeof(client->pass_fd);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msghdr.msg_accrights = NULL;
|
|
||||||
msghdr.msg_accrightslen = 0;
|
|
||||||
}
|
|
||||||
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
if (client->pass_fd != -1) /* we have an fd to send */
|
struct cmsg_fd cmsg;
|
||||||
{
|
|
||||||
cmsg.len = sizeof(cmsg);
|
cmsg.len = sizeof(cmsg);
|
||||||
cmsg.level = SOL_SOCKET;
|
cmsg.level = SOL_SOCKET;
|
||||||
cmsg.type = SCM_RIGHTS;
|
cmsg.type = SCM_RIGHTS;
|
||||||
cmsg.fd = client->pass_fd;
|
cmsg.fd = client->pass_fd;
|
||||||
msghdr.msg_control = &cmsg;
|
msghdr.msg_control = &cmsg;
|
||||||
msghdr.msg_controllen = sizeof(cmsg);
|
msghdr.msg_controllen = sizeof(cmsg);
|
||||||
}
|
msghdr.msg_flags = 0;
|
||||||
else
|
|
||||||
{
|
|
||||||
msghdr.msg_control = NULL;
|
|
||||||
msghdr.msg_controllen = 0;
|
|
||||||
}
|
|
||||||
msghdr.msg_flags = 0;
|
|
||||||
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
#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 (ret == -1)
|
||||||
{
|
{
|
||||||
if (errno != EPIPE) perror("sendmsg");
|
if (errno != EPIPE) perror("sendmsg");
|
||||||
remove_client( client, BROKEN_PIPE );
|
remove_client( client, BROKEN_PIPE );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (client->pass_fd != -1) /* We sent the fd, now we can close it */
|
fprintf( stderr, "Partial sequence sent (%d)\n", ret );
|
||||||
{
|
remove_client( client, BROKEN_PIPE );
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* read a message from a client that has something to say */
|
/* 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;
|
struct iovec vec;
|
||||||
int pass_fd = -1;
|
int ret, seq;
|
||||||
int ret;
|
|
||||||
|
|
||||||
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
||||||
struct msghdr msghdr;
|
struct msghdr msghdr;
|
||||||
|
|
||||||
msghdr.msg_accrights = (void *)&pass_fd;
|
msghdr.msg_accrights = (void *)&client->pass_fd;
|
||||||
msghdr.msg_accrightslen = sizeof(int);
|
msghdr.msg_accrightslen = sizeof(client->pass_fd);
|
||||||
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
struct msghdr msghdr;
|
struct msghdr msghdr;
|
||||||
struct cmsg_fd cmsg;
|
struct cmsg_fd cmsg;
|
||||||
|
@ -179,109 +137,57 @@ static void do_read( struct client *client, int client_fd )
|
||||||
msghdr.msg_flags = 0;
|
msghdr.msg_flags = 0;
|
||||||
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
|
|
||||||
|
assert( client->pass_fd == -1 );
|
||||||
|
|
||||||
msghdr.msg_name = NULL;
|
msghdr.msg_name = NULL;
|
||||||
msghdr.msg_namelen = 0;
|
msghdr.msg_namelen = 0;
|
||||||
msghdr.msg_iov = &vec;
|
msghdr.msg_iov = &vec;
|
||||||
msghdr.msg_iovlen = 1;
|
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;
|
int pass_fd = client->pass_fd;
|
||||||
vec.iov_len = sizeof(client->head) - client->count;
|
if (seq != client->seq++)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!client->data &&
|
|
||||||
!(client->data = malloc(client->head.len-sizeof(client->head))))
|
|
||||||
{
|
{
|
||||||
remove_client( client, OUT_OF_MEMORY );
|
protocol_error( client, "bad sequence %08x instead of %08x\n",
|
||||||
|
seq, client->seq - 1 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vec.iov_base = client->data + client->count - sizeof(client->head);
|
client->pass_fd = -1;
|
||||||
vec.iov_len = client->head.len - client->count;
|
call_req_handler( client->self, pass_fd );
|
||||||
|
if (pass_fd != -1) close( pass_fd );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = recvmsg( client_fd, &msghdr, 0 );
|
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
perror("recvmsg");
|
perror("recvmsg");
|
||||||
remove_client( client, BROKEN_PIPE );
|
remove_client( client, BROKEN_PIPE );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifndef HAVE_MSGHDR_ACCRIGHTS
|
if (!ret) /* closed pipe */
|
||||||
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 */
|
|
||||||
{
|
{
|
||||||
remove_client( client, BROKEN_PIPE );
|
remove_client( client, BROKEN_PIPE );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
protocol_error( client, "partial sequence received %d/%d\n", ret, sizeof(seq) );
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle a client event */
|
/* handle a client event */
|
||||||
static void client_event( int event, void *private )
|
static void client_event( int event, void *private )
|
||||||
{
|
{
|
||||||
struct client *client = (struct client *)private;
|
struct client *client = (struct client *)private;
|
||||||
if (event & WRITE_EVENT) do_write( client, client->select.fd );
|
if (event & WRITE_EVENT) do_write( client );
|
||||||
if (event & READ_EVENT) do_read( client, client->select.fd );
|
if (event & READ_EVENT) do_read( client );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/* server-side exported functions */
|
/* server-side exported functions */
|
||||||
|
|
||||||
|
@ -295,15 +201,10 @@ struct client *add_client( int fd, struct thread *self )
|
||||||
flags = fcntl( fd, F_GETFL, 0 );
|
flags = fcntl( fd, F_GETFL, 0 );
|
||||||
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
|
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
|
||||||
|
|
||||||
client->state = RUNNING;
|
|
||||||
client->select.fd = fd;
|
client->select.fd = fd;
|
||||||
client->select.func = client_event;
|
client->select.func = client_event;
|
||||||
client->select.private = client;
|
client->select.private = client;
|
||||||
client->seq = 0;
|
client->seq = 0;
|
||||||
client->head.len = 0;
|
|
||||||
client->head.type = 0;
|
|
||||||
client->count = 0;
|
|
||||||
client->data = NULL;
|
|
||||||
client->self = self;
|
client->self = self;
|
||||||
client->timeout = NULL;
|
client->timeout = NULL;
|
||||||
client->pass_fd = -1;
|
client->pass_fd = -1;
|
||||||
|
@ -324,42 +225,20 @@ void remove_client( struct client *client, int exit_code )
|
||||||
close( client->select.fd );
|
close( client->select.fd );
|
||||||
|
|
||||||
/* Purge messages */
|
/* Purge messages */
|
||||||
if (client->data) free( client->data );
|
|
||||||
if (client->pass_fd != -1) close( client->pass_fd );
|
if (client->pass_fd != -1) close( client->pass_fd );
|
||||||
free( client );
|
free( client );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send a reply to a client */
|
/* set the fd to pass to the client */
|
||||||
int send_reply_v( struct client *client, int type, int pass_fd,
|
void client_pass_fd( struct client *client, int pass_fd )
|
||||||
struct iovec *vec, int veclen )
|
|
||||||
{
|
{
|
||||||
int i;
|
assert( client->pass_fd == -1 );
|
||||||
unsigned int len;
|
client->pass_fd = pass_fd;
|
||||||
char *p;
|
}
|
||||||
|
|
||||||
assert( client );
|
/* send a reply to a client */
|
||||||
assert( client->state == WAITING );
|
void client_reply( struct client *client )
|
||||||
assert( !client->data );
|
{
|
||||||
|
if (debug_level) trace_reply( client->self, client->pass_fd );
|
||||||
if (debug_level) trace_reply( client->self, type, pass_fd, vec, veclen );
|
set_select_events( &client->select, WRITE_EVENT );
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
220
server/thread.c
220
server/thread.c
|
@ -10,6 +10,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -20,9 +21,9 @@
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "server.h"
|
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
|
|
||||||
/* thread queues */
|
/* thread queues */
|
||||||
|
@ -62,6 +63,7 @@ static void destroy_thread( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops thread_ops =
|
static const struct object_ops thread_ops =
|
||||||
{
|
{
|
||||||
|
sizeof(struct thread),
|
||||||
dump_thread,
|
dump_thread,
|
||||||
add_queue,
|
add_queue,
|
||||||
remove_queue,
|
remove_queue,
|
||||||
|
@ -76,10 +78,32 @@ static const struct object_ops thread_ops =
|
||||||
|
|
||||||
static struct thread *first_thread;
|
static struct thread *first_thread;
|
||||||
|
|
||||||
/* initialization of a thread structure */
|
/* allocate the buffer for the communication with the client */
|
||||||
static void init_thread( struct thread *thread, int fd )
|
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->client = NULL;
|
||||||
thread->unix_pid = 0; /* not known yet */
|
thread->unix_pid = 0; /* not known yet */
|
||||||
thread->teb = NULL;
|
thread->teb = NULL;
|
||||||
|
@ -97,61 +121,46 @@ static void init_thread( struct thread *thread, int fd )
|
||||||
thread->prev = NULL;
|
thread->prev = NULL;
|
||||||
thread->priority = THREAD_PRIORITY_NORMAL;
|
thread->priority = THREAD_PRIORITY_NORMAL;
|
||||||
thread->affinity = 1;
|
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 */
|
if (!first_thread) /* creating the first thread */
|
||||||
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 )))
|
|
||||||
{
|
{
|
||||||
free( thread );
|
current = thread;
|
||||||
return NULL;
|
thread->process = process = create_initial_process();
|
||||||
|
assert( process );
|
||||||
}
|
}
|
||||||
init_thread( thread, fd );
|
else thread->process = (struct process *)grab_object( process );
|
||||||
thread->process = process;
|
|
||||||
|
|
||||||
if (suspend) thread->suspend++;
|
|
||||||
|
|
||||||
if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
|
if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
|
||||||
first_thread = thread;
|
first_thread = thread;
|
||||||
add_process_thread( process, thread );
|
add_process_thread( process, thread );
|
||||||
|
|
||||||
if ((*handle = alloc_handle( current->process, thread,
|
if ((buf_fd = alloc_client_buffer( thread )) == -1) goto error;
|
||||||
THREAD_ALL_ACCESS, inherit )) == -1) goto error;
|
|
||||||
if (!(thread->client = add_client( fd, thread )))
|
if (!(thread->client = add_client( fd, thread )))
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
|
close( buf_fd );
|
||||||
goto error;
|
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;
|
return thread;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
close_handle( current->process, *handle );
|
|
||||||
remove_process_thread( process, thread );
|
remove_process_thread( process, thread );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
return NULL;
|
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 */
|
/* destroy a thread when its refcount is 0 */
|
||||||
static void destroy_thread( struct object *obj )
|
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;
|
if (thread->prev) thread->prev->next = thread->next;
|
||||||
else first_thread = thread->next;
|
else first_thread = thread->next;
|
||||||
if (thread->apc) free( thread->apc );
|
if (thread->apc) free( thread->apc );
|
||||||
if (debug_level) memset( thread, 0xaa, sizeof(thread) ); /* catch errors */
|
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_MSG_LENGTH );
|
||||||
free( thread );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dump a thread on stdout for debugging purposes */
|
/* dump a thread on stdout for debugging purposes */
|
||||||
|
@ -208,7 +216,7 @@ static void set_thread_info( struct thread *thread,
|
||||||
thread->priority = req->priority;
|
thread->priority = req->priority;
|
||||||
if (req->mask & SET_THREAD_INFO_AFFINITY)
|
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;
|
else thread->affinity = req->affinity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,25 +267,6 @@ void resume_all_threads( void )
|
||||||
resume_thread( thread );
|
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 */
|
/* 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 )
|
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))
|
if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS))
|
||||||
{
|
{
|
||||||
SET_ERROR( ERROR_INVALID_PARAMETER );
|
set_error( ERROR_INVALID_PARAMETER );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!(wait = mem_alloc( sizeof(*wait) + (count-1) * sizeof(*entry) ))) 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send the select reply to wake up the client */
|
/* build a select reply to wake up the client */
|
||||||
static void send_select_reply( struct thread *thread, int signaled )
|
static void build_select_reply( struct thread *thread, int signaled )
|
||||||
{
|
{
|
||||||
struct select_reply reply;
|
struct select_reply *reply = push_reply_data( thread, sizeof(*reply) );
|
||||||
reply.signaled = signaled;
|
reply->signaled = signaled;
|
||||||
if ((signaled == STATUS_USER_APC) && thread->apc)
|
if ((signaled == STATUS_USER_APC) && thread->apc)
|
||||||
{
|
{
|
||||||
struct thread_apc *apc = thread->apc;
|
add_reply_data( thread, thread->apc, thread->apc_count * sizeof(*thread->apc) );
|
||||||
int len = thread->apc_count * sizeof(*apc);
|
free( thread->apc );
|
||||||
thread->apc = NULL;
|
thread->apc = NULL;
|
||||||
thread->apc_count = 0;
|
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 */
|
/* attempt to wake up a thread */
|
||||||
|
@ -441,7 +426,7 @@ static int wake_thread( struct thread *thread )
|
||||||
|
|
||||||
if (!check_wait( thread, &signaled )) return 0;
|
if (!check_wait( thread, &signaled )) return 0;
|
||||||
end_wait( thread );
|
end_wait( thread );
|
||||||
send_select_reply( thread, signaled );
|
build_select_reply( thread, signaled );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,8 +436,7 @@ static void sleep_on( struct thread *thread, int count, int *handles, int flags,
|
||||||
assert( !thread->wait );
|
assert( !thread->wait );
|
||||||
if (!wait_on( thread, count, handles, flags, timeout ))
|
if (!wait_on( thread, count, handles, flags, timeout ))
|
||||||
{
|
{
|
||||||
/* return an error */
|
build_select_reply( thread, -1 );
|
||||||
send_select_reply( thread, -1 );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (wake_thread( thread )) 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,
|
if (!(thread->wait->user = add_timeout_user( &thread->wait->timeout,
|
||||||
call_timeout_handler, thread )))
|
call_timeout_handler, thread )))
|
||||||
{
|
{
|
||||||
send_select_reply( thread, -1 );
|
build_select_reply( thread, -1 );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
thread->state = SLEEPING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* timeout for the current thread */
|
/* timeout for the current thread */
|
||||||
|
@ -473,7 +459,8 @@ void thread_timeout(void)
|
||||||
assert( current->wait );
|
assert( current->wait );
|
||||||
current->wait->user = NULL;
|
current->wait->user = NULL;
|
||||||
end_wait( current );
|
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 */
|
/* attempt to wake threads sleeping on the object wait queue */
|
||||||
|
@ -483,12 +470,13 @@ void wake_up( struct object *obj, int max )
|
||||||
|
|
||||||
while (entry)
|
while (entry)
|
||||||
{
|
{
|
||||||
struct wait_queue_entry *next = entry->next;
|
struct thread *thread = entry->thread;
|
||||||
if (wake_thread( entry->thread ))
|
entry = entry->next;
|
||||||
|
if (wake_thread( thread ))
|
||||||
{
|
{
|
||||||
|
send_reply( thread );
|
||||||
if (max && !--max) break;
|
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].func = func;
|
||||||
thread->apc[thread->apc_count].param = param;
|
thread->apc[thread->apc_count].param = param;
|
||||||
thread->apc_count++;
|
thread->apc_count++;
|
||||||
if (thread->wait) wake_thread( thread );
|
if (thread->wait)
|
||||||
|
{
|
||||||
|
if (wake_thread( thread )) send_reply( thread );
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,24 +526,34 @@ void thread_killed( struct thread *thread, int exit_code )
|
||||||
DECL_HANDLER(new_thread)
|
DECL_HANDLER(new_thread)
|
||||||
{
|
{
|
||||||
struct new_thread_reply reply;
|
struct new_thread_reply reply;
|
||||||
|
struct thread *thread;
|
||||||
|
struct process *process;
|
||||||
int new_fd;
|
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,
|
if ((new_fd = dup(fd)) != -1)
|
||||||
req->inherit, &reply.handle );
|
{
|
||||||
if (!reply.tid) close( new_fd );
|
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
|
add_reply_data( current, &reply, sizeof(reply) );
|
||||||
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
|
|
||||||
|
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize a new thread */
|
/* initialize a new thread */
|
||||||
DECL_HANDLER(init_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)
|
if (current->state != STARTING)
|
||||||
{
|
{
|
||||||
|
@ -564,9 +565,8 @@ DECL_HANDLER(init_thread)
|
||||||
current->teb = req->teb;
|
current->teb = req->teb;
|
||||||
if (current->suspend + current->process->suspend > 0)
|
if (current->suspend + current->process->suspend > 0)
|
||||||
kill( current->unix_pid, SIGSTOP );
|
kill( current->unix_pid, SIGSTOP );
|
||||||
reply.pid = current->process;
|
reply->pid = current->process;
|
||||||
reply.tid = current;
|
reply->tid = current;
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* terminate a thread */
|
/* terminate a thread */
|
||||||
|
@ -579,23 +579,21 @@ DECL_HANDLER(terminate_thread)
|
||||||
kill_thread( thread, req->exit_code );
|
kill_thread( thread, req->exit_code );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
if (current) send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fetch information about a thread */
|
/* fetch information about a thread */
|
||||||
DECL_HANDLER(get_thread_info)
|
DECL_HANDLER(get_thread_info)
|
||||||
{
|
{
|
||||||
struct thread *thread;
|
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 )))
|
if ((thread = get_thread_from_handle( req->handle, THREAD_QUERY_INFORMATION )))
|
||||||
{
|
{
|
||||||
reply.tid = thread;
|
reply->tid = thread;
|
||||||
reply.exit_code = thread->exit_code;
|
reply->exit_code = thread->exit_code;
|
||||||
reply.priority = thread->priority;
|
reply->priority = thread->priority;
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set information about a thread */
|
/* set information about a thread */
|
||||||
|
@ -608,44 +606,41 @@ DECL_HANDLER(set_thread_info)
|
||||||
set_thread_info( thread, req );
|
set_thread_info( thread, req );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* suspend a thread */
|
/* suspend a thread */
|
||||||
DECL_HANDLER(suspend_thread)
|
DECL_HANDLER(suspend_thread)
|
||||||
{
|
{
|
||||||
struct thread *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 )))
|
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
|
||||||
{
|
{
|
||||||
reply.count = suspend_thread( thread );
|
reply->count = suspend_thread( thread );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resume a thread */
|
/* resume a thread */
|
||||||
DECL_HANDLER(resume_thread)
|
DECL_HANDLER(resume_thread)
|
||||||
{
|
{
|
||||||
struct thread *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 )))
|
if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME )))
|
||||||
{
|
{
|
||||||
reply.count = resume_thread( thread );
|
reply->count = resume_thread( thread );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* select on a handle list */
|
/* select on a handle list */
|
||||||
DECL_HANDLER(select)
|
DECL_HANDLER(select)
|
||||||
{
|
{
|
||||||
if (len != req->count * sizeof(int))
|
if (check_req_data( req->count * sizeof(int) ))
|
||||||
fatal_protocol_error( "select: bad length %d for %d handles\n",
|
{
|
||||||
len, req->count );
|
sleep_on( current, req->count, get_req_data( req->count * sizeof(int) ),
|
||||||
sleep_on( current, req->count, (int *)data, req->flags, req->timeout );
|
req->flags, req->timeout );
|
||||||
|
}
|
||||||
|
else fatal_protocol_error( "select: bad length" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* queue an APC for a thread */
|
/* queue an APC for a thread */
|
||||||
|
@ -657,5 +652,4 @@ DECL_HANDLER(queue_apc)
|
||||||
thread_queue_apc( thread, req->func, req->param );
|
thread_queue_apc( thread, req->func, req->param );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
send_reply( current, -1, 0 );
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct mutex;
|
||||||
struct debug_ctx;
|
struct debug_ctx;
|
||||||
struct debug_event;
|
struct debug_event;
|
||||||
|
|
||||||
enum run_state { STARTING, RUNNING, TERMINATED };
|
enum run_state { STARTING, RUNNING, SLEEPING, TERMINATED };
|
||||||
|
|
||||||
struct thread
|
struct thread
|
||||||
{
|
{
|
||||||
|
@ -48,6 +48,10 @@ struct thread
|
||||||
int priority; /* priority level */
|
int priority; /* priority level */
|
||||||
int affinity; /* affinity mask */
|
int affinity; /* affinity mask */
|
||||||
int suspend; /* suspend count */
|
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) */
|
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 struct thread *get_thread_from_handle( int handle, unsigned int access );
|
||||||
extern void suspend_all_threads( void );
|
extern void suspend_all_threads( void );
|
||||||
extern void resume_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 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 remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
extern void kill_thread( struct thread *thread, int exit_code );
|
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 thread_timeout(void);
|
||||||
extern void wake_up( struct object *obj, int max );
|
extern void wake_up( struct object *obj, int max );
|
||||||
|
|
||||||
#define GET_ERROR() (current->error)
|
static inline int get_error(void) { return current->error; }
|
||||||
#define SET_ERROR(err) (current->error = (err))
|
static inline void set_error( int err ) { current->error = err; }
|
||||||
#define CLEAR_ERROR() (current->error = 0)
|
static inline void clear_error(void) { set_error(0); }
|
||||||
|
|
||||||
#endif /* __WINE_SERVER_THREAD_H */
|
#endif /* __WINE_SERVER_THREAD_H */
|
||||||
|
|
|
@ -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 <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include "server.h"
|
#include "request.h"
|
||||||
#include "thread.h"
|
|
||||||
|
|
||||||
static int dump_chars( void *ptr, int len )
|
static int dump_chars( void *ptr, int len )
|
||||||
{
|
{
|
||||||
|
@ -40,6 +43,11 @@ static int dump_ptrs( void *ptr, int len )
|
||||||
return len * sizeof(void*);
|
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 )
|
static int dump_new_process_request( struct new_process_request *req, int len )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " inherit=%d,", req->inherit );
|
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 );
|
fprintf( stderr, " pid=%p", req->pid );
|
||||||
return (int)sizeof(*req);
|
return (int)sizeof(*req);
|
||||||
}
|
}
|
||||||
typedef int (*dump_func)( void *req, int len );
|
|
||||||
|
|
||||||
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_new_process_request,
|
(dump_func)dump_new_process_request,
|
||||||
|
@ -902,8 +909,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)0,
|
(dump_func)0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const req_names[REQ_NB_REQUESTS] =
|
static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
{
|
|
||||||
"new_process",
|
"new_process",
|
||||||
"new_thread",
|
"new_thread",
|
||||||
"set_debug",
|
"set_debug",
|
||||||
|
@ -968,15 +974,19 @@ static const char * const req_names[REQ_NB_REQUESTS] =
|
||||||
"debug_process",
|
"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;
|
current->last_req = req;
|
||||||
fprintf( stderr, "%08x: %s(", (unsigned int)current, req_names[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)
|
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++ );
|
while (len--) fprintf( stderr, ", %02x", *ptr++ );
|
||||||
}
|
}
|
||||||
if (fd != -1) fprintf( stderr, " ) fd=%d\n", fd );
|
if (fd != -1) fprintf( stderr, " ) fd=%d\n", fd );
|
||||||
|
@ -994,29 +1004,22 @@ void trace_kill( int exit_code )
|
||||||
(unsigned int)current, exit_code );
|
(unsigned int)current, exit_code );
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_reply( struct thread *thread, int type, int pass_fd,
|
void trace_reply( struct thread *thread, int pass_fd )
|
||||||
struct iovec *vec, int veclen )
|
|
||||||
{
|
{
|
||||||
static unsigned char buffer[MAX_MSG_LENGTH];
|
struct header *head = thread->buffer;
|
||||||
|
int len = head->len - sizeof(*head);
|
||||||
if (!thread) return;
|
|
||||||
fprintf( stderr, "%08x: %s() = %d",
|
fprintf( stderr, "%08x: %s() = %d",
|
||||||
(unsigned int)thread, req_names[thread->last_req], type );
|
(unsigned int)thread, req_names[thread->last_req], head->type );
|
||||||
if (veclen)
|
if (len)
|
||||||
{
|
{
|
||||||
unsigned char *p = buffer;
|
const unsigned char *data = (unsigned char *)(head + 1);
|
||||||
int len;
|
int res = 0;
|
||||||
for (; veclen; veclen--, vec++)
|
|
||||||
{
|
|
||||||
memcpy( p, vec->iov_base, vec->iov_len );
|
|
||||||
p += vec->iov_len;
|
|
||||||
}
|
|
||||||
fprintf( stderr, " {" );
|
fprintf( stderr, " {" );
|
||||||
len = p - buffer;
|
|
||||||
if (reply_dumpers[thread->last_req])
|
if (reply_dumpers[thread->last_req])
|
||||||
len -= reply_dumpers[thread->last_req]( buffer, len );
|
res = reply_dumpers[thread->last_req]( data, len );
|
||||||
p -= len;
|
len -= res;
|
||||||
while (len--) fprintf( stderr, ", %02x", *p++ );
|
data += res;
|
||||||
|
while (len--) fprintf( stderr, ", %02x", *data++ );
|
||||||
fprintf( stderr, " }" );
|
fprintf( stderr, " }" );
|
||||||
}
|
}
|
||||||
if (pass_fd != -1) fprintf( stderr, " fd=%d\n", pass_fd );
|
if (pass_fd != -1) fprintf( stderr, " fd=%d\n", pass_fd );
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#! /usr/bin/perl -w
|
#! /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.
|
# from the contents of include/server.h.
|
||||||
#
|
#
|
||||||
# Copyright (C) 1998 Alexandre Julliard
|
# Copyright (C) 1998 Alexandre Julliard
|
||||||
|
@ -23,57 +23,11 @@ my @requests = ();
|
||||||
my %replies = ();
|
my %replies = ();
|
||||||
|
|
||||||
open(SERVER,"include/server.h") or die "Can't open include/server.h";
|
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
|
### Parse server.h to find request/reply structure definitions
|
||||||
|
|
||||||
|
my @trace_lines = ();
|
||||||
|
|
||||||
while (<SERVER>)
|
while (<SERVER>)
|
||||||
{
|
{
|
||||||
if (/^struct +(\w+)_request/) { &DO_REQUEST($1); }
|
if (/^struct +(\w+)_request/) { &DO_REQUEST($1); }
|
||||||
|
@ -82,137 +36,56 @@ while (<SERVER>)
|
||||||
|
|
||||||
### Output the dumping function tables
|
### Output the dumping function tables
|
||||||
|
|
||||||
print TRACE "typedef int (*dump_func)( void *req, int len );\n\n";
|
push @trace_lines, "static const dump_func req_dumpers[REQ_NB_REQUESTS] = {\n";
|
||||||
print TRACE "static const dump_func req_dumpers[REQ_NB_REQUESTS] = {\n";
|
|
||||||
foreach $req (@requests)
|
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)
|
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;
|
push @trace_lines, "static const char * const req_names[REQ_NB_REQUESTS] = {\n";
|
||||||
static const char * const req_names[REQ_NB_REQUESTS] =
|
|
||||||
{
|
|
||||||
EOF
|
|
||||||
foreach $req (@requests)
|
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 )
|
my @server_lines = ();
|
||||||
{
|
|
||||||
int size;
|
|
||||||
current->last_req = req;
|
|
||||||
fprintf( stderr, "%08x: %s(", (unsigned int)current, req_names[req] );
|
|
||||||
size = req_dumpers[req]( data, len );
|
|
||||||
if ((len -= size) > 0)
|
|
||||||
{
|
|
||||||
unsigned char *ptr = (unsigned char *)data + size;
|
|
||||||
while (len--) fprintf( stderr, ", %02x", *ptr++ );
|
|
||||||
}
|
|
||||||
if (fd != -1) fprintf( stderr, " ) fd=%d\\n", fd );
|
|
||||||
else fprintf( stderr, " )\\n" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace_timeout(void)
|
push @server_lines, "enum request\n{\n";
|
||||||
{
|
foreach $req (@requests) { push @server_lines, " REQ_\U$req,\n"; }
|
||||||
fprintf( stderr, "%08x: *timeout*\\n", (unsigned int)current );
|
push @server_lines, " REQ_NB_REQUESTS\n};\n";
|
||||||
}
|
|
||||||
|
|
||||||
void trace_kill( int exit_code )
|
REPLACE_IN_FILE( "include/server.h", @server_lines );
|
||||||
{
|
|
||||||
fprintf( stderr,"%08x: *killed* exit_code=%d\\n",
|
|
||||||
(unsigned int)current, exit_code );
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace_reply( struct thread *thread, int type, int pass_fd,
|
### Output the request handlers list
|
||||||
struct iovec *vec, int veclen )
|
|
||||||
{
|
|
||||||
static unsigned char buffer[MAX_MSG_LENGTH];
|
|
||||||
|
|
||||||
if (!thread) return;
|
my @request_lines = ();
|
||||||
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
|
|
||||||
|
|
||||||
|
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)
|
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;
|
REPLACE_IN_FILE( "server/request.h", @request_lines );
|
||||||
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
|
|
||||||
|
|
||||||
### Handle a request structure definition
|
### Handle a request structure definition
|
||||||
|
|
||||||
|
@ -264,7 +137,7 @@ sub DO_DUMP_FUNC
|
||||||
{
|
{
|
||||||
my $vararg = 0;
|
my $vararg = 0;
|
||||||
my $name = shift;
|
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)
|
while ($#_ >= 0)
|
||||||
{
|
{
|
||||||
my $type = shift;
|
my $type = shift;
|
||||||
|
@ -272,17 +145,41 @@ sub DO_DUMP_FUNC
|
||||||
if ($type =~ /\[0\]$/) # vararg type?
|
if ($type =~ /\[0\]$/) # vararg type?
|
||||||
{
|
{
|
||||||
$vararg = 1;
|
$vararg = 1;
|
||||||
print TRACE " fprintf( stderr, \" $var=\" );\n";
|
push @trace_lines, " fprintf( stderr, \" $var=\" );\n";
|
||||||
print TRACE " return $formats{$type}( req+1, len - (int)sizeof(*req) ) + sizeof(*req);\n";
|
push @trace_lines, " return $formats{$type}( req+1, len - (int)sizeof(*req) ) + sizeof(*req);\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
print TRACE " fprintf( stderr, \" $var=$formats{$type}";
|
push @trace_lines, " fprintf( stderr, \" $var=$formats{$type}";
|
||||||
print TRACE "," if ($#_ > 0);
|
push @trace_lines, "," if ($#_ > 0);
|
||||||
print TRACE "\", ";
|
push @trace_lines, "\", ";
|
||||||
print TRACE "req->$var );\n";
|
push @trace_lines, "req->$var );\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print TRACE " return (int)sizeof(*req);\n" unless $vararg;
|
push @trace_lines, " return (int)sizeof(*req);\n" unless $vararg;
|
||||||
print TRACE "}\n";
|
push @trace_lines, "}\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
### Replace the contents of a file between ### make_requests ### marks
|
||||||
|
|
||||||
|
sub REPLACE_IN_FILE
|
||||||
|
{
|
||||||
|
my $name = shift;
|
||||||
|
my @data = @_;
|
||||||
|
my @lines = ();
|
||||||
|
open(FILE,$name) or die "Can't open $name";
|
||||||
|
while (<FILE>)
|
||||||
|
{
|
||||||
|
push @lines, $_;
|
||||||
|
last if /\#\#\# make_requests begin \#\#\#/;
|
||||||
|
}
|
||||||
|
push @lines, "\n", @data;
|
||||||
|
while (<FILE>)
|
||||||
|
{
|
||||||
|
if (/\#\#\# make_requests end \#\#\#/) { push @lines, "\n", $_; last; }
|
||||||
|
}
|
||||||
|
push @lines, <FILE>;
|
||||||
|
open(FILE,">$name") or die "Can't modify $name";
|
||||||
|
print FILE @lines;
|
||||||
|
close(FILE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,10 +43,8 @@
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "wincon.h"
|
#include "wincon.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "debugtools.h"
|
|
||||||
|
|
||||||
#include "server/request.h"
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#include "debugtools.h"
|
||||||
|
|
||||||
DEFAULT_DEBUG_CHANNEL(console)
|
DEFAULT_DEBUG_CHANNEL(console)
|
||||||
|
|
||||||
|
@ -65,7 +63,7 @@ static BOOL CONSOLE_GetInfo( HANDLE handle, struct get_console_info_reply *reply
|
||||||
|
|
||||||
req.handle = handle;
|
req.handle = handle;
|
||||||
CLIENT_SendRequest( REQ_GET_CONSOLE_INFO, -1, 1, &req, sizeof(req) );
|
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);
|
req.inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
||||||
CLIENT_SendRequest( REQ_OPEN_CONSOLE, -1, 1, &req, sizeof(req) );
|
CLIENT_SendRequest( REQ_OPEN_CONSOLE, -1, 1, &req, sizeof(req) );
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
|
if (!CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return reply.handle;
|
||||||
return reply.handle;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue