SoW-2019-0002: Dynamic Snapshot sow-2019-0002-rev1
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Tue, 11 Feb 2020 20:51:52 +0000 (15:51 -0500)
committerJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Sat, 15 Feb 2020 00:09:31 +0000 (19:09 -0500)
Revision 1

266 files changed:
.gitignore
configure.ac
doc/examples/trigger-on-event/README.md [new file with mode: 0644]
doc/examples/trigger-on-event/demo.sh [new file with mode: 0755]
doc/examples/trigger-on-event/instrumented-app.c [new file with mode: 0644]
doc/examples/trigger-on-event/notification-client.c [new file with mode: 0644]
doc/examples/trigger-on-event/tp.c [new file with mode: 0644]
doc/examples/trigger-on-event/tp.h [new file with mode: 0644]
doc/man/Makefile.am
doc/man/lttng-add-trigger.1.txt [new file with mode: 0644]
doc/man/lttng-list-triggers.1.txt [new file with mode: 0644]
doc/man/lttng-remove-trigger.1.txt [new file with mode: 0644]
extras/bindings/swig/python/lttng.i.in
include/Makefile.am
include/lttng/action/action-internal.h
include/lttng/action/action.h
include/lttng/action/group-internal.h [new file with mode: 0644]
include/lttng/action/group.h [new file with mode: 0644]
include/lttng/action/notify-internal.h
include/lttng/action/rotate-session-internal.h [new file with mode: 0644]
include/lttng/action/rotate-session.h [new file with mode: 0644]
include/lttng/action/snapshot-session-internal.h [new file with mode: 0644]
include/lttng/action/snapshot-session.h [new file with mode: 0644]
include/lttng/action/start-session-internal.h [new file with mode: 0644]
include/lttng/action/start-session.h [new file with mode: 0644]
include/lttng/action/stop-session-internal.h [new file with mode: 0644]
include/lttng/action/stop-session.h [new file with mode: 0644]
include/lttng/condition/condition-internal.h
include/lttng/condition/condition.h
include/lttng/condition/event-rule-internal.h [new file with mode: 0644]
include/lttng/condition/event-rule.h [new file with mode: 0644]
include/lttng/domain-internal.h [new file with mode: 0644]
include/lttng/event-internal.h
include/lttng/event-rule/event-rule-internal.h [new file with mode: 0644]
include/lttng/event-rule/event-rule.h [new file with mode: 0644]
include/lttng/event-rule/kprobe-internal.h [new file with mode: 0644]
include/lttng/event-rule/kprobe.h [new file with mode: 0644]
include/lttng/event-rule/kretprobe-internal.h [new file with mode: 0644]
include/lttng/event-rule/kretprobe.h [new file with mode: 0644]
include/lttng/event-rule/syscall-internal.h [new file with mode: 0644]
include/lttng/event-rule/syscall.h [new file with mode: 0644]
include/lttng/event-rule/tracepoint-internal.h [new file with mode: 0644]
include/lttng/event-rule/tracepoint.h [new file with mode: 0644]
include/lttng/event-rule/uprobe-internal.h [new file with mode: 0644]
include/lttng/event-rule/uprobe.h [new file with mode: 0644]
include/lttng/lttng.h
include/lttng/snapshot-internal.h
include/lttng/snapshot.h
include/lttng/trigger/trigger-internal.h
include/lttng/trigger/trigger.h
include/lttng/userspace-probe-internal.h
m4/ax_append_compile_flags.m4 [new file with mode: 0644]
m4/ax_append_flag.m4 [new file with mode: 0644]
m4/ax_check_compile_flag.m4 [new file with mode: 0644]
m4/ax_require_defined.m4 [new file with mode: 0644]
rename.sh [new file with mode: 0644]
src/bin/lttng-crash/lttng-crash.c
src/bin/lttng-relayd/cmd-2-2.c
src/bin/lttng-sessiond/Makefile.am
src/bin/lttng-sessiond/action-executor.c [new file with mode: 0644]
src/bin/lttng-sessiond/action-executor.h [new file with mode: 0644]
src/bin/lttng-sessiond/agent-thread.c
src/bin/lttng-sessiond/agent.c
src/bin/lttng-sessiond/agent.h
src/bin/lttng-sessiond/client.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/dispatch.c
src/bin/lttng-sessiond/event.c
src/bin/lttng-sessiond/event.h
src/bin/lttng-sessiond/globals.c
src/bin/lttng-sessiond/health-sessiond.h
src/bin/lttng-sessiond/kernel.c
src/bin/lttng-sessiond/kernel.h
src/bin/lttng-sessiond/lttng-sessiond.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/modprobe.c
src/bin/lttng-sessiond/notification-thread-commands.c
src/bin/lttng-sessiond/notification-thread-commands.h
src/bin/lttng-sessiond/notification-thread-events.c
src/bin/lttng-sessiond/notification-thread-events.h
src/bin/lttng-sessiond/notification-thread-internal.h
src/bin/lttng-sessiond/notification-thread.c
src/bin/lttng-sessiond/notification-thread.h
src/bin/lttng-sessiond/rotate.c
src/bin/lttng-sessiond/sessiond-config.c
src/bin/lttng-sessiond/thread.c
src/bin/lttng-sessiond/trace-kernel.c
src/bin/lttng-sessiond/trace-kernel.h
src/bin/lttng-sessiond/trace-ust.c
src/bin/lttng-sessiond/ust-abi-internal.h
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng-sessiond/ust-app.h
src/bin/lttng-sessiond/ust-ctl-internal.h
src/bin/lttng-sessiond/utils.c
src/bin/lttng-sessiond/utils.h
src/bin/lttng/Makefile.am
src/bin/lttng/command.h
src/bin/lttng/commands/add_context.c
src/bin/lttng/commands/add_trigger.c [new file with mode: 0644]
src/bin/lttng/commands/create.c
src/bin/lttng/commands/disable_events.c
src/bin/lttng/commands/enable_events.c
src/bin/lttng/commands/list_triggers.c [new file with mode: 0644]
src/bin/lttng/commands/remove_trigger.c [new file with mode: 0644]
src/bin/lttng/commands/track-untrack.c
src/bin/lttng/commands/view.c
src/bin/lttng/conf.c
src/bin/lttng/lttng.c
src/bin/lttng/uprobe.c [new file with mode: 0644]
src/bin/lttng/uprobe.h [new file with mode: 0644]
src/bin/lttng/utils.c
src/bin/lttng/utils.h
src/common/Makefile.am
src/common/action.c [deleted file]
src/common/actions/action.c [new file with mode: 0644]
src/common/actions/group.c [new file with mode: 0644]
src/common/actions/notify.c [new file with mode: 0644]
src/common/actions/rotate-session.c [new file with mode: 0644]
src/common/actions/snapshot-session.c [new file with mode: 0644]
src/common/actions/start-session.c [new file with mode: 0644]
src/common/actions/stop-session.c [new file with mode: 0644]
src/common/argpar/Makefile.am [new file with mode: 0644]
src/common/argpar/argpar.c [new file with mode: 0644]
src/common/argpar/argpar.h [new file with mode: 0644]
src/common/buffer-usage.c [deleted file]
src/common/buffer-view.c
src/common/buffer-view.h
src/common/condition.c [deleted file]
src/common/conditions/buffer-usage.c [new file with mode: 0644]
src/common/conditions/condition.c [new file with mode: 0644]
src/common/conditions/event-rule.c [new file with mode: 0644]
src/common/conditions/session-consumed-size.c [new file with mode: 0644]
src/common/conditions/session-rotation.c [new file with mode: 0644]
src/common/credentials.c [new file with mode: 0644]
src/common/credentials.h
src/common/domain.c [new file with mode: 0644]
src/common/dynamic-array.h
src/common/error.c
src/common/error.h
src/common/evaluation.c
src/common/event-rule-kprobe.c [new file with mode: 0644]
src/common/event-rule-kretprobe.c [new file with mode: 0644]
src/common/event-rule-syscall.c [new file with mode: 0644]
src/common/event-rule-tracepoint.c [new file with mode: 0644]
src/common/event-rule-uprobe.c [new file with mode: 0644]
src/common/event-rule.c [new file with mode: 0644]
src/common/filter/Makefile.am [new file with mode: 0644]
src/common/filter/filter-ast.h [new file with mode: 0644]
src/common/filter/filter-bytecode.h [new file with mode: 0644]
src/common/filter/filter-grammar-test.c [new file with mode: 0644]
src/common/filter/filter-ir.h [new file with mode: 0644]
src/common/filter/filter-lexer.l [new file with mode: 0644]
src/common/filter/filter-parser.y [new file with mode: 0644]
src/common/filter/filter-symbols.h [new file with mode: 0644]
src/common/filter/filter-visitor-generate-bytecode.c [new file with mode: 0644]
src/common/filter/filter-visitor-generate-ir.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-check-binary-comparator.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-check-binary-op-nesting.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-normalize-glob-patterns.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-validate-globbing.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-validate-string.c [new file with mode: 0644]
src/common/filter/filter-visitor-xml.c [new file with mode: 0644]
src/common/filter/memstream.h [new file with mode: 0644]
src/common/kernel-ctl/kernel-ctl.c
src/common/kernel-ctl/kernel-ctl.h
src/common/kernel-ctl/kernel-ioctl.h
src/common/lttng-elf.c
src/common/lttng-kernel.h
src/common/notification.c
src/common/notify.c [deleted file]
src/common/relayd/relayd.c
src/common/runas.c
src/common/runas.h
src/common/session-consumed-size.c [deleted file]
src/common/session-rotation.c [deleted file]
src/common/sessiond-comm/sessiond-comm.h
src/common/snapshot.c [new file with mode: 0644]
src/common/snapshot.h [new file with mode: 0644]
src/common/trigger.c
src/common/unix.c
src/common/userspace-probe.c
src/common/utils.c
src/common/utils.h
src/lib/lttng-ctl/Makefile.am
src/lib/lttng-ctl/channel.c
src/lib/lttng-ctl/filter/Makefile.am [deleted file]
src/lib/lttng-ctl/filter/filter-ast.h [deleted file]
src/lib/lttng-ctl/filter/filter-bytecode.h [deleted file]
src/lib/lttng-ctl/filter/filter-grammar-test.c [deleted file]
src/lib/lttng-ctl/filter/filter-ir.h [deleted file]
src/lib/lttng-ctl/filter/filter-lexer.l [deleted file]
src/lib/lttng-ctl/filter/filter-parser.y [deleted file]
src/lib/lttng-ctl/filter/filter-symbols.h [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-generate-bytecode.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-generate-ir.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-check-binary-comparator.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-check-binary-op-nesting.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-normalize-glob-patterns.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-validate-globbing.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-validate-string.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-xml.c [deleted file]
src/lib/lttng-ctl/filter/memstream.h [deleted file]
src/lib/lttng-ctl/lttng-ctl-health.c
src/lib/lttng-ctl/lttng-ctl-helper.h
src/lib/lttng-ctl/lttng-ctl.c
src/lib/lttng-ctl/snapshot.c
tests/regression/Makefile.am
tests/regression/kernel/select_poll_epoll.c
tests/regression/tools/Makefile.am
tests/regression/tools/exclusion/test_exclusion
tests/regression/tools/health/health_exit.c
tests/regression/tools/health/health_fail.c
tests/regression/tools/health/health_stall.c
tests/regression/tools/live/live_test.c
tests/regression/tools/notification/Makefile.am
tests/regression/tools/notification/base_client.c
tests/regression/tools/notification/consumer_testpoints.c
tests/regression/tools/notification/notification.c
tests/regression/tools/notification/test_notification_kernel [deleted file]
tests/regression/tools/notification/test_notification_kernel_buffer_usage [new file with mode: 0755]
tests/regression/tools/notification/test_notification_kernel_error [new file with mode: 0755]
tests/regression/tools/notification/test_notification_kernel_instrumentation [new file with mode: 0755]
tests/regression/tools/notification/test_notification_kernel_syscall [new file with mode: 0755]
tests/regression/tools/notification/test_notification_kernel_userspace_probe [new file with mode: 0755]
tests/regression/tools/notification/test_notification_ust [deleted file]
tests/regression/tools/notification/test_notification_ust_buffer_usage [new file with mode: 0755]
tests/regression/tools/notification/test_notification_ust_error [new file with mode: 0755]
tests/regression/tools/notification/test_notification_ust_event_rule_condition_exclusion [new file with mode: 0755]
tests/regression/tools/rotation/schedule_api.c
tests/regression/tools/snapshots/ust_test
tests/regression/tools/trigger/Makefile.am [new file with mode: 0644]
tests/regression/tools/trigger/base_client.c [new file with mode: 0644]
tests/regression/tools/trigger/consumer_testpoints.c [new file with mode: 0644]
tests/regression/tools/trigger/test_add_trigger_cli [new file with mode: 0755]
tests/regression/tools/trigger/test_list_triggers_cli [new file with mode: 0755]
tests/regression/tools/trigger/test_remove_trigger_cli [new file with mode: 0755]
tests/regression/tools/trigger/test_trigger_kernel [new file with mode: 0755]
tests/regression/tools/trigger/test_trigger_ust [new file with mode: 0755]
tests/regression/tools/trigger/trigger.c [new file with mode: 0644]
tests/regression/ust/clock-override/lttng-ust-clock-override-test.c
tests/regression/ust/fork/fork.c
tests/regression/ust/getcpu-override/lttng-ust-getcpu-override-test.c
tests/regression/ust/high-throughput/main.c
tests/regression/ust/low-throughput/tp.h
tests/regression/ust/multi-lib/callsites.c
tests/regression/ust/multi-lib/multi-lib-test.c
tests/unit/Makefile.am
tests/unit/test_buffer_view.c [new file with mode: 0644]
tests/unit/test_condition.c [new file with mode: 0644]
tests/unit/test_directory_handle.c
tests/unit/test_event_rule.c [new file with mode: 0644]
tests/unit/test_fd_tracker.c
tests/unit/test_relayd_backward_compat_group_by_session.c
tests/unit/test_session.c
tests/unit/test_utils_expand_path.c
tests/unit/test_utils_parse_size_suffix.c
tests/unit/test_utils_parse_time_suffix.c
tests/utils/tap/tap.c
tests/utils/tap/tap.h
tests/utils/testapp/gen-syscall-events-callstack/Makefile.am
tests/utils/testapp/gen-syscall-events/gen-syscall-events.c
tests/utils/testapp/gen-ust-nevents/gen-ust-nevents.c
tests/utils/testapp/gen-ust-tracef/gen-ust-tracef.c
tests/utils/testapp/userspace-probe-elf-binary/Makefile.am
tests/utils/utils.sh

index 34f133a2574ee3b038c6fddd4a2a90f5ed9ac976..b92dac27c7631bfaec53e5e9982ae534ad32baf9 100644 (file)
@@ -61,11 +61,11 @@ compile_commands.json
 /src/bin/lttng-crash/lttng-crash
 /src/bin/lttng-relayd/lttng-relayd
 /src/lib/lttng-ctl/lttng-ctl.pc
-/src/lib/lttng-ctl/filter/filter-grammar-test
-/src/lib/lttng-ctl/filter/filter-lexer.c
-/src/lib/lttng-ctl/filter/filter-parser.c
-/src/lib/lttng-ctl/filter/filter-parser.h
-/src/lib/lttng-ctl/filter/filter-parser.output
+/src/common/filter/filter-grammar-test
+/src/common/filter/filter-lexer.c
+/src/common/filter/filter-parser.c
+/src/common/filter/filter-parser.h
+/src/common/filter/filter-parser.output
 
 /extras/bindings/swig/python/lttng.i
 /extras/bindings/swig/python/lttng.py
@@ -88,6 +88,8 @@ compile_commands.json
 /tests/unit/test_directory_handle
 /tests/unit/test_relayd_backward_compat_group_by_session
 /tests/unit/test_fd_tracker
+/tests/unit/test_event_rule
+/tests/unit/test_condition
 kernel_all_events_basic
 kernel_event_basic
 ust_global_event_wildcard
@@ -105,6 +107,8 @@ health_check
 /tests/regression/tools/notification/notification
 /tests/regression/tools/rotation/schedule_api
 /tests/regression/tools/notification/rotation
+/tests/regression/tools/trigger/base_client
+/tests/regression/tools/trigger/trigger
 /tests/regression/ust/overlap/demo/demo
 /tests/regression/ust/linking/demo_builtin
 /tests/regression/ust/linking/demo_static
index 852c61f0e246e025849d3a63256b34977cc01b10..2ea9571ff6cdd0854bcf79d8759f117b4cc7c821 100644 (file)
@@ -26,6 +26,31 @@ AC_PROG_CXX
 RW_PROG_CXX_WORKS
 AM_CONDITIONAL([CXX_WORKS], [test "x$rw_cv_prog_cxx_works" = "xyes"])
 
+# Detect warning flags supported by the compiler, append them to WARN_CFLAGS.
+#
+# Pass -Werror as an extra flag during the test: this is needed to make the
+# -Wunknown-warning-option diagnostic fatal with clang.
+AX_APPEND_COMPILE_FLAGS([ dnl
+               -Wall dnl
+               dnl We currently get this warning when building with Clang:
+               dnl
+               dnl /usr/include/setjmp.h:54:12: error: declaration of built-in function '__sigsetjmp' requires the declaration of the 'jmp_buf' type, commonly provided in the header <setjmp.h>. [-Werror,-Wincomplete-setjmp-declaration]
+               dnl extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __THROWNL;
+               dnl            ^
+               -Wno-incomplete-setjmp-declaration dnl
+               -Wdiscarded-qualifiers dnl
+       ],
+       [WARN_CFLAGS],
+       [-Werror])
+
+# When given, add -Werror to WARN_CFLAGS.
+AC_ARG_ENABLE([Werror],
+       [AS_HELP_STRING([--enable-Werror], [Treat compiler warnings as errors.])]
+)
+AS_IF([test "x$enable_Werror" = "xyes"],
+       [WARN_CFLAGS="${WARN_CFLAGS} -Werror"]
+)
+
 # Checks for programs.
 AC_PROG_GREP
 AC_PROG_MAKE_SET
@@ -1038,16 +1063,20 @@ AM_CONDITIONAL([BUILD_LIB_SESSIOND_COMM], [test x$build_lib_sessiond_comm = xyes
 AM_CONDITIONAL([BUILD_LIB_TESTPOINT], [test x$build_lib_testpoint = xyes])
 AM_CONDITIONAL([BUILD_LIB_UST_CONSUMER], [test x$build_lib_ust_consumer = xyes])
 
-AM_CFLAGS="-Wall -fno-strict-aliasing $PTHREAD_CFLAGS"
+AM_CFLAGS="${WARN_CFLAGS} -fno-strict-aliasing $PTHREAD_CFLAGS"
 AC_SUBST(AM_CFLAGS)
 
+# This is set even though it is empty, so Makefiles can do "AM_LDFLAGS += ...".
+AM_LDFLAGS=""
+AC_SUBST(AM_LDFLAGS)
+
 # The order in which the include folders are searched is important.
 # The top_builddir should always be searched first in the event that a build
 # time generated file is included. An example of this is the "version.i" file.
 # In a scenario where lttng-tools is built from a distribution tarball and in a
 # out-of-tree manner, the generated "version.i" has priority on the one from
 # the source (distribution tarball) and must be found first.
-AM_CPPFLAGS="-I\$(top_builddir)/include -I\$(top_srcdir)/include -I\$(top_srcdir)/src -include config.h $AM_CPPFLAGS"
+AM_CPPFLAGS="-I\$(top_builddir)/include -I\$(top_srcdir)/include -I\$(top_builddir)/src -I\$(top_srcdir)/src -include config.h $AM_CPPFLAGS"
 AC_SUBST(AM_CPPFLAGS)
 
 lttngincludedir="${includedir}/lttng"
@@ -1065,6 +1094,9 @@ AC_SUBST(lttngnotificationincludedir)
 lttngtriggerincludedir="${includedir}/lttng/trigger"
 AC_SUBST(lttngtriggerincludedir)
 
+lttngeventruleincludedir="${includedir}/lttng/event-rule"
+AC_SUBST(lttngeventruleincludedir)
+
 lttnglibexecdir="${libdir}/lttng/libexec"
 AC_SUBST(lttnglibexecdir)
 
@@ -1081,6 +1113,7 @@ AC_CONFIG_FILES([
        extras/core-handler/Makefile
        src/Makefile
        src/common/Makefile
+       src/common/argpar/Makefile
        src/common/kernel-ctl/Makefile
        src/common/kernel-consumer/Makefile
        src/common/consumer/Makefile
@@ -1095,9 +1128,9 @@ AC_CONFIG_FILES([
        src/common/config/Makefile
        src/common/string-utils/Makefile
        src/common/fd-tracker/Makefile
+       src/common/filter/Makefile
        src/lib/Makefile
        src/lib/lttng-ctl/Makefile
-       src/lib/lttng-ctl/filter/Makefile
        src/lib/lttng-ctl/lttng-ctl.pc
        src/bin/Makefile
        src/bin/lttng-consumerd/Makefile
@@ -1132,6 +1165,7 @@ AC_CONFIG_FILES([
        tests/regression/tools/working-directory/Makefile
        tests/regression/tools/relayd-grouping/Makefile
        tests/regression/tools/clear/Makefile
+       tests/regression/tools/trigger/Makefile
        tests/regression/ust/Makefile
        tests/regression/ust/nprocesses/Makefile
        tests/regression/ust/high-throughput/Makefile
diff --git a/doc/examples/trigger-on-event/README.md b/doc/examples/trigger-on-event/README.md
new file mode 100644 (file)
index 0000000..2c184f7
--- /dev/null
@@ -0,0 +1,56 @@
+# Trigger notification exemple
+
+## Description
+This exemple is made-up of three executables.
+
+### `notification-client`
+
+```
+Usage: notification-client TRIGGER_NAME
+```
+
+A simple client that subscribes to the notifications emitted by the `TRIGGER_NAME` trigger.
+
+### `instrumented-app`
+
+An application that emits the `trigger_exemple:my_event` event every 2 seconds.
+
+### `demo.sh`
+
+This script adds a trigger named `demo_trigger` which emits a notification when the user-space `trigger_exemple:my_event` event occurs.
+
+Once the trigger has been setup, the notification-client is launched to print all notifications emitted by the `demo_trigger` trigger.
+
+## Building
+
+Simply run the included Makefile.
+
+## Running the exemple
+
+1) Launch a session daemon using:
+        ```
+        $ lttng-sessiond
+        ```
+2) Launch the `demo.sh` script
+3) Launch the `instrumented-app`
+
+The following output should be produced:
+
+```
+$ ./demo.sh
+Registering a notification trigger named "demo_trigger" for the trigger_exemple:my_event user-space event
+Trigger registered successfully.
+Subscribed to notifications of trigger "demo_trigger"
+[02-14-2020] 18:13:34.779766 - Received notification of event rule trigger "demo_trigger"
+[02-14-2020] 18:13:36.779888 - Received notification of event rule trigger "demo_trigger"
+[02-14-2020] 18:13:38.780514 - Received notification of event rule trigger "demo_trigger"
+[02-14-2020] 18:13:40.780656 - Received notification of event rule trigger "demo_trigger"
+```
+
+```
+$ ./instrumented-app
+[02-14-2020] 18:13:34.779433 - Tracing event "trigger_exemple:my_event"
+[02-14-2020] 18:13:36.779693 - Tracing event "trigger_exemple:my_event"
+[02-14-2020] 18:13:38.780010 - Tracing event "trigger_exemple:my_event"
+[02-14-2020] 18:13:40.780286 - Tracing event "trigger_exemple:my_event"
+```
diff --git a/doc/examples/trigger-on-event/demo.sh b/doc/examples/trigger-on-event/demo.sh
new file mode 100755 (executable)
index 0000000..61623fb
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+#
+# SPDX-License-Identifier: MIT
+
+EVENT_NAME=trigger_exemple:my_event
+TRIGGER_NAME=demo_trigger
+
+lttng list > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+    echo "Could not connect to session daemon, are you sure it is running?"
+    exit 1
+fi
+
+echo "Registering a notification trigger named \"$TRIGGER_NAME\" for the $EVENT_NAME user-space event"
+lttng add-trigger --id $TRIGGER_NAME --condition on-event --userspace $EVENT_NAME --action notify
+
+./notification-client $TRIGGER_NAME
+
diff --git a/doc/examples/trigger-on-event/instrumented-app.c b/doc/examples/trigger-on-event/instrumented-app.c
new file mode 100644 (file)
index 0000000..2490056
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include "tp.h"
+
+#include <lttng/tracepoint.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+       uint64_t i;
+
+       for (i = 0; i < UINT64_MAX; i++) {
+               char time_str[64];
+               struct timeval tv;
+               time_t the_time;
+
+               gettimeofday(&tv, NULL);
+               the_time = tv.tv_sec;
+
+               strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
+                               localtime(&the_time));
+               printf("%s.%ld - Tracing event \"trigger_exemple:my_event\"\n", time_str, tv.tv_usec);
+
+               tracepoint(trigger_exemple, my_event, i);
+               sleep(2);
+       }
+       return 0;
+}
diff --git a/doc/examples/trigger-on-event/notification-client.c b/doc/examples/trigger-on-event/notification-client.c
new file mode 100644 (file)
index 0000000..217b5c7
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <lttng/condition/event-rule.h>
+#include <lttng/lttng.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+bool action_group_contains_notify(const struct lttng_action *action_group)
+{
+       unsigned int i, count;
+       enum lttng_action_status status =
+                       lttng_action_group_get_count(action_group, &count);
+
+       if (status != LTTNG_ACTION_STATUS_OK) {
+               printf("Failed to get action count from action group\n");
+               exit(1);
+       }
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_action *action =
+                               lttng_action_group_get_at_index_const(
+                                               action_group, i);
+               const enum lttng_action_type action_type =
+                               lttng_action_get_type(action);
+
+               if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+int print_notification(struct lttng_notification *notification)
+{
+       int ret = 0;
+       const struct lttng_condition *condition =
+                       lttng_notification_get_condition(notification);
+       const struct lttng_evaluation *evaluation =
+                       lttng_notification_get_evaluation(notification);
+       const enum lttng_condition_type type =
+                       lttng_evaluation_get_type(evaluation);
+
+       switch (type) {
+       case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
+               printf("Received consumed size notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+               printf("Received buffer usage notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+               printf("Received session rotation ongoing notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+               printf("Received session rotation completed notification\n");
+               break;
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       {
+               const char *trigger_name;
+               enum lttng_evaluation_status evaluation_status;
+               char time_str[64];
+               struct timeval tv;
+               time_t the_time;
+
+               gettimeofday(&tv, NULL);
+               the_time = tv.tv_sec;
+
+               strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
+                        localtime(&the_time));
+               printf("%s.%ld - ", time_str, tv.tv_usec);
+
+               evaluation_status =
+                               lttng_evaluation_event_rule_get_trigger_name(
+                                               evaluation, &trigger_name);
+               if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
+                       fprintf(stderr, "Failed to get trigger name of event rule notification\n");
+                       ret = -1;
+                       break;
+               }
+
+               printf("Received notification of event rule trigger \"%s\"\n",
+                               trigger_name);
+               break;
+       }
+       default:
+               fprintf(stderr, "Unknown notification type (%d)\n", type);
+       }
+
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int count, i, subcription_count = 0;
+       enum lttng_trigger_status trigger_status;
+       struct lttng_notification_channel *notification_channel = NULL;
+
+       if (argc != 2) {
+               fprintf(stderr, "Missing trigger name\n");
+               fprintf(stderr, "Usage: notification-client TRIGGER_NAME\n");
+               goto end;
+       }
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       if (!notification_channel) {
+               fprintf(stderr, "Failed to create notification channel\n");
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_list_triggers(&triggers);
+       if (ret) {
+               fprintf(stderr, "Failed to list triggers\n");
+               goto end;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &count);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               fprintf(stderr, "Failed to get trigger count\n");
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_trigger *trigger =
+                               lttng_triggers_get_at_index(triggers, i);
+               const struct lttng_condition *condition =
+                               lttng_trigger_get_const_condition(trigger);
+               const struct lttng_action *action =
+                               lttng_trigger_get_const_action(trigger);
+               const enum lttng_action_type action_type =
+                               lttng_action_get_type(action);
+               enum lttng_notification_channel_status channel_status;
+               const char *trigger_name = NULL;
+               enum lttng_trigger_status trigger_status;
+
+               lttng_trigger_get_name(trigger, &trigger_name);
+               if (strcmp(trigger_name, argv[1])) {
+                       continue;
+               }
+
+               if (!((action_type == LTTNG_ACTION_TYPE_GROUP &&
+                                     action_group_contains_notify(action)) ||
+                                   action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
+                       printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
+                                       trigger_name);
+                       continue;
+               }
+
+               channel_status = lttng_notification_channel_subscribe(
+                               notification_channel, condition);
+               if (channel_status) {
+                       fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
+                                       trigger_name);
+                       ret = -1;
+                       goto end;
+               }
+
+               printf("Subscribed to notifications of trigger \"%s\"\n",
+                               trigger_name);
+               subcription_count++;
+       }
+
+       if (subcription_count == 0) {
+               printf("No matching trigger with a notify action found.\n");
+               ret = 0;
+               goto end;
+       }
+
+       for (;;) {
+               struct lttng_notification *notification;
+               enum lttng_notification_channel_status channel_status;
+
+               channel_status =
+                               lttng_notification_channel_get_next_notification(
+                                               notification_channel,
+                                               &notification);
+               switch (channel_status) {
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
+                       printf("Dropped notification\n");
+                       break;
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
+                       ret = 0;
+                       goto end;
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
+                       break;
+               case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
+                       printf("Notification channel was closed by peer.\n");
+                       break;
+               default:
+                       fprintf(stderr, "A communication error occurred on the notification channel.\n");
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = print_notification(notification);
+               lttng_notification_destroy(notification);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       lttng_triggers_destroy(triggers);
+       lttng_notification_channel_destroy(notification_channel);
+       return !!ret;
+}
diff --git a/doc/examples/trigger-on-event/tp.c b/doc/examples/trigger-on-event/tp.c
new file mode 100644 (file)
index 0000000..e1745ed
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_CREATE_PROBES
+#include "tp.h"
diff --git a/doc/examples/trigger-on-event/tp.h b/doc/examples/trigger-on-event/tp.h
new file mode 100644 (file)
index 0000000..ae4593a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER trigger_exemple
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./tp.h"
+
+#if !defined(_TRACEPOINT_TRIGGER_EXEMPLE_H) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define _TRACEPOINT_TRIGGER_EXEMPLE_H
+
+#include <lttng/tracepoint.h>
+
+TRACEPOINT_EVENT(trigger_exemple, my_event,
+       TP_ARGS(int, iteration),
+       TP_FIELDS(
+               ctf_integer(uint64_t, iteration, iteration)
+       )
+)
+
+#endif /* _TRACEPOINT_TRIGGER_EXEMPLE_H */
+
+#include <lttng/tracepoint-event.h>
index 80bedbadfd3f6a7d3bcbaa9ff249b5792bffeb94..5ae6ffbe30da3d4755deed80d5ccfb9e591414f1 100644 (file)
@@ -36,7 +36,11 @@ MAN1_NAMES = \
        lttng-rotate \
        lttng-enable-rotation \
        lttng-disable-rotation \
-       lttng-clear
+       lttng-clear \
+       lttng-add-trigger \
+       lttng-remove-trigger \
+       lttng-list-triggers
+
 MAN3_NAMES =
 MAN8_NAMES = lttng-sessiond lttng-relayd
 MAN1_NO_ASCIIDOC_NAMES =
diff --git a/doc/man/lttng-add-trigger.1.txt b/doc/man/lttng-add-trigger.1.txt
new file mode 100644 (file)
index 0000000..393e8c9
--- /dev/null
@@ -0,0 +1,134 @@
+lttng-add-trigger(1)
+=====================
+:revdate: 17 January 2020
+
+
+NAME
+----
+lttng-add-trigger - Create LTTng triggers
+
+
+SYNOPSIS
+--------
+
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *add-trigger* [--id ID]
+      [--fire-every N] [--fire-once-after N]
+      --condition CONDITION-NAME CONDITION-ARGS
+      --action ACTION-NAME ACTION-ARGS
+      [--action ACTION-NAME ACTION-ARGS]...
+
+
+DESCRIPTION
+-----------
+
+The `lttng add-trigger` command is used to create triggers.  A
+trigger is an association between a *condition* and one or more
+*actions*.  When the condition associated to a trigger is met, the
+actions associated to that trigger are executed.  The tracing does not
+have to be active for the conditions to be met, and triggers are
+independent from tracing sessions.
+
+By default, a trigger fires every time its condition is met.  The
+'--fire-every' and '--fire-once-after' options can be used to change
+this mode.
+
+The syntax by which conditions and actions are specified is described
+below.
+
+[[conditions]]
+Conditions
+~~~~~~~~~~
+
+Conditions are specified with the `--condition` option, followed by a
+condition name, and possibly some more arguments, depending on the
+specific condition.  There must be exactly one condition given in the
+`lttng add-trigger` invocation.
+
+The available conditions are:
+
+Event rule: `on-event [event rule arguments]`::
+    This type of condition is met when the tracer encounters an event
+    matching the given even rule.  The arguments describing the event
+    rule are the same as those describing the event rules of the
+    man:lttng-enable-event(1) command, with these exceptions:
+
+    - It is not possible to use filter operands that use values from
+      the context.
+
+[[actions]]
+Actions
+~~~~~~~
+
+Actions are specified with the `--action` option, followed by an action
+name, and possibly some more arguments, depending on the specific
+action.  There must be at least one action given in the
+`lttng add-trigger` invocation.
+
+The available actions are:
+
+Notify: *notify*::
+    This action causes the LTTng session daemon to send a notification,
+    through its notification mechanism (see man:lttng-sessiond(8)).
+    Some details about the condition evaluation are sent along with the
+    notification.
+
+Start session: *start-session* session-name::
+    This action causes the LTTng session daemon to start tracing for the
+    session with the given name.  If no session with the given name exist
+    at the time the condition is met, nothing is done.
+
+Stop session: *stop-session* session-name::
+    This action causes the LTTng session daemon to stop tracing for the
+    session with the given name.  If no session with the given name exist
+    at the time the condition is met, nothing is done.
+
+Rotate session: *rotate-session* session-name::
+    This action causes the LTTng session daemon to rotate the session
+    with the given name.  See  man:lttng-rotate(1) for more information
+    about the session rotation concept.  If no session with the given
+    name exist at the time the condition is met, nothing is done.
+
+Snapshot session: *snapshot-session* session-name::
+    This action causes the LTTng session daemon to take a snapshot of the
+    session with the given name.  See man:lttng-snapshot(1) for more
+    information about the session snapshot concept.  If no session with
+    the given name exist at the time the condition is met, nothing is
+    done.
+
+OPTIONS
+-------
+
+option:--condition::
+    Define the condition for the trigger.  See the
+    <<conditions,CONDITIONS>> section for more details.
+
+option:--action::
+    Define an action for the trigger.  See the <<actions,ACTIONS>>
+    section for more details.
+
+option:--id='ID'::
+    Set the id of the trigger to 'ID'.  If omitted, an id will
+    automatically be assigned to the trigger by the session daemon.
++
+If a trigger with the specified 'ID' already exists, the trigger
+creation will fail.
+
+option:--fire-every 'N'::
+    Execute the trigger's actions every 'N' times the condition is met.
+
+option:--fire-once-after 'N'::
+    Execute the trigger's actions once after 'N' times the condition is
+    met, then never after that.
+
+include::common-cmd-help-options.txt[]
+
+
+include::common-cmd-footer.txt[]
+
+
+SEE ALSO
+--------
+man:lttng-list-triggers(1),
+man:lttng-remove-trigger(1),
+man:lttng(1)
diff --git a/doc/man/lttng-list-triggers.1.txt b/doc/man/lttng-list-triggers.1.txt
new file mode 100644 (file)
index 0000000..2ab3085
--- /dev/null
@@ -0,0 +1,37 @@
+lttng-list-triggers(1)
+======================
+:revdate: 20 January 2020
+
+
+NAME
+----
+lttng-list-triggers - List LTTng triggers
+
+
+SYNOPSIS
+--------
+
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *list-triggers*
+
+
+DESCRIPTION
+-----------
+
+The `lttng list-triggers` command list the existing triggers.
+
+
+OPTIONS
+-------
+
+include::common-cmd-help-options.txt[]
+
+
+include::common-cmd-footer.txt[]
+
+
+SEE ALSO
+--------
+man:lttng-add-trigger(1),
+man:lttng-remove-trigger(1),
+man:lttng(1)
diff --git a/doc/man/lttng-remove-trigger.1.txt b/doc/man/lttng-remove-trigger.1.txt
new file mode 100644 (file)
index 0000000..645ef15
--- /dev/null
@@ -0,0 +1,38 @@
+lttng-remove-trigger(1)
+========================
+:revdate: 20 January 2020
+
+
+NAME
+----
+lttng-remove-trigger - Remove LTTng triggers
+
+
+SYNOPSIS
+--------
+
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *remove-trigger* 'ID'
+
+
+DESCRIPTION
+-----------
+
+The `lttng remove-trigger` command removes the trigger with the given
+'ID'.
+
+
+OPTIONS
+-------
+
+include::common-cmd-help-options.txt[]
+
+
+include::common-cmd-footer.txt[]
+
+
+SEE ALSO
+--------
+man:lttng-add-trigger(1),
+man:lttng-list-trigger(1),
+man:lttng(1)
index e99c9aecf53750b1c31e54dc7db67d3c7a69990a..b6b6f960eba7720955611e3adbeceaa3679195e2 100644 (file)
@@ -29,6 +29,9 @@ multiple concurrent processes and threads. Tracing across multiple systems is al
 // This makes the typemap code useable with both Python 2 and 3.
 #define PyInt_AsSsize_t PyLong_AsSsize_t
 #endif
+
+// Avoid -Wmissing-declarations warning.
+PyObject *SWIG_init(void);
 %}
 
 typedef unsigned int uint32_t;
index ccd0d87d62dc6ff3ecd9bfe0393cf84baaf44167..4fdd78c7d0681080c4ca0e8e2b3ee5f1f8a1f25e 100644 (file)
@@ -121,11 +121,17 @@ lttnginclude_HEADERS = \
 
 lttngactioninclude_HEADERS= \
        lttng/action/action.h \
-       lttng/action/notify.h
+       lttng/action/group.h \
+       lttng/action/notify.h \
+       lttng/action/rotate-session.h \
+       lttng/action/snapshot-session.h \
+       lttng/action/start-session.h \
+       lttng/action/stop-session.h
 
 lttngconditioninclude_HEADERS= \
        lttng/condition/condition.h \
        lttng/condition/buffer-usage.h \
+       lttng/condition/event-rule.h \
        lttng/condition/session-consumed-size.h \
        lttng/condition/session-rotation.h \
        lttng/condition/evaluation.h
@@ -137,6 +143,14 @@ lttngnotificationinclude_HEADERS= \
 lttngtriggerinclude_HEADERS= \
        lttng/trigger/trigger.h
 
+lttngeventruleinclude_HEADERS= \
+       lttng/event-rule/event-rule.h \
+       lttng/event-rule/kprobe.h \
+       lttng/event-rule/kretprobe.h \
+       lttng/event-rule/syscall.h \
+       lttng/event-rule/tracepoint.h \
+       lttng/event-rule/uprobe.h
+
 noinst_HEADERS = \
        lttng/snapshot-internal.h \
        lttng/health-internal.h \
@@ -146,6 +160,7 @@ noinst_HEADERS = \
        lttng/action/notify-internal.h \
        lttng/condition/condition-internal.h \
        lttng/condition/buffer-usage-internal.h \
+       lttng/condition/event-rule-internal.h \
        lttng/condition/session-consumed-size-internal.h \
        lttng/condition/evaluation-internal.h \
        lttng/condition/session-rotation-internal.h \
@@ -162,5 +177,11 @@ noinst_HEADERS = \
        lttng/session-internal.h \
        lttng/session-descriptor-internal.h \
        lttng/tracker-internal.h \
+       lttng/event-rule/event-rule-internal.h \
+       lttng/event-rule/kprobe-internal.h \
+       lttng/event-rule/kretprobe-internal.h \
+       lttng/event-rule/uprobe-internal.h \
+       lttng/event-rule/syscall-internal.h \
+       lttng/event-rule/tracepoint-internal.h \
        version.h \
        version.i
index 787e9087a01e353c664c1876575dad2867a4fa5b..af52a07ff52a74bd8128537733deeb8ef2db7495 100644 (file)
 #include <common/dynamic-buffer.h>
 #include <stdbool.h>
 #include <sys/types.h>
+#include <urcu/ref.h>
 
 typedef bool (*action_validate_cb)(struct lttng_action *action);
 typedef void (*action_destroy_cb)(struct lttng_action *action);
 typedef int (*action_serialize_cb)(struct lttng_action *action,
                struct lttng_dynamic_buffer *buf);
+typedef bool (*action_equal_cb)(const struct lttng_action *a,
+               const struct lttng_action *b);
+typedef ssize_t (*action_create_from_buffer_cb)(
+               const struct lttng_buffer_view *view,
+               struct lttng_action **action);
 
 struct lttng_action {
+       struct urcu_ref ref;
        enum lttng_action_type type;
        action_validate_cb validate;
        action_serialize_cb serialize;
+       action_equal_cb equal;
        action_destroy_cb destroy;
 };
 
@@ -32,6 +40,14 @@ struct lttng_action_comm {
        int8_t action_type;
 } LTTNG_PACKED;
 
+LTTNG_HIDDEN
+void lttng_action_init(struct lttng_action *action,
+               enum lttng_action_type type,
+               action_validate_cb validate,
+               action_serialize_cb serialize,
+               action_equal_cb equal,
+               action_destroy_cb destroy);
+
 LTTNG_HIDDEN
 bool lttng_action_validate(struct lttng_action *action);
 
@@ -47,4 +63,17 @@ LTTNG_HIDDEN
 enum lttng_action_type lttng_action_get_type_const(
                const struct lttng_action *action);
 
+LTTNG_HIDDEN
+bool lttng_action_is_equal(const struct lttng_action *a,
+               const struct lttng_action *b);
+
+LTTNG_HIDDEN
+void lttng_action_get(struct lttng_action *action);
+
+LTTNG_HIDDEN
+void lttng_action_put(struct lttng_action *action);
+
+LTTNG_HIDDEN
+const char* lttng_action_type_string(enum lttng_action_type action_type);
+
 #endif /* LTTNG_ACTION_INTERNAL_H */
index f3f8d9deef0f16722a668f6e109b24547076c69a..be7e397d0629e6f94091ac4a0eccaf1061366d2b 100644 (file)
@@ -17,6 +17,19 @@ extern "C" {
 enum lttng_action_type {
        LTTNG_ACTION_TYPE_UNKNOWN = -1,
        LTTNG_ACTION_TYPE_NOTIFY = 0,
+       LTTNG_ACTION_TYPE_START_SESSION = 1,
+       LTTNG_ACTION_TYPE_STOP_SESSION = 2,
+       LTTNG_ACTION_TYPE_ROTATE_SESSION = 3,
+       LTTNG_ACTION_TYPE_SNAPSHOT_SESSION = 4,
+       LTTNG_ACTION_TYPE_GROUP = 5,
+};
+
+enum lttng_action_status {
+       LTTNG_ACTION_STATUS_OK = 0,
+       LTTNG_ACTION_STATUS_ERROR = -1,
+       LTTNG_ACTION_STATUS_UNKNOWN = -2,
+       LTTNG_ACTION_STATUS_INVALID = -3,
+       LTTNG_ACTION_STATUS_UNSET = -4,
 };
 
 /*
@@ -25,7 +38,7 @@ enum lttng_action_type {
  * Returns the type of an action on success, LTTNG_ACTION_TYPE_UNKNOWN on error.
  */
 extern enum lttng_action_type lttng_action_get_type(
-               struct lttng_action *action);
+               const struct lttng_action *action);
 
 /*
  * Destroy (frees) an action object.
diff --git a/include/lttng/action/group-internal.h b/include/lttng/action/group-internal.h
new file mode 100644 (file)
index 0000000..4284795
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 EfficiOS, Inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_GROUP_INTERNAL_H
+#define LTTNG_ACTION_GROUP_INTERNAL_H
+
+#include <sys/types.h>
+
+#include <common/macros.h>
+
+struct lttng_action;
+struct lttng_buffer_view;
+
+/*
+ * Create an action group from a buffer view.
+ *
+ * On success, return the number of bytes consumed from `view`, and the created
+ * group in `*group`.  On failure, return -1.
+ */
+LTTNG_HIDDEN
+extern ssize_t lttng_action_group_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_action **group);
+
+#endif /* LTTNG_ACTION_GROUP_INTERNAL_H */
diff --git a/include/lttng/action/group.h b/include/lttng/action/group.h
new file mode 100644 (file)
index 0000000..a49660d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 EfficiOS, inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_GROUP_H
+#define LTTNG_ACTION_GROUP_H
+
+struct lttng_action;
+struct lttng_action_group;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Create a newly allocated action group object.
+ *
+ * Returns a new action group on success, NULL on failure. This action group
+ * must be destroyed using lttng_action_group_destroy().
+ */
+extern struct lttng_action *lttng_action_group_create(void);
+
+/*
+ * Add an action to an lttng_action object of type LTTNG_ACTION_GROUP.
+ *
+ * The group takes ownership of the action.
+ */
+extern enum lttng_action_status lttng_action_group_add_action(
+               struct lttng_action *group, struct lttng_action *action);
+
+extern enum lttng_action_status lttng_action_group_get_count(
+               const struct lttng_action *group, unsigned int *count);
+
+extern const struct lttng_action *lttng_action_group_get_at_index_const(
+               const struct lttng_action *group,
+               unsigned int index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_GROUP_H */
index e6cb174ceea5de44705dc7b880259e5cbdfe8705..a9d50612dbceace92565d08deed4a85ed31902cb 100644 (file)
@@ -15,4 +15,9 @@ struct lttng_action_notify {
        struct lttng_action parent;
 };
 
+LTTNG_HIDDEN
+ssize_t lttng_action_notify_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_action **action);
+
 #endif /* LTTNG_ACTION_NOTIFY_INTERNAL_H */
diff --git a/include/lttng/action/rotate-session-internal.h b/include/lttng/action/rotate-session-internal.h
new file mode 100644 (file)
index 0000000..b3389f7
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 EfficiOS, Inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_ROTATE_SESSION_INTERNAL_H
+#define LTTNG_ACTION_ROTATE_SESSION_INTERNAL_H
+
+#include <sys/types.h>
+
+#include <common/macros.h>
+
+struct lttng_action;
+struct lttng_buffer_view;
+
+/*
+ * Create a "rotate session" action from a buffer view.
+ *
+ * On success, return the number of bytes consumed from `view`, and the created
+ * action in `*action`.  On failure, return -1.
+ */
+LTTNG_HIDDEN
+extern ssize_t lttng_action_rotate_session_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_action **action);
+
+#endif /* LTTNG_ACTION_ROTATE_SESSION_INTERNAL_H */
diff --git a/include/lttng/action/rotate-session.h b/include/lttng/action/rotate-session.h
new file mode 100644 (file)
index 0000000..c7112bb
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 EfficiOS, inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_ROTATE_SESSION_H
+#define LTTNG_ACTION_ROTATE_SESSION_H
+
+struct lttng_action;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Create a newly allocated rotate-session action object.
+ *
+ * Returns a new action on success, NULL on failure. This action must be
+ * destroyed using lttng_action_destroy().
+ */
+extern struct lttng_action *lttng_action_rotate_session_create(void);
+
+/*
+ * Set the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_ROTATE_SESSION.
+ */
+extern enum lttng_action_status lttng_action_rotate_session_set_session_name(
+               struct lttng_action *action, const char *session_name);
+
+/*
+ * Get the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_ROTATE_SESSION.
+ */
+extern enum lttng_action_status lttng_action_rotate_session_get_session_name(
+               const struct lttng_action *action, const char **session_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_ROTATE_SESSION_H */
diff --git a/include/lttng/action/snapshot-session-internal.h b/include/lttng/action/snapshot-session-internal.h
new file mode 100644 (file)
index 0000000..0a3e0e9
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 EfficiOS, Inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_SNAPSHOT_SESSION_INTERNAL_H
+#define LTTNG_ACTION_SNAPSHOT_SESSION_INTERNAL_H
+
+#include <sys/types.h>
+
+#include <common/macros.h>
+
+struct lttng_action;
+struct lttng_buffer_view;
+
+/*
+ * Create a "snapshot session" action from a buffer view.
+ *
+ * On success, return the number of bytes consumed from `view`, and the created
+ * action in `*action`.  On failure, return -1.
+ */
+LTTNG_HIDDEN
+extern ssize_t lttng_action_snapshot_session_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_action **action);
+
+#endif /* LTTNG_ACTION_SNAPSHOT_SESSION_INTERNAL_H */
diff --git a/include/lttng/action/snapshot-session.h b/include/lttng/action/snapshot-session.h
new file mode 100644 (file)
index 0000000..eeb75e6
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 EfficiOS, inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_SNAPSHOT_SESSION_H
+#define LTTNG_ACTION_SNAPSHOT_SESSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_action;
+struct lttng_snapshot_output;
+
+/*
+ * Create a newly allocated snapshot-session action object.
+ *
+ * Returns a new action on success, NULL on failure. This action must be
+ * destroyed using lttng_action_destroy().
+ */
+extern struct lttng_action *lttng_action_snapshot_session_create(void);
+
+/*
+ * Set the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_SNAPSHOT_SESSION.
+ */
+extern enum lttng_action_status lttng_action_snapshot_session_set_session_name(
+               struct lttng_action *action, const char *session_name);
+
+/*
+ * Get the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_SNAPSHOT_SESSION.
+ */
+extern enum lttng_action_status lttng_action_snapshot_session_get_session_name(
+               const struct lttng_action *action, const char **session_name);
+
+/*
+ * Set an explicit snapshot output for this snapshot session action.
+ *
+ * The given snapshot output will be used instead of the session's
+ * default snapshot output.
+ *
+ * This function takes ownership of the given snapshot output.
+ */
+extern enum lttng_action_status lttng_action_snapshot_session_set_output(
+               struct lttng_action *action,
+               struct lttng_snapshot_output *output);
+
+/*
+ * Get the explicit snapshot output for this snapshot session action.
+ */
+extern enum lttng_action_status lttng_action_snapshot_session_get_output_const(
+               const struct lttng_action *action,
+               const struct lttng_snapshot_output **output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_SNAPSHOT_SESSION_H */
diff --git a/include/lttng/action/start-session-internal.h b/include/lttng/action/start-session-internal.h
new file mode 100644 (file)
index 0000000..496bee2
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 EfficiOS, Inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_START_SESSION_INTERNAL_H
+#define LTTNG_ACTION_START_SESSION_INTERNAL_H
+
+#include <sys/types.h>
+
+#include <common/macros.h>
+
+struct lttng_action;
+struct lttng_buffer_view;
+
+/*
+ * Create a "start session" action from a buffer view.
+ *
+ * On success, return the number of bytes consumed from `view`, and the created
+ * action in `*action`.  On failure, return -1.
+ */
+LTTNG_HIDDEN
+extern ssize_t lttng_action_start_session_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_action **action);
+
+#endif /* LTTNG_ACTION_START_SESSION_INTERNAL_H */
diff --git a/include/lttng/action/start-session.h b/include/lttng/action/start-session.h
new file mode 100644 (file)
index 0000000..b9eda70
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 EfficiOS, inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_START_SESSION_H
+#define LTTNG_ACTION_START_SESSION_H
+
+struct lttng_action;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Create a newly allocated start-session action object.
+ *
+ * Returns a new action on success, NULL on failure. This action must be
+ * destroyed using lttng_action_destroy().
+ */
+extern struct lttng_action *lttng_action_start_session_create(void);
+
+/*
+ * Set the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_START_SESSION.
+ */
+extern enum lttng_action_status lttng_action_start_session_set_session_name(
+               struct lttng_action *action, const char *session_name);
+
+/*
+ * Get the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_START_SESSION.
+ */
+extern enum lttng_action_status lttng_action_start_session_get_session_name(
+               const struct lttng_action *action, const char **session_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_START_SESSION_H */
diff --git a/include/lttng/action/stop-session-internal.h b/include/lttng/action/stop-session-internal.h
new file mode 100644 (file)
index 0000000..7a453ea
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 EfficiOS, Inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_STOP_SESSION_INTERNAL_H
+#define LTTNG_ACTION_STOP_SESSION_INTERNAL_H
+
+#include <sys/types.h>
+
+#include <common/macros.h>
+
+struct lttng_action;
+struct lttng_buffer_view;
+
+/*
+ * Create a "stop session" action from a buffer view.
+ *
+ * On success, return the number of bytes consumed from `view`, and the created
+ * action in `*action`.  On failure, return -1.
+ */
+LTTNG_HIDDEN
+extern ssize_t lttng_action_stop_session_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_action **action);
+
+#endif /* LTTNG_ACTION_STOP_SESSION_INTERNAL_H */
diff --git a/include/lttng/action/stop-session.h b/include/lttng/action/stop-session.h
new file mode 100644 (file)
index 0000000..cf9eaab
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 EfficiOS, inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_STOP_SESSION_H
+#define LTTNG_ACTION_STOP_SESSION_H
+
+struct lttng_action;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Create a newly allocated stop-session action object.
+ *
+ * Returns a new action on success, NULL on failure. This action must be
+ * destroyed using lttng_action_destroy().
+ */
+extern struct lttng_action *lttng_action_stop_session_create(void);
+
+/*
+ * Set the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_STOP_SESSION.
+ */
+extern enum lttng_action_status lttng_action_stop_session_set_session_name(
+               struct lttng_action *action, const char *session_name);
+
+/*
+ * Get the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_STOP_SESSION.
+ */
+extern enum lttng_action_status lttng_action_stop_session_get_session_name(
+               const struct lttng_action *action, const char **session_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_STOP_SESSION_H */
index 60686d29f8a8c96b7c0209170690b20114409ef9..2eaf9292f5165fdbb34d9fef41e759db53e51b95 100644 (file)
@@ -21,7 +21,8 @@ typedef void (*condition_destroy_cb)(struct lttng_condition *condition);
 typedef bool (*condition_validate_cb)(const struct lttng_condition *condition);
 typedef int (*condition_serialize_cb)(
                const struct lttng_condition *condition,
-               struct lttng_dynamic_buffer *buf);
+               struct lttng_dynamic_buffer *buf,
+               int *fd_to_send);
 typedef bool (*condition_equal_cb)(const struct lttng_condition *a,
                const struct lttng_condition *b);
 typedef ssize_t (*condition_create_from_buffer_cb)(
@@ -56,10 +57,14 @@ ssize_t lttng_condition_create_from_buffer(
 
 LTTNG_HIDDEN
 int lttng_condition_serialize(const struct lttng_condition *condition,
-               struct lttng_dynamic_buffer *buf);
+               struct lttng_dynamic_buffer *buf,
+               int *fd_to_send);
 
 LTTNG_HIDDEN
 bool lttng_condition_is_equal(const struct lttng_condition *a,
                const struct lttng_condition *b);
 
+LTTNG_HIDDEN
+const char *lttng_condition_type_str(enum lttng_condition_type type);
+
 #endif /* LTTNG_CONDITION_INTERNAL_H */
index 877ccd1a39d0bcc9534c55e4fbc9b578b285cbd0..78a206df3180fd929d3c0b4225ac4f1810cf117f 100644 (file)
@@ -21,6 +21,7 @@ enum lttng_condition_type {
        LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW = 102,
        LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING = 103,
        LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED = 104,
+       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT = 105,
 };
 
 enum lttng_condition_status {
diff --git a/include/lttng/condition/event-rule-internal.h b/include/lttng/condition/event-rule-internal.h
new file mode 100644 (file)
index 0000000..ce1004e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_CONDITION_event_rule_INTERNAL_H
+#define LTTNG_CONDITION_event_rule_INTERNAL_H
+
+#include <lttng/condition/condition-internal.h>
+#include <common/buffer-view.h>
+#include <common/macros.h>
+#include <lttng/condition/evaluation-internal.h>
+
+struct lttng_condition_event_rule {
+       struct lttng_condition parent;
+       struct lttng_event_rule *rule;
+};
+
+struct lttng_condition_event_rule_comm {
+       /* length excludes its own length */
+       uint32_t length;
+       /* rule */
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_evaluation_event_rule {
+       struct lttng_evaluation parent;
+       char *name;
+};
+
+struct lttng_evaluation_event_rule_comm {
+       uint32_t trigger_name_length;
+       /* Trigger name */
+       char payload[];
+} LTTNG_PACKED;
+
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_event_rule_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_condition **condition);
+
+LTTNG_HIDDEN
+enum lttng_condition_status
+lttng_condition_event_rule_get_rule_no_const(
+               const struct lttng_condition *condition,
+               struct lttng_event_rule **rule);
+
+LTTNG_HIDDEN
+struct lttng_evaluation *lttng_evaluation_event_rule_create(const char* trigger_name);
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_event_rule_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_evaluation **_evaluation);
+
+#endif /* LTTNG_CONDITION_event_rule_INTERNAL_H */
diff --git a/include/lttng/condition/event-rule.h b/include/lttng/condition/event-rule.h
new file mode 100644 (file)
index 0000000..2a536d3
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_CONDITION_EVENT_RULE_H
+#define LTTNG_CONDITION_EVENT_RULE_H
+
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/evaluation.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * TODO: overall desciption of an event rule condition.
+ */
+
+/*
+ * Create a newly allocated event rule condition.
+ *
+ * Rule will be copied internally.
+ *
+ * Returns a new condition on success, NULL on failure. This condition must be
+ * destroyed using lttng_condition_destroy().
+ */
+extern struct lttng_condition *lttng_condition_event_rule_create(
+               struct lttng_event_rule *rule);
+
+/*
+ * Get the rule property of a event rule condition.
+ *
+ * The caller does not assume the ownership of the returned rule. The
+ * rule shall only be used for the duration of the condition's
+ * lifetime.
+ *
+ * Returns LTTNG_CONDITION_STATUS_OK and a pointer to the condition's rule
+ * on success, LTTNG_CONDITION_STATUS_INVALID if an invalid
+ * parameter is passed. */
+extern enum lttng_condition_status lttng_condition_event_rule_get_rule(
+               const struct lttng_condition *condition, const struct lttng_event_rule **rule);
+
+/**
+ * lttng_evaluation_event_rule_hit are specialised lttng_evaluations which
+ * allow users to query a number of properties resulting from the evaluation
+ * of a condition which evaluated to true.
+ *
+ * The evaluation of a event rule hit yields two different results:
+ *    TEMPORARY - The name of the triggers associated with the condition.
+ *    TODO - The captured event payload if any
+ */
+
+/*
+ * Get the trigger name property of a event rule hit evaluation.
+ *
+ * Returns LTTNG_EVALUATION_STATUS_OK on success and a trigger name
+ * or LTTNG_EVALUATION_STATUS_INVALID if
+ * an invalid parameter is passed.
+ */
+extern enum lttng_evaluation_status
+lttng_evaluation_event_rule_get_trigger_name(
+               const struct lttng_evaluation *evaluation,
+               const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_CONDITION_EVENT_RULE_H */
diff --git a/include/lttng/domain-internal.h b/include/lttng/domain-internal.h
new file mode 100644 (file)
index 0000000..f34a33b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 - EfficiOS, inc.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_DOMAIN_INTERNAL_H
+#define LTTNG_DOMAIN_INTERNAL_H
+
+#include "lttng/domain.h"
+#include "common/macros.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LTTNG_HIDDEN
+const char *lttng_domain_type_str(enum lttng_domain_type domain_type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_DOMAIN_INTERNAL_H */
index b3df4c9c2b9c3deea142bf9a2cb5388ef72b5b76..01e9b8088db991426b63294b7222efe911c00602 100644 (file)
@@ -36,4 +36,19 @@ struct lttng_event_extended {
 LTTNG_HIDDEN
 struct lttng_event *lttng_event_copy(const struct lttng_event *event);
 
+// FIXME: the implementation of these should be moved to some common file,
+// they should not be in the enable_events.c file.
+
+LTTNG_HIDDEN
+int loglevel_str_to_value(const char *inputstr);
+
+LTTNG_HIDDEN
+int loglevel_log4j_str_to_value(const char *inputstr);
+
+LTTNG_HIDDEN
+int loglevel_jul_str_to_value(const char *inputstr);
+
+LTTNG_HIDDEN
+int loglevel_python_str_to_value(const char *inputstr);
+
 #endif /* LTTNG_EVENT_INTERNAL_H */
diff --git a/include/lttng/event-rule/event-rule-internal.h b/include/lttng/event-rule/event-rule-internal.h
new file mode 100644 (file)
index 0000000..265286a
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien
+ * <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_INTERNAL_H
+#define LTTNG_EVENT_RULE_INTERNAL_H
+
+#include <common/buffer-view.h>
+#include <common/dynamic-buffer.h>
+#include <common/macros.h>
+#include <lttng/event.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/lttng-error.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <urcu/ref.h>
+
+typedef void (*event_rule_destroy_cb)(struct lttng_event_rule *event_rule);
+typedef bool (*event_rule_validate_cb)(
+               const struct lttng_event_rule *event_rule);
+typedef int (*event_rule_serialize_cb)(
+               const struct lttng_event_rule *event_rule,
+               struct lttng_dynamic_buffer *buf,
+               int *fd_to_send);
+typedef bool (*event_rule_equal_cb)(const struct lttng_event_rule *a,
+               const struct lttng_event_rule *b);
+typedef ssize_t (*event_rule_create_from_buffer_cb)(
+               const struct lttng_buffer_view *view,
+               struct lttng_event_rule **event_rule);
+typedef enum lttng_error_code (*event_rule_populate_cb)(
+               struct lttng_event_rule *event_rule, uid_t uid, gid_t gid);
+typedef const char *(*event_rule_get_filter_cb)(
+               const struct lttng_event_rule *event_rule);
+typedef const struct lttng_filter_bytecode *(
+               *event_rule_get_filter_bytecode_cb)(
+               const struct lttng_event_rule *event_rule);
+typedef struct lttng_event_exclusion *(*event_rule_generate_exclusions_cb)(
+               struct lttng_event_rule *event_rule);
+typedef struct lttng_event *(*event_rule_generate_lttng_event_cb)(
+               const struct lttng_event_rule *event_rule);
+
+struct lttng_event_rule {
+       struct urcu_ref ref;
+       enum lttng_event_rule_type type;
+       event_rule_validate_cb validate;
+       event_rule_serialize_cb serialize;
+       event_rule_equal_cb equal;
+       event_rule_destroy_cb destroy;
+       event_rule_populate_cb populate;
+       /* Optional */
+       event_rule_get_filter_cb get_filter;
+       event_rule_get_filter_bytecode_cb get_filter_bytecode;
+       event_rule_generate_exclusions_cb generate_exclusions;
+       event_rule_generate_lttng_event_cb generate_lttng_event;
+};
+
+struct lttng_event_rule_comm {
+       /* enum lttng_event_rule_type */
+       int8_t event_rule_type;
+       char payload[];
+};
+
+LTTNG_HIDDEN
+void lttng_event_rule_init(struct lttng_event_rule *event_rule,
+               enum lttng_event_rule_type type);
+
+LTTNG_HIDDEN
+bool lttng_event_rule_validate(const struct lttng_event_rule *event_rule);
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_create_from_buffer(
+               const struct lttng_buffer_view *buffer,
+               struct lttng_event_rule **event_rule);
+
+LTTNG_HIDDEN
+int lttng_event_rule_serialize(const struct lttng_event_rule *event_rule,
+               struct lttng_dynamic_buffer *buf,
+               int *fd_to_send);
+
+LTTNG_HIDDEN
+bool lttng_event_rule_is_equal(const struct lttng_event_rule *a,
+               const struct lttng_event_rule *b);
+
+LTTNG_HIDDEN
+bool lttng_event_rule_get(struct lttng_event_rule *rule);
+
+LTTNG_HIDDEN
+void lttng_event_rule_put(struct lttng_event_rule *rule);
+
+LTTNG_HIDDEN
+enum lttng_domain_type lttng_event_rule_get_domain_type(
+               const struct lttng_event_rule *rule);
+
+LTTNG_HIDDEN
+enum lttng_error_code lttng_event_rule_populate(
+               struct lttng_event_rule *rule, uid_t uid, gid_t gid);
+
+/* If not present return NULL
+ * Caller DO NOT own the returned object
+ */
+LTTNG_HIDDEN
+const char *lttng_event_rule_get_filter(const struct lttng_event_rule *rule);
+
+/* If not present return NULL
+ * Caller DO NOT own the returned object
+ */
+LTTNG_HIDDEN
+const struct lttng_filter_bytecode *lttng_event_rule_get_filter_bytecode(
+               const struct lttng_event_rule *rule);
+
+/*
+ * If not present return NULL
+ * Caller OWN the returned object
+ * TODO: should this be done another way?
+ */
+LTTNG_HIDDEN
+struct lttng_event_exclusion *lttng_event_rule_generate_exclusions(
+               struct lttng_event_rule *rule);
+
+/*
+ * This is compatibility helper, allowing us to generate a sessiond side (not
+ * communication) struct lttng_event object. This facilitate integration with
+ * current code.
+ * Caller OWN the returned object
+ */
+LTTNG_HIDDEN
+struct lttng_event *lttng_event_rule_generate_lttng_event(
+               const struct lttng_event_rule *rule);
+
+/* Quick helper to test if the event rule apply to an agent domain */
+LTTNG_HIDDEN
+bool lttng_event_rule_is_agent(const struct lttng_event_rule *rule);
+
+LTTNG_HIDDEN
+const char *lttng_event_rule_type_str(enum lttng_event_rule_type type);
+
+#endif /* LTTNG_EVENT_RULE_INTERNAL_H */
diff --git a/include/lttng/event-rule/event-rule.h b/include/lttng/event-rule/event-rule.h
new file mode 100644 (file)
index 0000000..71678b7
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_H
+#define LTTNG_EVENT_RULE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_event_rule;
+
+enum lttng_event_rule_type {
+       LTTNG_EVENT_RULE_TYPE_UNKNOWN = -1,
+       LTTNG_EVENT_RULE_TYPE_TRACEPOINT = 100,
+       LTTNG_EVENT_RULE_TYPE_SYSCALL = 101,
+       LTTNG_EVENT_RULE_TYPE_KPROBE = 102,
+       LTTNG_EVENT_RULE_TYPE_KRETPROBE = 103,
+       LTTNG_EVENT_RULE_TYPE_UPROBE = 104,
+};
+
+
+enum lttng_event_rule_status {
+       LTTNG_EVENT_RULE_STATUS_OK = 0,
+       LTTNG_EVENT_RULE_STATUS_ERROR = -1,
+       LTTNG_EVENT_RULE_STATUS_UNKNOWN = -2,
+       LTTNG_EVENT_RULE_STATUS_INVALID = -3,
+       LTTNG_EVENT_RULE_STATUS_UNSET = -4,
+       LTTNG_EVENT_RULE_STATUS_UNSUPPORTED = -5,
+};
+
+/**
+ * Event rule describe a set of criteria to be used as a discriminant in regards
+ * to a set of events.
+ *
+ * Event rule have the following base properties:
+ *   - the instrumentation type for the event rule,
+ *       - tracepoint
+ *       - syscall
+ *       - probe
+ *       - userspace-probe
+ *   - the domain the event rule covers.
+ */
+
+/*
+ * Get the event rule type.
+ *
+ * Returns the type of an event rule on success, LTTNG_EVENT_RULE_UNKNOWN on
+ * error.
+ */
+extern enum lttng_event_rule_type lttng_event_rule_get_type(
+               const struct lttng_event_rule *event_rule);
+
+/*
+ * Destroy (release) a event_rule object.
+ */
+extern void lttng_event_rule_destroy(struct lttng_event_rule *rule);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_H */
diff --git a/include/lttng/event-rule/kprobe-internal.h b/include/lttng/event-rule/kprobe-internal.h
new file mode 100644 (file)
index 0000000..f3df8e4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_KPROBE_INTERNAL_H
+#define LTTNG_EVENT_RULE_KPROBE_INTERNAL_H
+
+#include <lttng/event-rule/kprobe.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <common/buffer-view.h>
+#include <common/macros.h>
+
+struct lttng_event_rule_kprobe {
+       struct lttng_event_rule parent;
+       char *name;
+       struct {
+               uint64_t address;
+               uint64_t offset;
+               char *symbol_name;
+               bool set;
+       } probe;
+};
+
+struct lttng_event_rule_kprobe_comm {
+       uint32_t name_len;
+       uint32_t probe_symbol_name_len;
+       uint64_t probe_address;
+       uint64_t probe_offset;
+       /* name, source symbol_name */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_kprobe_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_event_rule **rule);
+
+LTTNG_HIDDEN
+uint64_t lttng_event_rule_kprobe_get_address(
+               const struct lttng_event_rule *rule);
+
+LTTNG_HIDDEN
+uint64_t lttng_event_rule_kprobe_get_offset(
+               const struct lttng_event_rule *rule);
+
+LTTNG_HIDDEN
+const char *lttng_event_rule_kprobe_get_symbol_name(
+               const struct lttng_event_rule *rule);
+
+#endif /* LTTNG_EVENT_RULE_KPROBE_INTERNAL_H */
diff --git a/include/lttng/event-rule/kprobe.h b/include/lttng/event-rule/kprobe.h
new file mode 100644 (file)
index 0000000..16f7488
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_KPROBE_H
+#define LTTNG_EVENT_RULE_KPROBE_H
+
+#include <lttng/event-rule/event-rule.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * TODO:
+ */
+extern struct lttng_event_rule *lttng_event_rule_kprobe_create(void);
+
+/*
+ * Set the source of a kprobe event rule.
+ *
+ * TODO: list possible format
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kprobe_set_source(
+               struct lttng_event_rule *rule, const char *source);
+
+/*
+ * Set the name of a kprobe event rule.
+ *
+ * The name is copied.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kprobe_set_name(
+               struct lttng_event_rule *rule, const char *name);
+
+/*
+ * Get the name of a kprobe event rule.
+ *
+ * The caller does not assume the ownership of the returned name.
+ * The name shall only only be used for the duration of the event
+ * rule's lifetime, or before a different name is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's name on
+ * success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_EVENT_RULE_STATUS_UNSET if a name was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kprobe_get_name(
+               const struct lttng_event_rule *rule, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_KPROBE_H */
diff --git a/include/lttng/event-rule/kretprobe-internal.h b/include/lttng/event-rule/kretprobe-internal.h
new file mode 100644 (file)
index 0000000..bf90906
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_KRETPROBE_INTERNAL_H
+#define LTTNG_EVENT_RULE_KRETPROBE_INTERNAL_H
+
+#include <lttng/event-rule/kretprobe.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <common/buffer-view.h>
+#include <common/macros.h>
+
+struct lttng_event_rule_kretprobe {
+       struct lttng_event_rule parent;
+       char *name;
+       struct {
+               uint64_t address;
+               uint64_t offset;
+               char *symbol_name;
+       } probe;
+};
+
+struct lttng_event_rule_kretprobe_comm {
+       uint32_t name_len;
+       uint32_t probe_symbol_len;
+       /*name, probe symbol_name */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_kretprobe_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_event_rule **rule);
+
+LTTNG_HIDDEN
+uint64_t lttng_event_rule_kretprobe_get_address(
+               const struct lttng_event_rule *rule);
+
+LTTNG_HIDDEN
+uint64_t lttng_event_rule_kretprobe_get_offset(
+               const struct lttng_event_rule *rule);
+
+LTTNG_HIDDEN
+const char *lttng_event_rule_kretprobe_get_symbol_name(
+               const struct lttng_event_rule *rule);
+
+#endif /* LTTNG_EVENT_RULE_KRETPROBE_INTERNAL_H */
diff --git a/include/lttng/event-rule/kretprobe.h b/include/lttng/event-rule/kretprobe.h
new file mode 100644 (file)
index 0000000..5ed0852
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_KRETPROBE_H
+#define LTTNG_EVENT_RULE_KRETPROBE_H
+
+#include <lttng/event-rule/event-rule.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * TODO:
+ */
+extern struct lttng_event_rule *lttng_event_rule_kretprobe_create(void);
+
+/*
+ * Set the source of a kretprobe event rule.
+ *
+ * TODO: list possible format
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kretprobe_set_source(
+               struct lttng_event_rule *rule, const char *source);
+
+/*
+ * Set the name of a kretprobe event rule.
+ *
+ * The name is copied.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kretprobe_set_name(
+               struct lttng_event_rule *rule, const char *name);
+
+/*
+ * Get the name of a kretprobe event rule.
+ *
+ * The caller does not assume the ownership of the returned name.
+ * The name shall only only be used for the duration of the event
+ * rule's lifetime, or before a different name is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's name on
+ * success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_EVENT_RULE_STATUS_UNSET if a name was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kretprobe_get_name(
+               const struct lttng_event_rule *rule, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_KRETPROBE_H */
diff --git a/include/lttng/event-rule/syscall-internal.h b/include/lttng/event-rule/syscall-internal.h
new file mode 100644 (file)
index 0000000..47e8e0f
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_SYSCALL_INTERNAL_H
+#define LTTNG_EVENT_RULE_SYSCALL_INTERNAL_H
+
+#include <lttng/event-rule/syscall.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <common/buffer-view.h>
+#include <common/macros.h>
+
+struct lttng_event_rule_syscall {
+       struct lttng_event_rule parent;
+       char *pattern;
+       char *filter_expression;
+
+       /* internal use only */
+       struct {
+               char *filter;
+               struct lttng_filter_bytecode *bytecode;
+       } internal_filter;
+};
+
+struct lttng_event_rule_syscall_comm {
+       uint32_t pattern_len;
+       uint32_t filter_expression_len;
+       /* pattern, filter expression */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_syscall_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_event_rule **rule);
+
+#endif /* LTTNG_EVENT_RULE_SYSCALL_INTERNAL_H */
diff --git a/include/lttng/event-rule/syscall.h b/include/lttng/event-rule/syscall.h
new file mode 100644 (file)
index 0000000..7d3bd17
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_SYSCALL_H
+#define LTTNG_EVENT_RULE_SYSCALL_H
+
+#include <lttng/event-rule/event-rule.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * TODO:
+ */
+extern struct lttng_event_rule *lttng_event_rule_syscall_create(void);
+
+/*
+ * Set the pattern of a syscall event rule.
+ *
+ * Pattern can contains wildcard '*'. See man lttng-enable-event.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_syscall_set_pattern(
+               struct lttng_event_rule *rule, const char *pattern);
+
+/*
+ * Get the pattern of a tracecpoint event rule.
+ *
+ * The caller does not assume the ownership of the returned pattern. The
+ * pattern shall only only be used for the duration of the event rule's
+ * lifetime, or before a different pattern is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's pattern
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid
+ * parameter is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a pattern
+ * was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_syscall_get_pattern(
+               const struct lttng_event_rule *rule, const char **pattern);
+
+/*
+ * Set the filter expression of a syscall event rule.
+ *
+ * The expression is copied.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_syscall_set_filter(
+               struct lttng_event_rule *rule, const char *expression);
+
+/*
+ * Get the filter expression of a syscall event rule.
+ *
+ * The caller does not assume the ownership of the returned filter expression.
+ * The filter expression shall only only be used for the duration of the event
+ * rule's lifetime, or before a different filter expression is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's filter
+ * expression on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid
+ * parameter is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a filter expression
+ * was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_syscall_get_filter(
+               const struct lttng_event_rule *rule, const char **expression);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_H */
diff --git a/include/lttng/event-rule/tracepoint-internal.h b/include/lttng/event-rule/tracepoint-internal.h
new file mode 100644 (file)
index 0000000..e2432dd
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_TRACEPOINT_INTERNAL_H
+#define LTTNG_EVENT_RULE_TRACEPOINT_INTERNAL_H
+
+#include <lttng/event-rule/tracepoint.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/domain.h>
+#include <lttng/event.h>
+#include <common/buffer-view.h>
+#include <common/macros.h>
+
+struct lttng_event_rule_tracepoint {
+       struct lttng_event_rule parent;
+
+       /* Domain */
+       enum lttng_domain_type domain;
+
+       /* Name pattern */
+       char *pattern;
+
+       /* Filter */
+       char *filter_expression;
+
+       /* Loglevel */
+       struct {
+               enum lttng_loglevel_type type;
+               int value;
+       } loglevel;
+
+       /* Exclusions */
+
+       struct {
+               char **values;
+               unsigned int count;
+       } exclusions;
+
+       /* internal use only */
+       struct {
+               char *filter;
+               struct lttng_filter_bytecode *bytecode;
+       } internal_filter;
+};
+
+struct lttng_event_rule_tracepoint_comm {
+       /* enum lttng_domain_type */
+       int8_t domain_type;
+       /* enum lttng_event_logleven_type */
+       int8_t loglevel_type;
+       int32_t loglevel_value;
+       uint32_t pattern_len;
+       uint32_t filter_expression_len;
+       uint32_t exclusions_count;
+       uint32_t exclusions_len;
+       /*
+        * pattern, filter expression and exclusions each terminating with '\0'
+        */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_tracepoint_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_event_rule **rule);
+
+#endif /* LTTNG_EVENT_RULE_TRACEPOINT_INTERNAL_H */
diff --git a/include/lttng/event-rule/tracepoint.h b/include/lttng/event-rule/tracepoint.h
new file mode 100644 (file)
index 0000000..8868828
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_TRACEPOINT_H
+#define LTTNG_EVENT_RULE_TRACEPOINT_H
+
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/domain.h>
+#include <lttng/event.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * TODO:
+ */
+extern struct lttng_event_rule *lttng_event_rule_tracepoint_create(
+               enum lttng_domain_type domain);
+
+/*
+ * Set the pattern of a tracepoint event rule.
+ *
+ * Pattern can contains wildcard '*'. See man lttng-enable-event.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_set_pattern(
+               struct lttng_event_rule *rule, const char *pattern);
+
+/*
+ * Get the pattern of a tracepoint event rule.
+ *
+ * The caller does not assume the ownership of the returned pattern. The
+ * pattern shall only only be used for the duration of the event rule's
+ * lifetime, or before a different pattern is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's pattern
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid
+ * parameter is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a pattern
+ * was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_get_pattern(
+               const struct lttng_event_rule *rule, const char **pattern);
+
+/*
+ * Set the domain type of a tracepoint event rule.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_set_filter(
+               struct lttng_event_rule *rule, const char *expression);
+
+/*
+ * Get the domain type of a tracecpoint event rule.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the domain type output parameter
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
+ * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a pattern was not set prior to
+ * this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_get_domain_type(
+               const struct lttng_event_rule *rule,
+               enum lttng_domain_type *type);
+
+/*
+ * Set the filter expression of a tracepoint event rule.
+ *
+ * The expression is copied.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_set_filter(
+               struct lttng_event_rule *rule, const char *expression);
+
+/*
+ * Get the filter expression of a tracepoint event rule.
+ *
+ * The caller does not assume the ownership of the returned filter expression.
+ * The filter expression shall only only be used for the duration of the event
+ * rule's lifetime, or before a different filter expression is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's filter
+ * expression on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid
+ * parameter is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a filter expression
+ * was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_get_filter(
+               const struct lttng_event_rule *rule, const char **expression);
+
+/*
+ * Set the single loglevel of a tracepoint event rule.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_set_loglevel(
+               struct lttng_event_rule *rule, int level);
+
+/*
+ * Set the loglevel range of a tracepoint event rule.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status
+lttng_event_rule_tracepoint_set_loglevel_range(
+               struct lttng_event_rule *rule, int level);
+
+/*
+ * Set the loglevel to all of a tracepoint event rule.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status
+lttng_event_rule_tracepoint_set_loglevel_all(struct lttng_event_rule *rule);
+
+/*
+ * Get the loglevel type of a tracepoint event rule.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the loglevel type output
+ * parameter on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter
+ * is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a loglevel was not set prior
+ * to this call.
+ */
+extern enum lttng_event_rule_status
+lttng_event_rule_tracepoint_get_loglevel_type(
+               const struct lttng_event_rule *rule, enum lttng_loglevel_type *type);
+
+/*
+ * Get the loglevel of a tracepoint event rule.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the loglevel output parameter
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
+ * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a loglevel was not set prior to
+ * this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_get_loglevel(
+               const struct lttng_event_rule *rule, int *level);
+
+/*
+ * Set the exclusions property of a event rule.
+ *
+ * The passed exclusions will be copied to the event_rule.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK on success,
+ * LTTNG_EVENT_RULE_STATUS_INVALID if invalid parameters are passed, or
+ * LTTNG_EVENT_RULE_STATUS_UNSUPPORTED if this property is not supported by the
+ * domain.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_tracepoint_set_exclusions(
+               struct lttng_event_rule *rule,
+               unsigned int count,
+               const char **exclusions);
+
+/*
+ * Get the exclusions property count of a event rule.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the count output parameter
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
+ * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a domain type was not set prior
+ * to this call.
+ */
+extern enum lttng_event_rule_status
+lttng_event_rule_tracepoint_get_exclusions_count(
+               const struct lttng_event_rule *rule, unsigned int *count);
+
+/*
+ * TODO:
+ * */
+extern enum lttng_event_rule_status
+lttng_event_rule_tracepoint_get_exclusion_at_index(
+               const struct lttng_event_rule *rule,
+               unsigned int index,
+               const char **exclusion);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_TRACEPOINT_H */
diff --git a/include/lttng/event-rule/uprobe-internal.h b/include/lttng/event-rule/uprobe-internal.h
new file mode 100644 (file)
index 0000000..c26c8c7
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_UPROBE_INTERNAL_H
+#define LTTNG_EVENT_RULE_UPROBE_INTERNAL_H
+
+#include <lttng/event-rule/uprobe.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <common/buffer-view.h>
+#include <common/macros.h>
+
+struct lttng_event_rule_uprobe {
+       struct lttng_event_rule parent;
+       char *name;
+       struct lttng_userspace_probe_location *location;
+};
+
+struct lttng_event_rule_uprobe_comm {
+       uint32_t name_len;
+       uint32_t location_len;
+       /*name, location object */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_uprobe_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_event_rule **rule);
+
+LTTNG_HIDDEN
+struct lttng_userspace_probe_location *
+lttng_event_rule_uprobe_get_location_no_const(
+               const struct lttng_event_rule *rule);
+
+#endif /* LTTNG_EVENT_RULE_UPROBE_INTERNAL_H */
diff --git a/include/lttng/event-rule/uprobe.h b/include/lttng/event-rule/uprobe.h
new file mode 100644 (file)
index 0000000..dbe07bb
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 - Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVENT_RULE_UPROBE_H
+#define LTTNG_EVENT_RULE_UPROBE_H
+
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/userspace-probe.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * TODO:
+ */
+extern struct lttng_event_rule *lttng_event_rule_uprobe_create(void);
+
+/*
+ * Set the location of a uprobe event rule.
+ *
+ * The location is copied internally.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_uprobe_set_location(
+               struct lttng_event_rule *rule, const struct lttng_userspace_probe_location *location);
+
+/*
+ * Get the location of a uprobe event rule.
+ *
+ * The caller does not assume the ownership of the returned location.
+ * The location shall only be used for the duration of the event
+ * rule's lifetime, or before a different location is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's location
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_EVENT_RULE_STATUS_UNSET if a location was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_uprobe_get_location(
+               const struct lttng_event_rule *rule,
+               const struct lttng_userspace_probe_location **location);
+
+/*
+ * Set the name of a uprobe event rule.
+ *
+ * The name is copied.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_uprobe_set_name(
+               struct lttng_event_rule *rule, const char *name);
+
+/*
+ * Get the name of a uprobe event rule.
+ *
+ * The caller does not assume the ownership of the returned name.
+ * The name shall only only be used for the duration of the event
+ * rule's lifetime, or before a different name is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's name on
+ * success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_EVENT_RULE_STATUS_UNSET if a name was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_uprobe_get_name(
+               const struct lttng_event_rule *rule, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_UPROBE_H */
index 4557cf0d72a0a39c870b12076671157ced8d4cf3..a3d51894498d3a66da505d58bd454f97c4a79f1b 100644 (file)
 #include <lttng/session-descriptor.h>
 #include <lttng/destruction-handle.h>
 #include <lttng/action/action.h>
+#include <lttng/action/group.h>
 #include <lttng/action/notify.h>
+#include <lttng/action/rotate-session.h>
+#include <lttng/action/snapshot-session.h>
+#include <lttng/action/start-session.h>
+#include <lttng/action/stop-session.h>
 #include <lttng/condition/condition.h>
 #include <lttng/condition/buffer-usage.h>
 #include <lttng/condition/session-consumed-size.h>
 #include <lttng/condition/session-rotation.h>
 #include <lttng/condition/evaluation.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/kprobe.h>
+#include <lttng/event-rule/kretprobe.h>
+#include <lttng/event-rule/syscall.h>
+#include <lttng/event-rule/tracepoint.h>
+#include <lttng/event-rule/uprobe.h>
 #include <lttng/notification/channel.h>
 #include <lttng/notification/notification.h>
 #include <lttng/trigger/trigger.h>
index 72d4922375c1c029420184aeceeb291ee77bae3d..8012a1e4ea58303456f4d6c23fb0e624e3f7278f 100644 (file)
@@ -50,7 +50,7 @@ struct lttng_snapshot_output_list {
        size_t count;
 
        /*
-        * Containes snapshot output object.
+        * Contains snapshot output object.
         */
        struct lttng_snapshot_output *array;
 };
index 9bdf775a97c8e36dc7fe3846ec01189e6120e95c..33e9a53f9f8dfbcbd97eeb0084a25979eab8e9d8 100644 (file)
@@ -39,15 +39,15 @@ void lttng_snapshot_output_destroy(struct lttng_snapshot_output *output);
  */
 
 /* Return snapshot ID. */
-uint32_t lttng_snapshot_output_get_id(struct lttng_snapshot_output *output);
+uint32_t lttng_snapshot_output_get_id(const struct lttng_snapshot_output *output);
 /* Return maximum size of a snapshot. */
-uint64_t lttng_snapshot_output_get_maxsize(struct lttng_snapshot_output *output);
+uint64_t lttng_snapshot_output_get_maxsize(const struct lttng_snapshot_output *output);
 /* Return snapshot name. */
-const char *lttng_snapshot_output_get_name(struct lttng_snapshot_output *output);
+const char *lttng_snapshot_output_get_name(const struct lttng_snapshot_output *output);
 /* Return snapshot control URL in a text format. */
-const char *lttng_snapshot_output_get_ctrl_url(struct lttng_snapshot_output *output);
+const char *lttng_snapshot_output_get_ctrl_url(const struct lttng_snapshot_output *output);
 /* Return snapshot data URL in a text format. */
-const char *lttng_snapshot_output_get_data_url(struct lttng_snapshot_output *output);
+const char *lttng_snapshot_output_get_data_url(const struct lttng_snapshot_output *output);
 
 /*
  * Snapshot output setter family functions.
@@ -65,6 +65,36 @@ int lttng_snapshot_output_set_size(uint64_t size,
 /* Set the snapshot name. */
 int lttng_snapshot_output_set_name(const char *name,
                struct lttng_snapshot_output *output);
+
+/*
+ * Set the output destination to be a path on the local filesystem.
+ *
+ * The path must be absolute.  It can optionally begin with `file://`.
+ */
+int lttng_snapshot_output_set_local_path(const char *path,
+               struct lttng_snapshot_output *output);
+
+/*
+ * Set the output destination to be the network from a combined control/data
+ * URL.
+ *
+ * `url` must start with `net://` or `net6://`.
+ */
+int lttng_snapshot_output_set_network_url(const char *url,
+               struct lttng_snapshot_output *output);
+
+/*
+ * Set the output destination to be the network using separate URLs for control
+ * and data.
+ *
+ * `ctrl_url` and `data_url` must start with `tcp://` or `tcp6://`.
+ */
+int lttng_snapshot_output_set_network_urls(
+               const char *ctrl_url, const char *data_url,
+               struct lttng_snapshot_output *output);
+
+// Deprecated?
+
 /* Set the control URL. Local and remote URL are supported. */
 int lttng_snapshot_output_set_ctrl_url(const char *url,
                struct lttng_snapshot_output *output);
index cff4504a7d71e3b656bce857d6307125a338ff94..64937661f5f79f85e07c5d4ff970dd2023a17355 100644 (file)
 #include <common/macros.h>
 #include <common/buffer-view.h>
 #include <common/dynamic-buffer.h>
+#include <common/dynamic-array.h>
+#include <common/credentials.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <sys/types.h>
+#include <urcu/ref.h>
 
 struct lttng_trigger {
+       struct urcu_ref ref; /* internal use only */
+       bool owns_internal_objects; /* internal use only */
+
        struct lttng_condition *condition;
        struct lttng_action *action;
+       char *name;
+       struct { /* Internal use only */
+               bool set;
+               uint64_t value;
+       } key;
+       struct { /* internal use only */
+               struct lttng_credentials credentials;
+               bool set;
+       } creds;
+       struct {
+               enum lttng_trigger_firing_policy_type type;
+               uint64_t threshold;
+               uint64_t current_count;
+       } firing_policy;
+};
+
+struct lttng_triggers {
+       struct lttng_dynamic_pointer_array array;
 };
 
 struct lttng_trigger_comm {
        /* length excludes its own length. */
+       uint32_t name_length /* Includes '\0' */;
        uint32_t length;
-       /* A condition and action object follow. */
+       uint8_t policy_type;
+       uint64_t policy_threshold;
+       /* A name, condition and action object follow. */
        char payload[];
 } LTTNG_PACKED;
 
+struct lttng_triggers_comm {
+       uint32_t count;
+       uint32_t length;
+       /* Count * lttng_trigger_comm structure */
+       char payload[];
+};
+
 LTTNG_HIDDEN
 ssize_t lttng_trigger_create_from_buffer(const struct lttng_buffer_view *view,
                struct lttng_trigger **trigger);
 
 LTTNG_HIDDEN
-int lttng_trigger_serialize(struct lttng_trigger *trigger,
-               struct lttng_dynamic_buffer *buf);
+int lttng_trigger_serialize(const struct lttng_trigger *trigger,
+               struct lttng_dynamic_buffer *buf,
+               int *fd_to_send);
 
 LTTNG_HIDDEN
-const struct lttng_condition *lttng_trigger_get_const_condition(
-               const struct lttng_trigger *trigger);
+bool lttng_trigger_validate(const struct lttng_trigger *trigger);
+
+LTTNG_HIDDEN
+int lttng_trigger_assign(struct lttng_trigger *dst,
+               const struct lttng_trigger *src);
+
+LTTNG_HIDDEN
+bool lttng_trigger_is_equal(const struct lttng_trigger *a,
+               const struct lttng_trigger *b);
+
+LTTNG_HIDDEN
+void lttng_trigger_set_key(struct lttng_trigger *trigger, uint64_t key);
+
+LTTNG_HIDDEN
+uint64_t lttng_trigger_get_key(const struct lttng_trigger *trigger);
+
+LTTNG_HIDDEN
+int lttng_trigger_generate_name(struct lttng_trigger *trigger, uint64_t offset);
+
+/*
+ * Allocate a new list of lttng_trigger.
+ * The returned object must be freed via lttng_triggers_destroy.
+ */
+LTTNG_HIDDEN
+struct lttng_triggers *lttng_triggers_create(void);
+
+/*
+ * Return the non-const pointer of an element at index "index" of a
+ * lttng_triggers.
+ *
+ * The ownership of the lttng_triggers element is NOT transfered.
+ * The returned object can NOT be freed via lttng_trigger_destroy.
+ */
+LTTNG_HIDDEN
+struct lttng_trigger *lttng_triggers_get_pointer_of_index(
+               const struct lttng_triggers *triggers, unsigned int index);
+
+/*
+ * TODO:
+ */
+LTTNG_HIDDEN
+int lttng_triggers_add(
+               struct lttng_triggers *triggers, struct lttng_trigger *trigger);
+
+/*
+ * Serialize a trigger collection to a lttng_dynamic_buffer.
+ * Return LTTNG_OK on success, negative lttng error code on error.
+ */
+LTTNG_HIDDEN
+int lttng_triggers_serialize(const struct lttng_triggers *triggers,
+               struct lttng_dynamic_buffer *buffer);
+
+LTTNG_HIDDEN
+ssize_t lttng_triggers_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_triggers **triggers);
 
 LTTNG_HIDDEN
-const struct lttng_action *lttng_trigger_get_const_action(
+const struct lttng_credentials *lttng_trigger_get_credentials(
                const struct lttng_trigger *trigger);
 
 LTTNG_HIDDEN
-bool lttng_trigger_validate(struct lttng_trigger *trigger);
+void lttng_trigger_set_credentials(
+               struct lttng_trigger *trigger, uid_t uid, gid_t git);
+
+LTTNG_HIDDEN
+void lttng_trigger_get(struct lttng_trigger *trigger);
+
+LTTNG_HIDDEN
+void lttng_trigger_put(struct lttng_trigger *trigger);
+
+LTTNG_HIDDEN
+bool lttng_trigger_is_ready_to_fire(
+               struct lttng_trigger *trigger);
+
+/*
+ * Return the type of any uderlying domain requirement. If no particular
+ * requirement is needed return LTTNG_DOMAIN_NONE.
+ */
+LTTNG_HIDDEN
+enum lttng_domain_type lttng_trigger_get_underlying_domain_type_restriction(
+               const struct lttng_trigger *trigger);
 
 #endif /* LTTNG_TRIGGER_INTERNAL_H */
index feffc6a8f9fb0f1c05c8b1f19b9cb1f308988a7e..823a026518ecfc7d42a7462415576a3190667df9 100644 (file)
@@ -11,6 +11,8 @@
 struct lttng_action;
 struct lttng_condition;
 struct lttng_trigger;
+/* A collection of trigger */
+struct lttng_triggers;
 
 #ifdef __cplusplus
 extern "C" {
@@ -21,6 +23,20 @@ enum lttng_register_trigger_status {
        LTTNG_REGISTER_TRIGGER_STATUS_INVALID = -1,
 };
 
+enum lttng_trigger_status {
+       LTTNG_TRIGGER_STATUS_OK = 0,
+       LTTNG_TRIGGER_STATUS_ERROR = -1,
+       LTTNG_TRIGGER_STATUS_UNKNOWN = -2,
+       LTTNG_TRIGGER_STATUS_INVALID = -3,
+       LTTNG_TRIGGER_STATUS_UNSET = -4,
+       LTTNG_TRIGGER_STATUS_UNSUPPORTED = -5,
+};
+
+enum lttng_trigger_firing_policy_type {
+       LTTNG_TRIGGER_FIRE_EVERY_N = 0,
+       LTTNG_TRIGGER_FIRE_ONCE_AFTER_N = 1,
+};
+
 /*
  * Create a trigger object associating a condition and an action.
  *
@@ -52,6 +68,9 @@ extern struct lttng_trigger *lttng_trigger_create(
 extern struct lttng_condition *lttng_trigger_get_condition(
                struct lttng_trigger *trigger);
 
+const struct lttng_condition *lttng_trigger_get_const_condition(
+               const struct lttng_trigger *trigger);
+
 /*
  * Get the action of a trigger.
  *
@@ -62,6 +81,58 @@ extern struct lttng_condition *lttng_trigger_get_condition(
 extern struct lttng_action *lttng_trigger_get_action(
                struct lttng_trigger *trigger);
 
+const struct lttng_action *lttng_trigger_get_const_action(
+               const struct lttng_trigger *trigger);
+
+/*
+ * Get the name of a trigger.
+ *
+ * The caller does not assume the ownership of the returned name.
+ * The name shall only only be used for the duration of the trigger's
+ * lifetime, or before a different name is set.
+ *
+ * Returns LTTNG_TRIGGER_STATUS_OK and a pointer to the trigger's name on
+ * success, LTTNG_TRIGGER_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_TRIGGER_STATUS_UNSET if a name was not set prior to this call.
+ */
+extern enum lttng_trigger_status lttng_trigger_get_name(
+               const struct lttng_trigger *trigger, const char **name);
+
+/*
+ * Set the trigger name.
+ *
+ * A name is optional.
+ * A name will be assigned on trigger registration if no name is set.
+ *
+ * The name is copied.
+ *
+ * Return LTTNG_TRIGGER_STATUS_OK on success, LTTNG_TRIGGER_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_trigger_status lttng_trigger_set_name(
+               struct lttng_trigger *trigger, const char *name);
+
+/*
+ * Set the trigger firing policy.
+ *
+ * This is optional. By default a trigger is set to fire each time the
+ * associated condition occurs.
+ *
+ * Threshold is the number of time the condition must be hit before the policy is
+ * enacted.
+ *
+ * Return LTTNG_TRIGGER_STATUS_OK on success, LTTNG_TRIGGER_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_trigger_status lttng_trigger_set_firing_policy(
+               struct lttng_trigger *trigger,
+               enum lttng_trigger_firing_policy_type policy_type,
+               unsigned long long threshold);
+extern enum lttng_trigger_status lttng_trigger_get_firing_policy(
+               const struct lttng_trigger *trigger,
+               enum lttng_trigger_firing_policy_type *policy_type,
+               unsigned long long *threshold);
+
 /*
  * Destroy (frees) a trigger object.
  */
@@ -83,7 +154,44 @@ extern int lttng_register_trigger(struct lttng_trigger *trigger);
  *
  * Return 0 on success, a negative LTTng error code on error.
  */
-extern int lttng_unregister_trigger(struct lttng_trigger *trigger);
+extern int lttng_unregister_trigger(const struct lttng_trigger *trigger);
+
+/*
+ * List current triggers.
+ * 
+ * On success, triggers is allocated.
+ * The trigger collection must be free by the caller with lttng_destroy_triggers
+ *
+ * Returns 0 on success, else a negative LTTng error code.
+ */
+extern int lttng_list_triggers(struct lttng_triggers **triggers);
+
+/*
+ * Get a trigger from the collection at a given index.
+ *
+ * Note that the collection maintains the ownership of the returned trigger.
+ * It must not be destroyed by the user, nor should it be held beyond the
+ * lifetime of the trigger collection.
+ *
+ * Returns a trigger, or NULL on error.
+ */
+extern const struct lttng_trigger *lttng_triggers_get_at_index(
+               const struct lttng_triggers *triggers, unsigned int index);
+
+/*
+ * Get the number of trigger in a tracker id list.
+ *
+ * Return LTTNG_TRIGGER_STATUS_OK on success,
+ * LTTNG_TRIGGER_STATUS_INVALID when passed invalid parameters.
+ */
+extern enum lttng_trigger_status lttng_triggers_get_count(
+               const struct lttng_triggers *triggers, unsigned int *count);
+
+/*
+ * Destroy a trigger collection.
+ */
+extern void lttng_triggers_destroy(struct lttng_triggers *ids);
+
 
 #ifdef __cplusplus
 }
index 8287954931791e21bf3b7e0e5f595c91e46f605d..ef6a5726e1edf64710dea6826ea8472e5aa9555a 100644 (file)
 #include <common/dynamic-buffer.h>
 #include <common/buffer-view.h>
 
+typedef bool (*userspace_probe_location_equal_cb)(
+               const struct lttng_userspace_probe_location *a,
+               const struct lttng_userspace_probe_location *b);
+
 /*
  * No elf-specific comm structure is defined since no elf-specific payload is
  * currently needed.
@@ -79,6 +83,7 @@ struct lttng_userspace_probe_location_tracepoint_comm {
 struct lttng_userspace_probe_location {
        enum lttng_userspace_probe_location_type type;
        struct lttng_userspace_probe_location_lookup_method *lookup_method;
+       userspace_probe_location_equal_cb equal;
 };
 
 struct lttng_userspace_probe_location_function {
@@ -142,4 +147,13 @@ LTTNG_HIDDEN
 struct lttng_userspace_probe_location *lttng_userspace_probe_location_copy(
                const struct lttng_userspace_probe_location *location);
 
+LTTNG_HIDDEN
+bool lttng_userspace_probe_location_is_equal(
+               const struct lttng_userspace_probe_location *a,
+               const struct lttng_userspace_probe_location *b);
+
+LTTNG_HIDDEN
+int lttng_userspace_probe_location_set_binary_fd(
+               struct lttng_userspace_probe_location *location, int fd);
+
 #endif /* LTTNG_USERSPACE_PROBE_INTERNAL_H */
diff --git a/m4/ax_append_compile_flags.m4 b/m4/ax_append_compile_flags.m4
new file mode 100644 (file)
index 0000000..9c85635
--- /dev/null
@@ -0,0 +1,46 @@
+# ============================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+#   For every FLAG1, FLAG2 it is checked whether the compiler works with the
+#   flag.  If it does, the flag is added FLAGS-VARIABLE
+#
+#   If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
+#   CFLAGS) is used.  During the check the flag is always added to the
+#   current language's flags.
+#
+#   If EXTRA-FLAGS is defined, it is added to the current language's default
+#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with
+#   the flags: "CFLAGS EXTRA-FLAGS FLAG".  This can for example be used to
+#   force the compiler to issue an error when a bad flag is given.
+#
+#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+#   NOTE: This macro depends on the AX_APPEND_FLAG and
+#   AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
+#   AX_APPEND_LINK_FLAGS.
+#
+# LICENSE
+#
+#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 7
+
+AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
+[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
+AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
+for flag in $1; do
+  AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
+done
+])dnl AX_APPEND_COMPILE_FLAGS
diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4
new file mode 100644 (file)
index 0000000..dd6d8b6
--- /dev/null
@@ -0,0 +1,50 @@
+# ===========================================================================
+#      https://www.gnu.org/software/autoconf-archive/ax_append_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
+#
+# DESCRIPTION
+#
+#   FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
+#   added in between.
+#
+#   If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
+#   CFLAGS) is used.  FLAGS-VARIABLE is not changed if it already contains
+#   FLAG.  If FLAGS-VARIABLE is unset in the shell, it is set to exactly
+#   FLAG.
+#
+#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 8
+
+AC_DEFUN([AX_APPEND_FLAG],
+[dnl
+AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
+AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
+AS_VAR_SET_IF(FLAGS,[
+  AS_CASE([" AS_VAR_GET(FLAGS) "],
+    [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
+    [
+     AS_VAR_APPEND(FLAGS,[" $1"])
+     AC_RUN_LOG([: FLAGS="$FLAGS"])
+    ])
+  ],
+  [
+  AS_VAR_SET(FLAGS,[$1])
+  AC_RUN_LOG([: FLAGS="$FLAGS"])
+  ])
+AS_VAR_POPDEF([FLAGS])dnl
+])dnl AX_APPEND_FLAG
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
new file mode 100644 (file)
index 0000000..bd753b3
--- /dev/null
@@ -0,0 +1,53 @@
+# ===========================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+#   Check whether the given FLAG works with the current language's compiler
+#   or gives an error.  (Warnings, however, are ignored)
+#
+#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+#   success/failure.
+#
+#   If EXTRA-FLAGS is defined, it is added to the current language's default
+#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with
+#   the flags: "CFLAGS EXTRA-FLAGS FLAG".  This can for example be used to
+#   force the compiler to issue an error when a bad flag is given.
+#
+#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+#   macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 6
+
+AC_DEFUN([AX_CHECK_COMPILE_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
+  ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
+  _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
+  AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+    [AS_VAR_SET(CACHEVAR,[yes])],
+    [AS_VAR_SET(CACHEVAR,[no])])
+  _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+  [m4_default([$2], :)],
+  [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/m4/ax_require_defined.m4 b/m4/ax_require_defined.m4
new file mode 100644 (file)
index 0000000..17c3eab
--- /dev/null
@@ -0,0 +1,37 @@
+# ===========================================================================
+#    https://www.gnu.org/software/autoconf-archive/ax_require_defined.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_REQUIRE_DEFINED(MACRO)
+#
+# DESCRIPTION
+#
+#   AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
+#   been defined and thus are available for use.  This avoids random issues
+#   where a macro isn't expanded.  Instead the configure script emits a
+#   non-fatal:
+#
+#     ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
+#
+#   It's like AC_REQUIRE except it doesn't expand the required macro.
+#
+#   Here's an example:
+#
+#     AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
+#
+# LICENSE
+#
+#   Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 2
+
+AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
+  m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
+])dnl AX_REQUIRE_DEFINED
diff --git a/rename.sh b/rename.sh
new file mode 100644 (file)
index 0000000..ded105d
--- /dev/null
+++ b/rename.sh
@@ -0,0 +1,13 @@
+ag --ignore rename.sh -l "event-rule-uprobe-internal\.h" | xargs sed -i 's/event-rule-uprobe-internal\.h/uprobe-internal.h/g'
+ag --ignore rename.sh -l "event-rule-kprobe-internal\.h" | xargs sed -i 's/event-rule-kprobe-internal\.h/kprobe-internal.h/g'
+ag --ignore rename.sh -l "event-rule-kretprobe-internal\.h" | xargs sed -i 's/event-rule-kretprobe-internal\.h/kretprobe-internal.h/g'
+ag --ignore rename.sh -l "event-rule-syscall-internal\.h" | xargs sed -i 's/event-rule-syscall-internal\.h/syscall-internal.h/g'
+ag --ignore rename.sh -l "event-rule-tracepoint-internal\.h" | xargs sed -i 's/event-rule-tracepoint-internal\.h/tracepoint-internal.h/g'
+
+ag --ignore rename.sh -l "event-rule-uprobe\.h" | xargs sed -i 's/event-rule-uprobe\.h/uprobe.h/g'
+ag --ignore rename.sh -l "event-rule-kprobe\.h" | xargs sed -i 's/event-rule-kprobe\.h/kprobe.h/g'
+ag --ignore rename.sh -l "event-rule-kretprobe\.h" | xargs sed -i 's/event-rule-kretprobe\.h/kretprobe.h/g'
+ag --ignore rename.sh -l "event-rule-syscall\.h" | xargs sed -i 's/event-rule-syscall\.h/syscall.h/g'
+ag --ignore rename.sh -l "event-rule-tracepoint\.h" | xargs sed -i 's/event-rule-tracepoint\.h/tracepoint.h/g'
+git add .
+git commit --amend --no-edit
index c0bf42c5a58076b407eb46c50a567a4825f61894..98c52c59dcd835a2c48cde3def2543d025f13132 100644 (file)
@@ -180,9 +180,9 @@ struct lttng_crash_layout {
 };
 
 /* Variables */
-static char *progname,
-       *opt_viewer_path = NULL,
-       *opt_output_path = NULL;
+static const char *progname;
+static char *opt_viewer_path = NULL;
+static char *opt_output_path = NULL;
 
 static char *input_path;
 
@@ -296,7 +296,7 @@ static int parse_args(int argc, char **argv)
        }
 
        if (!opt_viewer_path) {
-               opt_viewer_path = DEFAULT_VIEWER;
+               opt_viewer_path = (char *) DEFAULT_VIEWER;
        }
 
        /* No leftovers, or more than one input path, print usage and quit */
index 09014be0f112959bc07e28b07081c940f339633a..8566ecfa8298c197f6c87f755c747d8f57296d3a 100644 (file)
@@ -10,6 +10,8 @@
 #define _LGPL_SOURCE
 #include <assert.h>
 
+#include "cmd-2-2.h"
+
 #include <common/common.h>
 #include <common/sessiond-comm/relayd.h>
 
index ee53655be18f8390934c01269c537a9a339d0117..dd807125b6342e243c4720f835ba01ba94c37f27 100644 (file)
@@ -54,7 +54,8 @@ lttng_sessiond_SOURCES = utils.c utils.h \
                        manage-kernel.c manage-kernel.h \
                        manage-consumer.c manage-consumer.h \
                        clear.c clear.h \
-                       tracker.c tracker.h
+                       tracker.c tracker.h \
+                       action-executor.c action-executor.h
 
 if HAVE_LIBLTTNG_UST_CTL
 lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \
diff --git a/src/bin/lttng-sessiond/action-executor.c b/src/bin/lttng-sessiond/action-executor.c
new file mode 100644 (file)
index 0000000..40686eb
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "action-executor.h"
+#include "cmd.h"
+#include "health-sessiond.h"
+#include "lttng-sessiond.h"
+#include "notification-thread-internal.h"
+#include "session.h"
+#include "thread.h"
+#include <common/macros.h>
+#include <lttng/action/group.h>
+#include <lttng/action/notify.h>
+#include <lttng/action/rotate-session.h>
+#include <lttng/action/snapshot-session.h>
+#include <lttng/action/start-session.h>
+#include <lttng/action/stop-session.h>
+#include <lttng/condition/evaluation.h>
+#include <lttng/condition/event-rule-internal.h>
+#include <lttng/lttng-error.h>
+#include <lttng/trigger/trigger-internal.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <urcu/list.h>
+
+#define THREAD_NAME "Action Executor"
+#define MAX_QUEUED_WORK_COUNT 8192
+
+struct action_work_item {
+       uint64_t id;
+       struct lttng_trigger *trigger;
+       struct notification_client_list *client_list;
+       struct cds_list_head list_node;
+};
+
+struct action_executor {
+       struct lttng_thread *thread;
+       struct notification_thread_handle *notification_thread_handle;
+       struct {
+               uint64_t pending_count;
+               struct cds_list_head list;
+               pthread_cond_t cond;
+               pthread_mutex_t lock;
+       } work;
+       bool should_quit;
+       uint64_t next_work_item_id;
+};
+
+typedef int (*action_executor_handler)(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *action);
+
+static int action_executor_notify_handler(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *);
+static int action_executor_start_session_handler(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *);
+static int action_executor_stop_session_handler(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *);
+static int action_executor_rotate_session_handler(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *);
+static int action_executor_snapshot_session_handler(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *);
+static int action_executor_group_handler(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *);
+static int action_executor_generic_handler(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *);
+
+static const action_executor_handler action_executors[] = {
+       [LTTNG_ACTION_TYPE_NOTIFY] = action_executor_notify_handler,
+       [LTTNG_ACTION_TYPE_START_SESSION] = action_executor_start_session_handler,
+       [LTTNG_ACTION_TYPE_STOP_SESSION] = action_executor_stop_session_handler,
+       [LTTNG_ACTION_TYPE_ROTATE_SESSION] = action_executor_rotate_session_handler,
+       [LTTNG_ACTION_TYPE_SNAPSHOT_SESSION] = action_executor_snapshot_session_handler,
+       [LTTNG_ACTION_TYPE_GROUP] = action_executor_group_handler,
+};
+
+static const char *get_action_name(const struct lttng_action *action)
+{
+       const char *action_type_names[] = {
+               [LTTNG_ACTION_TYPE_NOTIFY] = "Notify",
+               [LTTNG_ACTION_TYPE_START_SESSION] = "Start session",
+               [LTTNG_ACTION_TYPE_STOP_SESSION] = "Stop session",
+               [LTTNG_ACTION_TYPE_ROTATE_SESSION] = "Rotate session",
+               [LTTNG_ACTION_TYPE_SNAPSHOT_SESSION] = "Snapshot session",
+               [LTTNG_ACTION_TYPE_GROUP] = "Group",
+       };
+
+       return action_type_names[lttng_action_get_type(action)];
+}
+
+static const char *get_trigger_name(const struct lttng_trigger *trigger)
+{
+       const char *trigger_name;
+       enum lttng_trigger_status trigger_status;
+
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       return trigger_name;
+}
+
+static int client_handle_transmission_status(
+               struct notification_client *client,
+               enum client_transmission_status status,
+               void *user_data)
+{
+       struct action_executor *executor = user_data;
+
+       switch (status) {
+       case CLIENT_TRANSMISSION_STATUS_COMPLETE:
+               DBG("Sent notification to client");
+               break;
+       default:
+               ERR("Could not send notification to client");
+       }
+
+       return 0;
+}
+
+static int action_executor_notify_handler(struct action_executor *executor,
+               const struct action_work_item *work_item,
+               const struct lttng_action *action)
+{
+       int ret = 0;
+       struct lttng_evaluation *evaluation = NULL;
+
+       assert(work_item->client_list);
+
+       evaluation = lttng_evaluation_event_rule_create(
+                       get_trigger_name(work_item->trigger));
+       if (!evaluation) {
+               ERR("Failed to create event rule hit evaluation");
+               ret = -1;
+               goto end;
+       }
+
+       ret = notification_client_list_send_evaluation(work_item->client_list,
+                       lttng_trigger_get_const_condition(work_item->trigger),
+                       evaluation,
+                       lttng_trigger_get_credentials(work_item->trigger), NULL,
+                       client_handle_transmission_status, executor);
+end:
+       lttng_evaluation_destroy(evaluation);
+       return ret;
+}
+
+static int action_executor_start_session_handler(struct action_executor *executor,
+               const struct action_work_item *work_item,
+               const struct lttng_action *action)
+{
+       int ret = 0;
+       const char *session_name;
+       enum lttng_action_status action_status;
+       struct ltt_session *session;
+
+       action_status = lttng_action_start_session_get_session_name(
+                       action, &session_name);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to get session name from \"%s\" action",
+                               get_action_name(action));
+               ret = -1;
+               goto end;
+       }
+
+       session_lock_list();
+       session = session_find_by_name(session_name);
+       if (session) {
+               enum lttng_error_code cmd_ret;
+
+               session_lock(session);
+               cmd_ret = cmd_start_trace(session);
+               session_unlock(session);
+
+               switch (cmd_ret) {
+               case LTTNG_OK:
+                       DBG("Successfully started session \"%s\" on behalf of trigger \"%s\"",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger));
+                       break;
+               case LTTNG_ERR_TRACE_ALREADY_STARTED:
+                       DBG("Attempted to start session \"%s\" on behalf of trigger \"%s\" but it was already started",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger));
+                       break;
+               default:
+                       WARN("Failed to start session \"%s\" on behalf of trigger \"%s\": %s",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger),
+                                       lttng_strerror(-cmd_ret));
+                       break;
+               }
+               session_put(session);
+       } else {
+               DBG("Failed to find session \"%s\" by name while executing \"%s\" action of trigger \"%s\"",
+                               session_name, get_action_name(action),
+                               get_trigger_name(work_item->trigger));
+       }
+       session_unlock_list();
+end:
+       return ret;
+}
+
+static int action_executor_stop_session_handler(struct action_executor *executor,
+               const struct action_work_item *work_item,
+               const struct lttng_action *action)
+{
+       int ret = 0;
+       const char *session_name;
+       enum lttng_action_status action_status;
+       struct ltt_session *session;
+
+       action_status = lttng_action_stop_session_get_session_name(
+                       action, &session_name);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to get session name from \"%s\" action",
+                               get_action_name(action));
+               ret = -1;
+               goto end;
+       }
+
+       session_lock_list();
+       session = session_find_by_name(session_name);
+       if (session) {
+               enum lttng_error_code cmd_ret;
+
+               session_lock(session);
+               cmd_ret = cmd_stop_trace(session);
+               session_unlock(session);
+
+               switch (cmd_ret) {
+               case LTTNG_OK:
+                       DBG("Successfully stopped session \"%s\" on behalf of trigger \"%s\"",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger));
+                       break;
+               case LTTNG_ERR_TRACE_ALREADY_STOPPED:
+                       DBG("Attempted to stop session \"%s\" on behalf of trigger \"%s\" but it was already stopped",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger));
+                       break;
+               default:
+                       WARN("Failed to stop session \"%s\" on behalf of trigger \"%s\": %s",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger),
+                                       lttng_strerror(-cmd_ret));
+                       break;
+               }
+               session_put(session);
+       } else {
+               DBG("Failed to find session \"%s\" by name while executing \"%s\" action of trigger \"%s\"",
+                               session_name, get_action_name(action),
+                               get_trigger_name(work_item->trigger));
+       }
+       session_unlock_list();
+end:
+       return ret;
+}
+
+static int action_executor_rotate_session_handler(struct action_executor *executor,
+               const struct action_work_item *work_item,
+               const struct lttng_action *action)
+{
+       int ret = 0;
+       const char *session_name;
+       enum lttng_action_status action_status;
+       struct ltt_session *session;
+
+       action_status = lttng_action_rotate_session_get_session_name(
+                       action, &session_name);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to get session name from \"%s\" action",
+                               get_action_name(action));
+               ret = -1;
+               goto end;
+       }
+
+       session_lock_list();
+       session = session_find_by_name(session_name);
+       if (session) {
+               enum lttng_error_code cmd_ret;
+
+               session_lock(session);
+               cmd_ret = cmd_rotate_session(session, NULL, false,
+                               LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED);
+               session_unlock(session);
+
+               switch (cmd_ret) {
+               case LTTNG_OK:
+                       DBG("Successfully started rotation of session \"%s\" on behalf of trigger \"%s\"",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger));
+                       break;
+               case LTTNG_ERR_ROTATION_PENDING:
+                       DBG("Attempted to start a rotation of session \"%s\" on behalf of trigger \"%s\" but a rotation is already ongoing",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger));
+                       break;
+               case LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP:
+               case LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR:
+                       DBG("Attempted to start a rotation of session \"%s\" on behalf of trigger \"%s\" but a rotation has already been completed since the last stop or clear",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger));
+                       break;
+               default:
+                       WARN("Failed to start a rotation of session \"%s\" on behalf of trigger \"%s\": %s",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger),
+                                       lttng_strerror(-cmd_ret));
+                       break;
+               }
+               session_put(session);
+       } else {
+               DBG("Failed to find session \"%s\" by name while executing \"%s\" action of trigger \"%s\"",
+                               session_name, get_action_name(action),
+                               get_trigger_name(work_item->trigger));
+       }
+       session_unlock_list();
+end:
+       return ret;
+}
+
+static int action_executor_snapshot_session_handler(struct action_executor *executor,
+               const struct action_work_item *work_item,
+               const struct lttng_action *action)
+{
+       int ret = 0;
+       const char *session_name;
+       enum lttng_action_status action_status;
+       struct ltt_session *session;
+       const struct lttng_snapshot_output default_snapshot_output = {
+               .max_size = UINT64_MAX,
+       };
+       const struct lttng_snapshot_output *snapshot_output =
+                       &default_snapshot_output;
+
+       action_status = lttng_action_snapshot_session_get_session_name(
+                       action, &session_name);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to get session name from \"%s\" action",
+                               get_action_name(action));
+               ret = -1;
+               goto end;
+       }
+
+       action_status = lttng_action_snapshot_session_get_output_const(
+                       action, &snapshot_output);
+       if (action_status != LTTNG_ACTION_STATUS_OK &&
+                       action_status != LTTNG_ACTION_STATUS_UNSET) {
+               ERR("Failed to get output from \"%s\" action",
+                               get_action_name(action));
+               ret = -1;
+               goto end;
+       }
+
+       session_lock_list();
+       session = session_find_by_name(session_name);
+       if (session) {
+               enum lttng_error_code cmd_ret;
+
+               session_lock(session);
+               cmd_ret = cmd_snapshot_record(session, snapshot_output, 0);
+               session_unlock(session);
+
+               switch (cmd_ret) {
+               case LTTNG_OK:
+                       DBG("Successfully recorded snapshot of session \"%s\" on behalf of trigger \"%s\"",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger));
+                       break;
+               default:
+                       WARN("Failed to record snapshot of session \"%s\" on behalf of trigger \"%s\": %s",
+                                       session_name,
+                                       get_trigger_name(work_item->trigger),
+                                       lttng_strerror(-cmd_ret));
+                       break;
+               }
+               session_put(session);
+       } else {
+               DBG("Failed to find session \"%s\" by name while executing \"%s\" action of trigger \"%s\"",
+                               session_name, get_action_name(action),
+                               get_trigger_name(work_item->trigger));
+       }
+       session_unlock_list();
+end:
+       return ret;
+}
+
+static int action_executor_group_handler(struct action_executor *executor,
+               const struct action_work_item *work_item,
+               const struct lttng_action *action_group)
+{
+       int ret = 0;
+       unsigned int i, count;
+       enum lttng_action_status action_status;
+
+       action_status = lttng_action_group_get_count(action_group, &count);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               /* Fatal error. */
+               ERR("Failed to get count of action in action group");
+               ret = -1;
+               goto end;
+       }
+
+       DBG("Action group has %u action%s", count, count != 1 ? "s" : "");
+       for (i = 0; i < count; i++) {
+               const struct lttng_action *action =
+                               lttng_action_group_get_at_index_const(
+                                               action_group, i);
+
+               ret = action_executor_generic_handler(
+                               executor, work_item, action);
+               if (ret) {
+                       ERR("Stopping the execution of the action group of trigger \"%s\" following a fatal error",
+                                       get_trigger_name(work_item->trigger));
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+static int action_executor_generic_handler(struct action_executor *executor,
+               const struct action_work_item *work_item,
+               const struct lttng_action *action)
+{
+       DBG("Executing action \"%s\" of trigger \"%s\" action work item %" PRIu64,
+                       get_action_name(action),
+                       get_trigger_name(work_item->trigger),
+                       work_item->id);
+
+       return action_executors[lttng_action_get_type(action)](
+                       executor, work_item, action);
+}
+
+static int action_work_item_execute(struct action_executor *executor,
+               struct action_work_item *work_item)
+{
+       int ret;
+       const struct lttng_action *action =
+                       lttng_trigger_get_const_action(work_item->trigger);
+
+       DBG("Starting execution of action work item %" PRIu64 " of trigger \"%s\"",
+                       work_item->id, get_trigger_name(work_item->trigger));
+       ret = action_executor_generic_handler(executor, work_item, action);
+       DBG("Completed execution of action work item %" PRIu64 " of trigger \"%s\"",
+                       work_item->id, get_trigger_name(work_item->trigger));
+       return ret;
+}
+
+static void action_work_item_destroy(struct action_work_item *work_item)
+{
+       lttng_trigger_put(work_item->trigger);
+       notification_client_list_put(work_item->client_list);
+       free(work_item);
+}
+
+static void *action_executor_thread(void *_data)
+{
+       struct action_executor *executor = _data;
+
+       assert(executor);
+
+       health_register(health_sessiond, HEALTH_SESSIOND_TYPE_ACTION_EXECUTOR);
+
+       rcu_register_thread();
+       rcu_thread_online();
+
+       DBG("Entering work execution loop");
+       pthread_mutex_lock(&executor->work.lock);
+       while (!executor->should_quit) {
+               int ret;
+               struct action_work_item *work_item;
+
+               health_code_update();
+               if (executor->work.pending_count == 0) {
+                       health_poll_entry();
+                       DBG("No work items enqueued, entering wait");
+                       pthread_cond_wait(&executor->work.cond,
+                                       &executor->work.lock);
+                       DBG("Woke-up from wait");
+                       health_poll_exit();
+                       continue;
+               }
+
+               /* Pop item from front of the listwith work lock held. */
+               work_item = cds_list_first_entry(&executor->work.list,
+                               struct action_work_item, list_node);
+               cds_list_del(&work_item->list_node);
+               executor->work.pending_count--;
+
+               /*
+                * Work can be performed without holding the work lock,
+                * allowing new items to be queued.
+                */
+               pthread_mutex_unlock(&executor->work.lock);
+               ret = action_work_item_execute(executor, work_item);
+               action_work_item_destroy(work_item);
+               if (ret) {
+                       /* Fatal error. */
+                       break;
+               }
+               health_code_update();
+               pthread_mutex_lock(&executor->work.lock);
+       }
+       pthread_mutex_unlock(&executor->work.lock);
+       DBG("Left work execution loop");
+
+       health_code_update();
+
+       rcu_thread_offline();
+       rcu_unregister_thread();
+       health_unregister(health_sessiond);
+
+       return NULL;
+}
+
+static bool shutdown_action_executor_thread(void *_data)
+{
+       struct action_executor *executor = _data;
+
+       /* TODO. */
+       executor->should_quit = true;
+       pthread_cond_signal(&executor->work.cond);
+       return true;
+}
+
+static void clean_up_action_executor_thread(void *_data)
+{
+       struct action_executor *executor = _data;
+
+       assert(cds_list_empty(&executor->work.list));
+
+       pthread_mutex_destroy(&executor->work.lock);
+       pthread_cond_destroy(&executor->work.cond);
+       free(executor);
+}
+
+struct action_executor *action_executor_create(
+               struct notification_thread_handle *handle)
+{
+       struct action_executor *executor = zmalloc(sizeof(*executor));
+
+       if (!executor) {
+               goto end;
+       }
+
+       CDS_INIT_LIST_HEAD(&executor->work.list);
+       pthread_cond_init(&executor->work.cond, NULL);
+       pthread_mutex_init(&executor->work.lock, NULL);
+       executor->notification_thread_handle = handle;
+
+       executor->thread = lttng_thread_create(THREAD_NAME,
+                       action_executor_thread, shutdown_action_executor_thread,
+                       clean_up_action_executor_thread, executor);
+end:
+       return executor;
+}
+
+void action_executor_destroy(struct action_executor *executor)
+{
+       struct action_work_item *work_item, *tmp;
+
+       /* TODO Wait for work list to drain? */
+       lttng_thread_shutdown(executor->thread);
+       pthread_mutex_lock(&executor->work.lock);
+       if (executor->work.pending_count != 0) {
+               WARN("%" PRIu64
+                       " trigger action%s still queued for execution and will be discarded",
+                               executor->work.pending_count,
+                               executor->work.pending_count == 1 ? " is" :
+                                                                   "s are");
+       }
+
+       cds_list_for_each_entry_safe (
+                       work_item, tmp, &executor->work.list, list_node) {
+               WARN("Discarding action work item %" PRIu64
+                               " associated to trigger \"%s\"",
+                               work_item->id, get_trigger_name(work_item->trigger));
+               cds_list_del(&work_item->list_node);
+               action_work_item_destroy(work_item);
+       }
+       pthread_mutex_unlock(&executor->work.lock);
+       lttng_thread_put(executor->thread);
+}
+
+/* RCU read-lock must be held by the caller. */
+enum action_executor_status action_executor_enqueue(
+               struct action_executor *executor,
+               struct lttng_trigger *trigger,
+               struct notification_client_list *client_list)
+{
+       enum action_executor_status executor_status = ACTION_EXECUTOR_STATUS_OK;
+       const uint64_t work_item_id = executor->next_work_item_id++;
+       struct action_work_item *work_item;
+       bool signal = false;
+
+       pthread_mutex_lock(&executor->work.lock);
+       /* Check for queue overflow. */
+       if (executor->work.pending_count >= MAX_QUEUED_WORK_COUNT) {
+               /* Most likely spammy, remove if it is the case. */
+               DBG("Refusing to enqueue action for trigger \"%s\" as work item %" PRIu64
+                   " (overflow)",
+                               get_trigger_name(trigger), work_item_id);
+               executor_status = ACTION_EXECUTOR_STATUS_OVERFLOW;
+               goto error_unlock;
+       }
+
+       work_item = zmalloc(sizeof(*work_item));
+       if (!work_item) {
+               PERROR("Failed to allocate action executor work item on behalf of trigger \"%s\"",
+                               get_trigger_name(trigger));
+               executor_status = ACTION_EXECUTOR_STATUS_ERROR;
+               goto error_unlock;
+       }
+
+       lttng_trigger_get(trigger);
+       if (client_list) {
+               const bool reference_acquired =
+                               notification_client_list_get(client_list);
+
+               assert(reference_acquired);
+       }
+
+       *work_item = (typeof(*work_item)){
+                       .id = work_item_id,
+                       .trigger = trigger,
+                       .client_list = client_list,
+                       .list_node = CDS_LIST_HEAD_INIT(work_item->list_node),
+       };
+       cds_list_add_tail(&work_item->list_node, &executor->work.list);
+       executor->work.pending_count++;
+       DBG("Enqueued action for trigger \"%s\" as work item %" PRIu64,
+                       get_trigger_name(trigger), work_item_id);
+       signal = true;
+
+error_unlock:
+       pthread_mutex_unlock(&executor->work.lock);
+       if (signal) {
+               pthread_cond_signal(&executor->work.cond);
+       }
+       return executor_status;
+}
diff --git a/src/bin/lttng-sessiond/action-executor.h b/src/bin/lttng-sessiond/action-executor.h
new file mode 100644 (file)
index 0000000..60a740d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef ACTION_EXECUTOR_H
+#define ACTION_EXECUTOR_H
+
+struct action_executor;
+struct notification_thread_handle;
+struct lttng_trigger;
+struct notification_client_list;
+
+enum action_executor_status {
+       ACTION_EXECUTOR_STATUS_OK,
+       ACTION_EXECUTOR_STATUS_OVERFLOW,
+       ACTION_EXECUTOR_STATUS_ERROR,
+       ACTION_EXECUTOR_STATUS_INVALID,
+};
+
+struct action_executor *action_executor_create(
+               struct notification_thread_handle *handle);
+
+void action_executor_destroy(struct action_executor *executor);
+
+enum action_executor_status action_executor_enqueue(
+       struct action_executor *executor,
+       struct lttng_trigger *trigger,
+       struct notification_client_list *list);
+
+#endif /* ACTION_EXECUTOR_H */
index c278ce95e506daabf779636b2544dc799181b38e..3587fd4713312a7f85d0c577adaadc6852cff418 100644 (file)
@@ -49,6 +49,8 @@ static void update_agent_app(struct agent_app *app)
 {
        struct ltt_session *session, *stmp;
        struct ltt_session_list *list;
+       struct agent *trigger_agent;
+       struct lttng_ht_iter iter;
 
        list = session_get_list();
        assert(list);
@@ -74,6 +76,14 @@ static void update_agent_app(struct agent_app *app)
                session_put(session);
        }
        session_unlock_list();
+
+       /* Do we need more locking here? maybe against trigger add? */
+       rcu_read_lock();
+       cds_lfht_for_each_entry (trigger_agents_ht_by_domain->ht, &iter.iter,
+                       trigger_agent, node.node) {
+               agent_update(trigger_agent, app->sock->fd);
+       }
+       rcu_read_unlock();
 }
 
 /*
index 1926b0820fc808f4076e12b8110a4ce5fe34cbae..0b95c4d1d1a1fc5ac283d2a66cbba2624b94d2e6 100644 (file)
 #include <urcu/uatomic.h>
 #include <urcu/rculist.h>
 
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/tracepoint.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/event-rule.h>
+
 #include <common/common.h>
 #include <common/sessiond-comm/agent.h>
 
@@ -101,7 +107,8 @@ no_match:
 }
 
 /*
- * Match function for the events hash table lookup by name and loglevel.
+ * Match function for the events hash table lookup by name, loglevel and
+ * filter_expression.
  */
 static int ht_match_event(struct cds_lfht_node *node,
                const void *_key)
@@ -682,6 +689,7 @@ int agent_enable_event(struct agent_event *event,
        }
 
        event->enabled = 1;
+       event->user_refcount++;
        ret = LTTNG_OK;
 
 error:
@@ -791,6 +799,17 @@ int agent_disable_event(struct agent_event *event,
                goto end;
        }
 
+       if (event->user_refcount - 1 != 0) {
+               /*
+                * Disable the agent event only when all users (trigger etc.)
+                * have disabled it.
+                */
+
+               event->user_refcount--;
+               ret = LTTNG_OK;
+               goto end;
+       }
+
        rcu_read_lock();
 
        cds_lfht_for_each_entry(agent_apps_ht_by_sock->ht, &iter.iter, app,
@@ -806,6 +825,7 @@ int agent_disable_event(struct agent_event *event,
                }
        }
 
+       event->user_refcount = 0;
        event->enabled = 0;
 
 error:
@@ -1206,6 +1226,66 @@ void agent_find_events_by_name(const char *name, struct agent *agt,
                        ht_match_event_by_name, &key, &iter->iter);
 }
 
