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