From patchwork Fri Jun 10 20:35:03 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 12968 Received: (qmail 56678 invoked by alias); 10 Jun 2016 20:35:33 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 56668 invoked by uid 89); 10 Jun 2016 20:35:32 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=formula, 1257, canceled, ch X-HELO: mail-yw0-f177.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id; bh=Nw5EDH/F7pDtPcjy11XEPAngvK1JVRDcn61CD4P4uEI=; b=I+8khYHgAgkEB/52PugHZoP78O5i/n7A5rzuyE5o1soZQ2iridUDKPmngcBji52jZN HoZ5S9VD2Mq+VY+kiSS8/gC3v1sIyftKrMzm8238teMTr3rXUK8w6Lnw8VaobBzMGNse t6ANCi7kStQW5dNJcK0drcoskcAM8sjuQwIYcdYXP99KqH+lz3T5ml+iZUz0CM81iW7J Oddo3HfnDjL+MTuXkrKtdiDIcoeicW1bnsQPekPtPqE/nu9S8sA9+6fhHp4e9+8a1b34 Wr16FdSKmNkUnzlsWl/v+mjQ8t5JnNSrl0/lx28FRKtfUj7HW4y5v70WCd/lGCRn7gAA HYdw== X-Gm-Message-State: ALyK8tJmK6KdAoQv/MWzNn6bPbtSc7W2MHzPIMZlMJ7t7COcZkN5N0BX4g20FP5EmyvrvrT7 X-Received: by 10.13.249.4 with SMTP id j4mr2458873ywf.172.1465590919707; Fri, 10 Jun 2016 13:35:19 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2] nptl: Add sendmmsg and recvmmsg cancellation tests Date: Fri, 10 Jun 2016 17:35:03 -0300 Message-Id: <1465590903-10194-1-git-send-email-adhemerval.zanella@linaro.org> Changes from previous version: - Added separated tests for both sendmmsg and recvmmsg. --- This patch adds cancellation tests for both sendmmsg and recvmmsg syscalls. Since for some system configuration (x86_64/i686 on older kernels and non-Linux platforms), the tests are added as two independent that report as unsupported if the syscall is not presented. Both new tests uses the already tst-cancel4.c code, which as moved to a common tst-cancel4-common{.c,h} files. Tested on x86_64 and i686. * nptl/Makefile (test): Add tst-cancel4_1 and tst-cancel4_2. * nptl/tst-cancel4-common.c: New file. * nptl/tst-cancel4-common.h: Likewise. * nptl/tst-cancel4.c: Move common definitions to tst-cancel4-common.{c,h} file. * nptl/tst-cancel4_1.c: New test. * nptl/tst-cancel4_2.c: New test. --- ChangeLog | 8 ++ nptl/Makefile | 3 +- nptl/tst-cancel4-common.c | 257 ++++++++++++++++++++++++++++++++++++ nptl/tst-cancel4-common.h | 77 +++++++++++ nptl/tst-cancel4.c | 323 +++------------------------------------------- nptl/tst-cancel4_1.c | 127 ++++++++++++++++++ nptl/tst-cancel4_2.c | 125 ++++++++++++++++++ 7 files changed, 611 insertions(+), 309 deletions(-) create mode 100644 nptl/tst-cancel4-common.c create mode 100644 nptl/tst-cancel4-common.h create mode 100644 nptl/tst-cancel4_1.c create mode 100644 nptl/tst-cancel4_2.c diff --git a/ChangeLog b/ChangeLog index 34f51b5..7464021 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2016-06-10 Adhemerval Zanela + * nptl/Makefile (test): Add tst-cancel4_1 and tst-cancel4_2. + * nptl/tst-cancel4-common.c: New file. + * nptl/tst-cancel4-common.h: Likewise. + * nptl/tst-cancel4.c: Move common definitions to + tst-cancel4-common.{c,h} file. + * nptl/tst-cancel4_1.c: New test. + * nptl/tst-cancel4_2.c: New test. + * conform/data/sys/socket.h-data (msghdr.msg_iovlen): Add xfail-. (msghdr.msg_controllen): Likewise. (cmsghdr.cmsg_len): Likewise. diff --git a/nptl/Makefile b/nptl/Makefile index a159b58..e0bc1b7 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -255,7 +255,8 @@ tests = tst-typesizes \ tst-tls1 tst-tls2 \ tst-fork1 tst-fork2 tst-fork3 tst-fork4 \ tst-atfork1 \ - tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \ + tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel4_1 \ + tst-cancel4_2 tst-cancel5 \ tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \ tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \ tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \ diff --git a/nptl/tst-cancel4-common.c b/nptl/tst-cancel4-common.c new file mode 100644 index 0000000..f235d53 --- /dev/null +++ b/nptl/tst-cancel4-common.c @@ -0,0 +1,257 @@ +/* Common file for all tst-cancel4_* + + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +static int +do_test (void) +{ + int val; + socklen_t len; + + if (socketpair (AF_UNIX, SOCK_STREAM, PF_UNIX, fds) != 0) + { + perror ("socketpair"); + exit (1); + } + + val = 1; + len = sizeof(val); + setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); + if (getsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) + { + perror ("getsockopt"); + exit (1); + } + if (val >= WRITE_BUFFER_SIZE) + { + puts ("minimum write buffer size too large"); + exit (1); + } + setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); + + int result = 0; + size_t cnt; + for (cnt = 0; cnt < ntest_tf; ++cnt) + { + if (tests[cnt].only_early) + continue; + + if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + /* Reset the counter for the cleanup handler. */ + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tests[cnt].tf, NULL) != 0) + { + printf ("create for '%s' test failed\n", tests[cnt].name); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + if (pthread_cancel (th) != 0) + { + printf ("cancel for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("join for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("thread for '%s' not canceled\n", tests[cnt].name); + result = 1; + continue; + } + + if (pthread_barrier_destroy (&b2) != 0) + { + puts ("barrier_destroy failed"); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("cleanup handler not called for '%s'\n", tests[cnt].name); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("cleanup handler called more than once for '%s'\n", + tests[cnt].name); + result = 1; + continue; + } + + printf ("in-time cancel test of '%s' successful\n", tests[cnt].name); + + if (tempfd != -1) + { + close (tempfd); + tempfd = -1; + } + if (tempfd2 != -1) + { + close (tempfd2); + tempfd2 = -1; + } + if (tempfname != NULL) + { + unlink (tempfname); + free (tempfname); + tempfname = NULL; + } + if (tempmsg != -1) + { + msgctl (tempmsg, IPC_RMID, NULL); + tempmsg = -1; + } + } + + for (cnt = 0; cnt < ntest_tf; ++cnt) + { + if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + /* Reset the counter for the cleanup handler. */ + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tests[cnt].tf, (void *) 1l) != 0) + { + printf ("create for '%s' test failed\n", tests[cnt].name); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + if (pthread_cancel (th) != 0) + { + printf ("cancel for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("join for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("thread for '%s' not canceled\n", tests[cnt].name); + result = 1; + continue; + } + + if (pthread_barrier_destroy (&b2) != 0) + { + puts ("barrier_destroy failed"); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("cleanup handler not called for '%s'\n", tests[cnt].name); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("cleanup handler called more than once for '%s'\n", + tests[cnt].name); + result = 1; + continue; + } + + printf ("early cancel test of '%s' successful\n", tests[cnt].name); + + if (tempfd != -1) + { + close (tempfd); + tempfd = -1; + } + if (tempfd2 != -1) + { + close (tempfd2); + tempfd2 = -1; + } + if (tempfname != NULL) + { + unlink (tempfname); + free (tempfname); + tempfname = NULL; + } + if (tempmsg != -1) + { + msgctl (tempmsg, IPC_RMID, NULL); + tempmsg = -1; + } + } + + return result; +} + +#define TIMEOUT 60 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/tst-cancel4-common.h b/nptl/tst-cancel4-common.h new file mode 100644 index 0000000..e1683c4 --- /dev/null +++ b/nptl/tst-cancel4-common.h @@ -0,0 +1,77 @@ +/* Common definition for tst-cancel4_* tests. + + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* Pipe descriptors. */ +static int fds[2]; + +/* Temporary file descriptor, to be closed after each round. */ +static int tempfd = -1; +static int tempfd2 = -1; +/* Name of temporary file to be removed after each round. */ +static char *tempfname; +/* Temporary message queue. */ +static int tempmsg = -1; + +/* Often used barrier for two threads. */ +static pthread_barrier_t b2; + +/* The WRITE_BUFFER_SIZE value needs to be chosen such that if we set + the socket send buffer size to '1', a write of this size on that + socket will block. + + The Linux kernel imposes a minimum send socket buffer size which + has changed over the years. As of Linux 3.10 the value is: + + 2 * (2048 + SKB_DATA_ALIGN(sizeof(struct sk_buff))) + + which is attempting to make sure that with standard MTUs, + TCP can always queue up at least 2 full sized packets. + + Furthermore, there is logic in the socket send paths that + will allow one more packet (of any size) to be queued up as + long as some socket buffer space remains. Blocking only + occurs when we try to queue up a new packet and the send + buffer space has already been fully consumed. + + Therefore we must set this value to the largest possible value of + the formula above (and since it depends upon the size of "struct + sk_buff", it is dependent upon machine word size etc.) plus some + slack space. */ + +#define WRITE_BUFFER_SIZE 16384 + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + +struct cancel_tests +{ + const char *name; + void *(*tf) (void *); + int nb; + int only_early; +}; +#define ADD_TEST(name, nbar, early) { #name, tf_##name, nbar, early } diff --git a/nptl/tst-cancel4.c b/nptl/tst-cancel4.c index 60f7ead..4221af4 100644 --- a/nptl/tst-cancel4.c +++ b/nptl/tst-cancel4.c @@ -19,23 +19,21 @@ /* NOTE: this tests functionality beyond POSIX. POSIX does not allow exit to be called more than once. */ -#include -#include -#include -#include -#include #include #include #include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include #include -#include #include -#include -#include -#include -#include #include #include "pthreadP.h" @@ -62,62 +60,17 @@ aio_suspend() is tested in tst-cancel17. clock_nanosleep() is tested in tst-cancel18. -*/ - -/* Pipe descriptors. */ -static int fds[2]; -/* Temporary file descriptor, to be closed after each round. */ -static int tempfd = -1; -static int tempfd2 = -1; -/* Name of temporary file to be removed after each round. */ -static char *tempfname; -/* Temporary message queue. */ -static int tempmsg = -1; - -/* Often used barrier for two threads. */ -static pthread_barrier_t b2; + Linux sendmmsg and recvmmsg are checked in tst-cancel4_1.c and + tst-cancel4_2.c respectively. +*/ +#include "tst-cancel4-common.h" #ifndef IPC_ADDVAL # define IPC_ADDVAL 0 #endif -/* The WRITE_BUFFER_SIZE value needs to be chosen such that if we set - the socket send buffer size to '1', a write of this size on that - socket will block. - - The Linux kernel imposes a minimum send socket buffer size which - has changed over the years. As of Linux 3.10 the value is: - - 2 * (2048 + SKB_DATA_ALIGN(sizeof(struct sk_buff))) - - which is attempting to make sure that with standard MTUs, - TCP can always queue up at least 2 full sized packets. - - Furthermore, there is logic in the socket send paths that - will allow one more packet (of any size) to be queued up as - long as some socket buffer space remains. Blocking only - occurs when we try to queue up a new packet and the send - buffer space has already been fully consumed. - - Therefore we must set this value to the largest possible value of - the formula above (and since it depends upon the size of "struct - sk_buff", it is dependent upon machine word size etc.) plus some - slack space. */ - -#define WRITE_BUFFER_SIZE 16384 - -/* Cleanup handling test. */ -static int cl_called; - -static void -cl (void *arg) -{ - ++cl_called; -} - - static void * tf_read (void *arg) @@ -1391,7 +1344,6 @@ tf_recvmsg (void *arg) exit (1); } - static void * tf_open (void *arg) { @@ -2196,15 +2148,8 @@ tf_msgsnd (void *arg) } -static struct -{ - const char *name; - void *(*tf) (void *); - int nb; - int only_early; -} tests[] = +struct cancel_tests tests[] = { -#define ADD_TEST(name, nbar, early) { #name, tf_##name, nbar, early } ADD_TEST (read, 2, 0), ADD_TEST (readv, 2, 0), ADD_TEST (select, 2, 0), @@ -2249,242 +2194,4 @@ static struct }; #define ntest_tf (sizeof (tests) / sizeof (tests[0])) - -static int -do_test (void) -{ - int val; - socklen_t len; - - if (socketpair (AF_UNIX, SOCK_STREAM, PF_UNIX, fds) != 0) - { - perror ("socketpair"); - exit (1); - } - - val = 1; - len = sizeof(val); - setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); - if (getsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) - { - perror ("getsockopt"); - exit (1); - } - if (val >= WRITE_BUFFER_SIZE) - { - puts ("minimum write buffer size too large"); - exit (1); - } - setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); - - int result = 0; - size_t cnt; - for (cnt = 0; cnt < ntest_tf; ++cnt) - { - if (tests[cnt].only_early) - continue; - - if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) - { - puts ("b2 init failed"); - exit (1); - } - - /* Reset the counter for the cleanup handler. */ - cl_called = 0; - - pthread_t th; - if (pthread_create (&th, NULL, tests[cnt].tf, NULL) != 0) - { - printf ("create for '%s' test failed\n", tests[cnt].name); - result = 1; - continue; - } - - int r = pthread_barrier_wait (&b2); - if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) - { - printf ("%s: barrier_wait failed\n", __FUNCTION__); - result = 1; - continue; - } - - struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; - while (nanosleep (&ts, &ts) != 0) - continue; - - if (pthread_cancel (th) != 0) - { - printf ("cancel for '%s' failed\n", tests[cnt].name); - result = 1; - continue; - } - - void *status; - if (pthread_join (th, &status) != 0) - { - printf ("join for '%s' failed\n", tests[cnt].name); - result = 1; - continue; - } - if (status != PTHREAD_CANCELED) - { - printf ("thread for '%s' not canceled\n", tests[cnt].name); - result = 1; - continue; - } - - if (pthread_barrier_destroy (&b2) != 0) - { - puts ("barrier_destroy failed"); - result = 1; - continue; - } - - if (cl_called == 0) - { - printf ("cleanup handler not called for '%s'\n", tests[cnt].name); - result = 1; - continue; - } - if (cl_called > 1) - { - printf ("cleanup handler called more than once for '%s'\n", - tests[cnt].name); - result = 1; - continue; - } - - printf ("in-time cancel test of '%s' successful\n", tests[cnt].name); - - if (tempfd != -1) - { - close (tempfd); - tempfd = -1; - } - if (tempfd2 != -1) - { - close (tempfd2); - tempfd2 = -1; - } - if (tempfname != NULL) - { - unlink (tempfname); - free (tempfname); - tempfname = NULL; - } - if (tempmsg != -1) - { - msgctl (tempmsg, IPC_RMID, NULL); - tempmsg = -1; - } - } - - for (cnt = 0; cnt < ntest_tf; ++cnt) - { - if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) - { - puts ("b2 init failed"); - exit (1); - } - - /* Reset the counter for the cleanup handler. */ - cl_called = 0; - - pthread_t th; - if (pthread_create (&th, NULL, tests[cnt].tf, (void *) 1l) != 0) - { - printf ("create for '%s' test failed\n", tests[cnt].name); - result = 1; - continue; - } - - int r = pthread_barrier_wait (&b2); - if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) - { - printf ("%s: barrier_wait failed\n", __FUNCTION__); - result = 1; - continue; - } - - if (pthread_cancel (th) != 0) - { - printf ("cancel for '%s' failed\n", tests[cnt].name); - result = 1; - continue; - } - - r = pthread_barrier_wait (&b2); - if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) - { - printf ("%s: barrier_wait failed\n", __FUNCTION__); - result = 1; - continue; - } - - void *status; - if (pthread_join (th, &status) != 0) - { - printf ("join for '%s' failed\n", tests[cnt].name); - result = 1; - continue; - } - if (status != PTHREAD_CANCELED) - { - printf ("thread for '%s' not canceled\n", tests[cnt].name); - result = 1; - continue; - } - - if (pthread_barrier_destroy (&b2) != 0) - { - puts ("barrier_destroy failed"); - result = 1; - continue; - } - - if (cl_called == 0) - { - printf ("cleanup handler not called for '%s'\n", tests[cnt].name); - result = 1; - continue; - } - if (cl_called > 1) - { - printf ("cleanup handler called more than once for '%s'\n", - tests[cnt].name); - result = 1; - continue; - } - - printf ("early cancel test of '%s' successful\n", tests[cnt].name); - - if (tempfd != -1) - { - close (tempfd); - tempfd = -1; - } - if (tempfd2 != -1) - { - close (tempfd2); - tempfd2 = -1; - } - if (tempfname != NULL) - { - unlink (tempfname); - free (tempfname); - tempfname = NULL; - } - if (tempmsg != -1) - { - msgctl (tempmsg, IPC_RMID, NULL); - tempmsg = -1; - } - } - - return result; -} - -#define TIMEOUT 60 -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include "tst-cancel4-common.c" diff --git a/nptl/tst-cancel4_1.c b/nptl/tst-cancel4_1.c new file mode 100644 index 0000000..68296ec --- /dev/null +++ b/nptl/tst-cancel4_1.c @@ -0,0 +1,127 @@ +/* Check sendmmsg cancellation. + + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tst-cancel4-common.h" + +static void * +tf_sendmmsg (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which sendmmsg() + // blocks we can enable this test to run in both rounds. + abort (); + + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-7-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[1]; + struct iovec iov[1]; + iov[0].iov_base = mem; + iov[0].iov_len = 1; + + struct mmsghdr mm; + mm.msg_hdr.msg_name = &sun; + mm.msg_hdr.msg_namelen = (offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1); + mm.msg_hdr.msg_iov = iov; + mm.msg_hdr.msg_iovlen = 1; + mm.msg_hdr.msg_control = NULL; + mm.msg_hdr.msg_controllen = 0; + + ssize_t ret = sendmmsg (tempfd2, &mm, 1, 0); + if (ret == -1 && errno == ENOSYS) + exit (77); + + pthread_cleanup_pop (0); + + printf ("%s: sendmmsg returned\n", __FUNCTION__); + + exit (1); +} + +struct cancel_tests tests[] = +{ + ADD_TEST (sendmmsg, 2, 1), +}; +#define ntest_tf (sizeof (tests) / sizeof (tests[0])) + +#include "tst-cancel4-common.c" diff --git a/nptl/tst-cancel4_2.c b/nptl/tst-cancel4_2.c new file mode 100644 index 0000000..e8d7550 --- /dev/null +++ b/nptl/tst-cancel4_2.c @@ -0,0 +1,125 @@ +/* Check recvmmsg cancellation. + + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tst-cancel4-common.h" + +static void * +tf_recvmmsg (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-5-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + char mem[70]; + struct iovec iov[1]; + iov[0].iov_base = mem; + iov[0].iov_len = arg == NULL ? sizeof (mem) : 0; + + struct mmsghdr mm; + mm.msg_hdr.msg_name = &sun; + mm.msg_hdr.msg_namelen = sizeof (sun); + mm.msg_hdr.msg_iov = iov; + mm.msg_hdr.msg_iovlen = 1; + mm.msg_hdr.msg_control = NULL; + mm.msg_hdr.msg_controllen = 0; + + ssize_t ret = recvmmsg (tempfd2, &mm, 1, 0, NULL); + if (ret == -1 && errno == ENOSYS) + exit (77); + + pthread_cleanup_pop (0); + + printf ("%s: recvmmsg returned\n", __FUNCTION__); + + exit (1); +} + +struct cancel_tests tests[] = +{ + ADD_TEST (recvmmsg, 2, 1), +}; +#define ntest_tf (sizeof (tests) / sizeof (tests[0])) + +#include "tst-cancel4-common.c"