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 }