From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29865 invoked by alias); 13 Apr 2004 15:02:35 -0000 Mailing-List: contact libc-hacker-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sources.redhat.com Received: (qmail 29828 invoked from network); 13 Apr 2004 15:02:34 -0000 Received: from unknown (HELO sunsite.ms.mff.cuni.cz) (195.113.15.26) by sources.redhat.com with SMTP; 13 Apr 2004 15:02:34 -0000 Received: from sunsite.ms.mff.cuni.cz (sunsite.mff.cuni.cz [127.0.0.1]) by sunsite.ms.mff.cuni.cz (8.12.8/8.12.8) with ESMTP id i3DCpEHY002007; Tue, 13 Apr 2004 14:51:15 +0200 Received: (from jakub@localhost) by sunsite.ms.mff.cuni.cz (8.12.8/8.12.8/Submit) id i3DCPjUl027038; Tue, 13 Apr 2004 14:25:45 +0200 Date: Tue, 13 Apr 2004 15:02:00 -0000 From: Jakub Jelinek To: Ulrich Drepper Cc: Glibc hackers Subject: [PATCH] Two new mq testcases, one thinko fix Message-ID: <20040413122544.GX514@sunsite.ms.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4i X-SW-Source: 2004-04/txt/msg00028.txt.bz2 Hi! This patch contains 2 new mq tests, fixes a couple of minor nits and a thinko fix in tst-mqueue.h. CLEANUP_HANDLER is run in the parent process of do_test unless --direct, so if some test times out, the message queues would not be cleaned up. tst-mqueue5.c currently fails on current bk kernel, will mail a patch to lkml to fix this. 2004-04-13 Jakub Jelinek * rt/Makefile (tests): Add tst-mqueue5 and tst-mqueue6. * rt/tst-mqueue1.c (do_one_test): Bitwise or check_attrs () into result instead of replacing it. Use TEMP_FAILURE_RETRY around waitpid, kill child if waitpid failed. (do_test): Bitwise or check_attrs () into result instead of replacing it. Change temp mq name. * rt/tst-mqueue5.c: New test. * rt/tst-mqueue6.c: New test. * rt/tst-mqueue.h: Include stdio.h, unistd.h, sys/uio.h. (temp_mq_list, delete_temp_mqs): Remove. (temp_mq_fd): New variable. (do_cleanup, do_prepare): New functions. (add_temp_mq): Rewritten to use a temp file. (PREPARE): Define. (CLEANUP_HANDLER): Change to do_cleanup (). * rt/tst-timer3.c: Don't fail if _POSIX_THREADS is not available. linuxthreads/ * sysdeps/unix/sysv/linux/mq_notify.c: Shut up GCC warning. nptl/ * sysdeps/unix/sysv/linux/mq_notify.c: Shut up GCC warning. --- libc/rt/tst-mqueue1.c.jj 2004-04-13 04:06:21.000000000 +0200 +++ libc/rt/tst-mqueue1.c 2004-04-13 11:16:39.000000000 +0200 @@ -83,7 +83,7 @@ do_one_test (mqd_t q, const char *name, result = 1; } else - result = check_attrs (&attr, nonblock, 0); + result |= check_attrs (&attr, nonblock, 0); if (mq_receive (q, &v[0], 1, NULL) != -1) { @@ -156,7 +156,7 @@ do_one_test (mqd_t q, const char *name, result = 1; } else - result = check_attrs (&attr, nonblock, 10); + result |= check_attrs (&attr, nonblock, 10); pid_t pid = fork (); if (pid == -1) @@ -188,7 +188,7 @@ do_one_test (mqd_t q, const char *name, result = 1; } else - result = check_attrs (&attr, nonblock, 10); + result |= check_attrs (&attr, nonblock, 10); unsigned char vr[11] = { }; unsigned int prio; @@ -272,7 +272,7 @@ do_one_test (mqd_t q, const char *name, result = 1; } else - result = check_attrs (&attr, nonblock, 0); + result |= check_attrs (&attr, nonblock, 0); if (mq_close (q) != 0) { @@ -284,9 +284,10 @@ do_one_test (mqd_t q, const char *name, } int status; - if (waitpid (pid, &status, 0) != pid) + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) { printf ("waitpid failed: %m\n"); + kill (pid, SIGKILL); result = 1; } else if (!WIFEXITED (status) || WEXITSTATUS (status)) @@ -302,7 +303,7 @@ do_one_test (mqd_t q, const char *name, result = 1; } else - result = check_attrs (&attr, nonblock, 0); + result |= check_attrs (&attr, nonblock, 0); return result; } @@ -313,8 +314,8 @@ do_test (void) { int result = 0; - char name[sizeof "/tst-mqueue-" + sizeof (pid_t) * 3]; - snprintf (name, sizeof (name), "/tst-mqueue-%u", getpid ()); + char name[sizeof "/tst-mqueue1-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue1-%u", getpid ()); struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 }; mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr); @@ -327,7 +328,7 @@ do_test (void) else add_temp_mq (name); - result = do_one_test (q, name, 0); + result |= do_one_test (q, name, 0); mqd_t q2 = mq_open (name, O_WRONLY | O_NONBLOCK); if (q2 == (mqd_t) -1) --- libc/rt/Makefile.jj 2004-04-13 10:42:53.000000000 +0200 +++ libc/rt/Makefile 2004-04-13 15:53:21.474843135 +0200 @@ -44,7 +44,7 @@ librt-routines = $(aio-routines) \ tests := tst-shm tst-clock tst-clock_nanosleep tst-timer tst-timer2 \ tst-aio tst-aio64 tst-aio2 tst-aio3 tst-aio4 tst-aio5 tst-aio6 \ tst-aio7 tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \ - tst-timer3 + tst-mqueue5 tst-mqueue6 tst-timer3 extra-libs := librt extra-libs-others := $(extra-libs) --- libc/rt/tst-timer3.c.jj 2004-04-13 07:23:56.000000000 +0200 +++ libc/rt/tst-timer3.c 2004-04-13 11:20:20.000000000 +0200 @@ -9,7 +9,8 @@ #include #include #include -#include +#if _POSIX_THREADS +# include /* Creating timers in another thread should work too. */ @@ -77,5 +78,9 @@ do_test (void) return 0; } -#define TEST_FUNCTION do_test () +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + #include "../test-skeleton.c" --- libc/rt/tst-mqueue5.c.jj 2004-04-13 11:19:19.000000000 +0200 +++ libc/rt/tst-mqueue5.c 2004-04-13 16:20:39.000000000 +0200 @@ -0,0 +1,1008 @@ +/* Test mq_notify. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tst-mqueue.h" + +#define TIMEOUT 3 + +#if _POSIX_THREADS +# include + +volatile int rtmin_cnt; +volatile pid_t rtmin_pid; +volatile uid_t rtmin_uid; +volatile union sigval rtmin_sigval; + +static void +rtmin_handler (int sig, siginfo_t *info, void *ctx) +{ + if (sig != SIGRTMIN) + abort (); + ++rtmin_cnt; + rtmin_pid = info->si_pid; + rtmin_uid = info->si_uid; + rtmin_sigval = info->si_value; +} + +#define mqsend(q) (mqsend) (q, __LINE__) +static inline int +(mqsend) (mqd_t q, int line) +{ + char c; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send on line %d failed with: %m\n", line); + return 1; + } + return 0; +} + +#define mqrecv(q) (mqrecv) (q, __LINE__) +static inline int +(mqrecv) (mqd_t q, int line) +{ + char c; + ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive on line %d failed with: %m\n", line); + else + printf ("mq_receive on line %d returned %zd != 1\n", + line, rets); + return 1; + } + return 0; +} + +struct thr_data +{ + const char *name; + pthread_barrier_t *b3; + mqd_t q; +}; + +static void * +thr (void *arg) +{ + pthread_barrier_t *b3 = ((struct thr_data *)arg)->b3; + mqd_t q = ((struct thr_data *)arg)->q; + const char *name = ((struct thr_data *)arg)->name; + int result = 0; + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal in child did not arrive"); + result = 1; + } + else if (rtmin_pid != getppid () + || rtmin_uid != getuid () + || rtmin_sigval.sival_int != 0xdeadbeef) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), si_int %d (%d)\n", + rtmin_pid, getppid (), rtmin_uid, getuid (), + rtmin_sigval.sival_int, 0xdeadbeef); + result = 1; + } + + struct sigevent ev; + memset (&ev, 0x82, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify in thread (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify in thread (q, NULL) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + if (mq_notify (q, NULL) != 0) + { + printf ("second mq_notify in thread (q, NULL) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + mqd_t q4 = mq_open (name, O_RDONLY); + if (q4 == (mqd_t) -1) + { + printf ("mq_open in thread failed with: %m\n"); + result = 1; + } + + if (mq_notify (q4, NULL) != 0) + { + printf ("mq_notify in thread (q4, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_close (q4) != 0) + { + printf ("mq_close in thread failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + mqd_t q5 = mq_open (name, O_WRONLY); + if (q5 == (mqd_t) -1) + { + printf ("mq_open O_WRONLY in thread failed with: %m\n"); + result = 1; + } + + if (mq_notify (q5, NULL) != 0) + { + printf ("mq_notify in thread (q5, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_close (q5) != 0) + { + printf ("mq_close in thread failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + + return (void *) (long) result; +} + +static void +do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3, + mqd_t q) +{ + int result = 0; + + struct sigevent ev; + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q, &ev) == 0) + { + puts ("first mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("first mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mqsend (q), which makes notification available. */ + + (void) pthread_barrier_wait (b2); + + rtmin_cnt = 0; + + if (mq_notify (q, &ev) != 0) + { + printf ("second mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 0) + { + puts ("SIGRTMIN signal in child caught too early"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent unsuccessfully attempts to mq_notify. */ + /* Parent calls mqsend (q), which makes notification available + and triggers a signal in the child. */ + /* Parent successfully calls mq_notify SIGEV_SIGNAL. */ + + (void) pthread_barrier_wait (b2); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal in child did not arrive"); + result = 1; + } + else if (rtmin_pid != getppid () + || rtmin_uid != getuid () + || rtmin_sigval.sival_ptr != &ev) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), si_ptr %p (%p)\n", + rtmin_pid, getppid (), rtmin_uid, getuid (), + rtmin_sigval.sival_ptr, &ev); + result = 1; + } + + result |= mqsend (q); + + (void) pthread_barrier_wait (b2); + + /* Parent verifies caught SIGRTMIN. */ + + mqd_t q2 = mq_open (name, O_RDWR); + if (q2 == (mqd_t) -1) + { + printf ("mq_open in child failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent mq_open's another mqd_t for the same queue (q3). */ + + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q2, &ev) != 0) + { + printf ("mq_notify in child (q2, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent unsuccessfully attempts to mq_notify { SIGEV_NONE } on q. */ + + (void) pthread_barrier_wait (b2); + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent successfully calls mq_notify { SIGEV_NONE } on q3. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &b2; + if (mq_notify (q, &ev) == 0) + { + puts ("third mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("third mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mq_close on q3, which makes the queue available again for + notification. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0x13, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify in child (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify in child (q, NULL) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + struct thr_data thr_data = { .name = name, .b3 = b3, .q = q }; + pthread_t th; + int ret = pthread_create (&th, NULL, thr, &thr_data); + if (ret) + { + errno = ret; + printf ("pthread_created failed with: %m\n"); + result = 1; + } + + /* Wait till thr calls mq_receive on the empty queue q and blocks on it. */ + sleep (1); + + memset (&ev, 0x5f, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 0xdeadbeef; + if (mq_notify (q, &ev) != 0) + { + printf ("fourth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mqsend (q), which should wake up mqrecv (q) + in the thread but no notification should be sent. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal caught while thr was blocked on mq_receive"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Thread verifies SIGRTMIN has been received. */ + /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now + available for registration. */ + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + memset (&ev, 0x6a, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = do_child; + if (mq_notify (q, &ev) != 0) + { + printf ("fifth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread calls mq_notify (q, NULL), which should unregister the above + notification. */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + memset (&ev, 0x7b, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = thr; + if (mq_notify (q, &ev) != 0) + { + printf ("sixth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_RDONLY mqd_t (q4). */ + /* Thread calls mq_notify (q4, NULL), which should unregister the above + notification. */ + /* Thread calls mq_close (q4). */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + memset (&ev, 0xe1, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 127; + if (mq_notify (q, &ev) != 0) + { + printf ("seventh mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_WRONLY mqd_t (q5). */ + /* Thread calls mq_notify (q5, NULL), which should unregister the above + notification. */ + /* Thread calls mq_close (q5). */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + void *thr_ret; + ret = pthread_join (th, &thr_ret); + if (ret) + { + errno = ret; + printf ("pthread_join failed: %m\n"); + result = 1; + } + else if (thr_ret) + result = 1; + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + exit (result); +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char tmpfname[] = "/tmp/tst-mqueue5-barrier.XXXXXX"; + int fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + size_t ps = sysconf (_SC_PAGESIZE); + char data[ps]; + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + pthread_barrier_t *b2; + b2 = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + pthread_barrier_t *b3; + b3 = b2 + 1; + + pthread_barrierattr_t a; + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed, could not test"); + return 0; + } + + if (pthread_barrier_init (b2, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (b3, &a, 3) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + char name[sizeof "/tst-mqueue5-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue5-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + struct sigevent ev; + memset (&ev, 0xaa, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + result |= mqsend (q); + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + /* Implementation-defined behaviour, so don't fail, + just inform. */ + printf ("second mq_notify (q, NULL) failed with: %m\n"); + } + + struct sigaction sa = { .sa_sigaction = rtmin_handler, + .sa_flags = SA_SIGINFO }; + sigemptyset (&sa.sa_mask); + sigaction (SIGRTMIN, &sa, NULL); + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 26; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 0) + { + puts ("SIGRTMIN signal caught too early"); + result = 1; + } + + result |= mqsend (q); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal did not arrive"); + result = 1; + } + else if (rtmin_pid != getpid () + || rtmin_uid != getuid () + || rtmin_sigval.sival_int != 26) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), si_int %d (26)\n", + rtmin_pid, getpid (), rtmin_uid, getuid (), + rtmin_sigval.sival_int); + result = 1; + } + + ev.sigev_value.sival_int = 75; + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + memset (&ev, 0x33, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("fourth mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork () failed: %m\n"); + mq_unlink (name); + return 1; + } + + if (pid == 0) + do_child (name, b2, b3, q); + + /* Child unsuccessfully attempts to mq_notify. */ + + (void) pthread_barrier_wait (b2); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify SIGEV_SIGNAL now. */ + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 15; + if (mq_notify (q, &ev) == 0) + { + puts ("fourth mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("fourth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + result |= mqsend (q); + + if (mq_notify (q, &ev) != 0) + { + printf ("fifth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal caught too early"); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + /* Child verifies caught SIGRTMIN signal. */ + /* Child calls mq_send (q) which triggers SIGRTMIN signal here. */ + + (void) pthread_barrier_wait (b2); + + /* Child mq_open's another mqd_t for the same queue (q2). */ + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal did not arrive"); + result = 1; + } + else if (rtmin_pid != pid + || rtmin_uid != getuid () + || rtmin_sigval.sival_int != 15) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), si_int %d (15)\n", + rtmin_pid, pid, rtmin_uid, getuid (), + rtmin_sigval.sival_int); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q2. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) == 0) + { + puts ("fifth mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("fifth mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child calls mq_close on q2, which makes the queue available again for + notification. */ + + mqd_t q3 = mq_open (name, O_RDWR); + if (q3 == (mqd_t) -1) + { + printf ("mq_open q3 in parent failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0x12, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q3, &ev) != 0) + { + printf ("mq_notify (q3, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child unsuccessfully attempts to mq_notify { SIGEV_SIGNAL } on q. */ + + (void) pthread_barrier_wait (b2); + + if (mq_close (q3) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify { SIGEV_NONE } on q. */ + /* Child successfully calls mq_notify NULL on q. */ + + (void) pthread_barrier_wait (b2); + + /* Child creates new thread. */ + /* Thread blocks on mqrecv (q). */ + /* Child sleeps for 1sec so that thread has time to reach that point. */ + /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q. */ + + (void) pthread_barrier_wait (b2); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b3); + + /* Thread verifies SIGRTMIN has been caught. */ + /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now + available for registration. */ + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_RDONLY mqd_t (q4). */ + /* Thread calls mq_notify (q4, NULL). */ + /* Thread calls mq_close (q4). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_WRONLY mqd_t (q5). */ + /* Thread calls mq_notify (q5, NULL). */ + /* Thread calls mq_close (q5). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + kill (pid, SIGKILL); + result = 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + printf ("child failed with status %d\n", status); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" --- libc/rt/tst-mqueue.h.jj 2004-04-13 04:07:28.000000000 +0200 +++ libc/rt/tst-mqueue.h 2004-04-13 16:20:04.397578511 +0200 @@ -21,42 +21,64 @@ #include #include #include +#include #include +#include +#include -/* List of temporary files. */ -struct temp_mq_list -{ - struct qelem q; - char name[1]; -} *temp_mq_list; +static int temp_mq_fd; /* Add temporary files in list. */ static void __attribute__ ((unused)) add_temp_mq (const char *name) { - size_t len = strlen (name); - struct temp_mq_list *newp - = (struct temp_mq_list *) calloc (sizeof (*newp) + len, 1); - if (newp != NULL) + struct iovec iov[2]; + iov[0].iov_base = (char *) name; + iov[0].iov_len = strlen (name); + iov[1].iov_base = (char *) "\n"; + iov[1].iov_len = 1; + if (writev (temp_mq_fd, iov, 2) != iov[0].iov_len + 1) + printf ("Could not record temp mq filename %s\n", name); +} + +/* Delete all temporary message queues. */ +static void +do_cleanup (void) +{ + if (lseek (temp_mq_fd, 0, SEEK_SET) != 0) + return; + + FILE *f = fdopen (temp_mq_fd, "r"); + if (f == NULL) + return; + + char *line = NULL; + size_t n = 0; + ssize_t rets; + while ((rets = getline (&line, &n, f)) > 0) { - memcpy (newp->name, name, len + 1); - if (temp_mq_list == NULL) - temp_mq_list = (struct temp_mq_list *) &newp->q; - else - insque (newp, temp_mq_list); + if (line[rets - 1] != '\n') + continue; + + line[rets - 1] = '\0'; + mq_unlink (line); } + fclose (f); } -/* Delete all temporary files. */ static void -delete_temp_mqs (void) +do_prepare (void) { - while (temp_mq_list != NULL) + char name [] = "/tmp/tst-mqueueN.XXXXXX"; + temp_mq_fd = mkstemp (name); + if (temp_mq_fd == -1) { - mq_unlink (temp_mq_list->name); - temp_mq_list = (struct temp_mq_list *) temp_mq_list->q.q_forw; + printf ("Could not create temporary file %s: %m\n", name); + exit (1); } + unlink (name); } -#define CLEANUP_HANDLER delete_temp_mqs () +#define PREPARE(argc, argv) do_prepare () +#define CLEANUP_HANDLER do_cleanup () --- libc/rt/tst-mqueue6.c.jj 2004-04-13 15:05:56.944619986 +0200 +++ libc/rt/tst-mqueue6.c 2004-04-13 16:00:37.165761650 +0200 @@ -0,0 +1,305 @@ +/* Test mq_notify. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tst-mqueue.h" + +#if _POSIX_THREADS +# include + +#define mqsend(q) (mqsend) (q, __LINE__) +static inline int +(mqsend) (mqd_t q, int line) +{ + char c; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send on line %d failed with: %m\n", line); + return 1; + } + return 0; +} + +#define mqrecv(q) (mqrecv) (q, __LINE__) +static inline int +(mqrecv) (mqd_t q, int line) +{ + char c; + ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive on line %d failed with: %m\n", line); + else + printf ("mq_receive on line %d returned %zd != 1\n", + line, rets); + return 1; + } + return 0; +} + +volatile int fct_cnt, fct_err; +size_t fct_guardsize; + +static void +fct (union sigval s) +{ + mqd_t q = *(mqd_t *) s.sival_ptr; + + pthread_attr_t nattr; + int ret = pthread_getattr_np (pthread_self (), &nattr); + if (ret) + { + errno = ret; + printf ("pthread_getattr_np failed: %m\n"); + fct_err = 1; + } + else + { + ret = pthread_attr_getguardsize (&nattr, &fct_guardsize); + if (ret) + { + errno = ret; + printf ("pthread_attr_getguardsize failed: %m\n"); + fct_err = 1; + } + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("pthread_attr_destroy failed"); + fct_err = 1; + } + } + + ++fct_cnt; + fct_err |= mqsend (q); +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue6-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue6-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + pthread_attr_t nattr; + if (pthread_attr_init (&nattr) + || pthread_attr_setguardsize (&nattr, 0)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + fct_guardsize = 1; + + struct sigevent ev; + memset (&ev, 0xaa, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_ptr = &q; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n"); + result = 1; + } + + size_t ps = sysconf (_SC_PAGESIZE); + if (pthread_attr_setguardsize (&nattr, 32 * ps)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (fct_cnt != 0) + { + printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + + result |= mqsend (q); + + result |= mqrecv (q); + result |= mqrecv (q); + + if (fct_cnt != 1) + { + printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + else if (fct_guardsize != 0) + { + printf ("fct_guardsize %zd != 0\n", fct_guardsize); + result = 1; + } + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_ptr = &q; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n"); + result = 1; + } + + if (pthread_attr_setguardsize (&nattr, 0)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (fct_cnt != 1) + { + printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + + result |= mqsend (q); + + result |= mqrecv (q); + result |= mqrecv (q); + + if (fct_cnt != 2) + { + printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + else if (fct_guardsize != 32 * ps) + { + printf ("fct_guardsize %zd != %zd\n", fct_guardsize, 32 * ps); + result = 1; + } + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("pthread_attr_destroy failed"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = NULL; + ev.sigev_value.sival_int = 0; + if (mq_notify (q, &ev) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (fct_err) + result = 1; + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" --- libc/nptl/sysdeps/unix/sysv/linux/mq_notify.c.jj 2004-04-13 04:01:40.000000000 +0200 +++ libc/nptl/sysdeps/unix/sysv/linux/mq_notify.c 2004-04-13 12:49:29.981830310 +0200 @@ -137,6 +137,7 @@ helper_thread (void *arg) /* The only state we keep is the copy of the thread attributes. */ free (data.attr); } + return NULL; } --- libc/linuxthreads/sysdeps/unix/sysv/linux/mq_notify.c.jj 2004-04-13 12:58:26.099750999 +0200 +++ libc/linuxthreads/sysdeps/unix/sysv/linux/mq_notify.c 2004-04-13 12:59:38.670745332 +0200 @@ -137,6 +137,7 @@ helper_thread (void *arg) /* The only state we keep is the copy of the thread attributes. */ free (data.attr); } + return NULL; } Jakub