skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

commit 23bdcb4ad4ef19d99b729e5282fd15df6300a3b5
parent 828159d33b8ced9e016470c61ffd66bbef048e06
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Sun, 21 Dec 2014 00:26:40 +0000

 So the non-portable MSG_DONTWAIT may alleviate the problem... might
as well use it on architectures that support it.

Diffstat:
Mconfigure | 3++-
Msrc/libunixonacid/unixmessage_receive.c | 23+++++++++++------------
Asrc/sysdeps/trymsgdontwait.c | 17+++++++++++++++++
Asrc/sysdeps/trynbwaitall.c | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/sysdeps/tryokwaitall.c | 117-------------------------------------------------------------------------------
5 files changed, 147 insertions(+), 130 deletions(-)

diff --git a/configure b/configure @@ -442,7 +442,8 @@ EOF choose cl getpeerucred GETPEERUCRED 'getpeerucred()' choose cl ipv6 IPV6 'IPv6 support' $socket_lib choose clr malloc0 MALLOC0 'non-NULL malloc(0)' - choose clr okwaitall OKWAITALL 'a usable MSG_WAITALL flag' + choose c msgdontwait MSGDONTWAIT 'MSG_DONTWAIT' + choose clr nbwaitall NBWAITALL 'non-blocking MSG_WAITALL' choose cl openat OPENAT 'openat()' choose cl linkat LINKAT 'linkat()' choose clr pipe2 PIPE2 'pipe2()' diff --git a/src/libunixonacid/unixmessage_receive.c b/src/libunixonacid/unixmessage_receive.c @@ -14,19 +14,18 @@ #include <skalibs/siovec.h> #include <skalibs/unixmessage.h> -#ifdef SKALIBS_HASOKWAITALL -# ifdef SKALIBS_HASCMSGCLOEXEC -# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_WAITALL | MSG_CMSG_CLOEXEC) -# else -# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_WAITALL) -# endif +static int const awesomeflags = +#ifdef SKALIBS_HASMSGDONTWAIT + MSG_WAITALL | MSG_DONTWAIT +#elif defined (SKALIBS_HASNBWAITALL) + MSG_WAITALL #else -# ifdef SKALIBS_HASCMSGCLOEXEC -# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_CMSG_CLOEXEC) -# else -# define RECV(fd, hdr) recvmsg(fd, (hdr), 0) -# endif + 0 #endif +#ifdef SKALIBS_HASCMSGCLOEXEC + | MSG_CMSG_CLOEXEC +#endif + ; static int unixmessage_receiver_fill (unixmessage_receiver_t *b) { @@ -51,7 +50,7 @@ static int unixmessage_receiver_fill (unixmessage_receiver_t *b) cbuffer_wpeek(&b->mainb, v) ; iovec_from_siovec(iov, v, 2) ; } - r = RECV(b->fd, &msghdr) ; + r = recvmsg(b->fd, &msghdr, awesomeflags) ; if (r <= 0) return r ; { struct cmsghdr *c = CMSG_FIRSTHDR(&msghdr) ; diff --git a/src/sysdeps/trymsgdontwait.c b/src/sysdeps/trymsgdontwait.c @@ -0,0 +1,17 @@ +/* ISC license. */ + +#undef _POSIX_C_SOURCE +#undef _XOPEN_SOURCE + +#ifndef _XPG4_2 +# define _XPG4_2 +#endif + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif + +#include <sys/types.h> +#include <sys/socket.h> + +int value = MSG_DONTWAIT ; diff --git a/src/sysdeps/trynbwaitall.c b/src/sysdeps/trynbwaitall.c @@ -0,0 +1,117 @@ +/* ISC license. */ + +#undef _POSIX_C_SOURCE +#undef _XOPEN_SOURCE + +#ifndef _XPG4_2 +# define _XPG4_2 +#endif + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif + +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/uio.h> +#if defined(__FreeBSD__) +#include <sys/param.h> +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +static int ndelay_on (int fd) +{ + register int got = fcntl(fd, F_GETFL) ; + return (got == -1) ? -1 : fcntl(fd, F_SETFL, got | O_NONBLOCK) ; +} + +static int child (int p, int fd) +{ + char c ; + struct iovec v = { .iov_base = &c, .iov_len = 1 } ; + struct msghdr msg = + { + .msg_name = 0, + .msg_namelen = 0, + .msg_iov = &v, + .msg_iovlen = 1, + .msg_control = 0, + .msg_controllen = 0 + } ; + fd_set rfds ; + if (ndelay_on(fd) < 0) return 111 ; + FD_ZERO(&rfds) ; + FD_SET(fd, &rfds) ; + if (write(p, "", 1) < 1) return 111 ; /* sync with the parent */ + if (select(fd+1, &rfds, 0, 0, 0) < 1) return 111 ; + + /* The following recvmsg may block, despite setting the fd + non-blocking. That is what we're testing. */ + + if (recvmsg(fd, &msg, MSG_WAITALL) < 1) return 111 ; + if (write(p, "", 1) < 1) return 111 ; + return 0 ; +} + +static int parent (pid_t pid, int p, int fd) +{ + char c ; + struct iovec v = { .iov_base = &c, .iov_len = 1 } ; + struct msghdr msg = + { + .msg_name = 0, + .msg_namelen = 0, + .msg_iov = &v, + .msg_iovlen = 1, + .msg_control = 0, + .msg_controllen = 0 + } ; + struct timeval tv = { .tv_sec = 2, .tv_usec = 0 } ; + fd_set rfds ; + unsigned int n = p > fd ? p : fd ; + int r ; + FD_ZERO(&rfds) ; + FD_SET(p, &rfds) ; + if (read(p, &c, 1) < 1) return 111 ; + if (sendmsg(fd, &msg, MSG_NOSIGNAL) < 1) return 111 ; + for (;;) + { + r = select(n+1, &rfds, 0, 0, &tv) ; + if (r >= 0 || errno != EINTR) break ; + } + if (!r) /* child is still blocking on recvmsg() after 2 seconds */ + { + kill(pid, SIGTERM) ; + return 1 ; + } + if (read(p, &c, 1) < 1) return 111 ; + return 0 ; +} + +int main (void) +{ + pid_t pid ; + int fd[2] ; + int p[2] ; + if (pipe(p) < 0) return 111 ; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) return 111 ; + pid = fork() ; + if (pid < 0) return 111 ; + if (!pid) + { + close(p[0]) ; + close(fd[0]) ; + return child(p[1], fd[1]) ; + } + close(p[1]) ; + close(fd[1]) ; + return parent(pid, p[0], fd[0]) ; +} diff --git a/src/sysdeps/tryokwaitall.c b/src/sysdeps/tryokwaitall.c @@ -1,117 +0,0 @@ -/* ISC license. */ - -#undef _POSIX_C_SOURCE -#undef _XOPEN_SOURCE - -#ifndef _XPG4_2 -# define _XPG4_2 -#endif - -#ifndef _BSD_SOURCE -#define _BSD_SOURCE -#endif - -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <sys/uio.h> -#if defined(__FreeBSD__) -#include <sys/param.h> -#endif - -#ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 -#endif - -static int ndelay_on (int fd) -{ - register int got = fcntl(fd, F_GETFL) ; - return (got == -1) ? -1 : fcntl(fd, F_SETFL, got | O_NONBLOCK) ; -} - -static int child (int p, int fd) -{ - char c ; - struct iovec v = { .iov_base = &c, .iov_len = 1 } ; - struct msghdr msg = - { - .msg_name = 0, - .msg_namelen = 0, - .msg_iov = &v, - .msg_iovlen = 1, - .msg_control = 0, - .msg_controllen = 0 - } ; - fd_set rfds ; - if (ndelay_on(fd) < 0) return 111 ; - FD_ZERO(&rfds) ; - FD_SET(fd, &rfds) ; - if (write(p, "", 1) < 1) return 111 ; /* sync with the parent */ - if (select(fd+1, &rfds, 0, 0, 0) < 1) return 111 ; - - /* On buggy systems, the following recvmsg will block, despite - setting the fd non-blocking */ - - if (recvmsg(fd, &msg, MSG_WAITALL) < 1) return 111 ; - if (write(p, "", 1) < 1) return 111 ; - return 0 ; -} - -static int parent (pid_t pid, int p, int fd) -{ - char c ; - struct iovec v = { .iov_base = &c, .iov_len = 1 } ; - struct msghdr msg = - { - .msg_name = 0, - .msg_namelen = 0, - .msg_iov = &v, - .msg_iovlen = 1, - .msg_control = 0, - .msg_controllen = 0 - } ; - struct timeval tv = { .tv_sec = 2, .tv_usec = 0 } ; - fd_set rfds ; - unsigned int n = p > fd ? p : fd ; - int r ; - FD_ZERO(&rfds) ; - FD_SET(p, &rfds) ; - if (read(p, &c, 1) < 1) return 111 ; - if (sendmsg(fd, &msg, MSG_NOSIGNAL) < 1) return 111 ; - for (;;) - { - r = select(n+1, &rfds, 0, 0, &tv) ; - if (r >= 0 || errno != EINTR) break ; - } - if (!r) /* child is still blocking on recvmsg() after 2 seconds */ - { - kill(pid, SIGTERM) ; - return 1 ; - } - if (read(p, &c, 1) < 1) return 111 ; - return 0 ; -} - -int main (void) -{ - pid_t pid ; - int fd[2] ; - int p[2] ; - if (pipe(p) < 0) return 111 ; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) return 111 ; - pid = fork() ; - if (pid < 0) return 111 ; - if (!pid) - { - close(p[0]) ; - close(fd[0]) ; - return child(p[1], fd[1]) ; - } - close(p[1]) ; - close(fd[1]) ; - return parent(pid, p[0], fd[0]) ; -}