1tevent_events(3) tevent tevent_events(3)
2
3
4
6 tevent_events - Chapter 2: Tevent events
7
9 Ok, after reading previous chapter we can start doing something useful.
10 So, the way of creating events is similar for all types - signals, file
11 descriptors, time or immediate events. At the beginning it is good to
12 know about some typedefs which are set in tevent library and which
13 specify the arguments for each callback. These callbacks are:
14
15 • tevent_timer_handler_t()
16
17 • tevent_immediate_handler_t()
18
19 • tevent_signal_handler_t()
20
21 • tevent_fd_handler_t()
22
23 According their names it is obvious that for creating callback for e.g.
24 time event, tevent_timer_handler_t will be used.
25
26 The best way how to introduce registering an event and setting up a
27 callback would be example, so examples describing all the types of
28 events follow.
29
30 Time event
31 This example shows how to set up an event which will be repeated for a
32 minute with interval of 2 seconds (will be triggered 30 times). After
33 exceeding this limit, the event loop will finish and all the memory
34 resources will be freed. This is just example describing repeated
35 activity, nothing usefull is done within foo function
36
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <tevent.h>
40 #include <sys/time.h>
41
42 struct state {
43 struct timeval endtime;
44 int counter;
45 TALLOC_CTX *ctx;
46 };
47
48 static void callback(struct tevent_context *ev, struct tevent_timer *tim,
49 struct timeval current_time, void *private_data)
50 {
51 struct state *data = talloc_get_type_abort(private_data, struct state);
52 struct tevent_timer *time_event;
53 struct timeval schedule;
54
55 printf("Data value: %d\n", data->counter);
56 data->counter += 1; // increase counter
57
58 // if time has not reached its limit, set another event
59 if (tevent_timeval_compare(¤t_time, &(data->endtime)) < 0) {
60 // do something
61 // set repeat with delay 2 seconds
62 schedule = tevent_timeval_current_ofs(2, 0);
63 time_event = tevent_add_timer(ev, data->ctx, schedule, callback, data);
64 if (time_event == NULL) { // error ...
65 fprintf(stderr, "MEMORY PROBLEM\n");
66 return;
67 }
68 } else {
69 // time limit exceeded
70 }
71 }
72
73 int main(void) {
74 struct tevent_context *event_ctx;
75 TALLOC_CTX *mem_ctx;
76 struct tevent_timer *time_event;
77 struct timeval schedule;
78
79 mem_ctx = talloc_new(NULL); // parent
80 event_ctx = tevent_context_init(mem_ctx);
81
82 struct state *data = talloc(mem_ctx, struct state);
83
84 schedule = tevent_timeval_current_ofs(2, 0); // +2 second time value
85 data->endtime = tevent_timeval_add(&schedule, 60, 0); // one minute time limit
86 data->ctx = mem_ctx;
87 data->counter = 0;
88
89 // add time event
90 time_event = tevent_add_timer(event_ctx, mem_ctx, schedule, callback, data);
91 if (time_event == NULL) {
92 fprintf(stderr, "FAILED\n");
93 return EXIT_FAILURE;
94 }
95
96 tevent_loop_wait(event_ctx);
97 talloc_free(mem_ctx);
98 return EXIT_SUCCESS;
99 }
100
101 Variable counter is only used for counting the number of triggered
102 functions. List of all available functions which tevent offers for
103 working with time are listed here together with their description. More
104 detailed view at these functions is unnecessary because their purpose
105 and usage is quite simple and clear.
106
107 Immediate event
108 These events are, as their name indicates, activated and performed
109 immediately. It means that this kind of events have priority over
110 others (except signal events). So if there is a bulk of events
111 registered and after that a tevent loop is launched, then all the
112 immediate events will be triggered before the other events. Except
113 other immediate events (and signal events) because they are also
114 processed sequentially - according the order they were scheduled.
115 Signals have the highest priority and therefore they are processed
116 preferentially. Therefore the expression immediate may not correspond
117 exactly to the dictionary definition of 'something without delay' but
118 rather 'as soon as possible' after all preceding immediate events.
119
120 For creating an immediate event there is a small different which lies
121 in the fact that the creation of such event is done in 2 steps. One
122 represents the creation (memory allocation), the second one represents
123 registering as the event within some tevent context.
124
125 struct tevent_immediate *run(TALLOC_CTX* mem_ctx,
126 struct tevent_context event_ctx,
127 void * data)
128 {
129 struct tevent_immediate *im;
130
131 im = tevent_create_immediate(mem_ctx);
132 if (im == NULL) {
133 return NULL;
134 }
135 tevent_schedule_immediate(im, event_ctx, foo, data);
136
137 return im;
138 }
139
140 Example which may be compiled and run representing the creation of
141 immediate event.
142
143 #include <stdio.h>
144 #include <unistd.h>
145 #include <tevent.h>
146
147 struct info_struct {
148 int counter;
149 };
150
151 static void foo(struct tevent_context *ev, struct tevent_immediate *im,
152 void *private_data)
153 {
154 struct info_struct *data = talloc_get_type_abort(private_data, struct info_struct);
155 printf("Data value: %d\n", data->counter);
156 }
157
158 int main (void) {
159 struct tevent_context *event_ctx;
160 TALLOC_CTX *mem_ctx;
161 struct tevent_immediate *im;
162
163 printf("INIT\n");
164
165 mem_ctx = talloc_new(NULL);
166 event_ctx = tevent_context_init(mem_ctx);
167
168 struct info_struct *data = talloc(mem_ctx, struct info_struct);
169
170 // setting up private data
171 data->counter = 1;
172
173 // first immediate event
174 im = tevent_create_immediate(mem_ctx);
175 if (im == NULL) {
176 fprintf(stderr, "FAILED\n");
177 return EXIT_FAILURE;
178 }
179 tevent_schedule_immediate(im, event_ctx, foo, data);
180
181 tevent_loop_wait(event_ctx);
182 talloc_free(mem_ctx);
183
184 return 0;
185 }
186
187 Signal event
188 This is an alternative to standard C library functions signal() or
189 sigaction(). The main difference that distinguishes these ways of
190 treating signals is their setting up of handlers for different time
191 intervals of the running program.
192
193 While standard C library methods for dealing with signals offer
194 sufficient tools for most cases, they are inadequate for handling
195 signals within the tevent loop. It could be necessary to finish certain
196 tevent requests within the tevent loop without interruption. If a
197 signal was sent to a program at a moment when the tevent loop is in
198 progress, a standard signal handler would not return processing to the
199 application at the very same place and it would quit the tevent loop
200 for ever. In such cases, tevent signal handlers offer the possibility
201 of dealing with these signals by masking them from the rest of
202 application and not quitting the loop, so the other events can still be
203 processed.
204
205 Tevent offers also a control function, which enables us to verify
206 whether it is possible to handle signals via tevent, is defined within
207 tevent library and it returns a boolean value revealing the result of
208 the verification.
209
210 bool tevent_signal_support (struct tevent_context *ev)
211
212 Checking for signal support is not necessary, but if it is not
213 guaranteed, this is a good and easy control to prevent unexpected
214 behaviour or failure of the program occurring. Such a test of course
215 does not have to be run every single time you wish to create a signal
216 handler, but simply at the beginning - during the initialization
217 procedures of the program. Afterthat, simply adapt to each situation
218 that arises.
219
220 #include <stdio.h>
221 #include <tevent.h>
222 #include <signal.h>
223
224 static void handler(struct tevent_context *ev,
225 struct tevent_signal *se,
226 int signum,
227 int count,
228 void *siginfo,
229 void *private_data)
230 {
231
232 // Do something usefull
233
234 printf("handling signal...\n");
235 exit(EXIT_SUCCESS);
236 }
237
238 int main (void)
239 {
240 struct tevent_context *event_ctx;
241 TALLOC_CTX *mem_ctx;
242 struct tevent_signal *sig;
243
244 mem_ctx = talloc_new(NULL); //parent
245 if (mem_ctx == NULL) {
246 fprintf(stderr, "FAILED\n");
247 return EXIT_FAILURE;
248 }
249
250 event_ctx = tevent_context_init(mem_ctx);
251 if (event_ctx == NULL) {
252 fprintf(stderr, "FAILED\n");
253 return EXIT_FAILURE;
254 }
255
256 if (tevent_signal_support(event_ctx)) {
257 // create signal event
258 sig = tevent_add_signal(event_ctx, mem_ctx, SIGINT, 0, handler, NULL);
259 if (sig == NULL) {
260 fprintf(stderr, "FAILED\n");
261 return EXIT_FAILURE;
262 }
263 tevent_loop_wait(event_ctx);
264 }
265
266 talloc_free(mem_ctx);
267 return EXIT_SUCCESS;
268 }
269
270 File descriptor event
271 Support of events on file descriptors is mainly useful for socket
272 communication but it certainly works flawlessly with standard streams
273 (stdin, stdout, stderr) as well. Working asynchronously with file
274 descriptors enables switching within processing I/O operations. This
275 ability may rise with a greater number of I/O operations and such
276 overlapping leads to enhancement of the throughput.
277
278 There are several other functions included in tevent API related to
279 handling file descriptors (there are too many functions defined within
280 tevent therefore just some of them are fully described within this
281 thesis. The declaration of the rest can be easily found on the
282 library’s website or directly from the source code):
283
284 • tevent_fd_set_close_fn() - can add another function to be called at
285 the moment when a structure tevent fd is freed.
286 • tevent_fd_set_auto_close() - calling this function can simplify the
287 maintenance of file descriptors, because it instructs tevent to close
288 the appropriate file descriptor when the tevent fd structure is about
289 to be freed.
290 • tevent_fd_get_flags() - returns flags which are set on the file
291 descriptor connected with this tevent fd structure.
292 • tevent_fd_set_flags() - sets specified flags on the event’s file
293 descriptor.
294 static void close_fd(struct tevent_context *ev, struct tevent_fd *fd_event,
295 int fd, void *private_data)
296 {
297 // processing when fd_event is freed
298 }
299
300 struct static void handler(struct tevent_context *ev,
301 struct tevent_fd *fde,
302 uint16_t flags,
303 void *private_data)
304 {
305 // handling event; reading from a file descriptor
306 tevent_fd_set_close_fn (fd_event, close_fd);
307 }
308
309 int run(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx,
310 int fd, uint16_t flags, char *buffer)
311 {
312 struct tevent_fd* fd_event = NULL;
313
314 if (flags & TEVENT_FD_READ) {
315 fd_event = tevent_add_fd(event_ctx,
316 mem_ctx,
317 fd,
318 flags,
319 handler,
320 buffer);
321 }
322 if (fd_event == NULL) {
323 // error handling
324 }
325 return tevent_loop_once();
326 }
327Version 0.9.8 Thu Feb 16 2023 tevent_events(3)