(root)/
strace-6.5/
src/
delay.c
       1  /*
       2   * Copyright (c) 2018-2021 The strace developers.
       3   * All rights reserved.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   */
       7  
       8  #include "defs.h"
       9  #include "delay.h"
      10  
      11  struct inject_delay_data {
      12  	struct timespec ts_enter;
      13  	struct timespec ts_exit;
      14  };
      15  
      16  static struct inject_delay_data *delay_data_vec;
      17  static size_t delay_data_vec_capacity; /* size of the arena */
      18  static size_t delay_data_vec_size;     /* size of the used arena */
      19  
      20  static timer_t delay_timer = (timer_t) -1;
      21  static bool delay_timer_is_armed;
      22  
      23  static void
      24  expand_delay_data_vec(void)
      25  {
      26  	const size_t old_capacity = delay_data_vec_capacity;
      27  	delay_data_vec = xgrowarray(delay_data_vec, &delay_data_vec_capacity,
      28  				    sizeof(*delay_data_vec));
      29  	memset(delay_data_vec + old_capacity, 0,
      30  	       (delay_data_vec_capacity - old_capacity)
      31  	       * sizeof(*delay_data_vec));
      32  }
      33  
      34  uint16_t
      35  alloc_delay_data(void)
      36  {
      37  	const uint16_t rval = delay_data_vec_size;
      38  
      39  	if (rval < delay_data_vec_size)
      40  		error_func_msg_and_die("delay index overflow");
      41  
      42  	if (delay_data_vec_size == delay_data_vec_capacity)
      43  		expand_delay_data_vec();
      44  
      45  	++delay_data_vec_size;
      46  	return rval;
      47  }
      48  
      49  void
      50  fill_delay_data(uint16_t delay_idx, struct timespec *val, bool isenter)
      51  {
      52  	if (delay_idx >= delay_data_vec_size)
      53  		error_func_msg_and_die("delay_idx >= delay_data_vec_size");
      54  
      55  	struct timespec *ts;
      56  	if (isenter)
      57  		ts = &(delay_data_vec[delay_idx].ts_enter);
      58  	else
      59  		ts = &(delay_data_vec[delay_idx].ts_exit);
      60  
      61  	*ts = *val;
      62  }
      63  
      64  static bool
      65  is_delay_timer_created(void)
      66  {
      67  	return delay_timer != (timer_t) -1;
      68  }
      69  
      70  bool
      71  is_delay_timer_armed(void)
      72  {
      73  	return delay_timer_is_armed;
      74  }
      75  
      76  void
      77  delay_timer_expired(void)
      78  {
      79  	delay_timer_is_armed = false;
      80  }
      81  
      82  void
      83  arm_delay_timer(const struct tcb *const tcp)
      84  {
      85  	const struct itimerspec its = {
      86  		.it_value = tcp->delay_expiration_time
      87  	};
      88  
      89  	if (timer_settime(delay_timer, TIMER_ABSTIME, &its, NULL))
      90  		perror_msg_and_die("timer_settime");
      91  
      92  	delay_timer_is_armed = true;
      93  
      94  	debug_func_msg("timer set to %lld.%09ld for pid %d",
      95  		       (long long) tcp->delay_expiration_time.tv_sec,
      96  		       (long) tcp->delay_expiration_time.tv_nsec,
      97  		       tcp->pid);
      98  }
      99  
     100  void
     101  delay_tcb(struct tcb *tcp, uint16_t delay_idx, bool isenter)
     102  {
     103  	if (delay_idx >= delay_data_vec_size)
     104  		error_func_msg_and_die("delay_idx >= delay_data_vec_size");
     105  
     106  	debug_func_msg("delaying pid %d on %s",
     107  		       tcp->pid, isenter ? "enter" : "exit");
     108  	tcp->flags |= TCB_DELAYED;
     109  	tcp->flags |= TCB_TAMPERED_DELAYED;
     110  
     111  	struct timespec *ts_diff;
     112  	if (isenter)
     113  		ts_diff = &(delay_data_vec[delay_idx].ts_enter);
     114  	else
     115  		ts_diff = &(delay_data_vec[delay_idx].ts_exit);
     116  
     117  	struct timespec ts_now;
     118  	clock_gettime(CLOCK_MONOTONIC, &ts_now);
     119  	ts_add(&tcp->delay_expiration_time, &ts_now, ts_diff);
     120  
     121  	if (is_delay_timer_created()) {
     122  		struct itimerspec its;
     123  		if (timer_gettime(delay_timer, &its))
     124  			perror_msg_and_die("timer_gettime");
     125  
     126  		const struct timespec *const ts_old = &its.it_value;
     127  		if (ts_nz(ts_old) && ts_cmp(ts_diff, ts_old) > 0)
     128  			return;
     129  	} else {
     130  		if (timer_create(CLOCK_MONOTONIC, NULL, &delay_timer))
     131  			perror_msg_and_die("timer_create");
     132  	}
     133  
     134  	arm_delay_timer(tcp);
     135  }