This patch show a possibiliy to add a device per IPC message queue in
order to use the poll() or select() call. The goal is to have a easy way
in an application to wait on a IPC message in it main loop. This is just
to try and to have some code to talk about. Follow the patch and samples
applications.
Future work can be:
- debug :-)
- Config.in to controle CONFIG_IPC_DEV.
- removing device on ipcrm.
- ioctl to control type and mode of message to wait.
- read methode to replace msgrcv() ?
- write methode to replace msgsnd() ?
- speciale device (like /dev/ppp) to replace msgget() ?
- ...
Any comment ?
=== kernel patch =====================================================
--- ipc/msg.c 2001/10/03 09:03:38 1.1.1.13
+++ ipc/msg.c 2001/12/03 15:57:37
@@ -15,6 +15,8 @@
* (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
*/
+#define CONFIG_IPC_DEV
+
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/msg.h>
@@ -24,6 +26,10 @@
#include <linux/list.h>
#include <asm/uaccess.h>
#include "util.h"
+#ifdef CONFIG_IPC_DEV
+#include <linux/poll.h>
+#include <linux/devfs_fs_kernel.h>
+#endif
/* sysctl: */
int msg_ctlmax = MSGMAX;
@@ -79,6 +85,9 @@
struct list_head q_messages;
struct list_head q_receivers;
struct list_head q_senders;
+#ifdef CONFIG_IPC_DEV
+ wait_queue_head_t ipc_dev_wait; /* For the poll methode */
+#endif
};
#define SEARCH_ANY 1
@@ -112,11 +121,51 @@
#ifdef CONFIG_PROC_FS
create_proc_read_entry("sysvipc/msg", 0, 0,
sysvipc_msg_read_proc, NULL);
#endif
+#ifdef CONFIG_IPC_DEV
+ devfs_mk_dir(NULL, "ipc", NULL);
+#endif
+}
+
+#ifdef CONFIG_IPC_DEV
+static unsigned int ipc_dev_poll(struct file *file, poll_table *wait)
+{
+ int msqid=(int)file->private_data;
+ struct msg_queue *msq;
+ unsigned int ret = 0;
+
+ msq = msg_lock(msqid);
+ if(msq==NULL)
+ return -EINVAL;
+ ret = -EIDRM;
+ if (msg_checkid(msq,msqid))
+ goto out_unlock;
+ ret = -EACCES;
+ if (ipcperms (&msq->q_perm, S_IRUGO))
+ goto out_unlock;
+
+ poll_wait(file, &msq->ipc_dev_wait, wait);
+
+ ret = 0;
+ if(msq->q_qnum)
+ ret = POLLIN | POLLRDNORM;
+
+out_unlock:
+ msg_unlock(msqid);
+ return ret;
}
+static struct file_operations ipc_dev_fops = {
+ poll: ipc_dev_poll,
+};
+#endif
+
static int newque (key_t key, int msgflg)
{
int id;
+#ifdef CONFIG_IPC_DEV
+ int msgid;
+ char name[32];
+#endif
struct msg_queue *msq;
msq = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
@@ -138,9 +187,21 @@
INIT_LIST_HEAD(&msq->q_messages);
INIT_LIST_HEAD(&msq->q_receivers);
INIT_LIST_HEAD(&msq->q_senders);
+#ifdef CONFIG_IPC_DEV
+ init_waitqueue_head(&msq->ipc_dev_wait);
+#endif
msg_unlock(id);
+#ifdef CONFIG_IPC_DEV
+ msgid = msg_buildid(id,msq->q_perm.seq);
+ sprintf(name, "ipc/%d", msgid);
+ devfs_register(NULL, name,
+ DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR,
+ &ipc_dev_fops, (void*)msgid);
+ return msgid;
+#else
return msg_buildid(id,msq->q_perm.seq);
+#endif
}
static void free_msg(struct msg_msg* msg)
@@ -686,6 +747,9 @@
msq->q_lspid = current->pid;
msq->q_stime = CURRENT_TIME;
+#ifdef CONFIG_IPC_DEV
+ wake_up_interruptible_sync(&msq->ipc_dev_wait);
+#endif
if(!pipelined_send(msq,msg)) {
/* noone is waiting for this message, enqueue it */
list_add_tail(&msg->m_list,&msq->q_messages);
=== send.c ===========================================================
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/msg.h>
#define KEY 1235
#define MSGSZ 200
typedef struct msgbuftoto {
long mtype;
char mtext[MSGSZ];
} msgtoto;
int main(int argc, char *argv[])
{
int ret;
int msqid;
msgtoto toto;
assert((msqid=msgget(KEY, 0664|IPC_CREAT))!=-1);
printf("msqid=%d\n", msqid);
toto.mtype=1;
strncpy(toto.mtext, argv[1], MSGSZ);
assert((ret=msgsnd(msqid, (struct msgbuf*)&toto, MSGSZ, 0))!=-1);
return 0;
}
=== poll_receive.c =====================================================
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/msg.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#define KEY 1235
#define MSGSZ 200
typedef struct msgbuftoto {
long mtype;
char mtext[MSGSZ];
} msgtoto;
int main(int argc, char *argv[])
{
int ret;
int msqid;
char name[32];
struct pollfd pfd;
msgtoto toto;
assert((msqid=msgget(KEY, 0664|IPC_CREAT))!=-1);
sprintf(name, "/dev/ipc/%d", msqid);
assert((pfd.fd=open(name, O_RDONLY))!=-1);
pfd.events=POLLIN;
printf("poll start...\n");
assert(poll(&pfd, 1, -1)!=-1);
printf("poll done!\n");
assert((ret=msgrcv(msqid, (struct msgbuf*)&toto, MSGSZ, 0, 0))!=-1);
assert(close(pfd.fd)!=-1);
printf("%s\n", toto.mtext);
return 0;
}
===================================================================
-- Jean-Christian de Rivaz mailto:jc@lightning.ch - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/