From: Piotr Caban Subject: [PATCH 2/2] server: Update pipe quota if it was set incorrectly due to Unix socket overhead Message-Id: <552D4D53.5010809@codeweavers.com> Date: Tue, 14 Apr 2015 19:24:35 +0200 --- dlls/kernel32/tests/pipe.c | 6 ++--- dlls/ntdll/file.c | 17 ++++++++++++- server/named_pipe.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++ server/protocol.def | 6 +++++ 4 files changed, 84 insertions(+), 4 deletions(-) diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c index 3d79c78..dd20f41 100644 --- a/dlls/kernel32/tests/pipe.c +++ b/dlls/kernel32/tests/pipe.c @@ -1392,7 +1392,7 @@ static void test_CreatePipe(void) thread = CreateThread(NULL, 0, test_pipe_quota, pipewrite, 0, NULL); ok(thread != NULL, "CreateThread failed\n"); i = WaitForSingleObject(thread, 500); - todo_wine ok(i == WAIT_OBJECT_0, "CreatePipe test_pipe_quota thread still running\n"); + ok(i == WAIT_OBJECT_0, "CreatePipe test_pipe_quota thread still running\n"); if (i != WAIT_OBJECT_0) TerminateThread(thread, 0); CloseHandle(piperead); @@ -1407,7 +1407,7 @@ static void test_CreatePipe(void) thread = CreateThread(NULL, 0, test_pipe_quota, pipewrite, 0, NULL); ok(thread != NULL, "CreateThread failed\n"); i = WaitForSingleObject(thread, 500); - todo_wine ok(i == WAIT_OBJECT_0, "server test_pipe_quota thread still running\n"); + ok(i == WAIT_OBJECT_0, "server test_pipe_quota thread still running\n"); if (i != WAIT_OBJECT_0) TerminateThread(thread, 0); CloseHandle(piperead); @@ -1422,7 +1422,7 @@ static void test_CreatePipe(void) thread = CreateThread(NULL, 0, test_pipe_quota, pipewrite, 0, NULL); ok(thread != NULL, "CreateThread failed\n"); i = WaitForSingleObject(thread, 500); - todo_wine ok(i == WAIT_OBJECT_0, "client test_pipe_quota thread still running\n"); + ok(i == WAIT_OBJECT_0, "client test_pipe_quota thread still running\n"); if (i != WAIT_OBJECT_0) TerminateThread(thread, 0); CloseHandle(piperead); diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 0dc5c13..322a287 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -1140,8 +1140,23 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, for (;;) { + if (type == FD_TYPE_PIPE) + { + result = send( unix_handle, (const char *)buffer + total, length - total, MSG_DONTWAIT ); + if (result < 0 && errno == EAGAIN) + { + SERVER_START_REQ( update_named_pipe_quota ) + { + req->handle = wine_server_obj_handle( hFile ); + req->write_size = length - total; + wine_server_call( req ); + } + SERVER_END_REQ; + result = send( unix_handle, (const char *)buffer + total, length - total, 0 ); + } + } /* zero-length writes on sockets may not work with plain write(2) */ - if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET)) + else if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_SOCKET)) result = send( unix_handle, buffer, 0, 0 ); else result = write( unix_handle, (const char *)buffer + total, length - total ); diff --git a/server/named_pipe.c b/server/named_pipe.c index 706cce8..d33a4d9 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -36,6 +36,9 @@ #ifdef HAVE_SYS_SOCKET_H #include #endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif #include #include #ifdef HAVE_POLL_H @@ -1084,3 +1087,59 @@ DECL_HANDLER(set_named_pipe_info) else release_object(server); } + +DECL_HANDLER(update_named_pipe_quota) +{ +#ifdef FIONREAD + struct pipe_server *server; + struct pipe_client *client = NULL; + unsigned int in_queue, queue_size; + socklen_t len = sizeof(queue_size); + int pending_data_fd, quota_fd; + + server = get_pipe_server_obj( current->process, req->handle, FILE_WRITE_ATTRIBUTES ); + if (!server) + { + if (get_error() != STATUS_OBJECT_TYPE_MISMATCH) + return; + + clear_error(); + client = (struct pipe_client *)get_handle_obj( current->process, req->handle, + 0, &pipe_client_ops ); + if (!client) return; + + pending_data_fd = get_unix_fd( client->server->fd ); + quota_fd = get_unix_fd( client->fd ); + queue_size = client->server->pipe->insize; + } + else + { + if (!server->client) + { + release_object(server); + return; + } + + pending_data_fd = get_unix_fd( server->client->fd ); + quota_fd = get_unix_fd( server->fd ); + queue_size = server->pipe->outsize; + } + + if (!ioctl( pending_data_fd, FIONREAD, &in_queue )) + { + if (queue_size >= in_queue+req->write_size && + !getsockopt( quota_fd, SOL_SOCKET, SO_SNDBUF, &queue_size, &len )) + { + queue_size *= 2; + setsockopt( quota_fd, SOL_SOCKET, SO_SNDBUF, &queue_size, sizeof(queue_size) ); + } + } + + if (client) + release_object(client); + else + release_object(server); +#else + return; +#endif +} diff --git a/server/protocol.def b/server/protocol.def index 54501e8..189111d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2320,6 +2320,12 @@ enum message_type unsigned int flags; @END +/* Increases pipe quota if socket overhead is to big */ +@REQ(update_named_pipe_quota) + obj_handle_t handle; + unsigned int write_size; +@END + /* Create a window */ @REQ(create_window) user_handle_t parent; /* parent window */