/
githubmirror
/
strace
Обзор
Документация
Войти
/
githubmirror
/
strace
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/delay.c
188 строк
4 KB
Dmitry V. Levin
Update copyright headers
15 июн 2026, 11:00
15 июн 2026, 11:00
726d2e4
Код
Авторство
О чём код?
/* * Check delay injection. * * Copyright (c) 2018-2026 The strace developers. * All rights reserved. * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "tests.h" #include <errno.h> #include <inttypes.h> #include <limits.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <sys/wait.h> #include "scno.h" #include "kernel_timeval.h" static int64_t usecs_from_tv(const kernel_old_timeval_t *const tv) { return (int64_t) tv->tv_sec * 1000000 + tv->tv_usec; } static int64_t usecs_from_ts(const struct timespec *const ts) { return (int64_t) ts->tv_sec * 1000000 + ts->tv_nsec / 1000; } static bool check_expected(const int64_t got, const bool ge, const int64_t exp_delay, const int nproc) { const int64_t threshold = exp_delay * (ge ? (nproc - 1) : (nproc + 1)) / nproc; if (ge ? (got >= threshold) : (got <= threshold)) return true; fprintf(stderr, "Got delay of %" PRId64 ", %s than threshold value of" " %" PRId64 " (expected nominal delay value is %" PRId64 ")\n", got, ge ? "less" : "more", threshold, exp_delay); return false; } static int check_expectations(const int64_t got, const int64_t exp_delay, const int nproc, const int rc_short, const int rc_long) { if (!check_expected(got, true, exp_delay, nproc)) return rc_short; if (!check_expected(got, false, exp_delay, nproc)) return rc_long; return 0; } enum { BAD_OTHER = 2, DELAY_ENTER_TOO_SHORT = 4, DELAY_EXIT_TOO_SHORT = 8, DELAY_ENTER_TOO_LONG = 16, DELAY_EXIT_TOO_LONG = 32, MASK_DELAY_TOO_LONG = DELAY_ENTER_TOO_LONG | DELAY_EXIT_TOO_LONG, }; static int check_delay(const kernel_old_timeval_t *const tv0, const struct timespec *const ts, const kernel_old_timeval_t *const tv1, const int nproc, const int64_t delay_enter, const int64_t delay_exit) { const int64_t us0 = usecs_from_tv(tv0); const int64_t us = usecs_from_ts(ts); const int64_t us1 = usecs_from_tv(tv1); int rc = 0; rc |= check_expectations(us - us0, delay_exit, nproc, DELAY_EXIT_TOO_SHORT, DELAY_EXIT_TOO_LONG); rc |= check_expectations(us1 - us, delay_enter, nproc, DELAY_ENTER_TOO_SHORT, DELAY_ENTER_TOO_LONG); return rc; } static void do_child(const int nproc, const int delay_enter, const int delay_exit) { kernel_old_timeval_t prev = { 0, 0 }, now; struct timespec ts; int rc = 0; for (int i = 0; i < nproc; ++i, prev = now) { if (syscall(__NR_gettimeofday, &now, NULL)) perror_msg_and_fail("gettimeofday"); if (i) rc |= check_delay(&prev, &ts, &now, nproc, delay_enter, delay_exit); if (clock_gettime(CLOCK_REALTIME, &ts)) perror_msg_and_fail("clock_gettime"); } _exit(rc); } static int run_checks(const int nproc, const int delay_enter, const int delay_exit) { int rc = 0; pid_t pid; for (int i = 0; i < nproc; ++i) { pid = fork(); if (pid < 0) perror_msg_and_fail("fork"); if (pid) usleep(MAX(delay_enter, delay_exit) / nproc); else do_child(nproc, delay_enter, delay_exit); } int status; while ((pid = wait(&status)) > 0) { if (status == 0) continue; if (WIFEXITED(status)) { int es = WEXITSTATUS(status); fprintf(stderr, "pid %d exit status %d\n", pid, es); rc |= es; } else { fprintf(stderr, "pid %d wait status %#x\n", pid, status); rc |= BAD_OTHER; } } if (errno != ECHILD) perror_msg_and_fail("wait"); return rc; } int main(int ac, char *av[]) { int rc; if (ac != 4) error_msg_and_fail("usage: delay <nproc> <delay_enter> <delay_exit>"); const int nproc = atoi(av[1]); if (nproc <= 1) perror_msg_and_fail("invalid nproc: %s", av[1]); const int delay_enter = atoi(av[2]); if (delay_enter <= 0) perror_msg_and_fail("invalid delay_enter: %s", av[2]); const int delay_exit = atoi(av[3]); if (delay_exit <= 0) perror_msg_and_fail("invalid delay_exit: %s", av[3]); for (int i = 0; i < nproc; ++i) { rc = run_checks(nproc, delay_enter, delay_exit); if (rc == 0) { if (i) fprintf(stderr, "attempt #%d passed\n", i + 1); break; } if (rc & ~MASK_DELAY_TOO_LONG) break; fprintf(stderr, "attempt #%d failed\n", i + 1); } return rc; }