Made server communication faster by using a shared memory block.

A few other optimizations in request processing in the server.
Moved automatically generated request definitions to server.h and
removed include/server/request.h.
This commit is contained in:
Alexandre Julliard 1999-06-22 17:26:53 +00:00
parent 0a860a01f9
commit 5bc78089db
37 changed files with 1404 additions and 1525 deletions

View File

@ -43,7 +43,6 @@
#include "wincon.h" #include "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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,76 +1,80 @@
/* File generated automatically by tools/make_requests; DO NOT EDIT!! */ /*
* Wine server requests
*
* Copyright (C) 1999 Alexandre Julliard
*/
#ifndef __WINE_SERVER_REQUEST_H #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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,10 +1,13 @@
/* File generated automatically by tools/make_requests; DO NOT EDIT!! */ /*
* Server request tracing
*
* Copyright (C) 1999 Alexandre Julliard
*/
#include <stdio.h> #include <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 );

View File

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

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