Permalink
Browse files

demo program for using ZMQ_IGNERR patch

also contains a named pipe reading example

Signed-off-by: Michael Haberler <git@mah.priv.at>
  • Loading branch information...
1 parent 09e3711 commit b533e4255a0ab0e267d456a2577082c9ec1d8b39 Michael Haberler committed Sep 26, 2012
Showing with 337 additions and 0 deletions.
  1. +23 −0 demo/Makefile
  2. +58 −0 demo/README
  3. +91 −0 demo/sysfsexample.c
  4. +82 −0 demo/zloop-namedpipe.c
  5. +83 −0 demo/zloop-sysfs.c
View
@@ -0,0 +1,23 @@
+CZMQ_FLAGS := $(shell pkg-config libczmq libzmq --cflags --libs)
+
+all: zloop-sysfs zloop-namedpipe sysfsexample.ko
+
+
+zloop-namedpipe: zloop-namedpipe.c
+ gcc -g $(CZMQ_FLAGS) -o $@ $^
+
+
+
+zloop-sysfs: zloop-sysfs.c
+ gcc -g $(CZMQ_FLAGS) -o $@ $^
+
+obj-m := sysfsexample.o
+
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+sysfsexample.ko: sysfsexample.c
+ make M=$(PWD) -C $(KDIR)
+
+clean:
+ rm -f zloop-sysfs zloop-namedpipe sysfsexample.ko *.o modules.order Module.symvers
View
@@ -0,0 +1,58 @@
+This directory contains two zloop examples:
+
+
+zloop-sysfs:
+------------
+Example monitoring a sysfs device through a file descriptor zmq_pollitem.
+
+
+sysfsexample kernel module:
+---------------------------
+this creates two sysfs entries:
+- /sys/syfs_example/notify
+- /sys/syfs_example/trigger
+
+to activate:
+
+$ insmod ./sysfsexample.ko
+
+Verify with dmesg that it has been properly loaded.
+
+An int value written to /sys/syfs_example/trigger will be returned by
+reading /sys/syfs_example/notify; also a sysfs_notify() is executed on
+/sys/syfs_example/notify to signal to a user process that new content is available.
+
+then start zloop-sysfs like so:
+
+$ zloop-sysfs /sys/sysfs_example/notify
+
+then try a few times
+# echo 123 > /sys/syfs_example/trigger
+
+this will cause a sysfs_notify() on /sys/sysfs_example/notify; note that only
+the first echo will cause zloop-sysfs to react since the handler is disabled
+by czmq as a reaction to the POLLERR delivered by the sysfs event.
+
+To demonstrate the ZMQ_IGNERR patch, try like so:
+
+
+$ zloop-sysfs /sys/sysfs_example/notify 1
+
+# NB: the extra argument will activate the ZMQ_IGNERR option
+
+now try again a few times, which should work fine:
+# echo 123 > /sys/syfs_example/trigger
+
+The handler will not be disabled any more.
+
+
+zloop-namedpipe:
+------------
+Example monitoring a named pipe device through a file descriptor zmq_pollitem.
+This has nothing to do with the ZMQ_IGNERR patch per se - it just demonstrates handling
+reading, and dealing with a closed named pipe which is a bit tricky.
+
+To try:
+
+$ mknod /tmp/pipe p
+$ zloop-namedpip /tmp/pipe
View
@@ -0,0 +1,91 @@
+//http://godandme.wordpress.com/2011/04/05/how-to-make-a-sysfs-entry/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+struct my_attr {
+ struct attribute attr;
+ int value;
+};
+
+static struct my_attr notify = {
+ .attr.name="notify",
+ .attr.mode = 0644,
+ .value = 0,
+};
+
+static struct my_attr trigger = {
+ .attr.name="trigger",
+ .attr.mode = 0644,
+ .value = 0,
+};
+
+static struct attribute * myattr[] = {
+ &notify.attr,
+ &trigger.attr,
+ NULL
+};
+
+static ssize_t default_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct my_attr *a = container_of(attr, struct my_attr, attr);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", a->value);
+}
+static struct kobject *mykobj;
+
+static ssize_t default_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct my_attr *a = container_of(attr, struct my_attr, attr);
+
+ sscanf(buf, "%d", &a->value);
+ notify.value = a->value;
+ printk("sysfs_notify store %s = %d\n", a->attr.name, a->value);
+ sysfs_notify(mykobj, NULL, "notify");
+ return sizeof(int);
+}
+
+static struct sysfs_ops myops = {
+ .show = default_show,
+ .store = default_store,
+};
+
+static struct kobj_type mytype = {
+ .sysfs_ops = &myops,
+ .default_attrs = myattr,
+};
+
+static struct kobject *mykobj;
+static int __init sysfsexample_module_init(void)
+{
+ int err = -1;
+ printk("sysfs_notify init\n");
+ mykobj = kzalloc(sizeof(*mykobj), GFP_KERNEL);
+ if (mykobj) {
+ kobject_init(mykobj, &mytype);
+ if (kobject_add(mykobj, NULL, "%s", "sysfs_sample")) {
+ err = -1;
+ printk("sysfs_notify: kobject_add() failed\n");
+ kobject_put(mykobj);
+ mykobj = NULL;
+ }
+ err = 0;
+ }
+ return err;
+}
+
+static void __exit sysfsexample_module_exit(void)
+{
+ if (mykobj) {
+ kobject_put(mykobj);
+ kfree(mykobj);
+ }
+ printk("sysfs_notify exit\n");
+}
+
+module_init(sysfsexample_module_init);
+module_exit(sysfsexample_module_exit);
+MODULE_LICENSE("GPL");
View
@@ -0,0 +1,82 @@
+#include "czmq.h"
+
+static char *pipe_name;
+static int pipe_fd;
+static void *ctx;
+static zloop_t *loop;
+
+
+int s_handle_pipe(zloop_t *loop, zmq_pollitem_t *poller, void *arg)
+{
+ char buffer[20], *endptr;
+ unsigned eventmask;
+ int retval;
+
+ printf("s_handle_pipe revents=0x%x\n", poller->revents);
+
+ // if 'echo 123 >pipe' is executed, this handler is called twice:
+ // - first time when there's actually something to read
+ // - a second time when the pipe write side is closed
+
+ // depending on how libzmq is configured, revents may be subtly different
+ // on pipe write side close:
+ // if configured with --with-poller=poll|epoll, a ZMQ_POLLERR is signaled
+ // if configured with --with-poller=select, a ZMQ_POLLIN is signaled
+
+ if (poller->revents & (ZMQ_POLLIN|ZMQ_POLLERR)) {
+ // check if pipe readable
+ retval = read(poller->fd, buffer, sizeof(buffer));
+ if (retval > 0) {
+ printf("s_handle_pipe read(%d): '%.*s'\n", retval, retval, buffer);
+ }
+ if ((retval == 0) || (poller->revents & ZMQ_POLLERR)) {
+ printf("s_handle_pipe: pipe closed - re-registering poller\n");
+
+ // the write side was closed.
+ zloop_poller_end(loop, poller);
+ // close & reopen pipe,
+ close(poller->fd);
+ poller->fd = pipe_fd = open(pipe_name, O_RDONLY|O_NONBLOCK);
+ if (poller->fd < 0) {
+ // real bad - pipe removed?
+ printf("ERROR: reopening pipe %s : %s - disabling pipe notifications\n",
+ pipe_name,
+ strerror (errno));
+ return 0;
+ }
+ // reestablish zloop poller.
+ zloop_poller(loop, poller, s_handle_pipe, NULL);
+
+ } else if (retval < 0) {
+ // 'should not happen'
+ printf("ERROR: read(%s): %s - disabling pipe notifications\n",
+ pipe_name,
+ strerror (errno));
+ }
+ }
+ return 0;
+}
+
+
+int main (int argc, char *argv[])
+{
+ int i, retval;
+
+ pipe_name = argv[1];
+
+ ctx = zctx_new ();
+ assert(ctx != NULL);
+
+ pipe_fd = open(pipe_name, O_RDONLY|O_NONBLOCK);
+ assert(pipe_fd >= 0);
+
+ loop = zloop_new();
+ assert (loop);
+ zloop_set_verbose (loop, 1);
+
+ zmq_pollitem_t pipe_poller = { 0, pipe_fd, ZMQ_POLLIN };
+
+ zloop_poller (loop, &pipe_poller, s_handle_pipe, 0);
+ zloop_start(loop);
+ exit(0);
+}
View
@@ -0,0 +1,83 @@
+// example of monitoring a sysfs entry with a zloop reactor
+//
+// sysfs has a way of notifying a user process that the content of a sysfs
+// file has changed - the kernel function sysfs_notify() makes a
+// sysfs entry pollable.
+//
+// sysfs_notify() will make a poll(2) return with the POLLPRI and POLLERR
+// event bits set. However, by default czmq will interpret POLLERR
+// on a file descriptor as fatal and disable the zloop callback, resulting
+// in a once-only notification on a sysfs entry.
+//
+// the new ZMQ_IGNERR flag can be set in zmq_pollitem_t.events to suppress
+// this behaviour.
+//
+// see also: http://lwn.net/Articles/174660/ for background on sysfs_notify()
+//
+
+
+
+#include "czmq.h"
+
+
+static char *sysfs_name;
+static int sysfs_fd;
+static void *ctx;
+static zloop_t *loop;
+
+int s_handle_sysfs(zloop_t *loop, zmq_pollitem_t *poller, void *arg)
+{
+ char buffer[256], *endptr;
+ unsigned eventmask;
+ int retval;
+
+ printf("s_handle_sysfs revents=0x%x\n", poller->revents);
+
+ // with a sysfs device, poll returns POLLPRI|POLLERR which is mapped
+ // to ZMQ_POLLERR by libzmq; same for select() version of libzmq.
+
+ if (poller->revents & ZMQ_POLLERR) {
+ lseek(poller->fd, 0, SEEK_SET);
+ retval = read(poller->fd, buffer, sizeof(buffer));
+ if (retval > 0) {
+ printf("s_handle_sysfs read(%d): '%.*s'\n", retval, retval, buffer);
+ } else {
+ // pretty bad, but not much to do about it
+ printf("reading sysfs entry %s - %s : disabling sysfs notifications\n",
+ sysfs_name, strerror(retval));
+ zloop_poller_end (loop, poller);
+ }
+ }
+ return 0;
+}
+
+int main (int argc, char *argv[])
+{
+ int i, retval;
+
+ assert(argc > 1);
+ sysfs_name = argv[1];
+
+ ctx = zctx_new ();
+ assert(ctx != NULL);
+
+ sysfs_fd = open(sysfs_name, O_RDONLY);
+ assert(sysfs_fd >= 0);
+
+ loop = zloop_new();
+ assert (loop);
+ zloop_set_verbose (loop, 1);
+
+ zmq_pollitem_t sysfs_poller = { 0, sysfs_fd, ZMQ_POLLERR };
+ if (argc > 2) {
+#ifdef ZMQ_IGNERR
+ sysfs_poller.events |= ZMQ_IGNERR;
+ printf("ZMQ_IGNERR set on sysfs_poller\n");
+#else
+ printf("ZMQ_IGNERR not available in this czmq version.\n");
+#endif
+ }
+ zloop_poller (loop, &sysfs_poller, s_handle_sysfs, 0);
+ zloop_start(loop);
+ exit(0);
+}

0 comments on commit b533e42

Please sign in to comment.