diff options
49 files changed, 2690 insertions, 30 deletions
@@ -1,3 +1,44 @@ +2004-04-08 Ulrich Drepper <drepper@redhat.com> + + * rt/tst-mqueue3.c: New file. + * rt/Makefile (tests): Add tst-mqueue3. + +2004-04-08 Jakub Jelinek <jakub@redhat.com> + + * rt/tst-mqueue1.c: New file. + * rt/tst-mqueue2.c: New file. + * rt/tst-mqueue4.c: New file. + * rt/Makefile (tests): Add tst-mqueue1, tst-mqueue2, tst-mqueue4. + + * rt/Versions (librt): Add mq_*@@GLIBC_2.3.4. + * rt/Makefile (headers): Add mqueue.h and bits/mqueue.h. + (mq-routines): Set. + (librt-routines): Use it. + * rt/mqueue.h: New file. + * include/mqueue.h: New file. + * sysdeps/generic/bits/mqueue.h: New file. + * sysdeps/generic/mq_setattr.c: New file. + * sysdeps/generic/mq_getattr.c: New file. + * sysdeps/generic/mq_notify.c: New file. + * sysdeps/generic/mq_close.c: New file. + * sysdeps/generic/mq_send.c: New file. + * sysdeps/generic/mq_unlink.c: New file. + * sysdeps/generic/mq_receive.c: New file. + * sysdeps/generic/mq_timedreceive.c: New file. + * sysdeps/generic/mq_timedsend.c: New file. + * sysdeps/generic/mq_open.c: New file. + * sysdeps/unix/sysv/linux/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/bits/mqueue.h: New file. + * sysdeps/unix/sysv/linux/syscalls.list: Add mq_timedsend, + mq_timedreceive and mq_setattr. + * sysdeps/unix/sysv/linux/mq_getattr.c: New file. + * sysdeps/unix/sysv/linux/mq_notify.c: New file. + * sysdeps/unix/sysv/linux/mq_close.c: New file. + * sysdeps/unix/sysv/linux/mq_send.c: New file. + * sysdeps/unix/sysv/linux/mq_unlink.c: New file. + * sysdeps/unix/sysv/linux/mq_receive.c: New file. + * sysdeps/unix/sysv/linux/mq_open.c: New file. + 2004-04-09 Andreas Schwab <schwab@suse.de> * sysdeps/unix/sysv/linux/ia64/sysdep.h (DO_INLINE_SYSCALL): Move @@ -18,14 +59,6 @@ (LOAD_REGS_5, LOAD_REGS_6): New macros to actually load the syscall argument registers. -2004-04-09 Thorsten Kukuk <kukuk@suse.de> - - * sysdeps/s390/ffs.c: Don't add ffsl weak alias on s390x. - -2004-04-09 Steven Munroe <sjmunroe@us.ibm.com> - - * sysdeps/unix/sysv/linux/powerpc/powerpc64/umount.c: New file. - 2004-04-09 Andreas Schwab <schwab@suse.de> * sysdeps/unix/sysv/linux/m68k/sysdep.h (INTERNAL_SYSCALL): Add @@ -37,6 +70,14 @@ (LOAD_REGS_5, LOAD_REGS_6): New macros to actually load the syscall argument registers. +2004-04-09 Thorsten Kukuk <kukuk@suse.de> + + * sysdeps/s390/ffs.c: Don't add ffsl weak alias on s390x. + +2004-04-09 Steven Munroe <sjmunroe@us.ibm.com> + + * sysdeps/unix/sysv/linux/powerpc/powerpc64/umount.c: New file. + 2004-04-08 Ulrich Drepper <drepper@redhat.com> * po/nl.po: Update from translation team. diff --git a/bits/mqueue.h b/bits/mqueue.h new file mode 100644 index 0000000..27bb482 --- /dev/null +++ b/bits/mqueue.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _MQUEUE_H +# error "Never use <bits/mqueue.h> directly; include <mqueue.h> instead." +#endif + +typedef int mqd_t; + +struct mq_attr +{ + long int mq_flags; /* Message queue flags. */ + long int mq_maxmsg; /* Maximum number of messages. */ + long int mq_msgsize; /* Maximum message size. */ + long int mq_curmsgs; /* Number of messages currently queued. */ +}; diff --git a/include/mqueue.h b/include/mqueue.h new file mode 100644 index 0000000..1ac4f13 --- /dev/null +++ b/include/mqueue.h @@ -0,0 +1,7 @@ +#include <rt/mqueue.h> + +#ifdef IS_IN_librt +hidden_proto (mq_timedsend) +hidden_proto (mq_timedreceive) +hidden_proto (mq_setattr) +#endif diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index cbdfc73..ad881d4 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -1,3 +1,14 @@ +2004-04-08 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_MESSAGE_PASSING): + Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + 2004-04-10 Andreas Jaeger <aj@suse.de> * sysdeps/x86_64/pt-machine.h: Add used attribute to stack_pointer diff --git a/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h b/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h index e08763b..96893c5 100644 --- a/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h +++ b/linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h @@ -87,3 +87,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/linuxthreads/sysdeps/unix/sysv/linux/bits/local_lim.h b/linuxthreads/sysdeps/unix/sysv/linux/bits/local_lim.h index 4027c4d..ed6c3c5 100644 --- a/linuxthreads/sysdeps/unix/sysv/linux/bits/local_lim.h +++ b/linuxthreads/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -87,3 +87,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h b/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h index 3dae916..06fd0a2 100644 --- a/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h +++ b/linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -1,5 +1,5 @@ /* Define POSIX options for Linux. - Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1996-2001, 2002, 2003, 2004 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 @@ -129,8 +129,8 @@ /* The barrier functions are available. */ #define _POSIX_BARRIERS 200112L -/* POSIX message queues are not yet supported. */ -#undef _POSIX_MESSAGE_PASSING +/* POSIX message queues are available. */ +#define _POSIX_MESSAGE_PASSING 200112L /* The monotonic clock might be available. */ #define _POSIX_MONOTONIC_CLOCK 0 diff --git a/linuxthreads/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h b/linuxthreads/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h index 02da4d7..18a840e 100644 --- a/linuxthreads/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h +++ b/linuxthreads/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h @@ -1,5 +1,5 @@ /* Define POSIX options for Linux/ix86. - Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1996-2001, 2002, 2003, 2004 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 @@ -135,8 +135,8 @@ /* The barrier functions are available. */ #define _POSIX_BARRIERS 200112L -/* POSIX message queues are not yet supported. */ -#undef _POSIX_MESSAGE_PASSING +/* POSIX message queues are available. */ +#define _POSIX_MESSAGE_PASSING 200112L /* The monotonic clock might be available. */ #define _POSIX_MONOTONIC_CLOCK 0 diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h b/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h index 73fa616..629b1f8 100644 --- a/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h +++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h @@ -87,3 +87,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h index 6021294..27ffa66 100644 --- a/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h +++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h @@ -87,3 +87,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/nptl/ChangeLog b/nptl/ChangeLog index c197dd4..53fba00 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,22 @@ +2004-04-12 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/mq-notify.c: New file. + +2004-04-08 Jakub Jelinek <jakub@redhat.com> + + * sysdeps/unix/sysv/linux/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/alpha/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/ia64/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/sparc/bits/local_lim.h (MQ_PRIO_MAX): Define. + * sysdeps/unix/sysv/linux/bits/posix_opt.h (_POSIX_MESSAGE_PASSING): + Define. + * sysdeps/unix/sysv/linux/i386/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + * sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + * sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h + (_POSIX_MESSAGE_PASSING): Define. + 2004-04-04 Ulrich Drepper <drepper@redhat.com> * tst-context1.c (fct): Check whether correct stack is used. diff --git a/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h b/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h index bb3c4c0..e071878 100644 --- a/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h +++ b/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h @@ -84,3 +84,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h b/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h index 0c2a2bd..0bc8e04 100644 --- a/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h +++ b/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -84,3 +84,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h index 67a37d0..7335e38 100644 --- a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h +++ b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -1,5 +1,5 @@ /* Define POSIX options for Linux. - Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1996-2001, 2002, 2003, 2004 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 @@ -126,8 +126,8 @@ /* The barrier functions are available. */ #define _POSIX_BARRIERS 200112L -/* POSIX message queues are not yet supported. */ -#undef _POSIX_MESSAGE_PASSING +/* POSIX message queues are available. */ +#define _POSIX_MESSAGE_PASSING 200112L /* Thread process-shared synchronization is supported. */ #define _POSIX_THREAD_PROCESS_SHARED 200112L diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h index 4bc4eed..7563de8 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h +++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h @@ -1,5 +1,5 @@ /* Define POSIX options for Linux. - Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1996-2001, 2002, 2003, 2004 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 @@ -132,8 +132,8 @@ /* The barrier functions are available. */ #define _POSIX_BARRIERS 200112L -/* POSIX message queues are not yet supported. */ -#undef _POSIX_MESSAGE_PASSING +/* POSIX message queues are available. */ +#define _POSIX_MESSAGE_PASSING 200112L /* Thread process-shared synchronization is supported. */ #define _POSIX_THREAD_PROCESS_SHARED 200112L diff --git a/nptl/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h b/nptl/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h index 5d64136..f837250 100644 --- a/nptl/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h +++ b/nptl/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h @@ -84,3 +84,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/nptl/sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h index 4bc4eed..7563de8 100644 --- a/nptl/sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h +++ b/nptl/sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h @@ -1,5 +1,5 @@ /* Define POSIX options for Linux. - Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1996-2001, 2002, 2003, 2004 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 @@ -132,8 +132,8 @@ /* The barrier functions are available. */ #define _POSIX_BARRIERS 200112L -/* POSIX message queues are not yet supported. */ -#undef _POSIX_MESSAGE_PASSING +/* POSIX message queues are available. */ +#define _POSIX_MESSAGE_PASSING 200112L /* Thread process-shared synchronization is supported. */ #define _POSIX_THREAD_PROCESS_SHARED 200112L diff --git a/nptl/sysdeps/unix/sysv/linux/mq_notify.c b/nptl/sysdeps/unix/sysv/linux/mq_notify.c new file mode 100644 index 0000000..e231e59 --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/mq_notify.c @@ -0,0 +1,285 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contribute by Ulrich Drepper <drepper@redhat.com>, 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 <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <pthread.h> +#include <signal.h> +#include <string.h> +#include <sysdep.h> +#include <unistd.h> +#include <sys/socket.h> +#include <not-cancel.h> + + +#ifdef __NR_mq_notify + +/* Defined in the kernel headers: */ +#define NOTIFY_COOKIE_LEN 32 /* Length of the cookie used. */ +#define NOTIFY_WOKENUP 1 /* Code for notifcation. */ +#define NOTIFY_REMOVED 2 /* Code for closed message queue + of de-notifcation. */ + + +/* Data structure for the queued notification requests. */ +union notify_data +{ + struct + { + void (*fct) (union sigval); /* The function to run. */ + union sigval param; /* The parameter to pass. */ + pthread_attr_t *attr; /* Attributes to create the thread with. */ + /* NB: on 64-bit machines the struct as a size of 24 bytes. Which means + byte 31 can still be used for returning the status. */ + }; + char raw[NOTIFY_COOKIE_LEN]; +}; + + +/* Keep track of the initialization. */ +static pthread_once_t once = PTHREAD_ONCE_INIT; + + +/* The netlink socket. */ +static int netlink_socket = -1; + + +/* Barrier used to make sure data passed to the new thread is not + resused by the parent. */ +static pthread_barrier_t notify_barrier; + + +/* Modify the signal mask. We move this into a separate function so + that the stack space needed for sigset_t is not deducted from what + the thread can use. */ +static int +__attribute__ ((noinline)) +change_sigmask (int how, sigset_t *oss) +{ + sigset_t ss; + sigfillset (&ss); + return pthread_sigmask (how, &ss, oss); +} + + +/* The function used for the notification. */ +static void * +notification_function (void *arg) +{ + /* Copy the function and parameter so that the parent thread can go + on with its life. */ + volatile union notify_data *data = (volatile union notify_data *) arg; + void (*fct) (union sigval) = data->fct; + union sigval param = data->param; + + /* Let the parent go. */ + (void) pthread_barrier_wait (¬ify_barrier); + + /* Make the thread detached. */ + (void) pthread_detach (pthread_self ()); + + /* The parent thread has all signals blocked. This is probably a + bit surprising for this thread. So we unblock all of them. */ + (void) change_sigmask (SIG_UNBLOCK, NULL); + + /* Now run the user code. */ + fct (param); + + /* And we are done. */ + return NULL; +} + + +/* Helper thread. */ +static void * +helper_thread (void *arg) +{ + while (1) + { + union notify_data data; + + ssize_t n = recv (netlink_socket, &data, sizeof (data), + MSG_NOSIGNAL | MSG_WAITALL); + if (n < NOTIFY_COOKIE_LEN) + continue; + + if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_WOKENUP) + { + /* Just create the thread as instructed. There is no way to + report a problem with creating a thread. */ + pthread_t th; + if (__builtin_expect (pthread_create (&th, data.attr, + notification_function, &data) + == 0, 0)) + /* Since we passed a pointer to DATA to the new thread we have + to wait until it is done with it. */ + (void) pthread_barrier_wait (¬ify_barrier); + } + else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) + /* The only state we keep is the copy of the thread attributes. */ + free (data.attr); + } +} + + +static void +reset_once (void) +{ + once = PTHREAD_ONCE_INIT; +} + + +static void +init_mq_netlink (void) +{ + /* This code might be called a second time after fork(). The file + descriptor is inherited from the parent. */ + if (netlink_socket == -1) + { + /* Just a normal netlink socket, not bound. */ + netlink_socket = socket (AF_NETLINK, SOCK_RAW, 0); + /* No need to do more if we have no socket. */ + if (netlink_socket == -1) + return; + + /* Make sure the descriptor is closed on exec. */ + if (fcntl (netlink_socket, F_SETFD, FD_CLOEXEC) != 0) + goto errout; + } + + int err = 1; + + /* Initialize the barrier. */ + if (__builtin_expect (pthread_barrier_init (¬ify_barrier, NULL, 2) == 0, + 0)) + { + /* Create the helper thread. */ + pthread_attr_t attr; + (void) pthread_attr_init (&attr); + (void) pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + /* We do not need much stack space, the bare minimum will be enough. */ + (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + + /* Temporarily block all signals so that the newly created + thread inherits the mask. */ + sigset_t oss; + int have_no_oss = change_sigmask (SIG_BLOCK, &oss); + + pthread_t th; + err = pthread_create (&th, &attr, helper_thread, NULL); + + /* Reset the signal mask. */ + if (!have_no_oss) + pthread_sigmask (SIG_SETMASK, &oss, NULL); + + (void) pthread_attr_destroy (&attr); + + if (err == 0) + { + static int added_atfork; + + if (added_atfork == 0 + && pthread_atfork (NULL, NULL, reset_once) != 0) + { + /* The child thread will call recv() which is a + cancellation point. */ + (void) pthread_cancel (th); + err = 1; + } + else + added_atfork = 1; + } + } + + if (err != 0) + { + errout: + close_not_cancel_no_status (netlink_socket); + netlink_socket = -1; + } +} + + +/* Register notification upon message arrival to an empty message queue + MQDES. */ +int +mq_notify (mqd_t mqdes, const struct sigevent *notification) +{ + /* Make sure the type is correctly defined. */ + assert (sizeof (union notify_data) == NOTIFY_COOKIE_LEN); + + /* Special treatment needed for SIGEV_THREAD. */ + if (notification == NULL || notification->sigev_notify != SIGEV_THREAD) + return INLINE_SYSCALL (mq_notify, 2, mqdes, notification); + + /* The kernel cannot directly start threads. This will have to be + done at userlevel. Since we cannot start threads from signal + handlers we have to create a dedicated thread which waits for + notifications for arriving messages and creates threads in + response. */ + + /* Initialize only once. */ + pthread_once (&once, init_mq_netlink); + + /* If we cannot create the netlink socket we cannot provide + SIGEV_THREAD support. */ + if (__builtin_expect (netlink_socket == -1, 0)) + { + __set_errno (ENOSYS); + return -1; + } + + /* Create the cookie. It will hold almost all the state. */ + union notify_data data; + memset (&data, '\0', sizeof (data)); + data.fct = notification->sigev_notify_function; + data.param = notification->sigev_value; + + if (notification->sigev_notify_attributes != NULL) + { + /* The thread attribute has to be allocated separately. */ + data.attr = (pthread_attr_t *) malloc (sizeof (pthread_attr_t)); + if (data.attr == NULL) + return -1; + + memcpy (data.attr, notification->sigev_notify_attributes, + sizeof (pthread_attr_t)); + } + + /* Construct the new request. */ + struct sigevent se; + se.sigev_notify = SIGEV_THREAD; + se.sigev_signo = netlink_socket; + se.sigev_value.sival_ptr = &data; + + /* Tell the kernel. */ + int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se); + + /* If it failed, free the allocated memory. */ + if (__builtin_expect (retval != 0, 0)) + free (data.attr); + + return retval; +} + +#else +# include <sysdeps/generic/mq_notify.c> +#endif diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h b/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h index 1cfa807..e082ea8 100644 --- a/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h +++ b/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h @@ -84,3 +84,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h index 4bc4eed..7563de8 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h @@ -1,5 +1,5 @@ /* Define POSIX options for Linux. - Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1996-2001, 2002, 2003, 2004 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 @@ -132,8 +132,8 @@ /* The barrier functions are available. */ #define _POSIX_BARRIERS 200112L -/* POSIX message queues are not yet supported. */ -#undef _POSIX_MESSAGE_PASSING +/* POSIX message queues are available. */ +#define _POSIX_MESSAGE_PASSING 200112L /* Thread process-shared synchronization is supported. */ #define _POSIX_THREAD_PROCESS_SHARED 200112L diff --git a/rt/Makefile b/rt/Makefile index 4716789..fd51852 100644 --- a/rt/Makefile +++ b/rt/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1997-2001, 2002, 2003 Free Software Foundation, Inc. +# Copyright (C) 1997-2001, 2002, 2003, 2004 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 @@ -21,7 +21,7 @@ # subdir := rt -headers := aio.h +headers := aio.h mqueue.h bits/mqueue.h aio-routines := aio_cancel aio_error aio_fsync aio_misc aio_read \ aio_read64 aio_return aio_suspend aio_write \ @@ -33,14 +33,17 @@ clock-routines := get_clockfreq clock_getcpuclockid \ timer-routines := timer_create timer_delete timer_getoverr \ timer_gettime timer_settime shm-routines := shm_open shm_unlink +mq-routines := mq_open mq_close mq_unlink mq_getattr mq_setattr \ + mq_notify mq_send mq_receive mq_timedsend \ + mq_timedreceive librt-routines = $(aio-routines) \ $(clock-routines) $(timer-routines) \ - $(shm-routines) + $(shm-routines) $(mq-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-aio7 tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 extra-libs := librt extra-libs-others := $(extra-libs) @@ -53,6 +56,8 @@ CFLAGS-aio_suspend.c = -fexceptions CFLAGS-clock_nanosleep.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-librt-cancellation.c = -fasynchronous-unwind-tables +LDFLAGS-rt.so = -Wl,--enable-new-dtags,-z,nodelete + # Depend on libc.so so a DT_NEEDED is generated in the shared objects. # This ensures they will load libc.so for needed symbols if loaded by # a statically-linked program that hasn't already loaded it. diff --git a/rt/Versions b/rt/Versions index 133f374..a7d633d 100644 --- a/rt/Versions +++ b/rt/Versions @@ -17,4 +17,9 @@ librt { timer_create; timer_delete; timer_getoverrun; timer_gettime; timer_settime; } + GLIBC_2.3.4 { + # m* + mq_open; mq_close; mq_unlink; mq_getattr; mq_setattr; + mq_notify; mq_send; mq_receive; mq_timedsend; mq_timedreceive; + } } diff --git a/rt/mqueue.h b/rt/mqueue.h new file mode 100644 index 0000000..42313b1 --- /dev/null +++ b/rt/mqueue.h @@ -0,0 +1,91 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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. */ + +#ifndef _MQUEUE_H +#define _MQUEUE_H 1 + +#include <features.h> +#include <sys/types.h> +#include <fcntl.h> +#define __need_sigevent_t +#include <bits/siginfo.h> +#define __need_timespec +#include <time.h> +/* Get the definition of mqd_t and struct mq_attr. */ +#include <bits/mqueue.h> + +__BEGIN_DECLS + +/* Establish connection between a process and a message queue NAME and + return message queue descriptor or (mqd_t) -1 on error. OFLAG determines + the type of access used. If O_CREAT is on OFLAG, the third argument is + taken as a `mode_t', the mode of the created message queue, and the fourth + argument is taken as `struct mq_attr *', pointer to message queue + attributes. If the fourth argument is NULL, default attributes are + used. */ +extern mqd_t mq_open (const char *__name, int __oflag, ...) __THROW; + +/* Removes the association between message queue descriptor MQDES and its + message queue. */ +extern int mq_close (mqd_t __mqdes) __THROW; + +/* Query status and attributes of message queue MQDES. */ +extern int mq_getattr (mqd_t __mqdes, struct mq_attr *__mqstat) __THROW; + +/* Set attributes associated with message queue MQDES and if OMQSTAT is + not NULL also query its old attributes. */ +extern int mq_setattr (mqd_t __mqdes, + const struct mq_attr *__restrict __mqstat, + struct mq_attr *__restrict __omqstat) __THROW; + +/* Remove message queue named NAME. */ +extern int mq_unlink (const char *__name) __THROW; + +/* Register notification upon message arrival to an empty message queue + MQDES. */ +extern int mq_notify (mqd_t __mqdes, const struct sigevent *__notification) + __THROW; + +/* Receive the oldest from highest priority messages in message queue + MQDES. */ +extern ssize_t mq_receive (mqd_t __mqdes, char *__msg_ptr, size_t __msg_len, + unsigned int *__msg_prio); + +/* Add message pointed by MSG_PTR to message queue MQDES. */ +extern int mq_send (mqd_t __mqdes, const char *__msg_ptr, size_t __msg_len, + unsigned int __msg_prio); + +#ifdef __USE_XOPEN2K +/* Receive the oldest from highest priority messages in message queue + MQDES, stop waiting if ABS_TIMEOUT expires. */ +extern ssize_t mq_timedreceive (mqd_t __mqdes, char *__restrict __msg_ptr, + size_t __msg_len, + unsigned int *__restrict __msg_prio, + const struct timespec *__restrict __abs_timeout); + +/* Add message pointed by MSG_PTR to message queue MQDES, stop blocking + on full message queue if ABS_TIMEOUT expires. */ +extern int mq_timedsend (mqd_t __mqdes, const char *__msg_ptr, + size_t __msg_len, unsigned int __msg_prio, + const struct timespec *__abs_timeout); +#endif + +__END_DECLS + +#endif /* mqueue.h */ diff --git a/rt/tst-mqueue.h b/rt/tst-mqueue.h new file mode 100644 index 0000000..3659795 --- /dev/null +++ b/rt/tst-mqueue.h @@ -0,0 +1,62 @@ +/* Common code for message queue passing tests. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <mqueue.h> +#include <search.h> +#include <stdlib.h> +#include <string.h> + +/* List of temporary files. */ +struct temp_mq_list +{ + struct qelem q; + char name[1]; +} *temp_mq_list; + +/* 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) + { + 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); + } +} + +/* Delete all temporary files. */ +static void +delete_temp_mqs (void) +{ + while (temp_mq_list != NULL) + { + mq_unlink (temp_mq_list->name); + temp_mq_list = (struct temp_mq_list *) temp_mq_list->q.q_forw; + } +} + +#define CLEANUP_HANDLER delete_temp_mqs () diff --git a/rt/tst-mqueue1.c b/rt/tst-mqueue1.c new file mode 100644 index 0000000..a6f8fb5 --- /dev/null +++ b/rt/tst-mqueue1.c @@ -0,0 +1,416 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +static int +intcmp (const void *a, const void *b) +{ + if (*(unsigned char *)a < *(unsigned char *)b) + return 1; + if (*(unsigned char *)a > *(unsigned char *)b) + return -1; + return 0; +} + +static int +check_attrs (struct mq_attr *attr, int nonblock, long cnt) +{ + int result = 0; + + if (attr->mq_maxmsg != 10 || attr->mq_msgsize != 1) + { + printf ("attributes don't match those passed to mq_open\n" + "mq_maxmsg %ld, mq_msgsize %ld\n", + attr->mq_maxmsg, attr->mq_msgsize); + result = 1; + } + + if ((attr->mq_flags & O_NONBLOCK) != nonblock) + { + printf ("mq_flags %lx != %x\n", (attr->mq_flags & O_NONBLOCK), nonblock); + result = 1; + } + + if (attr->mq_curmsgs != cnt) + { + printf ("mq_curmsgs %ld != %ld\n", attr->mq_curmsgs, cnt); + result = 1; + } + + return result; +} + +static int +do_one_test (mqd_t q, const char *name, int nonblock) +{ + int result = 0; + + unsigned char v [] + = { 0x32, 0x62, 0x22, 0x31, 0x11, 0x73, 0x61, 0x21, 0x72, 0x71, 0x81 }; + + struct mq_attr attr; + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result = check_attrs (&attr, nonblock, 0); + + if (mq_receive (q, &v[0], 1, NULL) != -1) + { + puts ("mq_receive on O_WRONLY mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_receive on O_WRONLY mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + --ts.tv_sec; + else + { + ts.tv_sec = time (NULL) - 1; + ts.tv_nsec = 0; + } + + int ret; + for (int i = 0; i < 10; ++i) + { + if (i & 1) + ret = mq_send (q, &v[i], 1, v[i] >> 4); + else + ret = mq_timedsend (q, &v[i], 1, v[i] >> 4, &ts); + + if (ret) + { + printf ("mq_%ssend failed: %m\n", (i & 1) ? "" : "timed"); + result = 1; + } + } + + ret = mq_timedsend (q, &v[10], 1, 8, &ts); + if (ret != -1) + { + puts ("mq_timedsend on full queue did not fail"); + result = 1; + } + else if (errno != (nonblock ? EAGAIN : ETIMEDOUT)) + { + printf ("mq_timedsend on full queue did not fail with %s: %m\n", + nonblock ? "EAGAIN" : "ETIMEDOUT"); + result = 1; + } + + if (nonblock) + { + ret = mq_send (q, &v[10], 1, 8); + if (ret != -1) + { + puts ("mq_send on full non-blocking queue did not fail"); + result = 1; + } + else if (errno != EAGAIN) + { + printf ("mq_send on full non-blocking queue did not fail" + "with EAGAIN: %m\n"); + result = 1; + } + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result = check_attrs (&attr, nonblock, 10); + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + result = 1; + } + else if (pid == 0) + { + result = 0; + + if (mq_close (q) != 0) + { + printf ("mq_close in child failed: %m\n"); + result = 1; + } + + q = mq_open (name, O_RDONLY | nonblock); + if (q == (mqd_t) -1) + { + printf ("mq_open in child failed: %m\n"); + exit (1); + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result = check_attrs (&attr, nonblock, 10); + + unsigned char vr[11] = { }; + unsigned int prio; + ssize_t rets; + + if (mq_send (q, &v[0], 1, 1) != -1) + { + puts ("mq_send on O_RDONLY mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_send on O_WRONLY mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + for (int i = 0; i < 10; ++i) + { + if (i & 1) + rets = mq_receive (q, &vr[i], 1, &prio); + else + rets = mq_timedreceive (q, &vr[i], 1, &prio, &ts); + + if (rets != 1) + { + if (rets == -1) + printf ("mq_%sreceive failed: %m\n", (i & 1) ? "" : "timed"); + else + printf ("mq_%sreceive returned %zd != 1\n", + (i & 1) ? "" : "timed", rets); + result = 1; + } + else if (prio != (unsigned int) vr[i] >> 4) + { + printf ("unexpected priority %x for value %02x\n", prio, + vr[i]); + result = 1; + } + } + + qsort (v, 10, 1, intcmp); + if (memcmp (v, vr, 10) != 0) + { + puts ("messages not received in expected order"); + result = 1; + } + + rets = mq_timedreceive (q, &vr[10], 1, &prio, &ts); + if (rets != -1) + { + puts ("mq_timedreceive on empty queue did not fail"); + result = 1; + } + else if (errno != (nonblock ? EAGAIN : ETIMEDOUT)) + { + printf ("mq_timedreceive on empty queue did not fail with %s: %m\n", + nonblock ? "EAGAIN" : "ETIMEDOUT"); + result = 1; + } + + if (nonblock) + { + ret = mq_receive (q, &vr[10], 1, &prio); + if (ret != -1) + { + puts ("mq_receive on empty non-blocking queue did not fail"); + result = 1; + } + else if (errno != EAGAIN) + { + printf ("mq_receive on empty non-blocking queue did not fail" + "with EAGAIN: %m\n"); + result = 1; + } + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result = check_attrs (&attr, nonblock, 0); + + if (mq_close (q) != 0) + { + printf ("mq_close in child failed: %m\n"); + result = 1; + } + + exit (result); + } + + int status; + if (waitpid (pid, &status, 0) != pid) + { + printf ("waitpid failed: %m\n"); + result = 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + printf ("child failed: %d\n", status); + result = 1; + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result = check_attrs (&attr, nonblock, 0); + + return result; +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue-%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); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + result = do_one_test (q, name, 0); + + mqd_t q2 = mq_open (name, O_WRONLY | O_NONBLOCK); + if (q2 == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + q2 = q; + result = 1; + } + else + { + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + q = q2; + result |= do_one_test (q, name, O_NONBLOCK); + + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + { + attr.mq_flags ^= O_NONBLOCK; + + struct mq_attr attr2; + memset (&attr2, 0x55, sizeof (attr2)); + if (mq_setattr (q, &attr, &attr2) != 0) + { + printf ("mq_setattr failed: %m\n"); + result = 1; + } + else if (attr.mq_flags != (attr2.mq_flags ^ O_NONBLOCK) + || attr.mq_maxmsg != attr2.mq_maxmsg + || attr.mq_msgsize != attr2.mq_msgsize + || attr.mq_curmsgs != 0 + || attr2.mq_curmsgs != 0) + { + puts ("mq_setattr returned unexpected values in *omqstat"); + result = 1; + } + else + { + result |= do_one_test (q, name, 0); + + if (mq_setattr (q, &attr2, NULL) != 0) + { + printf ("mq_setattr failed: %m\n"); + result = 1; + } + else + result |= do_one_test (q, name, O_NONBLOCK); + } + } + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + if (mq_close (q) != -1) + { + puts ("second mq_close did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("second mq_close did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/rt/tst-mqueue2.c b/rt/tst-mqueue2.c new file mode 100644 index 0000000..1948965 --- /dev/null +++ b/rt/tst-mqueue2.c @@ -0,0 +1,477 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +static void +alrm_handler (int sig) +{ +} + +#define TIMEOUT 10 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue2-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue2-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; + 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); + + mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with O_EXCL unexpectedly succeeded"); + result = 1; + } + else if (errno != EEXIST) + { + printf ("mq_open did not fail with EEXIST: %m\n"); + result = 1; + } + + char name2[sizeof "/tst-mqueue2-2-" + sizeof (pid_t) * 3]; + snprintf (name2, sizeof (name2), "/tst-mqueue2-2-%u", getpid ()); + + attr.mq_maxmsg = -2; + q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with invalid mq_maxmsg unexpectedly succeeded"); + add_temp_mq (name2); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_open with invalid mq_maxmsg did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + attr.mq_maxmsg = 2; + attr.mq_msgsize = -56; + q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with invalid mq_msgsize unexpectedly succeeded"); + add_temp_mq (name2); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_open with invalid mq_msgsize did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + char buf[3]; + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ts.tv_sec += 10; + else + { + ts.tv_sec = time (NULL) + 10; + ts.tv_nsec = 0; + } + + if (mq_timedreceive (q, buf, 1, NULL, &ts) == 0) + { + puts ("mq_timedreceive with too small msg_len did not fail"); + result = 1; + } + else if (errno != EMSGSIZE) + { + printf ("mq_timedreceive with too small msg_len did not fail with " + "EMSGSIZE: %m\n"); + result = 1; + } + + ts.tv_nsec = -1; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive with negative tv_nsec did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedreceive with negative tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + ts.tv_nsec = 1000000000; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive with tv_nsec >= 1000000000 did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedreceive with tv_nsec >= 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + struct sigaction sa = { .sa_handler = alrm_handler, .sa_flags = 0 }; + sigemptyset (&sa.sa_mask); + sigaction (SIGALRM, &sa, NULL); + + struct itimerval it = { .it_value = { .tv_sec = 1 } }; + setitimer (ITIMER_REAL, &it, NULL); + + if (mq_receive (q, buf, 2, NULL) == 0) + { + puts ("mq_receive on empty queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_receive on empty queue did not fail with EINTR: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + ts.tv_nsec = 0; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive on empty queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_timedreceive on empty queue did not fail with EINTR: %m\n"); + result = 1; + } + + buf[0] = '6'; + buf[1] = '7'; + if (mq_send (q, buf, 2, 3) != 0 + || (buf[0] = '8', mq_send (q, buf, 1, 4) != 0)) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + unsigned int prio; + ssize_t rets = mq_receive (q, buf, 3, &prio); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 1\n", rets); + result = 1; + } + else if (prio != 4 || memcmp (buf, "8 ", 3) != 0) + { + printf ("mq_receive prio %u (4) buf \"%c%c%c\" (\"8 \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + rets = mq_receive (q, buf, 2, NULL); + if (rets != 2) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 2\n", rets); + result = 1; + } + else if (memcmp (buf, "67 ", 3) != 0) + { + printf ("mq_receive buf \"%c%c%c\" != \"67 \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + buf[0] = '2'; + buf[1] = '1'; + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + ts.tv_sec = time (NULL); + ts.tv_nsec = -1000000001; + if ((mq_timedsend (q, buf, 2, 5, &ts) != 0 + && (errno != EINVAL || mq_send (q, buf, 2, 5) != 0)) + || (buf[0] = '3', ts.tv_nsec = -ts.tv_nsec, + (mq_timedsend (q, buf, 1, 4, &ts) != 0 + && (errno != EINVAL || mq_send (q, buf, 1, 4) != 0)))) + { + printf ("mq_timedsend failed: %m\n"); + result = 1; + } + + buf[0] = '-'; + ts.tv_nsec = 1000000001; + if (mq_timedsend (q, buf, 1, 6, &ts) == 0) + { + puts ("mq_timedsend with tv_nsec >= 1000000000 did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedsend with tv_nsec >= 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + ts.tv_nsec = -2; + if (mq_timedsend (q, buf, 1, 6, &ts) == 0) + { + puts ("mq_timedsend with negative tv_nsec did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedsend with megatove tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + if (mq_send (q, buf, 2, 8) == 0) + { + puts ("mq_send on full queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_send on full queue did not fail with EINTR: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + ts.tv_sec += 10; + ts.tv_nsec = 0; + if (mq_timedsend (q, buf, 2, 7, &ts) == 0) + { + puts ("mq_timedsend on full queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_timedsend on full queue did not fail with EINTR: %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + ts.tv_sec = time (NULL); + ts.tv_nsec = -1000000001; + rets = mq_timedreceive (q, buf, 2, &prio, &ts); + if (rets == -1 && errno == EINVAL) + rets = mq_receive (q, buf, 2, &prio); + if (rets != 2) + { + if (rets == -1) + printf ("mq_timedreceive failed: %m\n"); + else + printf ("mq_timedreceive returned %zd != 2\n", rets); + result = 1; + } + else if (prio != 5 || memcmp (buf, "21 ", 3) != 0) + { + printf ("mq_timedreceive prio %u (5) buf \"%c%c%c\" (\"21 \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_receive (q, buf, 1, NULL) == 0) + { + puts ("mq_receive with too small msg_len did not fail"); + result = 1; + } + else if (errno != EMSGSIZE) + { + printf ("mq_receive with too small msg_len did not fail with " + "EMSGSIZE: %m\n"); + result = 1; + } + + ts.tv_nsec = -ts.tv_nsec; + rets = mq_timedreceive (q, buf, 2, NULL, &ts); + if (rets == -1 && errno == EINVAL) + rets = mq_receive (q, buf, 2, NULL); + if (rets != 1) + { + if (rets == -1) + printf ("mq_timedreceive failed: %m\n"); + else + printf ("mq_timedreceive returned %zd != 1\n", rets); + result = 1; + } + else if (memcmp (buf, "31 ", 3) != 0) + { + printf ("mq_timedreceive buf \"%c%c%c\" != \"31 \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_send (q, "", 0, 2) != 0) + { + printf ("mq_send with msg_len 0 failed: %m\n"); + result = 1; + } + + rets = mq_receive (q, buf, 2, &prio); + if (rets) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 0\n", rets); + result = 1; + } + + long mq_prio_max = sysconf (_SC_MQ_PRIO_MAX); + if (mq_prio_max > 0 && (unsigned int) mq_prio_max == mq_prio_max) + { + if (mq_send (q, buf, 1, mq_prio_max) == 0) + { + puts ("mq_send with MQ_PRIO_MAX priority unpexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_send with MQ_PRIO_MAX priority did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + if (mq_send (q, buf, 1, mq_prio_max - 1) != 0) + { + printf ("mq_send with MQ_PRIO_MAX-1 priority failed: %m\n"); + result = 1; + } + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + q2 = mq_open (name, O_RDWR); + if (q2 != (mqd_t) -1) + { + printf ("mq_open of unlinked %s without O_CREAT unexpectedly" + "succeeded\n", name); + result = 1; + } + else if (errno != ENOENT) + { + printf ("mq_open of unlinked %s without O_CREAT did not fail with " + "ENOENT: %m\n", name); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + if (mq_receive (q, buf, 2, NULL) == 0) + { + puts ("mq_receive on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_receive on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_send (q, buf, 1, 2) == 0) + { + puts ("mq_send on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_send on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_getattr (q, &attr) == 0) + { + puts ("mq_getattr on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_getattr on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + memset (&attr, 0, sizeof (attr)); + if (mq_setattr (q, &attr, NULL) == 0) + { + puts ("mq_setattr on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_setattr on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_unlink ("/tst-mqueue2-which-should-never-exist") != -1) + { + puts ("mq_unlink of non-existant message queue unexpectedly succeeded"); + result = 1; + } + else if (errno != ENOENT) + { + printf ("mq_unlink of non-existant message queue did not fail with " + "ENOENT: %m\n"); + result = 1; + } + return result; +} + +#include "../test-skeleton.c" diff --git a/rt/tst-mqueue3.c b/rt/tst-mqueue3.c new file mode 100644 index 0000000..021a373 --- /dev/null +++ b/rt/tst-mqueue3.c @@ -0,0 +1,238 @@ +/* Test SIGEV_THREAD handling for POSIX message queues. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <mqueue.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <unistd.h> + +#if _POSIX_THREADS +# include <pthread.h> + +static pid_t pid; +static mqd_t m; +static const char message[] = "hello"; + +# define MAXMSG 10 +# define MSGSIZE 10 +# define UNIQUE 42 + + +static void +fct (union sigval s) +{ + /* Put the mq in non-blocking mode. */ + struct mq_attr attr; + if (mq_getattr (m, &attr) != 0) + { + printf ("%s: mq_getattr failed: %m\n", __FUNCTION__); + exit (1); + } + attr.mq_flags |= O_NONBLOCK; + if (mq_setattr (m, &attr, NULL) != 0) + { + printf ("%s: mq_setattr failed: %m\n", __FUNCTION__); + exit (1); + } + + /* Check the values. */ + if (attr.mq_maxmsg != MAXMSG) + { + printf ("%s: mq_maxmsg wrong: is %ld, expecte %d\n", + __FUNCTION__, attr.mq_maxmsg, MAXMSG); + exit (1); + } + if (attr.mq_msgsize != MAXMSG) + { + printf ("%s: mq_msgsize wrong: is %ld, expecte %d\n", + __FUNCTION__, attr.mq_msgsize, MSGSIZE); + exit (1); + } + + /* Read the message. */ + char buf[attr.mq_msgsize]; + ssize_t n = TEMP_FAILURE_RETRY (mq_receive (m, buf, attr.mq_msgsize, NULL)); + if (n != sizeof (message)) + { + printf ("%s: length of message wrong: is %zd, expected %zu\n", + __FUNCTION__, n, sizeof (message)); + exit (1); + } + if (memcmp (buf, message, sizeof (message)) != 0) + { + printf ("%s: message wrong: is \"%s\", expected \"%s\"\n", + __FUNCTION__, buf, message); + exit (1); + } + + exit (UNIQUE); +} + + +int +do_test (void) +{ + char tmpfname[] = "/tmp/tst-mqueue3-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 *b; + b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 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 (b, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + /* Name for the message queue. */ + char mqname[sizeof ("/tst-mqueue3-") + 3 * sizeof (pid_t)]; + snprintf (mqname, sizeof (mqname) - 1, "/tst-mqueue3-%ld", + (long int) getpid ()); + + /* Create the message queue. */ + struct mq_attr attr = { .mq_maxmsg = MAXMSG, .mq_msgsize = MSGSIZE }; + m = mq_open (mqname, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (m == -1) + { + puts ("mq_open failed"); + return 1; + } + + /* Unlink the message queue right away. */ + if (mq_unlink (mqname) != 0) + { + puts ("mq_unlink failed"); + return 1; + } + + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + if (pid == 0) + { + /* Request notification via thread. */ + struct sigevent ev; + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_value.sival_ptr = NULL; + ev.sigev_notify_attributes = NULL; + + /* Tell the kernel. */ + if (mq_notify (m,&ev) != 0) + { + puts ("mq_notify failed"); + exit (1); + } + + /* Tell the parent we are ready. */ + (void) pthread_barrier_wait (b); + + /* Make sure the process goes away eventually. */ + alarm (10); + + /* Do nothing forever. */ + while (1) + pause (); + } + + /* Wait for the child process to register to notification method. */ + (void) pthread_barrier_wait (b); + + /* Send the message. */ + if (mq_send (m, message, sizeof (message), 1) != 0) + { + kill (pid, SIGKILL); + puts ("mq_send failed"); + return 1; + } + + int r; + if (TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)) != pid) + { + kill (pid, SIGKILL); + puts ("waitpid failed"); + return 1; + } + + return WIFEXITED (r) && WEXITSTATUS (r) == UNIQUE ? 0 : 1; +} +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/rt/tst-mqueue4.c b/rt/tst-mqueue4.c new file mode 100644 index 0000000..fa83ece --- /dev/null +++ b/rt/tst-mqueue4.c @@ -0,0 +1,276 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue4-" + sizeof (pid_t) * 3 + NAME_MAX]; + char *p; + p = name + snprintf (name, sizeof (name), "/tst-mqueue4-%u", getpid ()); + struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; + 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); + + *p = '.'; + memset (p + 1, 'x', NAME_MAX + 1 - (p - name)); + name[NAME_MAX + 1] = '\0'; + + mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 == (mqd_t) -1) + { + printf ("mq_open with NAME_MAX long name compoment failed with: %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + name[NAME_MAX + 1] = 'x'; + name[NAME_MAX + 2] = '\0'; + q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with too long name component unexpectedly succeeded"); + mq_unlink (name); + mq_close (q2); + result = 1; + } + else if (errno != ENAMETOOLONG) + { + printf ("mq_open with too long name component did not fail with " + "ENAMETOOLONG: %m\n"); + result = 1; + } + + *p = '\0'; + attr.mq_maxmsg = 1; + attr.mq_msgsize = 3; + q2 = mq_open (name, O_CREAT | O_RDWR, 0600, &attr); + if (q2 == (mqd_t) -1) + { + printf ("mq_open without O_EXCL failed with %m\n"); + result = 1; + } + + char buf[3]; + strcpy (buf, "jk"); + if (mq_send (q, buf, 2, 4) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + if (mq_send (q, buf + 1, 1, 5) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + if (mq_getattr (q2, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + + if ((attr.mq_flags & O_NONBLOCK) + || attr.mq_maxmsg != 2 + || attr.mq_msgsize != 2 + || attr.mq_curmsgs != 2) + { + printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n" + ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n", + attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); + result = 1; + } + + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ++ts.tv_sec; + else + { + ts.tv_sec = time (NULL) + 1; + ts.tv_nsec = 0; + } + + if (mq_timedsend (q2, buf, 1, 1, &ts) == 0) + { + puts ("mq_timedsend unexpectedly succeeded"); + result = 1; + } + else if (errno != ETIMEDOUT) + { + printf ("mq_timedsend did not fail with ETIMEDOUT: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + q2 = mq_open (name, O_RDONLY, 0600); + if (q2 == (mqd_t) -1) + { + printf ("mq_open without O_CREAT failed with %m\n"); + result = 1; + } + + mqd_t q3 = mq_open (name, O_RDONLY, 0600); + if (q3 == (mqd_t) -1) + { + printf ("mq_open without O_CREAT failed with %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + unsigned int prio; + ssize_t rets = mq_receive (q2, buf, 2, &prio); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive failed with: %m\n"); + else + printf ("mq_receive returned %zd != 1\n", rets); + result = 1; + } + else if (prio != 5 || memcmp (buf, "k ", 3) != 0) + { + printf ("mq_receive returned prio %u (2) buf \"%c%c%c\" (\"k \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_getattr (q3, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + + if ((attr.mq_flags & O_NONBLOCK) + || attr.mq_maxmsg != 2 + || attr.mq_msgsize != 2 + || attr.mq_curmsgs != 1) + { + printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n" + ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n", + attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); + result = 1; + } + + rets = mq_receive (q3, buf, 2, NULL); + if (rets != 2) + { + if (rets == -1) + printf ("mq_receive failed with: %m\n"); + else + printf ("mq_receive returned %zd != 2\n", rets); + result = 1; + } + else if (memcmp (buf, "jk ", 3) != 0) + { + printf ("mq_receive returned buf \"%c%c%c\" != \"jk \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ++ts.tv_sec; + else + { + ts.tv_sec = time (NULL) + 1; + ts.tv_nsec = 0; + } + + if (mq_timedreceive (q2, buf, 2, NULL, &ts) != -1) + { + puts ("mq_timedreceive on empty queue unexpectedly succeeded"); + result = 1; + } + else if (errno != ETIMEDOUT) + { + printf ("mq_timedreceive on empty queue did not fail with " + "ETIMEDOUT: %m\n"); + 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_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_close (q3) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/sysdeps/generic/bits/mqueue.h b/sysdeps/generic/bits/mqueue.h new file mode 100644 index 0000000..27bb482 --- /dev/null +++ b/sysdeps/generic/bits/mqueue.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _MQUEUE_H +# error "Never use <bits/mqueue.h> directly; include <mqueue.h> instead." +#endif + +typedef int mqd_t; + +struct mq_attr +{ + long int mq_flags; /* Message queue flags. */ + long int mq_maxmsg; /* Maximum number of messages. */ + long int mq_msgsize; /* Maximum message size. */ + long int mq_curmsgs; /* Number of messages currently queued. */ +}; diff --git a/sysdeps/generic/mq_close.c b/sysdeps/generic/mq_close.c new file mode 100644 index 0000000..8237a64 --- /dev/null +++ b/sysdeps/generic/mq_close.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Removes the association between message queue descriptor MQDES and its + message queue. */ +int +mq_close (mqd_t mqdes) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (mq_close) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_getattr.c b/sysdeps/generic/mq_getattr.c new file mode 100644 index 0000000..2d24b85 --- /dev/null +++ b/sysdeps/generic/mq_getattr.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Query status and attributes of message queue MQDES. */ +int +mq_getattr (mqd_t mqdes, struct mq_attr *mqstat) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (mq_getattr) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_notify.c b/sysdeps/generic/mq_notify.c new file mode 100644 index 0000000..29de75a --- /dev/null +++ b/sysdeps/generic/mq_notify.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Register notification upon message arrival to an empty message queue + MQDES. */ +int +mq_notify (mqd_t mqdes, const struct sigevent *notification) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (mq_notify) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_open.c b/sysdeps/generic/mq_open.c new file mode 100644 index 0000000..dea5741 --- /dev/null +++ b/sysdeps/generic/mq_open.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Establish connection between a process and a message queue NAME and + return message queue descriptor or (mqd_t) -1 on error. OFLAG determines + the type of access used. If O_CREAT is on OFLAG, the third argument is + taken as a `mode_t', the mode of the created message queue, and the fourth + argument is taken as `struct mq_attr *', pointer to message queue + attributes. If the fourth argument is NULL, default attributes are + used. */ +mqd_t +mq_open (const char *name, int oflag, ...) +{ + __set_errno (ENOSYS); + return (mqd_t) -1; +} +stub_warning (mq_open) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_receive.c b/sysdeps/generic/mq_receive.c new file mode 100644 index 0000000..527fd75 --- /dev/null +++ b/sysdeps/generic/mq_receive.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Receive the oldest from highest priority messages in message queue + MQDES. */ +ssize_t +mq_receive (mqd_t mqdes, char *msg_ptr, size_t msg_len, + unsigned int *msg_prio) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (mq_receive) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_send.c b/sysdeps/generic/mq_send.c new file mode 100644 index 0000000..8b7cd87 --- /dev/null +++ b/sysdeps/generic/mq_send.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Add message pointed by MSG_PTR to message queue MQDES. */ +int +mq_send (mqd_t mqdes, const char *msg_ptr, size_t msg_len, + unsigned int msg_prio) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (mq_send) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_setattr.c b/sysdeps/generic/mq_setattr.c new file mode 100644 index 0000000..57ee075 --- /dev/null +++ b/sysdeps/generic/mq_setattr.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Set attributes associated with message queue MQDES and if OMQSTAT is + not NULL also query its old attributes. */ +int +mq_setattr (mqd_t mqdes, const struct mq_attr *__restrict mqstat, + struct mq_attr *__restrict omqstat) +{ + __set_errno (ENOSYS); + return -1; +} +hidden_def (mq_setattr) +stub_warning (mq_setattr) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_timedreceive.c b/sysdeps/generic/mq_timedreceive.c new file mode 100644 index 0000000..e4723f8 --- /dev/null +++ b/sysdeps/generic/mq_timedreceive.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Receive the oldest from highest priority messages in message queue + MQDES, stop waiting if ABS_TIMEOUT expires. */ +ssize_t +mq_timedreceive (mqd_t mqdes, char *__restrict msg_ptr, size_t msg_len, + unsigned int *__restrict msg_prio, + const struct timespec *__restrict abs_timeout) +{ + __set_errno (ENOSYS); + return -1; +} +hidden_def (mq_timedreceive) +stub_warning (mq_timedreceive) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_timedsend.c b/sysdeps/generic/mq_timedsend.c new file mode 100644 index 0000000..5ccfe23 --- /dev/null +++ b/sysdeps/generic/mq_timedsend.c @@ -0,0 +1,33 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Add message pointed by MSG_PTR to message queue MQDES, stop blocking + on full message queue if ABS_TIMEOUT expires. */ +int +mq_timedsend (mqd_t mqdes, const char *msg_ptr, size_t msg_len, + unsigned int msg_prio, const struct timespec *abs_timeout) +{ + __set_errno (ENOSYS); + return -1; +} +hidden_def (mq_timedsend) +stub_warning (mq_timedsend) +#include <stub-tag.h> diff --git a/sysdeps/generic/mq_unlink.c b/sysdeps/generic/mq_unlink.c new file mode 100644 index 0000000..e947b84 --- /dev/null +++ b/sysdeps/generic/mq_unlink.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> + +/* Remove message queue named NAME. */ +int +mq_unlink (const char *name) +{ + __set_errno (ENOSYS); + return -1; +} +stub_warning (mq_unlink) +#include <stub-tag.h> diff --git a/sysdeps/unix/sysv/linux/bits/local_lim.h b/sysdeps/unix/sysv/linux/bits/local_lim.h index 169a5f1..54a51ee 100644 --- a/sysdeps/unix/sysv/linux/bits/local_lim.h +++ b/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -63,3 +63,6 @@ /* Maximum host name length. */ #define HOST_NAME_MAX 64 + +/* Maximum message queue priority level. */ +#define MQ_PRIO_MAX 32768 diff --git a/sysdeps/unix/sysv/linux/bits/mqueue.h b/sysdeps/unix/sysv/linux/bits/mqueue.h new file mode 100644 index 0000000..df528f8 --- /dev/null +++ b/sysdeps/unix/sysv/linux/bits/mqueue.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _MQUEUE_H +# error "Never use <bits/mqueue.h> directly; include <mqueue.h> instead." +#endif + +typedef int mqd_t; + +struct mq_attr +{ + long int mq_flags; /* Message queue flags. */ + long int mq_maxmsg; /* Maximum number of messages. */ + long int mq_msgsize; /* Maximum message size. */ + long int mq_curmsgs; /* Number of messages currently queued. */ + long int __pad[4]; +}; diff --git a/sysdeps/unix/sysv/linux/mq_close.c b/sysdeps/unix/sysv/linux/mq_close.c new file mode 100644 index 0000000..65522d5 --- /dev/null +++ b/sysdeps/unix/sysv/linux/mq_close.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <sysdep.h> + +#ifdef __NR_mq_open + +/* Removes the association between message queue descriptor MQDES and its + message queue. */ +int +mq_close (mqd_t mqdes) +{ + return INLINE_SYSCALL (close, 1, mqdes); +} + +#else +# include <sysdeps/generic/mq_close.c> +#endif diff --git a/sysdeps/unix/sysv/linux/mq_getattr.c b/sysdeps/unix/sysv/linux/mq_getattr.c new file mode 100644 index 0000000..94c1df5 --- /dev/null +++ b/sysdeps/unix/sysv/linux/mq_getattr.c @@ -0,0 +1,34 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <sysdep.h> + +#ifdef __NR_mq_getsetattr + +/* Query status and attributes of message queue MQDES. */ +int +mq_getattr (mqd_t mqdes, struct mq_attr *mqstat) +{ + return mq_setattr (mqdes, NULL, mqstat); +} + +#else +# include <sysdeps/generic/mq_getattr.c> +#endif diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c new file mode 100644 index 0000000..6ebe8ef --- /dev/null +++ b/sysdeps/unix/sysv/linux/mq_notify.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <sysdep.h> + +#ifdef __NR_mq_notify + +/* Register notification upon message arrival to an empty message queue + MQDES. */ +int +mq_notify (mqd_t mqdes, const struct sigevent *notification) +{ + /* mq_notify which handles SIGEV_THREAD is included in the thread + add-on. */ + if (notification != NULL + && notification->sigev_notify == SIGEV_THREAD) + { + __set_errno (ENOSYS); + return -1; + } + return INLINE_SYSCALL (mq_notify, 2, mqdes, notification); +} + +#else +# include <sysdeps/generic/mq_notify.c> +#endif diff --git a/sysdeps/unix/sysv/linux/mq_open.c b/sysdeps/unix/sysv/linux/mq_open.c new file mode 100644 index 0000000..ce5f5e9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/mq_open.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <stdarg.h> +#include <sysdep.h> + +#ifdef __NR_mq_open + +/* Establish connection between a process and a message queue NAME and + return message queue descriptor or (mqd_t) -1 on error. OFLAG determines + the type of access used. If O_CREAT is on OFLAG, the third argument is + taken as a `mode_t', the mode of the created message queue, and the fourth + argument is taken as `struct mq_attr *', pointer to message queue + attributes. If the fourth argument is NULL, default attributes are + used. */ +mqd_t +mq_open (const char *name, int oflag, ...) +{ + if (name[0] != '/') + { + __set_errno (EINVAL); + return -1; + } + + mode_t mode = 0; + struct mq_attr *attr = NULL; + if (oflag & O_CREAT) + { + va_list ap; + + va_start (ap, oflag); + mode = va_arg (ap, mode_t); + attr = va_arg (ap, struct mq_attr *); + va_end (ap); + } + + return INLINE_SYSCALL (mq_open, 4, name + 1, oflag, mode, attr); +} + +#else +# include <sysdeps/generic/mq_open.c> +#endif diff --git a/sysdeps/unix/sysv/linux/mq_receive.c b/sysdeps/unix/sysv/linux/mq_receive.c new file mode 100644 index 0000000..b24ba4b --- /dev/null +++ b/sysdeps/unix/sysv/linux/mq_receive.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <sysdep.h> + +#ifdef __NR_mq_timedreceive + +/* Receive the oldest from highest priority messages in message queue + MQDES. */ +ssize_t +mq_receive (mqd_t mqdes, char *msg_ptr, size_t msg_len, + unsigned int *msg_prio) +{ + return mq_timedreceive (mqdes, msg_ptr, msg_len, msg_prio, NULL); +} + +#else +# include <sysdeps/generic/mq_receive.c> +#endif diff --git a/sysdeps/unix/sysv/linux/mq_send.c b/sysdeps/unix/sysv/linux/mq_send.c new file mode 100644 index 0000000..06d367b --- /dev/null +++ b/sysdeps/unix/sysv/linux/mq_send.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <sysdep.h> + +#ifdef __NR_mq_timedsend + +/* Add message pointed by MSG_PTR to message queue MQDES. */ +int +mq_send (mqd_t mqdes, const char *msg_ptr, size_t msg_len, + unsigned int msg_prio) +{ + return mq_timedsend (mqdes, msg_ptr, msg_len, msg_prio, NULL); +} + +#else +# include <sysdeps/generic/mq_send.c> +#endif diff --git a/sysdeps/unix/sysv/linux/mq_unlink.c b/sysdeps/unix/sysv/linux/mq_unlink.c new file mode 100644 index 0000000..8da70ea --- /dev/null +++ b/sysdeps/unix/sysv/linux/mq_unlink.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <sysdep.h> + +#ifdef __NR_mq_unlink + +/* Remove message queue named NAME. */ +int +mq_unlink (const char *name) +{ + if (name[0] != '/') + { + __set_errno (EINVAL); + return -1; + } + return INLINE_SYSCALL (mq_unlink, 1, name + 1); +} + +#else +# include <sysdeps/generic/mq_unlink.c> +#endif diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list index 9ec085d..860094b 100644 --- a/sysdeps/unix/sysv/linux/syscalls.list +++ b/sysdeps/unix/sysv/linux/syscalls.list @@ -86,3 +86,7 @@ flistxattr - flistxattr i:isi flistxattr removexattr - removexattr i:ss removexattr lremovexattr - lremovexattr i:ss lremovexattr fremovexattr - fremovexattr i:is fremovexattr + +mq_timedsend - mq_timedsend Ci:ipiip __GI_mq_timedsend mq_timedsend +mq_timedreceive - mq_timedreceive Ci:ipipp __GI_mq_timedreceive mq_timedreceive +mq_setattr - mq_getsetattr i:ipp __GI_mq_setattr mq_setattr |