686e2ed9b3e96530e2d1d68b157c150c8b113766
[metze/samba/wip.git] / lib / tevent / testsuite.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    testing of the events subsystem
5
6    Copyright (C) Stefan Metzmacher 2006-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 "includes.h"
27 #include "lib/tevent/tevent.h"
28 #include "system/filesys.h"
29 #include "system/select.h"
30 #include "torture/torture.h"
31 #ifdef HAVE_PTHREAD
32 #include <pthread.h>
33 #include <assert.h>
34 #endif
35
36 static int fde_count;
37
38 static void fde_handler(struct tevent_context *ev_ctx, struct tevent_fd *f, 
39                         uint16_t flags, void *private_data)
40 {
41         int *fd = (int *)private_data;
42         char c;
43 #ifdef SA_SIGINFO
44         kill(getpid(), SIGUSR1);
45 #endif
46         kill(getpid(), SIGALRM);
47         read(fd[0], &c, 1);
48         write(fd[1], &c, 1);
49         fde_count++;
50 }
51
52 static void finished_handler(struct tevent_context *ev_ctx, struct tevent_timer *te,
53                              struct timeval tval, void *private_data)
54 {
55         int *finished = (int *)private_data;
56         (*finished) = 1;
57 }
58
59 static void count_handler(struct tevent_context *ev_ctx, struct tevent_signal *te,
60                           int signum, int count, void *info, void *private_data)
61 {
62         int *countp = (int *)private_data;
63         (*countp) += count;
64 }
65
66 static bool test_event_context(struct torture_context *test,
67                                const void *test_data)
68 {
69         struct tevent_context *ev_ctx;
70         int fd[2] = { -1, -1 };
71         const char *backend = (const char *)test_data;
72         int alarm_count=0, info_count=0;
73         struct tevent_fd *fde;
74 #ifdef SA_RESTART
75         struct tevent_signal *se1 = NULL;
76 #endif
77 #ifdef SA_RESETHAND
78         struct tevent_signal *se2 = NULL;
79 #endif
80 #ifdef SA_SIGINFO
81         struct tevent_signal *se3 = NULL;
82 #endif
83         int finished=0;
84         struct timeval t;
85         char c = 0;
86
87         ev_ctx = tevent_context_init_byname(test, backend);
88         if (ev_ctx == NULL) {
89                 torture_comment(test, "event backend '%s' not supported\n", backend);
90                 return true;
91         }
92
93         torture_comment(test, "backend '%s' - %s\n",
94                         backend, __FUNCTION__);
95
96         /* reset globals */
97         fde_count = 0;
98
99         /* create a pipe */
100         pipe(fd);
101
102         fde = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ,
103                             fde_handler, fd);
104         tevent_fd_set_auto_close(fde);
105
106         tevent_add_timer(ev_ctx, ev_ctx, timeval_current_ofs(2,0),
107                          finished_handler, &finished);
108
109 #ifdef SA_RESTART
110         se1 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count);
111 #endif
112 #ifdef SA_RESETHAND
113         se2 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count);
114 #endif
115 #ifdef SA_SIGINFO
116         se3 = tevent_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count);
117 #endif
118
119         write(fd[1], &c, 1);
120
121         t = timeval_current();
122         while (!finished) {
123                 errno = 0;
124                 if (tevent_loop_once(ev_ctx) == -1) {
125                         talloc_free(ev_ctx);
126                         torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno)));
127                 }
128         }
129
130         talloc_free(fde);
131         close(fd[1]);
132
133         while (alarm_count < fde_count+1) {
134                 if (tevent_loop_once(ev_ctx) == -1) {
135                         break;
136                 }
137         }
138
139         torture_comment(test, "Got %.2f pipe events/sec\n", fde_count/timeval_elapsed(&t));
140
141 #ifdef SA_RESTART
142         talloc_free(se1);
143 #endif
144
145         torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch");
146
147 #ifdef SA_RESETHAND
148         talloc_free(se2);
149 #endif
150
151 #ifdef SA_SIGINFO
152         talloc_free(se3);
153         torture_assert_int_equal(test, info_count, fde_count, "info count mismatch");
154 #endif
155
156         talloc_free(ev_ctx);
157
158         return true;
159 }
160
161 #ifdef HAVE_PTHREAD
162
163 static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
164 static bool do_shutdown = false;
165
166 static void test_event_threaded_lock(void)
167 {
168         int ret;
169         ret = pthread_mutex_lock(&threaded_mutex);
170         assert(ret == 0);
171 }
172
173 static void test_event_threaded_unlock(void)
174 {
175         int ret;
176         ret = pthread_mutex_unlock(&threaded_mutex);
177         assert(ret == 0);
178 }
179
180 static void test_event_threaded_trace(enum tevent_trace_point point,
181                                       void *private_data)
182 {
183         switch (point) {
184         case TEVENT_TRACE_BEFORE_WAIT:
185                 test_event_threaded_unlock();
186                 break;
187         case TEVENT_TRACE_AFTER_WAIT:
188                 test_event_threaded_lock();
189                 break;
190         }
191 }
192
193 static void test_event_threaded_timer(struct tevent_context *ev,
194                                       struct tevent_timer *te,
195                                       struct timeval current_time,
196                                       void *private_data)
197 {
198         return;
199 }
200
201 static void *test_event_poll_thread(void *private_data)
202 {
203         struct tevent_context *ev = (struct tevent_context *)private_data;
204
205         test_event_threaded_lock();
206
207         while (true) {
208                 int ret;
209                 ret = tevent_loop_once(ev);
210                 assert(ret == 0);
211                 if (do_shutdown) {
212                         test_event_threaded_unlock();
213                         return NULL;
214                 }
215         }
216
217 }
218
219 static void test_event_threaded_read_handler(struct tevent_context *ev,
220                                              struct tevent_fd *fde,
221                                              uint16_t flags,
222                                              void *private_data)
223 {
224         int *pfd = (int *)private_data;
225         char c;
226         ssize_t nread;
227
228         if ((flags & TEVENT_FD_READ) == 0) {
229                 return;
230         }
231
232         do {
233                 nread = read(*pfd, &c, 1);
234         } while ((nread == -1) && (errno == EINTR));
235
236         assert(nread == 1);
237 }
238
239 static bool test_event_context_threaded(struct torture_context *test,
240                                         const void *test_data)
241 {
242         struct tevent_context *ev;
243         struct tevent_timer *te;
244         struct tevent_fd *fde;
245         pthread_t poll_thread;
246         int fds[2];
247         int ret;
248         char c = 0;
249
250         ev = tevent_context_init_byname(test, "poll_mt");
251         torture_assert(test, ev != NULL, "poll_mt not supported");
252
253         tevent_set_trace_callback(ev, test_event_threaded_trace, NULL);
254
255         te = tevent_add_timer(ev, ev, timeval_current_ofs(5, 0),
256                               test_event_threaded_timer, NULL);
257         torture_assert(test, te != NULL, "Could not add timer");
258
259         ret = pthread_create(&poll_thread, NULL, test_event_poll_thread, ev);
260         torture_assert(test, ret == 0, "Could not create poll thread");
261
262         ret = pipe(fds);
263         torture_assert(test, ret == 0, "Could not create pipe");
264
265         poll(NULL, 0, 100);
266
267         test_event_threaded_lock();
268
269         fde = tevent_add_fd(ev, ev, fds[0], TEVENT_FD_READ,
270                             test_event_threaded_read_handler, &fds[0]);
271         torture_assert(test, fde != NULL, "Could not add fd event");
272
273         test_event_threaded_unlock();
274
275         poll(NULL, 0, 100);
276
277         write(fds[1], &c, 1);
278
279         poll(NULL, 0, 100);
280
281         test_event_threaded_lock();
282         do_shutdown = true;
283         test_event_threaded_unlock();
284
285         write(fds[1], &c, 1);
286
287         ret = pthread_join(poll_thread, NULL);
288         torture_assert(test, ret == 0, "pthread_join failed");
289
290         return true;
291 }
292
293 #endif
294
295 struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
296 {
297         struct torture_suite *suite = torture_suite_create(mem_ctx, "event");
298         const char **list = tevent_backend_list(suite);
299         int i;
300
301         for (i=0;list && list[i];i++) {
302                 torture_suite_add_simple_tcase_const(suite, list[i],
303                                                test_event_context,
304                                                (const void *)list[i]);
305         }
306
307 #ifdef HAVE_PTHREAD
308         torture_suite_add_simple_tcase_const(suite, "poll_mt_threaded",
309                                              test_event_context_threaded,
310                                              NULL);
311 #endif
312
313         return suite;
314 }