(root)/
strace-6.5/
tests-m32/
delay.c
       1  /*
       2   * Check delay injection.
       3   *
       4   * Copyright (c) 2018-2023 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include <inttypes.h>
      12  #include <limits.h>
      13  #include <stdio.h>
      14  #include <stdint.h>
      15  #include <stdlib.h>
      16  #include <unistd.h>
      17  #include <time.h>
      18  #include <sys/time.h>
      19  #include <sys/wait.h>
      20  #include "scno.h"
      21  #include "kernel_timeval.h"
      22  
      23  static int64_t
      24  usecs_from_tv(const kernel_old_timeval_t *const tv)
      25  {
      26      return (int64_t) tv->tv_sec * 1000000 + tv->tv_usec;
      27  }
      28  
      29  static int64_t
      30  usecs_from_ts(const struct timespec *const ts)
      31  {
      32      return (int64_t) ts->tv_sec * 1000000 + ts->tv_nsec / 1000;
      33  }
      34  
      35  static void
      36  check_(const int64_t got, const bool ge, const int64_t orig, const int nproc,
      37         const int exitcode)
      38  {
      39  	const int64_t thresh = (orig * (ge ? nproc - 1 : nproc + 1)) / nproc;
      40  
      41  	if (ge ? got >= thresh : got <= thresh)
      42  		return;
      43  
      44  	fprintf(stderr, "Got delay of %" PRId64 ", %s than threshold value of "
      45  			"%" PRId64 " (expected nominal delay value is %" PRId64
      46  			")\n", got, ge ? "less" : "more", thresh, orig);
      47  
      48  	_exit(exitcode);
      49  }
      50  
      51  static void
      52  check_delay(const kernel_old_timeval_t *const tv0,
      53  	    const struct timespec *const ts,
      54  	    const kernel_old_timeval_t *const tv1,
      55  	    const int nproc,
      56  	    const int64_t delay_enter,
      57  	    const int64_t delay_exit)
      58  {
      59  	const int64_t us0 = usecs_from_tv(tv0);
      60  	const int64_t us  = usecs_from_ts(ts);
      61  	const int64_t us1 = usecs_from_tv(tv1);
      62  
      63  	check_(us - us0, true,  delay_exit,  nproc, 1);
      64  	check_(us - us0, false, delay_exit,  nproc, 2);
      65  	check_(us1 - us, true,  delay_enter, nproc, 3);
      66  	check_(us1 - us, false, delay_enter, nproc, 4);
      67  }
      68  
      69  static void
      70  run(const int nproc, const int delay_enter, const int delay_exit)
      71  {
      72  	kernel_old_timeval_t prev = { 0, 0 }, now;
      73  
      74  	for (int i = 0; i < nproc; ++i, prev = now) {
      75  		struct timespec ts;
      76  
      77  		if (i && clock_gettime(CLOCK_REALTIME, &ts))
      78  			perror_msg_and_fail("clock_gettime");
      79  
      80  		if (syscall(__NR_gettimeofday, &now, NULL))
      81  			perror_msg_and_fail("gettimeofday");
      82  
      83  		if (!i)
      84  			continue;
      85  
      86  		check_delay(&prev, &ts, &now, nproc, delay_enter, delay_exit);
      87  	}
      88  
      89  	_exit(0);
      90  }
      91  
      92  int
      93  main(int ac, char *av[])
      94  {
      95  	if (ac != 4)
      96  		error_msg_and_fail("usage: delay <nproc> <delay_enter> <delay_exit>");
      97  
      98  	const int nproc = atoi(av[1]);
      99  	if (nproc <= 1)
     100  		perror_msg_and_fail("invalid nproc: %s", av[1]);
     101  
     102  	const int delay_enter = atoi(av[2]);
     103  	if (delay_enter <= 0)
     104  		perror_msg_and_fail("invalid delay_enter: %s", av[2]);
     105  
     106  	const int delay_exit = atoi(av[3]);
     107  	if (delay_exit <= 0)
     108  		perror_msg_and_fail("invalid delay_exit: %s", av[3]);
     109  
     110  	for (int i = 0; i < nproc; ++i) {
     111  		pid_t pid = fork();
     112  
     113  		if (pid)
     114  			usleep(MAX(delay_enter, delay_exit) / nproc);
     115  		else
     116  			run(nproc, delay_enter, delay_exit);
     117  	}
     118  
     119  	int status;
     120  	while (wait(&status) > 0) {
     121  		if (status)
     122  			perror_msg_and_fail("wait status %d", status);
     123  	}
     124  
     125  	return 0;
     126  }