Add CPU hotplug notifier for ltt debugfs ABI, add pollwait exclusive wrapper
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 9 Jun 2011 20:00:14 +0000 (16:00 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 9 Jun 2011 20:00:14 +0000 (16:00 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
13 files changed:
Makefile
lib/Makefile
lib/ringbuffer/frontend.h
lib/ringbuffer/frontend_types.h
lib/ringbuffer/ring_buffer_frontend.c
lib/ringbuffer/ring_buffer_vfs.c
ltt-debugfs-abi.c
ltt-events.c
ltt-events.h
ltt-ring-buffer-client.h
ltt-ring-buffer-metadata-client.h
wrapper/poll.c [new file with mode: 0644]
wrapper/poll.h

index dc44fd40b6cfb2834ef0b1e89861aa5e85ecafc4..d6f1a886c220f03c256bbd35a419b783902cdd8e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,8 @@ obj-m += ltt-relay.o
 ltt-relay-objs :=  ltt-events.o ltt-debugfs-abi.o \
                        ltt-probes.o ltt-core.o ltt-context.o \
                        lttng-context-pid.o lttng-context-comm.o \
-                       lttng-context-prio.o lttng-context-nice.o
+                       lttng-context-prio.o lttng-context-nice.o \
+                       wrapper/poll.o
 
 ifneq ($(CONFIG_PERF_EVENTS),)
 ltt-relay-objs += lttng-context-perf-counters.o
index 9fa49efc9b7037766e326bb87bc4497175c436dd..1697b7f56ea5537d669504f9cfffc9ce9006feab 100644 (file)
@@ -7,4 +7,5 @@ lib-ring-buffer-objs := \
        ringbuffer/ring_buffer_vfs.o \
        ringbuffer/ring_buffer_splice.o \
        ringbuffer/ring_buffer_mmap.o \
-       prio_heap/lttng_prio_heap.o
+       prio_heap/lttng_prio_heap.o \
+       ../wrapper/poll.o
index 003c2e1915f70cb7e53601efe9e8de0fb0d9b0e1..85858d936ca0c3f43ad1c8b84f5f569b1e5e2e54 100644 (file)
@@ -157,6 +157,12 @@ int lib_ring_buffer_is_finalized(const struct lib_ring_buffer_config *config,
        return finalized;
 }
 
+static inline
+int lib_ring_buffer_channel_is_finalized(const struct channel *chan)
+{
+       return chan->finalized;
+}
+
 static inline
 unsigned long lib_ring_buffer_get_read_data_size(
                                const struct lib_ring_buffer_config *config,
index 1a3187e64d5653bec97bbaf581606ca4186f13e2..fe208b676e0f035f8bd4b9794ca94f79f24ca8dd 100644 (file)
@@ -62,6 +62,8 @@ struct channel {
        int cpu_hp_enable:1;                    /* Enable CPU hotplug notif. */
        int hp_iter_enable:1;                   /* Enable hp iter notif. */
        wait_queue_head_t read_wait;            /* reader wait queue */
+       wait_queue_head_t hp_wait;              /* CPU hotplug wait queue */
+       int finalized;                          /* Has channel been finalized */
        struct channel_iter iter;               /* Channel read-side iterator */
        struct kref ref;                        /* Reference count */
 };
index 1931414b067a4c8836b1cece70be5c5ad45ad8a7..ecc72ab84f7e3143f930e77cac0bc6ad3de16a8e 100644 (file)
@@ -410,6 +410,7 @@ int __cpuinit lib_ring_buffer_cpu_hp_callback(struct notifier_block *nb,
        case CPU_DOWN_FAILED_FROZEN:
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
+               wake_up_interruptible(&chan->hp_wait);
                lib_ring_buffer_start_switch_timer(buf);
                lib_ring_buffer_start_read_timer(buf);
                return NOTIFY_OK;
@@ -626,6 +627,7 @@ struct channel *channel_create(const struct lib_ring_buffer_config *config,
        chan->read_timer_interval = usecs_to_jiffies(read_timer_interval);
        kref_init(&chan->ref);
        init_waitqueue_head(&chan->read_wait);
+       init_waitqueue_head(&chan->hp_wait);
 
        if (config->alloc == RING_BUFFER_ALLOC_PER_CPU) {
 #if defined(CONFIG_NO_HZ) && defined(CONFIG_LIB_RING_BUFFER)
@@ -748,6 +750,8 @@ void *channel_destroy(struct channel *chan)
                ACCESS_ONCE(buf->finalized) = 1;
                wake_up_interruptible(&buf->read_wait);
        }
+       ACCESS_ONCE(chan->finalized) = 1;
+       wake_up_interruptible(&chan->hp_wait);
        wake_up_interruptible(&chan->read_wait);
        kref_put(&chan->ref, channel_release);
        priv = chan->backend.priv;
index 6a9fb469ca4f73ccc4940b755a3607ec4bf3784d..2558ab667666be50b29eb9df484d4ea3773d140d 100644 (file)
@@ -89,7 +89,7 @@ unsigned int lib_ring_buffer_poll(struct file *filp, poll_table *wait)
        int finalized;
 
        if (filp->f_mode & FMODE_READ) {
-               poll_wait_set_exclusive(wait);
+               init_poll_funcptr(wait, wrapper_pollwait_exclusive);
                poll_wait(filp, &buf->read_wait, wait);
 
                finalized = lib_ring_buffer_is_finalized(config, buf);
index 1314c663e77e321fc32bc638d0183bacc74f727a..fb6c789f1e0da0f4aa32bba7775fb86d439b90f0 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include "wrapper/vmalloc.h"   /* for wrapper_vmalloc_sync_all() */
 #include "wrapper/ringbuffer/vfs.h"
+#include "wrapper/poll.h"
 #include "ltt-debugfs-abi.h"
 #include "ltt-events.h"
 #include "ltt-tracer.h"
@@ -551,8 +552,6 @@ long lttng_metadata_ioctl(struct file *file, unsigned int cmd, unsigned long arg
        }
 }
 
-/* TODO: poll */
-#if 0
 /**
  *     lttng_channel_poll - lttng stream addition/removal monitoring
  *
@@ -565,11 +564,11 @@ unsigned int lttng_channel_poll(struct file *file, poll_table *wait)
        unsigned int mask = 0;
 
        if (file->f_mode & FMODE_READ) {
-               poll_wait_set_exclusive(wait);
-               poll_wait(file, &channel->notify_wait, wait);
+               init_poll_funcptr(wait, wrapper_pollwait_exclusive);
+               poll_wait(file, channel->ops->get_hp_wait_queue(channel->chan),
+                         wait);
 
-               /* TODO: identify when the channel is being finalized. */
-               if (finalized)
+               if (channel->ops->is_finalized(channel->chan))
                        return POLLHUP;
                else
                        return POLLIN | POLLRDNORM;
@@ -577,7 +576,6 @@ unsigned int lttng_channel_poll(struct file *file, poll_table *wait)
        return mask;
 
 }
-#endif //0
 
 static
 int lttng_channel_release(struct inode *inode, struct file *file)
@@ -591,10 +589,7 @@ int lttng_channel_release(struct inode *inode, struct file *file)
 
 static const struct file_operations lttng_channel_fops = {
        .release = lttng_channel_release,
-/* TODO */
-#if 0
        .poll = lttng_channel_poll,
-#endif //0
        .unlocked_ioctl = lttng_channel_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = lttng_channel_ioctl,
index e3c252d33962b52cdf3e86b90233bec53e2c92f9..40e8e459183efacae2744fcc6a6071bd9625e5b1 100644 (file)
@@ -169,7 +169,6 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session,
        if (!chan)
                goto nomem;
        chan->session = session;
-       init_waitqueue_head(&chan->notify_wait);
        chan->id = session->free_chan_id++;
        /*
         * Note: the channel creation op already writes into the packet
@@ -385,7 +384,7 @@ int lttng_metadata_printf(struct ltt_session *session,
                 * we need to bail out after timeout or being
                 * interrupted.
                 */
-               waitret = wait_event_interruptible_timeout(*chan->ops->get_reader_wait_queue(chan),
+               waitret = wait_event_interruptible_timeout(*chan->ops->get_reader_wait_queue(chan->chan),
                        ({
                                ret = chan->ops->event_reserve(&ctx, 0);
                                ret != -ENOBUFS || !ret;
index ec70eceadc69986627e2b02031a3b41324185c86..9c6fcac31a7a9207ad718be60a733c365755111c 100644 (file)
@@ -202,7 +202,9 @@ struct ltt_channel_ops {
         * may change due to concurrent writes.
         */
        size_t (*packet_avail_size)(struct channel *chan);
-       wait_queue_head_t *(*get_reader_wait_queue)(struct ltt_channel *chan);
+       wait_queue_head_t *(*get_reader_wait_queue)(struct channel *chan);
+       wait_queue_head_t *(*get_hp_wait_queue)(struct channel *chan);
+       int (*is_finalized)(struct channel *chan);
 };
 
 struct ltt_channel {
@@ -214,7 +216,6 @@ struct ltt_channel {
        struct file *file;              /* File associated to channel */
        unsigned int free_event_id;     /* Next event ID to allocate */
        struct list_head list;          /* Channel list */
-       wait_queue_head_t notify_wait;  /* Channel addition notif. waitqueue */
        struct ltt_channel_ops *ops;
        int header_type;                /* 0: unset, 1: compact, 2: large */
        int metadata_dumped:1;
index 1c9308e04f7151e9d38db7aeb83609bdca8c51c3..d14297857925b274fcf89222d37895adb97bcd8c 100644 (file)
@@ -455,9 +455,21 @@ void ltt_event_write(struct lib_ring_buffer_ctx *ctx, const void *src,
 }
 
 static
-wait_queue_head_t *ltt_get_reader_wait_queue(struct ltt_channel *chan)
+wait_queue_head_t *ltt_get_reader_wait_queue(struct channel *chan)
 {
-       return &chan->chan->read_wait;
+       return &chan->read_wait;
+}
+
+static
+wait_queue_head_t *ltt_get_hp_wait_queue(struct channel *chan)
+{
+       return &chan->hp_wait;
+}
+
+static
+int ltt_is_finalized(struct channel *chan)
+{
+       return lib_ring_buffer_channel_is_finalized(chan);
 }
 
 static struct ltt_transport ltt_relay_transport = {
@@ -473,6 +485,8 @@ static struct ltt_transport ltt_relay_transport = {
                .event_write = ltt_event_write,
                .packet_avail_size = NULL,      /* Would be racy anyway */
                .get_reader_wait_queue = ltt_get_reader_wait_queue,
+               .get_hp_wait_queue = ltt_get_hp_wait_queue,
+               .is_finalized = ltt_is_finalized,
        },
 };
 
index a5ce2062652b9681394711fb48436569b4b20c27..a687b7050adfa94a3049b0f56e301a8c81611355 100644 (file)
@@ -220,9 +220,21 @@ size_t ltt_packet_avail_size(struct channel *chan)
 }
 
 static
-wait_queue_head_t *ltt_get_reader_wait_queue(struct ltt_channel *chan)
+wait_queue_head_t *ltt_get_reader_wait_queue(struct channel *chan)
 {
-       return &chan->chan->read_wait;
+       return &chan->read_wait;
+}
+
+static
+wait_queue_head_t *ltt_get_hp_wait_queue(struct channel *chan)
+{
+       return &chan->hp_wait;
+}
+
+static
+int ltt_is_finalized(struct channel *chan)
+{
+       return lib_ring_buffer_channel_is_finalized(chan);
 }
 
 static struct ltt_transport ltt_relay_transport = {
@@ -238,6 +250,8 @@ static struct ltt_transport ltt_relay_transport = {
                .event_write = ltt_event_write,
                .packet_avail_size = ltt_packet_avail_size,
                .get_reader_wait_queue = ltt_get_reader_wait_queue,
+               .get_hp_wait_queue = ltt_get_hp_wait_queue,
+               .is_finalized = ltt_is_finalized,
        },
 };
 
diff --git a/wrapper/poll.c b/wrapper/poll.c
new file mode 100644 (file)
index 0000000..f3f76fe
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Mathieu Desnoyers (mathieu.desnoyers@efficios.com)
+ *
+ * wrapper around poll __pollwait and poll_get_entry. Using KALLSYMS to get its
+ * address when available, else we need to have a kernel that exports this
+ * function to GPL modules.
+ *
+ * Dual LGPL v2.1/GPL v2 license.
+ */
+
+#ifdef CONFIG_KALLSYMS
+
+#include <linux/kallsyms.h>
+#include <linux/poll.h>
+
+struct poll_table_entry;
+struct splice_pipe_desc;
+
+static
+void (*__pollwait_sym)(struct file *filp, wait_queue_head_t *wait_address,
+               poll_table *p);
+static
+struct poll_table_entry *(*poll_get_entry_sym)(struct poll_wqueues *p);
+
+void wrapper_pollwait_exclusive(struct file *filp,
+                        wait_queue_head_t *wait_address,
+                        poll_table *p)
+
+{
+       struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
+       struct poll_table_entry *entry;
+
+       if (!poll_get_entry_sym)
+               poll_get_entry_sym = (void *) kallsyms_lookup_name("poll_get_entry");
+       if (!poll_get_entry_sym) {
+               printk(KERN_WARNING "LTTng: poll_get_entry_sym symbol lookup failed.\n");
+               return;
+       }
+       entry = poll_get_entry_sym(pwq);
+
+       if (!__pollwait_sym)
+               __pollwait_sym = (void *) kallsyms_lookup_name("__pollwait");
+       if (!__pollwait_sym) {
+               printk(KERN_WARNING "LTTng: __pollwait symbol lookup failed.\n");
+               return;
+       }
+       return __pollwait_sym(filp, wait_address, p);
+}
+
+#else
+
+#include <linux/poll.h>
+
+ssize_t wrapper_pollwait_exclusive(struct file *filp,
+                       wait_queue_head_t *wait_address,
+                       poll_table *p)
+{
+       return pollwait_exclusive(filp, wait_address, p);
+}
+
+#endif
index 416ce5740da7a6e15b88401e209c49dc54860310..ae524730cda3e184c34293e69d8bd7beec4fa5d3 100644 (file)
@@ -1,20 +1,20 @@
+#ifndef _LTTNG_WRAPPER_POLL_H
+#define _LTTNG_WRAPPER_POLL_H
+
 /*
- * wrapper/poll.h
+ * Copyright (C) 2011 Mathieu Desnoyers (mathieu.desnoyers@efficios.com)
  *
- * Copyright (C) 2010-2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * wrapper around poll __pollwait and poll_get_entry. Using KALLSYMS to get its
+ * address when available, else we need to have a kernel that exports this
+ * function to GPL modules.
  *
  * Dual LGPL v2.1/GPL v2 license.
  */
 
-#ifndef CONFIG_LIB_RING_BUFFER
 #include <linux/poll.h>
 
-#warning "poll_wait_set_exclusive() is defined as no-op. Will increase LTTng overhead. Please consider using the LTTng kernel tree for better results."
-
-/*
- * Will cause higher overhead when signalling all possible reader threads when a
- * buffer is ready to be consumed.
- */
-#define poll_wait_set_exclusive(poll_table)
+void wrapper_pollwait_exclusive(struct file *filp,
+                        wait_queue_head_t *wait_address,
+                        poll_table *p);
 
-#endif
+#endif /* _LTTNG_WRAPPER_POLL_H */
This page took 0.037765 seconds and 4 git commands to generate.