+/*
+ * Find the agent event matching the trigger.
+ *
+ * RCU read side lock MUST be acquired. It must be kept for as long as
+ * the returned agent_event is used.
+ *
+ * Return object if found else NULL.
+ */
+struct agent_event *agent_find_event_by_trigger(
+               const struct lttng_trigger *trigger, struct agent *agt)
+{
+       enum lttng_condition_status c_status;
+       enum lttng_event_rule_status er_status;
+       enum lttng_domain_type d_type;
+       const struct lttng_condition *condition;
+       const struct lttng_event_rule *rule;
+       const char *name;
+       const char *filter_expression;
+       /* TODO validate if this is the unset value or no */
+       int loglevel_value = 0;
+       enum lttng_loglevel_type loglevel_type;
+
+       assert(agt);
+       assert(agt->events);
+
+       condition = lttng_trigger_get_const_condition(trigger);
+
+       assert(lttng_condition_get_type(condition) ==
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+
+       c_status = lttng_condition_event_rule_get_rule(condition, &rule);
+       assert(c_status == LTTNG_CONDITION_STATUS_OK);
+
+       assert(lttng_event_rule_get_type(rule) ==
+                       LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
+
+       d_type = lttng_event_rule_get_domain_type(rule);
+       assert(d_type == LTTNG_DOMAIN_JUL || d_type == LTTNG_DOMAIN_LOG4J ||
+                       d_type == LTTNG_DOMAIN_PYTHON);
+
+       /* Get the name (aka pattern) */
+       er_status = lttng_event_rule_tracepoint_get_pattern(rule, &name);
+       assert(er_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+       /* Get the internal filter_expression */
+       filter_expression = lttng_event_rule_get_filter(rule);
+
+       er_status = lttng_event_rule_tracepoint_get_loglevel_type(
+                       rule, &loglevel_type);
+       assert(er_status == LTTNG_EVENT_RULE_STATUS_OK);
+       if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+               er_status = lttng_event_rule_tracepoint_get_loglevel(
+                               rule, &loglevel_value);
+               assert(er_status == LTTNG_EVENT_RULE_STATUS_OK);
+       }
+
+       return agent_find_event(name, loglevel_type, loglevel_value,
+                       filter_expression, agt);
+}
+
 /*
  * Get the next agent event duplicate by name. This should be called
  * after a call to agent_find_events_by_name() to iterate on events.
@@ -1233,8 +1313,10 @@ void agent_event_next_duplicate(const char *name,
  * Return object if found else NULL.
  */
 struct agent_event *agent_find_event(const char *name,
-               enum lttng_loglevel_type loglevel_type, int loglevel_value,
-               char *filter_expression, struct agent *agt)
+               enum lttng_loglevel_type loglevel_type,
+               int loglevel_value,
+               const char *filter_expression,
+               struct agent *agt)
 {
        struct lttng_ht_node_str *node;
        struct lttng_ht_iter iter;
@@ -1347,6 +1429,21 @@ int agent_app_ht_alloc(void)
        return ret;
 }
 
+/*
+ * Allocate agent_apps_ht_by_sock.
+ */
+int trigger_agent_ht_alloc(void)
+{
+       int ret = 0;
+
+       trigger_agents_ht_by_domain = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       if (!trigger_agents_ht_by_domain) {
+               ret = -1;
+       }
+
+       return ret;
+}
+
 /*
  * Destroy a agent application by socket.
  */
@@ -1396,6 +1493,32 @@ void agent_app_ht_clean(void)
        lttng_ht_destroy(agent_apps_ht_by_sock);
 }
 
