]> granicus.if.org Git - strace/blob - delay.c
nlattr: add unsigned int decoders that print in hex form
[strace] / delay.c
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 }