about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog57
-rw-r--r--bits/mqueue.h31
-rw-r--r--include/mqueue.h7
-rw-r--r--linuxthreads/ChangeLog11
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h3
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/bits/local_lim.h3
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/bits/posix_opt.h6
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h6
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h3
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h3
-rw-r--r--nptl/ChangeLog19
-rw-r--r--nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/bits/local_lim.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/ia64/bits/local_lim.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/ia64/bits/posix_opt.h6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mq_notify.c285
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/bits/posix_opt.h6
-rw-r--r--rt/Makefile13
-rw-r--r--rt/Versions5
-rw-r--r--rt/mqueue.h91
-rw-r--r--rt/tst-mqueue.h62
-rw-r--r--rt/tst-mqueue1.c416
-rw-r--r--rt/tst-mqueue2.c477
-rw-r--r--rt/tst-mqueue3.c238
-rw-r--r--rt/tst-mqueue4.c276
-rw-r--r--sysdeps/generic/bits/mqueue.h31
-rw-r--r--sysdeps/generic/mq_close.c31
-rw-r--r--sysdeps/generic/mq_getattr.c30
-rw-r--r--sysdeps/generic/mq_notify.c31
-rw-r--r--sysdeps/generic/mq_open.c36
-rw-r--r--sysdeps/generic/mq_receive.c32
-rw-r--r--sysdeps/generic/mq_send.c31
-rw-r--r--sysdeps/generic/mq_setattr.c33
-rw-r--r--sysdeps/generic/mq_timedreceive.c34
-rw-r--r--sysdeps/generic/mq_timedsend.c33
-rw-r--r--sysdeps/generic/mq_unlink.c30
-rw-r--r--sysdeps/unix/sysv/linux/bits/local_lim.h3
-rw-r--r--sysdeps/unix/sysv/linux/bits/mqueue.h32
-rw-r--r--sysdeps/unix/sysv/linux/mq_close.c35
-rw-r--r--sysdeps/unix/sysv/linux/mq_getattr.c34
-rw-r--r--sysdeps/unix/sysv/linux/mq_notify.c43
-rw-r--r--sysdeps/unix/sysv/linux/mq_open.c59
-rw-r--r--sysdeps/unix/sysv/linux/mq_receive.c36
-rw-r--r--sysdeps/unix/sysv/linux/mq_send.c35
-rw-r--r--sysdeps/unix/sysv/linux/mq_unlink.c39
-rw-r--r--sysdeps/unix/sysv/linux/syscalls.list4
49 files changed, 2690 insertions, 30 deletions
diff --git a/ChangeLog b/ChangeLog
index dfaa11f7cc..1156766cf8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 0000000000..27bb4824b8
--- /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 0000000000..1ac4f13445
--- /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 cbdfc73ba4..ad881d4968 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 e08763b1ad..96893c59da 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 4027c4df99..ed6c3c589b 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 3dae916554..06fd0a29b2 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 02da4d77dc..18a840ed98 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 73fa616082..629b1f89c1 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 60212946c8..27ffa668f4 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 c197dd42ea..53fba001db 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 bb3c4c061d..e0718780cc 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 0c2a2bd2b4..0bc8e048af 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 67a37d01c8..7335e38a98 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 4bc4eed72a..7563de8ad2 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 5d64136214..f837250b95 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 4bc4eed72a..7563de8ad2 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 0000000000..e231e591d1
--- /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 (&notify_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 (&notify_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 (&notify_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 1cfa807eb9..e082ea8f04 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 4bc4eed72a..7563de8ad2 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 47167890a0..fd5185292c 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 133f374ea6..a7d633d0ea 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 0000000000..42313b192b
--- /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 0000000000..3659795a1b
--- /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 0000000000..a6f8fb50c7
--- /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 0000000000..1948965c68
--- /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 0000000000..021a373e5e
--- /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 0000000000..fa83ece95a
--- /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 0000000000..27bb4824b8
--- /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 0000000000..8237a6438e
--- /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 0000000000..2d24b85d47
--- /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 0000000000..29de75a471
--- /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 0000000000..dea5741d5a
--- /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 0000000000..527fd75963
--- /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 0000000000..8b7cd87f7f
--- /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 0000000000..57ee0759ab
--- /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 0000000000..e4723f812a
--- /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 0000000000..5ccfe23b0a
--- /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 0000000000..e947b84f3b
--- /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 169a5f1474..54a51ee766 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 0000000000..df528f876a
--- /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 0000000000..65522d5adc
--- /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 0000000000..94c1df57a3
--- /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 0000000000..6ebe8efe5a
--- /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 0000000000..ce5f5e9959
--- /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 0000000000..b24ba4b688
--- /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 0000000000..06d367b566
--- /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 0000000000..8da70ea42b
--- /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 9ec085da40..860094be50 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