Coverage Report

Created: 2025-11-24 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/timer.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <stdbool.h>
17
18
#include <isc/async.h>
19
#include <isc/atomic.h>
20
#include <isc/heap.h>
21
#include <isc/job.h>
22
#include <isc/log.h>
23
#include <isc/magic.h>
24
#include <isc/mem.h>
25
#include <isc/once.h>
26
#include <isc/refcount.h>
27
#include <isc/thread.h>
28
#include <isc/time.h>
29
#include <isc/timer.h>
30
#include <isc/util.h>
31
#include <isc/uv.h>
32
33
#include "loop_p.h"
34
35
0
#define TIMER_MAGIC    ISC_MAGIC('T', 'I', 'M', 'R')
36
#define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC)
37
38
struct isc_timer {
39
  unsigned int magic;
40
  isc_loop_t *loop;
41
  uv_timer_t timer;
42
  isc_job_cb cb;
43
  void *cbarg;
44
  uint64_t timeout;
45
  uint64_t repeat;
46
  atomic_bool running;
47
};
48
49
void
50
isc_timer_create(isc_loop_t *loop, isc_job_cb cb, void *cbarg,
51
0
     isc_timer_t **timerp) {
52
0
  int r;
53
0
  isc_timer_t *timer;
54
55
0
  REQUIRE(cb != NULL);
56
0
  REQUIRE(timerp != NULL && *timerp == NULL);
57
58
0
  REQUIRE(VALID_LOOP(loop));
59
0
  REQUIRE(loop == isc_loop());
60
61
0
  timer = isc_mem_get(loop->mctx, sizeof(*timer));
62
0
  *timer = (isc_timer_t){
63
0
    .cb = cb,
64
0
    .cbarg = cbarg,
65
0
    .magic = TIMER_MAGIC,
66
0
  };
67
68
0
  isc_loop_attach(loop, &timer->loop);
69
70
0
  r = uv_timer_init(&loop->loop, &timer->timer);
71
0
  UV_RUNTIME_CHECK(uv_timer_init, r);
72
0
  uv_handle_set_data(&timer->timer, timer);
73
74
0
  *timerp = timer;
75
0
}
76
77
void
78
0
isc_timer_stop(isc_timer_t *timer) {
79
0
  REQUIRE(VALID_TIMER(timer));
80
81
0
  if (!atomic_compare_exchange_strong_acq_rel(&timer->running,
82
0
                &(bool){ true }, false))
83
0
  {
84
    /* Timer was already stopped */
85
0
    return;
86
0
  }
87
88
  /* Stop the timer, if the loops are matching */
89
0
  if (timer->loop == isc_loop()) {
90
0
    uv_timer_stop(&timer->timer);
91
0
  }
92
0
}
93
94
static void
95
timer_cb(uv_timer_t *handle) {
96
  isc_timer_t *timer = uv_handle_get_data(handle);
97
98
  REQUIRE(VALID_TIMER(timer));
99
100
  if (!atomic_load_acquire(&timer->running)) {
101
    uv_timer_stop(&timer->timer);
102
    return;
103
  }
104
105
  timer->cb(timer->cbarg);
106
}
107
108
void
109
isc_timer_start(isc_timer_t *timer, isc_timertype_t type,
110
0
    const isc_interval_t *interval) {
111
0
  isc_loop_t *loop = NULL;
112
0
  int r;
113
114
0
  REQUIRE(VALID_TIMER(timer));
115
0
  REQUIRE(type == isc_timertype_ticker || type == isc_timertype_once);
116
0
  REQUIRE(timer->loop == isc_loop());
117
118
0
  loop = timer->loop;
119
120
0
  REQUIRE(VALID_LOOP(loop));
121
122
0
  switch (type) {
123
0
  case isc_timertype_once:
124
0
    timer->timeout = isc_interval_ms(interval);
125
0
    timer->repeat = 0;
126
0
    break;
127
0
  case isc_timertype_ticker:
128
0
    timer->timeout = timer->repeat = isc_interval_ms(interval);
129
0
    break;
130
0
  default:
131
0
    UNREACHABLE();
132
0
  }
133
134
0
  atomic_store_release(&timer->running, true);
135
0
  r = uv_timer_start(&timer->timer, timer_cb, timer->timeout,
136
0
         timer->repeat);
137
0
  UV_RUNTIME_CHECK(uv_timer_start, r);
138
0
}
139
140
static void
141
0
timer_close(uv_handle_t *handle) {
142
0
  isc_timer_t *timer = uv_handle_get_data(handle);
143
0
  isc_loop_t *loop;
144
145
0
  REQUIRE(VALID_TIMER(timer));
146
147
0
  loop = timer->loop;
148
149
0
  isc_mem_put(loop->mctx, timer, sizeof(*timer));
150
151
0
  isc_loop_detach(&loop);
152
0
}
153
154
static void
155
timer_destroy(void *arg) {
156
  isc_timer_t *timer = arg;
157
158
  atomic_store_release(&timer->running, false);
159
  uv_timer_stop(&timer->timer);
160
  uv_close(&timer->timer, timer_close);
161
}
162
163
void
164
0
isc_timer_destroy(isc_timer_t **timerp) {
165
0
  isc_timer_t *timer = NULL;
166
167
0
  REQUIRE(timerp != NULL && VALID_TIMER(*timerp));
168
169
0
  timer = *timerp;
170
0
  *timerp = NULL;
171
172
0
  REQUIRE(timer->loop == isc_loop());
173
174
0
  timer_destroy(timer);
175
0
}
176
177
void
178
0
isc_timer_async_destroy(isc_timer_t **timerp) {
179
0
  isc_timer_t *timer = NULL;
180
181
0
  REQUIRE(timerp != NULL && VALID_TIMER(*timerp));
182
183
0
  timer = *timerp;
184
0
  *timerp = NULL;
185
186
0
  isc_timer_stop(timer);
187
0
  isc_async_run(timer->loop, timer_destroy, timer);
188
0
}
189
190
bool
191
0
isc_timer_running(isc_timer_t *timer) {
192
0
  REQUIRE(VALID_TIMER(timer));
193
194
  return atomic_load_acquire(&timer->running);
195
0
}