Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/tevent/tevent_immediate.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   common events code for immediate events
5
6
   Copyright (C) Stefan Metzmacher 2009
7
8
     ** NOTE! The following LGPL license applies to the tevent
9
     ** library. This does NOT imply that all of Samba is released
10
     ** under the LGPL
11
12
   This library is free software; you can redistribute it and/or
13
   modify it under the terms of the GNU Lesser General Public
14
   License as published by the Free Software Foundation; either
15
   version 3 of the License, or (at your option) any later version.
16
17
   This library is distributed in the hope that it will be useful,
18
   but WITHOUT ANY WARRANTY; without even the implied warranty of
19
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20
   Lesser General Public License for more details.
21
22
   You should have received a copy of the GNU Lesser General Public
23
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
24
*/
25
26
#include "replace.h"
27
#define TEVENT_DEPRECATED 1
28
#include "tevent.h"
29
#include "tevent_internal.h"
30
#include "tevent_util.h"
31
32
void tevent_common_immediate_cancel(struct tevent_immediate *im)
33
0
{
34
0
  const char *create_location = im->create_location;
35
0
  bool busy = im->busy;
36
0
  uint64_t tag = im->tag;
37
0
  struct tevent_context *detach_ev_ctx = NULL;
38
39
0
  if (im->destroyed) {
40
0
    tevent_abort(im->event_ctx, "tevent_immediate use after free");
41
0
    return;
42
0
  }
43
44
0
  if (im->detach_ev_ctx != NULL) {
45
0
    detach_ev_ctx = im->detach_ev_ctx;
46
0
    im->detach_ev_ctx = NULL;
47
0
    tevent_trace_immediate_callback(detach_ev_ctx,
48
0
            im,
49
0
            TEVENT_EVENT_TRACE_DETACH);
50
0
    return;
51
0
  }
52
53
0
  if (!im->event_ctx) {
54
0
    return;
55
0
  }
56
57
0
  if (im->handler_name != NULL) {
58
0
    TEVENT_DEBUG(im->event_ctx, TEVENT_DEBUG_TRACE,
59
0
           "Cancel immediate event %p \"%s\"\n",
60
0
           im, im->handler_name);
61
0
  }
62
63
  /* let the backend free im->additional_data */
64
0
  if (im->cancel_fn) {
65
0
    im->cancel_fn(im);
66
0
  }
67
68
0
  if (busy && im->handler_name == NULL) {
69
0
    detach_ev_ctx = im->event_ctx;
70
0
  } else {
71
0
    tevent_trace_immediate_callback(im->event_ctx,
72
0
            im,
73
0
            TEVENT_EVENT_TRACE_DETACH);
74
0
  }
75
0
  DLIST_REMOVE(im->event_ctx->immediate_events, im);
76
77
0
  *im = (struct tevent_immediate) {
78
0
    .create_location  = create_location,
79
0
    .busy     = busy,
80
0
    .tag      = tag,
81
0
    .detach_ev_ctx    = detach_ev_ctx,
82
0
  };
83
84
0
  if (!busy) {
85
0
    talloc_set_destructor(im, NULL);
86
0
  }
87
0
}
88
89
/*
90
  destroy an immediate event
91
*/
92
static int tevent_common_immediate_destructor(struct tevent_immediate *im)
93
0
{
94
0
  if (im->destroyed) {
95
0
    tevent_common_check_double_free(im,
96
0
            "tevent_immediate double free");
97
0
    goto done;
98
0
  }
99
100
0
  tevent_common_immediate_cancel(im);
101
102
0
  im->destroyed = true;
103
104
0
done:
105
0
  if (im->busy) {
106
0
    return -1;
107
0
  }
108
109
0
  return 0;
110
0
}
111
112
/*
113
 * schedule an immediate event on
114
 */
115
void tevent_common_schedule_immediate(struct tevent_immediate *im,
116
              struct tevent_context *ev,
117
              tevent_immediate_handler_t handler,
118
              void *private_data,
119
              const char *handler_name,
120
              const char *location)
