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 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 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 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 85 is_delay_timer_created(void) 86 { 87 return delay_timer != (timer_t) -1; 88 } 89 90 bool 91 is_delay_timer_armed(void) 92 { 93 return delay_timer_is_armed; 94 } 95 96 void 97 delay_timer_expired(void) 98 { 99 delay_timer_is_armed = false; 100 } 101 102 void 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 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