1 /* 2 * QEMU System Emulator 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "sysemu.h" 26 #include "net.h" 27 #include "monitor.h" 28 #include "console.h" 29 30 #include "hw/hw.h" 31 32 #include "qemu-timer.h" 33 34 #ifdef _WIN32 35 #include <mmsystem.h> 36 #endif 37 38 /***********************************************************/ 39 /* timers */ 40 41 #define QEMU_CLOCK_REALTIME 0 42 #define QEMU_CLOCK_VIRTUAL 1 43 #define QEMU_CLOCK_HOST 2 44 45 struct QEMUClock { 46 QEMUTimer *active_timers; 47 48 NotifierList reset_notifiers; 49 int64_t last; 50 51 int type; 52 bool enabled; 53 }; 54 55 struct QEMUTimer { 56 int64_t expire_time; /* in nanoseconds */ 57 QEMUClock *clock; 58 QEMUTimerCB *cb; 59 void *opaque; 60 QEMUTimer *next; 61 int scale; 62 }; 63 64 struct qemu_alarm_timer { 65 char const *name; 66 int (*start)(struct qemu_alarm_timer *t); 67 void (*stop)(struct qemu_alarm_timer *t); 68 void (*rearm)(struct qemu_alarm_timer *t, int64_t nearest_delta_ns); 69 #if defined(__linux__) 70 timer_t timer; 71 int fd; 72 #elif defined(_WIN32) 73 HANDLE timer; 74 #endif 75 bool expired; 76 bool pending; 77 }; 78 79 static struct qemu_alarm_timer *alarm_timer; 80 81 static bool qemu_timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) 82 { 83 return timer_head && (timer_head->expire_time <= current_time); 84 } 85 86 static int64_t qemu_next_alarm_deadline(void) 87 { 88 int64_t delta = INT64_MAX; 89 int64_t rtdelta; 90 91 if (!use_icount && vm_clock->enabled && vm_clock->active_timers) { 92 delta = vm_clock->active_timers->expire_time - 93 qemu_get_clock_ns(vm_clock); 94 } 95 if (host_clock->enabled && host_clock->active_timers) { 96 int64_t hdelta = host_clock->active_timers->expire_time - 97 qemu_get_clock_ns(host_clock); 98 if (hdelta < delta) { 99 delta = hdelta; 100 } 101 } 102 if (rt_clock->enabled && rt_clock->active_timers) { 103 rtdelta = (rt_clock->active_timers->expire_time - 104 qemu_get_clock_ns(rt_clock)); 105 if (rtdelta < delta) { 106 delta = rtdelta; 107 } 108 } 109 110 return delta; 111 } 112 113 static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) 114 { 115 int64_t nearest_delta_ns; 116 if (!rt_clock->active_timers && 117 !vm_clock->active_timers && 118 !host_clock->active_timers) { 119 return; 120 } 121 nearest_delta_ns = qemu_next_alarm_deadline(); 122 t->rearm(t, nearest_delta_ns); 123 } 124 125 /* TODO: MIN_TIMER_REARM_NS should be optimized */ 126 #define MIN_TIMER_REARM_NS 250000 127 128 #ifdef _WIN32 129 130 static int mm_start_timer(struct qemu_alarm_timer *t); 131 static void mm_stop_timer(struct qemu_alarm_timer *t); 132 static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); 133 134 static int win32_start_timer(struct qemu_alarm_timer *t); 135 static void win32_stop_timer(struct qemu_alarm_timer *t); 136 static void win32_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); 137 138 #else 139 140 static int unix_start_timer(struct qemu_alarm_timer *t); 141 static void unix_stop_timer(struct qemu_alarm_timer *t); 142 static void unix_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); 143 144 #ifdef __linux__ 145 146 static int dynticks_start_timer(struct qemu_alarm_timer *t); 147 static void dynticks_stop_timer(struct qemu_alarm_timer *t); 148 static void dynticks_rearm_timer(struct qemu_alarm_timer *t, int64_t delta); 149 150 #endif /* __linux__ */ 151 152 #endif /* _WIN32 */ 153 154 static struct qemu_alarm_timer alarm_timers[] = { 155 #ifndef _WIN32 156 #ifdef __linux__ 157 {"dynticks", dynticks_start_timer, 158 dynticks_stop_timer, dynticks_rearm_timer}, 159 #endif 160 {"unix", unix_start_timer, unix_stop_timer, unix_rearm_timer}, 161 #else 162 {"mmtimer", mm_start_timer, mm_stop_timer, mm_rearm_timer}, 163 {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer}, 164 #endif 165 {NULL, } 166 }; 167 168 static void show_available_alarms(void) 169 { 170 int i; 171 172 printf("Available alarm timers, in order of precedence:\n"); 173 for (i = 0; alarm_timers[i].name; i++) 174 printf("%s\n", alarm_timers[i].name); 175 } 176 177 void configure_alarms(char const *opt) 178 { 179 int i; 180 int cur = 0; 181 int count = ARRAY_SIZE(alarm_timers) - 1; 182 char *arg; 183 char *name; 184 struct qemu_alarm_timer tmp; 185 186 if (!strcmp(opt, "?")) { 187 show_available_alarms(); 188 exit(0); 189 } 190 191 arg = g_strdup(opt); 192 193 /* Reorder the array */ 194 name = strtok(arg, ","); 195 while (name) { 196 for (i = 0; i < count && alarm_timers[i].name; i++) { 197 if (!strcmp(alarm_timers[i].name, name)) 198 break; 199 } 200 201 if (i == count) { 202 fprintf(stderr, "Unknown clock %s\n", name); 203 goto next; 204 } 205 206 if (i < cur) 207 /* Ignore */ 208 goto next; 209 210 /* Swap */ 211 tmp = alarm_timers[i]; 212 alarm_timers[i] = alarm_timers[cur]; 213 alarm_timers[cur] = tmp; 214 215 cur++; 216 next: 217 name = strtok(NULL, ","); 218 } 219 220 g_free(arg); 221 222 if (cur) { 223 /* Disable remaining timers */ 224 for (i = cur; i < count; i++) 225 alarm_timers[i].name = NULL; 226 } else { 227 show_available_alarms(); 228 exit(1); 229 } 230 } 231 232 QEMUClock *rt_clock; 233 QEMUClock *vm_clock; 234 QEMUClock *host_clock; 235 236 static QEMUClock *qemu_new_clock(int type) 237 { 238 QEMUClock *clock; 239 240 clock = g_malloc0(sizeof(QEMUClock)); 241 clock->type = type; 242 clock->enabled = true; 243 clock->last = INT64_MIN; 244 notifier_list_init(&clock->reset_notifiers); 245 return clock; 246 } 247 248 void qemu_clock_enable(QEMUClock *clock, bool enabled) 249 { 250 bool old = clock->enabled; 251 clock->enabled = enabled; 252 if (enabled && !old) { 253 qemu_rearm_alarm_timer(alarm_timer); 254 } 255 } 256 257 int64_t qemu_clock_has_timers(QEMUClock *clock) 258 { 259 return !!clock->active_timers; 260 } 261 262 int64_t qemu_clock_expired(QEMUClock *clock) 263 { 264 return (clock->active_timers && 265 clock->active_timers->expire_time < qemu_get_clock_ns(clock)); 266 } 267 268 int64_t qemu_clock_deadline(QEMUClock *clock) 269 { 270 /* To avoid problems with overflow limit this to 2^32. */ 271 int64_t delta = INT32_MAX; 272 273 if (clock->active_timers) { 274 delta = clock->active_timers->expire_time - qemu_get_clock_ns(clock); 275 } 276 if (delta < 0) { 277 delta = 0; 278 } 279 return delta; 280 } 281 282 QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, 283 QEMUTimerCB *cb, void *opaque) 284 { 285 QEMUTimer *ts; 286 287 ts = g_malloc0(sizeof(QEMUTimer)); 288 ts->clock = clock; 289 ts->cb = cb; 290 ts->opaque = opaque; 291 ts->scale = scale; 292 return ts; 293 } 294 295 void qemu_free_timer(QEMUTimer *ts) 296 { 297 g_free(ts); 298 } 299 300 /* stop a timer, but do not dealloc it */ 301 void qemu_del_timer(QEMUTimer *ts) 302 { 303 QEMUTimer **pt, *t; 304 305 /* NOTE: this code must be signal safe because 306 qemu_timer_expired() can be called from a signal. */ 307 pt = &ts->clock->active_timers; 308 for(;;) { 309 t = *pt; 310 if (!t) 311 break; 312 if (t == ts) { 313 *pt = t->next; 314 break; 315 } 316 pt = &t->next; 317 } 318 } 319 320 /* modify the current timer so that it will be fired when current_time 321 >= expire_time. The corresponding callback will be called. */ 322 void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time) 323 { 324 QEMUTimer **pt, *t; 325 326 qemu_del_timer(ts); 327 328 /* add the timer in the sorted list */ 329 /* NOTE: this code must be signal safe because 330 qemu_timer_expired() can be called from a signal. */ 331 pt = &ts->clock->active_timers; 332 for(;;) { 333 t = *pt; 334 if (!qemu_timer_expired_ns(t, expire_time)) { 335 break; 336 } 337 pt = &t->next; 338 } 339 ts->expire_time = expire_time; 340 ts->next = *pt; 341 *pt = ts; 342 343 /* Rearm if necessary */ 344 if (pt == &ts->clock->active_timers) { 345 if (!alarm_timer->pending) { 346 qemu_rearm_alarm_timer(alarm_timer); 347 } 348 /* Interrupt execution to force deadline recalculation. */ 349 qemu_clock_warp(ts->clock); 350 if (use_icount) { 351 qemu_notify_event(); 352 } 353 } 354 } 355 356 void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) 357 { 358 qemu_mod_timer_ns(ts, expire_time * ts->scale); 359 } 360 361 bool qemu_timer_pending(QEMUTimer *ts) 362 { 363 QEMUTimer *t; 364 for (t = ts->clock->active_timers; t != NULL; t = t->next) { 365 if (t == ts) { 366 return true; 367 } 368 } 369 return false; 370 } 371 372 bool qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) 373 { 374 return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale); 375 } 376 377 void qemu_run_timers(QEMUClock *clock) 378 { 379 QEMUTimer **ptimer_head, *ts; 380 int64_t current_time; 381 382 if (!clock->enabled) 383 return; 384 385 current_time = qemu_get_clock_ns(clock); 386 ptimer_head = &clock->active_timers; 387 for(;;) { 388 ts = *ptimer_head; 389 if (!qemu_timer_expired_ns(ts, current_time)) { 390 break; 391 } 392 /* remove timer from the list before calling the callback */ 393 *ptimer_head = ts->next; 394 ts->next = NULL; 395 396 /* run the callback (the timer list can be modified) */ 397 ts->cb(ts->opaque); 398 } 399 } 400 401 int64_t qemu_get_clock_ns(QEMUClock *clock) 402 { 403 int64_t now, last; 404 405 switch(clock->type) { 406 case QEMU_CLOCK_REALTIME: 407 return get_clock(); 408 default: 409 case QEMU_CLOCK_VIRTUAL: 410 if (use_icount) { 411 return cpu_get_icount(); 412 } else { 413 return cpu_get_clock(); 414 } 415 case QEMU_CLOCK_HOST: 416 now = get_clock_realtime(); 417 last = clock->last; 418 clock->last = now; 419 if (now < last) { 420 notifier_list_notify(&clock->reset_notifiers, &now); 421 } 422 return now; 423 } 424 } 425 426 void qemu_register_clock_reset_notifier(QEMUClock *clock, Notifier *notifier) 427 { 428 notifier_list_add(&clock->reset_notifiers, notifier); 429 } 430 431 void qemu_unregister_clock_reset_notifier(QEMUClock *clock, Notifier *notifier) 432 { 433 notifier_remove(notifier); 434 } 435 436 void init_clocks(void) 437 { 438 rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); 439 vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL); 440 host_clock = qemu_new_clock(QEMU_CLOCK_HOST); 441 } 442 443 uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts) 444 { 445 return qemu_timer_pending(ts) ? ts->expire_time : -1; 446 } 447 448 void qemu_run_all_timers(void) 449 { 450 alarm_timer->pending = false; 451 452 /* vm time timers */ 453 qemu_run_timers(vm_clock); 454 qemu_run_timers(rt_clock); 455 qemu_run_timers(host_clock); 456 457 /* rearm timer, if not periodic */ 458 if (alarm_timer->expired) { 459 alarm_timer->expired = false; 460 qemu_rearm_alarm_timer(alarm_timer); 461 } 462 } 463 464 #ifdef _WIN32 465 static void CALLBACK host_alarm_handler(PVOID lpParam, BOOLEAN unused) 466 #else 467 static void host_alarm_handler(int host_signum) 468 #endif 469 { 470 struct qemu_alarm_timer *t = alarm_timer; 471 if (!t) 472 return; 473 474 t->expired = true; 475 t->pending = true; 476 qemu_notify_event(); 477 } 478 479 #if defined(__linux__) 480 481 #include "compatfd.h" 482 483 static int dynticks_start_timer(struct qemu_alarm_timer *t) 484 { 485 struct sigevent ev; 486 timer_t host_timer; 487 struct sigaction act; 488 489 sigfillset(&act.sa_mask); 490 act.sa_flags = 0; 491 act.sa_handler = host_alarm_handler; 492 493 sigaction(SIGALRM, &act, NULL); 494 495 /* 496 * Initialize ev struct to 0 to avoid valgrind complaining 497 * about uninitialized data in timer_create call 498 */ 499 memset(&ev, 0, sizeof(ev)); 500 ev.sigev_value.sival_int = 0; 501 ev.sigev_notify = SIGEV_SIGNAL; 502 #ifdef SIGEV_THREAD_ID 503 if (qemu_signalfd_available()) { 504 ev.sigev_notify = SIGEV_THREAD_ID; 505 ev._sigev_un._tid = qemu_get_thread_id(); 506 } 507 #endif /* SIGEV_THREAD_ID */ 508 ev.sigev_signo = SIGALRM; 509 510 if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { 511 perror("timer_create"); 512 return -1; 513 } 514 515 t->timer = host_timer; 516 517 return 0; 518 } 519 520 static void dynticks_stop_timer(struct qemu_alarm_timer *t) 521 { 522 timer_t host_timer = t->timer; 523 524 timer_delete(host_timer); 525 } 526 527 static void dynticks_rearm_timer(struct qemu_alarm_timer *t, 528 int64_t nearest_delta_ns) 529 { 530 timer_t host_timer = t->timer; 531 struct itimerspec timeout; 532 int64_t current_ns; 533 534 if (nearest_delta_ns < MIN_TIMER_REARM_NS) 535 nearest_delta_ns = MIN_TIMER_REARM_NS; 536 537 /* check whether a timer is already running */ 538 if (timer_gettime(host_timer, &timeout)) { 539 perror("gettime"); 540 fprintf(stderr, "Internal timer error: aborting\n"); 541 exit(1); 542 } 543 current_ns = timeout.it_value.tv_sec * 1000000000LL + timeout.it_value.tv_nsec; 544 if (current_ns && current_ns <= nearest_delta_ns) 545 return; 546 547 timeout.it_interval.tv_sec = 0; 548 timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ 549 timeout.it_value.tv_sec = nearest_delta_ns / 1000000000; 550 timeout.it_value.tv_nsec = nearest_delta_ns % 1000000000; 551 if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { 552 perror("settime"); 553 fprintf(stderr, "Internal timer error: aborting\n"); 554 exit(1); 555 } 556 } 557 558 #endif /* defined(__linux__) */ 559 560 #if !defined(_WIN32) 561 562 static int unix_start_timer(struct qemu_alarm_timer *t) 563 { 564 struct sigaction act; 565 566 /* timer signal */ 567 sigfillset(&act.sa_mask); 568 act.sa_flags = 0; 569 act.sa_handler = host_alarm_handler; 570 571 sigaction(SIGALRM, &act, NULL); 572 return 0; 573 } 574 575 static void unix_rearm_timer(struct qemu_alarm_timer *t, 576 int64_t nearest_delta_ns) 577 { 578 struct itimerval itv; 579 int err; 580 581 if (nearest_delta_ns < MIN_TIMER_REARM_NS) 582 nearest_delta_ns = MIN_TIMER_REARM_NS; 583 584 itv.it_interval.tv_sec = 0; 585 itv.it_interval.tv_usec = 0; /* 0 for one-shot timer */ 586 itv.it_value.tv_sec = nearest_delta_ns / 1000000000; 587 itv.it_value.tv_usec = (nearest_delta_ns % 1000000000) / 1000; 588 err = setitimer(ITIMER_REAL, &itv, NULL); 589 if (err) { 590 perror("setitimer"); 591 fprintf(stderr, "Internal timer error: aborting\n"); 592 exit(1); 593 } 594 } 595 596 static void unix_stop_timer(struct qemu_alarm_timer *t) 597 { 598 struct itimerval itv; 599 600 memset(&itv, 0, sizeof(itv)); 601 setitimer(ITIMER_REAL, &itv, NULL); 602 } 603 604 #endif /* !defined(_WIN32) */ 605 606 607 #ifdef _WIN32 608 609 static MMRESULT mm_timer; 610 static TIMECAPS mm_tc; 611 612 static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg, 613 DWORD_PTR dwUser, DWORD_PTR dw1, 614 DWORD_PTR dw2) 615 { 616 struct qemu_alarm_timer *t = alarm_timer; 617 if (!t) { 618 return; 619 } 620 t->expired = true; 621 t->pending = true; 622 qemu_notify_event(); 623 } 624 625 static int mm_start_timer(struct qemu_alarm_timer *t) 626 { 627 timeGetDevCaps(&mm_tc, sizeof(mm_tc)); 628 629 timeBeginPeriod(mm_tc.wPeriodMin); 630 631 mm_timer = timeSetEvent(mm_tc.wPeriodMin, /* interval (ms) */ 632 mm_tc.wPeriodMin, /* resolution */ 633 mm_alarm_handler, /* function */ 634 (DWORD_PTR)t, /* parameter */ 635 TIME_ONESHOT | TIME_CALLBACK_FUNCTION); 636 637 if (!mm_timer) { 638 fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", 639 GetLastError()); 640 timeEndPeriod(mm_tc.wPeriodMin); 641 return -1; 642 } 643 644 return 0; 645 } 646 647 static void mm_stop_timer(struct qemu_alarm_timer *t) 648 { 649 timeKillEvent(mm_timer); 650 timeEndPeriod(mm_tc.wPeriodMin); 651 } 652 653 static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta) 654 { 655 int64_t nearest_delta_ms = delta / 1000000; 656 if (nearest_delta_ms < mm_tc.wPeriodMin) { 657 nearest_delta_ms = mm_tc.wPeriodMin; 658 } else if (nearest_delta_ms > mm_tc.wPeriodMax) { 659 nearest_delta_ms = mm_tc.wPeriodMax; 660 } 661 662 timeKillEvent(mm_timer); 663 mm_timer = timeSetEvent((UINT)nearest_delta_ms, 664 mm_tc.wPeriodMin, 665 mm_alarm_handler, 666 (DWORD_PTR)t, 667 TIME_ONESHOT | TIME_CALLBACK_FUNCTION); 668 669 if (!mm_timer) { 670 fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n", 671 GetLastError()); 672 673 timeEndPeriod(mm_tc.wPeriodMin); 674 exit(1); 675 } 676 } 677 678 static int win32_start_timer(struct qemu_alarm_timer *t) 679 { 680 HANDLE hTimer; 681 BOOLEAN success; 682 683 /* If you call ChangeTimerQueueTimer on a one-shot timer (its period 684 is zero) that has already expired, the timer is not updated. Since 685 creating a new timer is relatively expensive, set a bogus one-hour 686 interval in the dynticks case. */ 687 success = CreateTimerQueueTimer(&hTimer, 688 NULL, 689 host_alarm_handler, 690 t, 691 1, 692 3600000, 693 WT_EXECUTEINTIMERTHREAD); 694 695 if (!success) { 696 fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", 697 GetLastError()); 698 return -1; 699 } 700 701 t->timer = hTimer; 702 return 0; 703 } 704 705 static void win32_stop_timer(struct qemu_alarm_timer *t) 706 { 707 HANDLE hTimer = t->timer; 708 709 if (hTimer) { 710 DeleteTimerQueueTimer(NULL, hTimer, NULL); 711 } 712 } 713 714 static void win32_rearm_timer(struct qemu_alarm_timer *t, 715 int64_t nearest_delta_ns) 716 { 717 HANDLE hTimer = t->timer; 718 int64_t nearest_delta_ms; 719 BOOLEAN success; 720 721 nearest_delta_ms = nearest_delta_ns / 1000000; 722 if (nearest_delta_ms < 1) { 723 nearest_delta_ms = 1; 724 } 725 /* ULONG_MAX can be 32 bit */ 726 if (nearest_delta_ms > ULONG_MAX) { 727 nearest_delta_ms = ULONG_MAX; 728 } 729 success = ChangeTimerQueueTimer(NULL, 730 hTimer, 731 (unsigned long) nearest_delta_ms, 732 3600000); 733 734 if (!success) { 735 fprintf(stderr, "Failed to rearm win32 alarm timer: %ld\n", 736 GetLastError()); 737 exit(-1); 738 } 739 740 } 741 742 #endif /* _WIN32 */ 743 744 static void quit_timers(void) 745 { 746 struct qemu_alarm_timer *t = alarm_timer; 747 alarm_timer = NULL; 748 t->stop(t); 749 } 750 751 int init_timer_alarm(void) 752 { 753 struct qemu_alarm_timer *t = NULL; 754 int i, err = -1; 755 756 for (i = 0; alarm_timers[i].name; i++) { 757 t = &alarm_timers[i]; 758 759 err = t->start(t); 760 if (!err) 761 break; 762 } 763 764 if (err) { 765 err = -ENOENT; 766 goto fail; 767 } 768 769 /* first event is at time 0 */ 770 atexit(quit_timers); 771 t->pending = true; 772 alarm_timer = t; 773 774 return 0; 775 776 fail: 777 return err; 778 } 779 780