+/*
+ * Clean-up the trigger agent hash table and destroy it.
+ */
+void trigger_agent_ht_clean(void)
+{
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+
+       if (!trigger_agents_ht_by_domain) {
+               return;
+       }
+       rcu_read_lock();
+       cds_lfht_for_each_entry (trigger_agents_ht_by_domain->ht, &iter.iter,
+                       node, node) {
+               struct agent *agent;
+
+               (void) lttng_ht_del(trigger_agents_ht_by_domain, &iter);
+
+               agent = caa_container_of(node, struct agent, node);
+               agent_destroy(agent);
+       }
+       rcu_read_unlock();
+
+       lttng_ht_destroy(trigger_agents_ht_by_domain);
+}
+
 /*
  * Update a agent application (given socket) using the given agent.
  *
@@ -1449,3 +1572,27 @@ void agent_update(struct agent *agt, int sock)
 
        rcu_read_unlock();
 }
+
+struct agent *trigger_find_agent(enum lttng_domain_type domain_type)
+{
+       struct agent *agt = NULL;
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       uint64_t key;
+
+       assert(trigger_agents_ht_by_domain);
+
+       DBG3("Trigger agent lookup for domain %d", domain_type);
+
+       key = domain_type;
+
+       lttng_ht_lookup(trigger_agents_ht_by_domain, &key, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (!node) {
+               goto end;
+       }
+       agt = caa_container_of(node, struct agent, node);
+
+end:
+       return agt;
+}
index 2d2d6425559d2330904bd9d6c83eb24dbcba7872..ebb12628e15ebd08cae0981021991a3a193bd527 100644 (file)
  */
 extern struct lttng_ht *agent_apps_ht_by_sock;
 
