Skip to content

Commit

Permalink
demo program for using ZMQ_IGNERR patch
Browse files Browse the repository at this point in the history
also contains a named pipe reading example

Signed-off-by: Michael Haberler <git@mah.priv.at>
  • Loading branch information
Michael Haberler committed Sep 27, 2012
1 parent 09e3711 commit b533e42
Show file tree
Hide file tree
Showing 5 changed files with 337 additions and 0 deletions.
23 changes: 23 additions & 0 deletions demo/Makefile
@@ -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
58 changes: 58 additions & 0 deletions demo/README
@@ -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
91 changes: 91 additions & 0 deletions demo/sysfsexample.c
@@ -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");
82 changes: 82 additions & 0 deletions demo/zloop-namedpipe.c
@@ -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);
}
83 changes: 83 additions & 0 deletions demo/zloop-sysfs.c
@@ -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.