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