forked from zeromq/czmq
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
Michael Haberler
committed
Sep 27, 2012
1 parent
09e3711
commit b533e42
Showing
5 changed files
with
337 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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[] = { | ||
¬ify.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"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |