18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * trace context switch
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2007 Steven Rostedt <srostedt@redhat.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/kallsyms.h>
108c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
118c2ecf20Sopenharmony_ci#include <linux/ftrace.h>
128c2ecf20Sopenharmony_ci#include <trace/events/sched.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "trace.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define RECORD_CMDLINE	1
178c2ecf20Sopenharmony_ci#define RECORD_TGID	2
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic int		sched_cmdline_ref;
208c2ecf20Sopenharmony_cistatic int		sched_tgid_ref;
218c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(sched_register_mutex);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic void
248c2ecf20Sopenharmony_ciprobe_sched_switch(void *ignore, bool preempt,
258c2ecf20Sopenharmony_ci		   struct task_struct *prev, struct task_struct *next)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	int flags;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	flags = (RECORD_TGID * !!sched_tgid_ref) +
308c2ecf20Sopenharmony_ci		(RECORD_CMDLINE * !!sched_cmdline_ref);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (!flags)
338c2ecf20Sopenharmony_ci		return;
348c2ecf20Sopenharmony_ci	tracing_record_taskinfo_sched_switch(prev, next, flags);
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic void
388c2ecf20Sopenharmony_ciprobe_sched_wakeup(void *ignore, struct task_struct *wakee)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	int flags;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	flags = (RECORD_TGID * !!sched_tgid_ref) +
438c2ecf20Sopenharmony_ci		(RECORD_CMDLINE * !!sched_cmdline_ref);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	if (!flags)
468c2ecf20Sopenharmony_ci		return;
478c2ecf20Sopenharmony_ci	tracing_record_taskinfo(current, flags);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int tracing_sched_register(void)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	int ret;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	ret = register_trace_sched_wakeup(probe_sched_wakeup, NULL);
558c2ecf20Sopenharmony_ci	if (ret) {
568c2ecf20Sopenharmony_ci		pr_info("wakeup trace: Couldn't activate tracepoint"
578c2ecf20Sopenharmony_ci			" probe to kernel_sched_wakeup\n");
588c2ecf20Sopenharmony_ci		return ret;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	ret = register_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
628c2ecf20Sopenharmony_ci	if (ret) {
638c2ecf20Sopenharmony_ci		pr_info("wakeup trace: Couldn't activate tracepoint"
648c2ecf20Sopenharmony_ci			" probe to kernel_sched_wakeup_new\n");
658c2ecf20Sopenharmony_ci		goto fail_deprobe;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	ret = register_trace_sched_switch(probe_sched_switch, NULL);
698c2ecf20Sopenharmony_ci	if (ret) {
708c2ecf20Sopenharmony_ci		pr_info("sched trace: Couldn't activate tracepoint"
718c2ecf20Sopenharmony_ci			" probe to kernel_sched_switch\n");
728c2ecf20Sopenharmony_ci		goto fail_deprobe_wake_new;
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return ret;
768c2ecf20Sopenharmony_cifail_deprobe_wake_new:
778c2ecf20Sopenharmony_ci	unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
788c2ecf20Sopenharmony_cifail_deprobe:
798c2ecf20Sopenharmony_ci	unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
808c2ecf20Sopenharmony_ci	return ret;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void tracing_sched_unregister(void)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	unregister_trace_sched_switch(probe_sched_switch, NULL);
868c2ecf20Sopenharmony_ci	unregister_trace_sched_wakeup_new(probe_sched_wakeup, NULL);
878c2ecf20Sopenharmony_ci	unregister_trace_sched_wakeup(probe_sched_wakeup, NULL);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic void tracing_start_sched_switch(int ops)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	bool sched_register;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	mutex_lock(&sched_register_mutex);
958c2ecf20Sopenharmony_ci	sched_register = (!sched_cmdline_ref && !sched_tgid_ref);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	switch (ops) {
988c2ecf20Sopenharmony_ci	case RECORD_CMDLINE:
998c2ecf20Sopenharmony_ci		sched_cmdline_ref++;
1008c2ecf20Sopenharmony_ci		break;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	case RECORD_TGID:
1038c2ecf20Sopenharmony_ci		sched_tgid_ref++;
1048c2ecf20Sopenharmony_ci		break;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (sched_register && (sched_cmdline_ref || sched_tgid_ref))
1088c2ecf20Sopenharmony_ci		tracing_sched_register();
1098c2ecf20Sopenharmony_ci	mutex_unlock(&sched_register_mutex);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic void tracing_stop_sched_switch(int ops)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	mutex_lock(&sched_register_mutex);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	switch (ops) {
1178c2ecf20Sopenharmony_ci	case RECORD_CMDLINE:
1188c2ecf20Sopenharmony_ci		sched_cmdline_ref--;
1198c2ecf20Sopenharmony_ci		break;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	case RECORD_TGID:
1228c2ecf20Sopenharmony_ci		sched_tgid_ref--;
1238c2ecf20Sopenharmony_ci		break;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (!sched_cmdline_ref && !sched_tgid_ref)
1278c2ecf20Sopenharmony_ci		tracing_sched_unregister();
1288c2ecf20Sopenharmony_ci	mutex_unlock(&sched_register_mutex);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_civoid tracing_start_cmdline_record(void)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	tracing_start_sched_switch(RECORD_CMDLINE);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_civoid tracing_stop_cmdline_record(void)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	tracing_stop_sched_switch(RECORD_CMDLINE);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_civoid tracing_start_tgid_record(void)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	tracing_start_sched_switch(RECORD_TGID);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_civoid tracing_stop_tgid_record(void)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	tracing_stop_sched_switch(RECORD_TGID);
1498c2ecf20Sopenharmony_ci}
150