1 /*
2 * Copyright (c) 2018 The strace developers.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "defs.h"
29
30 struct inject_delay_data {
31 struct timespec ts_enter;
32 struct timespec ts_exit;
33 };
34
35 static struct inject_delay_data *delay_data_vec;
36 static size_t delay_data_vec_capacity; /* size of the arena */
37 static size_t delay_data_vec_size; /* size of the used arena */
38
39 static timer_t delay_timer = (timer_t) -1;
40 static bool delay_timer_is_armed;
41
42 static void
expand_delay_data_vec(void)43 expand_delay_data_vec(void)
44 {
45 const size_t old_capacity = delay_data_vec_capacity;
46 delay_data_vec = xgrowarray(delay_data_vec, &delay_data_vec_capacity,
47 sizeof(*delay_data_vec));
48 memset(delay_data_vec + old_capacity, 0,
49 (delay_data_vec_capacity - old_capacity)
50 * sizeof(*delay_data_vec));
51 }
52
53 uint16_t
alloc_delay_data(void)54 alloc_delay_data(void)
55 {
56 const uint16_t rval = delay_data_vec_size;
57
58 if (rval < delay_data_vec_size)
59 error_func_msg_and_die("delay index overflow");
60
61 if (delay_data_vec_size == delay_data_vec_capacity)
62 expand_delay_data_vec();
63
64 ++delay_data_vec_size;
65 return rval;
66 }
67
68 void
fill_delay_data(uint16_t delay_idx,int intval,bool isenter)69 fill_delay_data(uint16_t delay_idx, int intval, bool isenter)
70 {
71 if (delay_idx >= delay_data_vec_size)
72 error_func_msg_and_die("delay_idx >= delay_data_vec_size");
73
74 struct timespec *ts;
75 if (isenter)
76 ts = &(delay_data_vec[delay_idx].ts_enter);
77 else
78 ts = &(delay_data_vec[delay_idx].ts_exit);
79
80 ts->tv_sec = intval / 1000000;
81 ts->tv_nsec = intval % 1000000 * 1000;
82 }
83
84 static bool
is_delay_timer_created(void)85 is_delay_timer_created(void)
86 {
87 return delay_timer != (timer_t) -1;
88 }
89
90 bool
is_delay_timer_armed(void)91 is_delay_timer_armed(void)
92 {
93 return delay_timer_is_armed;
94 }
95
96 void
delay_timer_expired(void)97 delay_timer_expired(void)
98 {
99 delay_timer_is_armed = false;
100 }
101
102 void
arm_delay_timer(const struct tcb * const tcp)103 arm_delay_timer(const struct tcb *const tcp)
104 {
105 const struct itimerspec its = {
106 .it_value = tcp->delay_expiration_time
107 };
108
109 if (timer_settime(delay_timer, TIMER_ABSTIME, &its, NULL))
110 perror_msg_and_die("timer_settime");
111
112 delay_timer_is_armed = true;
113
114 debug_func_msg("timer set to %lld.%09ld for pid %d",
115 (long long) tcp->delay_expiration_time.tv_sec,
116 (long) tcp->delay_expiration_time.tv_nsec,
117 tcp->pid);
118 }
119
120 void
delay_tcb(struct tcb * tcp,uint16_t delay_idx,bool isenter)121 delay_tcb(struct tcb *tcp, uint16_t delay_idx, bool isenter)
122 {
123 if (delay_idx >= delay_data_vec_size)
124 error_func_msg_and_die("delay_idx >= delay_data_vec_size");
125
126 debug_func_msg("delaying pid %d on %s",
127 tcp->pid, isenter ? "enter" : "exit");
128 tcp->flags |= TCB_DELAYED;
129
130 struct timespec *ts_diff;
131 if (isenter)
132 ts_diff = &(delay_data_vec[delay_idx].ts_enter);
133 else
134 ts_diff = &(delay_data_vec[delay_idx].ts_exit);
135
136 struct timespec ts_now;
137 clock_gettime(CLOCK_MONOTONIC, &ts_now);
138 ts_add(&tcp->delay_expiration_time, &ts_now, ts_diff);
139
140 if (is_delay_timer_created()) {
141 struct itimerspec its;
142 if (timer_gettime(delay_timer, &its))
143 perror_msg_and_die("timer_gettime");
144
145 const struct timespec *const ts_old = &its.it_value;
146 if (ts_nz(ts_old) && ts_cmp(ts_diff, ts_old) > 0)
147 return;
148 } else {
149 if (timer_create(CLOCK_MONOTONIC, NULL, &delay_timer))
150 perror_msg_and_die("timer_create");
151 }
152
153 arm_delay_timer(tcp);
154 }
155