+/*
+ * Hash table that contains the trigger agents by domain */
+extern struct lttng_ht *trigger_agents_ht_by_domain;
+
 struct agent_ht_key {
        const char *name;
        int loglevel_value;
        enum lttng_loglevel_type loglevel_type;
-       char *filter_expression;
+       const char *filter_expression;
 };
 
 /*
@@ -87,6 +91,12 @@ struct agent_event {
        struct lttng_filter_bytecode *filter;
        char *filter_expression;
        struct lttng_event_exclusion *exclusion;
+
+       /*
+        * Multiple triggers and events can use this agent event.
+        * The event can only be disabled when the count is zero.
+        */
+       unsigned int user_refcount;
 };
 
 /*
@@ -133,8 +143,10 @@ struct agent_event *agent_create_event(const char *name,
 void agent_add_event(struct agent_event *event, struct agent *agt);
 
 struct agent_event *agent_find_event(const char *name,
-               enum lttng_loglevel_type loglevel_type, int loglevel_value,
-               char *filter_expression, struct agent *agt);
+               enum lttng_loglevel_type loglevel_type,
+               int loglevel_value,
+               const char *filter_expression,
+               struct agent *agt);
 void agent_find_events_by_name(const char *name, struct agent *agt,
                struct lttng_ht_iter* iter);
 void agent_event_next_duplicate(const char *name,
@@ -167,4 +179,12 @@ void agent_update(struct agent *agt, int sock);
 int agent_list_events(struct lttng_event **events,
                enum lttng_domain_type domain);
 
+struct agent_event *agent_find_event_by_trigger(
+               const struct lttng_trigger *trigger, struct agent *agt);
+
+/* todo: find a better place for this */
+struct agent *trigger_find_agent(enum lttng_domain_type domain_type);
+void trigger_agent_ht_clean(void);
+int trigger_agent_ht_alloc(void);
+
 #endif /* LTTNG_SESSIOND_AGENT_H */
