tests: Make test_per_application_leaks more robust master
authorKienan Stewart <kstewart@efficios.com>
Wed, 22 May 2024 14:45:08 +0000 (10:45 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 24 May 2024 15:29:29 +0000 (11:29 -0400)
Observed issue
==============

On some systems (e.g. sles15sp4, RHEL 7), test_per_application_leaks
would fail spuriously.

Cause
=====

When walking the the FDs in `/proc/XX/fds`, the symbolic links exist but
link to unlinked files. E.g.

```
lrwx------ 1 root root 64 May 22 14:49 /proc/83578/fd/58 -> '/dev/shm/shm-ust-consumer-83578 (deleted)'
```

Solution
========

The test has been modified to loop, waiting for the post-destroy shm
count to drop back to the post-start count. In the case of a failure,
the test will hang forever but doesn't fail spuriously.

Known drawbacks
===============

None.

Change-Id: Id3c8a9f6db83fe888e79b8f06cb8308b4d90da87
Signed-off-by: Kienan Stewart <kstewart@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
22 files changed:
.clang-format
.clang-tidy
.gitignore
doc/man/lttng-sessiond.8.txt
src/bin/lttng-relayd/sessiond-trace-chunks.cpp
src/bin/lttng-sessiond/ust-app.cpp
src/bin/lttng/commands/create.cpp
src/bin/lttng/conf.cpp
src/common/Makefile.am
src/common/consumer/consumer.hpp
src/common/error.hpp
src/common/event-rule/kernel-syscall.cpp
src/common/string-utils/c-string-view.hpp [new file with mode: 0644]
src/common/type-traits.hpp [new file with mode: 0644]
tests/regression/tools/live/test_per_application_leaks.py
tests/regression/tools/snapshots/ust_test
tests/utils/utils.sh
tests/utils/xml-utils/Makefile.am
tests/utils/xml-utils/common.hpp [new file with mode: 0644]
tests/utils/xml-utils/extract_xml.cpp
tests/utils/xml-utils/pretty_xml.c [deleted file]
tests/utils/xml-utils/pretty_xml.cpp [new file with mode: 0644]

index 28ea69873145dcb40b167d659a3b828b8968e9b8..8fcee64f873254026f520850185a7b610cb5a1c8 100644 (file)
@@ -35,7 +35,6 @@ BraceWrapping:
   SplitEmptyFunction: true
 BreakBeforeBinaryOperators: None
 BreakBeforeTernaryOperators: false
   SplitEmptyFunction: true
 BreakBeforeBinaryOperators: None
 BreakBeforeTernaryOperators: false
-BreakConstructorInitializers: AfterColon
 BreakStringLiterals: false
 ColumnLimit: 100
 ConstructorInitializerAllOnOneLineOrOnePerLine: true
 BreakStringLiterals: false
 ColumnLimit: 100
 ConstructorInitializerAllOnOneLineOrOnePerLine: true
index 5b6f3705b05298d17d9cd3a4ec1967c2b3cd4217..d2a18789e9580a9e0106d5007ada189118171db8 100644 (file)
@@ -70,7 +70,6 @@ Checks:          '-*,
                   misc-unused-using-decls,
                   misc-use-anonymous-namespace,
                   modernize-avoid-bind,
                   misc-unused-using-decls,
                   misc-use-anonymous-namespace,
                   modernize-avoid-bind,
-                  modernize-concat-nested-namespaces,
                   modernize-loop-convert,
                   modernize-make-shared,
                   modernize-make-unique,
                   modernize-loop-convert,
                   modernize-make-shared,
                   modernize-make-unique,
index b0884eb16f858d8d970b3ba478048fc3b1b97e31..66e76696f08c12e4aaca56a965f03a90a23d042e 100644 (file)
@@ -47,6 +47,7 @@ TAGS
 /.clangd/
 compile_commands.json
 *_flymake*
 /.clangd/
 compile_commands.json
 *_flymake*
+/.vscode/settings.json
 
 # m4 macros not automatically generated
 /m4/libtool.m4
 
 # m4 macros not automatically generated
 /m4/libtool.m4
index 2bfce1c3744571fad962b1e9a083d75478509b0a..57b05ecc09522429b72a5a77ecd60b181afc4e14 100644 (file)
@@ -232,7 +232,7 @@ See also the `LTTNG_CONSUMERD64_LIBDIR` environment variable.
 option:--consumerd64-path='PATH'::
     Set the 64-bit consumer daemon binary path to 'PATH'.
 +
 option:--consumerd64-path='PATH'::
     Set the 64-bit consumer daemon binary path to 'PATH'.
 +
-See also the `LTTNG_CONSUMERD32_BIN` environment variable.
+See also the `LTTNG_CONSUMERD64_BIN` environment variable.
 
 option:--kconsumerd-cmd-sock='PATH'::
     Set the command Unix socket path of the Linux kernel consumer daemon
 
 option:--kconsumerd-cmd-sock='PATH'::
     Set the command Unix socket path of the Linux kernel consumer daemon
index 9d793c9bcf79315e722447fcb3c205f785a60c54..2326878fb9fd6a9dd2f9d6dfd8dc8dd4504243f1 100644 (file)
@@ -78,8 +78,8 @@ struct trace_chunk_registry_ht_element {
 
 static unsigned long trace_chunk_registry_ht_key_hash(const struct trace_chunk_registry_ht_key *key)
 {
 
 static unsigned long trace_chunk_registry_ht_key_hash(const struct trace_chunk_registry_ht_key *key)
 {
-       const uint64_t uuid_h1 = *reinterpret_cast<const uint64_t *>(&key->sessiond_uuid[0]);
-       const uint64_t uuid_h2 = *reinterpret_cast<const uint64_t *>(&key->sessiond_uuid[1]);
+       const uint64_t uuid_h1 = reinterpret_cast<const uint64_t *>(key->sessiond_uuid.data())[0];
+       const uint64_t uuid_h2 = reinterpret_cast<const uint64_t *>(key->sessiond_uuid.data())[1];
 
        return hash_key_u64(&uuid_h1, lttng_ht_seed) ^ hash_key_u64(&uuid_h2, lttng_ht_seed);
 }
 
        return hash_key_u64(&uuid_h1, lttng_ht_seed) ^ hash_key_u64(&uuid_h2, lttng_ht_seed);
 }
index 12250edfdaefb1341736ba5b78c62a53ceba1c8e..d993b7b4439059f2448940f7b3130a2e638e3954 100644 (file)
@@ -6025,8 +6025,8 @@ static void ust_app_synchronize_event_notifier_rules(struct ust_app *app)
        }
 
        for (i = 0; i < count; i++) {
        }
 
        for (i = 0; i < count; i++) {
-               struct lttng_condition *condition;
-               struct lttng_event_rule *event_rule;
+               const struct lttng_condition *condition;
+               const struct lttng_event_rule *event_rule;
                struct lttng_trigger *trigger;
                const struct ust_app_event_notifier_rule *looked_up_event_notifier_rule;
                enum lttng_condition_status condition_status;
                struct lttng_trigger *trigger;
                const struct ust_app_event_notifier_rule *looked_up_event_notifier_rule;
                enum lttng_condition_status condition_status;
@@ -6036,7 +6036,7 @@ static void ust_app_synchronize_event_notifier_rules(struct ust_app *app)
                LTTNG_ASSERT(trigger);
 
                token = lttng_trigger_get_tracer_token(trigger);
                LTTNG_ASSERT(trigger);
 
                token = lttng_trigger_get_tracer_token(trigger);
-               condition = lttng_trigger_get_condition(trigger);
+               condition = lttng_trigger_get_const_condition(trigger);
 
                if (lttng_condition_get_type(condition) !=
                    LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES) {
 
                if (lttng_condition_get_type(condition) !=
                    LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES) {
@@ -6044,8 +6044,8 @@ static void ust_app_synchronize_event_notifier_rules(struct ust_app *app)
                        continue;
                }
 
                        continue;
                }
 
-               condition_status = lttng_condition_event_rule_matches_borrow_rule_mutable(
-                       condition, &event_rule);
+               condition_status =
+                       lttng_condition_event_rule_matches_get_rule(condition, &event_rule);
                LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
 
                if (lttng_event_rule_get_domain_type(event_rule) == LTTNG_DOMAIN_KERNEL) {
                LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
 
                if (lttng_event_rule_get_domain_type(event_rule) == LTTNG_DOMAIN_KERNEL) {
index dce13866f6dea7d2948149de093e49af65935bde..e1756c3d30a30c4449a641e5548391f58da9413e 100644 (file)
@@ -479,7 +479,8 @@ static int create_session(const char *session_name)
        /* Init lttng session config */
        ret = config_init(created_session_name);
        if (ret < 0) {
        /* Init lttng session config */
        ret = config_init(created_session_name);
        if (ret < 0) {
-               ret = CMD_ERROR;
+               MSG("Unable to initialize configuration for created session: future commands will require the target session name explicitly");
+               ret = CMD_WARNING;
                goto error;
        }
 
                goto error;
        }
 
index 65be35a158f70518dda1317f78900347ba67b117..81aa654384c97bbccf0360be39d91a2e7326f230 100644 (file)
@@ -54,6 +54,7 @@ static FILE *open_config(const char *path, const char *mode)
 
        fp = fopen(file_path, mode);
        if (fp == nullptr) {
 
        fp = fopen(file_path, mode);
        if (fp == nullptr) {
+               PWARN("Failed to open configuration file '%s'", file_path);
                goto error;
        }
 
                goto error;
        }
 
@@ -74,7 +75,6 @@ static int create_config_file(const char *path)
 
        fp = open_config(path, "w+");
        if (fp == nullptr) {
 
        fp = open_config(path, "w+");
        if (fp == nullptr) {
-               ERR("Unable to create config file");
                ret = -1;
                goto error;
        }
                ret = -1;
                goto error;
        }
index 34fd83452802f5b8caa21a347ce4264e693f1e88..8170e6e5add57dc5c66e459b9612e2bbbb2a2c4a 100644 (file)
@@ -115,6 +115,7 @@ libcommon_lgpl_la_SOURCES = \
        time.cpp \
        tracker.cpp tracker.hpp \
        trigger.cpp \
        time.cpp \
        tracker.cpp tracker.hpp \
        trigger.cpp \
+       type-traits.hpp \
        unix.cpp unix.hpp \
        uri.cpp uri.hpp \
        userspace-probe.cpp \
        unix.cpp unix.hpp \
        uri.cpp uri.hpp \
        userspace-probe.cpp \
@@ -432,6 +433,7 @@ endif
 # libstring-utils
 noinst_LTLIBRARIES += libstring-utils.la
 libstring_utils_la_SOURCES = \
 # libstring-utils
 noinst_LTLIBRARIES += libstring-utils.la
 libstring_utils_la_SOURCES = \
+       string-utils/c-string-view.hpp \
        string-utils/format.hpp \
        string-utils/string-utils.cpp \
        string-utils/string-utils.hpp
        string-utils/format.hpp \
        string-utils/string-utils.cpp \
        string-utils/string-utils.hpp
index 310969172d73f656a258d038cfdb1c0c55c9441f..851b3e2b8137eaef4d5904b19deb81a3f9921bdf 100644 (file)
@@ -922,7 +922,7 @@ void lttng_consumer_set_command_sock_path(struct lttng_consumer_local_data *ctx,
  * on error.
  */
 int lttng_consumer_send_error(struct lttng_consumer_local_data *ctx,
  * on error.
  */
 int lttng_consumer_send_error(struct lttng_consumer_local_data *ctx,
-               enum lttcomm_return_code error_code);
+                             enum lttcomm_return_code error_code);
 
 /*
  * Called from signal handler to ensure a clean exit.
 
 /*
  * Called from signal handler to ensure a clean exit.
index 23d840c2daafcd3870ba4445708921c1ea3b93ad..66f38bf2eca36e7e9356d9eb3fb837e6db4873bb 100644 (file)
@@ -226,6 +226,7 @@ static inline void __lttng_print_check_abort(enum lttng_error_level type)
        } while (0);
 
 #define _PERROR(fmt, args...) _ERRMSG("PERROR", PRINT_ERR, fmt, ##args)
        } while (0);
 
 #define _PERROR(fmt, args...) _ERRMSG("PERROR", PRINT_ERR, fmt, ##args)
+#define _PWARN(fmt, args...)  _ERRMSG("PWARN", PRINT_WARN, fmt, ##args)
 
 #if !defined(__GLIBC__) || \
        ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE))
 
 #if !defined(__GLIBC__) || \
        ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE))
@@ -239,6 +240,13 @@ static inline void __lttng_print_check_abort(enum lttng_error_level type)
                strerror_r(errno, _perror_buf, sizeof(_perror_buf)); \
                _PERROR(call ": %s", ##args, _perror_buf);           \
        } while (0);
                strerror_r(errno, _perror_buf, sizeof(_perror_buf)); \
                _PERROR(call ": %s", ##args, _perror_buf);           \
        } while (0);
+
+#define PWARN(call, args...)                                         \
+       do {                                                         \
+               char _perror_buf[200];                               \
+               strerror_r(errno, _perror_buf, sizeof(_perror_buf)); \
+               _PWARN(call ": %s", ##args, _perror_buf);            \
+       } while (0);
 #else
 /*
  * Version using GNU strerror_r, for linux with appropriate defines.
 #else
 /*
  * Version using GNU strerror_r, for linux with appropriate defines.
@@ -250,6 +258,13 @@ static inline void __lttng_print_check_abort(enum lttng_error_level type)
                _perror_buf = strerror_r(errno, _perror_tmp, sizeof(_perror_tmp)); \
                _PERROR(call ": %s", ##args, _perror_buf);                         \
        } while (0);
                _perror_buf = strerror_r(errno, _perror_tmp, sizeof(_perror_tmp)); \
                _PERROR(call ": %s", ##args, _perror_buf);                         \
        } while (0);
+#define PWARN(call, args...)                                                       \
+       do {                                                                       \
+               char *_perror_buf;                                                 \
+               char _perror_tmp[200];                                             \
+               _perror_buf = strerror_r(errno, _perror_tmp, sizeof(_perror_tmp)); \
+               _PWARN(call ": %s", ##args, _perror_buf);                          \
+       } while (0);
 #endif
 
 const char *error_get_str(int32_t code);
 #endif
 
 const char *error_get_str(int32_t code);
index 23a432aacaaff285e6f0e3cb735d8cb1b4b3f26a..933c3543fcc155d5e74e3310089397155d9d4a76 100644 (file)
@@ -133,6 +133,10 @@ static bool lttng_event_rule_kernel_syscall_is_equal(const struct lttng_event_ru
                goto end;
        }
 
                goto end;
        }
 
+       if (a->emission_site != b->emission_site) {
+               goto end;
+       }
+
        is_equal = true;
 end:
        return is_equal;
        is_equal = true;
 end:
        return is_equal;
diff --git a/src/common/string-utils/c-string-view.hpp b/src/common/string-utils/c-string-view.hpp
new file mode 100644 (file)
index 0000000..6b175ea
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2023 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef LTTNG_C_STRING_VIEW_HPP
+#define LTTNG_C_STRING_VIEW_HPP
+
+#include <common/format.hpp>
+#include <common/type-traits.hpp>
+
+#include <cstddef>
+#include <cstring>
+#include <functional>
+#include <string>
+
+namespace lttng {
+
+/*
+ * A view on a constant null-terminated C string.
+ */
+class c_string_view final {
+public:
+       /*
+        * Builds an empty view (data() returns `nullptr`).
+        *
+        * Intentionally not explicit.
+        */
+       constexpr c_string_view() noexcept = default;
+
+       /*
+        * Builds a view of the C string `str` (may be `nullptr`).
+        *
+        * Intentionally not explicit.
+        */
+       /* NOLINTBEGIN(google-explicit-constructor) */
+       constexpr c_string_view(const char *const str) noexcept : _str{ str }
+       {
+       }
+       /* NOLINTEND(google-explicit-constructor) */
+
+       /*
+        * Builds a view of the string `str`.
+        */
+       /* NOLINTBEGIN(google-explicit-constructor) */
+       c_string_view(const std::string& str) noexcept : _str{ str.c_str() }
+       {
+       }
+       /* NOLINTEND */
+
+       /*
+        * Makes this view view the C string `str` (may be `nullptr`).
+        */
+       c_string_view& operator=(const char *const str) noexcept
+       {
+               _str = str;
+               return *this;
+       }
+
+       /*
+        * Viewed null-terminated C string (may be `nullptr`).
+        */
+       const char *data() const noexcept
+       {
+               return _str;
+       }
+
+       /*
+        * Alias of data().
+        */
+       operator const char *() const noexcept /* NOLINT(google-explicit-constructor) */
+       {
+               return this->data();
+       }
+
+       /*
+        * Evaluate as boolean (false means an empty string).
+        */
+       operator bool() const noexcept /* NOLINT(google-explicit-constructor) */
+       {
+               return *this->data();
+       }
+
+       /*
+        * Alias of data().
+        */
+       const char *operator*() const noexcept
+       {
+               return this->data();
+       }
+
+       /*
+        * Alias of data().
+        *
+        * data() must not return `nullptr`.
+        */
+       const char *begin() const noexcept
+       {
+               return this->data();
+       }
+
+       /*
+        * Pointer to the null character of the viewed C string.
+        *
+        * data() must not return `nullptr`.
+        */
+       const char *end() const noexcept
+       {
+               return _str + this->len();
+       }
+
+       /*
+        * Length of the viewed C string, excluding the null character.
+        *
+        * data() must not return `nullptr`.
+        */
+       std::size_t len() const noexcept
+       {
+               return std::strlen(_str);
+       }
+
+       /*
+        * Returns an `std::string` instance containing a copy of the viewed
+        * C string.
+        *
+        * data() must not return `nullptr`.
+        */
+       std::string str() const
+       {
+               return std::string{ _str };
+       }
+
+       /*
+        * Alias of str().
+        */
+       operator std::string() const /* NOLINT(google-explicit-constructor) */
+       {
+               return this->str();
+       }
+
+       /*
+        * Returns the character at index `i`.
+        *
+        * `i` must be less than what len() returns.
+        *
+        * data() must not return `nullptr`.
+        */
+       char operator[](const std::size_t i) const noexcept
+       {
+               return _str[i];
+       }
+
+       bool startsWith(const lttng::c_string_view prefix) const noexcept
+       {
+               return std::strncmp(_str, (const char *) prefix, prefix.len()) == 0;
+       }
+
+private:
+       const char *_str = nullptr;
+};
+
+inline const char *format_as(const c_string_view& str)
+{
+       return str ? *str : "(null)";
+}
+
+namespace internal {
+
+template <typename StrT>
+const char *as_const_char_ptr(StrT&& val) noexcept
+{
+       return val.data();
+}
+
+inline const char *as_const_char_ptr(const char *const val) noexcept
+{
+       return val;
+}
+
+template <typename StrT>
+using comparable_with_c_string_view = lttng::traits::
+       is_one_of<typename std::decay<StrT>::type, c_string_view, std::string, const char *>;
+
+} /* namespace internal */
+
+/*
+ * Returns true if `lhs` is equal to `rhs`.
+ *
+ * `LhsT` and `RhsT` may be any of:
+ *
+ * • `const char *`
+ * • `std::string`
+ * • `c_string_view`
+ *
+ * Both `lhs` and `rhs` must not have an underlying `nullptr` raw data.
+ */
+template <
+       typename LhsT,
+       typename RhsT,
+       typename =
+               typename std::enable_if<internal::comparable_with_c_string_view<LhsT>::value>::type,
+       typename =
+               typename std::enable_if<internal::comparable_with_c_string_view<RhsT>::value>::type>
+bool operator==(LhsT&& lhs, RhsT&& rhs) noexcept
+{
+       const auto raw_lhs = internal::as_const_char_ptr(lhs);
+       const auto raw_rhs = internal::as_const_char_ptr(rhs);
+
+       return std::strcmp(raw_lhs, raw_rhs) == 0;
+}
+
+/*
+ * Returns true if `lhs` is not equal to `rhs`.
+ *
+ * `LhsT` and `RhsT` may be any of:
+ *
+ * • `const char *`
+ * • `std::string`
+ * • `c_string_view`
+ *
+ * Both `lhs` and `rhs` must not have an underlying `nullptr` raw data.
+ */
+template <
+       typename LhsT,
+       typename RhsT,
+       typename =
+               typename std::enable_if<internal::comparable_with_c_string_view<LhsT>::value>::type,
+       typename =
+               typename std::enable_if<internal::comparable_with_c_string_view<RhsT>::value>::type>
+bool operator!=(LhsT&& lhs, RhsT&& rhs) noexcept
+{
+       return !(std::forward<LhsT>(lhs) == std::forward<RhsT>(rhs));
+}
+
+} /* namespace lttng */
+
+/*
+ * Appends `rhs` to `lhs`.
+ */
+inline void operator+=(std::string& lhs, lttng::c_string_view rhs)
+{
+       lhs += rhs.data();
+}
+
+namespace std {
+template <>
+struct hash<lttng::c_string_view> {
+       std::size_t operator()(const lttng::c_string_view& str) const
+       {
+               auto hash_value = std::hash<char>{}('\0');
+
+               for (auto character : str) {
+                       hash_value ^= std::hash<decltype(character)>{}(character);
+               }
+
+               return hash_value;
+       }
+};
+} /* namespace std */
+
+#endif /* LTTNG_C_STRING_VIEW_HPP */
diff --git a/src/common/type-traits.hpp b/src/common/type-traits.hpp
new file mode 100644 (file)
index 0000000..3801bf1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef LTTNG_TYPE_TRAITS_HPP
+#define LTTNG_TYPE_TRAITS_HPP
+
+#include <type_traits>
+
+namespace lttng {
+namespace traits {
+
+/*
+ * Provides the member constant `value` equal to:
+ *
+ * `T` is in the list of types `Ts`:
+ *     `true`
+ *
+ * Otherwise:
+ *     `false`
+ */
+template <typename T, typename... Ts>
+struct is_one_of : std::false_type {
+};
+
+template <typename T, typename... Ts>
+struct is_one_of<T, T, Ts...> : std::true_type {
+};
+
+template <typename T, typename U, typename... Ts>
+struct is_one_of<T, U, Ts...> : is_one_of<T, Ts...> {
+};
+} /* namespace traits */
+} /* namespace lttng */
+
+#endif /* LTTNG_TYPE_TRAITS_HPP */
index 1d12049ed544ccaaca332d7e76d76ce222c8bd59..60267810c417ca0334abf2c0a01658ef80d3e9d5 100755 (executable)
@@ -14,6 +14,7 @@ import os
 import pathlib
 import subprocess
 import sys
 import pathlib
 import subprocess
 import sys
+import time
 
 test_utils_import_path = pathlib.Path(__file__).absolute().parents[3] / "utils"
 sys.path.append(str(test_utils_import_path))
 
 test_utils_import_path = pathlib.Path(__file__).absolute().parents[3] / "utils"
 sys.path.append(str(test_utils_import_path))
@@ -22,7 +23,7 @@ import lttngtest
 
 
 def get_consumerd_pid(tap, parent, match_string):
 
 
 def get_consumerd_pid(tap, parent, match_string):
-    pid = 0
+    pid = None
     try:
         process = subprocess.Popen(
             ["pgrep", "-P", str(parent), "-f", match_string],
     try:
         process = subprocess.Popen(
             ["pgrep", "-P", str(parent), "-f", match_string],
@@ -30,13 +31,14 @@ def get_consumerd_pid(tap, parent, match_string):
         )
         process.wait()
         output = str(process.stdout.read(), encoding="UTF-8").splitlines()
         )
         process.wait()
         output = str(process.stdout.read(), encoding="UTF-8").splitlines()
-        if len(output) != 1:
+        if len(output) > 1:
             raise Exception(
                 "Unexpected number of output lines (got {}): {}".format(
                     len(output), output
                 )
             )
             raise Exception(
                 "Unexpected number of output lines (got {}): {}".format(
                     len(output), output
                 )
             )
-        pid = int(output[0])
+        elif len(output) == 1:
+            pid = int(output[0])
     except Exception as e:
         tap.diagnostic(
             "Failed to find child process of '{}' matching '{}': '{}'".format(
     except Exception as e:
         tap.diagnostic(
             "Failed to find child process of '{}' matching '{}': '{}'".format(
@@ -48,19 +50,23 @@ def get_consumerd_pid(tap, parent, match_string):
 
 def count_process_dev_shm_fds(pid):
     count = 0
 
 def count_process_dev_shm_fds(pid):
     count = 0
-    if pid == 0:
+    if pid is None:
         return count
     dir = os.path.join("/proc", str(pid), "fd")
     for root, dirs, files in os.walk(dir):
         for f in files:
             filename = pathlib.Path(os.path.join(root, f))
             try:
         return count
     dir = os.path.join("/proc", str(pid), "fd")
     for root, dirs, files in os.walk(dir):
         for f in files:
             filename = pathlib.Path(os.path.join(root, f))
             try:
+                # The symlink in /proc/PID may exist, but point to an unlinked
+                # file - shm_unlink is called but either the kernel hasn't yet
+                # finished the clean-up or the consumer hasn't called close()
+                # on the FD yet.
                 if filename.is_symlink() and str(filename.resolve()).startswith(
                     "/dev/shm/shm-ust-consumer"
                 ):
                     count += 1
             except FileNotFoundError:
                 if filename.is_symlink() and str(filename.resolve()).startswith(
                     "/dev/shm/shm-ust-consumer"
                 ):
                     count += 1
             except FileNotFoundError:
-                # As we're walking /proc/XX/fd/, fds may be added or removed
+                # As /proc/XX/fd/ is being walked, fds may be added or removed
                 continue
     return count
 
                 continue
     return count
 
@@ -112,7 +118,18 @@ def test_fd_leak(tap, test_env, buffer_sharing_policy, kill_relayd=True):
     session.stop()
     session.destroy()
 
     session.stop()
     session.destroy()
 
-    count_post_destroy = count_dev_shm_fds(tap, test_env)
+    # As there is not method to know exactly when the final close of the
+    # shm happens (it is timing dependant from an external point of view),
+    # this test iterates waiting for the post-destroy count to reach the
+    # post-start count. In a failure, this will loop infinitely.
+    tap.diagnostic(
+        "Waiting for post-destroy shm count to drop back to post-start level"
+    )
+    while True:
+        count_post_destroy = count_dev_shm_fds(tap, test_env)
+        if count_post_destroy == count_post_start:
+            break
+        time.sleep(0.1)
 
     tap.diagnostic(
         "FD counts post-start: {}, post-destroy: {}".format(
 
     tap.diagnostic(
         "FD counts post-start: {}, post-destroy: {}".format(
index 5188c2b5b21215c58adec2bc88a52f4aa98f0f39..e495498045d19c9d54de4131b069ae6cbe081ad0 100755 (executable)
@@ -16,7 +16,7 @@ TESTAPP_NAME="gen-ust-events"
 TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
 APPS_PID=()
 
 TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
 APPS_PID=()
 
-NUM_TESTS=104
+NUM_TESTS=106
 
 TRACE_PATH=$(mktemp -d -t tmp.test_snapshots_ust_trace_path.XXXXXX)
 
 
 TRACE_PATH=$(mktemp -d -t tmp.test_snapshots_ust_trace_path.XXXXXX)
 
@@ -209,7 +209,8 @@ function test_ust_local_snapshot_small_discard_buffers ()
        OLDCPUSET=$(taskset -p $$)
 
        diag "Test local UST snapshots with small discard buffers"
        OLDCPUSET=$(taskset -p $$)
 
        diag "Test local UST snapshots with small discard buffers"
-       taskset -c "$(get_any_available_cpu)" -p $$ 1>/dev/null 2>&1
+       taskset -cp "$(get_any_available_cpu)" $$ 1>/dev/null 2>&1
+       ok $? "Set current process CPU affinity"
        create_lttng_session_no_output "$SESSION_NAME"
        enable_mmap_small_discard_ust_channel "$SESSION_NAME" $CHANNEL_NAME
        enable_ust_lttng_event_ok "$SESSION_NAME" $EVENT_NAME $CHANNEL_NAME
        create_lttng_session_no_output "$SESSION_NAME"
        enable_mmap_small_discard_ust_channel "$SESSION_NAME" $CHANNEL_NAME
        enable_ust_lttng_event_ok "$SESSION_NAME" $EVENT_NAME $CHANNEL_NAME
@@ -254,7 +255,8 @@ function test_ust_local_snapshot_small_overwrite_buffers ()
        OLDCPUSET=$(taskset -p $$)
 
        diag "Test local UST snapshots with small overwrite buffers"
        OLDCPUSET=$(taskset -p $$)
 
        diag "Test local UST snapshots with small overwrite buffers"
-       taskset -p "$(get_any_available_cpu)" $$ 1>/dev/null 2>&1
+       taskset -cp "$(get_any_available_cpu)" $$ 1>/dev/null 2>&1
+       ok $? "Set current process CPU affinity"
        create_lttng_session_no_output "$SESSION_NAME"
        enable_mmap_small_overwrite_ust_channel "$SESSION_NAME" $CHANNEL_NAME
        enable_ust_lttng_event_ok "$SESSION_NAME" $EVENT_NAME $CHANNEL_NAME
        create_lttng_session_no_output "$SESSION_NAME"
        enable_mmap_small_overwrite_ust_channel "$SESSION_NAME" $CHANNEL_NAME
        enable_ust_lttng_event_ok "$SESSION_NAME" $EVENT_NAME $CHANNEL_NAME
index 0e8ec54dd4f102b99424466eafc5275f0ba10092..55c821d60860bf75642bede7b306be283af0f51c 100644 (file)
@@ -1337,7 +1337,7 @@ function enable_lttng_mmap_overwrite_small_kernel_channel()
 
        _run_lttng_cmd "$OUTPUT_DEST" "$ERROR_OUTPUT_DEST" \
                enable-channel -s $sess_name $channel_name -k --output mmap --overwrite --subbuf-size=$(getconf PAGE_SIZE) --num-subbuf=2
 
        _run_lttng_cmd "$OUTPUT_DEST" "$ERROR_OUTPUT_DEST" \
                enable-channel -s $sess_name $channel_name -k --output mmap --overwrite --subbuf-size=$(getconf PAGE_SIZE) --num-subbuf=2
-       ok $? "Enable small discard channel $channel_name for session $sess_name"
+       ok $? "Enable small overwrite channel $channel_name for session $sess_name"
 }
 
 function enable_lttng_mmap_overwrite_ust_channel()
 }
 
 function enable_lttng_mmap_overwrite_ust_channel()
index 7997d94e126369e694114d5b7584d593ba637c8b..5890eef27533c185f1c7033c85b8a0f14f707b3c 100644 (file)
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 # SPDX-License-Identifier: GPL-2.0-only
 
+EXTRA_DIST = common.hpp
+
 noinst_PROGRAMS = validate_xml extract_xml pretty_xml
 validate_xml_SOURCES = validate_xml.cpp
 validate_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 noinst_PROGRAMS = validate_xml extract_xml pretty_xml
 validate_xml_SOURCES = validate_xml.cpp
 validate_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
@@ -9,7 +11,7 @@ extract_xml_SOURCES = extract_xml.cpp
 extract_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 extract_xml_LDADD = $(libxml2_LIBS)
 
 extract_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 extract_xml_LDADD = $(libxml2_LIBS)
 
-pretty_xml_SOURCES = pretty_xml.c
+pretty_xml_SOURCES = pretty_xml.cpp
 pretty_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 pretty_xml_LDADD = $(libxml2_LIBS)
 
 pretty_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
 pretty_xml_LDADD = $(libxml2_LIBS)
 
diff --git a/tests/utils/xml-utils/common.hpp b/tests/utils/xml-utils/common.hpp
new file mode 100644 (file)
index 0000000..01a9b52
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 EfficiOS Inc.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef TESTS_UTILS_XML_UTILS_COMMON_HPP
+#define TESTS_UTILS_XML_UTILS_COMMON_HPP
+
+#include "common/make-unique-wrapper.hpp"
+
+#include <libxml/parser.h>
+#include <memory>
+
+namespace lttng {
+namespace libxml {
+
+using parser_ctx_uptr = std::unique_ptr<
+       xmlParserCtxt,
+       lttng::memory::create_deleter_class<xmlParserCtxt, xmlFreeParserCtxt>::deleter>;
+using doc_uptr =
+       std::unique_ptr<xmlDoc, lttng::memory::create_deleter_class<xmlDoc, xmlFreeDoc>::deleter>;
+
+/*
+ * Manage the global parser context of libxml2.
+ * There should only be one instance of this class per process.
+ */
+class global_parser_context {
+public:
+       global_parser_context()
+       {
+               xmlInitParser();
+       }
+
+       ~global_parser_context()
+       {
+               xmlCleanupParser();
+       }
+
+       /* Deactivate copy and assignment. */
+       global_parser_context(const global_parser_context&) = delete;
+       global_parser_context(global_parser_context&&) = delete;
+       global_parser_context& operator=(const global_parser_context&) = delete;
+       global_parser_context& operator=(global_parser_context&&) = delete;
+};
+} /* namespace libxml */
+} /* namespace lttng */
+#endif /* TESTS_UTILS_XML_UTILS_COMMON_HPP */
index 3995dde48a27d9d96485f148222b883f58f4ef10..280f2ed0284b80736ce92485479c488ce75aad1b 100644 (file)
@@ -24,6 +24,8 @@
  *     node;b;
  *     node;c;
  */
  *     node;b;
  *     node;c;
  */
+#include "common.hpp"
+
 #include <common/defaults.hpp>
 
 #include <libxml/parser.h>
 #include <common/defaults.hpp>
 
 #include <libxml/parser.h>
@@ -36,6 +38,8 @@
 #include <string.h>
 #include <unistd.h>
 
 #include <string.h>
 #include <unistd.h>
 
+namespace ll = lttng::libxml;
+
 #if defined(LIBXML_XPATH_ENABLED)
 
 static int opt_verbose;
 #if defined(LIBXML_XPATH_ENABLED)
 
 static int opt_verbose;
@@ -176,8 +180,15 @@ static int extract_xpath(const char *xml_path, const xmlChar *xpath)
        LTTNG_ASSERT(xml_path);
        LTTNG_ASSERT(xpath);
 
        LTTNG_ASSERT(xml_path);
        LTTNG_ASSERT(xpath);
 
+       ll::parser_ctx_uptr parserCtx{ xmlNewParserCtxt() };
+
+       if (!parserCtx) {
+               fprintf(stderr, "ERR: could not allocate an XML parser context\n");
+               return -1;
+       }
+
        /* Parse the xml file */
        /* Parse the xml file */
-       doc = xmlParseFile(xml_path);
+       doc = xmlCtxtReadFile(parserCtx.get(), xml_path, nullptr, XML_PARSE_NOBLANKS);
        if (!doc) {
                fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path);
                return -1;
        if (!doc) {
                fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path);
                return -1;
@@ -253,7 +264,6 @@ int main(int argc, char **argv)
 
        /* Init libxml */
        xmlInitParser();
 
        /* Init libxml */
        xmlInitParser();
-       xmlKeepBlanksDefault(0);
        if (access(argv[optind], F_OK)) {
                fprintf(stderr, "ERR:%s\n", "Xml path not valid");
                return -1;
        if (access(argv[optind], F_OK)) {
                fprintf(stderr, "ERR:%s\n", "Xml path not valid");
                return -1;
diff --git a/tests/utils/xml-utils/pretty_xml.c b/tests/utils/xml-utils/pretty_xml.c
deleted file mode 100644 (file)
index 3f296f0..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2021 EfficiOS Inc.
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-/*
- * Prettyfi a xml input from stdin to stddout.
- * This allows a more human friendly format for xml testing when problems occur.
- */
-
-#include <libxml/parser.h>
-
-int main(void)
-{
-       xmlDocPtr doc = NULL;
-
-       /* Init libxml. */
-       xmlInitParser();
-       xmlKeepBlanksDefault(0);
-
-       /* Parse the XML document from stdin. */
-       doc = xmlParseFile("-");
-       if (!doc) {
-               fprintf(stderr, "ERR parsing: xml input invalid");
-               return -1;
-       }
-
-       xmlDocFormatDump(stdout, doc, 1);
-
-       xmlFreeDoc(doc);
-       /* Shutdown libxml. */
-       xmlCleanupParser();
-
-       return 0;
-}
diff --git a/tests/utils/xml-utils/pretty_xml.cpp b/tests/utils/xml-utils/pretty_xml.cpp
new file mode 100644 (file)
index 0000000..8a6e967
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 EfficiOS Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+/*
+ * Prettyfi a xml input from stdin to stddout.
+ * This allows a more human friendly format for xml testing when problems occur.
+ */
+
+#include "common.hpp"
+
+#include <common/scope-exit.hpp>
+
+#include <iostream>
+#include <libxml/parser.h>
+#include <unistd.h>
+
+namespace ll = lttng::libxml;
+
+int main()
+{
+       const ll::global_parser_context global_parser_context;
+       const ll::parser_ctx_uptr parserCtx{ xmlNewParserCtxt() };
+
+       /* Parse the XML document from stdin. */
+       const ll::doc_uptr doc{ xmlCtxtReadFd(
+               parserCtx.get(), STDIN_FILENO, nullptr, nullptr, XML_PARSE_NOBLANKS) };
+       if (!doc) {
+               std::cerr << "Error: invalid XML input on stdin\n";
+               return -1;
+       }
+
+       xmlDocFormatDump(stdout, doc.get(), 1);
+
+       return 0;
+}
This page took 0.042387 seconds and 4 git commands to generate.