qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 718 lines 23 kB view raw
1/* 2 * Tests for util/filemonitor-*.c 3 * 4 * Copyright 2018 Red Hat, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21#include "qemu/osdep.h" 22#include "qemu/main-loop.h" 23#include "qapi/error.h" 24#include "qemu/filemonitor.h" 25 26#include <utime.h> 27 28enum { 29 QFILE_MONITOR_TEST_OP_ADD_WATCH, 30 QFILE_MONITOR_TEST_OP_DEL_WATCH, 31 QFILE_MONITOR_TEST_OP_EVENT, 32 QFILE_MONITOR_TEST_OP_CREATE, 33 QFILE_MONITOR_TEST_OP_APPEND, 34 QFILE_MONITOR_TEST_OP_TRUNC, 35 QFILE_MONITOR_TEST_OP_RENAME, 36 QFILE_MONITOR_TEST_OP_TOUCH, 37 QFILE_MONITOR_TEST_OP_UNLINK, 38 QFILE_MONITOR_TEST_OP_MKDIR, 39 QFILE_MONITOR_TEST_OP_RMDIR, 40}; 41 42typedef struct { 43 int type; 44 const char *filesrc; 45 const char *filedst; 46 int64_t *watchid; 47 int eventid; 48 /* 49 * Only valid with OP_EVENT - this event might be 50 * swapped with the next OP_EVENT 51 */ 52 bool swapnext; 53} QFileMonitorTestOp; 54 55typedef struct { 56 int64_t id; 57 QFileMonitorEvent event; 58 char *filename; 59} QFileMonitorTestRecord; 60 61 62typedef struct { 63 QemuMutex lock; 64 GList *records; 65} QFileMonitorTestData; 66 67static QemuMutex evlock; 68static bool evstopping; 69static bool evrunning; 70static bool debug; 71 72/* 73 * Main function for a background thread that is 74 * running the event loop during the test 75 */ 76static void * 77qemu_file_monitor_test_event_loop(void *opaque G_GNUC_UNUSED) 78{ 79 qemu_mutex_lock(&evlock); 80 81 while (!evstopping) { 82 qemu_mutex_unlock(&evlock); 83 main_loop_wait(true); 84 qemu_mutex_lock(&evlock); 85 } 86 87 evrunning = false; 88 qemu_mutex_unlock(&evlock); 89 return NULL; 90} 91 92 93/* 94 * File monitor event handler which simply maintains 95 * an ordered list of all events that it receives 96 */ 97static void 98qemu_file_monitor_test_handler(int64_t id, 99 QFileMonitorEvent event, 100 const char *filename, 101 void *opaque) 102{ 103 QFileMonitorTestData *data = opaque; 104 QFileMonitorTestRecord *rec = g_new0(QFileMonitorTestRecord, 1); 105 106 if (debug) { 107 g_printerr("Queue event id %" PRIx64 " event %d file %s\n", 108 id, event, filename); 109 } 110 rec->id = id; 111 rec->event = event; 112 rec->filename = g_strdup(filename); 113 114 qemu_mutex_lock(&data->lock); 115 data->records = g_list_append(data->records, rec); 116 qemu_mutex_unlock(&data->lock); 117} 118 119 120static void 121qemu_file_monitor_test_record_free(QFileMonitorTestRecord *rec) 122{ 123 g_free(rec->filename); 124 g_free(rec); 125} 126 127 128/* 129 * Get the next event record that has been received by 130 * the file monitor event handler. Since events are 131 * emitted in the background thread running the event 132 * loop, we can't assume there is a record available 133 * immediately. Thus we will sleep for upto 5 seconds 134 * to wait for the event to be queued for us. 135 */ 136static QFileMonitorTestRecord * 137qemu_file_monitor_test_next_record(QFileMonitorTestData *data, 138 QFileMonitorTestRecord *pushback) 139{ 140 GTimer *timer = g_timer_new(); 141 QFileMonitorTestRecord *record = NULL; 142 GList *tmp; 143 144 qemu_mutex_lock(&data->lock); 145 while (!data->records && g_timer_elapsed(timer, NULL) < 5) { 146 qemu_mutex_unlock(&data->lock); 147 usleep(10 * 1000); 148 qemu_mutex_lock(&data->lock); 149 } 150 if (data->records) { 151 record = data->records->data; 152 if (pushback) { 153 data->records->data = pushback; 154 } else { 155 tmp = data->records; 156 data->records = g_list_remove_link(data->records, tmp); 157 g_list_free(tmp); 158 } 159 } else if (pushback) { 160 qemu_file_monitor_test_record_free(pushback); 161 } 162 qemu_mutex_unlock(&data->lock); 163 164 g_timer_destroy(timer); 165 return record; 166} 167 168 169/* 170 * Check whether the event record we retrieved matches 171 * data we were expecting to see for the event 172 */ 173static bool 174qemu_file_monitor_test_expect(QFileMonitorTestData *data, 175 int64_t id, 176 QFileMonitorEvent event, 177 const char *filename, 178 bool swapnext) 179{ 180 QFileMonitorTestRecord *rec; 181 bool ret = false; 182 183 rec = qemu_file_monitor_test_next_record(data, NULL); 184 185 retry: 186 if (!rec) { 187 g_printerr("Missing event watch id %" PRIx64 " event %d file %s\n", 188 id, event, filename); 189 return false; 190 } 191 192 if (id != rec->id) { 193 if (swapnext) { 194 rec = qemu_file_monitor_test_next_record(data, rec); 195 swapnext = false; 196 goto retry; 197 } 198 g_printerr("Expected watch id %" PRIx64 " but got %" PRIx64 "\n", 199 id, rec->id); 200 goto cleanup; 201 } 202 203 if (event != rec->event) { 204 g_printerr("Expected event %d but got %d\n", event, rec->event); 205 goto cleanup; 206 } 207 208 if (!g_str_equal(filename, rec->filename)) { 209 g_printerr("Expected filename %s but got %s\n", 210 filename, rec->filename); 211 goto cleanup; 212 } 213 214 ret = true; 215 216 cleanup: 217 qemu_file_monitor_test_record_free(rec); 218 return ret; 219} 220 221 222static void 223test_file_monitor_events(void) 224{ 225 int64_t watch0 = 0; 226 int64_t watch1 = 0; 227 int64_t watch2 = 0; 228 int64_t watch3 = 0; 229 int64_t watch4 = 0; 230 int64_t watch5 = 0; 231 QFileMonitorTestOp ops[] = { 232 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH, 233 .filesrc = NULL, .watchid = &watch0 }, 234 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH, 235 .filesrc = "one.txt", .watchid = &watch1 }, 236 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH, 237 .filesrc = "two.txt", .watchid = &watch2 }, 238 239 240 { .type = QFILE_MONITOR_TEST_OP_CREATE, 241 .filesrc = "one.txt", }, 242 { .type = QFILE_MONITOR_TEST_OP_EVENT, 243 .filesrc = "one.txt", .watchid = &watch0, 244 .eventid = QFILE_MONITOR_EVENT_CREATED }, 245 { .type = QFILE_MONITOR_TEST_OP_EVENT, 246 .filesrc = "one.txt", .watchid = &watch1, 247 .eventid = QFILE_MONITOR_EVENT_CREATED }, 248 249 250 { .type = QFILE_MONITOR_TEST_OP_CREATE, 251 .filesrc = "two.txt", }, 252 { .type = QFILE_MONITOR_TEST_OP_EVENT, 253 .filesrc = "two.txt", .watchid = &watch0, 254 .eventid = QFILE_MONITOR_EVENT_CREATED }, 255 { .type = QFILE_MONITOR_TEST_OP_EVENT, 256 .filesrc = "two.txt", .watchid = &watch2, 257 .eventid = QFILE_MONITOR_EVENT_CREATED }, 258 259 260 { .type = QFILE_MONITOR_TEST_OP_CREATE, 261 .filesrc = "three.txt", }, 262 { .type = QFILE_MONITOR_TEST_OP_EVENT, 263 .filesrc = "three.txt", .watchid = &watch0, 264 .eventid = QFILE_MONITOR_EVENT_CREATED }, 265 266 267 { .type = QFILE_MONITOR_TEST_OP_UNLINK, 268 .filesrc = "three.txt", }, 269 { .type = QFILE_MONITOR_TEST_OP_EVENT, 270 .filesrc = "three.txt", .watchid = &watch0, 271 .eventid = QFILE_MONITOR_EVENT_DELETED }, 272 273 274 { .type = QFILE_MONITOR_TEST_OP_RENAME, 275 .filesrc = "one.txt", .filedst = "two.txt" }, 276 { .type = QFILE_MONITOR_TEST_OP_EVENT, 277 .filesrc = "one.txt", .watchid = &watch0, 278 .eventid = QFILE_MONITOR_EVENT_DELETED }, 279 { .type = QFILE_MONITOR_TEST_OP_EVENT, 280 .filesrc = "one.txt", .watchid = &watch1, 281 .eventid = QFILE_MONITOR_EVENT_DELETED }, 282 { .type = QFILE_MONITOR_TEST_OP_EVENT, 283 .filesrc = "two.txt", .watchid = &watch0, 284 .eventid = QFILE_MONITOR_EVENT_CREATED }, 285 { .type = QFILE_MONITOR_TEST_OP_EVENT, 286 .filesrc = "two.txt", .watchid = &watch2, 287 .eventid = QFILE_MONITOR_EVENT_CREATED }, 288 289 290 { .type = QFILE_MONITOR_TEST_OP_APPEND, 291 .filesrc = "two.txt", }, 292 { .type = QFILE_MONITOR_TEST_OP_EVENT, 293 .filesrc = "two.txt", .watchid = &watch0, 294 .eventid = QFILE_MONITOR_EVENT_MODIFIED }, 295 { .type = QFILE_MONITOR_TEST_OP_EVENT, 296 .filesrc = "two.txt", .watchid = &watch2, 297 .eventid = QFILE_MONITOR_EVENT_MODIFIED }, 298 299 300 { .type = QFILE_MONITOR_TEST_OP_TOUCH, 301 .filesrc = "two.txt", }, 302 { .type = QFILE_MONITOR_TEST_OP_EVENT, 303 .filesrc = "two.txt", .watchid = &watch0, 304 .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES }, 305 { .type = QFILE_MONITOR_TEST_OP_EVENT, 306 .filesrc = "two.txt", .watchid = &watch2, 307 .eventid = QFILE_MONITOR_EVENT_ATTRIBUTES }, 308 309 310 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 311 .filesrc = "one.txt", .watchid = &watch1 }, 312 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH, 313 .filesrc = "one.txt", .watchid = &watch3 }, 314 { .type = QFILE_MONITOR_TEST_OP_CREATE, 315 .filesrc = "one.txt", }, 316 { .type = QFILE_MONITOR_TEST_OP_EVENT, 317 .filesrc = "one.txt", .watchid = &watch0, 318 .eventid = QFILE_MONITOR_EVENT_CREATED }, 319 { .type = QFILE_MONITOR_TEST_OP_EVENT, 320 .filesrc = "one.txt", .watchid = &watch3, 321 .eventid = QFILE_MONITOR_EVENT_CREATED }, 322 323 324 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 325 .filesrc = "one.txt", .watchid = &watch3 }, 326 { .type = QFILE_MONITOR_TEST_OP_UNLINK, 327 .filesrc = "one.txt", }, 328 { .type = QFILE_MONITOR_TEST_OP_EVENT, 329 .filesrc = "one.txt", .watchid = &watch0, 330 .eventid = QFILE_MONITOR_EVENT_DELETED }, 331 332 333 { .type = QFILE_MONITOR_TEST_OP_MKDIR, 334 .filesrc = "fish", }, 335 { .type = QFILE_MONITOR_TEST_OP_EVENT, 336 .filesrc = "fish", .watchid = &watch0, 337 .eventid = QFILE_MONITOR_EVENT_CREATED }, 338 339 340 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH, 341 .filesrc = "fish/", .watchid = &watch4 }, 342 { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH, 343 .filesrc = "fish/one.txt", .watchid = &watch5 }, 344 { .type = QFILE_MONITOR_TEST_OP_CREATE, 345 .filesrc = "fish/one.txt", }, 346 { .type = QFILE_MONITOR_TEST_OP_EVENT, 347 .filesrc = "one.txt", .watchid = &watch4, 348 .eventid = QFILE_MONITOR_EVENT_CREATED }, 349 { .type = QFILE_MONITOR_TEST_OP_EVENT, 350 .filesrc = "one.txt", .watchid = &watch5, 351 .eventid = QFILE_MONITOR_EVENT_CREATED }, 352 353 354 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 355 .filesrc = "fish/one.txt", .watchid = &watch5 }, 356 { .type = QFILE_MONITOR_TEST_OP_RENAME, 357 .filesrc = "fish/one.txt", .filedst = "two.txt", }, 358 { .type = QFILE_MONITOR_TEST_OP_EVENT, 359 .filesrc = "one.txt", .watchid = &watch4, 360 .eventid = QFILE_MONITOR_EVENT_DELETED }, 361 { .type = QFILE_MONITOR_TEST_OP_EVENT, 362 .filesrc = "two.txt", .watchid = &watch0, 363 .eventid = QFILE_MONITOR_EVENT_CREATED }, 364 { .type = QFILE_MONITOR_TEST_OP_EVENT, 365 .filesrc = "two.txt", .watchid = &watch2, 366 .eventid = QFILE_MONITOR_EVENT_CREATED }, 367 368 369 { .type = QFILE_MONITOR_TEST_OP_RMDIR, 370 .filesrc = "fish", }, 371 { .type = QFILE_MONITOR_TEST_OP_EVENT, 372 .filesrc = "", .watchid = &watch4, 373 .eventid = QFILE_MONITOR_EVENT_IGNORED, 374 .swapnext = true }, 375 { .type = QFILE_MONITOR_TEST_OP_EVENT, 376 .filesrc = "fish", .watchid = &watch0, 377 .eventid = QFILE_MONITOR_EVENT_DELETED }, 378 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 379 .filesrc = "fish", .watchid = &watch4 }, 380 381 382 { .type = QFILE_MONITOR_TEST_OP_UNLINK, 383 .filesrc = "two.txt", }, 384 { .type = QFILE_MONITOR_TEST_OP_EVENT, 385 .filesrc = "two.txt", .watchid = &watch0, 386 .eventid = QFILE_MONITOR_EVENT_DELETED }, 387 { .type = QFILE_MONITOR_TEST_OP_EVENT, 388 .filesrc = "two.txt", .watchid = &watch2, 389 .eventid = QFILE_MONITOR_EVENT_DELETED }, 390 391 392 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 393 .filesrc = "two.txt", .watchid = &watch2 }, 394 { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 395 .filesrc = NULL, .watchid = &watch0 }, 396 }; 397 Error *local_err = NULL; 398 GError *gerr = NULL; 399 QFileMonitor *mon = qemu_file_monitor_new(&local_err); 400 QemuThread th; 401 GTimer *timer; 402 gchar *dir = NULL; 403 int err = -1; 404 gsize i; 405 char *pathsrc = NULL; 406 char *pathdst = NULL; 407 QFileMonitorTestData data; 408 GHashTable *ids = g_hash_table_new(g_int64_hash, g_int64_equal); 409 char *travis_arch; 410 411 qemu_mutex_init(&data.lock); 412 data.records = NULL; 413 414 /* 415 * This test does not work on Travis LXD containers since some 416 * syscalls are blocked in that environment. 417 */ 418 travis_arch = getenv("TRAVIS_ARCH"); 419 if (travis_arch && !g_str_equal(travis_arch, "x86_64")) { 420 g_test_skip("Test does not work on non-x86 Travis containers."); 421 return; 422 } 423 424 /* 425 * The file monitor needs the main loop running in 426 * order to receive events from inotify. We must 427 * thus spawn a background thread to run an event 428 * loop impl, while this thread triggers the 429 * actual file operations we're testing 430 */ 431 evrunning = 1; 432 evstopping = 0; 433 qemu_thread_create(&th, "event-loop", 434 qemu_file_monitor_test_event_loop, NULL, 435 QEMU_THREAD_JOINABLE); 436 437 if (local_err) { 438 g_printerr("File monitoring not available: %s", 439 error_get_pretty(local_err)); 440 error_free(local_err); 441 return; 442 } 443 444 dir = g_dir_make_tmp("test-util-filemonitor-XXXXXX", 445 &gerr); 446 if (!dir) { 447 g_printerr("Unable to create tmp dir %s", 448 gerr->message); 449 g_error_free(gerr); 450 abort(); 451 } 452 453 /* 454 * Run through the operation sequence validating events 455 * as we go 456 */ 457 for (i = 0; i < G_N_ELEMENTS(ops); i++) { 458 const QFileMonitorTestOp *op = &(ops[i]); 459 int fd; 460 struct utimbuf ubuf; 461 char *watchdir; 462 const char *watchfile; 463 464 pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc); 465 if (op->filedst) { 466 pathdst = g_strdup_printf("%s/%s", dir, op->filedst); 467 } 468 469 switch (op->type) { 470 case QFILE_MONITOR_TEST_OP_ADD_WATCH: 471 if (debug) { 472 g_printerr("Add watch %s %s\n", 473 dir, op->filesrc); 474 } 475 if (op->filesrc && strchr(op->filesrc, '/')) { 476 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc); 477 watchfile = strrchr(watchdir, '/'); 478 *(char *)watchfile = '\0'; 479 watchfile++; 480 if (*watchfile == '\0') { 481 watchfile = NULL; 482 } 483 } else { 484 watchdir = g_strdup(dir); 485 watchfile = op->filesrc; 486 } 487 *op->watchid = 488 qemu_file_monitor_add_watch(mon, 489 watchdir, 490 watchfile, 491 qemu_file_monitor_test_handler, 492 &data, 493 &local_err); 494 g_free(watchdir); 495 if (*op->watchid < 0) { 496 g_printerr("Unable to add watch %s", 497 error_get_pretty(local_err)); 498 error_free(local_err); 499 goto cleanup; 500 } 501 if (debug) { 502 g_printerr("Watch ID %" PRIx64 "\n", *op->watchid); 503 } 504 if (g_hash_table_contains(ids, op->watchid)) { 505 g_printerr("Watch ID %" PRIx64 "already exists", *op->watchid); 506 goto cleanup; 507 } 508 g_hash_table_add(ids, op->watchid); 509 break; 510 case QFILE_MONITOR_TEST_OP_DEL_WATCH: 511 if (debug) { 512 g_printerr("Del watch %s %" PRIx64 "\n", dir, *op->watchid); 513 } 514 if (op->filesrc && strchr(op->filesrc, '/')) { 515 watchdir = g_strdup_printf("%s/%s", dir, op->filesrc); 516 watchfile = strrchr(watchdir, '/'); 517 *(char *)watchfile = '\0'; 518 } else { 519 watchdir = g_strdup(dir); 520 } 521 g_hash_table_remove(ids, op->watchid); 522 qemu_file_monitor_remove_watch(mon, 523 watchdir, 524 *op->watchid); 525 g_free(watchdir); 526 break; 527 case QFILE_MONITOR_TEST_OP_EVENT: 528 if (debug) { 529 g_printerr("Event id=%" PRIx64 " event=%d file=%s\n", 530 *op->watchid, op->eventid, op->filesrc); 531 } 532 if (!qemu_file_monitor_test_expect(&data, *op->watchid, 533 op->eventid, op->filesrc, 534 op->swapnext)) 535 goto cleanup; 536 break; 537 case QFILE_MONITOR_TEST_OP_CREATE: 538 if (debug) { 539 g_printerr("Create %s\n", pathsrc); 540 } 541 fd = open(pathsrc, O_WRONLY | O_CREAT, 0700); 542 if (fd < 0) { 543 g_printerr("Unable to create %s: %s", 544 pathsrc, strerror(errno)); 545 goto cleanup; 546 } 547 close(fd); 548 break; 549 550 case QFILE_MONITOR_TEST_OP_APPEND: 551 if (debug) { 552 g_printerr("Append %s\n", pathsrc); 553 } 554 fd = open(pathsrc, O_WRONLY | O_APPEND, 0700); 555 if (fd < 0) { 556 g_printerr("Unable to open %s: %s", 557 pathsrc, strerror(errno)); 558 goto cleanup; 559 } 560 561 if (write(fd, "Hello World", 10) != 10) { 562 g_printerr("Unable to write %s: %s", 563 pathsrc, strerror(errno)); 564 close(fd); 565 goto cleanup; 566 } 567 close(fd); 568 break; 569 570 case QFILE_MONITOR_TEST_OP_TRUNC: 571 if (debug) { 572 g_printerr("Truncate %s\n", pathsrc); 573 } 574 if (truncate(pathsrc, 4) < 0) { 575 g_printerr("Unable to truncate %s: %s", 576 pathsrc, strerror(errno)); 577 goto cleanup; 578 } 579 break; 580 581 case QFILE_MONITOR_TEST_OP_RENAME: 582 if (debug) { 583 g_printerr("Rename %s -> %s\n", pathsrc, pathdst); 584 } 585 if (rename(pathsrc, pathdst) < 0) { 586 g_printerr("Unable to rename %s to %s: %s", 587 pathsrc, pathdst, strerror(errno)); 588 goto cleanup; 589 } 590 break; 591 592 case QFILE_MONITOR_TEST_OP_UNLINK: 593 if (debug) { 594 g_printerr("Unlink %s\n", pathsrc); 595 } 596 if (unlink(pathsrc) < 0) { 597 g_printerr("Unable to unlink %s: %s", 598 pathsrc, strerror(errno)); 599 goto cleanup; 600 } 601 break; 602 603 case QFILE_MONITOR_TEST_OP_TOUCH: 604 if (debug) { 605 g_printerr("Touch %s\n", pathsrc); 606 } 607 ubuf.actime = 1024; 608 ubuf.modtime = 1025; 609 if (utime(pathsrc, &ubuf) < 0) { 610 g_printerr("Unable to touch %s: %s", 611 pathsrc, strerror(errno)); 612 goto cleanup; 613 } 614 break; 615 616 case QFILE_MONITOR_TEST_OP_MKDIR: 617 if (debug) { 618 g_printerr("Mkdir %s\n", pathsrc); 619 } 620 if (mkdir(pathsrc, 0700) < 0) { 621 g_printerr("Unable to mkdir %s: %s", 622 pathsrc, strerror(errno)); 623 goto cleanup; 624 } 625 break; 626 627 case QFILE_MONITOR_TEST_OP_RMDIR: 628 if (debug) { 629 g_printerr("Rmdir %s\n", pathsrc); 630 } 631 if (rmdir(pathsrc) < 0) { 632 g_printerr("Unable to rmdir %s: %s", 633 pathsrc, strerror(errno)); 634 goto cleanup; 635 } 636 break; 637 638 default: 639 g_assert_not_reached(); 640 } 641 642 g_free(pathsrc); 643 g_free(pathdst); 644 pathsrc = pathdst = NULL; 645 } 646 647 g_assert_cmpint(g_hash_table_size(ids), ==, 0); 648 649 err = 0; 650 651 cleanup: 652 g_free(pathsrc); 653 g_free(pathdst); 654 655 qemu_mutex_lock(&evlock); 656 evstopping = 1; 657 timer = g_timer_new(); 658 while (evrunning && g_timer_elapsed(timer, NULL) < 5) { 659 qemu_mutex_unlock(&evlock); 660 usleep(10 * 1000); 661 qemu_mutex_lock(&evlock); 662 } 663 qemu_mutex_unlock(&evlock); 664 665 if (g_timer_elapsed(timer, NULL) >= 5) { 666 g_printerr("Event loop failed to quit after 5 seconds\n"); 667 } 668 g_timer_destroy(timer); 669 670 qemu_file_monitor_free(mon); 671 g_list_foreach(data.records, 672 (GFunc)qemu_file_monitor_test_record_free, NULL); 673 g_list_free(data.records); 674 qemu_mutex_destroy(&data.lock); 675 if (dir) { 676 for (i = 0; i < G_N_ELEMENTS(ops); i++) { 677 const QFileMonitorTestOp *op = &(ops[i]); 678 char *path = g_strdup_printf("%s/%s", 679 dir, op->filesrc); 680 if (op->type == QFILE_MONITOR_TEST_OP_MKDIR) { 681 rmdir(path); 682 g_free(path); 683 } else { 684 unlink(path); 685 g_free(path); 686 if (op->filedst) { 687 path = g_strdup_printf("%s/%s", 688 dir, op->filedst); 689 unlink(path); 690 g_free(path); 691 } 692 } 693 } 694 if (rmdir(dir) < 0) { 695 g_printerr("Failed to remove %s: %s\n", 696 dir, strerror(errno)); 697 abort(); 698 } 699 } 700 g_hash_table_unref(ids); 701 g_free(dir); 702 g_assert(err == 0); 703} 704 705 706int main(int argc, char **argv) 707{ 708 g_test_init(&argc, &argv, NULL); 709 710 qemu_init_main_loop(&error_abort); 711 712 qemu_mutex_init(&evlock); 713 714 debug = getenv("FILEMONITOR_DEBUG") != NULL; 715 g_test_add_func("/util/filemonitor", test_file_monitor_events); 716 717 return g_test_run(); 718}