From: Christian Grothoff Date: Sat, 14 Jan 2012 23:18:06 +0000 (+0000) Subject: LRN: enable more fine-grained control over blocking/non-blocking pipe operation X-Git-Tag: initial-import-from-subversion-38251~15305 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=91ab799c42b2496e65afd0c866811999d88119ed;p=oweals%2Fgnunet.git LRN: enable more fine-grained control over blocking/non-blocking pipe operation --- diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c index 4c78e6fe7..88fabef2f 100644 --- a/src/arm/gnunet-service-arm.c +++ b/src/arm/gnunet-service-arm.c @@ -1174,7 +1174,7 @@ main (int argc, char *const *argv) int ret; struct GNUNET_SIGNAL_Context *shc_chld; - sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO); + sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); GNUNET_assert (sigpipe != NULL); shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); diff --git a/src/fs/fs_dirmetascan.c b/src/fs/fs_dirmetascan.c index 880710356..ce76b0387 100644 --- a/src/fs/fs_dirmetascan.c +++ b/src/fs/fs_dirmetascan.c @@ -1047,7 +1047,7 @@ GNUNET_FS_directory_scan_start (const char *filename, if (filename_expanded == NULL) return NULL; - progress_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO); + progress_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); if (progress_pipe == NULL) { GNUNET_free (filename_expanded); diff --git a/src/include/gnunet_disk_lib.h b/src/include/gnunet_disk_lib.h index be92a91c6..46dd7c4c4 100644 --- a/src/include/gnunet_disk_lib.h +++ b/src/include/gnunet_disk_lib.h @@ -395,7 +395,7 @@ GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh, * @return handle to the new pipe, NULL on error */ struct GNUNET_DISK_PipeHandle * -GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write); +GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write); /** @@ -408,7 +408,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write); * @return handle to the new pipe, NULL on error */ struct GNUNET_DISK_PipeHandle * -GNUNET_DISK_pipe_from_fd (int blocking, int fd[2]); +GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]); /** * Closes an interprocess channel @@ -461,6 +461,19 @@ ssize_t GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h, void *result, size_t len); +/** + * Read the contents of a binary file into a buffer. + * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN + * when no data can be read). + * + * @param h handle to an open file + * @param result the buffer to write the result to + * @param len the maximum number of bytes to read + * @return the number of bytes read on success, GNUNET_SYSERR on failure + */ +ssize_t +GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h, + void *result, size_t len); /** * Read the contents of a binary file into a buffer. @@ -487,6 +500,17 @@ GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n); +/** + * Write a buffer to a file, blocking, if necessary. + * @param h handle to open file + * @param buffer the data to write + * @param n number of bytes to write + * @return number of bytes written on success, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h, + const void *buffer, size_t n); + /** * Write a buffer to a file. If the file is longer than * the given buffer size, it will be truncated. diff --git a/src/nat/nat.c b/src/nat/nat.c index 9f8fec9a0..02ff7547b 100644 --- a/src/nat/nat.c +++ b/src/nat/nat.c @@ -835,7 +835,7 @@ start_gnunet_nat_server (struct GNUNET_NAT_Handle *h) (h->internal_address != NULL) && (NULL != (h->server_stdout = - GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES)))) + GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES)))) { #if DEBUG_NAT LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting `%s' at `%s'\n", diff --git a/src/nat/nat_mini.c b/src/nat/nat_mini.c index 5a83d7a4f..6c48f28fe 100644 --- a/src/nat/nat_mini.c +++ b/src/nat/nat_mini.c @@ -169,7 +169,7 @@ GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout, eh = GNUNET_malloc (sizeof (struct GNUNET_NAT_ExternalHandle)); eh->cb = cb; eh->cb_cls = cb_cls; - eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); + eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if (NULL == eh->opipe) { GNUNET_free (eh); diff --git a/src/testing/testing.c b/src/testing/testing.c index d7f6946b0..a729c5063 100644 --- a/src/testing/testing.c +++ b/src/testing/testing.c @@ -239,7 +239,7 @@ start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) /* Start create hostkey process if we don't already know the peer identity! */ if (GNUNET_NO == d->have_hostkey) { - d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES); + d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES); if (d->pipe_stdout == NULL) { cb = d->cb; diff --git a/src/transport/plugin_transport_wlan.c b/src/transport/plugin_transport_wlan.c index d121ec9be..5ac44c2f2 100644 --- a/src/transport/plugin_transport_wlan.c +++ b/src/transport/plugin_transport_wlan.c @@ -1441,11 +1441,11 @@ wlan_transport_start_wlan_helper (struct Plugin *plugin) return GNUNET_YES; } - plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); + plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if (plugin->server_stdout == NULL) return GNUNET_SYSERR; - plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); + plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); if (plugin->server_stdin == NULL) return GNUNET_SYSERR; diff --git a/src/util/disk.c b/src/util/disk.c index eb707fd62..a5190d587 100644 --- a/src/util/disk.c +++ b/src/util/disk.c @@ -746,6 +746,74 @@ GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result, #endif } +/** + * Read the contents of a binary file into a buffer. + * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN + * when no data can be read). + * + * @param h handle to an open file + * @param result the buffer to write the result to + * @param len the maximum number of bytes to read + * @return the number of bytes read on success, GNUNET_SYSERR on failure + */ +ssize_t +GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle * h, + void *result, size_t len) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + DWORD bytesRead; + + if (h->type != GNUNET_PIPE) + { + if (!ReadFile (h->h, result, len, &bytesRead, NULL)) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + } + else + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe, trying to read\n"); +#endif + if (!ReadFile (h->h, result, len, &bytesRead, h->oOverlapRead)) + { + if (GetLastError () != ERROR_IO_PENDING) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ()); +#endif + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + else + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, + "ReadFile() queued a read, cancelling\n"); +#endif + CancelIo (h->h); + errno = EAGAIN; + return GNUNET_SYSERR; + } + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes\n", bytesRead); +#endif + } + return bytesRead; +#else + /* FIXME: set to non-blocking (fcntl?), read, then set back? */ + return read (h->fd, result, len); +#endif +} + /** * Read the contents of a binary file into a buffer. @@ -870,6 +938,64 @@ GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h, #endif } +/** + * Write a buffer to a file, blocking, if necessary. + * @param h handle to open file + * @param buffer the data to write + * @param n number of bytes to write + * @return number of bytes written on success, GNUNET_SYSERR on error + */ +ssize_t +GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle * h, + const void *buffer, size_t n) +{ + if (h == NULL) + { + errno = EINVAL; + return GNUNET_SYSERR; + } + +#ifdef MINGW + DWORD bytesWritten; + /* We do a non-overlapped write, which is as blocking as it gets */ +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n); +#endif + if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) + { + SetErrnoFromWinError (GetLastError ()); +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", + GetLastError ()); +#endif + return GNUNET_SYSERR; + } + if (bytesWritten == 0 && n > 0) + { +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n"); +#endif + WaitForSingleObject (h->h, INFINITE); + if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL)) + { + SetErrnoFromWinError (GetLastError ()); +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n", + GetLastError ()); +#endif + return GNUNET_SYSERR; + } + } +#if DEBUG_PIPE + LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytesWritten); +#endif + return bytesWritten; +#else + /* FIXME: switch to blocking mode (fcntl?), write, then switch back? */ + return write (h->fd, buffer, n); +#endif +} + /** * Write a buffer to a file. If the file is longer than the * number of bytes that will be written, it will be truncated. @@ -1971,7 +2097,7 @@ create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr, * @return handle to the new pipe, NULL on error */ struct GNUNET_DISK_PipeHandle * -GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write) +GNUNET_DISK_pipe (int blocking_read, int blocking_write, int inherit_read, int inherit_write) { struct GNUNET_DISK_PipeHandle *p; struct GNUNET_DISK_FileHandle *fds; @@ -2000,7 +2126,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write) p->fd[1]->fd = fd[1]; ret = 0; flags = fcntl (fd[0], F_GETFL); - if (!blocking) + if (!blocking_read) flags |= O_NONBLOCK; if (0 > fcntl (fd[0], F_SETFL, flags)) ret = -1; @@ -2010,7 +2136,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write) ret = -1; flags = fcntl (fd[1], F_GETFL); - if (!blocking) + if (!blocking_write) flags |= O_NONBLOCK; if (0 > fcntl (fd[1], F_SETFL, flags)) ret = -1; @@ -2034,7 +2160,8 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write) ret = create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0, - FILE_FLAG_OVERLAPPED, FILE_FLAG_OVERLAPPED); + blocking_read ? 0 : FILE_FLAG_OVERLAPPED, + blocking_write ? 0 : FILE_FLAG_OVERLAPPED); if (!ret) { GNUNET_free (p); @@ -2066,15 +2193,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write) } CloseHandle (p->fd[1]->h); p->fd[1]->h = tmp_handle; - if (!blocking) - { - DWORD mode; - mode = PIPE_NOWAIT; - SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL); - SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL); - /* this always fails on Windows 95, so we don't care about error handling */ - } p->fd[0]->type = GNUNET_PIPE; p->fd[1]->type = GNUNET_PIPE; @@ -2103,7 +2222,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write) * @return handle to the new pipe, NULL on error */ struct GNUNET_DISK_PipeHandle * -GNUNET_DISK_pipe_from_fd (int blocking, int fd[2]) +GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2]) { struct GNUNET_DISK_PipeHandle *p; struct GNUNET_DISK_FileHandle *fds; @@ -2124,7 +2243,7 @@ GNUNET_DISK_pipe_from_fd (int blocking, int fd[2]) if (fd[0] >= 0) { flags = fcntl (fd[0], F_GETFL); - if (!blocking) + if (!blocking_read) flags |= O_NONBLOCK; if (0 > fcntl (fd[0], F_SETFL, flags)) ret = -1; @@ -2137,7 +2256,7 @@ GNUNET_DISK_pipe_from_fd (int blocking, int fd[2]) if (fd[1] >= 0) { flags = fcntl (fd[1], F_GETFL); - if (!blocking) + if (!blocking_write) flags |= O_NONBLOCK; if (0 > fcntl (fd[1], F_SETFL, flags)) ret = -1; @@ -2170,18 +2289,6 @@ GNUNET_DISK_pipe_from_fd (int blocking, int fd[2]) else p->fd[1]->h = INVALID_HANDLE_VALUE; - if (!blocking) - { - DWORD mode; - - mode = PIPE_NOWAIT; - if (p->fd[0]->h != INVALID_HANDLE_VALUE) - SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL); - if (p->fd[1]->h != INVALID_HANDLE_VALUE) - SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL); - /* this always fails on Windows 95, so we don't care about error handling */ - } - if (p->fd[0]->h != INVALID_HANDLE_VALUE) { p->fd[0]->type = GNUNET_PIPE; diff --git a/src/util/helper.c b/src/util/helper.c index d4d26ba51..d0aab3ccf 100644 --- a/src/util/helper.c +++ b/src/util/helper.c @@ -286,8 +286,8 @@ helper_read (void *cls, static void start_helper (struct GNUNET_HELPER_Handle *h) { - h->helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); - h->helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); + h->helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); + h->helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if ( (h->helper_in == NULL) || (h->helper_out == NULL)) { /* out of file descriptors? try again later... */ diff --git a/src/util/os_priority.c b/src/util/os_priority.c index 13f002f5d..b344cd862 100644 --- a/src/util/os_priority.c +++ b/src/util/os_priority.c @@ -1135,7 +1135,7 @@ GNUNET_OS_start_process_v (const SOCKTYPE *lsocks, } if (lsocks != NULL && lsocks[0] != INVALID_SOCKET) { - lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); + lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); if (lsocks_pipe == NULL) { @@ -1582,7 +1582,7 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, struct GNUNET_DISK_PipeHandle *opipe; va_list ap; - opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); + opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if (NULL == opipe) return NULL; va_start (ap, binary); diff --git a/src/util/scheduler.c b/src/util/scheduler.c index 5f91ffbbc..412896946 100644 --- a/src/util/scheduler.c +++ b/src/util/scheduler.c @@ -803,7 +803,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls) rs = GNUNET_NETWORK_fdset_create (); ws = GNUNET_NETWORK_fdset_create (); GNUNET_assert (shutdown_pipe_handle == NULL); - shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO); + shutdown_pipe_handle = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); GNUNET_assert (shutdown_pipe_handle != NULL); pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_READ); diff --git a/src/util/test_common_logging_runtime_loglevels.c b/src/util/test_common_logging_runtime_loglevels.c index 51123d9b3..092f06041 100644 --- a/src/util/test_common_logging_runtime_loglevels.c +++ b/src/util/test_common_logging_runtime_loglevels.c @@ -268,7 +268,7 @@ runone () { const struct GNUNET_DISK_FileHandle *stdout_read_handle; - pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); + pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if (pipe_stdout == NULL) { diff --git a/src/util/test_os_start_process.c b/src/util/test_os_start_process.c index 78538404a..f66e741d9 100644 --- a/src/util/test_os_start_process.c +++ b/src/util/test_os_start_process.c @@ -114,8 +114,8 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_asprintf (&fn, "cat"); - hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); - hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); + hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO); + hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL)) { diff --git a/src/util/test_scheduler.c b/src/util/test_scheduler.c index 788ba13fa..8072feaf1 100644 --- a/src/util/test_scheduler.c +++ b/src/util/test_scheduler.c @@ -119,7 +119,7 @@ task5 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_assert (5 == *ok); (*ok) = 6; - p = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO); + p = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO); GNUNET_assert (NULL != p); fds[0] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_READ); fds[1] = GNUNET_DISK_pipe_handle (p, GNUNET_DISK_PIPE_END_WRITE);