misc-unused-using-decls,
misc-use-anonymous-namespace,
modernize-avoid-bind,
- modernize-concat-nested-namespaces,
modernize-loop-convert,
modernize-make-shared,
modernize-make-unique,
/.clangd/
compile_commands.json
*_flymake*
+/.vscode/settings.json
# m4 macros not automatically generated
/m4/libtool.m4
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
/* 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;
}
fp = fopen(file_path, mode);
if (fp == nullptr) {
+ PWARN("Failed to open configuration file '%s'", file_path);
goto error;
}
fp = open_config(path, "w+");
if (fp == nullptr) {
- ERR("Unable to create config file");
ret = -1;
goto error;
}
time.cpp \
tracker.cpp tracker.hpp \
trigger.cpp \
+ type-traits.hpp \
unix.cpp unix.hpp \
uri.cpp uri.hpp \
userspace-probe.cpp \
# 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
} 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))
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.
_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);
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
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))
def get_consumerd_pid(tap, parent, match_string):
- pid = 0
+ pid = None
try:
process = subprocess.Popen(
["pgrep", "-P", str(parent), "-f", match_string],
)
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
)
)
- 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(
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:
+ # 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:
- # 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
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(
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)
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
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
_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()