121
0
{
122
0
  const char *create_location = im->create_location;
123
0
  bool busy = im->busy;
124
0
  uint64_t tag = im->tag;
125
0
  struct tevent_wrapper_glue *glue = im->wrapper;
126
127
0
  tevent_common_immediate_cancel(im);
128
129
0
  if (!handler) {
130
0
    return;
131
0
  }
132
133
0
  *im = (struct tevent_immediate) {
134
0
    .event_ctx    = ev,
135
0
    .wrapper    = glue,
136
0
    .handler    = handler,
137
0
    .private_data   = private_data,
138
0
    .handler_name   = handler_name,
139
0
    .create_location  = create_location,
140
0
    .schedule_location  = location,
141
0
    .busy     = busy,
142
0
    .tag      = tag,
143
0
  };
144
145
0
  tevent_trace_immediate_callback(im->event_ctx, im, TEVENT_EVENT_TRACE_ATTACH);
146
0
  DLIST_ADD_END(ev->immediate_events, im);
147
0
  talloc_set_destructor(im, tevent_common_immediate_destructor);
148
149
0
  TEVENT_DEBUG(ev, TEVENT_DEBUG_TRACE,
150
0
         "Schedule immediate event \"%s\": %p\n",
151
0
         handler_name, im);
152
0
}
153
154
int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
155
             bool *removed)
156
0
{
157
0
  struct tevent_context *handler_ev = im->event_ctx;
158
0
  struct tevent_context *ev = im->event_ctx;
159
0
  struct tevent_immediate cur = *im;
160
161
0
  if (removed != NULL) {
162
0
    *removed = false;
163
0
  }
164
165
0
  TEVENT_DEBUG(ev, TEVENT_DEBUG_TRACE,
166
0
         "Run immediate event \"%s\": %p\n",
167
0
         im->handler_name, im);
168
169
  /*
170
   * remember the handler and then clear the event
171
   * the handler might reschedule the event
172
   */
173
174
0
  im->busy = true;
175
0
  im->handler_name = NULL;
176
0
  tevent_common_immediate_cancel(im);
177
0
  if (cur.wrapper != NULL) {
178
0
    handler_ev = cur.wrapper->wrap_ev;
179
180
0
    tevent_wrapper_push_use_internal(handler_ev, cur.wrapper);
181
0
    cur.wrapper->ops->before_immediate_handler(
182
0
          cur.wrapper->wrap_ev,
183
0
          cur.wrapper->private_state,
184
0
          cur.wrapper->main_ev,
185
0
          im,
186
0
          cur.handler_name,
187
0
          cur.schedule_location);
188
0
  }
189
0
  tevent_trace_immediate_callback(cur.event_ctx, im, TEVENT_EVENT_TRACE_BEFORE_HANDLER);
190
0
  cur.handler(handler_ev, im, cur.private_data);
191
0
  if (cur.wrapper != NULL) {
192
0
    cur.wrapper->ops->after_immediate_handler(
193
0
          cur.wrapper->wrap_ev,
194
0
          cur.wrapper->private_state,
195
0
          cur.wrapper->main_ev,
196
0
          im,
197
0
          cur.handler_name,
198
0
          cur.schedule_location);
199
0
    tevent_wrapper_pop_use_internal(handler_ev, cur.wrapper);
200
0
  }
201
0
  im->busy = false;
202
203
  /* The event was removed in tevent_common_immediate_cancel(). */
204
0
  if (im->detach_ev_ctx != NULL) {
205
0
    struct tevent_context *detach_ev_ctx = im->detach_ev_ctx;
206
0
    im->detach_ev_ctx = NULL;
207
0
    tevent_trace_immediate_callback(detach_ev_ctx,
208
0
            im,
209
0
            TEVENT_EVENT_TRACE_DETACH);
210
0
  }
211
212
0
  if (im->destroyed) {
213
0
    talloc_set_destructor(im, NULL);
214
0
    TALLOC_FREE(im);
215
0
    if (removed != NULL) {
216
0
      *removed = true;
217
0
    }
218
0
  }
219
220
0
  return 0;
221
0
}
222
223
/*
224
  trigger the first immediate event and return true
225
  if no event was triggered return false
226
*/
227
bool tevent_common_loop_immediate(struct tevent_context *ev)
228
0
{
229
0
  struct tevent_immediate *im = ev->immediate_events;
230
0
  int ret;
231
232
0
  if (!im) {
233
0
    return false;
234
0
  }
235
236
0
  ret = tevent_common_invoke_immediate_handler(im, NULL);
237
0
  if (ret != 0) {
238
0
    tevent_abort(ev, "tevent_common_invoke_immediate_handler() failed");
239
0
  }
240
241
0
  return true;
242
0
}
243
244
245
void tevent_immediate_set_tag(struct tevent_immediate *im, uint64_t tag)
246
0
{
247
0
  if (im == NULL) {
248
0
    return;
249
0
  }
250
251
0
  im->tag = tag;
252
0
}
253
254
uint64_t tevent_immediate_get_tag(const struct tevent_immediate *im)
255
0
{
256
0
  if (im == NULL) {
257
0
    return 0;
258
0
  }
259
260
0
  return im->tag;
261
0
}