Handle release of parent files (header)
[deliverable/lttng-modules.git] / ltt-events.c
index a85b7932e38e42ffda5fba7fa501aa55b0282381..3060c07e05d2386d8d90d0482b3040d3d0f970b9 100644 (file)
@@ -13,18 +13,22 @@ static LIST_HEAD(sessions);
 static DEFINE_MUTEX(sessions_mutex);
 static struct kmem_cache *event_cache;
 
-struct ltt_session *ltt_session_create(char *name)
+static void synchronize_trace(void)
+{
+       synchronize_sched();
+#ifdef CONFIG_PREEMPT_RT
+       synchronize_rcu();
+#endif
+}
+
+struct ltt_session *ltt_session_create(void)
 {
        struct ltt_session *session;
 
        mutex_lock(&sessions_mutex);
-       list_for_each_entry(session, &sessions, list)
-               if (!strcmp(session->name, name))
-                       goto exist;
-       session = kmalloc(sizeof(struct ltt_session) + strlen(name) + 1);
+       session = kmalloc(sizeof(struct ltt_session));
        if (!session)
                return NULL;
-       strcpy(session->name, name);
        INIT_LIST_HEAD(&session->chan);
        list_add(&session->list, &sessions);
        mutex_unlock(&sessions_mutex);
@@ -41,6 +45,8 @@ int ltt_session_destroy(struct ltt_session *session)
        struct ltt_event *event, *tmpevent;
 
        mutex_lock(&sessions_mutex);
+       session->active = 0;
+       synchronize_trace();    /* Wait for in-flight events to complete */
        list_for_each_entry_safe(event, tmpevent, &session->events, list)
                _ltt_event_destroy(event);
        list_for_each_entry_safe(chan, tmpchan, &session->chan, list)
@@ -50,7 +56,7 @@ int ltt_session_destroy(struct ltt_session *session)
        kfree(session);
 }
 
-struct ltt_channel *ltt_channel_create(struct ltt_session *session, char *name,
+struct ltt_channel *ltt_channel_create(struct ltt_session *session,
                                       int overwrite, void *buf_addr,
                                       size_t subbuf_size, size_t num_subbuf,
                                       unsigned int switch_timer_interval,
@@ -59,14 +65,13 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, char *name,
        struct ltt_channel *chan;
 
        mutex_lock(&sessions_mutex);
-       list_for_each_entry(chan, &session->chan, list)
-               if (!strcmp(chan->name, name))
-                       goto exist;
-       chan = kmalloc(sizeof(struct ltt_channel) + strlen(name) + 1, GFP_KERNEL);
+       if (session->active)
+               goto active;    /* Refuse to add channel to active session */
+       chan = kmalloc(sizeof(struct ltt_channel), GFP_KERNEL);
        if (!chan)
                return NULL;
-       strcpy(chan->name, name);
        chan->session = session;
+       init_waitqueue_head(&chan->notify_wait);
 
        /* TODO: create rb channel */
        list_add(&chan->list, &session->chan);
@@ -74,6 +79,7 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, char *name,
        return chan;
 
 exist:
+active:
        mutex_unlock(&sessions_mutex);
        return NULL;
 }
@@ -83,16 +89,24 @@ exist:
  */
 int _ltt_channel_destroy(struct ltt_channel *chan)
 {
+       /* TODO: destroy rb channel */
        list_del(&chan->list);
        kfree(chan);
 }
 
+/*
+ * Supports event creation while tracing session is active.
+ */
 struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name,
-                                  void *filter)
+                                  enum instrum_type itype,
+                                  void *probe, void *filter)
 {
        struct ltt_event *event;
+       int ret;
 
        mutex_lock(&sessions_mutex);
+       if (chan->free_event_id == -1UL)
+               goto full;
        /*
         * This is O(n^2) (for each event loop called at event creation).
         * Might require a hash if we have lots of events.
@@ -108,16 +122,27 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name,
                goto error;
        strcpy(event->name, name);
        event->chan = chan;
+       event->probe = probe;
        event->filter = filter;
-       event->id = atomic_inc_return(&chan->free_event_id) - 1;
-       /* TODO register to tracepoint */
+       event->id = chan->free_event_id++;
+       event->itype = itype;
        mutex_unlock(&sessions_mutex);
+       /* Populate ltt_event structure before tracepoint registration. */
+       smp_wmb();
+       switch (itype) {
+       case INSTRUM_TRACEPOINTS:
+               ret = tracepoint_probe_register(name, probe, event);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+       }
        return event;
 
 error:
        kmem_cache_free(event);
 cache_error:
 exist:
+full:
        mutex_unlock(&sessions_mutex);
        return NULL;
 }
@@ -127,7 +152,13 @@ exist:
  */
 int _ltt_event_destroy(struct ltt_event *event)
 {
-       /* TODO unregister from tracepoint */
+       switch (event->itype) {
+       case INSTRUM_TRACEPOINTS:
+               ret = tracepoint_probe_unregister(name, event->probe, event);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+       }
        kfree(event->name);
        kmem_cache_free(event);
 }
@@ -139,10 +170,23 @@ static int __init ltt_events_init(void)
        events_cache = KMEM_CACHE(ltt_event, 0);
        if (!events_cache)
                return -ENOMEM;
+
+       /* TODO: show ABI to userspace */
+
        return 0;
 }
 
 static void __exit ltt_events_exit(void)
 {
+       struct ltt_session *session, *tmpsession;
+
+       /* TODO: hide ABI from userspace, wait for callers to release refs. */
+
+       list_for_each_entry_safe(session, tmpsession, &sessions, list)
+               ltt_session_destroy(session);
        kmem_cache_destroy(events_cache);
 }
+
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
+MODULE_DESCRIPTION("LTTng Events");
This page took 0.043382 seconds and 5 git commands to generate.