Home | History | Annotate | Download | only in strace
      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