Fix: sessiond: inverted condition checking for empty hash table
[lttng-tools.git] / src / bin / lttng-sessiond / session.cpp
index 0d19042b594f8edfda6817a866cf6931378a8b4b..3dc8065569d2dfd850e7949912bc9e4dece9b3da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 EfficiOS Inc.
  *
  * SPDX-License-Identifier: GPL-2.0-only
  *
 #include <sys/types.h>
 #include <pthread.h>
 
-#include <common/common.h>
-#include <common/utils.h>
-#include <common/trace-chunk.h>
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <lttng/location-internal.h>
-#include "lttng-sessiond.h"
-#include "kernel.h"
+#include <common/common.hpp>
+#include <common/utils.hpp>
+#include <common/trace-chunk.hpp>
+#include <common/sessiond-comm/sessiond-comm.hpp>
+#include <lttng/location-internal.hpp>
+#include "lttng-sessiond.hpp"
+#include "kernel.hpp"
 
-#include "session.h"
-#include "utils.h"
-#include "trace-ust.h"
-#include "timer.h"
-#include "cmd.h"
+#include "session.hpp"
+#include "utils.hpp"
+#include "trace-ust.hpp"
+#include "timer.hpp"
+#include "cmd.hpp"
 
 struct ltt_session_destroy_notifier_element {
        ltt_session_destroy_notifier notifier;
@@ -331,12 +331,12 @@ end:
 static void ltt_sessions_ht_destroy(void)
 {
        if (ltt_sessions_ht_by_id) {
-               ht_cleanup_push(ltt_sessions_ht_by_id);
+               lttng_ht_destroy(ltt_sessions_ht_by_id);
                ltt_sessions_ht_by_id = NULL;
        }
 
        if (ltt_sessions_ht_by_name) {
-               ht_cleanup_push(ltt_sessions_ht_by_name);
+               lttng_ht_destroy(ltt_sessions_ht_by_name);
                ltt_sessions_ht_by_name = NULL;
        }
 
@@ -377,28 +377,49 @@ end:
 
 /*
  * Test if ltt_sessions_ht_by_id/name are empty.
- * Return 1 if empty, 0 if not empty.
+ * Return `false` if hash table objects are null.
  * The session list lock must be held.
  */
-static int ltt_sessions_ht_empty(void)
+static bool ltt_sessions_ht_empty(void)
 {
-       unsigned long count;
+       bool empty = false;
 
        if (!ltt_sessions_ht_by_id) {
-               count = 0;
+               /* The hash tables do not exist yet. */
                goto end;
        }
 
        LTTNG_ASSERT(ltt_sessions_ht_by_name);
 
-       count = lttng_ht_get_count(ltt_sessions_ht_by_id);
-       LTTNG_ASSERT(count == lttng_ht_get_count(ltt_sessions_ht_by_name));
+       if (lttng_ht_get_count(ltt_sessions_ht_by_id) != 0) {
+               /* Not empty.*/
+               goto end;
+       }
+
+       /*
+        * At this point it is expected that the `ltt_sessions_ht_by_name` ht is
+        * empty.
+        *
+        * The removal from both hash tables is done in two different
+        * places:
+        *   - removal from `ltt_sessions_ht_by_name` is done during
+        *     `session_destroy()`
+        *   - removal from `ltt_sessions_ht_by_id` is done later
+        *     in `session_release()` on the last reference put.
+        *
+        * This means that it is possible for `ltt_sessions_ht_by_name` to be
+        * empty but for `ltt_sessions_ht_by_id` to still contain objects when
+        * multiple sessions exists. The reverse is false, hence this sanity
+        * check.
+        */
+       LTTNG_ASSERT(lttng_ht_get_count(ltt_sessions_ht_by_name) == 0);
+       empty = true;
 end:
-       return count ? 0 : 1;
+       return empty;
 }
 
 /*
- * Remove a ltt_session from the ltt_sessions_ht_by_id/name.
+ * Remove a ltt_session from the ltt_sessions_ht_by_id.
  * If empty, the ltt_sessions_ht_by_id/name HTs are freed.
  * The session list lock must be held.
  */
@@ -415,10 +436,6 @@ static void del_session_ht(struct ltt_session *ls)
        ret = lttng_ht_del(ltt_sessions_ht_by_id, &iter);
        LTTNG_ASSERT(!ret);
 
-       iter.iter.node = &ls->node_by_name.node;
-       ret = lttng_ht_del(ltt_sessions_ht_by_name, &iter);
-       LTTNG_ASSERT(!ret);
-
        if (ltt_sessions_ht_empty()) {
                DBG("Empty ltt_sessions_ht_by_id/name, destroying hast tables");
                ltt_sessions_ht_destroy();
@@ -1065,8 +1082,23 @@ void session_put(struct ltt_session *session)
  */
 void session_destroy(struct ltt_session *session)
 {
+       int ret;
+       struct lttng_ht_iter iter;
+
        LTTNG_ASSERT(!session->destroyed);
        session->destroyed = true;
+
+       /*
+        * Remove immediately from the "session by name" hash table. Only one
+        * session is expected to exist with a given name for at any given time.
+        *
+        * Even if a session still technically exists for a little while longer,
+        * there is no point in performing action on a "destroyed" session.
+        */
+       iter.iter.node = &session->node_by_name.node;
+       ret = lttng_ht_del(ltt_sessions_ht_by_name, &iter);
+       LTTNG_ASSERT(!ret);
+
        session_put(session);
 }
 
@@ -1132,6 +1164,7 @@ struct ltt_session *session_find_by_id(uint64_t id)
        struct lttng_ht_iter iter;
        struct ltt_session *ls;
 
+       ASSERT_RCU_READ_LOCKED();
        ASSERT_LOCKED(ltt_session_list.lock);
 
        if (!ltt_sessions_ht_by_id) {
@@ -1175,7 +1208,7 @@ enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
                        goto error;
                }
        }
-       new_session = (ltt_session *) zmalloc(sizeof(struct ltt_session));
+       new_session = zmalloc<ltt_session>();
        if (!new_session) {
                PERROR("Failed to allocate an ltt_session structure");
                ret_code = LTTNG_ERR_NOMEM;
This page took 0.026255 seconds and 4 git commands to generate.