From 309ed4e1f11398025a1948aa1e3f5fb25b40fffd Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Wed, 7 Nov 2001 20:14:45 +0000 Subject: [PATCH] Make ConnectNamedPipe work in overlapped mode. --- dlls/kernel/sync.c | 147 +++++++++++++++++++++++++-------- include/wine/server_protocol.h | 8 +- scheduler/synchro.c | 1 + server/named_pipe.c | 60 ++++++++------ server/protocol.def | 6 +- server/trace.c | 6 +- 6 files changed, 162 insertions(+), 66 deletions(-) diff --git a/dlls/kernel/sync.c b/dlls/kernel/sync.c index 833b781b138..5fe788a9dbb 100644 --- a/dlls/kernel/sync.c +++ b/dlls/kernel/sync.c @@ -601,38 +601,72 @@ BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer, return FALSE; } +/*********************************************************************** + * SYNC_CompletePipeOverlapped (Internal) + */ +static void SYNC_CompletePipeOverlapped (LPOVERLAPPED overlapped, DWORD result) +{ + TRACE("for %p result %08lx\n",overlapped,result); + if(!overlapped) + return; + overlapped->Internal = result; + SetEvent(overlapped->hEvent); +} /*********************************************************************** * WaitNamedPipeA (KERNEL32.@) */ -BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut) +static BOOL SYNC_WaitNamedPipeA (LPCSTR name, DWORD nTimeOut, LPOVERLAPPED overlapped) { DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0; - HANDLE event; BOOL ret; - TRACE("%s 0x%08lx\n",debugstr_a(name),nTimeOut); - if (len >= MAX_PATH) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return FALSE; } - if (!(event = CreateEventA( NULL, 0, 0, NULL ))) return FALSE; - SERVER_START_VAR_REQ( wait_named_pipe, len * sizeof(WCHAR) ) { req->timeout = nTimeOut; - req->event = event; + req->overlapped = overlapped; + req->func = SYNC_CompletePipeOverlapped; if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len ); ret = !SERVER_CALL_ERR(); } SERVER_END_REQ; - if (ret) WaitForSingleObject(event,INFINITE); + return ret; +} - CloseHandle(event); +/*********************************************************************** + * WaitNamedPipeA (KERNEL32.@) + */ +BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut) +{ + BOOL ret; + OVERLAPPED ov; + + TRACE("%s 0x%08lx\n",debugstr_a(name),nTimeOut); + + memset(&ov,0,sizeof ov); + ov.hEvent = CreateEventA( NULL, 0, 0, NULL ); + if (!ov.hEvent) + return FALSE; + + /* expect to fail with STATUS_PENDING */ + ret = SYNC_WaitNamedPipeA(name, nTimeOut, &ov); + if(ret) + { + if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE)) + { + SetLastError(ov.Internal); + ret = (ov.Internal==STATUS_SUCCESS); + } + } + + CloseHandle(ov.hEvent); return ret; } @@ -640,68 +674,115 @@ BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut) /*********************************************************************** * WaitNamedPipeW (KERNEL32.@) */ -BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut) +static BOOL SYNC_WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut, LPOVERLAPPED overlapped) { DWORD len = name ? strlenW(name) : 0; - HANDLE event; BOOL ret; - TRACE("%s 0x%08lx\n",debugstr_w(name),nTimeOut); - if (len >= MAX_PATH) { SetLastError( ERROR_FILENAME_EXCED_RANGE ); return FALSE; } - if (!(event = CreateEventA( NULL, 0, 0, NULL ))) return FALSE; - SERVER_START_VAR_REQ( wait_named_pipe, len * sizeof(WCHAR) ) { req->timeout = nTimeOut; - req->event = event; + req->overlapped = overlapped; + req->func = SYNC_CompletePipeOverlapped; memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) ); ret = !SERVER_CALL_ERR(); } SERVER_END_REQ; - if (ret) WaitForSingleObject(event,INFINITE); - - CloseHandle(event); return ret; } +/*********************************************************************** + * WaitNamedPipeW (KERNEL32.@) + */ +BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut) +{ + BOOL ret; + OVERLAPPED ov; + + TRACE("%s 0x%08lx\n",debugstr_w(name),nTimeOut); + + memset(&ov,0,sizeof ov); + ov.hEvent = CreateEventA( NULL, 0, 0, NULL ); + if (!ov.hEvent) + return FALSE; + + ret = SYNC_WaitNamedPipeW(name, nTimeOut, &ov); + if(ret) + { + if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE)) + { + SetLastError(ov.Internal); + ret = (ov.Internal==STATUS_SUCCESS); + } + } + + CloseHandle(ov.hEvent); + + return ret; +} + + +/*********************************************************************** + * SYNC_ConnectNamedPipe (Internal) + */ +static BOOL SYNC_ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped) +{ + BOOL ret; + + if(!overlapped) + return FALSE; + + overlapped->Internal = STATUS_PENDING; + + SERVER_START_REQ( connect_named_pipe ) + { + req->handle = hPipe; + req->overlapped = overlapped; + req->func = SYNC_CompletePipeOverlapped; + ret = !SERVER_CALL_ERR(); + } + SERVER_END_REQ; + + return ret; +} /*********************************************************************** * ConnectNamedPipe (KERNEL32.@) */ BOOL WINAPI ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped) { + OVERLAPPED ov; BOOL ret; - HANDLE event; TRACE("(%d,%p)\n",hPipe, overlapped); if(overlapped) - { - FIXME("overlapped operation not supported\n"); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return SYNC_ConnectNamedPipe(hPipe,overlapped); + + memset(&ov,0,sizeof ov); + ov.hEvent = CreateEventA(NULL,0,0,NULL); + if (!ov.hEvent) return FALSE; - } - if (!(event = CreateEventA(NULL,0,0,NULL))) return FALSE; - - SERVER_START_REQ( connect_named_pipe ) + ret=SYNC_ConnectNamedPipe(hPipe, &ov); + if(ret) { - req->handle = hPipe; - req->event = event; - ret = !SERVER_CALL_ERR(); + if (WAIT_OBJECT_0==WaitForSingleObject(ov.hEvent,INFINITE)) + { + SetLastError(ov.Internal); + ret = (ov.Internal==STATUS_SUCCESS); + } } - SERVER_END_REQ; - if (ret) WaitForSingleObject(event,INFINITE); + CloseHandle(ov.hEvent); - CloseHandle(event); return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index fe437e90682..41dba2ee446 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1552,7 +1552,8 @@ struct connect_named_pipe_request { struct request_header __header; handle_t handle; - handle_t event; + void* overlapped; + void* func; }; @@ -1561,7 +1562,8 @@ struct wait_named_pipe_request { struct request_header __header; unsigned int timeout; - handle_t event; + void* overlapped; + void* func; /* VARARG(filename,string); */ }; @@ -2056,6 +2058,6 @@ union generic_request struct get_window_properties_request get_window_properties; }; -#define SERVER_PROTOCOL_VERSION 62 +#define SERVER_PROTOCOL_VERSION 63 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/scheduler/synchro.c b/scheduler/synchro.c index 77907a4a4f4..5bb83ffc311 100644 --- a/scheduler/synchro.c +++ b/scheduler/synchro.c @@ -243,6 +243,7 @@ static void call_apcs( BOOL alertable ) case APC_NONE: return; /* no more APCs */ case APC_ASYNC: + proc( args[0], args[1]); break; case APC_USER: proc( args[0] ); diff --git a/server/named_pipe.c b/server/named_pipe.c index edc92e89496..57013d92a6e 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -48,7 +48,9 @@ struct pipe_user struct named_pipe *pipe; struct pipe_user *next; struct pipe_user *prev; - struct event *event; + void *thread; + void *func; + void *overlapped; }; struct named_pipe @@ -122,18 +124,28 @@ static void named_pipe_destroy( struct object *obj) assert( !pipe->users ); } +static void notify_waiter( struct pipe_user *user, unsigned int status) +{ + if(user->thread && user->func && user->overlapped) + { + /* queue a system APC, to notify a waiting thread */ + thread_queue_apc(user->thread,NULL,user->func, + APC_ASYNC,1,2,user->overlapped,status); + } + user->thread = NULL; + user->func = NULL; + user->overlapped=NULL; +} + static void pipe_user_destroy( struct object *obj) { struct pipe_user *user = (struct pipe_user *)obj; assert( obj->ops == &pipe_user_ops ); - if(user->event) - { - /* FIXME: signal waiter of failure */ - release_object(user->event); - user->event = NULL; - } + if(user->overlapped) + notify_waiter(user,STATUS_HANDLES_CLOSED); + if(user->other) { close(user->other->obj.fd); @@ -217,8 +229,10 @@ static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd ) user->pipe = pipe; user->state = ps_none; - user->event = NULL; /* thread wait on this pipe */ user->other = NULL; + user->thread = NULL; + user->func = NULL; + user->overlapped = NULL; /* add to list of pipe users */ if ((user->next = pipe->users)) user->next->prev = user; @@ -301,9 +315,7 @@ DECL_HANDLER(open_named_pipe) if( (user = create_pipe_user (pipe, fds[1])) ) { partner->obj.fd = fds[0]; - set_event(partner->event); - release_object(partner->event); - partner->event = NULL; + notify_waiter(partner,STATUS_SUCCESS); partner->state = ps_connected_server; partner->other = user; user->state = ps_connected_client; @@ -334,7 +346,6 @@ DECL_HANDLER(open_named_pipe) DECL_HANDLER(connect_named_pipe) { struct pipe_user *user, *partner; - struct event *event; user = get_pipe_user_obj(current->process, req->handle, 0); if(!user) @@ -347,16 +358,14 @@ DECL_HANDLER(connect_named_pipe) else { user->state = ps_wait_open; - event = get_event_obj(current->process, req->event, 0); - if(event) - user->event = event; + user->thread = current; + user->func = req->func; + user->overlapped = req->overlapped; /* notify all waiters that a pipe just became available */ while( (partner = find_partner(user->pipe,ps_wait_connect)) ) { - set_event(partner->event); - release_object(partner->event); - partner->event = NULL; + notify_waiter(partner,STATUS_SUCCESS); release_object(partner); release_object(partner); } @@ -367,13 +376,8 @@ DECL_HANDLER(connect_named_pipe) DECL_HANDLER(wait_named_pipe) { - struct event *event; struct named_pipe *pipe; - event = get_event_obj(current->process, req->event, 0); - if(!event) - return; - pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) ); if( pipe ) { @@ -385,7 +389,10 @@ DECL_HANDLER(wait_named_pipe) set_error(STATUS_SUCCESS); if( (partner = find_partner(pipe,ps_wait_open)) ) { - set_event(event); + /* this should use notify_waiter, + but no pipe_user object exists now... */ + thread_queue_apc(current,NULL,req->func, + APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS); release_object(partner); } else @@ -394,8 +401,10 @@ DECL_HANDLER(wait_named_pipe) if( (user = create_pipe_user (pipe, -1)) ) { - user->event = (struct event *)grab_object( event ); user->state = ps_wait_connect; + user->thread = current; + user->func = req->func; + user->overlapped = req->overlapped; /* don't release it */ } } @@ -406,7 +415,6 @@ DECL_HANDLER(wait_named_pipe) } release_object(pipe); } - release_object(event); } DECL_HANDLER(disconnect_named_pipe) diff --git a/server/protocol.def b/server/protocol.def index 07c7f79fc09..5e6c8a0082a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1392,14 +1392,16 @@ enum message_type /* Connect to a named pipe */ @REQ(connect_named_pipe) handle_t handle; - handle_t event; /* set this event when it's ready */ + void* overlapped; + void* func; @END /* Wait for a named pipe */ @REQ(wait_named_pipe) unsigned int timeout; - handle_t event; /* set this event when it's ready */ + void* overlapped; + void* func; VARARG(filename,string); /* pipe name */ @END diff --git a/server/trace.c b/server/trace.c index ba98c0a7ed1..012286bbb8b 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1661,13 +1661,15 @@ static void dump_open_named_pipe_reply( const struct open_named_pipe_request *re static void dump_connect_named_pipe_request( const struct connect_named_pipe_request *req ) { fprintf( stderr, " handle=%d,", req->handle ); - fprintf( stderr, " event=%d", req->event ); + fprintf( stderr, " overlapped=%p,", req->overlapped ); + fprintf( stderr, " func=%p", req->func ); } static void dump_wait_named_pipe_request( const struct wait_named_pipe_request *req ) { fprintf( stderr, " timeout=%08x,", req->timeout ); - fprintf( stderr, " event=%d,", req->event ); + fprintf( stderr, " overlapped=%p,", req->overlapped ); + fprintf( stderr, " func=%p,", req->func ); fprintf( stderr, " filename=" ); cur_pos += dump_varargs_string( req ); }