index ae0e020924b38b1929d97a1857c27eb382d5826a..e381514e063d39e6b2a75abe9762bc95248af62a 100644 (file)
@@ -30,6 +30,7 @@
 #include "utils.h"
 #include "manage-consumer.h"
 #include "clear.h"
+#include "agent-thread.h"
 
 static bool is_root;
 
@@ -182,7 +183,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data)
                case LTTNG_CONSUMER64_UST:
                {
                        if (config.consumerd64_lib_dir.value) {
-                               char *tmp;
+                               const char *tmp;
                                size_t tmplen;
                                char *tmpnew;
 
@@ -219,7 +220,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data)
                case LTTNG_CONSUMER32_UST:
                {
                        if (config.consumerd32_lib_dir.value) {
-                               char *tmp;
+                               const char *tmp;
                                size_t tmplen;
                                char *tmpnew;
 
@@ -532,7 +533,6 @@ static int receive_userspace_probe(struct command_ctx *cmd_ctx, int sock,
 {
        int fd, ret;
        struct lttng_userspace_probe_location *probe_location;
-       const struct lttng_userspace_probe_location_lookup_method *lookup = NULL;
        struct lttng_dynamic_buffer probe_location_buffer;
        struct lttng_buffer_view buffer_view;
 
@@ -592,30 +592,7 @@ static int receive_userspace_probe(struct command_ctx *cmd_ctx, int sock,
         * Set the file descriptor received from the client through the unix
         * socket in the probe location.
         */
-       lookup = lttng_userspace_probe_location_get_lookup_method(probe_location);
-       if (!lookup) {
-               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
-               goto error;
-       }
-
-       /*
-        * From the kernel tracer's perspective, all userspace probe event types
-        * are all the same: a file and an offset.
-        */
-       switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) {
-       case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
-               ret = lttng_userspace_probe_location_function_set_binary_fd(
-                               probe_location, fd);
-               break;
-       case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
-               ret = lttng_userspace_probe_location_tracepoint_set_binary_fd(
-                               probe_location, fd);
-               break;
-       default:
-               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
-               goto error;
-       }
-
+       ret = lttng_userspace_probe_location_set_binary_fd(probe_location, fd);
        if (ret) {
                ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
                goto error;
@@ -710,6 +687,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        int ret = LTTNG_OK;
        int need_tracing_session = 1;
        int need_domain;
+       int need_consumerd = 1;
 
        DBG("Processing client command %d", cmd_ctx->lsm->cmd_type);
 
@@ -733,19 +711,29 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        case LTTNG_SET_SESSION_SHM_PATH:
        case LTTNG_REGENERATE_METADATA:
        case LTTNG_REGENERATE_STATEDUMP:
-       case LTTNG_REGISTER_TRIGGER:
-       case LTTNG_UNREGISTER_TRIGGER:
        case LTTNG_ROTATE_SESSION:
        case LTTNG_ROTATION_GET_INFO:
        case LTTNG_ROTATION_SET_SCHEDULE:
        case LTTNG_SESSION_LIST_ROTATION_SCHEDULES:
        case LTTNG_CLEAR_SESSION:
+       case LTTNG_LIST_TRIGGERS:
                need_domain = 0;
                break;
        default:
                need_domain = 1;
        }
 
+       /* Needs a functioning consumerd */
+       switch (cmd_ctx->lsm->cmd_type) {
+       case LTTNG_REGISTER_TRIGGER:
+       case LTTNG_UNREGISTER_TRIGGER:
+               need_consumerd = 0;
+               break;
+       default:
+               need_consumerd = 1;
+               break;
+       }
+
        if (config.no_kernel && need_domain
                        && cmd_ctx->lsm->domain.type == LTTNG_DOMAIN_KERNEL) {
                if (!is_root) {
@@ -785,6 +773,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        case LTTNG_ROTATE_SESSION:
        case LTTNG_ROTATION_GET_INFO:
        case LTTNG_SESSION_LIST_ROTATION_SCHEDULES:
+       case LTTNG_REGISTER_TRIGGER:
+       case LTTNG_LIST_TRIGGERS:
                break;
        default:
                /* Setup lttng message with no payload */
@@ -805,6 +795,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        case LTTNG_SAVE_SESSION:
        case LTTNG_REGISTER_TRIGGER:
        case LTTNG_UNREGISTER_TRIGGER:
+       case LTTNG_LIST_TRIGGERS:
                need_tracing_session = 0;
                break;
        default:
@@ -883,7 +874,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
                }
 
                /* Consumer is in an ERROR state. Report back to client */
-               if (uatomic_read(&kernel_consumerd_state) == CONSUMER_ERROR) {
+               if (need_consumerd && uatomic_read(&kernel_consumerd_state) ==
+                                                     CONSUMER_ERROR) {
                        ret = LTTNG_ERR_NO_KERNCONSUMERD;
                        goto error;
                }
@@ -928,14 +920,21 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_LOG4J:
        case LTTNG_DOMAIN_PYTHON:
+               if (!agent_tracing_is_enabled()) {
+                       ret = LTTNG_ERR_AGENT_TRACING_DISABLED;
+                       goto error;
+               }
+               /* Fallthrough */
        case LTTNG_DOMAIN_UST:
        {
                if (!ust_app_supported()) {
                        ret = LTTNG_ERR_NO_UST;
                        goto error;
                }
+
                /* Consumer is in an ERROR state. Report back to client */
-               if (uatomic_read(&ust_consumerd_state) == CONSUMER_ERROR) {
+               if (need_consumerd && uatomic_read(&ust_consumerd_state) ==
+                                                     CONSUMER_ERROR) {
                        ret = LTTNG_ERR_NO_USTCONSUMERD;
                        goto error;
                }
@@ -1957,8 +1956,33 @@ error_add_context:
        }
        case LTTNG_REGISTER_TRIGGER:
        {
+               struct lttng_dynamic_buffer payload;
+               struct lttng_trigger *return_trigger;
+
+               lttng_dynamic_buffer_init(&payload);
                ret = cmd_register_trigger(cmd_ctx, *sock,
-                               notification_thread_handle);
+                               notification_thread_handle, &return_trigger);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
+               ret = lttng_trigger_serialize(return_trigger, &payload, NULL);
+               if (ret) {
+                       ERR("Failed to serialize trigger in reply to \"register trigger\" command");
+                       ret = LTTNG_ERR_NOMEM;
+                       lttng_trigger_destroy(return_trigger);
+                       goto error;
+               }
+               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, payload.data,
+                               payload.size);
+               if (ret) {
+                       lttng_trigger_destroy(return_trigger);
+                       ret = LTTNG_ERR_NOMEM;
+                       goto error;
+               }
+               lttng_trigger_destroy(return_trigger);
+               lttng_dynamic_buffer_reset(&payload);
+               ret = LTTNG_OK;
                break;
        }
        case LTTNG_UNREGISTER_TRIGGER:
@@ -2071,6 +2095,37 @@ error_add_context:
                ret = cmd_clear_session(cmd_ctx->session, sock);
                break;
        }
+       case LTTNG_LIST_TRIGGERS:
+       {
+               struct lttng_dynamic_buffer payload;
+               struct lttng_triggers *return_triggers;
+
+               lttng_dynamic_buffer_init(&payload);
+               ret = cmd_list_triggers(cmd_ctx, *sock,
+                               notification_thread_handle, &return_triggers);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
+               ret = lttng_triggers_serialize(return_triggers, &payload);
+               if (ret) {
+                       ERR("Failed to serialize triggers in reply to \"list triggers\" command");
+                       ret = LTTNG_ERR_NOMEM;
+                       lttng_triggers_destroy(return_triggers);
+                       goto error;
+               }
+               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, payload.data,
+                               payload.size);
+               if (ret) {
+                       ret = LTTNG_ERR_NOMEM;
+                       lttng_triggers_destroy(return_triggers);
+                       goto error;
+               }
+               lttng_dynamic_buffer_reset(&payload);
+               lttng_triggers_destroy(return_triggers);
+               ret = LTTNG_OK;
+               break;
+       }
        default:
                ret = LTTNG_ERR_UND;
                break;
index 5e522d6fe0886108b87df756e930a6519a5a8a09..f4c7390ef784d52d9371d982e78a68dab966e358 100644 (file)
 #include <lttng/location-internal.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/condition/condition.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/condition/event-rule-internal.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/uprobe-internal.h>
+#include <lttng/event-rule/tracepoint.h>
 #include <lttng/action/action.h>
 #include <lttng/channel.h>
 #include <lttng/channel-internal.h>
@@ -4283,8 +4290,94 @@ end:
        return ret;
 }
 
+/* TODO: is this the best place to perform this? (code wise) */
+/*
+ * Set sock to -1 if reception of more information is not necessary e.g on
+ * unregister. TODO find a better way.
+ *
+ * On success LTTNG_OK. On error, returns lttng_error code.
+ * */
+static enum lttng_error_code prepare_trigger_object(struct lttng_trigger *trigger, int sock)
+{
+       enum lttng_error_code ret;
+       /* Internal object of the trigger might have to "generate" and
+        * "populate" internal field e.g filter bytecode
+        */
+       struct lttng_condition *condition = NULL;
+       condition = lttng_trigger_get_condition(trigger);
+       if (!condition) {
+               ret = LTTNG_ERR_INVALID_TRIGGER;
+               goto end;
+       }
+
+       switch (lttng_condition_get_type(condition)) {
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       {
+               struct lttng_event_rule *event_rule;
+               const struct lttng_credentials *credential = lttng_trigger_get_credentials(trigger);
+               lttng_condition_event_rule_get_rule_no_const(
+                               condition, &event_rule);
+               ret = lttng_event_rule_populate(event_rule, credential->uid, credential->gid);
+               if (ret != LTTNG_OK) {
+                       goto end;
+               }
+
+               switch (lttng_event_rule_get_type(event_rule)) {
+               case LTTNG_EVENT_RULE_TYPE_UPROBE:
+               {
+                       int fd;
+                       struct lttng_userspace_probe_location *location = lttng_event_rule_uprobe_get_location_no_const(event_rule);
+
+                       if (sock < 0) {
+                               /* Nothing to receive */
+                               break;
+                       }
+                       /*
+                        * Receive the file descriptor to the target binary from
+                        * the client.
+                        */
+                       DBG("Receiving userspace probe target FD from client ...");
+                       ret = lttcomm_recv_fds_unix_sock(sock, &fd, 1);
+                       if (ret <= 0) {
+                               DBG("Nothing recv() from client userspace probe fd... continuing");
+                               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+                               goto end;
+                       }
+
+                       /*
+                        * Set the file descriptor received from the client
+                        * through the unix socket in the probe location.
+                        */
+                       ret = lttng_userspace_probe_location_set_binary_fd(
+                                       location, fd);
+                       if (ret) {
+                               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+                               goto end;
+                       }
+
+                       break;
+               }
+               default:
+                       /* Nothing to do */
+                       break;
+               }
+               ret = LTTNG_OK;
+               break;
+       }
+       default:
+       {
+               ret = LTTNG_OK;
+               break;
+       }
+       }
+end:
+       return ret;
+}
+
+/* Caller must call lttng_destroy_trigger on the returned trigger object */
 int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
-               struct notification_thread_handle *notification_thread)
+               struct notification_thread_handle *notification_thread,
+               struct lttng_trigger **return_trigger)
 {
        int ret;
        size_t trigger_len;
@@ -4318,9 +4411,95 @@ int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
                goto end;
        }
 
+       /* Set the trigger credential */
+       lttng_trigger_set_credentials(trigger, cmd_ctx->creds.uid, cmd_ctx->creds.gid);
+
+       /* Prepare internal trigger object if needed on reception.
+        * Handles also special treatment for certain internal object of the
+        * trigger (e.g uprobe event rule binary fd.
+        */
+       ret = prepare_trigger_object(trigger, sock);
+       if (ret != LTTNG_OK) {
+               goto end;
+       }
+
+       /*
+        * Since we return the trigger object, take a reference to it
+        * Caller is responsible for calling lttng_destroy_trigger on it.
+        * This thread does not OWN the trigger.
+        */
+       lttng_trigger_get(trigger);
+
+       /* Inform the notification thread */
        ret = notification_thread_command_register_trigger(notification_thread,
                        trigger);
-       /* Ownership of trigger was transferred. */
+       if (ret != LTTNG_OK) {
+               goto end;
+       }
+
+       /* Synchronize tracers, only if needed */
+       /* TODO: maybe extract somewhere else */
+       {
+               struct lttng_condition *condition = NULL;
+               condition = lttng_trigger_get_condition(trigger);
+               if (!condition) {
+                       ret = LTTNG_ERR_INVALID_TRIGGER;
+                       goto end;
+               }
+
+               if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+                       const struct lttng_event_rule *rule = NULL;
+                       (void) lttng_condition_event_rule_get_rule(condition, &rule);
+                       if (!rule) {
+                               ret = LTTNG_ERR_INVALID_TRIGGER;
+                               goto end;
+                       }
+                       if (lttng_event_rule_get_domain_type(rule) == LTTNG_DOMAIN_KERNEL) {
+                               /* TODO: get the token value from the
+                                * notification thread and only perform an
+                                * enable and a disable.... This is NOT
+                                * OPTIMIZED AT ALL
+                                */
+                               kernel_update_tokens();
+                       } else {
+                               /* TODO: get the token value from the
+                                * notification thread and only perform an
+                                * enable and a disable.... This is NOT
+                                * OPTIMIZED AT ALL
+                                */
+                               ust_app_global_update_all_tokens();
+                               /* Agent handling */
+                               if (lttng_event_rule_is_agent(rule)) {
+                                       struct agent *agt;
+                                       const char *pattern;
+                                       enum lttng_domain_type domain_type;
+                                       domain_type = lttng_event_rule_get_domain_type(
+                                                       rule);
+                                       (void) lttng_event_rule_tracepoint_get_pattern(
+                                                       rule, &pattern);
+                                       agt = trigger_find_agent(domain_type);
+                                       if (!agt) {
+                                               agt = agent_create(domain_type);
+                                               if (!agt) {
+                                                       ret = LTTNG_ERR_NOMEM;
+                                                       goto end;
+                                               }
+                                               agent_add(agt, trigger_agents_ht_by_domain);
+                                       }
+
+                                       ret = trigger_agent_enable(
+                                                       trigger, agt);
+                                       if (ret != LTTNG_OK) {
+                                               goto end;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* Return an image of the updated object to the client */
+       *return_trigger = trigger;
+       /* Ownership of trigger was transferred to caller. */
        trigger = NULL;
 end:
        lttng_trigger_destroy(trigger);
@@ -4363,14 +4542,110 @@ int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock,
                goto end;
        }
 
+       lttng_trigger_set_credentials(trigger, cmd_ctx->creds.uid, cmd_ctx->creds.gid);
+
+       /* TODO: forgotting this bited me for agent since the filter is
+        * genereted on this side. Wonder if we could find a way to detect when
+        * do it or not.
+        */
+
+       /* Prepare internal trigger object if needed on reception.
+        * Handles also special treatment for certain internal object of the
+        * trigger (e.g uprobe event rule binary fd.
+        */
+       ret = prepare_trigger_object(trigger, -1);
+       if (ret != LTTNG_OK) {
+               goto end;
+       }
+
        ret = notification_thread_command_unregister_trigger(notification_thread,
                        trigger);
+
+       /* Synchronize tracers, only if needed */
+       /* TODO: maybe extract somewhere else */
+       {
+               struct lttng_condition *condition = NULL;
+               condition = lttng_trigger_get_condition(trigger);
+               if (!condition) {
+                       ret = LTTNG_ERR_INVALID_TRIGGER;
+                       goto end;
+               }
+
+               if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+                       const struct lttng_event_rule *rule = NULL;
+                       (void) lttng_condition_event_rule_get_rule(condition, &rule);
+                       if (!rule) {
+                               ret = LTTNG_ERR_INVALID_TRIGGER;
+                               goto end;
+                       }
+                       if (lttng_event_rule_get_domain_type(rule) == LTTNG_DOMAIN_KERNEL) {
+                               /* TODO: get the token value from the
+                                * notification thread and only perform an
+                                * enable and a disable.... This is NOT
+                                * OPTIMIZED AT ALL
+                                */
+                               kernel_update_tokens();
+                       } else {
+                               /* TODO: get the token value from the
+                                * notification thread and only perform an
+                                * enable and a disable.... This is NOT
+                                * OPTIMIZED AT ALL
+                                */
+                               ust_app_global_update_all_tokens();
+                               if (lttng_event_rule_is_agent(rule)) {
+                                       struct agent *agt;
+                                       const char *pattern;
+                                       enum lttng_domain_type domain_type;
+
+                                       domain_type = lttng_event_rule_get_domain_type(
+                                                       rule);
+                                       (void) lttng_event_rule_tracepoint_get_pattern(
+                                                       rule, &pattern);
+
+                                       agt = trigger_find_agent(domain_type);
+                                       if (!agt) {
+                                               ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
+                                               goto end;
+                                       }
+                                       ret = trigger_agent_disable(
+                                                       trigger, agt);
+                                       if (ret != LTTNG_OK) {
+                                               goto end;
+                                       }
+                               }
+                       }
+               }
+       }
+
 end:
        lttng_trigger_destroy(trigger);
        lttng_dynamic_buffer_reset(&trigger_buffer);
        return ret;
 }
 
+int cmd_list_triggers(struct command_ctx *cmd_ctx, int sock,
+               struct notification_thread_handle *notification_thread,
+               struct lttng_triggers **return_triggers)
+{
+       int ret = 0;
+       enum lttng_error_code ret_code;
+       struct lttng_triggers *triggers = NULL;
+
+       /* Get list of token trigger from the notification thread here */
+       ret_code = notification_thread_command_list_triggers(notification_thread_handle, cmd_ctx->creds.uid, cmd_ctx->creds.gid, &triggers);
+       if (ret_code != LTTNG_OK) {
+               ret = ret_code;
+               goto end;
+       }
+
+       /* Return a "view" of the current triggers */
+       *return_triggers = triggers;
+       triggers = NULL;
+       ret = LTTNG_OK;
+end:
+       lttng_triggers_destroy(triggers);
+       return ret;
+}
 /*
  * Send relayd sockets from snapshot output to consumer. Ignore request if the
  * snapshot output is *not* set with a remote destination.
index 23d9d5e026e0496ac31591f637e495873d7a8f31..76052100d32e05c388479d54e8dd283751a9268d 100644 (file)
@@ -125,10 +125,15 @@ int cmd_regenerate_metadata(struct ltt_session *session);
 int cmd_regenerate_statedump(struct ltt_session *session);
 
 int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
-               struct notification_thread_handle *notification_thread_handle);
+               struct notification_thread_handle *notification_thread_handle,
+               struct lttng_trigger **return_trigger);
 int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock,
                struct notification_thread_handle *notification_thread_handle);
 
+int cmd_list_triggers(struct command_ctx *cmd_ctx, int sock,
+               struct notification_thread_handle *notification_thread_handle,
+               struct lttng_triggers **return_triggers);
+
 int cmd_rotate_session(struct ltt_session *session,
                struct lttng_rotate_session_return *rotate_return,
                bool quiet_rotation,
index 4fe3dfce70e40d22a05d361e3071e8966e610258..ea147ddf82f81c170a3789f930c6945ec875dd02 100644 (file)
@@ -36,6 +36,7 @@ static void update_ust_app(int app_sock)
 {
        struct ltt_session *sess, *stmp;
        const struct ltt_session_list *session_list = session_get_list();
+       struct ust_app *app;
 
        /* Consumer is in an ERROR state. Stop any application update. */
        if (uatomic_read(&ust_consumerd_state) == CONSUMER_ERROR) {
@@ -43,10 +44,25 @@ static void update_ust_app(int app_sock)
                return;
        }
 
+       rcu_read_lock();
+       assert(app_sock >= 0);
+       app = ust_app_find_by_sock(app_sock);
+       if (app == NULL) {
+               /*
+                * Application can be unregistered before so
+                * this is possible hence simply stopping the
+                * update.
+                */
+               DBG3("UST app update failed to find app sock %d",
+                       app_sock);
+               goto unlock_rcu;
+       }
+
+       /* Update all tokens for the app */
+       ust_app_global_update_tokens(app);
+
        /* For all tracing session(s) */
        cds_list_for_each_entry_safe(sess, stmp, &session_list->head, list) {
-               struct ust_app *app;
-
                if (!session_get(sess)) {
                        continue;
                }
@@ -55,26 +71,14 @@ static void update_ust_app(int app_sock)
                        goto unlock_session;
                }
 
-               rcu_read_lock();
-               assert(app_sock >= 0);
-               app = ust_app_find_by_sock(app_sock);
-               if (app == NULL) {
-                       /*
-                        * Application can be unregistered before so
-                        * this is possible hence simply stopping the
-                        * update.
-                        */
-                       DBG3("UST app update failed to find app sock %d",
-                               app_sock);
-                       goto unlock_rcu;
-               }
                ust_app_global_update(sess->ust_session, app);
-       unlock_rcu:
-               rcu_read_unlock();
        unlock_session:
                session_unlock(sess);
                session_put(sess);
        }
+
+unlock_rcu:
+       rcu_read_unlock();
 }
 
 /*
@@ -386,6 +390,8 @@ static void *thread_dispatch_ust_registration(void *data)
                                /* Set app version. This call will print an error if needed. */
                                (void) ust_app_version(app);
 
+                               (void) ust_app_setup_trigger_group(app);
+
                                /* Send notify socket through the notify pipe. */
                                ret = send_socket_to_thread(
                                                notifiers->apps_cmd_notify_pipe_write_fd,
index 189236beb1171a05ba21e89b3ecb51216a7b5e47..6a7545dc0d982d84c361f8307e016ae5765ed2e3 100644 (file)
 #include <string.h>
 
 #include <lttng/lttng.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
 #include <common/error.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <common/filter.h>
@@ -27,6 +31,7 @@
 #include "trace-kernel.h"
 #include "trace-ust.h"
 #include "agent.h"
+#include "utils.h"
 
 /*
  * Add unique UST event based on the event name, filter bytecode and loglevel.
@@ -366,6 +371,20 @@ error:
        return ret;
 }
 
+static void agent_enable_all(struct agent *agt)
+{
+       struct agent_event *aevent;
+       struct lttng_ht_iter iter;
+
+       /* Flag every event that they are now enabled. */
+       rcu_read_lock();
+       cds_lfht_for_each_entry (
+                       agt->events->ht, &iter.iter, aevent, node.node) {
+               aevent->enabled = 1;
+       }
+       rcu_read_unlock();
+}
+
 /*
  * Enable all agent event for a given UST session.
  *
@@ -376,8 +395,6 @@ int event_agent_enable_all(struct ltt_ust_session *usess,
                struct lttng_filter_bytecode *filter ,char *filter_expression)
 {
        int ret;
-       struct agent_event *aevent;
-       struct lttng_ht_iter iter;
 
        assert(usess);
 
@@ -389,13 +406,7 @@ int event_agent_enable_all(struct ltt_ust_session *usess,
                goto error;
        }
 
-       /* Flag every event that they are now enabled. */
-       rcu_read_lock();
-       cds_lfht_for_each_entry(agt->events->ht, &iter.iter, aevent,
-                       node.node) {
-               aevent->enabled = 1;
-       }
-       rcu_read_unlock();
+       agent_enable_all(agt);
 
        ret = LTTNG_OK;
 
@@ -467,28 +478,17 @@ end:
        return ret;
 }
 
-/*
- * Enable a single agent event for a given UST session.
- *
- * Return LTTNG_OK on success or else a LTTNG_ERR* code.
- */
-int event_agent_enable(struct ltt_ust_session *usess,
-               struct agent *agt, struct lttng_event *event,
+static int agent_enable(struct agent *agt,
+               struct lttng_event *event,
                struct lttng_filter_bytecode *filter,
                char *filter_expression)
 {
        int ret, created = 0;
        struct agent_event *aevent;
 
-       assert(usess);
        assert(event);
        assert(agt);
 
-       DBG("Event agent enabling %s for session %" PRIu64 " with loglevel type %d "
-                       ", loglevel %d and filter \"%s\"", event->name,
-                       usess->id, event->loglevel_type, event->loglevel,
-                       filter_expression ? filter_expression : "NULL");
-
        aevent = agent_find_event(event->name, event->loglevel_type,
                        event->loglevel, filter_expression, agt);
        if (!aevent) {
@@ -542,6 +542,113 @@ end:
        return ret;
 }
 
+/*
+ * Enable a single agent event for a given UST session.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int event_agent_enable(struct ltt_ust_session *usess,
+               struct agent *agt,
+               struct lttng_event *event,
+               struct lttng_filter_bytecode *filter,
+               char *filter_expression)
+{
+       assert(usess);
+       assert(event);
+       assert(agt);
+
+       DBG("Event agent enabling %s for session %" PRIu64
+           " with loglevel type %d "
+           ", loglevel %d and filter \"%s\"",
+                       event->name, usess->id, event->loglevel_type,
+                       event->loglevel,
+                       filter_expression ? filter_expression : "NULL");
+
+       return agent_enable(agt, event, filter, filter_expression);
+}
+
+/*
+ * Enable a single agent event for a trigger.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int trigger_agent_enable(const struct lttng_trigger *trigger, struct agent *agt)
+{
+       int ret;
+       enum lttng_condition_status c_status;
+       enum lttng_domain_type d_type;
+       const struct lttng_condition *condition;
+       const struct lttng_event_rule *rule;
+       const char *filter_expression;
+       char *filter_expression_copy = NULL;
+       const struct lttng_filter_bytecode *filter_bytecode;
+       struct lttng_filter_bytecode *filter_bytecode_copy = NULL;
+       struct lttng_event *event = NULL;
+
+       assert(trigger);
+       assert(agt);
+
+       condition = lttng_trigger_get_const_condition(trigger);
+
+       assert(lttng_condition_get_type(condition) ==
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+
+       c_status = lttng_condition_event_rule_get_rule(condition, &rule);
+       assert(c_status == LTTNG_CONDITION_STATUS_OK);
+
+       assert(lttng_event_rule_get_type(rule) ==
+                       LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
+
+       d_type = lttng_event_rule_get_domain_type(rule);
+       assert(d_type == agt->domain);
+
+       event = lttng_event_rule_generate_lttng_event(rule);
+       if (!event) {
+               ret = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Get the internal filter_expression and bytecode */
+       filter_expression = lttng_event_rule_get_filter(rule);
+       if (filter_expression) {
+               filter_expression_copy = strdup(filter_expression);
+               if (!filter_expression_copy) {
+                       ret = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Get the filter bytecode */
+               filter_bytecode = lttng_event_rule_get_filter_bytecode(rule);
+               if (filter_bytecode) {
+                       filter_bytecode_copy =
+                                       copy_filter_bytecode(filter_bytecode);
+                       if (!filter_bytecode_copy) {
+                               ret = LTTNG_ERR_NOMEM;
+                               goto end;
+                       }
+               }
+       }
+
+       DBG("Event agent enabling %s for trigger %" PRIu64
+           " with loglevel type %d "
+           ", loglevel %d and filter \"%s\"",
+                       event->name, lttng_trigger_get_key(trigger),
+                       event->loglevel_type, event->loglevel,
+                       filter_expression ? filter_expression : "NULL");
+
+       ret = agent_enable(agt, event, filter_bytecode_copy,
+                       filter_expression_copy);
+       /* Ownership was passed even in case of error */
+       filter_expression_copy = NULL;
+       filter_bytecode_copy = NULL;
+
+end:
+       free(filter_expression_copy);
+       free(filter_bytecode_copy);
+       free(event);
+       return ret;
+}
+
 /*
  * Return the default event name associated with the provided UST domain. Return
  * NULL on error.
@@ -567,6 +674,43 @@ const char *event_get_default_agent_ust_name(enum lttng_domain_type domain)
        return default_event_name;
 }
 
+static int trigger_agent_disable_one(const struct lttng_trigger *trigger,
+               struct agent *agt,
+               struct agent_event *aevent)
+
+{
+       int ret;
+
+       assert(agt);
+       assert(trigger);
+       assert(aevent);
+
+       /*
+        * Actual ust event un-registration happens on the trigger
+        * un-registration at that point.
+        */
+
+       DBG("Event agent disabling %s (loglevel type %d, loglevel value %d) for trigger %" PRIu64,
+                       aevent->name, aevent->loglevel_type,
+                       aevent->loglevel_value, lttng_trigger_get_key(trigger));
+
+       /* Already disabled? */
+       if (!aevent->enabled) {
+               goto end;
+       }
+
+       ret = agent_disable_event(aevent, agt->domain);
+       if (ret != LTTNG_OK) {
+               goto error;
+       }
+
+end:
+       return LTTNG_OK;
+
+error:
+       return ret;
+}
+
 /*
  * Disable a given agent event for a given UST session.
  *
@@ -659,6 +803,44 @@ error:
        return ret;
 }
 
+/*
+ * Disable agent event matching a given trigger.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int trigger_agent_disable(
+               const struct lttng_trigger *trigger, struct agent *agt)
+{
+       int ret = LTTNG_OK;
+       struct agent_event *aevent;
+
+       assert(trigger);
+       assert(agt);
+
+       DBG("Event agent disabling for trigger %" PRIu64,
+                       lttng_trigger_get_key(trigger));
+
+       rcu_read_lock();
+       aevent = agent_find_event_by_trigger(trigger, agt);
+
+       if (aevent == NULL) {
+               DBG2("Event agent NOT found by trigger %" PRIu64,
+                               lttng_trigger_get_key(trigger));
+               ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
+               goto end;
+       }
+
+       ret = trigger_agent_disable_one(trigger, agt, aevent);
+
+       if (ret != LTTNG_OK) {
+               goto end;
+       }
+
+end:
+       rcu_read_unlock();
+       return ret;
+}
+
 /*
  * Disable all agent events matching a given name for a given UST session.
  *
index 1c646db37b7d4d7956d1bc50303ed1032415ac3f..c7a849c0b3d46017d4660ed217a2fcd6e348eafb 100644 (file)
@@ -42,6 +42,11 @@ int event_agent_disable(struct ltt_ust_session *usess, struct agent *agt,
                const char *event_name);
 int event_agent_disable_all(struct ltt_ust_session *usess, struct agent *agt);
 
+int trigger_agent_enable(
+               const struct lttng_trigger *trigger, struct agent *agt);
+int trigger_agent_disable(
+               const struct lttng_trigger *trigger, struct agent *agt);
+
 const char *event_get_default_agent_ust_name(enum lttng_domain_type domain);
 
 #endif /* _LTT_EVENT_H */
index 20aa790a7540d4dcfd0adbb8897a7da81ff47582..6e111b63b2755fb72c63f6f022f7e72b2d36d37e 100644 (file)
@@ -20,8 +20,12 @@ long page_size;
 struct health_app *health_sessiond;
 
 struct notification_thread_handle *notification_thread_handle;
+pthread_mutex_t notification_trigger_tokens_ht_lock = PTHREAD_MUTEX_INITIALIZER;
 
 struct lttng_ht *agent_apps_ht_by_sock = NULL;
+struct lttng_ht *trigger_agents_ht_by_domain = NULL;
+
+struct lttng_ht *registered_ust_event_rule = NULL;
 
 struct lttng_kernel_tracer_version kernel_tracer_version;
 struct lttng_kernel_tracer_abi_version kernel_tracer_abi_version;
index 7c9dbd0b3218d6c0f3cbc7c9f24d9060ed106390..b541822f87081ed47b8d7d551cabdb728d516992 100644 (file)
@@ -23,6 +23,7 @@ enum health_type_sessiond {
        HEALTH_SESSIOND_TYPE_NOTIFICATION       = 8,
        HEALTH_SESSIOND_TYPE_ROTATION           = 9,
        HEALTH_SESSIOND_TYPE_TIMER              = 10,
+       HEALTH_SESSIOND_TYPE_ACTION_EXECUTOR    = 11,
 
        NR_HEALTH_SESSIOND_TYPES,
 };
index 4ee4bea64ff630abae9617624f86ce21cc87950d..646da3ba83affd3463a30dd7e2efb7a43b05535c 100644 (file)
 #include <sys/types.h>
 
 #include <common/common.h>
+#include <common/hashtable/utils.h>
 #include <common/trace-chunk.h>
 #include <common/kernel-ctl/kernel-ctl.h>
 #include <common/kernel-ctl/kernel-ioctl.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 
+#include <lttng/userspace-probe.h>
+#include <lttng/userspace-probe-internal.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/condition/event-rule-internal.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/uprobe-internal.h>
+
 #include "lttng-sessiond.h"
 #include "lttng-syscall.h"
 #include "consumer.h"
@@ -29,6 +38,7 @@
 #include "utils.h"
 #include "rotate.h"
 #include "modprobe.h"
+#include "notification-thread-commands.h"
 
 /*
  * Key used to reference a channel between the sessiond and the consumer. This
@@ -39,9 +49,10 @@ static uint64_t next_kernel_channel_key;
 static const char *module_proc_lttng = "/proc/lttng";
 
 static int kernel_tracer_fd = -1;
+static int kernel_tracer_trigger_group_fd = -1;
+static int kernel_tracer_trigger_group_notification_fd = -1;
+static struct ltt_kernel_token_event_rule_list kernel_tracer_token_list;
 
-#include <lttng/userspace-probe.h>
-#include <lttng/userspace-probe-internal.h>
 /*
  * Add context on a kernel channel.
  *
@@ -213,6 +224,44 @@ error:
        return -1;
 }
 
+/*
+ * Create a kernel channel, register it to the kernel tracer and add it to the
+ * kernel session.
+ */
+static
+int kernel_create_trigger_group(int *trigger_group_fd)
+{
+       int ret;
+       int local_fd = -1;
+
+       assert(trigger_group_fd);
+
+       /* Kernel tracer channel creation */
+       ret = kernctl_create_trigger_group(kernel_tracer_fd);
+       if (ret < 0) {
+               PERROR("ioctl kernel create trigger group");
+               ret = -1;
+               goto error;
+       }
+
+       /* Store locally */
+       local_fd = ret;
+
+       /* Prevent fd duplication after execlp() */
+       ret = fcntl(local_fd, F_SETFD, FD_CLOEXEC);
+       if (ret < 0) {
+               PERROR("fcntl session fd");
+       }
+
+       DBG("Kernel trigger group created (fd: %d)",
+                       local_fd);
+       ret = 0;
+
+error:
+       *trigger_group_fd = local_fd;
+       return ret;
+}
+
 /*
  * Compute the offset of the instrumentation byte in the binary based on the
  * function probe location using the ELF lookup method.
@@ -224,7 +273,7 @@ error:
 static
 int extract_userspace_probe_offset_function_elf(
                const struct lttng_userspace_probe_location *probe_location,
-               struct ltt_kernel_session *session, uint64_t *offset)
+               uid_t uid, gid_t gid, uint64_t *offset)
 {
        int fd;
        int ret = 0;
@@ -261,8 +310,7 @@ int extract_userspace_probe_offset_function_elf(
                goto end;
        }
 
-       ret = run_as_extract_elf_symbol_offset(fd, symbol, session->uid,
-                       session->gid, offset);
+       ret = run_as_extract_elf_symbol_offset(fd, symbol, uid, gid, offset);
        if (ret < 0) {
                DBG("userspace probe offset calculation failed for "
                                "function %s", symbol);
@@ -286,7 +334,7 @@ end:
 static
 int extract_userspace_probe_offset_tracepoint_sdt(
                const struct lttng_userspace_probe_location *probe_location,
-               struct ltt_kernel_session *session, uint64_t **offsets,
+               uid_t uid, gid_t gid, uint64_t **offsets,
                uint32_t *offsets_count)
 {
        enum lttng_userspace_probe_location_lookup_method_type lookup_method_type;
@@ -332,7 +380,7 @@ int extract_userspace_probe_offset_tracepoint_sdt(
        }
 
        ret = run_as_extract_sdt_probe_offsets(fd, provider_name, probe_name,
-                       session->uid, session->gid, offsets, offsets_count);
+                       uid, gid, offsets, offsets_count);
        if (ret < 0) {
                DBG("userspace probe offset calculation failed for sdt "
                                "probe %s:%s", provider_name, probe_name);
@@ -353,29 +401,16 @@ end:
        return ret;
 }
 
-/*
- * Extract the offsets of the instrumentation point for the different lookup
- * methods.
- */
 static
-int userspace_probe_add_callsites(struct lttng_event *ev,
-                       struct ltt_kernel_session *session, int fd)
+int userspace_probe_add_callsite(
+               const struct lttng_userspace_probe_location *location,
+               uid_t uid, gid_t gid, int fd)
 {
        const struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
        enum lttng_userspace_probe_location_lookup_method_type type;
-       const struct lttng_userspace_probe_location *location = NULL;
        int ret;
 
-       assert(ev);
-       assert(ev->type == LTTNG_EVENT_USERSPACE_PROBE);
-
-       location = lttng_event_get_userspace_probe_location(ev);
-       if (!location) {
-               ret = -1;
-               goto end;
-       }
-       lookup_method =
-                       lttng_userspace_probe_location_get_lookup_method(location);
+       lookup_method = lttng_userspace_probe_location_get_lookup_method(location);
        if (!lookup_method) {
                ret = -1;
                goto end;
@@ -388,7 +423,8 @@ int userspace_probe_add_callsites(struct lttng_event *ev,
                struct lttng_kernel_event_callsite callsite;
                uint64_t offset;
 
-               ret = extract_userspace_probe_offset_function_elf(location, session, &offset);
+               ret = extract_userspace_probe_offset_function_elf(location,
+                               uid, gid, &offset);
                if (ret) {
                        ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
                        goto end;
@@ -397,8 +433,7 @@ int userspace_probe_add_callsites(struct lttng_event *ev,
                callsite.u.uprobe.offset = offset;
                ret = kernctl_add_callsite(fd, &callsite);
                if (ret) {
-                       WARN("Adding callsite to userspace probe "
-                                       "event %s failed.", ev->name);
+                       WARN("Adding callsite to ELF userspace probe failed.");
                        ret = LTTNG_ERR_KERN_ENABLE_FAIL;
                        goto end;
                }
@@ -415,8 +450,8 @@ int userspace_probe_add_callsites(struct lttng_event *ev,
                 * This call allocates the offsets buffer. This buffer must be freed
                 * by the caller
                 */
-               ret = extract_userspace_probe_offset_tracepoint_sdt(location, session,
-                               &offsets, &offsets_count);
+               ret = extract_userspace_probe_offset_tracepoint_sdt(location,
+                               uid, gid, &offsets, &offsets_count);
                if (ret) {
                        ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
                        goto end;
@@ -425,8 +460,8 @@ int userspace_probe_add_callsites(struct lttng_event *ev,
                        callsite.u.uprobe.offset = offsets[i];
                        ret = kernctl_add_callsite(fd, &callsite);
                        if (ret) {
-                               WARN("Adding callsite to userspace probe "
-                                               "event %s failed.", ev->name);
+                               WARN("Adding callsite to SDT userspace probe "
+                                       "failed.");
                                ret = LTTNG_ERR_KERN_ENABLE_FAIL;
                                free(offsets);
                                goto end;
@@ -443,6 +478,71 @@ end:
        return ret;
 }
 
+/*
+ * Extract the offsets of the instrumentation point for the different lookup
+ * methods.
+ */
+static
+int userspace_probe_event_add_callsites(struct lttng_event *ev,
+                       struct ltt_kernel_session *session, int fd)
+{
+       const struct lttng_userspace_probe_location *location = NULL;
+       int ret;
+
+       assert(ev);
+       assert(ev->type == LTTNG_EVENT_USERSPACE_PROBE);
+
+       location = lttng_event_get_userspace_probe_location(ev);
+       if (!location) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = userspace_probe_add_callsite(location, session->uid, session->gid,
+               fd);
+       if (ret) {
+               WARN("Adding callsite to userspace probe event \"%s\" "
+                       "failed.", ev->name);
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Extract the offsets of the instrumentation point for the different lookup
+ * methods.
+ */
+static int userspace_probe_event_rule_add_callsites(
+               const struct lttng_event_rule *rule,
+               const struct lttng_credentials *creds,
+               int fd)
+{
+       const struct lttng_userspace_probe_location *location = NULL;
+       enum lttng_event_rule_status status;
+       int ret;
+
+       assert(rule);
+       assert(creds);
+       assert(lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_UPROBE);
+
+       status = lttng_event_rule_uprobe_get_location(rule, &location);
+       if (status != LTTNG_EVENT_RULE_STATUS_OK || !location) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = userspace_probe_add_callsite(location, creds->uid, creds->gid,
+               fd);
+       if (ret) {
+               WARN("Adding callsite to userspace probe object %d"
+                       "failed.", fd);
+       }
+
+end:
+       return ret;
+}
+
 /*
  * Create a kernel event, enable it to the kernel tracer and add it to the
  * channel event list of the kernel session.
@@ -512,7 +612,8 @@ int kernel_create_event(struct lttng_event *ev,
        }
 
        if (ev->type == LTTNG_EVENT_USERSPACE_PROBE) {
-               ret = userspace_probe_add_callsites(ev, channel->session, event->fd);
+               ret = userspace_probe_event_add_callsites(ev, channel->session,
+                       event->fd);
                if (ret) {
                        goto add_callsite_error;
                }
@@ -669,6 +770,36 @@ error:
        return ret;
 }
 
+/*
+ * Disable a kernel trigger.
+ */
+int kernel_disable_token_event_rule(struct ltt_kernel_token_event_rule *event)
+{
+       int ret;
+
+       assert(event);
+
+       ret = kernctl_disable(event->fd);
+       if (ret < 0) {
+               switch (-ret) {
+               case EEXIST:
+                       ret = LTTNG_ERR_KERN_EVENT_EXIST;
+                       break;
+               default:
+                       PERROR("disable kernel event");
+                       break;
+               }
+               goto error;
+       }
+
+       event->enabled = 0;
+       DBG("Kernel trigger token %" PRIu64" disabled (fd: %d)", event->token, event->fd);
+
+       return 0;
+
+error:
+       return ret;
+}
 static struct lttng_tracker_list *get_id_tracker_list(
                struct ltt_kernel_session *session,
                enum lttng_tracker_type tracker_type)
@@ -1732,20 +1863,37 @@ int init_kernel_tracer(void)
        if (ret < 0) {
                goto error_modules;
        }
-
        if (ret < 1) {
                WARN("Kernel tracer does not support buffer monitoring. "
                        "The monitoring timer of channels in the kernel domain "
                        "will be set to 0 (disabled).");
        }
 
+       ret = kernel_create_trigger_group(&kernel_tracer_trigger_group_fd);
+       if (ret < 0) {
+               /* TODO: error handling if it is not supported etc. */
+               WARN("Failed trigger group creation");
+               kernel_tracer_trigger_group_fd = -1;
+               /* This is not fatal */
+       } else {
+               ret = kernel_create_trigger_group_notification_fd(&kernel_tracer_trigger_group_notification_fd);
+               if (ret < 0) {
+                       goto error_modules;
+               }
+       }
+
+       CDS_INIT_LIST_HEAD(&kernel_tracer_token_list.head);
+
        DBG("Kernel tracer fd %d", kernel_tracer_fd);
+       DBG("Kernel tracer trigger group fd %d", kernel_tracer_trigger_group_fd);
+       DBG("Kernel tracer trigger group notificationi fd %d", kernel_tracer_trigger_group_notification_fd);
 
        ret = syscall_init_table(kernel_tracer_fd);
        if (ret < 0) {
                ERR("Unable to populate syscall table. Syscall tracing won't "
                        "work for this session daemon.");
        }
+
        return 0;
 
 error_version:
@@ -1781,6 +1929,31 @@ void cleanup_kernel_tracer(void)
 {
        int ret;
 
+       struct ltt_kernel_token_event_rule *rule, *rtmp;
+        cds_list_for_each_entry_safe(rule, rtmp, &kernel_tracer_token_list.head, list) {
+               kernel_disable_token_event_rule(rule);
+               trace_kernel_destroy_token_event_rule(rule);
+       }
+
+       DBG2("Closing kernel trigger group notification fd");
+       if (kernel_tracer_trigger_group_notification_fd >= 0) {
+               ret = close(kernel_tracer_trigger_group_notification_fd);
+               if (ret) {
+                       PERROR("close");
+               }
+               kernel_tracer_trigger_group_notification_fd = -1;
+       }
+
+       /* TODO: do we iterate over the list to remove all token? */
+       DBG2("Closing kernel trigger group fd");
+       if (kernel_tracer_trigger_group_fd >= 0) {
+               ret = close(kernel_tracer_trigger_group_fd);
+               if (ret) {
+                       PERROR("close");
+               }
+               kernel_tracer_trigger_group_fd = -1;
+       }
+
        DBG2("Closing kernel fd");
        if (kernel_tracer_fd >= 0) {
                ret = close(kernel_tracer_fd);
@@ -1789,6 +1962,8 @@ void cleanup_kernel_tracer(void)
                }
                kernel_tracer_fd = -1;
        }
+
+       
        DBG("Unloading kernel modules");
        modprobe_remove_lttng_all();
        free(syscall_table);
@@ -1879,3 +2054,274 @@ end:
        rcu_read_unlock();
        return status;
 }
+
+enum lttng_error_code kernel_create_trigger_group_notification_fd(
+               int *trigger_group_notification_fd)
+{
+       enum lttng_error_code ret = LTTNG_OK;
+       int local_fd = -1;
+
+       assert(trigger_group_notification_fd);
+
+       ret = kernctl_create_trigger_group_notification_fd(kernel_tracer_trigger_group_fd);
+       if (ret < 0) {
+               PERROR("ioctl kernel create trigger group");
+               ret = -1;
+               goto error;
+       }
+
+       /* Store locally */
+       local_fd = ret;
+
+       /* Prevent fd duplication after execlp() */
+       ret = fcntl(local_fd, F_SETFD, FD_CLOEXEC);
+       if (ret < 0) {
+               PERROR("fcntl session fd");
+       }
+
+       DBG("Kernel trigger group notification created (fd: %d)",
+                       local_fd);
+       ret = 0;
+
+error:
+       *trigger_group_notification_fd = local_fd;
+       return ret;
+}
+
+enum lttng_error_code kernel_destroy_trigger_group_notification_fd(
+               int trigger_group_notification_fd)
+{
+       enum lttng_error_code ret = LTTNG_OK;
+       DBG("Closing trigger group notification fd %d", trigger_group_notification_fd);
+       if (trigger_group_notification_fd >= 0) {
+               ret = close(trigger_group_notification_fd);
+               if (ret) {
+                       PERROR("close");
+               }
+       }
+       return ret;
+}
+
+static int kernel_create_token_event_rule(struct lttng_event_rule *rule,
+               const struct lttng_credentials *creds, uint64_t token)
+{
+       int err, fd;
+       enum lttng_error_code ret;
+       struct ltt_kernel_token_event_rule *event;
+       struct lttng_kernel_trigger trigger;
+
+       assert(rule);
+
+       ret = trace_kernel_create_token_event_rule(rule, token, &event);
+       if (ret != LTTNG_OK) {
+               goto error;
+       }
+       
+       trace_kernel_init_trigger_from_event_rule(event->event_rule, &trigger);
+       trigger.id = event->token;
+
+       fd = kernctl_create_trigger(kernel_tracer_trigger_group_fd, &trigger);
+       if (fd < 0) {
+               switch (-fd) {
+               case EEXIST:
+                       ret = LTTNG_ERR_KERN_EVENT_EXIST;
+                       break;
+               case ENOSYS:
+                       WARN("Trigger type not implemented");
+                       ret = LTTNG_ERR_KERN_EVENT_ENOSYS;
+                       break;
+               case ENOENT:
+                       WARN("Event %s not found!", trigger.name);
+                       ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       break;
+               default:
+                       ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       PERROR("create trigger ioctl");
+               }
+               goto free_event;
+       }
+
+       event->fd = fd;
+       /* Prevent fd duplication after execlp() */
+       err = fcntl(event->fd, F_SETFD, FD_CLOEXEC);
+       if (err < 0) {
+               PERROR("fcntl session fd");
+       }
+
+       if (event->filter) {
+               err = kernctl_filter(event->fd, event->filter);
+               if (err < 0) {
+                       switch (-err) {
+                       case ENOMEM:
+                               ret = LTTNG_ERR_FILTER_NOMEM;
+                               break;
+                       default:
+                               ret = LTTNG_ERR_FILTER_INVAL;
+                               break;
+                       }
+                       goto filter_error;
+               }
+       }
+
+       if (lttng_event_rule_get_type(event->event_rule) ==
+                       LTTNG_EVENT_RULE_TYPE_UPROBE) {
+               ret = userspace_probe_event_rule_add_callsites(
+                               rule, creds, event->fd);
+               if (ret) {
+                       goto add_callsite_error;
+               }
+       }
+
+       err = kernctl_enable(event->fd);
+       if (err < 0) {
+               switch (-err) {
+               case EEXIST:
+                       ret = LTTNG_ERR_KERN_EVENT_EXIST;
+                       break;
+               default:
+                       PERROR("enable kernel trigger");
+                       ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       break;
+               }
+               goto enable_error;
+       }
+
+       /* Add event to event list */
+       cds_list_add(&event->list, &kernel_tracer_token_list.head);
+
+       DBG("Trigger %s created (fd: %d)", trigger.name, event->fd);
+
+       return 0;
+
+add_callsite_error:
+enable_error:
+filter_error:
+       {
+               int closeret;
+
+               closeret = close(event->fd);
+               if (closeret) {
+                       PERROR("close event fd");
+               }
+       }
+free_event:
+       free(event);
+error:
+       return ret;
+}
+
+enum lttng_error_code kernel_update_tokens(void)
+{
+       enum lttng_error_code ret = LTTNG_OK;
+       enum lttng_trigger_status t_status;
+       struct ltt_kernel_token_event_rule *token_event_rule_element;
+       struct lttng_triggers *triggers;
+       unsigned int count;
+       
+       /* TODO error handling */
+
+       /* Get list of token trigger from the notification thread here */
+       rcu_read_lock();
+       pthread_mutex_lock(&notification_trigger_tokens_ht_lock);
+       ret = notification_thread_command_get_tokens(notification_thread_handle, &triggers);
+       if (ret != LTTNG_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       assert(triggers);
+
+       t_status = lttng_triggers_get_count(triggers, &count);
+       if (t_status != LTTNG_TRIGGER_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       for (unsigned int i = 0; i < count; i++) {
+               struct lttng_condition *condition;
+               struct lttng_event_rule *event_rule;
+               struct lttng_trigger *trigger;
+               struct ltt_kernel_token_event_rule *k_token;
+               const struct lttng_credentials *creds;
+               uint64_t token;
+
+               trigger = lttng_triggers_get_pointer_of_index(triggers, i);
+               assert(trigger);
+
+               /* TODO: error checking and type checking */
+               token = lttng_trigger_get_key(trigger);
+               condition = lttng_trigger_get_condition(trigger);
+               (void) lttng_condition_event_rule_get_rule_no_const(condition, &event_rule);
+
+               if (lttng_event_rule_get_domain_type(event_rule) != LTTNG_DOMAIN_KERNEL) {
+                       /* Skip ust related trigger */
+                       continue;
+               }
+
+               creds = lttng_trigger_get_credentials(trigger);
+               /* Iterate over all known token trigger */
+               k_token = trace_kernel_find_trigger_by_token(&kernel_tracer_token_list, token);
+               if (!k_token) {
+                       ret = kernel_create_token_event_rule(event_rule, creds, token);
+                       if (ret < 0) {
+                               goto end;
+                       }
+               }
+       }
+
+       /* Remove all unknown trigger from the app
+        * TODO find a way better way then this, do it on the unregister command
+        * and be specific on the token to remove instead of going over all
+        * trigger known to the app. This is sub optimal.
+        */
+       cds_list_for_each_entry (token_event_rule_element, &kernel_tracer_token_list.head,
+                       list) {
+               uint64_t token;
+               bool found = false;
+
+               token = token_event_rule_element->token;
+
+       /*
+                * Check if the app event trigger still exists on the
+                * notification side.
+                * TODO: might want to change the backing data struct of the
+                * lttng_triggers object to allow quick lookup?
+                * For kernel mostly all of this can be removed once we delete
+                * on a per trigger basis.
+                */
+
+               for (unsigned int i = 0; i < count; i++) {
+                       struct lttng_trigger *trigger;
+                       uint64_t inner_token;
+
+                       trigger = lttng_triggers_get_pointer_of_index(
+                                       triggers, i);
+                       assert(trigger);
+
+                       inner_token = lttng_trigger_get_key(trigger);
+
+                       if (inner_token == token) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (found) {
+                       /* Still valid */
+                       continue;
+               }
+
+               kernel_disable_token_event_rule(token_event_rule_element);
+               trace_kernel_destroy_token_event_rule(token_event_rule_element);
+       }
+end:
+       rcu_read_unlock();
+       pthread_mutex_unlock(&notification_trigger_tokens_ht_lock);
+       return ret;
+
+}
+
+int kernel_get_notification_fd(void)
+{
+       return kernel_tracer_trigger_group_notification_fd;
+}
index 4f3bedea5c392d09f94e9fbdd43ab60583e4c9e1..d22a5b7a07375477869df702a4dad4bf860fae43 100644 (file)
@@ -74,4 +74,11 @@ bool kernel_tracer_is_initialized(void);
 enum lttng_error_code kernel_create_channel_subdirectories(
                const struct ltt_kernel_session *ksess);
 
+enum lttng_error_code kernel_create_trigger_group_notification_fd(
+               int *trigger_group_notification_fd);
+enum lttng_error_code kernel_destroy_trigger_group_notification_fd(
+               int trigger_group_notification_fd);
+enum lttng_error_code kernel_update_tokens(void);
+int kernel_get_notification_fd(void);
+
 #endif /* _LTT_KERNEL_CTL_H */
index 277fc23e30f22ff4be3d9c93f7b66bd343721be6..ee8ea2400359ea8791fe3fa9105abfdcf7f04326 100644 (file)
@@ -70,6 +70,7 @@ extern struct lttng_kernel_tracer_abi_version kernel_tracer_abi_version;
 
 /* Notification thread handle. */
 extern struct notification_thread_handle *notification_thread_handle;
+extern pthread_mutex_t notification_trigger_tokens_ht_lock;
 
 /*
  * This contains extra data needed for processing a command received by the
index 55e0ad3d7a28623cb6f1bdad7ccc04e289f410f8..965625c9bb8ad7f70c74a61422b8e299ce164648 100644 (file)
@@ -314,6 +314,9 @@ static void sessiond_cleanup(void)
 
        pthread_mutex_destroy(&session_list->lock);
 
+       DBG("Cleaning up all trigger agents");
+       trigger_agent_ht_clean();
+
        DBG("Cleaning up all agent apps");
        agent_app_ht_clean();
        DBG("Closing all UST sockets");
@@ -1302,6 +1305,7 @@ int main(int argc, char **argv)
        struct lttng_thread *notification_thread = NULL;
        struct lttng_thread *register_apps_thread = NULL;
 
+       logger_set_thread_name("Main", false);
        init_kernel_workarounds();
 
        rcu_register_thread();
@@ -1538,6 +1542,11 @@ int main(int argc, char **argv)
                goto stop_threads;
        }
 
+       if (trigger_agent_ht_alloc()) {
+               ERR("Failed to allocate trigger agent hash table");
+               retval = -1;
+               goto stop_threads;
+       }
        /*
         * These actions must be executed as root. We do that *after* setting up
         * the sockets path because we MUST make the check for another daemon using
@@ -1635,7 +1644,8 @@ int main(int argc, char **argv)
        notification_thread_handle = notification_thread_handle_create(
                        ust32_channel_monitor_pipe,
                        ust64_channel_monitor_pipe,
-                       kernel_channel_monitor_pipe);
+                       kernel_channel_monitor_pipe,
+                       kernel_get_notification_fd());
        if (!notification_thread_handle) {
                retval = -1;
                ERR("Failed to create notification thread shared data");
index 66e80e75b26dbc1b5ae8bfa4e122c37136ceadfa..7bee25f887cf95b08bb5f8edfa3c7bd69d991e9d 100644 (file)
 #define LTTNG_MOD_OPTIONAL     0
 
 /* LTTng kernel tracer mandatory core modules list */
+/* TODO: the new trigger client might not be present in previous lttng-modules
+ * should it be optional?
+ * Can we reuse this to also know of the trigger feature is supported?
+ */
 struct kern_modules_param kern_modules_control_core[] = {
-       { "lttng-ring-buffer-client-discard" },
-       { "lttng-ring-buffer-client-overwrite" },
-       { "lttng-ring-buffer-metadata-client" },
-       { "lttng-ring-buffer-client-mmap-discard" },
-       { "lttng-ring-buffer-client-mmap-overwrite" },
-       { "lttng-ring-buffer-metadata-mmap-client" },
+       { (char *) "lttng-ring-buffer-client-discard" },
+       { (char *) "lttng-ring-buffer-client-overwrite" },
+       { (char *) "lttng-ring-buffer-metadata-client" },
+       { (char *) "lttng-ring-buffer-client-mmap-discard" },
+       { (char *) "lttng-ring-buffer-client-mmap-overwrite" },
+       { (char *) "lttng-ring-buffer-metadata-mmap-client" },
+       { (char *) "lttng-ring-buffer-trigger-client" },
 };
 
 /* LTTng kernel tracer probe modules list */
 struct kern_modules_param kern_modules_probes_default[] = {
-       { "lttng-probe-asoc" },
-       { "lttng-probe-block" },
-       { "lttng-probe-btrfs" },
-       { "lttng-probe-compaction" },
-       { "lttng-probe-ext3" },
-       { "lttng-probe-ext4" },
-       { "lttng-probe-gpio" },
-       { "lttng-probe-i2c" },
-       { "lttng-probe-irq" },
-       { "lttng-probe-jbd" },
-       { "lttng-probe-jbd2" },
-       { "lttng-probe-kmem" },
-       { "lttng-probe-kvm" },
-       { "lttng-probe-kvm-x86" },
-       { "lttng-probe-kvm-x86-mmu" },
-       { "lttng-probe-lock" },
-       { "lttng-probe-module" },
-       { "lttng-probe-napi" },
-       { "lttng-probe-net" },
-       { "lttng-probe-power" },
-       { "lttng-probe-preemptirq" },
-       { "lttng-probe-printk" },
-       { "lttng-probe-random" },
-       { "lttng-probe-rcu" },
-       { "lttng-probe-regmap" },
-       { "lttng-probe-regulator" },
-       { "lttng-probe-rpm" },
-       { "lttng-probe-sched" },
-       { "lttng-probe-scsi" },
-       { "lttng-probe-signal" },
-       { "lttng-probe-skb" },
-       { "lttng-probe-sock" },
-       { "lttng-probe-statedump" },
-       { "lttng-probe-sunrpc" },
-       { "lttng-probe-timer" },
-       { "lttng-probe-udp" },
-       { "lttng-probe-vmscan" },
-       { "lttng-probe-v4l2" },
-       { "lttng-probe-workqueue" },
-       { "lttng-probe-writeback" },
-       { "lttng-probe-x86-irq-vectors" },
-       { "lttng-probe-x86-exceptions" },
+       { (char *) "lttng-probe-asoc" },
+       { (char *) "lttng-probe-block" },
+       { (char *) "lttng-probe-btrfs" },
+       { (char *) "lttng-probe-compaction" },
+       { (char *) "lttng-probe-ext3" },
+       { (char *) "lttng-probe-ext4" },
+       { (char *) "lttng-probe-gpio" },
+       { (char *) "lttng-probe-i2c" },
+       { (char *) "lttng-probe-irq" },
+       { (char *) "lttng-probe-jbd" },
+       { (char *) "lttng-probe-jbd2" },
+       { (char *) "lttng-probe-kmem" },
+       { (char *) "lttng-probe-kvm" },
+       { (char *) "lttng-probe-kvm-x86" },
+       { (char *) "lttng-probe-kvm-x86-mmu" },
+       { (char *) "lttng-probe-lock" },
+       { (char *) "lttng-probe-module" },
+       { (char *) "lttng-probe-napi" },
+       { (char *) "lttng-probe-net" },
+       { (char *) "lttng-probe-power" },
+       { (char *) "lttng-probe-preemptirq" },
+       { (char *) "lttng-probe-printk" },
+       { (char *) "lttng-probe-random" },
+       { (char *) "lttng-probe-rcu" },
+       { (char *) "lttng-probe-regmap" },
+       { (char *) "lttng-probe-regulator" },
+       { (char *) "lttng-probe-rpm" },
+       { (char *) "lttng-probe-sched" },
+       { (char *) "lttng-probe-scsi" },
+       { (char *) "lttng-probe-signal" },
+       { (char *) "lttng-probe-skb" },
+       { (char *) "lttng-probe-sock" },
+       { (char *) "lttng-probe-statedump" },
+       { (char *) "lttng-probe-sunrpc" },
+       { (char *) "lttng-probe-timer" },
+       { (char *) "lttng-probe-udp" },
+       { (char *) "lttng-probe-vmscan" },
+       { (char *) "lttng-probe-v4l2" },
+       { (char *) "lttng-probe-workqueue" },
+       { (char *) "lttng-probe-writeback" },
+       { (char *) "lttng-probe-x86-irq-vectors" },
+       { (char *) "lttng-probe-x86-exceptions" },
 };
 
 /* dynamic probe modules list */
index 4474d1978ed524f29866248910c6b697cc494282..9d346f947b9395cd33e9973d081a585712b2a3e0 100644 (file)
@@ -17,7 +17,6 @@
 static
 void init_notification_thread_command(struct notification_thread_command *cmd)
 {
-       memset(cmd, 0, sizeof(*cmd));
        CDS_INIT_LIST_HEAD(&cmd->cmd_list_node);
        lttng_waiter_init(&cmd->reply_waiter);
 }
@@ -54,13 +53,69 @@ error_unlock_queue:
        return -1;
 }
 
+static
+struct notification_thread_command *notification_thread_command_copy(
+       const struct notification_thread_command *original_cmd)
+{
+       struct notification_thread_command *new_cmd;
+
+       new_cmd = zmalloc(sizeof(*new_cmd));
+       if (!new_cmd) {
+               goto end;
+       }
+
+       *new_cmd = *original_cmd;
+       init_notification_thread_command(new_cmd);
+end:
+       return new_cmd;
+}
+
+static
+int run_command_no_wait(struct notification_thread_handle *handle,
+               const struct notification_thread_command *in_cmd)
+{
+       int ret;
+       uint64_t notification_counter = 1;
+       struct notification_thread_command *new_cmd =
+                       notification_thread_command_copy(in_cmd);
+
+       if (!new_cmd) {
+               goto error;
+       }
+       new_cmd->is_async = true;
+
+       pthread_mutex_lock(&handle->cmd_queue.lock);
+       /* Add to queue. */
+       cds_list_add_tail(&new_cmd->cmd_list_node,
+                       &handle->cmd_queue.list);
+       /* Wake-up thread. */
+       ret = lttng_write(lttng_pipe_get_writefd(handle->cmd_queue.event_pipe),
+                       &notification_counter, sizeof(notification_counter));
+       if (ret != sizeof(notification_counter)) {
+               PERROR("write to notification thread's queue event fd");
+               /*
+                * Remove the command from the list so the notification
+                * thread does not process it.
+                */
+               cds_list_del(&new_cmd->cmd_list_node);
+               goto error_unlock_queue;
+       }
+       pthread_mutex_unlock(&handle->cmd_queue.lock);
+       return 0;
+error_unlock_queue:
+       free(new_cmd);
+       pthread_mutex_unlock(&handle->cmd_queue.lock);
+error:
+       return -1;
+}
+
 enum lttng_error_code notification_thread_command_register_trigger(
                struct notification_thread_handle *handle,
                struct lttng_trigger *trigger)
 {
        int ret;
        enum lttng_error_code ret_code;
-       struct notification_thread_command cmd;
+       struct notification_thread_command cmd = {};
 
        init_notification_thread_command(&cmd);
 
@@ -83,7 +138,7 @@ enum lttng_error_code notification_thread_command_unregister_trigger(
 {
        int ret;
        enum lttng_error_code ret_code;
-       struct notification_thread_command cmd;
+       struct notification_thread_command cmd = {};
 
        init_notification_thread_command(&cmd);
 
@@ -108,7 +163,7 @@ enum lttng_error_code notification_thread_command_add_channel(
 {
        int ret;
        enum lttng_error_code ret_code;
-       struct notification_thread_command cmd;
+       struct notification_thread_command cmd = {};
 
        init_notification_thread_command(&cmd);
 
@@ -137,7 +192,7 @@ enum lttng_error_code notification_thread_command_remove_channel(
 {
        int ret;
        enum lttng_error_code ret_code;
-       struct notification_thread_command cmd;
+       struct notification_thread_command cmd = {};
 
        init_notification_thread_command(&cmd);
 
@@ -162,7 +217,7 @@ enum lttng_error_code notification_thread_command_session_rotation_ongoing(
 {
        int ret;
        enum lttng_error_code ret_code;
-       struct notification_thread_command cmd;
+       struct notification_thread_command cmd = {};
 
        init_notification_thread_command(&cmd);
 
@@ -191,7 +246,7 @@ enum lttng_error_code notification_thread_command_session_rotation_completed(
 {
        int ret;
        enum lttng_error_code ret_code;
-       struct notification_thread_command cmd;
+       struct notification_thread_command cmd = {};
 
        init_notification_thread_command(&cmd);
 
@@ -213,11 +268,115 @@ end:
        return ret_code;
 }
 
+enum lttng_error_code notification_thread_command_add_application(
+               struct notification_thread_handle *handle,
+               struct lttng_pipe *pipe)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       struct notification_thread_command cmd = {};
+
+       init_notification_thread_command(&cmd);
+
+       cmd.type = NOTIFICATION_COMMAND_TYPE_ADD_APPLICATION;
+       cmd.parameters.application.read_side_trigger_event_application_pipe = lttng_pipe_get_readfd(pipe);
+
+       ret = run_command_wait(handle, &cmd);
+       if (ret) {
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+       ret_code = cmd.reply_code;
+end:
+       return ret_code;
+}
+
+enum lttng_error_code notification_thread_command_remove_application(
+               struct notification_thread_handle *handle,
+               struct lttng_pipe *pipe)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       struct notification_thread_command cmd = {};
+
+       init_notification_thread_command(&cmd);
+
+       cmd.type = NOTIFICATION_COMMAND_TYPE_REMOVE_APPLICATION;
+       cmd.parameters.application.read_side_trigger_event_application_pipe = lttng_pipe_get_readfd(pipe);
+
+       ret = run_command_wait(handle, &cmd);
+       if (ret) {
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+       ret_code = cmd.reply_code;
+end:
+       return ret_code;
+}
+
+enum lttng_error_code notification_thread_command_get_tokens(
+               struct notification_thread_handle *handle,
+               struct lttng_triggers **tokens_triggers)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       struct notification_thread_command cmd = {};
+
+       assert(handle);
+       assert(tokens_triggers);
+
+       init_notification_thread_command(&cmd);
+
+       cmd.type = NOTIFICATION_COMMAND_TYPE_GET_TOKENS;
+
+       ret = run_command_wait(handle, &cmd);
+       if (ret) {
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+       ret_code = cmd.reply_code;
+       *tokens_triggers = cmd.reply.get_tokens.triggers;
+
+end:
+       return ret_code;
+}
+
+enum lttng_error_code notification_thread_command_list_triggers(
+               struct notification_thread_handle *handle,
+               uid_t uid,
+               gid_t gid,
+               struct lttng_triggers **triggers)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       struct notification_thread_command cmd = {};
+
+       assert(handle);
+       assert(triggers);
+
+       init_notification_thread_command(&cmd);
+
+       cmd.type = NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS;
+       cmd.parameters.list_triggers.uid = uid;
+       cmd.parameters.list_triggers.gid = gid;
+
+       ret = run_command_wait(handle, &cmd);
+       if (ret) {
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+       ret_code = cmd.reply_code;
+       *triggers = cmd.reply.list_triggers.triggers;
+
+end:
+       return ret_code;
+}
+
 void notification_thread_command_quit(
                struct notification_thread_handle *handle)
 {
        int ret;
-       struct notification_thread_command cmd;
+       struct notification_thread_command cmd = {};
 
        init_notification_thread_command(&cmd);
 
index a90d1ac2b2f662697fd54412596cba2e06689b9d..f0e857fae3f7d785bec815d26347154d971977a3 100644 (file)
@@ -15,6 +15,7 @@
 #include "notification-thread-internal.h"
 #include "notification-thread-events.h"
 #include <common/waiter.h>
+#include <stdbool.h>
 
 struct notification_thread_data;
 struct lttng_trigger;
@@ -26,6 +27,10 @@ enum notification_thread_command_type {
        NOTIFICATION_COMMAND_TYPE_REMOVE_CHANNEL,
        NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING,
        NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_COMPLETED,
+       NOTIFICATION_COMMAND_TYPE_ADD_APPLICATION,
+       NOTIFICATION_COMMAND_TYPE_REMOVE_APPLICATION,
+       NOTIFICATION_COMMAND_TYPE_GET_TOKENS,
+       NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS,
        NOTIFICATION_COMMAND_TYPE_QUIT,
 };
 
@@ -62,11 +67,32 @@ struct notification_thread_command {
                        uint64_t trace_archive_chunk_id;
                        struct lttng_trace_archive_location *location;
                } session_rotation;
+               /* Add/Remove application */
+               struct {
+                       int read_side_trigger_event_application_pipe;
+               } application;
+               /* List triggers */
+               struct {
+                       /* Credential */
+                       uid_t uid;
+                       gid_t gid;
+               } list_triggers;
+
        } parameters;
 
+       union {
+               struct {
+                       struct lttng_triggers *triggers;
+               } get_tokens;
+               struct {
+                       struct lttng_triggers *triggers;
+               } list_triggers;
+       } reply;
+
        /* lttng_waiter on which to wait for command reply (optional). */
        struct lttng_waiter reply_waiter;
        enum lttng_error_code reply_code;
+       bool is_async;
 };
 
 enum lttng_error_code notification_thread_command_register_trigger(
@@ -99,6 +125,28 @@ enum lttng_error_code notification_thread_command_session_rotation_completed(
                uint64_t trace_archive_chunk_id,
                struct lttng_trace_archive_location *location);
 
+enum lttng_error_code notification_thread_command_add_application(
+               struct notification_thread_handle *handle,
+               struct lttng_pipe *trigger_event_application_pipe);
+
+enum lttng_error_code notification_thread_command_remove_application(
+               struct notification_thread_handle *handle,
+               struct lttng_pipe *trigger_event_application_pipe);
+
+/* Must hold the notification_trigger_tokens_ht_lock to protect against
+ * insertion removal of triggers TODO: is it the case even with refcounting? */
+/* todo find a better way....*/
+enum lttng_error_code notification_thread_command_get_tokens(
+               struct notification_thread_handle *handle,
+               struct lttng_triggers **triggers);
+
+/* TODO: for now we borrow with no refcount the trigger. THIS IS DANGEROUS */
+enum lttng_error_code notification_thread_command_list_triggers(
+               struct notification_thread_handle *handle,
+               uid_t uid,
+               gid_t gid,
+               struct lttng_triggers **triggers);
+
 void notification_thread_command_quit(
                struct notification_thread_handle *handle);
 
index 73ec72f89c308b86ce2c95da5c364738d5b42680..e3c35f3a5e9e4f7cbbabfe48b923ed0556a05b9d 100644 (file)
 #include <common/macros.h>
 #include <lttng/condition/condition.h>
 #include <lttng/action/action-internal.h>
+#include <lttng/action/group-internal.h>
 #include <lttng/notification/notification-internal.h>
 #include <lttng/condition/condition-internal.h>
 #include <lttng/condition/buffer-usage-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
 #include <lttng/condition/session-rotation-internal.h>
+#include <lttng/condition/event-rule-internal.h>
 #include <lttng/notification/channel-internal.h>
+#include <lttng/trigger/trigger-internal.h>
 
 #include <time.h>
 #include <unistd.h>
@@ -50,7 +53,7 @@ enum lttng_object_type {
 
 struct lttng_trigger_list_element {
        /* No ownership of the trigger object is assumed. */
-       const struct lttng_trigger *trigger;
+       struct lttng_trigger *trigger;
        struct cds_list_head node;
 };
 
@@ -108,6 +111,7 @@ struct lttng_session_trigger_list {
 struct lttng_trigger_ht_element {
        struct lttng_trigger *trigger;
        struct cds_lfht_node node;
+       struct cds_lfht_node node_by_name;
        /* call_rcu delayed reclaim. */
        struct rcu_head rcu_node;
 };
@@ -117,85 +121,17 @@ struct lttng_condition_list_element {
        struct cds_list_head node;
 };
 
-struct notification_client_list_element {
-       struct notification_client *client;
-       struct cds_list_head node;
-};
-
-struct notification_client_list {
-       const struct lttng_trigger *trigger;
-       struct cds_list_head list;
-       struct cds_lfht_node notification_trigger_ht_node;
-       /* call_rcu delayed reclaim. */
-       struct rcu_head rcu_node;
-};
-
-struct notification_client {
-       int socket;
-       /* Client protocol version. */
-       uint8_t major, minor;
-       uid_t uid;
-       gid_t gid;
-       /*
-        * Indicates if the credentials and versions of the client have been
-        * checked.
-        */
-       bool v