• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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