summaryrefslogtreecommitdiffstats
path: root/lib/tevent/doc/tevent_events.dox
blob: 94fed9c69c206d76d8c821d5450d383eaf331894 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/**
@page tevent_events Chapter 2: Tevent events
@section pools Tevent events

Ok, after reading previous chapter we can start doing something useful. So, the
way of creating events is similar for all types - signals, file descriptors,
time or immediate events. At the beginning it is good to know about some
typedefs which are set in tevent library and which specify the arguments for
each callback. These callbacks are:

- tevent_timer_handler_t()

- tevent_immediate_handler_t()

- tevent_signal_handler_t()

- tevent_fd_handler_t()

According their names it is obvious that for creating callback for e.g. time
event, tevent_timer_handler_t will be used.

The best way how to introduce registering an event and setting up a callback
would be example, so examples describing all the types of events follow.

@subsection Time Time event

This example shows how to set up an event which will be repeated for a minute
with interval of 2 seconds (will be triggered 30 times). After exceeding this
limit, the event loop will finish and all the memory resources will be freed.
This is just example describing repeated activity, nothing useful is done
within foo function

@code
#include <stdio.h>
#include <unistd.h>
#include <tevent.h>
#include <sys/time.h>

struct state {
     struct timeval endtime;
     int counter;
     TALLOC_CTX *ctx;
};

static void callback(struct tevent_context *ev, struct tevent_timer *tim,
                     struct timeval current_time, void *private_data)
{
    struct state *data = talloc_get_type_abort(private_data, struct state);
    struct tevent_timer *time_event;
    struct timeval schedule;

    printf("Data value: %d\n", data->counter);
    data->counter += 1; // increase counter

    // if time has not reached its limit, set another event
    if (tevent_timeval_compare(&current_time, &(data->endtime)) < 0) {
        // do something
        // set repeat with delay 2 seconds
        schedule = tevent_timeval_current_ofs(2, 0);
        time_event = tevent_add_timer(ev, data->ctx, schedule, callback, data);
        if (time_event == NULL) { // error ...
            fprintf(stderr, "MEMORY PROBLEM\n");
            return;
        }
    } else {
        // time limit exceeded
    }
}

int main(void)  {
    struct tevent_context *event_ctx;
    TALLOC_CTX *mem_ctx;
    struct tevent_timer *time_event;
    struct timeval schedule;

    mem_ctx = talloc_new(NULL); // parent
    event_ctx = tevent_context_init(mem_ctx);

    struct state *data = talloc(mem_ctx, struct state);

    schedule = tevent_timeval_current_ofs(2, 0); // +2 second time value
    data->endtime = tevent_timeval_add(&schedule, 60, 0); // one minute time limit
    data->ctx = mem_ctx;
    data->counter = 0;

    // add time event
    time_event = tevent_add_timer(event_ctx, mem_ctx, schedule, callback, data);
    if (time_event == NULL) {
        fprintf(stderr, "FAILED\n");
        return EXIT_FAILURE;
    }

    tevent_loop_wait(event_ctx);
    talloc_free(mem_ctx);
    return EXIT_SUCCESS;
}
@endcode

Variable <code>counter</code> is only used for counting the number of triggered
functions. List of all available functions which tevent offers for working with
time are listed
<a href="http://tevent.samba.org/group__tevent__helpers.html">here</a> together
with their description. More detailed view at these functions is unnecessary
because their purpose and usage is quite simple and clear.

@subsection Immediate Immediate event

These events are, as their name indicates, activated and performed immediately.
It means that this kind of events have priority over others (except signal
events). So if there is a bulk of events registered and after that a
tevent loop is launched, then all the immediate events will be triggered before
the other events. Except other immediate events (and signal events) because
they are also processed sequentially - according the order they were scheduled.
Signals have the highest priority and therefore they are processed
preferentially. Therefore the expression immediate may not correspond exactly
to the dictionary definition of "something without delay" but rather "as soon
as possible" after all preceding immediate events.

For creating an immediate event there is a small different which lies in the
fact that the creation of such event is done in 2 steps. One represents the
creation (memory allocation), the second one represents registering as the
event within some tevent context.

@code
struct tevent_immediate *run(TALLOC_CTX* mem_ctx,
                             struct tevent_context event_ctx,
                             void * data)
{
    struct tevent_immediate *im;

    im = tevent_create_immediate(mem_ctx);
    if (im == NULL) {
        return NULL;
    }
    tevent_schedule_immediate(im, event_ctx, foo, data);

    return im;
}
@endcode

Example which may be compiled and run representing the creation of immediate event.

@code

#include <stdio.h>
#include <unistd.h>
#include <tevent.h>

struct info_struct {
    int counter;
};

static void foo(struct tevent_context *ev, struct tevent_immediate *im,
                void *private_data)
{
    struct info_struct *data = talloc_get_type_abort(private_data, struct info_struct);
    printf("Data value: %d\n", data->counter);
}

int main (void) {
    struct tevent_context *event_ctx;
    TALLOC_CTX *mem_ctx;
    struct tevent_immediate *im;

    printf("INIT\n");

    mem_ctx = talloc_new(NULL);
    event_ctx = tevent_context_init(mem_ctx);

    struct info_struct *data = talloc(mem_ctx, struct info_struct);

    // setting up private data
    data->counter = 1;

    // first immediate event
    im = tevent_create_immediate(mem_ctx);
    if (im == NULL) {
        fprintf(stderr, "FAILED\n");
        return EXIT_FAILURE;
    }
    tevent_schedule_immediate(im, event_ctx, foo, data);

    tevent_loop_wait(event_ctx);
    talloc_free(mem_ctx);

    return 0;
}
@endcode

@subsection Signal Signal event

This is an alternative to standard C library functions signal() or sigaction().
The main difference that distinguishes these ways of treating signals is their
setting up of handlers for different time intervals of the running program. 

While standard C library methods for dealing with signals offer sufficient
tools for most cases, they are inadequate for handling signals within the
tevent loop. It could be necessary to finish certain tevent requests within the
tevent loop without interruption. If a signal was sent to a program at a moment
when the tevent loop is in progress, a standard signal handler would not return
processing to the application at the very same place and it would quit the
tevent loop for ever. In such cases, tevent signal handlers offer the
possibility of dealing with these signals by masking them from the rest of
application and not quitting the loop, so the other events can still be
processed.

Tevent offers also a control function, which enables us to verify whether it is
possible to handle signals via tevent, is defined within tevent library and it
returns a boolean value revealing the result of the verification.

@code
bool tevent_signal_support (struct tevent_context *ev)
@endcode

Checking for signal support is not necessary, but if it is not guaranteed, this
is a good and easy control to prevent unexpected behaviour or failure of the
program occurring. Such a test of course does not have to be run every single
time you wish to create a signal handler, but simply at the beginning - during
the initialization procedures of the program. Afterthat, simply adapt to each
situation that arises.

@code

#include <stdio.h>
#include <tevent.h>
#include <signal.h>

static void handler(struct tevent_context *ev,
                    struct tevent_signal *se,
                    int signum,
                    int count,
                    void *siginfo,
                    void *private_data)
{

    // Do something useful

    printf("handling signal...\n");
    exit(EXIT_SUCCESS);
}

int main (void)
{
    struct tevent_context *event_ctx;
    TALLOC_CTX *mem_ctx;
    struct tevent_signal *sig;

    mem_ctx = talloc_new(NULL); //parent
    if (mem_ctx == NULL) {
        fprintf(stderr, "FAILED\n");
        return EXIT_FAILURE;
    }

    event_ctx = tevent_context_init(mem_ctx);
    if (event_ctx == NULL) {
        fprintf(stderr, "FAILED\n");
        return EXIT_FAILURE;
    }

    if (tevent_signal_support(event_ctx)) {
        // create signal event
        sig = tevent_add_signal(event_ctx, mem_ctx, SIGINT, 0, handler, NULL);
        if (sig == NULL) {
            fprintf(stderr, "FAILED\n");
            return EXIT_FAILURE;
        }
        tevent_loop_wait(event_ctx);
    }

    talloc_free(mem_ctx);
    return EXIT_SUCCESS;
}
@endcode


@subsection File File descriptor event

Support of events on file descriptors is mainly useful for socket communication
but it certainly works flawlessly with standard streams (stdin, stdout, stderr)
    as well. Working asynchronously with file descriptors enables switching
    within processing I/O operations. This ability may rise with a greater
    number of I/O operations and such overlapping leads to enhancement of the
    throughput.

There are several other functions included in tevent API related to handling
file descriptors (there are too many functions defined within tevent therefore
just some of them are fully described within this thesis. The
declaration of the rest can be easily found on the library’s website or
directly from the source code):

<ul>
<li>tevent_fd_set_close_fn() - can add another function to be called at the
    moment when a structure tevent fd is freed.</li>
<li>tevent_fd_set_auto_close() - calling this function can simplify the
    maintenance of file descriptors, because it instructs tevent to close the
    appropriate file descriptor when the tevent fd structure is about to be
    freed.</li>
<li>tevent_fd_get_flags() - returns flags which are set on the file descriptor
    connected with this tevent fd structure.</li>
<li>tevent_fd_set_flags() - sets specified flags on the event’s file
    descriptor.</li>
</ul>

@code

static void close_fd(struct tevent_context *ev, struct tevent_fd *fd_event,
                     int fd, void *private_data)
{
    // processing when fd_event is freed
}

struct static void handler(struct tevent_context *ev,
                           struct tevent_fd *fde,
                           uint16_t flags,
                           void *private_data)
{
    // handling event; reading from a file descriptor
    tevent_fd_set_close_fn (fd_event, close_fd);
}

int run(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx,
        int fd, uint16_t flags, char *buffer)
{
    struct tevent_fd* fd_event = NULL;

    if (flags & TEVENT_FD_READ) {
        fd_event = tevent_add_fd(event_ctx,
                                 mem_ctx,
                                 fd,
                                 flags,
                                 handler,
                                 buffer);
    }
    if (fd_event == NULL) {
        // error handling
    }
    return tevent_loop_once();
}
@endcode

*/