brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 01dbf9a Raw
227 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2023 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>4 */5 6#define _GNU_SOURCE7#include <sched.h>8#include <fcntl.h>9#include <stdlib.h>10#include <unistd.h>11#include <stdio.h>12#include <errno.h>13#include <string.h>14#include <tracefs.h>15#include <pthread.h>16#include <sys/wait.h>17#include <sys/prctl.h>18 19#include "utils.h"20#include "timerlat_u.h"21 22/*23 * This is the user-space main for the tool timerlatu/ threads.24 *25 * It is as simple as this:26 *  - set affinity27 *  - set priority28 *  - open tracer fd29 *  - spin30 *  - close31 */32static int timerlat_u_main(int cpu, struct timerlat_u_params *params)33{34	struct sched_param sp = { .sched_priority = 95 };35	char buffer[1024];36	int timerlat_fd;37	cpu_set_t set;38	int retval;39 40	/*41	 * This all is only setting up the tool.42	 */43	CPU_ZERO(&set);44	CPU_SET(cpu, &set);45 46	retval = sched_setaffinity(gettid(), sizeof(set), &set);47	if (retval == -1) {48		debug_msg("Error setting user thread affinity %d, is the CPU online?\n", cpu);49		exit(1);50	}51 52	if (!params->sched_param) {53		retval = sched_setscheduler(0, SCHED_FIFO, &sp);54		if (retval < 0) {55			err_msg("Error setting timerlat u default priority: %s\n", strerror(errno));56			exit(1);57		}58	} else {59		retval = __set_sched_attr(getpid(), params->sched_param);60		if (retval) {61			/* __set_sched_attr prints an error message, so */62			exit(0);63		}64	}65 66	if (params->cgroup_name) {67		retval = set_pid_cgroup(gettid(), params->cgroup_name);68		if (!retval) {69			err_msg("Error setting timerlat u cgroup pid\n");70			pthread_exit(&retval);71		}72	}73 74	/*75	 * This is the tool's loop. If you want to use as base for your own tool...76	 * go ahead.77	 */78	snprintf(buffer, sizeof(buffer), "osnoise/per_cpu/cpu%d/timerlat_fd", cpu);79 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));83		exit(1);84	}85 86	debug_msg("User-space timerlat pid %d on cpu %d\n", gettid(), cpu);87 88	/* add should continue with a signal handler */89	while (true) {90		retval = read(timerlat_fd, buffer, 1024);91		if (retval < 0)92			break;93	}94 95	close(timerlat_fd);96 97	debug_msg("Leaving timerlat pid %d on cpu %d\n", gettid(), cpu);98	exit(0);99}100 101/*102 * timerlat_u_send_kill - send a kill signal for all processes103 *104 * Return the number of processes that received the kill.105 */106static int timerlat_u_send_kill(pid_t *procs, int nr_cpus)107{108	int killed = 0;109	int i, retval;110 111	for (i = 0; i < nr_cpus; i++) {112		if (!procs[i])113			continue;114		retval = kill(procs[i], SIGKILL);115		if (!retval)116			killed++;117		else118			err_msg("Error killing child process %d\n", procs[i]);119	}120 121	return killed;122}123 124/**125 * timerlat_u_dispatcher - dispatch one timerlatu/ process per monitored CPU126 *127 * This is a thread main that will fork one new process for each monitored128 * CPU. It will wait for:129 *130 *  - rtla to tell to kill the child processes131 *  - some child process to die, and the cleanup all the processes132 *133 * whichever comes first.134 *135 */136void *timerlat_u_dispatcher(void *data)137{138	int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);139	struct timerlat_u_params *params = data;140	char proc_name[128];141	int procs_count = 0;142	int retval = 1;143	pid_t *procs;144	int wstatus;145	pid_t pid;146	int i;147 148	debug_msg("Dispatching timerlat u procs\n");149 150	procs = calloc(nr_cpus, sizeof(pid_t));151	if (!procs)152		pthread_exit(&retval);153 154	for (i = 0; i < nr_cpus; i++) {155		if (params->set && !CPU_ISSET(i, params->set))156			continue;157 158		pid = fork();159 160		/* child */161		if (!pid) {162 163			/*164			 * rename the process165			 */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);169 170			timerlat_u_main(i, params);171			/* timerlat_u_main should exit()! Anyways... */172			pthread_exit(&retval);173		}174 175		/* parent */176		if (pid == -1) {177			timerlat_u_send_kill(procs, nr_cpus);178			debug_msg("Failed to create child processes");179			pthread_exit(&retval);180		}181 182		procs_count++;183		procs[i] = pid;184	}185 186	while (params->should_run) {187		/* check if processes died */188		pid = waitpid(-1, &wstatus, WNOHANG);189		if (pid != 0) {190			for (i = 0; i < nr_cpus; i++) {191				if (procs[i] == pid) {192					procs[i] = 0;193					procs_count--;194				}195			}196 197			if (!procs_count)198				break;199		}200 201		sleep(1);202	}203 204	timerlat_u_send_kill(procs, nr_cpus);205 206	while (procs_count) {207		pid = waitpid(-1, &wstatus, 0);208		if (pid == -1) {209			err_msg("Failed to monitor child processes");210			pthread_exit(&retval);211		}212		for (i = 0; i < nr_cpus; i++) {213			if (procs[i] == pid) {214				procs[i] = 0;215				procs_count--;216			}217		}218	}219 220	params->stopped_running = 1;221 222	free(procs);223	retval = 0;224	pthread_exit(&retval);225 226}227