Keep event description registry instead of just name callback mapping
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 13 May 2011 08:24:30 +0000 (04:24 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 13 May 2011 08:24:30 +0000 (04:24 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
ltt-debugfs-abi.c
ltt-events.c
ltt-events.h
ltt-probes.c
probes/lttng-events.h

index 99b4196616419e754544e46469da5edba4f9610a..0f649fc2af4bd10682949be82408cce0b7191ec9 100644 (file)
@@ -124,30 +124,30 @@ void lttng_metadata_create_events(struct file *channel_file)
 {
        struct ltt_channel *channel = channel_file->private_data;
        char *event_name = "lttng-metadata";
+       const struct lttng_event_desc *event_desc;
        struct ltt_event *event;
        int ret;
-       void *probe;
 
-       probe = ltt_probe_get(event_name);
-       if (!probe) {
+       event_desc = ltt_event_get(event_name);
+       if (!event_desc) {
                ret = -ENOENT;
-               goto probe_error;
+               goto get_error;
        }
        /*
         * We tolerate no failure path after event creation. It will stay
         * invariant for the rest of the session.
         */
        event = ltt_event_create(channel, event_name, INSTRUM_TRACEPOINTS,
-                                probe, NULL);
+                                event_desc, NULL);
        if (!event) {
-               goto event_error;
+               goto create_error;
                ret = -EEXIST;
        }
        return;
 
-event_error:
-       ltt_probe_put(probe);
-probe_error:
+create_error:
+       ltt_event_put(event_desc);
+get_error:
        WARN_ON(1);
        return;         /* not allowed to return error */
 }
@@ -338,12 +338,12 @@ int lttng_abi_create_event(struct file *channel_file,
                           struct lttng_event __user *uevent_param)
 {
        struct ltt_channel *channel = channel_file->private_data;
+       const struct lttng_event_desc *event_desc;
        struct ltt_event *event;
        char *event_name;
        struct lttng_event event_param;
        int event_fd, ret;
        struct file *event_file;
-       void *probe;
 
        if (copy_from_user(&event_param, uevent_param, sizeof(event_param)))
                return -EFAULT;
@@ -356,10 +356,10 @@ int lttng_abi_create_event(struct file *channel_file,
        }
        event_name[PATH_MAX - 1] = '\0';
 
-       probe = ltt_probe_get(event_name);
-       if (!probe) {
+       event_desc = ltt_event_get(event_name);
+       if (!event_desc) {
                ret = -ENOENT;
-               goto probe_error;
+               goto get_error;
        }
        event_fd = get_unused_fd();
        if (event_fd < 0) {
@@ -378,7 +378,7 @@ int lttng_abi_create_event(struct file *channel_file,
         * invariant for the rest of the session.
         */
        event = ltt_event_create(channel, event_name, event_param.itype,
-                                probe, NULL);
+                                event_desc, NULL);
        if (!event) {
                goto event_error;
                ret = -EEXIST;
@@ -395,8 +395,8 @@ event_error:
 file_error:
        put_unused_fd(event_fd);
 fd_error:
-       ltt_probe_put(probe);
-probe_error:
+       ltt_event_put(event_desc);
+get_error:
 name_error:
        kfree(event_name);
        return ret;
index 512e7a24676214e09063a35566cef322eca8644a..a5ca1abaa798c83489fc604705a0ea966141ffa4 100644 (file)
@@ -167,7 +167,8 @@ void _ltt_channel_destroy(struct ltt_channel *chan)
  */
 struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name,
                                   enum instrum_type itype,
-                                  void *probe, void *filter)
+                                  const struct lttng_event_desc *event_desc,
+                                  void *filter)
 {
        struct ltt_event *event;
        int ret;
@@ -180,17 +181,13 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name,
         * creation). Might require a hash if we have lots of events.
         */
        list_for_each_entry(event, &chan->session->events, list)
-               if (!strcmp(event->name, name))
+               if (!strcmp(event->desc->name, name))
                        goto exist;
        event = kmem_cache_zalloc(event_cache, GFP_KERNEL);
        if (!event)
                goto cache_error;
-       event->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
-       if (!event->name)
-               goto name_error;
-       strcpy(event->name, name);
        event->chan = chan;
-       event->probe = probe;
+       event->desc = event_desc;
        event->filter = filter;
        event->id = chan->free_event_id++;
        event->itype = itype;
@@ -198,7 +195,8 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name,
        smp_wmb();
        switch (itype) {
        case INSTRUM_TRACEPOINTS:
-               ret = tracepoint_probe_register(name, probe, event);
+               ret = tracepoint_probe_register(name, event_desc->probe_callback,
+                                               event);
                if (ret)
                        goto register_error;
                break;
@@ -210,8 +208,6 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name,
        return event;
 
 register_error:
-       kfree(event->name);
-name_error:
        kmem_cache_free(event_cache, event);
 cache_error:
 exist:
@@ -229,7 +225,8 @@ int _ltt_event_unregister(struct ltt_event *event)
 
        switch (event->itype) {
        case INSTRUM_TRACEPOINTS:
-               ret = tracepoint_probe_unregister(event->name, event->probe,
+               ret = tracepoint_probe_unregister(event->desc->name,
+                                                 event->desc->probe_callback,
                                                  event);
                if (ret)
                        return ret;
@@ -245,7 +242,7 @@ int _ltt_event_unregister(struct ltt_event *event)
  */
 void _ltt_event_destroy(struct ltt_event *event)
 {
-       kfree(event->name);
+       ltt_event_put(event->desc);
        list_del(&event->list);
        kmem_cache_free(event_cache, event);
 }
@@ -297,16 +294,11 @@ static int __init ltt_events_init(void)
        event_cache = KMEM_CACHE(ltt_event, 0);
        if (!event_cache)
                return -ENOMEM;
-       ret = ltt_probes_init();
-       if (ret)
-               goto error;
        ret = ltt_debugfs_abi_init();
        if (ret)
                goto error_abi;
        return 0;
 error_abi:
-       ltt_probes_exit();
-error:
        kmem_cache_destroy(event_cache);
        return ret;
 }
@@ -318,7 +310,6 @@ static void __exit ltt_events_exit(void)
        struct ltt_session *session, *tmpsession;
 
        ltt_debugfs_abi_exit();
-       ltt_probes_exit();
        list_for_each_entry_safe(session, tmpsession, &sessions, list)
                ltt_session_destroy(session);
        kmem_cache_destroy(event_cache);
index 9e0ad2d74784c6696be40827e9dce816b1ae4a34..344b6fd1e037b2bf73e0f173f975d1ff98646bbc 100644 (file)
@@ -16,62 +16,6 @@ struct ltt_channel;
 struct ltt_session;
 struct lib_ring_buffer_ctx;
 
-/*
- * ltt_event structure is referred to by the tracing fast path. It must be
- * kept small.
- */
-struct ltt_event {
-       unsigned int id;
-       struct ltt_channel *chan;
-       void *probe;
-       void *filter;
-       char *name;
-       enum instrum_type itype;
-       struct list_head list;          /* Event list */
-};
-
-struct ltt_channel_ops {
-       struct channel *(*channel_create)(const char *name,
-                               struct ltt_session *session,
-                               void *buf_addr,
-                               size_t subbuf_size, size_t num_subbuf,
-                               unsigned int switch_timer_interval,
-                               unsigned int read_timer_interval);
-       void (*channel_destroy)(struct channel *chan);
-       struct lib_ring_buffer *(*buffer_read_open)(struct channel *chan);
-       void (*buffer_read_close)(struct lib_ring_buffer *buf);
-       int (*event_reserve)(struct lib_ring_buffer_ctx *ctx);
-       void (*event_commit)(struct lib_ring_buffer_ctx *ctx);
-       void (*event_write)(struct lib_ring_buffer_ctx *ctx, const void *src,
-                           size_t len);
-};
-
-struct ltt_channel {
-       struct channel *chan;           /* Channel buffers */
-       /* Event ID management */
-       struct ltt_session *session;
-       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;
-};
-
-struct ltt_session {
-       int active;                     /* Is trace session active ? */
-       struct file *file;              /* File associated to session */
-       struct list_head chan;          /* Channel list head */
-       struct list_head events;        /* Event list head */
-       struct list_head list;          /* Session list */
-};
-
-struct ltt_transport {
-       char *name;
-       struct module *owner;
-       struct list_head node;
-       struct ltt_channel_ops ops;
-};
-
 /* Type description */
 
 /* Update the astract_types name table in lttng-types.c along with this enum */
@@ -143,6 +87,67 @@ struct lttng_event_desc {
        unsigned int nr_fields;
 };
 
+struct lttng_probe_desc {
+       const struct lttng_event_desc *event_desc;
+       unsigned int nr_events;
+       struct list_head head;                  /* chain registered probes */
+};
+
+/*
+ * ltt_event structure is referred to by the tracing fast path. It must be
+ * kept small.
+ */
+struct ltt_event {
+       unsigned int id;
+       struct ltt_channel *chan;
+       const struct lttng_event_desc *desc;
+       void *filter;
+       enum instrum_type itype;
+       struct list_head list;          /* Event list */
+};
+
+struct ltt_channel_ops {
+       struct channel *(*channel_create)(const char *name,
+                               struct ltt_session *session,
+                               void *buf_addr,
+                               size_t subbuf_size, size_t num_subbuf,
+                               unsigned int switch_timer_interval,
+                               unsigned int read_timer_interval);
+       void (*channel_destroy)(struct channel *chan);
+       struct lib_ring_buffer *(*buffer_read_open)(struct channel *chan);
+       void (*buffer_read_close)(struct lib_ring_buffer *buf);
+       int (*event_reserve)(struct lib_ring_buffer_ctx *ctx);
+       void (*event_commit)(struct lib_ring_buffer_ctx *ctx);
+       void (*event_write)(struct lib_ring_buffer_ctx *ctx, const void *src,
+                           size_t len);
+};
+
+struct ltt_channel {
+       struct channel *chan;           /* Channel buffers */
+       /* Event ID management */
+       struct ltt_session *session;
+       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;
+};
+
+struct ltt_session {
+       int active;                     /* Is trace session active ? */
+       struct file *file;              /* File associated to session */
+       struct list_head chan;          /* Channel list head */
+       struct list_head events;        /* Event list head */
+       struct list_head list;          /* Session list */
+};
+
+struct ltt_transport {
+       char *name;
+       struct module *owner;
+       struct list_head node;
+       struct ltt_channel_ops ops;
+};
+
 struct ltt_session *ltt_session_create(void);
 int ltt_session_start(struct ltt_session *session);
 int ltt_session_stop(struct ltt_session *session);
@@ -164,7 +169,8 @@ void _ltt_channel_destroy(struct ltt_channel *chan);
 struct ltt_event *ltt_event_create(struct ltt_channel *chan,
                                   char *name,
                                   enum instrum_type itype,
-                                  void *probe, void *filter);
+                                  const struct lttng_event_desc *event_desc,
+                                  void *filter);
 int _ltt_event_unregister(struct ltt_event *event);
 void _ltt_event_destroy(struct ltt_event *event);
 
@@ -174,11 +180,9 @@ void ltt_transport_unregister(struct ltt_transport *transport);
 int ltt_debugfs_abi_init(void);
 void ltt_debugfs_abi_exit(void);
 
-int ltt_probe_register(const char *name, void *cb);
-void ltt_probe_unregister(const char *name);
-void *ltt_probe_get(const char *name);
-void ltt_probe_put(void *cb);
-int ltt_probes_init(void);
-void ltt_probes_exit(void);
+int ltt_probe_register(struct lttng_probe_desc *desc);
+void ltt_probe_unregister(struct lttng_probe_desc *desc);
+const struct lttng_event_desc *ltt_event_get(const char *name);
+void ltt_event_put(const struct lttng_event_desc *desc);
 
 #endif /* _LTT_EVENTS_H */
index f8f1ef225b417473fb0c6a69fc969fe4cbac40bd..dbdb50d402a2f7bbecd06a203d03fe46a3b85300 100644 (file)
 #include <linux/module.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
-#include <linux/slab.h>
 
-struct ltt_probe {
-       const char *name;
-       void *cb;
-       struct list_head list;
-};
+#include "ltt-events.h"
 
 static LIST_HEAD(probe_list);
 static DEFINE_MUTEX(probe_mutex);
-static struct kmem_cache *probe_cache;
 
-static struct ltt_probe *find_probe(const char *name)
+static
+const struct lttng_event_desc *find_event(const char *name)
 {
-       struct ltt_probe *probe;
+       struct lttng_probe_desc *probe_desc;
+       int i;
 
-       list_for_each_entry(probe, &probe_list, list) {
-               if (!strcmp(probe->name, name))
-                       return probe;
+       list_for_each_entry(probe_desc, &probe_list, head) {
+               for (i = 0; i < probe_desc->nr_events; i++) {
+                       if (!strcmp(probe_desc->event_desc[i].name, name))
+                               return &probe_desc->event_desc[i];
+               }
        }
        return NULL;
 }
 
-int ltt_probe_register(const char *name, void *cb)
+/*
+ * TODO: registration of probe descriptions in dynamically allocated memory (not
+ * directly in a module memory) will require some care for refcounting: it's
+ * currently done by just refcounting the module in event_get/put.
+ */
+int ltt_probe_register(struct lttng_probe_desc *desc)
 {
-       struct ltt_probe *probe;
        int ret = 0;
-
-       if (!cb)
-               return -EPERM;
+       int i;
 
        mutex_lock(&probe_mutex);
-       if (find_probe(name)) {
-               ret = -EEXIST;
-               goto end;
+       /*
+        * TODO: This is O(N^2). Turn into a hash table when probe registration
+        * overhead becomes an issue.
+        */
+       for (i = 0; i < desc->nr_events; i++) {
+               if (find_event(desc->event_desc[i].name)) {
+                       ret = -EEXIST;
+                       goto end;
+               }
        }
-       probe = kmem_cache_zalloc(probe_cache, GFP_KERNEL);
-       if (!probe) {
-               ret = -ENOMEM;
-               goto end;
-       }
-       probe->name = name;
-       probe->cb = cb;
-       list_add(&probe->list, &probe_list);
+       list_add(&desc->head, &probe_list);
 end:
        mutex_unlock(&probe_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(ltt_probe_register);
 
-void ltt_probe_unregister(const char *name)
+void ltt_probe_unregister(struct lttng_probe_desc *desc)
 {
-       struct ltt_probe *probe;
-
        mutex_lock(&probe_mutex);
-       probe = find_probe(name);
-       WARN_ON_ONCE(!probe);
-       list_del(&probe->list);
+       list_del(&desc->head);
        mutex_unlock(&probe_mutex);
-       kmem_cache_free(probe_cache, probe);
 }
 EXPORT_SYMBOL_GPL(ltt_probe_unregister);
 
-void *ltt_probe_get(const char *name)
+const struct lttng_event_desc *ltt_event_get(const char *name)
 {
-       struct ltt_probe *probe;
-       void *cb = NULL;
+       const struct lttng_event_desc *event;
        int ret;
 
        mutex_lock(&probe_mutex);
-       probe = find_probe(name);
-       if (!probe)
+       event = find_event(name);
+       if (!event)
                goto end;
-       cb = probe->cb;
-       ret = try_module_get(__module_text_address((unsigned long) cb));
+       ret = try_module_get(__module_text_address((unsigned long) event));
        WARN_ON_ONCE(!ret);
 end:
        mutex_unlock(&probe_mutex);
-       return cb;
-}
-EXPORT_SYMBOL_GPL(ltt_probe_get);
-
-void ltt_probe_put(void *cb)
-{
-       module_put(__module_text_address((unsigned long) cb));
-}
-EXPORT_SYMBOL_GPL(ltt_probe_put);
-
-int __init ltt_probes_init(void)
-{
-       probe_cache = KMEM_CACHE(ltt_probe, 0);
-       if (!probe_cache)
-               return -ENOMEM;
-       return 0;
+       return event;
 }
+EXPORT_SYMBOL_GPL(ltt_event_get);
 
-void __exit ltt_probes_exit(void)
+void ltt_event_put(const struct lttng_event_desc *event)
 {
-       kmem_cache_destroy(probe_cache);
+       module_put(__module_text_address((unsigned long) event));
 }
+EXPORT_SYMBOL_GPL(ltt_event_put);
index 3a5a3b9cd61c5aeba731e7232b19d398ad5c0584..a739bbc8e20dce85b35fdaa3476ab0f591bc220e 100644 (file)
@@ -173,6 +173,25 @@ static const struct lttng_event_desc TP_ID(__event_desc___, TRACE_SYSTEM)[] = {
 #undef TP_ID1
 #undef TP_ID
 
+
+/*
+ * Stage 2.1 of the trace events.
+ *
+ * Create a toplevel descriptor for the whole probe.
+ */
+
+#define TP_ID1(_token, _system)        _token##_system
+#define TP_ID(_token, _system) TP_ID1(_token, _system)
+
+/* non-const because list head will be modified when registered. */
+static struct lttng_probe_desc TP_ID(__probe_desc___, TRACE_SYSTEM) = {
+       .event_desc = TP_ID(__event_desc___, TRACE_SYSTEM),
+       .nr_events = ARRAY_SIZE(TP_ID(__event_desc___, TRACE_SYSTEM)),
+};
+
+#undef TP_ID1
+#undef TP_ID
+
 /*
  * Stage 3 of the trace events.
  *
@@ -581,46 +600,20 @@ static void __event_probe__##_name(void *__data, _proto)                \
 static int TP_ID(__lttng_events_init__, TRACE_SYSTEM)(void)
 {
        int ret;
-       int i;
 
        wrapper_vmalloc_sync_all();
        ret = TP_ID(__lttng_types_init__, TRACE_SYSTEM)();
        if (ret)
                return ret;
-       for (i = 0; i < ARRAY_SIZE(TP_ID(__event_desc___, TRACE_SYSTEM)); i++) {
-               const struct lttng_event_desc *event_desc;
-
-               event_desc = &TP_ID(__event_desc___, TRACE_SYSTEM)[i];
-               ret = ltt_probe_register(event_desc->name,
-                                        event_desc->probe_callback);
-               if (ret)
-                       goto error;
-       }
-       return 0;
-
-error:
-       for (i--; i >= 0; i--) {
-               const struct lttng_event_desc *event_desc;
-
-               event_desc = &TP_ID(__event_desc___, TRACE_SYSTEM)[i];
-               ltt_probe_unregister(event_desc->name);
-       }
-       return ret;
+       return ltt_probe_register(&TP_ID(__probe_desc___, TRACE_SYSTEM));
 }
 
 module_init_eval(__lttng_events_init__, TRACE_SYSTEM);
 
 static void TP_ID(__lttng_events_exit__, TRACE_SYSTEM)(void)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(TP_ID(__event_desc___, TRACE_SYSTEM)); i++) {
-               const struct lttng_event_desc *event_desc;
-
-               event_desc = &TP_ID(__event_desc___, TRACE_SYSTEM)[i];
-               ltt_probe_unregister(event_desc->name);
-       }
        TP_ID(__lttng_types_exit__, TRACE_SYSTEM)();
+       ltt_probe_unregister(&TP_ID(__probe_desc___, TRACE_SYSTEM));
 }
 
 module_exit_eval(__lttng_events_exit__, TRACE_SYSTEM);
This page took 0.037657 seconds and 4 git commands to generate.