1tevent_events(3)                    tevent                    tevent_events(3)
2
3
4

NAME

6       tevent_events - Chapter 2: Tevent events
7

Tevent events

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
15tevent_timer_handler_t()
16
17tevent_immediate_handler_t()
18
19tevent_signal_handler_t()
20
21tevent_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(&current_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
284tevent_fd_set_close_fn() - can add another function to be called at
285         the moment when a structure tevent fd is freed.
286tevent_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.
290tevent_fd_get_flags() - returns flags which are set on the file
291         descriptor connected with this tevent fd structure.
292tevent_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)
Impressum