/*
 * Module life cycle.
 */
static void probes_unregister(void)
{
  lttng_wrapper_tracepoint_probe_unregister(
      "sys_enter", syscall_entry_probe, NULL);
  lttng_wrapper_tracepoint_probe_unregister(
      "sys_exit", syscall_exit_probe, NULL);
  lttng_wrapper_tracepoint_probe_unregister(
      "sched_process_exit", sched_process_exit_probe, NULL);
}
static
void __exit wakeup_latency_exit(void)
{
	uint64_t skipped;
	struct wakeup_tracker *wakeup_priv;

	lttng_wrapper_tracepoint_probe_unregister("sched_waking",
			probe_sched_waking, NULL);
	lttng_wrapper_tracepoint_probe_unregister("sched_switch",
			probe_sched_switch, NULL);
	tracepoint_synchronize_unregister();
	skipped = latency_tracker_skipped_count(tracker);
	wakeup_priv = latency_tracker_get_priv(tracker);
	wakeup_destroy_priv(wakeup_priv);
	latency_tracker_destroy(tracker);
	printk("Missed events : %llu\n", skipped);
	printk("Total wakeup alerts : %d\n", cnt);
}
static
void __exit critical_timing_exit(void)
{
	lttng_wrapper_tracepoint_probe_unregister("core_critical_timing_hit",
			probe_core_critical_timing_hit, NULL);
	tracepoint_synchronize_unregister();
	latency_tracker_destroy(tracker);
	printk("Total critical_timing alerts : %d\n", cnt);
}
/*
 * Only called at session destruction.
 */
int lttng_syscalls_unregister(struct lttng_channel *chan)
{
	int ret;

	if (!chan->sc_table)
		return 0;
	ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
			(void *) __event_probe__exit_syscall,
			chan->sc_exit);
	if (ret)
		return ret;
	ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
			(void *) syscall_entry_probe, chan);
	if (ret)
		return ret;
	/* lttng_event destroy will be performed by lttng_session_destroy() */
	kfree(chan->sc_table);
#ifdef CONFIG_COMPAT
	kfree(chan->compat_sc_table);
#endif
	return 0;
}
int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
{
	struct lttng_kernel_event ev;
	int ret;

	wrapper_vmalloc_sync_all();

	if (!chan->sc_table) {
		/* create syscall table mapping syscall to events */
		chan->sc_table = kzalloc(sizeof(struct lttng_event *)
					* ARRAY_SIZE(sc_table), GFP_KERNEL);
		if (!chan->sc_table)
			return -ENOMEM;
	}

#ifdef CONFIG_COMPAT
	if (!chan->compat_sc_table) {
		/* create syscall table mapping compat syscall to events */
		chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
					* ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
		if (!chan->compat_sc_table)
			return -ENOMEM;
	}
#endif
	if (!chan->sc_unknown) {
		const struct lttng_event_desc *desc =
			&__event_desc___sys_unknown;

		memset(&ev, 0, sizeof(ev));
		strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
		ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
		ev.instrumentation = LTTNG_KERNEL_NOOP;
		chan->sc_unknown = lttng_event_create(chan, &ev, filter,
						    desc);
		WARN_ON_ONCE(!chan->sc_unknown);
		if (IS_ERR(chan->sc_unknown)) {
			return PTR_ERR(chan->sc_unknown);
		}
	}

	if (!chan->sc_compat_unknown) {
		const struct lttng_event_desc *desc =
			&__event_desc___compat_sys_unknown;

		memset(&ev, 0, sizeof(ev));
		strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
		ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
		ev.instrumentation = LTTNG_KERNEL_NOOP;
		chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
							   desc);
		WARN_ON_ONCE(!chan->sc_unknown);
		if (IS_ERR(chan->sc_compat_unknown)) {
			return PTR_ERR(chan->sc_compat_unknown);
		}
	}

	if (!chan->sc_exit) {
		const struct lttng_event_desc *desc =
			&__event_desc___exit_syscall;

		memset(&ev, 0, sizeof(ev));
		strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
		ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
		ev.instrumentation = LTTNG_KERNEL_NOOP;
		chan->sc_exit = lttng_event_create(chan, &ev, filter,
						 desc);
		WARN_ON_ONCE(!chan->sc_exit);
		if (IS_ERR(chan->sc_exit)) {
			return PTR_ERR(chan->sc_exit);
		}
	}

	ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
			chan->sc_table, chan, filter);
	if (ret)
		return ret;
#ifdef CONFIG_COMPAT
	ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
			chan->compat_sc_table, chan, filter);
	if (ret)
		return ret;
#endif
	ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
			(void *) syscall_entry_probe, chan);
	if (ret)
		return ret;
	/*
	 * We change the name of sys_exit tracepoint due to namespace
	 * conflict with sys_exit syscall entry.
	 */
	ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
			(void *) __event_probe__exit_syscall,
			chan->sc_exit);
	if (ret) {
		WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
			(void *) syscall_entry_probe, chan));
	}
	return ret;
}