1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2023 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
17 #include <sys/prctl.h>
20 #include "timerlat_u.h"
23 * This is the user-space main for the tool timerlatu/ threads.
25 * It is as simple as this:
32 static int timerlat_u_main(int cpu, struct timerlat_u_params *params)
34 struct sched_param sp = { .sched_priority = 95 };
41 * This all is only setting up the tool.
46 retval = sched_setaffinity(gettid(), sizeof(set), &set);
48 debug_msg("Error setting user thread affinity %d, is the CPU online?\n", cpu);
52 if (!params->sched_param) {
53 retval = sched_setscheduler(0, SCHED_FIFO, &sp);
55 err_msg("Error setting timerlat u default priority: %s\n", strerror(errno));
59 retval = __set_sched_attr(getpid(), params->sched_param);
61 /* __set_sched_attr prints an error message, so */
66 if (params->cgroup_name) {
67 retval = set_pid_cgroup(gettid(), params->cgroup_name);
69 err_msg("Error setting timerlat u cgroup pid\n");
70 pthread_exit(&retval);
75 * This is the tool's loop. If you want to use as base for your own tool...
78 snprintf(buffer, sizeof(buffer), "osnoise/per_cpu/cpu%d/timerlat_fd", cpu);
80 timerlat_fd = tracefs_instance_file_open(NULL, buffer, O_RDONLY);
81 if (timerlat_fd < 0) {
82 err_msg("Error opening %s:%s\n", buffer, strerror(errno));
86 debug_msg("User-space timerlat pid %d on cpu %d\n", gettid(), cpu);
88 /* add should continue with a signal handler */
90 retval = read(timerlat_fd, buffer, 1024);
97 debug_msg("Leaving timerlat pid %d on cpu %d\n", gettid(), cpu);
102 * timerlat_u_send_kill - send a kill signal for all processes
104 * Return the number of processes that received the kill.
106 static int timerlat_u_send_kill(pid_t *procs, int nr_cpus)
111 for (i = 0; i < nr_cpus; i++) {
114 retval = kill(procs[i], SIGKILL);
118 err_msg("Error killing child process %d\n", procs[i]);
125 * timerlat_u_dispatcher - dispatch one timerlatu/ process per monitored CPU
127 * This is a thread main that will fork one new process for each monitored
128 * CPU. It will wait for:
130 * - rtla to tell to kill the child processes
131 * - some child process to die, and the cleanup all the processes
133 * whichever comes first.
136 void *timerlat_u_dispatcher(void *data)
138 int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
139 struct timerlat_u_params *params = data;
148 debug_msg("Dispatching timerlat u procs\n");
150 procs = calloc(nr_cpus, sizeof(pid_t));
152 pthread_exit(&retval);
154 for (i = 0; i < nr_cpus; i++) {
155 if (params->set && !CPU_ISSET(i, params->set))
166 snprintf(proc_name, sizeof(proc_name), "timerlatu/%d", i);
167 pthread_setname_np(pthread_self(), proc_name);
168 prctl(PR_SET_NAME, (unsigned long)proc_name, 0, 0, 0);
170 timerlat_u_main(i, params);
171 /* timerlat_u_main should exit()! Anyways... */
172 pthread_exit(&retval);
177 timerlat_u_send_kill(procs, nr_cpus);
178 debug_msg("Failed to create child processes");
179 pthread_exit(&retval);
186 while (params->should_run) {
187 /* check if processes died */
188 pid = waitpid(-1, &wstatus, WNOHANG);
190 for (i = 0; i < nr_cpus; i++) {
191 if (procs[i] == pid) {
204 timerlat_u_send_kill(procs, nr_cpus);
206 while (procs_count) {
207 pid = waitpid(-1, &wstatus, 0);
209 err_msg("Failed to monitor child processes");
210 pthread_exit(&retval);
212 for (i = 0; i < nr_cpus; i++) {
213 if (procs[i] == pid) {
220 params->stopped_running = 1;
224 pthread_exit(&retval);