Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu> |
michael@0 | 3 | * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson |
michael@0 | 4 | * |
michael@0 | 5 | * Redistribution and use in source and binary forms, with or without |
michael@0 | 6 | * modification, are permitted provided that the following conditions |
michael@0 | 7 | * are met: |
michael@0 | 8 | * 1. Redistributions of source code must retain the above copyright |
michael@0 | 9 | * notice, this list of conditions and the following disclaimer. |
michael@0 | 10 | * 2. Redistributions in binary form must reproduce the above copyright |
michael@0 | 11 | * notice, this list of conditions and the following disclaimer in the |
michael@0 | 12 | * documentation and/or other materials provided with the distribution. |
michael@0 | 13 | * 3. The name of the author may not be used to endorse or promote products |
michael@0 | 14 | * derived from this software without specific prior written permission. |
michael@0 | 15 | * |
michael@0 | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
michael@0 | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
michael@0 | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
michael@0 | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
michael@0 | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
michael@0 | 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
michael@0 | 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 26 | */ |
michael@0 | 27 | |
michael@0 | 28 | #ifdef WIN32 |
michael@0 | 29 | #include <winsock2.h> |
michael@0 | 30 | #include <windows.h> |
michael@0 | 31 | #endif |
michael@0 | 32 | |
michael@0 | 33 | #include "event2/event-config.h" |
michael@0 | 34 | |
michael@0 | 35 | #include <sys/types.h> |
michael@0 | 36 | #include <sys/stat.h> |
michael@0 | 37 | #ifdef _EVENT_HAVE_SYS_TIME_H |
michael@0 | 38 | #include <sys/time.h> |
michael@0 | 39 | #endif |
michael@0 | 40 | #include <sys/queue.h> |
michael@0 | 41 | #ifndef WIN32 |
michael@0 | 42 | #include <sys/socket.h> |
michael@0 | 43 | #include <sys/wait.h> |
michael@0 | 44 | #include <signal.h> |
michael@0 | 45 | #include <unistd.h> |
michael@0 | 46 | #include <netdb.h> |
michael@0 | 47 | #endif |
michael@0 | 48 | #include <fcntl.h> |
michael@0 | 49 | #include <signal.h> |
michael@0 | 50 | #include <stdlib.h> |
michael@0 | 51 | #include <stdio.h> |
michael@0 | 52 | #include <string.h> |
michael@0 | 53 | #include <errno.h> |
michael@0 | 54 | #include <assert.h> |
michael@0 | 55 | #include <ctype.h> |
michael@0 | 56 | |
michael@0 | 57 | #include "event2/event.h" |
michael@0 | 58 | #include "event2/event_struct.h" |
michael@0 | 59 | #include "event2/event_compat.h" |
michael@0 | 60 | #include "event2/tag.h" |
michael@0 | 61 | #include "event2/buffer.h" |
michael@0 | 62 | #include "event2/buffer_compat.h" |
michael@0 | 63 | #include "event2/util.h" |
michael@0 | 64 | #include "event-internal.h" |
michael@0 | 65 | #include "evthread-internal.h" |
michael@0 | 66 | #include "util-internal.h" |
michael@0 | 67 | #include "log-internal.h" |
michael@0 | 68 | |
michael@0 | 69 | #include "regress.h" |
michael@0 | 70 | |
michael@0 | 71 | #ifndef WIN32 |
michael@0 | 72 | #include "regress.gen.h" |
michael@0 | 73 | #endif |
michael@0 | 74 | |
michael@0 | 75 | evutil_socket_t pair[2]; |
michael@0 | 76 | int test_ok; |
michael@0 | 77 | int called; |
michael@0 | 78 | struct event_base *global_base; |
michael@0 | 79 | |
michael@0 | 80 | static char wbuf[4096]; |
michael@0 | 81 | static char rbuf[4096]; |
michael@0 | 82 | static int woff; |
michael@0 | 83 | static int roff; |
michael@0 | 84 | static int usepersist; |
michael@0 | 85 | static struct timeval tset; |
michael@0 | 86 | static struct timeval tcalled; |
michael@0 | 87 | |
michael@0 | 88 | |
michael@0 | 89 | #define TEST1 "this is a test" |
michael@0 | 90 | #define SECONDS 1 |
michael@0 | 91 | |
michael@0 | 92 | #ifndef SHUT_WR |
michael@0 | 93 | #define SHUT_WR 1 |
michael@0 | 94 | #endif |
michael@0 | 95 | |
michael@0 | 96 | #ifdef WIN32 |
michael@0 | 97 | #define write(fd,buf,len) send((fd),(buf),(int)(len),0) |
michael@0 | 98 | #define read(fd,buf,len) recv((fd),(buf),(int)(len),0) |
michael@0 | 99 | #endif |
michael@0 | 100 | |
michael@0 | 101 | struct basic_cb_args |
michael@0 | 102 | { |
michael@0 | 103 | struct event_base *eb; |
michael@0 | 104 | struct event *ev; |
michael@0 | 105 | unsigned int callcount; |
michael@0 | 106 | }; |
michael@0 | 107 | |
michael@0 | 108 | static void |
michael@0 | 109 | simple_read_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 110 | { |
michael@0 | 111 | char buf[256]; |
michael@0 | 112 | int len; |
michael@0 | 113 | |
michael@0 | 114 | len = read(fd, buf, sizeof(buf)); |
michael@0 | 115 | |
michael@0 | 116 | if (len) { |
michael@0 | 117 | if (!called) { |
michael@0 | 118 | if (event_add(arg, NULL) == -1) |
michael@0 | 119 | exit(1); |
michael@0 | 120 | } |
michael@0 | 121 | } else if (called == 1) |
michael@0 | 122 | test_ok = 1; |
michael@0 | 123 | |
michael@0 | 124 | called++; |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | static void |
michael@0 | 128 | basic_read_cb(evutil_socket_t fd, short event, void *data) |
michael@0 | 129 | { |
michael@0 | 130 | char buf[256]; |
michael@0 | 131 | int len; |
michael@0 | 132 | struct basic_cb_args *arg = data; |
michael@0 | 133 | |
michael@0 | 134 | len = read(fd, buf, sizeof(buf)); |
michael@0 | 135 | |
michael@0 | 136 | if (len < 0) { |
michael@0 | 137 | tt_fail_perror("read (callback)"); |
michael@0 | 138 | } else { |
michael@0 | 139 | switch (arg->callcount++) { |
michael@0 | 140 | case 0: /* first call: expect to read data; cycle */ |
michael@0 | 141 | if (len > 0) |
michael@0 | 142 | return; |
michael@0 | 143 | |
michael@0 | 144 | tt_fail_msg("EOF before data read"); |
michael@0 | 145 | break; |
michael@0 | 146 | |
michael@0 | 147 | case 1: /* second call: expect EOF; stop */ |
michael@0 | 148 | if (len > 0) |
michael@0 | 149 | tt_fail_msg("not all data read on first cycle"); |
michael@0 | 150 | break; |
michael@0 | 151 | |
michael@0 | 152 | default: /* third call: should not happen */ |
michael@0 | 153 | tt_fail_msg("too many cycles"); |
michael@0 | 154 | } |
michael@0 | 155 | } |
michael@0 | 156 | |
michael@0 | 157 | event_del(arg->ev); |
michael@0 | 158 | event_base_loopexit(arg->eb, NULL); |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | static void |
michael@0 | 162 | dummy_read_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 163 | { |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | static void |
michael@0 | 167 | simple_write_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 168 | { |
michael@0 | 169 | int len; |
michael@0 | 170 | |
michael@0 | 171 | len = write(fd, TEST1, strlen(TEST1) + 1); |
michael@0 | 172 | if (len == -1) |
michael@0 | 173 | test_ok = 0; |
michael@0 | 174 | else |
michael@0 | 175 | test_ok = 1; |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | static void |
michael@0 | 179 | multiple_write_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 180 | { |
michael@0 | 181 | struct event *ev = arg; |
michael@0 | 182 | int len; |
michael@0 | 183 | |
michael@0 | 184 | len = 128; |
michael@0 | 185 | if (woff + len >= (int)sizeof(wbuf)) |
michael@0 | 186 | len = sizeof(wbuf) - woff; |
michael@0 | 187 | |
michael@0 | 188 | len = write(fd, wbuf + woff, len); |
michael@0 | 189 | if (len == -1) { |
michael@0 | 190 | fprintf(stderr, "%s: write\n", __func__); |
michael@0 | 191 | if (usepersist) |
michael@0 | 192 | event_del(ev); |
michael@0 | 193 | return; |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | woff += len; |
michael@0 | 197 | |
michael@0 | 198 | if (woff >= (int)sizeof(wbuf)) { |
michael@0 | 199 | shutdown(fd, SHUT_WR); |
michael@0 | 200 | if (usepersist) |
michael@0 | 201 | event_del(ev); |
michael@0 | 202 | return; |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | if (!usepersist) { |
michael@0 | 206 | if (event_add(ev, NULL) == -1) |
michael@0 | 207 | exit(1); |
michael@0 | 208 | } |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | static void |
michael@0 | 212 | multiple_read_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 213 | { |
michael@0 | 214 | struct event *ev = arg; |
michael@0 | 215 | int len; |
michael@0 | 216 | |
michael@0 | 217 | len = read(fd, rbuf + roff, sizeof(rbuf) - roff); |
michael@0 | 218 | if (len == -1) |
michael@0 | 219 | fprintf(stderr, "%s: read\n", __func__); |
michael@0 | 220 | if (len <= 0) { |
michael@0 | 221 | if (usepersist) |
michael@0 | 222 | event_del(ev); |
michael@0 | 223 | return; |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | roff += len; |
michael@0 | 227 | if (!usepersist) { |
michael@0 | 228 | if (event_add(ev, NULL) == -1) |
michael@0 | 229 | exit(1); |
michael@0 | 230 | } |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | static void |
michael@0 | 234 | timeout_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 235 | { |
michael@0 | 236 | struct timeval tv; |
michael@0 | 237 | int diff; |
michael@0 | 238 | |
michael@0 | 239 | evutil_gettimeofday(&tcalled, NULL); |
michael@0 | 240 | if (evutil_timercmp(&tcalled, &tset, >)) |
michael@0 | 241 | evutil_timersub(&tcalled, &tset, &tv); |
michael@0 | 242 | else |
michael@0 | 243 | evutil_timersub(&tset, &tcalled, &tv); |
michael@0 | 244 | |
michael@0 | 245 | diff = tv.tv_sec*1000 + tv.tv_usec/1000 - SECONDS * 1000; |
michael@0 | 246 | if (diff < 0) |
michael@0 | 247 | diff = -diff; |
michael@0 | 248 | |
michael@0 | 249 | if (diff < 100) |
michael@0 | 250 | test_ok = 1; |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | struct both { |
michael@0 | 254 | struct event ev; |
michael@0 | 255 | int nread; |
michael@0 | 256 | }; |
michael@0 | 257 | |
michael@0 | 258 | static void |
michael@0 | 259 | combined_read_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 260 | { |
michael@0 | 261 | struct both *both = arg; |
michael@0 | 262 | char buf[128]; |
michael@0 | 263 | int len; |
michael@0 | 264 | |
michael@0 | 265 | len = read(fd, buf, sizeof(buf)); |
michael@0 | 266 | if (len == -1) |
michael@0 | 267 | fprintf(stderr, "%s: read\n", __func__); |
michael@0 | 268 | if (len <= 0) |
michael@0 | 269 | return; |
michael@0 | 270 | |
michael@0 | 271 | both->nread += len; |
michael@0 | 272 | if (event_add(&both->ev, NULL) == -1) |
michael@0 | 273 | exit(1); |
michael@0 | 274 | } |
michael@0 | 275 | |
michael@0 | 276 | static void |
michael@0 | 277 | combined_write_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 278 | { |
michael@0 | 279 | struct both *both = arg; |
michael@0 | 280 | char buf[128]; |
michael@0 | 281 | int len; |
michael@0 | 282 | |
michael@0 | 283 | len = sizeof(buf); |
michael@0 | 284 | if (len > both->nread) |
michael@0 | 285 | len = both->nread; |
michael@0 | 286 | |
michael@0 | 287 | memset(buf, 'q', len); |
michael@0 | 288 | |
michael@0 | 289 | len = write(fd, buf, len); |
michael@0 | 290 | if (len == -1) |
michael@0 | 291 | fprintf(stderr, "%s: write\n", __func__); |
michael@0 | 292 | if (len <= 0) { |
michael@0 | 293 | shutdown(fd, SHUT_WR); |
michael@0 | 294 | return; |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | both->nread -= len; |
michael@0 | 298 | if (event_add(&both->ev, NULL) == -1) |
michael@0 | 299 | exit(1); |
michael@0 | 300 | } |
michael@0 | 301 | |
michael@0 | 302 | /* These macros used to replicate the work of the legacy test wrapper code */ |
michael@0 | 303 | #define setup_test(x) do { \ |
michael@0 | 304 | if (!in_legacy_test_wrapper) { \ |
michael@0 | 305 | TT_FAIL(("Legacy test %s not wrapped properly", x)); \ |
michael@0 | 306 | return; \ |
michael@0 | 307 | } \ |
michael@0 | 308 | } while (0) |
michael@0 | 309 | #define cleanup_test() setup_test("cleanup") |
michael@0 | 310 | |
michael@0 | 311 | static void |
michael@0 | 312 | test_simpleread(void) |
michael@0 | 313 | { |
michael@0 | 314 | struct event ev; |
michael@0 | 315 | |
michael@0 | 316 | /* Very simple read test */ |
michael@0 | 317 | setup_test("Simple read: "); |
michael@0 | 318 | |
michael@0 | 319 | if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 320 | tt_fail_perror("write"); |
michael@0 | 321 | } |
michael@0 | 322 | |
michael@0 | 323 | shutdown(pair[0], SHUT_WR); |
michael@0 | 324 | |
michael@0 | 325 | event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev); |
michael@0 | 326 | if (event_add(&ev, NULL) == -1) |
michael@0 | 327 | exit(1); |
michael@0 | 328 | event_dispatch(); |
michael@0 | 329 | |
michael@0 | 330 | cleanup_test(); |
michael@0 | 331 | } |
michael@0 | 332 | |
michael@0 | 333 | static void |
michael@0 | 334 | test_simplewrite(void) |
michael@0 | 335 | { |
michael@0 | 336 | struct event ev; |
michael@0 | 337 | |
michael@0 | 338 | /* Very simple write test */ |
michael@0 | 339 | setup_test("Simple write: "); |
michael@0 | 340 | |
michael@0 | 341 | event_set(&ev, pair[0], EV_WRITE, simple_write_cb, &ev); |
michael@0 | 342 | if (event_add(&ev, NULL) == -1) |
michael@0 | 343 | exit(1); |
michael@0 | 344 | event_dispatch(); |
michael@0 | 345 | |
michael@0 | 346 | cleanup_test(); |
michael@0 | 347 | } |
michael@0 | 348 | |
michael@0 | 349 | static void |
michael@0 | 350 | simpleread_multiple_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 351 | { |
michael@0 | 352 | if (++called == 2) |
michael@0 | 353 | test_ok = 1; |
michael@0 | 354 | } |
michael@0 | 355 | |
michael@0 | 356 | static void |
michael@0 | 357 | test_simpleread_multiple(void) |
michael@0 | 358 | { |
michael@0 | 359 | struct event one, two; |
michael@0 | 360 | |
michael@0 | 361 | /* Very simple read test */ |
michael@0 | 362 | setup_test("Simple read to multiple evens: "); |
michael@0 | 363 | |
michael@0 | 364 | if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 365 | tt_fail_perror("write"); |
michael@0 | 366 | } |
michael@0 | 367 | |
michael@0 | 368 | shutdown(pair[0], SHUT_WR); |
michael@0 | 369 | |
michael@0 | 370 | event_set(&one, pair[1], EV_READ, simpleread_multiple_cb, NULL); |
michael@0 | 371 | if (event_add(&one, NULL) == -1) |
michael@0 | 372 | exit(1); |
michael@0 | 373 | event_set(&two, pair[1], EV_READ, simpleread_multiple_cb, NULL); |
michael@0 | 374 | if (event_add(&two, NULL) == -1) |
michael@0 | 375 | exit(1); |
michael@0 | 376 | event_dispatch(); |
michael@0 | 377 | |
michael@0 | 378 | cleanup_test(); |
michael@0 | 379 | } |
michael@0 | 380 | |
michael@0 | 381 | static int have_closed = 0; |
michael@0 | 382 | static int premature_event = 0; |
michael@0 | 383 | static void |
michael@0 | 384 | simpleclose_close_fd_cb(evutil_socket_t s, short what, void *ptr) |
michael@0 | 385 | { |
michael@0 | 386 | evutil_socket_t **fds = ptr; |
michael@0 | 387 | TT_BLATHER(("Closing")); |
michael@0 | 388 | evutil_closesocket(*fds[0]); |
michael@0 | 389 | evutil_closesocket(*fds[1]); |
michael@0 | 390 | *fds[0] = -1; |
michael@0 | 391 | *fds[1] = -1; |
michael@0 | 392 | have_closed = 1; |
michael@0 | 393 | } |
michael@0 | 394 | |
michael@0 | 395 | static void |
michael@0 | 396 | record_event_cb(evutil_socket_t s, short what, void *ptr) |
michael@0 | 397 | { |
michael@0 | 398 | short *whatp = ptr; |
michael@0 | 399 | if (!have_closed) |
michael@0 | 400 | premature_event = 1; |
michael@0 | 401 | *whatp = what; |
michael@0 | 402 | TT_BLATHER(("Recorded %d on socket %d", (int)what, (int)s)); |
michael@0 | 403 | } |
michael@0 | 404 | |
michael@0 | 405 | static void |
michael@0 | 406 | test_simpleclose(void *ptr) |
michael@0 | 407 | { |
michael@0 | 408 | /* Test that a close of FD is detected as a read and as a write. */ |
michael@0 | 409 | struct event_base *base = event_base_new(); |
michael@0 | 410 | evutil_socket_t pair1[2]={-1,-1}, pair2[2] = {-1, -1}; |
michael@0 | 411 | evutil_socket_t *to_close[2]; |
michael@0 | 412 | struct event *rev=NULL, *wev=NULL, *closeev=NULL; |
michael@0 | 413 | struct timeval tv; |
michael@0 | 414 | short got_read_on_close = 0, got_write_on_close = 0; |
michael@0 | 415 | char buf[1024]; |
michael@0 | 416 | memset(buf, 99, sizeof(buf)); |
michael@0 | 417 | #ifdef WIN32 |
michael@0 | 418 | #define LOCAL_SOCKETPAIR_AF AF_INET |
michael@0 | 419 | #else |
michael@0 | 420 | #define LOCAL_SOCKETPAIR_AF AF_UNIX |
michael@0 | 421 | #endif |
michael@0 | 422 | if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair1)<0) |
michael@0 | 423 | TT_DIE(("socketpair: %s", strerror(errno))); |
michael@0 | 424 | if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair2)<0) |
michael@0 | 425 | TT_DIE(("socketpair: %s", strerror(errno))); |
michael@0 | 426 | if (evutil_make_socket_nonblocking(pair1[1]) < 0) |
michael@0 | 427 | TT_DIE(("make_socket_nonblocking")); |
michael@0 | 428 | if (evutil_make_socket_nonblocking(pair2[1]) < 0) |
michael@0 | 429 | TT_DIE(("make_socket_nonblocking")); |
michael@0 | 430 | |
michael@0 | 431 | /** Stuff pair2[1] full of data, until write fails */ |
michael@0 | 432 | while (1) { |
michael@0 | 433 | int r = write(pair2[1], buf, sizeof(buf)); |
michael@0 | 434 | if (r<0) { |
michael@0 | 435 | int err = evutil_socket_geterror(pair2[1]); |
michael@0 | 436 | if (! EVUTIL_ERR_RW_RETRIABLE(err)) |
michael@0 | 437 | TT_DIE(("write failed strangely: %s", |
michael@0 | 438 | evutil_socket_error_to_string(err))); |
michael@0 | 439 | break; |
michael@0 | 440 | } |
michael@0 | 441 | } |
michael@0 | 442 | to_close[0] = &pair1[0]; |
michael@0 | 443 | to_close[1] = &pair2[0]; |
michael@0 | 444 | |
michael@0 | 445 | closeev = event_new(base, -1, EV_TIMEOUT, simpleclose_close_fd_cb, |
michael@0 | 446 | to_close); |
michael@0 | 447 | rev = event_new(base, pair1[1], EV_READ, record_event_cb, |
michael@0 | 448 | &got_read_on_close); |
michael@0 | 449 | TT_BLATHER(("Waiting for read on %d", (int)pair1[1])); |
michael@0 | 450 | wev = event_new(base, pair2[1], EV_WRITE, record_event_cb, |
michael@0 | 451 | &got_write_on_close); |
michael@0 | 452 | TT_BLATHER(("Waiting for write on %d", (int)pair2[1])); |
michael@0 | 453 | tv.tv_sec = 0; |
michael@0 | 454 | tv.tv_usec = 100*1000; /* Close pair1[0] after a little while, and make |
michael@0 | 455 | * sure we get a read event. */ |
michael@0 | 456 | event_add(closeev, &tv); |
michael@0 | 457 | event_add(rev, NULL); |
michael@0 | 458 | event_add(wev, NULL); |
michael@0 | 459 | /* Don't let the test go on too long. */ |
michael@0 | 460 | tv.tv_sec = 0; |
michael@0 | 461 | tv.tv_usec = 200*1000; |
michael@0 | 462 | event_base_loopexit(base, &tv); |
michael@0 | 463 | event_base_loop(base, 0); |
michael@0 | 464 | |
michael@0 | 465 | tt_int_op(got_read_on_close, ==, EV_READ); |
michael@0 | 466 | tt_int_op(got_write_on_close, ==, EV_WRITE); |
michael@0 | 467 | tt_int_op(premature_event, ==, 0); |
michael@0 | 468 | |
michael@0 | 469 | end: |
michael@0 | 470 | if (pair1[0] >= 0) |
michael@0 | 471 | evutil_closesocket(pair1[0]); |
michael@0 | 472 | if (pair1[1] >= 0) |
michael@0 | 473 | evutil_closesocket(pair1[1]); |
michael@0 | 474 | if (pair2[0] >= 0) |
michael@0 | 475 | evutil_closesocket(pair2[0]); |
michael@0 | 476 | if (pair2[1] >= 0) |
michael@0 | 477 | evutil_closesocket(pair2[1]); |
michael@0 | 478 | if (rev) |
michael@0 | 479 | event_free(rev); |
michael@0 | 480 | if (wev) |
michael@0 | 481 | event_free(wev); |
michael@0 | 482 | if (closeev) |
michael@0 | 483 | event_free(closeev); |
michael@0 | 484 | if (base) |
michael@0 | 485 | event_base_free(base); |
michael@0 | 486 | } |
michael@0 | 487 | |
michael@0 | 488 | |
michael@0 | 489 | static void |
michael@0 | 490 | test_multiple(void) |
michael@0 | 491 | { |
michael@0 | 492 | struct event ev, ev2; |
michael@0 | 493 | int i; |
michael@0 | 494 | |
michael@0 | 495 | /* Multiple read and write test */ |
michael@0 | 496 | setup_test("Multiple read/write: "); |
michael@0 | 497 | memset(rbuf, 0, sizeof(rbuf)); |
michael@0 | 498 | for (i = 0; i < (int)sizeof(wbuf); i++) |
michael@0 | 499 | wbuf[i] = i; |
michael@0 | 500 | |
michael@0 | 501 | roff = woff = 0; |
michael@0 | 502 | usepersist = 0; |
michael@0 | 503 | |
michael@0 | 504 | event_set(&ev, pair[0], EV_WRITE, multiple_write_cb, &ev); |
michael@0 | 505 | if (event_add(&ev, NULL) == -1) |
michael@0 | 506 | exit(1); |
michael@0 | 507 | event_set(&ev2, pair[1], EV_READ, multiple_read_cb, &ev2); |
michael@0 | 508 | if (event_add(&ev2, NULL) == -1) |
michael@0 | 509 | exit(1); |
michael@0 | 510 | event_dispatch(); |
michael@0 | 511 | |
michael@0 | 512 | if (roff == woff) |
michael@0 | 513 | test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0; |
michael@0 | 514 | |
michael@0 | 515 | cleanup_test(); |
michael@0 | 516 | } |
michael@0 | 517 | |
michael@0 | 518 | static void |
michael@0 | 519 | test_persistent(void) |
michael@0 | 520 | { |
michael@0 | 521 | struct event ev, ev2; |
michael@0 | 522 | int i; |
michael@0 | 523 | |
michael@0 | 524 | /* Multiple read and write test with persist */ |
michael@0 | 525 | setup_test("Persist read/write: "); |
michael@0 | 526 | memset(rbuf, 0, sizeof(rbuf)); |
michael@0 | 527 | for (i = 0; i < (int)sizeof(wbuf); i++) |
michael@0 | 528 | wbuf[i] = i; |
michael@0 | 529 | |
michael@0 | 530 | roff = woff = 0; |
michael@0 | 531 | usepersist = 1; |
michael@0 | 532 | |
michael@0 | 533 | event_set(&ev, pair[0], EV_WRITE|EV_PERSIST, multiple_write_cb, &ev); |
michael@0 | 534 | if (event_add(&ev, NULL) == -1) |
michael@0 | 535 | exit(1); |
michael@0 | 536 | event_set(&ev2, pair[1], EV_READ|EV_PERSIST, multiple_read_cb, &ev2); |
michael@0 | 537 | if (event_add(&ev2, NULL) == -1) |
michael@0 | 538 | exit(1); |
michael@0 | 539 | event_dispatch(); |
michael@0 | 540 | |
michael@0 | 541 | if (roff == woff) |
michael@0 | 542 | test_ok = memcmp(rbuf, wbuf, sizeof(wbuf)) == 0; |
michael@0 | 543 | |
michael@0 | 544 | cleanup_test(); |
michael@0 | 545 | } |
michael@0 | 546 | |
michael@0 | 547 | static void |
michael@0 | 548 | test_combined(void) |
michael@0 | 549 | { |
michael@0 | 550 | struct both r1, r2, w1, w2; |
michael@0 | 551 | |
michael@0 | 552 | setup_test("Combined read/write: "); |
michael@0 | 553 | memset(&r1, 0, sizeof(r1)); |
michael@0 | 554 | memset(&r2, 0, sizeof(r2)); |
michael@0 | 555 | memset(&w1, 0, sizeof(w1)); |
michael@0 | 556 | memset(&w2, 0, sizeof(w2)); |
michael@0 | 557 | |
michael@0 | 558 | w1.nread = 4096; |
michael@0 | 559 | w2.nread = 8192; |
michael@0 | 560 | |
michael@0 | 561 | event_set(&r1.ev, pair[0], EV_READ, combined_read_cb, &r1); |
michael@0 | 562 | event_set(&w1.ev, pair[0], EV_WRITE, combined_write_cb, &w1); |
michael@0 | 563 | event_set(&r2.ev, pair[1], EV_READ, combined_read_cb, &r2); |
michael@0 | 564 | event_set(&w2.ev, pair[1], EV_WRITE, combined_write_cb, &w2); |
michael@0 | 565 | tt_assert(event_add(&r1.ev, NULL) != -1); |
michael@0 | 566 | tt_assert(!event_add(&w1.ev, NULL)); |
michael@0 | 567 | tt_assert(!event_add(&r2.ev, NULL)); |
michael@0 | 568 | tt_assert(!event_add(&w2.ev, NULL)); |
michael@0 | 569 | event_dispatch(); |
michael@0 | 570 | |
michael@0 | 571 | if (r1.nread == 8192 && r2.nread == 4096) |
michael@0 | 572 | test_ok = 1; |
michael@0 | 573 | |
michael@0 | 574 | end: |
michael@0 | 575 | cleanup_test(); |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | static void |
michael@0 | 579 | test_simpletimeout(void) |
michael@0 | 580 | { |
michael@0 | 581 | struct timeval tv; |
michael@0 | 582 | struct event ev; |
michael@0 | 583 | |
michael@0 | 584 | setup_test("Simple timeout: "); |
michael@0 | 585 | |
michael@0 | 586 | tv.tv_usec = 0; |
michael@0 | 587 | tv.tv_sec = SECONDS; |
michael@0 | 588 | evtimer_set(&ev, timeout_cb, NULL); |
michael@0 | 589 | evtimer_add(&ev, &tv); |
michael@0 | 590 | |
michael@0 | 591 | evutil_gettimeofday(&tset, NULL); |
michael@0 | 592 | event_dispatch(); |
michael@0 | 593 | |
michael@0 | 594 | cleanup_test(); |
michael@0 | 595 | } |
michael@0 | 596 | |
michael@0 | 597 | static void |
michael@0 | 598 | periodic_timeout_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 599 | { |
michael@0 | 600 | int *count = arg; |
michael@0 | 601 | |
michael@0 | 602 | (*count)++; |
michael@0 | 603 | if (*count == 6) { |
michael@0 | 604 | /* call loopexit only once - on slow machines(?), it is |
michael@0 | 605 | * apparently possible for this to get called twice. */ |
michael@0 | 606 | test_ok = 1; |
michael@0 | 607 | event_base_loopexit(global_base, NULL); |
michael@0 | 608 | } |
michael@0 | 609 | } |
michael@0 | 610 | |
michael@0 | 611 | static void |
michael@0 | 612 | test_persistent_timeout(void) |
michael@0 | 613 | { |
michael@0 | 614 | struct timeval tv; |
michael@0 | 615 | struct event ev; |
michael@0 | 616 | int count = 0; |
michael@0 | 617 | |
michael@0 | 618 | evutil_timerclear(&tv); |
michael@0 | 619 | tv.tv_usec = 10000; |
michael@0 | 620 | |
michael@0 | 621 | event_assign(&ev, global_base, -1, EV_TIMEOUT|EV_PERSIST, |
michael@0 | 622 | periodic_timeout_cb, &count); |
michael@0 | 623 | event_add(&ev, &tv); |
michael@0 | 624 | |
michael@0 | 625 | event_dispatch(); |
michael@0 | 626 | |
michael@0 | 627 | event_del(&ev); |
michael@0 | 628 | } |
michael@0 | 629 | |
michael@0 | 630 | static void |
michael@0 | 631 | test_persistent_timeout_jump(void *ptr) |
michael@0 | 632 | { |
michael@0 | 633 | struct basic_test_data *data = ptr; |
michael@0 | 634 | struct event ev; |
michael@0 | 635 | int count = 0; |
michael@0 | 636 | struct timeval msec100 = { 0, 100 * 1000 }; |
michael@0 | 637 | struct timeval msec50 = { 0, 50 * 1000 }; |
michael@0 | 638 | |
michael@0 | 639 | event_assign(&ev, data->base, -1, EV_PERSIST, periodic_timeout_cb, &count); |
michael@0 | 640 | event_add(&ev, &msec100); |
michael@0 | 641 | /* Wait for a bit */ |
michael@0 | 642 | #ifdef _WIN32 |
michael@0 | 643 | Sleep(1000); |
michael@0 | 644 | #else |
michael@0 | 645 | sleep(1); |
michael@0 | 646 | #endif |
michael@0 | 647 | event_base_loopexit(data->base, &msec50); |
michael@0 | 648 | event_base_dispatch(data->base); |
michael@0 | 649 | tt_int_op(count, ==, 1); |
michael@0 | 650 | |
michael@0 | 651 | end: |
michael@0 | 652 | event_del(&ev); |
michael@0 | 653 | } |
michael@0 | 654 | |
michael@0 | 655 | struct persist_active_timeout_called { |
michael@0 | 656 | int n; |
michael@0 | 657 | short events[16]; |
michael@0 | 658 | struct timeval tvs[16]; |
michael@0 | 659 | }; |
michael@0 | 660 | |
michael@0 | 661 | static void |
michael@0 | 662 | activate_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 663 | { |
michael@0 | 664 | struct event *ev = arg; |
michael@0 | 665 | event_active(ev, EV_READ, 1); |
michael@0 | 666 | } |
michael@0 | 667 | |
michael@0 | 668 | static void |
michael@0 | 669 | persist_active_timeout_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 670 | { |
michael@0 | 671 | struct persist_active_timeout_called *c = arg; |
michael@0 | 672 | if (c->n < 15) { |
michael@0 | 673 | c->events[c->n] = event; |
michael@0 | 674 | evutil_gettimeofday(&c->tvs[c->n], NULL); |
michael@0 | 675 | ++c->n; |
michael@0 | 676 | } |
michael@0 | 677 | } |
michael@0 | 678 | |
michael@0 | 679 | static void |
michael@0 | 680 | test_persistent_active_timeout(void *ptr) |
michael@0 | 681 | { |
michael@0 | 682 | struct timeval tv, tv2, tv_exit, start; |
michael@0 | 683 | struct event ev; |
michael@0 | 684 | struct persist_active_timeout_called res; |
michael@0 | 685 | |
michael@0 | 686 | struct basic_test_data *data = ptr; |
michael@0 | 687 | struct event_base *base = data->base; |
michael@0 | 688 | |
michael@0 | 689 | memset(&res, 0, sizeof(res)); |
michael@0 | 690 | |
michael@0 | 691 | tv.tv_sec = 0; |
michael@0 | 692 | tv.tv_usec = 200 * 1000; |
michael@0 | 693 | event_assign(&ev, base, -1, EV_TIMEOUT|EV_PERSIST, |
michael@0 | 694 | persist_active_timeout_cb, &res); |
michael@0 | 695 | event_add(&ev, &tv); |
michael@0 | 696 | |
michael@0 | 697 | tv2.tv_sec = 0; |
michael@0 | 698 | tv2.tv_usec = 100 * 1000; |
michael@0 | 699 | event_base_once(base, -1, EV_TIMEOUT, activate_cb, &ev, &tv2); |
michael@0 | 700 | |
michael@0 | 701 | tv_exit.tv_sec = 0; |
michael@0 | 702 | tv_exit.tv_usec = 600 * 1000; |
michael@0 | 703 | event_base_loopexit(base, &tv_exit); |
michael@0 | 704 | |
michael@0 | 705 | event_base_assert_ok(base); |
michael@0 | 706 | evutil_gettimeofday(&start, NULL); |
michael@0 | 707 | |
michael@0 | 708 | event_base_dispatch(base); |
michael@0 | 709 | event_base_assert_ok(base); |
michael@0 | 710 | |
michael@0 | 711 | tt_int_op(res.n, ==, 3); |
michael@0 | 712 | tt_int_op(res.events[0], ==, EV_READ); |
michael@0 | 713 | tt_int_op(res.events[1], ==, EV_TIMEOUT); |
michael@0 | 714 | tt_int_op(res.events[2], ==, EV_TIMEOUT); |
michael@0 | 715 | test_timeval_diff_eq(&start, &res.tvs[0], 100); |
michael@0 | 716 | test_timeval_diff_eq(&start, &res.tvs[1], 300); |
michael@0 | 717 | test_timeval_diff_eq(&start, &res.tvs[2], 500); |
michael@0 | 718 | end: |
michael@0 | 719 | event_del(&ev); |
michael@0 | 720 | } |
michael@0 | 721 | |
michael@0 | 722 | struct common_timeout_info { |
michael@0 | 723 | struct event ev; |
michael@0 | 724 | struct timeval called_at; |
michael@0 | 725 | int which; |
michael@0 | 726 | int count; |
michael@0 | 727 | }; |
michael@0 | 728 | |
michael@0 | 729 | static void |
michael@0 | 730 | common_timeout_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 731 | { |
michael@0 | 732 | struct common_timeout_info *ti = arg; |
michael@0 | 733 | ++ti->count; |
michael@0 | 734 | evutil_gettimeofday(&ti->called_at, NULL); |
michael@0 | 735 | if (ti->count >= 6) |
michael@0 | 736 | event_del(&ti->ev); |
michael@0 | 737 | } |
michael@0 | 738 | |
michael@0 | 739 | static void |
michael@0 | 740 | test_common_timeout(void *ptr) |
michael@0 | 741 | { |
michael@0 | 742 | struct basic_test_data *data = ptr; |
michael@0 | 743 | |
michael@0 | 744 | struct event_base *base = data->base; |
michael@0 | 745 | int i; |
michael@0 | 746 | struct common_timeout_info info[100]; |
michael@0 | 747 | |
michael@0 | 748 | struct timeval now; |
michael@0 | 749 | struct timeval tmp_100_ms = { 0, 100*1000 }; |
michael@0 | 750 | struct timeval tmp_200_ms = { 0, 200*1000 }; |
michael@0 | 751 | |
michael@0 | 752 | const struct timeval *ms_100, *ms_200; |
michael@0 | 753 | |
michael@0 | 754 | ms_100 = event_base_init_common_timeout(base, &tmp_100_ms); |
michael@0 | 755 | ms_200 = event_base_init_common_timeout(base, &tmp_200_ms); |
michael@0 | 756 | tt_assert(ms_100); |
michael@0 | 757 | tt_assert(ms_200); |
michael@0 | 758 | tt_ptr_op(event_base_init_common_timeout(base, &tmp_200_ms), |
michael@0 | 759 | ==, ms_200); |
michael@0 | 760 | tt_int_op(ms_100->tv_sec, ==, 0); |
michael@0 | 761 | tt_int_op(ms_200->tv_sec, ==, 0); |
michael@0 | 762 | tt_int_op(ms_100->tv_usec, ==, 100000|0x50000000); |
michael@0 | 763 | tt_int_op(ms_200->tv_usec, ==, 200000|0x50100000); |
michael@0 | 764 | |
michael@0 | 765 | memset(info, 0, sizeof(info)); |
michael@0 | 766 | |
michael@0 | 767 | for (i=0; i<100; ++i) { |
michael@0 | 768 | info[i].which = i; |
michael@0 | 769 | event_assign(&info[i].ev, base, -1, EV_TIMEOUT|EV_PERSIST, |
michael@0 | 770 | common_timeout_cb, &info[i]); |
michael@0 | 771 | if (i % 2) { |
michael@0 | 772 | event_add(&info[i].ev, ms_100); |
michael@0 | 773 | } else { |
michael@0 | 774 | event_add(&info[i].ev, ms_200); |
michael@0 | 775 | } |
michael@0 | 776 | } |
michael@0 | 777 | |
michael@0 | 778 | event_base_assert_ok(base); |
michael@0 | 779 | event_base_dispatch(base); |
michael@0 | 780 | |
michael@0 | 781 | evutil_gettimeofday(&now, NULL); |
michael@0 | 782 | event_base_assert_ok(base); |
michael@0 | 783 | |
michael@0 | 784 | for (i=0; i<10; ++i) { |
michael@0 | 785 | struct timeval tmp; |
michael@0 | 786 | int ms_diff; |
michael@0 | 787 | tt_int_op(info[i].count, ==, 6); |
michael@0 | 788 | evutil_timersub(&now, &info[i].called_at, &tmp); |
michael@0 | 789 | ms_diff = tmp.tv_usec/1000 + tmp.tv_sec*1000; |
michael@0 | 790 | if (i % 2) { |
michael@0 | 791 | tt_int_op(ms_diff, >, 500); |
michael@0 | 792 | tt_int_op(ms_diff, <, 700); |
michael@0 | 793 | } else { |
michael@0 | 794 | tt_int_op(ms_diff, >, -100); |
michael@0 | 795 | tt_int_op(ms_diff, <, 100); |
michael@0 | 796 | } |
michael@0 | 797 | } |
michael@0 | 798 | |
michael@0 | 799 | /* Make sure we can free the base with some events in. */ |
michael@0 | 800 | for (i=0; i<100; ++i) { |
michael@0 | 801 | if (i % 2) { |
michael@0 | 802 | event_add(&info[i].ev, ms_100); |
michael@0 | 803 | } else { |
michael@0 | 804 | event_add(&info[i].ev, ms_200); |
michael@0 | 805 | } |
michael@0 | 806 | } |
michael@0 | 807 | |
michael@0 | 808 | end: |
michael@0 | 809 | event_base_free(data->base); /* need to do this here before info is |
michael@0 | 810 | * out-of-scope */ |
michael@0 | 811 | data->base = NULL; |
michael@0 | 812 | } |
michael@0 | 813 | |
michael@0 | 814 | #ifndef WIN32 |
michael@0 | 815 | static void signal_cb(evutil_socket_t fd, short event, void *arg); |
michael@0 | 816 | |
michael@0 | 817 | #define current_base event_global_current_base_ |
michael@0 | 818 | extern struct event_base *current_base; |
michael@0 | 819 | |
michael@0 | 820 | static void |
michael@0 | 821 | child_signal_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 822 | { |
michael@0 | 823 | struct timeval tv; |
michael@0 | 824 | int *pint = arg; |
michael@0 | 825 | |
michael@0 | 826 | *pint = 1; |
michael@0 | 827 | |
michael@0 | 828 | tv.tv_usec = 500000; |
michael@0 | 829 | tv.tv_sec = 0; |
michael@0 | 830 | event_loopexit(&tv); |
michael@0 | 831 | } |
michael@0 | 832 | |
michael@0 | 833 | static void |
michael@0 | 834 | test_fork(void) |
michael@0 | 835 | { |
michael@0 | 836 | int status, got_sigchld = 0; |
michael@0 | 837 | struct event ev, sig_ev; |
michael@0 | 838 | pid_t pid; |
michael@0 | 839 | |
michael@0 | 840 | setup_test("After fork: "); |
michael@0 | 841 | |
michael@0 | 842 | tt_assert(current_base); |
michael@0 | 843 | evthread_make_base_notifiable(current_base); |
michael@0 | 844 | |
michael@0 | 845 | if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 846 | tt_fail_perror("write"); |
michael@0 | 847 | } |
michael@0 | 848 | |
michael@0 | 849 | event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev); |
michael@0 | 850 | if (event_add(&ev, NULL) == -1) |
michael@0 | 851 | exit(1); |
michael@0 | 852 | |
michael@0 | 853 | evsignal_set(&sig_ev, SIGCHLD, child_signal_cb, &got_sigchld); |
michael@0 | 854 | evsignal_add(&sig_ev, NULL); |
michael@0 | 855 | |
michael@0 | 856 | event_base_assert_ok(current_base); |
michael@0 | 857 | TT_BLATHER(("Before fork")); |
michael@0 | 858 | if ((pid = regress_fork()) == 0) { |
michael@0 | 859 | /* in the child */ |
michael@0 | 860 | TT_BLATHER(("In child, before reinit")); |
michael@0 | 861 | event_base_assert_ok(current_base); |
michael@0 | 862 | if (event_reinit(current_base) == -1) { |
michael@0 | 863 | fprintf(stdout, "FAILED (reinit)\n"); |
michael@0 | 864 | exit(1); |
michael@0 | 865 | } |
michael@0 | 866 | TT_BLATHER(("After reinit")); |
michael@0 | 867 | event_base_assert_ok(current_base); |
michael@0 | 868 | TT_BLATHER(("After assert-ok")); |
michael@0 | 869 | |
michael@0 | 870 | evsignal_del(&sig_ev); |
michael@0 | 871 | |
michael@0 | 872 | called = 0; |
michael@0 | 873 | |
michael@0 | 874 | event_dispatch(); |
michael@0 | 875 | |
michael@0 | 876 | event_base_free(current_base); |
michael@0 | 877 | |
michael@0 | 878 | /* we do not send an EOF; simple_read_cb requires an EOF |
michael@0 | 879 | * to set test_ok. we just verify that the callback was |
michael@0 | 880 | * called. */ |
michael@0 | 881 | exit(test_ok != 0 || called != 2 ? -2 : 76); |
michael@0 | 882 | } |
michael@0 | 883 | |
michael@0 | 884 | /* wait for the child to read the data */ |
michael@0 | 885 | sleep(1); |
michael@0 | 886 | |
michael@0 | 887 | if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 888 | tt_fail_perror("write"); |
michael@0 | 889 | } |
michael@0 | 890 | |
michael@0 | 891 | TT_BLATHER(("Before waitpid")); |
michael@0 | 892 | if (waitpid(pid, &status, 0) == -1) { |
michael@0 | 893 | fprintf(stdout, "FAILED (fork)\n"); |
michael@0 | 894 | exit(1); |
michael@0 | 895 | } |
michael@0 | 896 | TT_BLATHER(("After waitpid")); |
michael@0 | 897 | |
michael@0 | 898 | if (WEXITSTATUS(status) != 76) { |
michael@0 | 899 | fprintf(stdout, "FAILED (exit): %d\n", WEXITSTATUS(status)); |
michael@0 | 900 | exit(1); |
michael@0 | 901 | } |
michael@0 | 902 | |
michael@0 | 903 | /* test that the current event loop still works */ |
michael@0 | 904 | if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 905 | fprintf(stderr, "%s: write\n", __func__); |
michael@0 | 906 | } |
michael@0 | 907 | |
michael@0 | 908 | shutdown(pair[0], SHUT_WR); |
michael@0 | 909 | |
michael@0 | 910 | event_dispatch(); |
michael@0 | 911 | |
michael@0 | 912 | if (!got_sigchld) { |
michael@0 | 913 | fprintf(stdout, "FAILED (sigchld)\n"); |
michael@0 | 914 | exit(1); |
michael@0 | 915 | } |
michael@0 | 916 | |
michael@0 | 917 | evsignal_del(&sig_ev); |
michael@0 | 918 | |
michael@0 | 919 | end: |
michael@0 | 920 | cleanup_test(); |
michael@0 | 921 | } |
michael@0 | 922 | |
michael@0 | 923 | static void |
michael@0 | 924 | signal_cb_sa(int sig) |
michael@0 | 925 | { |
michael@0 | 926 | test_ok = 2; |
michael@0 | 927 | } |
michael@0 | 928 | |
michael@0 | 929 | static void |
michael@0 | 930 | signal_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 931 | { |
michael@0 | 932 | struct event *ev = arg; |
michael@0 | 933 | |
michael@0 | 934 | evsignal_del(ev); |
michael@0 | 935 | test_ok = 1; |
michael@0 | 936 | } |
michael@0 | 937 | |
michael@0 | 938 | static void |
michael@0 | 939 | test_simplesignal(void) |
michael@0 | 940 | { |
michael@0 | 941 | struct event ev; |
michael@0 | 942 | struct itimerval itv; |
michael@0 | 943 | |
michael@0 | 944 | setup_test("Simple signal: "); |
michael@0 | 945 | evsignal_set(&ev, SIGALRM, signal_cb, &ev); |
michael@0 | 946 | evsignal_add(&ev, NULL); |
michael@0 | 947 | /* find bugs in which operations are re-ordered */ |
michael@0 | 948 | evsignal_del(&ev); |
michael@0 | 949 | evsignal_add(&ev, NULL); |
michael@0 | 950 | |
michael@0 | 951 | memset(&itv, 0, sizeof(itv)); |
michael@0 | 952 | itv.it_value.tv_sec = 1; |
michael@0 | 953 | if (setitimer(ITIMER_REAL, &itv, NULL) == -1) |
michael@0 | 954 | goto skip_simplesignal; |
michael@0 | 955 | |
michael@0 | 956 | event_dispatch(); |
michael@0 | 957 | skip_simplesignal: |
michael@0 | 958 | if (evsignal_del(&ev) == -1) |
michael@0 | 959 | test_ok = 0; |
michael@0 | 960 | |
michael@0 | 961 | cleanup_test(); |
michael@0 | 962 | } |
michael@0 | 963 | |
michael@0 | 964 | static void |
michael@0 | 965 | test_multiplesignal(void) |
michael@0 | 966 | { |
michael@0 | 967 | struct event ev_one, ev_two; |
michael@0 | 968 | struct itimerval itv; |
michael@0 | 969 | |
michael@0 | 970 | setup_test("Multiple signal: "); |
michael@0 | 971 | |
michael@0 | 972 | evsignal_set(&ev_one, SIGALRM, signal_cb, &ev_one); |
michael@0 | 973 | evsignal_add(&ev_one, NULL); |
michael@0 | 974 | |
michael@0 | 975 | evsignal_set(&ev_two, SIGALRM, signal_cb, &ev_two); |
michael@0 | 976 | evsignal_add(&ev_two, NULL); |
michael@0 | 977 | |
michael@0 | 978 | memset(&itv, 0, sizeof(itv)); |
michael@0 | 979 | itv.it_value.tv_sec = 1; |
michael@0 | 980 | if (setitimer(ITIMER_REAL, &itv, NULL) == -1) |
michael@0 | 981 | goto skip_simplesignal; |
michael@0 | 982 | |
michael@0 | 983 | event_dispatch(); |
michael@0 | 984 | |
michael@0 | 985 | skip_simplesignal: |
michael@0 | 986 | if (evsignal_del(&ev_one) == -1) |
michael@0 | 987 | test_ok = 0; |
michael@0 | 988 | if (evsignal_del(&ev_two) == -1) |
michael@0 | 989 | test_ok = 0; |
michael@0 | 990 | |
michael@0 | 991 | cleanup_test(); |
michael@0 | 992 | } |
michael@0 | 993 | |
michael@0 | 994 | static void |
michael@0 | 995 | test_immediatesignal(void) |
michael@0 | 996 | { |
michael@0 | 997 | struct event ev; |
michael@0 | 998 | |
michael@0 | 999 | test_ok = 0; |
michael@0 | 1000 | evsignal_set(&ev, SIGUSR1, signal_cb, &ev); |
michael@0 | 1001 | evsignal_add(&ev, NULL); |
michael@0 | 1002 | raise(SIGUSR1); |
michael@0 | 1003 | event_loop(EVLOOP_NONBLOCK); |
michael@0 | 1004 | evsignal_del(&ev); |
michael@0 | 1005 | cleanup_test(); |
michael@0 | 1006 | } |
michael@0 | 1007 | |
michael@0 | 1008 | static void |
michael@0 | 1009 | test_signal_dealloc(void) |
michael@0 | 1010 | { |
michael@0 | 1011 | /* make sure that evsignal_event is event_del'ed and pipe closed */ |
michael@0 | 1012 | struct event ev; |
michael@0 | 1013 | struct event_base *base = event_init(); |
michael@0 | 1014 | evsignal_set(&ev, SIGUSR1, signal_cb, &ev); |
michael@0 | 1015 | evsignal_add(&ev, NULL); |
michael@0 | 1016 | evsignal_del(&ev); |
michael@0 | 1017 | event_base_free(base); |
michael@0 | 1018 | /* If we got here without asserting, we're fine. */ |
michael@0 | 1019 | test_ok = 1; |
michael@0 | 1020 | cleanup_test(); |
michael@0 | 1021 | } |
michael@0 | 1022 | |
michael@0 | 1023 | static void |
michael@0 | 1024 | test_signal_pipeloss(void) |
michael@0 | 1025 | { |
michael@0 | 1026 | /* make sure that the base1 pipe is closed correctly. */ |
michael@0 | 1027 | struct event_base *base1, *base2; |
michael@0 | 1028 | int pipe1; |
michael@0 | 1029 | test_ok = 0; |
michael@0 | 1030 | base1 = event_init(); |
michael@0 | 1031 | pipe1 = base1->sig.ev_signal_pair[0]; |
michael@0 | 1032 | base2 = event_init(); |
michael@0 | 1033 | event_base_free(base2); |
michael@0 | 1034 | event_base_free(base1); |
michael@0 | 1035 | if (close(pipe1) != -1 || errno!=EBADF) { |
michael@0 | 1036 | /* fd must be closed, so second close gives -1, EBADF */ |
michael@0 | 1037 | printf("signal pipe not closed. "); |
michael@0 | 1038 | test_ok = 0; |
michael@0 | 1039 | } else { |
michael@0 | 1040 | test_ok = 1; |
michael@0 | 1041 | } |
michael@0 | 1042 | cleanup_test(); |
michael@0 | 1043 | } |
michael@0 | 1044 | |
michael@0 | 1045 | /* |
michael@0 | 1046 | * make two bases to catch signals, use both of them. this only works |
michael@0 | 1047 | * for event mechanisms that use our signal pipe trick. kqueue handles |
michael@0 | 1048 | * signals internally, and all interested kqueues get all the signals. |
michael@0 | 1049 | */ |
michael@0 | 1050 | static void |
michael@0 | 1051 | test_signal_switchbase(void) |
michael@0 | 1052 | { |
michael@0 | 1053 | struct event ev1, ev2; |
michael@0 | 1054 | struct event_base *base1, *base2; |
michael@0 | 1055 | int is_kqueue; |
michael@0 | 1056 | test_ok = 0; |
michael@0 | 1057 | base1 = event_init(); |
michael@0 | 1058 | base2 = event_init(); |
michael@0 | 1059 | is_kqueue = !strcmp(event_get_method(),"kqueue"); |
michael@0 | 1060 | evsignal_set(&ev1, SIGUSR1, signal_cb, &ev1); |
michael@0 | 1061 | evsignal_set(&ev2, SIGUSR1, signal_cb, &ev2); |
michael@0 | 1062 | if (event_base_set(base1, &ev1) || |
michael@0 | 1063 | event_base_set(base2, &ev2) || |
michael@0 | 1064 | event_add(&ev1, NULL) || |
michael@0 | 1065 | event_add(&ev2, NULL)) { |
michael@0 | 1066 | fprintf(stderr, "%s: cannot set base, add\n", __func__); |
michael@0 | 1067 | exit(1); |
michael@0 | 1068 | } |
michael@0 | 1069 | |
michael@0 | 1070 | tt_ptr_op(event_get_base(&ev1), ==, base1); |
michael@0 | 1071 | tt_ptr_op(event_get_base(&ev2), ==, base2); |
michael@0 | 1072 | |
michael@0 | 1073 | test_ok = 0; |
michael@0 | 1074 | /* can handle signal before loop is called */ |
michael@0 | 1075 | raise(SIGUSR1); |
michael@0 | 1076 | event_base_loop(base2, EVLOOP_NONBLOCK); |
michael@0 | 1077 | if (is_kqueue) { |
michael@0 | 1078 | if (!test_ok) |
michael@0 | 1079 | goto end; |
michael@0 | 1080 | test_ok = 0; |
michael@0 | 1081 | } |
michael@0 | 1082 | event_base_loop(base1, EVLOOP_NONBLOCK); |
michael@0 | 1083 | if (test_ok && !is_kqueue) { |
michael@0 | 1084 | test_ok = 0; |
michael@0 | 1085 | |
michael@0 | 1086 | /* set base1 to handle signals */ |
michael@0 | 1087 | event_base_loop(base1, EVLOOP_NONBLOCK); |
michael@0 | 1088 | raise(SIGUSR1); |
michael@0 | 1089 | event_base_loop(base1, EVLOOP_NONBLOCK); |
michael@0 | 1090 | event_base_loop(base2, EVLOOP_NONBLOCK); |
michael@0 | 1091 | } |
michael@0 | 1092 | end: |
michael@0 | 1093 | event_base_free(base1); |
michael@0 | 1094 | event_base_free(base2); |
michael@0 | 1095 | cleanup_test(); |
michael@0 | 1096 | } |
michael@0 | 1097 | |
michael@0 | 1098 | /* |
michael@0 | 1099 | * assert that a signal event removed from the event queue really is |
michael@0 | 1100 | * removed - with no possibility of it's parent handler being fired. |
michael@0 | 1101 | */ |
michael@0 | 1102 | static void |
michael@0 | 1103 | test_signal_assert(void) |
michael@0 | 1104 | { |
michael@0 | 1105 | struct event ev; |
michael@0 | 1106 | struct event_base *base = event_init(); |
michael@0 | 1107 | test_ok = 0; |
michael@0 | 1108 | /* use SIGCONT so we don't kill ourselves when we signal to nowhere */ |
michael@0 | 1109 | evsignal_set(&ev, SIGCONT, signal_cb, &ev); |
michael@0 | 1110 | evsignal_add(&ev, NULL); |
michael@0 | 1111 | /* |
michael@0 | 1112 | * if evsignal_del() fails to reset the handler, it's current handler |
michael@0 | 1113 | * will still point to evsig_handler(). |
michael@0 | 1114 | */ |
michael@0 | 1115 | evsignal_del(&ev); |
michael@0 | 1116 | |
michael@0 | 1117 | raise(SIGCONT); |
michael@0 | 1118 | #if 0 |
michael@0 | 1119 | /* only way to verify we were in evsig_handler() */ |
michael@0 | 1120 | /* XXXX Now there's no longer a good way. */ |
michael@0 | 1121 | if (base->sig.evsig_caught) |
michael@0 | 1122 | test_ok = 0; |
michael@0 | 1123 | else |
michael@0 | 1124 | test_ok = 1; |
michael@0 | 1125 | #else |
michael@0 | 1126 | test_ok = 1; |
michael@0 | 1127 | #endif |
michael@0 | 1128 | |
michael@0 | 1129 | event_base_free(base); |
michael@0 | 1130 | cleanup_test(); |
michael@0 | 1131 | return; |
michael@0 | 1132 | } |
michael@0 | 1133 | |
michael@0 | 1134 | /* |
michael@0 | 1135 | * assert that we restore our previous signal handler properly. |
michael@0 | 1136 | */ |
michael@0 | 1137 | static void |
michael@0 | 1138 | test_signal_restore(void) |
michael@0 | 1139 | { |
michael@0 | 1140 | struct event ev; |
michael@0 | 1141 | struct event_base *base = event_init(); |
michael@0 | 1142 | #ifdef _EVENT_HAVE_SIGACTION |
michael@0 | 1143 | struct sigaction sa; |
michael@0 | 1144 | #endif |
michael@0 | 1145 | |
michael@0 | 1146 | test_ok = 0; |
michael@0 | 1147 | #ifdef _EVENT_HAVE_SIGACTION |
michael@0 | 1148 | sa.sa_handler = signal_cb_sa; |
michael@0 | 1149 | sa.sa_flags = 0x0; |
michael@0 | 1150 | sigemptyset(&sa.sa_mask); |
michael@0 | 1151 | if (sigaction(SIGUSR1, &sa, NULL) == -1) |
michael@0 | 1152 | goto out; |
michael@0 | 1153 | #else |
michael@0 | 1154 | if (signal(SIGUSR1, signal_cb_sa) == SIG_ERR) |
michael@0 | 1155 | goto out; |
michael@0 | 1156 | #endif |
michael@0 | 1157 | evsignal_set(&ev, SIGUSR1, signal_cb, &ev); |
michael@0 | 1158 | evsignal_add(&ev, NULL); |
michael@0 | 1159 | evsignal_del(&ev); |
michael@0 | 1160 | |
michael@0 | 1161 | raise(SIGUSR1); |
michael@0 | 1162 | /* 1 == signal_cb, 2 == signal_cb_sa, we want our previous handler */ |
michael@0 | 1163 | if (test_ok != 2) |
michael@0 | 1164 | test_ok = 0; |
michael@0 | 1165 | out: |
michael@0 | 1166 | event_base_free(base); |
michael@0 | 1167 | cleanup_test(); |
michael@0 | 1168 | return; |
michael@0 | 1169 | } |
michael@0 | 1170 | |
michael@0 | 1171 | static void |
michael@0 | 1172 | signal_cb_swp(int sig, short event, void *arg) |
michael@0 | 1173 | { |
michael@0 | 1174 | called++; |
michael@0 | 1175 | if (called < 5) |
michael@0 | 1176 | raise(sig); |
michael@0 | 1177 | else |
michael@0 | 1178 | event_loopexit(NULL); |
michael@0 | 1179 | } |
michael@0 | 1180 | static void |
michael@0 | 1181 | timeout_cb_swp(evutil_socket_t fd, short event, void *arg) |
michael@0 | 1182 | { |
michael@0 | 1183 | if (called == -1) { |
michael@0 | 1184 | struct timeval tv = {5, 0}; |
michael@0 | 1185 | |
michael@0 | 1186 | called = 0; |
michael@0 | 1187 | evtimer_add((struct event *)arg, &tv); |
michael@0 | 1188 | raise(SIGUSR1); |
michael@0 | 1189 | return; |
michael@0 | 1190 | } |
michael@0 | 1191 | test_ok = 0; |
michael@0 | 1192 | event_loopexit(NULL); |
michael@0 | 1193 | } |
michael@0 | 1194 | |
michael@0 | 1195 | static void |
michael@0 | 1196 | test_signal_while_processing(void) |
michael@0 | 1197 | { |
michael@0 | 1198 | struct event_base *base = event_init(); |
michael@0 | 1199 | struct event ev, ev_timer; |
michael@0 | 1200 | struct timeval tv = {0, 0}; |
michael@0 | 1201 | |
michael@0 | 1202 | setup_test("Receiving a signal while processing other signal: "); |
michael@0 | 1203 | |
michael@0 | 1204 | called = -1; |
michael@0 | 1205 | test_ok = 1; |
michael@0 | 1206 | signal_set(&ev, SIGUSR1, signal_cb_swp, NULL); |
michael@0 | 1207 | signal_add(&ev, NULL); |
michael@0 | 1208 | evtimer_set(&ev_timer, timeout_cb_swp, &ev_timer); |
michael@0 | 1209 | evtimer_add(&ev_timer, &tv); |
michael@0 | 1210 | event_dispatch(); |
michael@0 | 1211 | |
michael@0 | 1212 | event_base_free(base); |
michael@0 | 1213 | cleanup_test(); |
michael@0 | 1214 | return; |
michael@0 | 1215 | } |
michael@0 | 1216 | #endif |
michael@0 | 1217 | |
michael@0 | 1218 | static void |
michael@0 | 1219 | test_free_active_base(void *ptr) |
michael@0 | 1220 | { |
michael@0 | 1221 | struct basic_test_data *data = ptr; |
michael@0 | 1222 | struct event_base *base1; |
michael@0 | 1223 | struct event ev1; |
michael@0 | 1224 | |
michael@0 | 1225 | base1 = event_init(); |
michael@0 | 1226 | if (base1) { |
michael@0 | 1227 | event_assign(&ev1, base1, data->pair[1], EV_READ, |
michael@0 | 1228 | dummy_read_cb, NULL); |
michael@0 | 1229 | event_add(&ev1, NULL); |
michael@0 | 1230 | event_base_free(base1); /* should not crash */ |
michael@0 | 1231 | } else { |
michael@0 | 1232 | tt_fail_msg("failed to create event_base for test"); |
michael@0 | 1233 | } |
michael@0 | 1234 | |
michael@0 | 1235 | base1 = event_init(); |
michael@0 | 1236 | tt_assert(base1); |
michael@0 | 1237 | event_assign(&ev1, base1, 0, 0, dummy_read_cb, NULL); |
michael@0 | 1238 | event_active(&ev1, EV_READ, 1); |
michael@0 | 1239 | event_base_free(base1); |
michael@0 | 1240 | end: |
michael@0 | 1241 | ; |
michael@0 | 1242 | } |
michael@0 | 1243 | |
michael@0 | 1244 | static void |
michael@0 | 1245 | test_manipulate_active_events(void *ptr) |
michael@0 | 1246 | { |
michael@0 | 1247 | struct basic_test_data *data = ptr; |
michael@0 | 1248 | struct event_base *base = data->base; |
michael@0 | 1249 | struct event ev1; |
michael@0 | 1250 | |
michael@0 | 1251 | event_assign(&ev1, base, -1, EV_TIMEOUT, dummy_read_cb, NULL); |
michael@0 | 1252 | |
michael@0 | 1253 | /* Make sure an active event is pending. */ |
michael@0 | 1254 | event_active(&ev1, EV_READ, 1); |
michael@0 | 1255 | tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL), |
michael@0 | 1256 | ==, EV_READ); |
michael@0 | 1257 | |
michael@0 | 1258 | /* Make sure that activating an event twice works. */ |
michael@0 | 1259 | event_active(&ev1, EV_WRITE, 1); |
michael@0 | 1260 | tt_int_op(event_pending(&ev1, EV_READ|EV_TIMEOUT|EV_WRITE, NULL), |
michael@0 | 1261 | ==, EV_READ|EV_WRITE); |
michael@0 | 1262 | |
michael@0 | 1263 | end: |
michael@0 | 1264 | event_del(&ev1); |
michael@0 | 1265 | } |
michael@0 | 1266 | |
michael@0 | 1267 | static void |
michael@0 | 1268 | test_bad_assign(void *ptr) |
michael@0 | 1269 | { |
michael@0 | 1270 | struct event ev; |
michael@0 | 1271 | int r; |
michael@0 | 1272 | /* READ|SIGNAL is not allowed */ |
michael@0 | 1273 | r = event_assign(&ev, NULL, -1, EV_SIGNAL|EV_READ, dummy_read_cb, NULL); |
michael@0 | 1274 | tt_int_op(r,==,-1); |
michael@0 | 1275 | |
michael@0 | 1276 | end: |
michael@0 | 1277 | ; |
michael@0 | 1278 | } |
michael@0 | 1279 | |
michael@0 | 1280 | static int reentrant_cb_run = 0; |
michael@0 | 1281 | |
michael@0 | 1282 | static void |
michael@0 | 1283 | bad_reentrant_run_loop_cb(evutil_socket_t fd, short what, void *ptr) |
michael@0 | 1284 | { |
michael@0 | 1285 | struct event_base *base = ptr; |
michael@0 | 1286 | int r; |
michael@0 | 1287 | reentrant_cb_run = 1; |
michael@0 | 1288 | /* This reentrant call to event_base_loop should be detected and |
michael@0 | 1289 | * should fail */ |
michael@0 | 1290 | r = event_base_loop(base, 0); |
michael@0 | 1291 | tt_int_op(r, ==, -1); |
michael@0 | 1292 | end: |
michael@0 | 1293 | ; |
michael@0 | 1294 | } |
michael@0 | 1295 | |
michael@0 | 1296 | static void |
michael@0 | 1297 | test_bad_reentrant(void *ptr) |
michael@0 | 1298 | { |
michael@0 | 1299 | struct basic_test_data *data = ptr; |
michael@0 | 1300 | struct event_base *base = data->base; |
michael@0 | 1301 | struct event ev; |
michael@0 | 1302 | int r; |
michael@0 | 1303 | event_assign(&ev, base, -1, |
michael@0 | 1304 | 0, bad_reentrant_run_loop_cb, base); |
michael@0 | 1305 | |
michael@0 | 1306 | event_active(&ev, EV_WRITE, 1); |
michael@0 | 1307 | r = event_base_loop(base, 0); |
michael@0 | 1308 | tt_int_op(r, ==, 1); |
michael@0 | 1309 | tt_int_op(reentrant_cb_run, ==, 1); |
michael@0 | 1310 | end: |
michael@0 | 1311 | ; |
michael@0 | 1312 | } |
michael@0 | 1313 | |
michael@0 | 1314 | static void |
michael@0 | 1315 | test_event_base_new(void *ptr) |
michael@0 | 1316 | { |
michael@0 | 1317 | struct basic_test_data *data = ptr; |
michael@0 | 1318 | struct event_base *base = 0; |
michael@0 | 1319 | struct event ev1; |
michael@0 | 1320 | struct basic_cb_args args; |
michael@0 | 1321 | |
michael@0 | 1322 | int towrite = (int)strlen(TEST1)+1; |
michael@0 | 1323 | int len = write(data->pair[0], TEST1, towrite); |
michael@0 | 1324 | |
michael@0 | 1325 | if (len < 0) |
michael@0 | 1326 | tt_abort_perror("initial write"); |
michael@0 | 1327 | else if (len != towrite) |
michael@0 | 1328 | tt_abort_printf(("initial write fell short (%d of %d bytes)", |
michael@0 | 1329 | len, towrite)); |
michael@0 | 1330 | |
michael@0 | 1331 | if (shutdown(data->pair[0], SHUT_WR)) |
michael@0 | 1332 | tt_abort_perror("initial write shutdown"); |
michael@0 | 1333 | |
michael@0 | 1334 | base = event_base_new(); |
michael@0 | 1335 | if (!base) |
michael@0 | 1336 | tt_abort_msg("failed to create event base"); |
michael@0 | 1337 | |
michael@0 | 1338 | args.eb = base; |
michael@0 | 1339 | args.ev = &ev1; |
michael@0 | 1340 | args.callcount = 0; |
michael@0 | 1341 | event_assign(&ev1, base, data->pair[1], |
michael@0 | 1342 | EV_READ|EV_PERSIST, basic_read_cb, &args); |
michael@0 | 1343 | |
michael@0 | 1344 | if (event_add(&ev1, NULL)) |
michael@0 | 1345 | tt_abort_perror("initial event_add"); |
michael@0 | 1346 | |
michael@0 | 1347 | if (event_base_loop(base, 0)) |
michael@0 | 1348 | tt_abort_msg("unsuccessful exit from event loop"); |
michael@0 | 1349 | |
michael@0 | 1350 | end: |
michael@0 | 1351 | if (base) |
michael@0 | 1352 | event_base_free(base); |
michael@0 | 1353 | } |
michael@0 | 1354 | |
michael@0 | 1355 | static void |
michael@0 | 1356 | test_loopexit(void) |
michael@0 | 1357 | { |
michael@0 | 1358 | struct timeval tv, tv_start, tv_end; |
michael@0 | 1359 | struct event ev; |
michael@0 | 1360 | |
michael@0 | 1361 | setup_test("Loop exit: "); |
michael@0 | 1362 | |
michael@0 | 1363 | tv.tv_usec = 0; |
michael@0 | 1364 | tv.tv_sec = 60*60*24; |
michael@0 | 1365 | evtimer_set(&ev, timeout_cb, NULL); |
michael@0 | 1366 | evtimer_add(&ev, &tv); |
michael@0 | 1367 | |
michael@0 | 1368 | tv.tv_usec = 0; |
michael@0 | 1369 | tv.tv_sec = 1; |
michael@0 | 1370 | event_loopexit(&tv); |
michael@0 | 1371 | |
michael@0 | 1372 | evutil_gettimeofday(&tv_start, NULL); |
michael@0 | 1373 | event_dispatch(); |
michael@0 | 1374 | evutil_gettimeofday(&tv_end, NULL); |
michael@0 | 1375 | evutil_timersub(&tv_end, &tv_start, &tv_end); |
michael@0 | 1376 | |
michael@0 | 1377 | evtimer_del(&ev); |
michael@0 | 1378 | |
michael@0 | 1379 | tt_assert(event_base_got_exit(global_base)); |
michael@0 | 1380 | tt_assert(!event_base_got_break(global_base)); |
michael@0 | 1381 | |
michael@0 | 1382 | if (tv.tv_sec < 2) |
michael@0 | 1383 | test_ok = 1; |
michael@0 | 1384 | |
michael@0 | 1385 | end: |
michael@0 | 1386 | cleanup_test(); |
michael@0 | 1387 | } |
michael@0 | 1388 | |
michael@0 | 1389 | static void |
michael@0 | 1390 | test_loopexit_multiple(void) |
michael@0 | 1391 | { |
michael@0 | 1392 | struct timeval tv; |
michael@0 | 1393 | struct event_base *base; |
michael@0 | 1394 | |
michael@0 | 1395 | setup_test("Loop Multiple exit: "); |
michael@0 | 1396 | |
michael@0 | 1397 | base = event_base_new(); |
michael@0 | 1398 | |
michael@0 | 1399 | tv.tv_usec = 0; |
michael@0 | 1400 | tv.tv_sec = 1; |
michael@0 | 1401 | event_base_loopexit(base, &tv); |
michael@0 | 1402 | |
michael@0 | 1403 | tv.tv_usec = 0; |
michael@0 | 1404 | tv.tv_sec = 2; |
michael@0 | 1405 | event_base_loopexit(base, &tv); |
michael@0 | 1406 | |
michael@0 | 1407 | event_base_dispatch(base); |
michael@0 | 1408 | |
michael@0 | 1409 | tt_assert(event_base_got_exit(base)); |
michael@0 | 1410 | tt_assert(!event_base_got_break(base)); |
michael@0 | 1411 | |
michael@0 | 1412 | event_base_free(base); |
michael@0 | 1413 | |
michael@0 | 1414 | test_ok = 1; |
michael@0 | 1415 | |
michael@0 | 1416 | end: |
michael@0 | 1417 | cleanup_test(); |
michael@0 | 1418 | } |
michael@0 | 1419 | |
michael@0 | 1420 | static void |
michael@0 | 1421 | break_cb(evutil_socket_t fd, short events, void *arg) |
michael@0 | 1422 | { |
michael@0 | 1423 | test_ok = 1; |
michael@0 | 1424 | event_loopbreak(); |
michael@0 | 1425 | } |
michael@0 | 1426 | |
michael@0 | 1427 | static void |
michael@0 | 1428 | fail_cb(evutil_socket_t fd, short events, void *arg) |
michael@0 | 1429 | { |
michael@0 | 1430 | test_ok = 0; |
michael@0 | 1431 | } |
michael@0 | 1432 | |
michael@0 | 1433 | static void |
michael@0 | 1434 | test_loopbreak(void) |
michael@0 | 1435 | { |
michael@0 | 1436 | struct event ev1, ev2; |
michael@0 | 1437 | struct timeval tv; |
michael@0 | 1438 | |
michael@0 | 1439 | setup_test("Loop break: "); |
michael@0 | 1440 | |
michael@0 | 1441 | tv.tv_sec = 0; |
michael@0 | 1442 | tv.tv_usec = 0; |
michael@0 | 1443 | evtimer_set(&ev1, break_cb, NULL); |
michael@0 | 1444 | evtimer_add(&ev1, &tv); |
michael@0 | 1445 | evtimer_set(&ev2, fail_cb, NULL); |
michael@0 | 1446 | evtimer_add(&ev2, &tv); |
michael@0 | 1447 | |
michael@0 | 1448 | event_dispatch(); |
michael@0 | 1449 | |
michael@0 | 1450 | tt_assert(!event_base_got_exit(global_base)); |
michael@0 | 1451 | tt_assert(event_base_got_break(global_base)); |
michael@0 | 1452 | |
michael@0 | 1453 | evtimer_del(&ev1); |
michael@0 | 1454 | evtimer_del(&ev2); |
michael@0 | 1455 | |
michael@0 | 1456 | end: |
michael@0 | 1457 | cleanup_test(); |
michael@0 | 1458 | } |
michael@0 | 1459 | |
michael@0 | 1460 | static struct event *readd_test_event_last_added = NULL; |
michael@0 | 1461 | static void |
michael@0 | 1462 | re_add_read_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 1463 | { |
michael@0 | 1464 | char buf[256]; |
michael@0 | 1465 | struct event *ev_other = arg; |
michael@0 | 1466 | readd_test_event_last_added = ev_other; |
michael@0 | 1467 | |
michael@0 | 1468 | if (read(fd, buf, sizeof(buf)) < 0) { |
michael@0 | 1469 | tt_fail_perror("read"); |
michael@0 | 1470 | } |
michael@0 | 1471 | |
michael@0 | 1472 | event_add(ev_other, NULL); |
michael@0 | 1473 | ++test_ok; |
michael@0 | 1474 | } |
michael@0 | 1475 | |
michael@0 | 1476 | static void |
michael@0 | 1477 | test_nonpersist_readd(void) |
michael@0 | 1478 | { |
michael@0 | 1479 | struct event ev1, ev2; |
michael@0 | 1480 | |
michael@0 | 1481 | setup_test("Re-add nonpersistent events: "); |
michael@0 | 1482 | event_set(&ev1, pair[0], EV_READ, re_add_read_cb, &ev2); |
michael@0 | 1483 | event_set(&ev2, pair[1], EV_READ, re_add_read_cb, &ev1); |
michael@0 | 1484 | |
michael@0 | 1485 | if (write(pair[0], "Hello", 5) < 0) { |
michael@0 | 1486 | tt_fail_perror("write(pair[0])"); |
michael@0 | 1487 | } |
michael@0 | 1488 | |
michael@0 | 1489 | if (write(pair[1], "Hello", 5) < 0) { |
michael@0 | 1490 | tt_fail_perror("write(pair[1])\n"); |
michael@0 | 1491 | } |
michael@0 | 1492 | |
michael@0 | 1493 | if (event_add(&ev1, NULL) == -1 || |
michael@0 | 1494 | event_add(&ev2, NULL) == -1) { |
michael@0 | 1495 | test_ok = 0; |
michael@0 | 1496 | } |
michael@0 | 1497 | if (test_ok != 0) |
michael@0 | 1498 | exit(1); |
michael@0 | 1499 | event_loop(EVLOOP_ONCE); |
michael@0 | 1500 | if (test_ok != 2) |
michael@0 | 1501 | exit(1); |
michael@0 | 1502 | /* At this point, we executed both callbacks. Whichever one got |
michael@0 | 1503 | * called first added the second, but the second then immediately got |
michael@0 | 1504 | * deleted before its callback was called. At this point, though, it |
michael@0 | 1505 | * re-added the first. |
michael@0 | 1506 | */ |
michael@0 | 1507 | if (!readd_test_event_last_added) { |
michael@0 | 1508 | test_ok = 0; |
michael@0 | 1509 | } else if (readd_test_event_last_added == &ev1) { |
michael@0 | 1510 | if (!event_pending(&ev1, EV_READ, NULL) || |
michael@0 | 1511 | event_pending(&ev2, EV_READ, NULL)) |
michael@0 | 1512 | test_ok = 0; |
michael@0 | 1513 | } else { |
michael@0 | 1514 | if (event_pending(&ev1, EV_READ, NULL) || |
michael@0 | 1515 | !event_pending(&ev2, EV_READ, NULL)) |
michael@0 | 1516 | test_ok = 0; |
michael@0 | 1517 | } |
michael@0 | 1518 | |
michael@0 | 1519 | event_del(&ev1); |
michael@0 | 1520 | event_del(&ev2); |
michael@0 | 1521 | |
michael@0 | 1522 | cleanup_test(); |
michael@0 | 1523 | } |
michael@0 | 1524 | |
michael@0 | 1525 | struct test_pri_event { |
michael@0 | 1526 | struct event ev; |
michael@0 | 1527 | int count; |
michael@0 | 1528 | }; |
michael@0 | 1529 | |
michael@0 | 1530 | static void |
michael@0 | 1531 | test_priorities_cb(evutil_socket_t fd, short what, void *arg) |
michael@0 | 1532 | { |
michael@0 | 1533 | struct test_pri_event *pri = arg; |
michael@0 | 1534 | struct timeval tv; |
michael@0 | 1535 | |
michael@0 | 1536 | if (pri->count == 3) { |
michael@0 | 1537 | event_loopexit(NULL); |
michael@0 | 1538 | return; |
michael@0 | 1539 | } |
michael@0 | 1540 | |
michael@0 | 1541 | pri->count++; |
michael@0 | 1542 | |
michael@0 | 1543 | evutil_timerclear(&tv); |
michael@0 | 1544 | event_add(&pri->ev, &tv); |
michael@0 | 1545 | } |
michael@0 | 1546 | |
michael@0 | 1547 | static void |
michael@0 | 1548 | test_priorities_impl(int npriorities) |
michael@0 | 1549 | { |
michael@0 | 1550 | struct test_pri_event one, two; |
michael@0 | 1551 | struct timeval tv; |
michael@0 | 1552 | |
michael@0 | 1553 | TT_BLATHER(("Testing Priorities %d: ", npriorities)); |
michael@0 | 1554 | |
michael@0 | 1555 | event_base_priority_init(global_base, npriorities); |
michael@0 | 1556 | |
michael@0 | 1557 | memset(&one, 0, sizeof(one)); |
michael@0 | 1558 | memset(&two, 0, sizeof(two)); |
michael@0 | 1559 | |
michael@0 | 1560 | timeout_set(&one.ev, test_priorities_cb, &one); |
michael@0 | 1561 | if (event_priority_set(&one.ev, 0) == -1) { |
michael@0 | 1562 | fprintf(stderr, "%s: failed to set priority", __func__); |
michael@0 | 1563 | exit(1); |
michael@0 | 1564 | } |
michael@0 | 1565 | |
michael@0 | 1566 | timeout_set(&two.ev, test_priorities_cb, &two); |
michael@0 | 1567 | if (event_priority_set(&two.ev, npriorities - 1) == -1) { |
michael@0 | 1568 | fprintf(stderr, "%s: failed to set priority", __func__); |
michael@0 | 1569 | exit(1); |
michael@0 | 1570 | } |
michael@0 | 1571 | |
michael@0 | 1572 | evutil_timerclear(&tv); |
michael@0 | 1573 | |
michael@0 | 1574 | if (event_add(&one.ev, &tv) == -1) |
michael@0 | 1575 | exit(1); |
michael@0 | 1576 | if (event_add(&two.ev, &tv) == -1) |
michael@0 | 1577 | exit(1); |
michael@0 | 1578 | |
michael@0 | 1579 | event_dispatch(); |
michael@0 | 1580 | |
michael@0 | 1581 | event_del(&one.ev); |
michael@0 | 1582 | event_del(&two.ev); |
michael@0 | 1583 | |
michael@0 | 1584 | if (npriorities == 1) { |
michael@0 | 1585 | if (one.count == 3 && two.count == 3) |
michael@0 | 1586 | test_ok = 1; |
michael@0 | 1587 | } else if (npriorities == 2) { |
michael@0 | 1588 | /* Two is called once because event_loopexit is priority 1 */ |
michael@0 | 1589 | if (one.count == 3 && two.count == 1) |
michael@0 | 1590 | test_ok = 1; |
michael@0 | 1591 | } else { |
michael@0 | 1592 | if (one.count == 3 && two.count == 0) |
michael@0 | 1593 | test_ok = 1; |
michael@0 | 1594 | } |
michael@0 | 1595 | } |
michael@0 | 1596 | |
michael@0 | 1597 | static void |
michael@0 | 1598 | test_priorities(void) |
michael@0 | 1599 | { |
michael@0 | 1600 | test_priorities_impl(1); |
michael@0 | 1601 | if (test_ok) |
michael@0 | 1602 | test_priorities_impl(2); |
michael@0 | 1603 | if (test_ok) |
michael@0 | 1604 | test_priorities_impl(3); |
michael@0 | 1605 | } |
michael@0 | 1606 | |
michael@0 | 1607 | /* priority-active-inversion: activate a higher-priority event, and make sure |
michael@0 | 1608 | * it keeps us from running a lower-priority event first. */ |
michael@0 | 1609 | static int n_pai_calls = 0; |
michael@0 | 1610 | static struct event pai_events[3]; |
michael@0 | 1611 | |
michael@0 | 1612 | static void |
michael@0 | 1613 | prio_active_inversion_cb(evutil_socket_t fd, short what, void *arg) |
michael@0 | 1614 | { |
michael@0 | 1615 | int *call_order = arg; |
michael@0 | 1616 | *call_order = n_pai_calls++; |
michael@0 | 1617 | if (n_pai_calls == 1) { |
michael@0 | 1618 | /* This should activate later, even though it shares a |
michael@0 | 1619 | priority with us. */ |
michael@0 | 1620 | event_active(&pai_events[1], EV_READ, 1); |
michael@0 | 1621 | /* This should activate next, since its priority is higher, |
michael@0 | 1622 | even though we activated it second. */ |
michael@0 | 1623 | event_active(&pai_events[2], EV_TIMEOUT, 1); |
michael@0 | 1624 | } |
michael@0 | 1625 | } |
michael@0 | 1626 | |
michael@0 | 1627 | static void |
michael@0 | 1628 | test_priority_active_inversion(void *data_) |
michael@0 | 1629 | { |
michael@0 | 1630 | struct basic_test_data *data = data_; |
michael@0 | 1631 | struct event_base *base = data->base; |
michael@0 | 1632 | int call_order[3]; |
michael@0 | 1633 | int i; |
michael@0 | 1634 | tt_int_op(event_base_priority_init(base, 8), ==, 0); |
michael@0 | 1635 | |
michael@0 | 1636 | n_pai_calls = 0; |
michael@0 | 1637 | memset(call_order, 0, sizeof(call_order)); |
michael@0 | 1638 | |
michael@0 | 1639 | for (i=0;i<3;++i) { |
michael@0 | 1640 | event_assign(&pai_events[i], data->base, -1, 0, |
michael@0 | 1641 | prio_active_inversion_cb, &call_order[i]); |
michael@0 | 1642 | } |
michael@0 | 1643 | |
michael@0 | 1644 | event_priority_set(&pai_events[0], 4); |
michael@0 | 1645 | event_priority_set(&pai_events[1], 4); |
michael@0 | 1646 | event_priority_set(&pai_events[2], 0); |
michael@0 | 1647 | |
michael@0 | 1648 | event_active(&pai_events[0], EV_WRITE, 1); |
michael@0 | 1649 | |
michael@0 | 1650 | event_base_dispatch(base); |
michael@0 | 1651 | tt_int_op(n_pai_calls, ==, 3); |
michael@0 | 1652 | tt_int_op(call_order[0], ==, 0); |
michael@0 | 1653 | tt_int_op(call_order[1], ==, 2); |
michael@0 | 1654 | tt_int_op(call_order[2], ==, 1); |
michael@0 | 1655 | end: |
michael@0 | 1656 | ; |
michael@0 | 1657 | } |
michael@0 | 1658 | |
michael@0 | 1659 | |
michael@0 | 1660 | static void |
michael@0 | 1661 | test_multiple_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 1662 | { |
michael@0 | 1663 | if (event & EV_READ) |
michael@0 | 1664 | test_ok |= 1; |
michael@0 | 1665 | else if (event & EV_WRITE) |
michael@0 | 1666 | test_ok |= 2; |
michael@0 | 1667 | } |
michael@0 | 1668 | |
michael@0 | 1669 | static void |
michael@0 | 1670 | test_multiple_events_for_same_fd(void) |
michael@0 | 1671 | { |
michael@0 | 1672 | struct event e1, e2; |
michael@0 | 1673 | |
michael@0 | 1674 | setup_test("Multiple events for same fd: "); |
michael@0 | 1675 | |
michael@0 | 1676 | event_set(&e1, pair[0], EV_READ, test_multiple_cb, NULL); |
michael@0 | 1677 | event_add(&e1, NULL); |
michael@0 | 1678 | event_set(&e2, pair[0], EV_WRITE, test_multiple_cb, NULL); |
michael@0 | 1679 | event_add(&e2, NULL); |
michael@0 | 1680 | event_loop(EVLOOP_ONCE); |
michael@0 | 1681 | event_del(&e2); |
michael@0 | 1682 | |
michael@0 | 1683 | if (write(pair[1], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 1684 | tt_fail_perror("write"); |
michael@0 | 1685 | } |
michael@0 | 1686 | |
michael@0 | 1687 | event_loop(EVLOOP_ONCE); |
michael@0 | 1688 | event_del(&e1); |
michael@0 | 1689 | |
michael@0 | 1690 | if (test_ok != 3) |
michael@0 | 1691 | test_ok = 0; |
michael@0 | 1692 | |
michael@0 | 1693 | cleanup_test(); |
michael@0 | 1694 | } |
michael@0 | 1695 | |
michael@0 | 1696 | int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf); |
michael@0 | 1697 | int evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf); |
michael@0 | 1698 | int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t number); |
michael@0 | 1699 | int evtag_decode_tag(ev_uint32_t *pnumber, struct evbuffer *evbuf); |
michael@0 | 1700 | |
michael@0 | 1701 | static void |
michael@0 | 1702 | read_once_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 1703 | { |
michael@0 | 1704 | char buf[256]; |
michael@0 | 1705 | int len; |
michael@0 | 1706 | |
michael@0 | 1707 | len = read(fd, buf, sizeof(buf)); |
michael@0 | 1708 | |
michael@0 | 1709 | if (called) { |
michael@0 | 1710 | test_ok = 0; |
michael@0 | 1711 | } else if (len) { |
michael@0 | 1712 | /* Assumes global pair[0] can be used for writing */ |
michael@0 | 1713 | if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 1714 | tt_fail_perror("write"); |
michael@0 | 1715 | test_ok = 0; |
michael@0 | 1716 | } else { |
michael@0 | 1717 | test_ok = 1; |
michael@0 | 1718 | } |
michael@0 | 1719 | } |
michael@0 | 1720 | |
michael@0 | 1721 | called++; |
michael@0 | 1722 | } |
michael@0 | 1723 | |
michael@0 | 1724 | static void |
michael@0 | 1725 | test_want_only_once(void) |
michael@0 | 1726 | { |
michael@0 | 1727 | struct event ev; |
michael@0 | 1728 | struct timeval tv; |
michael@0 | 1729 | |
michael@0 | 1730 | /* Very simple read test */ |
michael@0 | 1731 | setup_test("Want read only once: "); |
michael@0 | 1732 | |
michael@0 | 1733 | if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 1734 | tt_fail_perror("write"); |
michael@0 | 1735 | } |
michael@0 | 1736 | |
michael@0 | 1737 | /* Setup the loop termination */ |
michael@0 | 1738 | evutil_timerclear(&tv); |
michael@0 | 1739 | tv.tv_sec = 1; |
michael@0 | 1740 | event_loopexit(&tv); |
michael@0 | 1741 | |
michael@0 | 1742 | event_set(&ev, pair[1], EV_READ, read_once_cb, &ev); |
michael@0 | 1743 | if (event_add(&ev, NULL) == -1) |
michael@0 | 1744 | exit(1); |
michael@0 | 1745 | event_dispatch(); |
michael@0 | 1746 | |
michael@0 | 1747 | cleanup_test(); |
michael@0 | 1748 | } |
michael@0 | 1749 | |
michael@0 | 1750 | #define TEST_MAX_INT 6 |
michael@0 | 1751 | |
michael@0 | 1752 | static void |
michael@0 | 1753 | evtag_int_test(void *ptr) |
michael@0 | 1754 | { |
michael@0 | 1755 | struct evbuffer *tmp = evbuffer_new(); |
michael@0 | 1756 | ev_uint32_t integers[TEST_MAX_INT] = { |
michael@0 | 1757 | 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 |
michael@0 | 1758 | }; |
michael@0 | 1759 | ev_uint32_t integer; |
michael@0 | 1760 | ev_uint64_t big_int; |
michael@0 | 1761 | int i; |
michael@0 | 1762 | |
michael@0 | 1763 | evtag_init(); |
michael@0 | 1764 | |
michael@0 | 1765 | for (i = 0; i < TEST_MAX_INT; i++) { |
michael@0 | 1766 | int oldlen, newlen; |
michael@0 | 1767 | oldlen = (int)EVBUFFER_LENGTH(tmp); |
michael@0 | 1768 | evtag_encode_int(tmp, integers[i]); |
michael@0 | 1769 | newlen = (int)EVBUFFER_LENGTH(tmp); |
michael@0 | 1770 | TT_BLATHER(("encoded 0x%08x with %d bytes", |
michael@0 | 1771 | (unsigned)integers[i], newlen - oldlen)); |
michael@0 | 1772 | big_int = integers[i]; |
michael@0 | 1773 | big_int *= 1000000000; /* 1 billion */ |
michael@0 | 1774 | evtag_encode_int64(tmp, big_int); |
michael@0 | 1775 | } |
michael@0 | 1776 | |
michael@0 | 1777 | for (i = 0; i < TEST_MAX_INT; i++) { |
michael@0 | 1778 | tt_int_op(evtag_decode_int(&integer, tmp), !=, -1); |
michael@0 | 1779 | tt_uint_op(integer, ==, integers[i]); |
michael@0 | 1780 | tt_int_op(evtag_decode_int64(&big_int, tmp), !=, -1); |
michael@0 | 1781 | tt_assert((big_int / 1000000000) == integers[i]); |
michael@0 | 1782 | } |
michael@0 | 1783 | |
michael@0 | 1784 | tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0); |
michael@0 | 1785 | end: |
michael@0 | 1786 | evbuffer_free(tmp); |
michael@0 | 1787 | } |
michael@0 | 1788 | |
michael@0 | 1789 | static void |
michael@0 | 1790 | evtag_fuzz(void *ptr) |
michael@0 | 1791 | { |
michael@0 | 1792 | u_char buffer[4096]; |
michael@0 | 1793 | struct evbuffer *tmp = evbuffer_new(); |
michael@0 | 1794 | struct timeval tv; |
michael@0 | 1795 | int i, j; |
michael@0 | 1796 | |
michael@0 | 1797 | int not_failed = 0; |
michael@0 | 1798 | |
michael@0 | 1799 | evtag_init(); |
michael@0 | 1800 | |
michael@0 | 1801 | for (j = 0; j < 100; j++) { |
michael@0 | 1802 | for (i = 0; i < (int)sizeof(buffer); i++) |
michael@0 | 1803 | buffer[i] = rand(); |
michael@0 | 1804 | evbuffer_drain(tmp, -1); |
michael@0 | 1805 | evbuffer_add(tmp, buffer, sizeof(buffer)); |
michael@0 | 1806 | |
michael@0 | 1807 | if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) |
michael@0 | 1808 | not_failed++; |
michael@0 | 1809 | } |
michael@0 | 1810 | |
michael@0 | 1811 | /* The majority of decodes should fail */ |
michael@0 | 1812 | tt_int_op(not_failed, <, 10); |
michael@0 | 1813 | |
michael@0 | 1814 | /* Now insert some corruption into the tag length field */ |
michael@0 | 1815 | evbuffer_drain(tmp, -1); |
michael@0 | 1816 | evutil_timerclear(&tv); |
michael@0 | 1817 | tv.tv_sec = 1; |
michael@0 | 1818 | evtag_marshal_timeval(tmp, 0, &tv); |
michael@0 | 1819 | evbuffer_add(tmp, buffer, sizeof(buffer)); |
michael@0 | 1820 | |
michael@0 | 1821 | ((char *)EVBUFFER_DATA(tmp))[1] = '\xff'; |
michael@0 | 1822 | if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) { |
michael@0 | 1823 | tt_abort_msg("evtag_unmarshal_timeval should have failed"); |
michael@0 | 1824 | } |
michael@0 | 1825 | |
michael@0 | 1826 | end: |
michael@0 | 1827 | evbuffer_free(tmp); |
michael@0 | 1828 | } |
michael@0 | 1829 | |
michael@0 | 1830 | static void |
michael@0 | 1831 | evtag_tag_encoding(void *ptr) |
michael@0 | 1832 | { |
michael@0 | 1833 | struct evbuffer *tmp = evbuffer_new(); |
michael@0 | 1834 | ev_uint32_t integers[TEST_MAX_INT] = { |
michael@0 | 1835 | 0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000 |
michael@0 | 1836 | }; |
michael@0 | 1837 | ev_uint32_t integer; |
michael@0 | 1838 | int i; |
michael@0 | 1839 | |
michael@0 | 1840 | evtag_init(); |
michael@0 | 1841 | |
michael@0 | 1842 | for (i = 0; i < TEST_MAX_INT; i++) { |
michael@0 | 1843 | int oldlen, newlen; |
michael@0 | 1844 | oldlen = (int)EVBUFFER_LENGTH(tmp); |
michael@0 | 1845 | evtag_encode_tag(tmp, integers[i]); |
michael@0 | 1846 | newlen = (int)EVBUFFER_LENGTH(tmp); |
michael@0 | 1847 | TT_BLATHER(("encoded 0x%08x with %d bytes", |
michael@0 | 1848 | (unsigned)integers[i], newlen - oldlen)); |
michael@0 | 1849 | } |
michael@0 | 1850 | |
michael@0 | 1851 | for (i = 0; i < TEST_MAX_INT; i++) { |
michael@0 | 1852 | tt_int_op(evtag_decode_tag(&integer, tmp), !=, -1); |
michael@0 | 1853 | tt_uint_op(integer, ==, integers[i]); |
michael@0 | 1854 | } |
michael@0 | 1855 | |
michael@0 | 1856 | tt_uint_op(EVBUFFER_LENGTH(tmp), ==, 0); |
michael@0 | 1857 | |
michael@0 | 1858 | end: |
michael@0 | 1859 | evbuffer_free(tmp); |
michael@0 | 1860 | } |
michael@0 | 1861 | |
michael@0 | 1862 | static void |
michael@0 | 1863 | evtag_test_peek(void *ptr) |
michael@0 | 1864 | { |
michael@0 | 1865 | struct evbuffer *tmp = evbuffer_new(); |
michael@0 | 1866 | ev_uint32_t u32; |
michael@0 | 1867 | |
michael@0 | 1868 | evtag_marshal_int(tmp, 30, 0); |
michael@0 | 1869 | evtag_marshal_string(tmp, 40, "Hello world"); |
michael@0 | 1870 | |
michael@0 | 1871 | tt_int_op(evtag_peek(tmp, &u32), ==, 1); |
michael@0 | 1872 | tt_int_op(u32, ==, 30); |
michael@0 | 1873 | tt_int_op(evtag_peek_length(tmp, &u32), ==, 0); |
michael@0 | 1874 | tt_int_op(u32, ==, 1+1+1); |
michael@0 | 1875 | tt_int_op(evtag_consume(tmp), ==, 0); |
michael@0 | 1876 | |
michael@0 | 1877 | tt_int_op(evtag_peek(tmp, &u32), ==, 1); |
michael@0 | 1878 | tt_int_op(u32, ==, 40); |
michael@0 | 1879 | tt_int_op(evtag_peek_length(tmp, &u32), ==, 0); |
michael@0 | 1880 | tt_int_op(u32, ==, 1+1+11); |
michael@0 | 1881 | tt_int_op(evtag_payload_length(tmp, &u32), ==, 0); |
michael@0 | 1882 | tt_int_op(u32, ==, 11); |
michael@0 | 1883 | |
michael@0 | 1884 | end: |
michael@0 | 1885 | evbuffer_free(tmp); |
michael@0 | 1886 | } |
michael@0 | 1887 | |
michael@0 | 1888 | |
michael@0 | 1889 | static void |
michael@0 | 1890 | test_methods(void *ptr) |
michael@0 | 1891 | { |
michael@0 | 1892 | const char **methods = event_get_supported_methods(); |
michael@0 | 1893 | struct event_config *cfg = NULL; |
michael@0 | 1894 | struct event_base *base = NULL; |
michael@0 | 1895 | const char *backend; |
michael@0 | 1896 | int n_methods = 0; |
michael@0 | 1897 | |
michael@0 | 1898 | tt_assert(methods); |
michael@0 | 1899 | |
michael@0 | 1900 | backend = methods[0]; |
michael@0 | 1901 | while (*methods != NULL) { |
michael@0 | 1902 | TT_BLATHER(("Support method: %s", *methods)); |
michael@0 | 1903 | ++methods; |
michael@0 | 1904 | ++n_methods; |
michael@0 | 1905 | } |
michael@0 | 1906 | |
michael@0 | 1907 | cfg = event_config_new(); |
michael@0 | 1908 | assert(cfg != NULL); |
michael@0 | 1909 | |
michael@0 | 1910 | tt_int_op(event_config_avoid_method(cfg, backend), ==, 0); |
michael@0 | 1911 | event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV); |
michael@0 | 1912 | |
michael@0 | 1913 | base = event_base_new_with_config(cfg); |
michael@0 | 1914 | if (n_methods > 1) { |
michael@0 | 1915 | tt_assert(base); |
michael@0 | 1916 | tt_str_op(backend, !=, event_base_get_method(base)); |
michael@0 | 1917 | } else { |
michael@0 | 1918 | tt_assert(base == NULL); |
michael@0 | 1919 | } |
michael@0 | 1920 | |
michael@0 | 1921 | end: |
michael@0 | 1922 | if (base) |
michael@0 | 1923 | event_base_free(base); |
michael@0 | 1924 | if (cfg) |
michael@0 | 1925 | event_config_free(cfg); |
michael@0 | 1926 | } |
michael@0 | 1927 | |
michael@0 | 1928 | static void |
michael@0 | 1929 | test_version(void *arg) |
michael@0 | 1930 | { |
michael@0 | 1931 | const char *vstr; |
michael@0 | 1932 | ev_uint32_t vint; |
michael@0 | 1933 | int major, minor, patch, n; |
michael@0 | 1934 | |
michael@0 | 1935 | vstr = event_get_version(); |
michael@0 | 1936 | vint = event_get_version_number(); |
michael@0 | 1937 | |
michael@0 | 1938 | tt_assert(vstr); |
michael@0 | 1939 | tt_assert(vint); |
michael@0 | 1940 | |
michael@0 | 1941 | tt_str_op(vstr, ==, LIBEVENT_VERSION); |
michael@0 | 1942 | tt_int_op(vint, ==, LIBEVENT_VERSION_NUMBER); |
michael@0 | 1943 | |
michael@0 | 1944 | n = sscanf(vstr, "%d.%d.%d", &major, &minor, &patch); |
michael@0 | 1945 | tt_assert(3 == n); |
michael@0 | 1946 | tt_int_op((vint&0xffffff00), ==, ((major<<24)|(minor<<16)|(patch<<8))); |
michael@0 | 1947 | end: |
michael@0 | 1948 | ; |
michael@0 | 1949 | } |
michael@0 | 1950 | |
michael@0 | 1951 | static void |
michael@0 | 1952 | test_base_features(void *arg) |
michael@0 | 1953 | { |
michael@0 | 1954 | struct event_base *base = NULL; |
michael@0 | 1955 | struct event_config *cfg = NULL; |
michael@0 | 1956 | |
michael@0 | 1957 | cfg = event_config_new(); |
michael@0 | 1958 | |
michael@0 | 1959 | tt_assert(0 == event_config_require_features(cfg, EV_FEATURE_ET)); |
michael@0 | 1960 | |
michael@0 | 1961 | base = event_base_new_with_config(cfg); |
michael@0 | 1962 | if (base) { |
michael@0 | 1963 | tt_int_op(EV_FEATURE_ET, ==, |
michael@0 | 1964 | event_base_get_features(base) & EV_FEATURE_ET); |
michael@0 | 1965 | } else { |
michael@0 | 1966 | base = event_base_new(); |
michael@0 | 1967 | tt_int_op(0, ==, event_base_get_features(base) & EV_FEATURE_ET); |
michael@0 | 1968 | } |
michael@0 | 1969 | |
michael@0 | 1970 | end: |
michael@0 | 1971 | if (base) |
michael@0 | 1972 | event_base_free(base); |
michael@0 | 1973 | if (cfg) |
michael@0 | 1974 | event_config_free(cfg); |
michael@0 | 1975 | } |
michael@0 | 1976 | |
michael@0 | 1977 | #ifdef _EVENT_HAVE_SETENV |
michael@0 | 1978 | #define SETENV_OK |
michael@0 | 1979 | #elif !defined(_EVENT_HAVE_SETENV) && defined(_EVENT_HAVE_PUTENV) |
michael@0 | 1980 | static void setenv(const char *k, const char *v, int _o) |
michael@0 | 1981 | { |
michael@0 | 1982 | char b[256]; |
michael@0 | 1983 | evutil_snprintf(b, sizeof(b), "%s=%s",k,v); |
michael@0 | 1984 | putenv(b); |
michael@0 | 1985 | } |
michael@0 | 1986 | #define SETENV_OK |
michael@0 | 1987 | #endif |
michael@0 | 1988 | |
michael@0 | 1989 | #ifdef _EVENT_HAVE_UNSETENV |
michael@0 | 1990 | #define UNSETENV_OK |
michael@0 | 1991 | #elif !defined(_EVENT_HAVE_UNSETENV) && defined(_EVENT_HAVE_PUTENV) |
michael@0 | 1992 | static void unsetenv(const char *k) |
michael@0 | 1993 | { |
michael@0 | 1994 | char b[256]; |
michael@0 | 1995 | evutil_snprintf(b, sizeof(b), "%s=",k); |
michael@0 | 1996 | putenv(b); |
michael@0 | 1997 | } |
michael@0 | 1998 | #define UNSETENV_OK |
michael@0 | 1999 | #endif |
michael@0 | 2000 | |
michael@0 | 2001 | #if defined(SETENV_OK) && defined(UNSETENV_OK) |
michael@0 | 2002 | static void |
michael@0 | 2003 | methodname_to_envvar(const char *mname, char *buf, size_t buflen) |
michael@0 | 2004 | { |
michael@0 | 2005 | char *cp; |
michael@0 | 2006 | evutil_snprintf(buf, buflen, "EVENT_NO%s", mname); |
michael@0 | 2007 | for (cp = buf; *cp; ++cp) { |
michael@0 | 2008 | *cp = EVUTIL_TOUPPER(*cp); |
michael@0 | 2009 | } |
michael@0 | 2010 | } |
michael@0 | 2011 | #endif |
michael@0 | 2012 | |
michael@0 | 2013 | static void |
michael@0 | 2014 | test_base_environ(void *arg) |
michael@0 | 2015 | { |
michael@0 | 2016 | struct event_base *base = NULL; |
michael@0 | 2017 | struct event_config *cfg = NULL; |
michael@0 | 2018 | |
michael@0 | 2019 | #if defined(SETENV_OK) && defined(UNSETENV_OK) |
michael@0 | 2020 | const char **basenames; |
michael@0 | 2021 | int i, n_methods=0; |
michael@0 | 2022 | char varbuf[128]; |
michael@0 | 2023 | const char *defaultname, *ignoreenvname; |
michael@0 | 2024 | |
michael@0 | 2025 | /* See if unsetenv works before we rely on it. */ |
michael@0 | 2026 | setenv("EVENT_NOWAFFLES", "1", 1); |
michael@0 | 2027 | unsetenv("EVENT_NOWAFFLES"); |
michael@0 | 2028 | if (getenv("EVENT_NOWAFFLES") != NULL) { |
michael@0 | 2029 | #ifndef _EVENT_HAVE_UNSETENV |
michael@0 | 2030 | TT_DECLARE("NOTE", ("Can't fake unsetenv; skipping test")); |
michael@0 | 2031 | #else |
michael@0 | 2032 | TT_DECLARE("NOTE", ("unsetenv doesn't work; skipping test")); |
michael@0 | 2033 | #endif |
michael@0 | 2034 | tt_skip(); |
michael@0 | 2035 | } |
michael@0 | 2036 | |
michael@0 | 2037 | basenames = event_get_supported_methods(); |
michael@0 | 2038 | for (i = 0; basenames[i]; ++i) { |
michael@0 | 2039 | methodname_to_envvar(basenames[i], varbuf, sizeof(varbuf)); |
michael@0 | 2040 | unsetenv(varbuf); |
michael@0 | 2041 | ++n_methods; |
michael@0 | 2042 | } |
michael@0 | 2043 | |
michael@0 | 2044 | base = event_base_new(); |
michael@0 | 2045 | tt_assert(base); |
michael@0 | 2046 | |
michael@0 | 2047 | defaultname = event_base_get_method(base); |
michael@0 | 2048 | TT_BLATHER(("default is <%s>", defaultname)); |
michael@0 | 2049 | event_base_free(base); |
michael@0 | 2050 | base = NULL; |
michael@0 | 2051 | |
michael@0 | 2052 | /* Can we disable the method with EVENT_NOfoo ? */ |
michael@0 | 2053 | if (!strcmp(defaultname, "epoll (with changelist)")) { |
michael@0 | 2054 | setenv("EVENT_NOEPOLL", "1", 1); |
michael@0 | 2055 | ignoreenvname = "epoll"; |
michael@0 | 2056 | } else { |
michael@0 | 2057 | methodname_to_envvar(defaultname, varbuf, sizeof(varbuf)); |
michael@0 | 2058 | setenv(varbuf, "1", 1); |
michael@0 | 2059 | ignoreenvname = defaultname; |
michael@0 | 2060 | } |
michael@0 | 2061 | |
michael@0 | 2062 | /* Use an empty cfg rather than NULL so a failure doesn't exit() */ |
michael@0 | 2063 | cfg = event_config_new(); |
michael@0 | 2064 | base = event_base_new_with_config(cfg); |
michael@0 | 2065 | event_config_free(cfg); |
michael@0 | 2066 | cfg = NULL; |
michael@0 | 2067 | if (n_methods == 1) { |
michael@0 | 2068 | tt_assert(!base); |
michael@0 | 2069 | } else { |
michael@0 | 2070 | tt_assert(base); |
michael@0 | 2071 | tt_str_op(defaultname, !=, event_base_get_method(base)); |
michael@0 | 2072 | event_base_free(base); |
michael@0 | 2073 | base = NULL; |
michael@0 | 2074 | } |
michael@0 | 2075 | |
michael@0 | 2076 | /* Can we disable looking at the environment with IGNORE_ENV ? */ |
michael@0 | 2077 | cfg = event_config_new(); |
michael@0 | 2078 | event_config_set_flag(cfg, EVENT_BASE_FLAG_IGNORE_ENV); |
michael@0 | 2079 | base = event_base_new_with_config(cfg); |
michael@0 | 2080 | tt_assert(base); |
michael@0 | 2081 | tt_str_op(ignoreenvname, ==, event_base_get_method(base)); |
michael@0 | 2082 | #else |
michael@0 | 2083 | tt_skip(); |
michael@0 | 2084 | #endif |
michael@0 | 2085 | |
michael@0 | 2086 | end: |
michael@0 | 2087 | if (base) |
michael@0 | 2088 | event_base_free(base); |
michael@0 | 2089 | if (cfg) |
michael@0 | 2090 | event_config_free(cfg); |
michael@0 | 2091 | } |
michael@0 | 2092 | |
michael@0 | 2093 | static void |
michael@0 | 2094 | read_called_once_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 2095 | { |
michael@0 | 2096 | tt_int_op(event, ==, EV_READ); |
michael@0 | 2097 | called += 1; |
michael@0 | 2098 | end: |
michael@0 | 2099 | ; |
michael@0 | 2100 | } |
michael@0 | 2101 | |
michael@0 | 2102 | static void |
michael@0 | 2103 | timeout_called_once_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 2104 | { |
michael@0 | 2105 | tt_int_op(event, ==, EV_TIMEOUT); |
michael@0 | 2106 | called += 100; |
michael@0 | 2107 | end: |
michael@0 | 2108 | ; |
michael@0 | 2109 | } |
michael@0 | 2110 | |
michael@0 | 2111 | static void |
michael@0 | 2112 | test_event_once(void *ptr) |
michael@0 | 2113 | { |
michael@0 | 2114 | struct basic_test_data *data = ptr; |
michael@0 | 2115 | struct timeval tv; |
michael@0 | 2116 | int r; |
michael@0 | 2117 | |
michael@0 | 2118 | tv.tv_sec = 0; |
michael@0 | 2119 | tv.tv_usec = 50*1000; |
michael@0 | 2120 | called = 0; |
michael@0 | 2121 | r = event_base_once(data->base, data->pair[0], EV_READ, |
michael@0 | 2122 | read_called_once_cb, NULL, NULL); |
michael@0 | 2123 | tt_int_op(r, ==, 0); |
michael@0 | 2124 | r = event_base_once(data->base, -1, EV_TIMEOUT, |
michael@0 | 2125 | timeout_called_once_cb, NULL, &tv); |
michael@0 | 2126 | tt_int_op(r, ==, 0); |
michael@0 | 2127 | r = event_base_once(data->base, -1, 0, NULL, NULL, NULL); |
michael@0 | 2128 | tt_int_op(r, <, 0); |
michael@0 | 2129 | |
michael@0 | 2130 | if (write(data->pair[1], TEST1, strlen(TEST1)+1) < 0) { |
michael@0 | 2131 | tt_fail_perror("write"); |
michael@0 | 2132 | } |
michael@0 | 2133 | |
michael@0 | 2134 | shutdown(data->pair[1], SHUT_WR); |
michael@0 | 2135 | |
michael@0 | 2136 | event_base_dispatch(data->base); |
michael@0 | 2137 | |
michael@0 | 2138 | tt_int_op(called, ==, 101); |
michael@0 | 2139 | end: |
michael@0 | 2140 | ; |
michael@0 | 2141 | } |
michael@0 | 2142 | |
michael@0 | 2143 | static void |
michael@0 | 2144 | test_event_pending(void *ptr) |
michael@0 | 2145 | { |
michael@0 | 2146 | struct basic_test_data *data = ptr; |
michael@0 | 2147 | struct event *r=NULL, *w=NULL, *t=NULL; |
michael@0 | 2148 | struct timeval tv, now, tv2, diff; |
michael@0 | 2149 | |
michael@0 | 2150 | tv.tv_sec = 0; |
michael@0 | 2151 | tv.tv_usec = 500 * 1000; |
michael@0 | 2152 | r = event_new(data->base, data->pair[0], EV_READ, simple_read_cb, |
michael@0 | 2153 | NULL); |
michael@0 | 2154 | w = event_new(data->base, data->pair[1], EV_WRITE, simple_write_cb, |
michael@0 | 2155 | NULL); |
michael@0 | 2156 | t = evtimer_new(data->base, timeout_cb, NULL); |
michael@0 | 2157 | |
michael@0 | 2158 | tt_assert(r); |
michael@0 | 2159 | tt_assert(w); |
michael@0 | 2160 | tt_assert(t); |
michael@0 | 2161 | |
michael@0 | 2162 | evutil_gettimeofday(&now, NULL); |
michael@0 | 2163 | event_add(r, NULL); |
michael@0 | 2164 | event_add(t, &tv); |
michael@0 | 2165 | |
michael@0 | 2166 | tt_assert( event_pending(r, EV_READ, NULL)); |
michael@0 | 2167 | tt_assert(!event_pending(w, EV_WRITE, NULL)); |
michael@0 | 2168 | tt_assert(!event_pending(r, EV_WRITE, NULL)); |
michael@0 | 2169 | tt_assert( event_pending(r, EV_READ|EV_WRITE, NULL)); |
michael@0 | 2170 | tt_assert(!event_pending(r, EV_TIMEOUT, NULL)); |
michael@0 | 2171 | tt_assert( event_pending(t, EV_TIMEOUT, NULL)); |
michael@0 | 2172 | tt_assert( event_pending(t, EV_TIMEOUT, &tv2)); |
michael@0 | 2173 | |
michael@0 | 2174 | tt_assert(evutil_timercmp(&tv2, &now, >)); |
michael@0 | 2175 | evutil_timeradd(&now, &tv, &tv); |
michael@0 | 2176 | evutil_timersub(&tv2, &tv, &diff); |
michael@0 | 2177 | tt_int_op(diff.tv_sec, ==, 0); |
michael@0 | 2178 | tt_int_op(labs(diff.tv_usec), <, 1000); |
michael@0 | 2179 | |
michael@0 | 2180 | end: |
michael@0 | 2181 | if (r) { |
michael@0 | 2182 | event_del(r); |
michael@0 | 2183 | event_free(r); |
michael@0 | 2184 | } |
michael@0 | 2185 | if (w) { |
michael@0 | 2186 | event_del(w); |
michael@0 | 2187 | event_free(w); |
michael@0 | 2188 | } |
michael@0 | 2189 | if (t) { |
michael@0 | 2190 | event_del(t); |
michael@0 | 2191 | event_free(t); |
michael@0 | 2192 | } |
michael@0 | 2193 | } |
michael@0 | 2194 | |
michael@0 | 2195 | #ifndef WIN32 |
michael@0 | 2196 | /* You can't do this test on windows, since dup2 doesn't work on sockets */ |
michael@0 | 2197 | |
michael@0 | 2198 | static void |
michael@0 | 2199 | dfd_cb(evutil_socket_t fd, short e, void *data) |
michael@0 | 2200 | { |
michael@0 | 2201 | *(int*)data = (int)e; |
michael@0 | 2202 | } |
michael@0 | 2203 | |
michael@0 | 2204 | /* Regression test for our workaround for a fun epoll/linux related bug |
michael@0 | 2205 | * where fd2 = dup(fd1); add(fd2); close(fd2); dup2(fd1,fd2); add(fd2) |
michael@0 | 2206 | * will get you an EEXIST */ |
michael@0 | 2207 | static void |
michael@0 | 2208 | test_dup_fd(void *arg) |
michael@0 | 2209 | { |
michael@0 | 2210 | struct basic_test_data *data = arg; |
michael@0 | 2211 | struct event_base *base = data->base; |
michael@0 | 2212 | struct event *ev1=NULL, *ev2=NULL; |
michael@0 | 2213 | int fd, dfd=-1; |
michael@0 | 2214 | int ev1_got, ev2_got; |
michael@0 | 2215 | |
michael@0 | 2216 | tt_int_op(write(data->pair[0], "Hello world", |
michael@0 | 2217 | strlen("Hello world")), >, 0); |
michael@0 | 2218 | fd = data->pair[1]; |
michael@0 | 2219 | |
michael@0 | 2220 | dfd = dup(fd); |
michael@0 | 2221 | tt_int_op(dfd, >=, 0); |
michael@0 | 2222 | |
michael@0 | 2223 | ev1 = event_new(base, fd, EV_READ|EV_PERSIST, dfd_cb, &ev1_got); |
michael@0 | 2224 | ev2 = event_new(base, dfd, EV_READ|EV_PERSIST, dfd_cb, &ev2_got); |
michael@0 | 2225 | ev1_got = ev2_got = 0; |
michael@0 | 2226 | event_add(ev1, NULL); |
michael@0 | 2227 | event_add(ev2, NULL); |
michael@0 | 2228 | event_base_loop(base, EVLOOP_ONCE); |
michael@0 | 2229 | tt_int_op(ev1_got, ==, EV_READ); |
michael@0 | 2230 | tt_int_op(ev2_got, ==, EV_READ); |
michael@0 | 2231 | |
michael@0 | 2232 | /* Now close and delete dfd then dispatch. We need to do the |
michael@0 | 2233 | * dispatch here so that when we add it later, we think there |
michael@0 | 2234 | * was an intermediate delete. */ |
michael@0 | 2235 | close(dfd); |
michael@0 | 2236 | event_del(ev2); |
michael@0 | 2237 | ev1_got = ev2_got = 0; |
michael@0 | 2238 | event_base_loop(base, EVLOOP_ONCE); |
michael@0 | 2239 | tt_want_int_op(ev1_got, ==, EV_READ); |
michael@0 | 2240 | tt_int_op(ev2_got, ==, 0); |
michael@0 | 2241 | |
michael@0 | 2242 | /* Re-duplicate the fd. We need to get the same duplicated |
michael@0 | 2243 | * value that we closed to provoke the epoll quirk. Also, we |
michael@0 | 2244 | * need to change the events to write, or else the old lingering |
michael@0 | 2245 | * read event will make the test pass whether the change was |
michael@0 | 2246 | * successful or not. */ |
michael@0 | 2247 | tt_int_op(dup2(fd, dfd), ==, dfd); |
michael@0 | 2248 | event_free(ev2); |
michael@0 | 2249 | ev2 = event_new(base, dfd, EV_WRITE|EV_PERSIST, dfd_cb, &ev2_got); |
michael@0 | 2250 | event_add(ev2, NULL); |
michael@0 | 2251 | ev1_got = ev2_got = 0; |
michael@0 | 2252 | event_base_loop(base, EVLOOP_ONCE); |
michael@0 | 2253 | tt_want_int_op(ev1_got, ==, EV_READ); |
michael@0 | 2254 | tt_int_op(ev2_got, ==, EV_WRITE); |
michael@0 | 2255 | |
michael@0 | 2256 | end: |
michael@0 | 2257 | if (ev1) |
michael@0 | 2258 | event_free(ev1); |
michael@0 | 2259 | if (ev2) |
michael@0 | 2260 | event_free(ev2); |
michael@0 | 2261 | if (dfd >= 0) |
michael@0 | 2262 | close(dfd); |
michael@0 | 2263 | } |
michael@0 | 2264 | #endif |
michael@0 | 2265 | |
michael@0 | 2266 | #ifdef _EVENT_DISABLE_MM_REPLACEMENT |
michael@0 | 2267 | static void |
michael@0 | 2268 | test_mm_functions(void *arg) |
michael@0 | 2269 | { |
michael@0 | 2270 | _tinytest_set_test_skipped(); |
michael@0 | 2271 | } |
michael@0 | 2272 | #else |
michael@0 | 2273 | static int |
michael@0 | 2274 | check_dummy_mem_ok(void *_mem) |
michael@0 | 2275 | { |
michael@0 | 2276 | char *mem = _mem; |
michael@0 | 2277 | mem -= 16; |
michael@0 | 2278 | return !memcmp(mem, "{[<guardedram>]}", 16); |
michael@0 | 2279 | } |
michael@0 | 2280 | |
michael@0 | 2281 | static void * |
michael@0 | 2282 | dummy_malloc(size_t len) |
michael@0 | 2283 | { |
michael@0 | 2284 | char *mem = malloc(len+16); |
michael@0 | 2285 | memcpy(mem, "{[<guardedram>]}", 16); |
michael@0 | 2286 | return mem+16; |
michael@0 | 2287 | } |
michael@0 | 2288 | |
michael@0 | 2289 | static void * |
michael@0 | 2290 | dummy_realloc(void *_mem, size_t len) |
michael@0 | 2291 | { |
michael@0 | 2292 | char *mem = _mem; |
michael@0 | 2293 | if (!mem) |
michael@0 | 2294 | return dummy_malloc(len); |
michael@0 | 2295 | tt_want(check_dummy_mem_ok(_mem)); |
michael@0 | 2296 | mem -= 16; |
michael@0 | 2297 | mem = realloc(mem, len+16); |
michael@0 | 2298 | return mem+16; |
michael@0 | 2299 | } |
michael@0 | 2300 | |
michael@0 | 2301 | static void |
michael@0 | 2302 | dummy_free(void *_mem) |
michael@0 | 2303 | { |
michael@0 | 2304 | char *mem = _mem; |
michael@0 | 2305 | tt_want(check_dummy_mem_ok(_mem)); |
michael@0 | 2306 | mem -= 16; |
michael@0 | 2307 | free(mem); |
michael@0 | 2308 | } |
michael@0 | 2309 | |
michael@0 | 2310 | static void |
michael@0 | 2311 | test_mm_functions(void *arg) |
michael@0 | 2312 | { |
michael@0 | 2313 | struct event_base *b = NULL; |
michael@0 | 2314 | struct event_config *cfg = NULL; |
michael@0 | 2315 | event_set_mem_functions(dummy_malloc, dummy_realloc, dummy_free); |
michael@0 | 2316 | cfg = event_config_new(); |
michael@0 | 2317 | event_config_avoid_method(cfg, "Nonesuch"); |
michael@0 | 2318 | b = event_base_new_with_config(cfg); |
michael@0 | 2319 | tt_assert(b); |
michael@0 | 2320 | tt_assert(check_dummy_mem_ok(b)); |
michael@0 | 2321 | end: |
michael@0 | 2322 | if (cfg) |
michael@0 | 2323 | event_config_free(cfg); |
michael@0 | 2324 | if (b) |
michael@0 | 2325 | event_base_free(b); |
michael@0 | 2326 | } |
michael@0 | 2327 | #endif |
michael@0 | 2328 | |
michael@0 | 2329 | static void |
michael@0 | 2330 | many_event_cb(evutil_socket_t fd, short event, void *arg) |
michael@0 | 2331 | { |
michael@0 | 2332 | int *calledp = arg; |
michael@0 | 2333 | *calledp += 1; |
michael@0 | 2334 | } |
michael@0 | 2335 | |
michael@0 | 2336 | static void |
michael@0 | 2337 | test_many_events(void *arg) |
michael@0 | 2338 | { |
michael@0 | 2339 | /* Try 70 events that should all be ready at once. This will |
michael@0 | 2340 | * exercise the "resize" code on most of the backends, and will make |
michael@0 | 2341 | * sure that we can get past the 64-handle limit of some windows |
michael@0 | 2342 | * functions. */ |
michael@0 | 2343 | #define MANY 70 |
michael@0 | 2344 | |
michael@0 | 2345 | struct basic_test_data *data = arg; |
michael@0 | 2346 | struct event_base *base = data->base; |
michael@0 | 2347 | int one_at_a_time = data->setup_data != NULL; |
michael@0 | 2348 | evutil_socket_t sock[MANY]; |
michael@0 | 2349 | struct event *ev[MANY]; |
michael@0 | 2350 | int called[MANY]; |
michael@0 | 2351 | int i; |
michael@0 | 2352 | int loopflags = EVLOOP_NONBLOCK, evflags=0; |
michael@0 | 2353 | const int is_evport = !strcmp(event_base_get_method(base),"evport"); |
michael@0 | 2354 | if (one_at_a_time) { |
michael@0 | 2355 | loopflags |= EVLOOP_ONCE; |
michael@0 | 2356 | evflags = EV_PERSIST; |
michael@0 | 2357 | } |
michael@0 | 2358 | |
michael@0 | 2359 | memset(sock, 0xff, sizeof(sock)); |
michael@0 | 2360 | memset(ev, 0, sizeof(ev)); |
michael@0 | 2361 | memset(called, 0, sizeof(called)); |
michael@0 | 2362 | if (is_evport && one_at_a_time) { |
michael@0 | 2363 | TT_DECLARE("NOTE", ("evport can't pass this in 2.0; skipping\n")); |
michael@0 | 2364 | tt_skip(); |
michael@0 | 2365 | } |
michael@0 | 2366 | |
michael@0 | 2367 | for (i = 0; i < MANY; ++i) { |
michael@0 | 2368 | /* We need an event that will hit the backend, and that will |
michael@0 | 2369 | * be ready immediately. "Send a datagram" is an easy |
michael@0 | 2370 | * instance of that. */ |
michael@0 | 2371 | sock[i] = socket(AF_INET, SOCK_DGRAM, 0); |
michael@0 | 2372 | tt_assert(sock[i] >= 0); |
michael@0 | 2373 | called[i] = 0; |
michael@0 | 2374 | ev[i] = event_new(base, sock[i], EV_WRITE|evflags, |
michael@0 | 2375 | many_event_cb, &called[i]); |
michael@0 | 2376 | event_add(ev[i], NULL); |
michael@0 | 2377 | if (one_at_a_time) |
michael@0 | 2378 | event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE); |
michael@0 | 2379 | } |
michael@0 | 2380 | |
michael@0 | 2381 | event_base_loop(base, loopflags); |
michael@0 | 2382 | |
michael@0 | 2383 | for (i = 0; i < MANY; ++i) { |
michael@0 | 2384 | if (one_at_a_time) |
michael@0 | 2385 | tt_int_op(called[i], ==, MANY - i + 1); |
michael@0 | 2386 | else |
michael@0 | 2387 | tt_int_op(called[i], ==, 1); |
michael@0 | 2388 | } |
michael@0 | 2389 | |
michael@0 | 2390 | end: |
michael@0 | 2391 | for (i = 0; i < MANY; ++i) { |
michael@0 | 2392 | if (ev[i]) |
michael@0 | 2393 | event_free(ev[i]); |
michael@0 | 2394 | if (sock[i] >= 0) |
michael@0 | 2395 | evutil_closesocket(sock[i]); |
michael@0 | 2396 | } |
michael@0 | 2397 | #undef MANY |
michael@0 | 2398 | } |
michael@0 | 2399 | |
michael@0 | 2400 | static void |
michael@0 | 2401 | test_struct_event_size(void *arg) |
michael@0 | 2402 | { |
michael@0 | 2403 | tt_int_op(event_get_struct_event_size(), <=, sizeof(struct event)); |
michael@0 | 2404 | end: |
michael@0 | 2405 | ; |
michael@0 | 2406 | } |
michael@0 | 2407 | |
michael@0 | 2408 | struct testcase_t main_testcases[] = { |
michael@0 | 2409 | /* Some converted-over tests */ |
michael@0 | 2410 | { "methods", test_methods, TT_FORK, NULL, NULL }, |
michael@0 | 2411 | { "version", test_version, 0, NULL, NULL }, |
michael@0 | 2412 | BASIC(base_features, TT_FORK|TT_NO_LOGS), |
michael@0 | 2413 | { "base_environ", test_base_environ, TT_FORK, NULL, NULL }, |
michael@0 | 2414 | |
michael@0 | 2415 | BASIC(event_base_new, TT_FORK|TT_NEED_SOCKETPAIR), |
michael@0 | 2416 | BASIC(free_active_base, TT_FORK|TT_NEED_SOCKETPAIR), |
michael@0 | 2417 | |
michael@0 | 2418 | BASIC(manipulate_active_events, TT_FORK|TT_NEED_BASE), |
michael@0 | 2419 | |
michael@0 | 2420 | BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), |
michael@0 | 2421 | BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), |
michael@0 | 2422 | |
michael@0 | 2423 | LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE), |
michael@0 | 2424 | { "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, |
michael@0 | 2425 | { "persistent_active_timeout", test_persistent_active_timeout, |
michael@0 | 2426 | TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, |
michael@0 | 2427 | LEGACY(priorities, TT_FORK|TT_NEED_BASE), |
michael@0 | 2428 | BASIC(priority_active_inversion, TT_FORK|TT_NEED_BASE), |
michael@0 | 2429 | { "common_timeout", test_common_timeout, TT_FORK|TT_NEED_BASE, |
michael@0 | 2430 | &basic_setup, NULL }, |
michael@0 | 2431 | |
michael@0 | 2432 | /* These legacy tests may not all need all of these flags. */ |
michael@0 | 2433 | LEGACY(simpleread, TT_ISOLATED), |
michael@0 | 2434 | LEGACY(simpleread_multiple, TT_ISOLATED), |
michael@0 | 2435 | LEGACY(simplewrite, TT_ISOLATED), |
michael@0 | 2436 | { "simpleclose", test_simpleclose, TT_FORK, &basic_setup, |
michael@0 | 2437 | NULL }, |
michael@0 | 2438 | LEGACY(multiple, TT_ISOLATED), |
michael@0 | 2439 | LEGACY(persistent, TT_ISOLATED), |
michael@0 | 2440 | LEGACY(combined, TT_ISOLATED), |
michael@0 | 2441 | LEGACY(simpletimeout, TT_ISOLATED), |
michael@0 | 2442 | LEGACY(loopbreak, TT_ISOLATED), |
michael@0 | 2443 | LEGACY(loopexit, TT_ISOLATED), |
michael@0 | 2444 | LEGACY(loopexit_multiple, TT_ISOLATED), |
michael@0 | 2445 | LEGACY(nonpersist_readd, TT_ISOLATED), |
michael@0 | 2446 | LEGACY(multiple_events_for_same_fd, TT_ISOLATED), |
michael@0 | 2447 | LEGACY(want_only_once, TT_ISOLATED), |
michael@0 | 2448 | { "event_once", test_event_once, TT_ISOLATED, &basic_setup, NULL }, |
michael@0 | 2449 | { "event_pending", test_event_pending, TT_ISOLATED, &basic_setup, |
michael@0 | 2450 | NULL }, |
michael@0 | 2451 | #ifndef WIN32 |
michael@0 | 2452 | { "dup_fd", test_dup_fd, TT_ISOLATED, &basic_setup, NULL }, |
michael@0 | 2453 | #endif |
michael@0 | 2454 | { "mm_functions", test_mm_functions, TT_FORK, NULL, NULL }, |
michael@0 | 2455 | { "many_events", test_many_events, TT_ISOLATED, &basic_setup, NULL }, |
michael@0 | 2456 | { "many_events_slow_add", test_many_events, TT_ISOLATED, &basic_setup, (void*)1 }, |
michael@0 | 2457 | |
michael@0 | 2458 | { "struct_event_size", test_struct_event_size, 0, NULL, NULL }, |
michael@0 | 2459 | |
michael@0 | 2460 | #ifndef WIN32 |
michael@0 | 2461 | LEGACY(fork, TT_ISOLATED), |
michael@0 | 2462 | #endif |
michael@0 | 2463 | END_OF_TESTCASES |
michael@0 | 2464 | }; |
michael@0 | 2465 | |
michael@0 | 2466 | struct testcase_t evtag_testcases[] = { |
michael@0 | 2467 | { "int", evtag_int_test, TT_FORK, NULL, NULL }, |
michael@0 | 2468 | { "fuzz", evtag_fuzz, TT_FORK, NULL, NULL }, |
michael@0 | 2469 | { "encoding", evtag_tag_encoding, TT_FORK, NULL, NULL }, |
michael@0 | 2470 | { "peek", evtag_test_peek, 0, NULL, NULL }, |
michael@0 | 2471 | |
michael@0 | 2472 | END_OF_TESTCASES |
michael@0 | 2473 | }; |
michael@0 | 2474 | |
michael@0 | 2475 | struct testcase_t signal_testcases[] = { |
michael@0 | 2476 | #ifndef WIN32 |
michael@0 | 2477 | LEGACY(simplesignal, TT_ISOLATED), |
michael@0 | 2478 | LEGACY(multiplesignal, TT_ISOLATED), |
michael@0 | 2479 | LEGACY(immediatesignal, TT_ISOLATED), |
michael@0 | 2480 | LEGACY(signal_dealloc, TT_ISOLATED), |
michael@0 | 2481 | LEGACY(signal_pipeloss, TT_ISOLATED), |
michael@0 | 2482 | LEGACY(signal_switchbase, TT_ISOLATED|TT_NO_LOGS), |
michael@0 | 2483 | LEGACY(signal_restore, TT_ISOLATED), |
michael@0 | 2484 | LEGACY(signal_assert, TT_ISOLATED), |
michael@0 | 2485 | LEGACY(signal_while_processing, TT_ISOLATED), |
michael@0 | 2486 | #endif |
michael@0 | 2487 | END_OF_TESTCASES |
michael@0 | 2488 | }; |
michael@0 | 2489 |