* Software (low priority) clock interrupt. * Run periodic events from timeout queue. */
| 555 | * Run periodic events from timeout queue. |
| 556 | */ |
| 557 | void |
| 558 | softclock(void *arg) |
| 559 | { |
| 560 | struct callout *c; |
| 561 | struct callout_cpu *cc; |
| 562 | struct callout_list *sc; |
| 563 | int curticks; |
| 564 | #ifdef CALLOUT_PROFILING |
| 565 | int depth = 0, gcalls = 0, mpcalls = 0, lockcalls = 0; |
| 566 | #endif |
| 567 | |
| 568 | cc = (struct callout_cpu *)arg; |
| 569 | CC_LOCK(cc); |
| 570 | |
| 571 | while (cc->cc_softticks != ticks) { |
| 572 | /* |
| 573 | * cc_softticks may be modified by hard clock, so cache |
| 574 | * it while we work on a given bucket. |
| 575 | */ |
| 576 | curticks = cc->cc_softticks; |
| 577 | cc->cc_softticks++; |
| 578 | sc = &cc->cc_callwheel[curticks & callwheelmask]; |
| 579 | c = LIST_FIRST(sc); |
| 580 | while (c) { |
| 581 | #ifdef CALLOUT_PROFILING |
| 582 | depth++; |
| 583 | #endif |
| 584 | if (c->c_time != curticks) { |
| 585 | c = LIST_NEXT(c, c_links.le); |
| 586 | } else { |
| 587 | cc_exec_next(cc) = |
| 588 | LIST_NEXT(c, c_links.le); |
| 589 | cc->cc_bucket = callout_get_bucket(curticks); |
| 590 | LIST_REMOVE(c, c_links.le); |
| 591 | softclock_call_cc(c, cc, |
| 592 | #ifdef CALLOUT_PROFILING |
| 593 | &mpcalls, &lockcalls, &gcalls, |
| 594 | #endif |
| 595 | 1); |
| 596 | c = cc_exec_next(cc); |
| 597 | cc_exec_next(cc) = NULL; |
| 598 | } |
| 599 | } |
| 600 | } |
| 601 | |
| 602 | #ifdef CALLOUT_PROFILING |
| 603 | avg_depth += (depth * 1000 - avg_depth) >> 8; |
| 604 | avg_mpcalls += (mpcalls * 1000 - avg_mpcalls) >> 8; |
| 605 | avg_lockcalls += (lockcalls * 1000 - avg_lockcalls) >> 8; |
| 606 | avg_gcalls += (gcalls * 1000 - avg_gcalls) >> 8; |
| 607 | #endif |
| 608 | CC_UNLOCK(cc); |
| 609 | } |
| 610 | |
| 611 | #if 0 |
| 612 | /* |
no test coverage detected