From: Manfred Spraul <manfred@colorfullife.com>
To: "David S. Miller" <davem@redhat.com>
Cc: akpm@osdl.org, linux-arch@vger.kernel.org
Subject: Re: posix message queues
Date: Sat, 10 Apr 2004 13:19:45 +0200 [thread overview]
Message-ID: <4077D851.7000008@colorfullife.com> (raw)
In-Reply-To: <20040409164506.0611846a.davem@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 1169 bytes --]
David S. Miller wrote:
>On Wed, 07 Apr 2004 21:15:44 +0200
>Manfred Spraul <manfred@colorfullife.com> wrote:
>
>
>
>>No. The unix spec mandates 'long' for the final C-library api. Using u32
>>would mean that glibc would have to add an emulation layer in user space
>>for 64-bit archs. In the long run, 64-bit kernels running 64-bit apps
>>will be the common case. I don't want to add an emulation layer to the
>>common case.
>>
>>
>
>We need to support this stuff when running 32-bit apps, you cannot
>avoid this Manfred.
>
Of course. But the compat stuff is only used if a 32-bit app runs on a
64-bit kernel. If I'd use u32 for the kernel interface, then a compat
wrappers would be necessary if a 64-bit app runs on a 64-bit kernel, and
that would be the wrong thing.
> So we'll need kernel compat layer code to
>translate these structures containing 'long'. Please code up the
>necessary compat.c code for this posix message queues feature.
>
>
Arndt did 90% of the coding, it's already in 2.6.5-mm3. The only missing
part was the SIGEV_THREAD handling, I've attached a patch that adds
this, together a small user space test app.
--
Manfred
[-- Attachment #2: mq_test.c --]
[-- Type: text/x-csrc, Size: 9849 bytes --]
/*
* Test app for Linux Kernel posix message queues.
*
* Copyright (C) 2004 Manfred Spraul
*
* Redistribution of this file is permitted under the terms of the GNU
* Public License (GPL)
* $Header: /home/manfred/cvs-tree/mq/mq_test.c,v 1.3 2004/04/10 11:17:31 manfred Exp $
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <string.h>
#include <limits.h>
/*
* Kernel-interface based on the Mqueue library:
*
* Copyright (C) 2003 Krzysztof Benedyczak & Michal Wronski
This program 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.
It 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 this software; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
*/
/****************** implementation *****************/
#define __NR_mq_open 277
#define __NR_mq_unlink (__NR_mq_open+1)
#define __NR_mq_timedsend (__NR_mq_open+2)
#define __NR_mq_timedreceive (__NR_mq_open+3)
#define __NR_mq_notify (__NR_mq_open+4)
#define __NR_mq_getsetattr (__NR_mq_open+5)
#define MQ_PRIO_MAX 32768
typedef int mqd_t;
struct mq_attr {
long mq_flags; /* message queue flags */
long mq_maxmsg; /* maximum number of messages */
long mq_msgsize; /* maximum message size */
long mq_curmsgs; /* number of messages currently queued */
long __reserved[4]; /* unused */
};
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <stdarg.h>
mqd_t mq_open(const char *name, int oflag, /* mode_t mode, struct mq_attr *attr */ ...);
int mq_close(mqd_t mqdes);
int mq_unlink(const char *name);
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
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);
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat);
int mq_setattr(mqd_t mqdes, const struct mq_attr *__restrict mqstat, struct mq_attr *__restrict omqstat);
/*
* kernel interfaces. We use glibc's syscall(3) instead of the macros
* _syscall1, _syscall2, etc, as the macros generate compilation errors
* when mqueue.c is built as a dynamic shared library.
*/
static inline mqd_t __mq_open(const char *name,
int oflag, mode_t mode, struct mq_attr* attr)
{
return syscall(__NR_mq_open, name, oflag, mode, attr);
}
static inline int __mq_unlink(const char *name)
{
return syscall(__NR_mq_unlink, name);
}
static inline int __mq_notify(mqd_t mqdes, const struct sigevent *notification)
{
return syscall(__NR_mq_notify, mqdes, notification);
}
static inline int __mq_getsetattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat)
{
return syscall(__NR_mq_getsetattr, mqdes, mqstat, omqstat);
}
static inline int __mq_timedsend(mqd_t mqdes, const char *msg_ptr,
size_t msg_len, unsigned int msg_prio,
const struct timespec *abs_timeout)
{
return syscall(__NR_mq_timedsend, mqdes, msg_ptr, msg_len,
msg_prio, abs_timeout);
}
static inline ssize_t __mq_timedreceive(mqd_t mqdes, char *msg_ptr,
size_t msg_len, unsigned int *msg_prio,
const struct timespec *abs_timeout)
{
return syscall(__NR_mq_timedreceive, mqdes, msg_ptr, msg_len,
msg_prio, abs_timeout);
}
static inline int is_valid_path(const char *name)
{
if (name[0] != '/') {
errno = EINVAL;
return -1;
}
return 0;
}
/*
* application-visible wrappers around the kernel interfaces
*/
mqd_t mq_open(const char *name, int oflag, ...)
{
unsigned long mode;
struct mq_attr *attr;
va_list ap;
va_start(ap, oflag);
mode = va_arg(ap, unsigned long);
attr = va_arg(ap, struct mq_attr *);
va_end(ap);
if (is_valid_path(name) < 0)
return (mqd_t)-1;
/* omit leading slash */
return __mq_open(name + 1, oflag, mode, attr);
}
int mq_close(mqd_t mqdes)
{
return close(mqdes);
}
int mq_unlink(const char *name)
{
if (is_valid_path(name) < 0)
return -1;
return __mq_unlink(name+1);
}
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);
}
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);
}
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
unsigned int msg_prio,
const struct timespec *abs_timeout)
{
return __mq_timedsend(mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
}
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
unsigned int *msg_prio,
const struct timespec *abs_timeout)
{
return __mq_timedreceive(mqdes, msg_ptr, msg_len, msg_prio,
abs_timeout);
}
int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat)
{
return __mq_getsetattr(mqdes, NULL, mqstat);
}
int mq_setattr( mqd_t mqdes, const struct mq_attr *mqstat,
struct mq_attr *omqstat)
{
return __mq_getsetattr(mqdes, mqstat, omqstat);
}
int mq_notify(mqd_t mqdes, const struct sigevent *notification)
{
return __mq_notify(mqdes, notification);
}
int got_signal = 0;
void usr1_handler(int unused)
{
printf("usr1 signal caught.\n");
got_signal = 1;
}
char buffer[131072];
int main(int argc, char **argv)
{
static const char qname[] = "/test_123";
int err;
mqd_t m, m2;
struct mq_attr ma;
printf("Test 1: mq_open()\n");
m = mq_open(qname, O_CREAT|O_RDWR, S_IRUSR | S_IWUSR, NULL);
if (m == -1) {
printf("mq_open() failed, errno %d.\n", errno);
return 1;
}
printf("Test 2: check exclusive open()\n");
m2 = mq_open(qname, O_EXCL|O_CREAT|O_RDWR, S_IRUSR | S_IWUSR, NULL);
if (m2 != -1 || errno != EEXIST) {
printf("mq_open() succeeded or wrong errno (%d).\n", errno);
return 1;
}
printf("Test 3: close handle\n");
err = mq_close(m);
if (err) {
printf("mq_close() failed.\n");
}
printf("Test 4: mq_unlink\n");
err = mq_unlink(qname);
if (err) {
printf("mq_unlink() failed, errno %d.\n", errno);
return 1;
}
printf("Test 4: mq_unlink on nonexisting file\n");
err = mq_unlink(qname);
if (err != -1 || errno != ENOENT) {
printf("mq_unlink() failed, errno %d.\n", errno);
return 1;
}
printf("Test 5: mq_open()\n");
m = mq_open(qname, O_CREAT|O_EXCL|O_RDWR, S_IRUSR | S_IWUSR, NULL);
if (m == -1) {
printf("mq_open() failed, errno %d.\n", errno);
return 1;
}
printf("Test 6: mq_getattr()\n");
err = mq_getattr(m, &ma);
if (err || ma.mq_curmsgs != 0) {
printf("mq_getattr() failed, errno %d, curmsg %ld.\n", errno, ma.mq_curmsgs);
return 1;
}
printf("Test 7: setup signal based notify().\n");
signal (SIGUSR1,usr1_handler);
struct sigevent event;
event.sigev_notify = SIGEV_SIGNAL;
event.sigev_signo = SIGUSR1;
err = mq_notify(m, &event);
if (err) {
printf("mq_notify() failed, errno %d.\n", errno);
return 1;
}
printf("Test 8: mq_send()\n");
err = mq_send(m, qname, strlen(qname), 1);
if (err) {
printf("mq_send() failed, errno %d.\n", errno);
return 1;
}
if (!got_signal) {
printf("No signal received.\n");
return 1;
}
printf("Test 9: mq_getattr() with one pending message\n");
err = mq_getattr(m, &ma);
if (err || ma.mq_curmsgs != 1) {
printf("mq_getattr() failed, errno %d, curmsg %ld.\n", errno, ma.mq_curmsgs);
return 1;
}
printf("Test 10: mq_receive()\n");
err = mq_receive(m, buffer, sizeof(buffer), NULL);
if (err < 0) {
printf("mq_receive() failed, errno %d.\n", errno);
return 1;
}
printf("Test 11: data comparison\n");
if (strcmp(qname, buffer)) {
printf("Data mismatch!!!.\n");
return 1;
}
printf("Test 12: request notification cookie.\n");
{
int fd, i;
char inc[32], outc[64];
fd = socket(PF_NETLINK, SOCK_RAW, 0);
if (fd == -1) {
printf("opening netlink socket failed, errno %d.\n", errno);
return 1;
}
for (i=0;i<32;i++)
inc[i] = 64+2*i;
event.sigev_notify = SIGEV_THREAD;
event.sigev_signo = fd;
event.sigev_value.sival_ptr = inc;
err = mq_notify(m, &event);
if (err < 0) {
printf("mq_notify() failed, errno %d.\n", errno);
return 1;
}
err = mq_send(m, qname, strlen(qname), 1);
if (err) {
printf("mq_send() failed, errno %d.\n", errno);
return 1;
}
err = recv(fd, outc, sizeof(outc), MSG_NOSIGNAL|MSG_DONTWAIT);
if (err != 32) {
printf("recv unexpected result %d, errno %d.\n", err, errno);
return 1;
}
for (i=0;i<31;i++) {
if (outc[i] != 64+2*i) {
printf("Data mismatch in cookie at offset %d: %d.\n",
i, outc[i]);
return 1;
}
}
if (outc[31] != 1) {
printf("state mismatch in cookie: got %d.\n", outc[31]);
}
}
printf("Test 13: another mq_unlink\n");
err = mq_unlink(qname);
if (err) {
printf("mq_unlink() failed, errno %d.\n", errno);
return 1;
}
printf("Test 14: mq_close()\n");
err = mq_close(m);
if (err) {
printf("mq_close() failed, errno %d.\n", errno);
return 1;
}
return 0;
}
[-- Attachment #3: patch-mqueue-compat --]
[-- Type: text/plain, Size: 793 bytes --]
// $Header$
// Kernel Version:
// VERSION = 2
// PATCHLEVEL = 6
// SUBLEVEL = 5
// EXTRAVERSION = -mm3
--- 2.6/ipc/compat_mq.c 2004-04-10 09:59:40.000000000 +0200
+++ build-2.6/ipc/compat_mq.c 2004-04-10 13:15:40.414231437 +0200
@@ -139,6 +139,7 @@
{
mm_segment_t oldfs;
struct sigevent notification;
+ char cookie[NOTIFY_COOKIE_LEN];
long ret;
if (!u_notification)
@@ -147,6 +148,14 @@
if (get_compat_sigevent(¬ification, u_notification))
return -EFAULT;
+ if (notification.sigev_notify == SIGEV_THREAD) {
+ if (copy_from_user(cookie, u_notification.sigev_value.sival_ptr,
+ NOTIFY_COOKIE_LEN)) {
+ return -EFAULT;
+ }
+ notification.sigev_value.sival_ptr = cookie;
+ }
+
oldfs = get_fs();
set_fs(KERNEL_DS);
ret = sys_mq_notify(mqdes, ¬ification);
next prev parent reply other threads:[~2004-04-10 11:45 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-04-07 19:07 posix message queues Andrew Morton
2004-04-07 19:15 ` Manfred Spraul
2004-04-08 8:17 ` Arnd Bergmann
2004-04-08 8:49 ` Andrew Morton
2004-04-08 14:08 ` Manfred Spraul
2004-04-08 20:24 ` Andrew Morton
2004-04-09 23:45 ` David S. Miller
2004-04-10 11:19 ` Manfred Spraul [this message]
2004-04-10 11:53 ` Manfred Spraul
2004-04-10 20:43 ` Arnd Bergmann
-- strict thread matches above, loose matches on Subject: below --
2004-04-08 22:22 Arnd Bergmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4077D851.7000008@colorfullife.com \
--to=manfred@colorfullife.com \
--cc=akpm@osdl.org \
--cc=davem@redhat.com \
--cc=linux-arch@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox