+static
+void lttng_trigger_send_notification(struct lttng_trigger *trigger)
+{
+ struct lttng_trigger_group *trigger_group = trigger->group;
+ struct lib_ring_buffer_ctx ctx;
+ int ret;
+
+ if (unlikely(!READ_ONCE(trigger->enabled)))
+ return;
+
+ lib_ring_buffer_ctx_init(&ctx, trigger_group->chan, NULL, sizeof(trigger->id),
+ lttng_alignof(trigger->id), -1);
+ ret = trigger_group->ops->event_reserve(&ctx, 0);
+ if (ret < 0) {
+ //TODO: error handling with counter maps
+ //silently drop for now. WARN_ON_ONCE(1);
+ return;
+ }
+ lib_ring_buffer_align_ctx(&ctx, lttng_alignof(trigger->id));
+ trigger_group->ops->event_write(&ctx, &trigger->id, sizeof(trigger->id));
+ trigger_group->ops->event_commit(&ctx);
+ irq_work_queue(&trigger_group->wakeup_pending);
+}
+
+struct lttng_trigger *_lttng_trigger_create(
+ const struct lttng_event_desc *event_desc,
+ uint64_t id, struct lttng_trigger_group *trigger_group,
+ struct lttng_kernel_trigger *trigger_param, void *filter,
+ enum lttng_kernel_instrumentation itype)
+{
+ struct lttng_trigger *trigger;
+ const char *event_name;
+ struct hlist_head *head;
+ int ret;
+
+ switch (itype) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ event_name = event_desc->name;
+ break;
+ case LTTNG_KERNEL_KPROBE:
+ case LTTNG_KERNEL_UPROBE:
+ case LTTNG_KERNEL_SYSCALL:
+ event_name = trigger_param->name;
+ break;
+ case LTTNG_KERNEL_KRETPROBE:
+ case LTTNG_KERNEL_FUNCTION:
+ case LTTNG_KERNEL_NOOP:
+ default:
+ WARN_ON_ONCE(1);
+ ret = -EINVAL;
+ goto type_error;
+ }
+
+ head = utils_borrow_hash_table_bucket(trigger_group->triggers_ht.table,
+ LTTNG_TRIGGER_HT_SIZE, event_name);
+ lttng_hlist_for_each_entry(trigger, head, hlist) {
+ WARN_ON_ONCE(!trigger->desc);
+ if (!strncmp(trigger->desc->name, event_name,
+ LTTNG_KERNEL_SYM_NAME_LEN - 1)
+ && trigger_group == trigger->group
+ && id == trigger->id) {
+ ret = -EEXIST;
+ goto exist;
+ }
+ }
+
+ trigger = kmem_cache_zalloc(trigger_cache, GFP_KERNEL);
+ if (!trigger) {
+ ret = -ENOMEM;
+ goto cache_error;
+ }
+ trigger->group = trigger_group;
+ trigger->id = id;
+ trigger->filter = filter;
+ trigger->instrumentation = itype;
+ trigger->evtype = LTTNG_TYPE_EVENT;
+ trigger->send_notification = lttng_trigger_send_notification;
+ INIT_LIST_HEAD(&trigger->bytecode_runtime_head);
+ INIT_LIST_HEAD(&trigger->enablers_ref_head);
+
+ switch (itype) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ /* Event will be enabled by enabler sync. */
+ trigger->enabled = 0;
+ trigger->registered = 0;
+ trigger->desc = lttng_event_desc_get(event_name);
+ if (!trigger->desc) {
+ ret = -ENOENT;
+ goto register_error;
+ }
+ /* Populate lttng_trigger structure before event registration. */
+ smp_wmb();
+ break;
+ case LTTNG_KERNEL_KPROBE:
+ /*
+ * Needs to be explicitly enabled after creation, since
+ * we may want to apply filters.
+ */
+ trigger->enabled = 0;
+ trigger->registered = 1;
+ /*
+ * Populate lttng_trigger structure before event
+ * registration.
+ */
+ smp_wmb();
+ ret = lttng_kprobes_register_trigger(
+ trigger_param->u.kprobe.symbol_name,
+ trigger_param->u.kprobe.offset,
+ trigger_param->u.kprobe.addr,
+ trigger);
+ if (ret) {
+ ret = -EINVAL;
+ goto register_error;
+ }
+ ret = try_module_get(trigger->desc->owner);
+ WARN_ON_ONCE(!ret);
+ break;
+ case LTTNG_KERNEL_NOOP:
+ case LTTNG_KERNEL_SYSCALL:
+ /*
+ * Needs to be explicitly enabled after creation, since
+ * we may want to apply filters.
+ */
+ trigger->enabled = 0;
+ trigger->registered = 0;
+ trigger->desc = event_desc;
+ if (!trigger->desc) {
+ ret = -EINVAL;
+ goto register_error;
+ }
+ break;
+ case LTTNG_KERNEL_UPROBE:
+ /*
+ * Needs to be explicitly enabled after creation, since
+ * we may want to apply filters.
+ */
+ trigger->enabled = 0;
+ trigger->registered = 1;
+
+ /*
+ * Populate lttng_trigger structure before trigger
+ * registration.
+ */
+ smp_wmb();
+
+ ret = lttng_uprobes_register_trigger(trigger_param->name,
+ trigger_param->u.uprobe.fd,
+ trigger);
+ if (ret)
+ goto register_error;
+ ret = try_module_get(trigger->desc->owner);
+ WARN_ON_ONCE(!ret);
+ break;
+ case LTTNG_KERNEL_KRETPROBE:
+ case LTTNG_KERNEL_FUNCTION:
+ default:
+ WARN_ON_ONCE(1);
+ ret = -EINVAL;
+ goto register_error;
+ }
+
+ list_add(&trigger->list, &trigger_group->triggers_head);
+ hlist_add_head(&trigger->hlist, head);
+ return trigger;
+
+register_error:
+ kmem_cache_free(trigger_cache, trigger);
+cache_error:
+exist:
+type_error:
+ return ERR_PTR(ret);
+}
+