Duncan Coutts pushed to branch wip/io-manager-deadlock-detection at Glasgow Haskell Compiler / GHC
Commits:
-
f340f464
by Duncan Coutts at 2026-02-11T22:48:35+00:00
13 changed files:
- rts/Capability.c
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/PrimOps.cmm
- rts/RaiseAsync.c
- rts/Schedule.c
- rts/posix/Poll.c
- rts/posix/Poll.h
- rts/posix/Select.c
- rts/posix/Select.h
- rts/posix/Timeout.c
- rts/posix/Timeout.h
Changes:
| ... | ... | @@ -286,7 +286,8 @@ initCapability (Capability *cap, uint32_t i) |
| 286 | 286 | #endif
|
| 287 | 287 | cap->total_allocated = 0;
|
| 288 | 288 | |
| 289 | - initCapabilityIOManager(cap); /* initialises cap->iomgr */
|
|
| 289 | + cap->iomgr = allocCapabilityIOManager(cap);
|
|
| 290 | + initCapabilityIOManager(cap->iomgr);
|
|
| 290 | 291 | |
| 291 | 292 | cap->f.stgEagerBlackholeInfo = (W_)&__stg_EAGER_BLACKHOLE_info;
|
| 292 | 293 | cap->f.stgGCEnter1 = (StgFunPtr)__stg_gc_enter_1;
|
| ... | ... | @@ -1344,7 +1345,7 @@ markCapability (evac_fn evac, void *user, Capability *cap, |
| 1344 | 1345 | }
|
| 1345 | 1346 | #endif
|
| 1346 | 1347 | |
| 1347 | - markCapabilityIOManager(evac, user, cap);
|
|
| 1348 | + markCapabilityIOManager(evac, user, cap->iomgr);
|
|
| 1348 | 1349 | |
| 1349 | 1350 | // Free STM structures for this Capability
|
| 1350 | 1351 | stmPreGCHook(cap);
|
| ... | ... | @@ -316,22 +316,29 @@ char * showIOManager(void) |
| 316 | 316 | }
|
| 317 | 317 | }
|
| 318 | 318 | |
| 319 | +/* Allocate a CapIOManager for a given Capability. Having this helps us keep
|
|
| 320 | + * struct CapIOManager opaque from most of the rest of the RTS.
|
|
| 321 | + */
|
|
| 322 | +CapIOManager *allocCapabilityIOManager(Capability *cap)
|
|
| 323 | +{
|
|
| 324 | + CapIOManager *iomgr = stgMallocBytes(sizeof(CapIOManager),
|
|
| 325 | + "allocCapabilityIOManager");
|
|
| 326 | + iomgr->cap = cap; /* link back */
|
|
| 327 | + return iomgr;
|
|
| 328 | +}
|
|
| 329 | + |
|
| 319 | 330 | |
| 320 | -/* Allocate and initialise the per-capability CapIOManager that lives in each
|
|
| 321 | - * Capability. Called from initCapability(), which is done in the RTS startup
|
|
| 322 | - * in initCapabilities(), and later at runtime via setNumCapabilities().
|
|
| 331 | +/* Initialise the per-capability CapIOManager that lives in each Capability.
|
|
| 332 | + * Called from initCapability(), which is done in the RTS startup in
|
|
| 333 | + * initCapabilities(), and later at runtime via setNumCapabilities().
|
|
| 323 | 334 | *
|
| 324 | 335 | * Note that during RTS startup this is called _before_ the storage manager
|
| 325 | 336 | * is initialised, so this is not allowed to allocate on the GC heap.
|
| 326 | 337 | */
|
| 327 | -void initCapabilityIOManager(Capability *cap)
|
|
| 338 | +void initCapabilityIOManager(CapIOManager *iomgr)
|
|
| 328 | 339 | {
|
| 329 | 340 | debugTrace(DEBUG_iomanager, "initialising I/O manager %s for cap %d",
|
| 330 | - showIOManager(), cap->no);
|
|
| 331 | - |
|
| 332 | - CapIOManager *iomgr =
|
|
| 333 | - (CapIOManager *) stgMallocBytes(sizeof(CapIOManager),
|
|
| 334 | - "initCapabilityIOManager");
|
|
| 341 | + showIOManager(), iomgr->cap->no);
|
|
| 335 | 342 | |
| 336 | 343 | switch (iomgr_type) {
|
| 337 | 344 | #if defined(IOMGR_ENABLED_SELECT)
|
| ... | ... | @@ -363,8 +370,6 @@ void initCapabilityIOManager(Capability *cap) |
| 363 | 370 | default:
|
| 364 | 371 | break;
|
| 365 | 372 | }
|
| 366 | - |
|
| 367 | - cap->iomgr = iomgr;
|
|
| 368 | 373 | }
|
| 369 | 374 | |
| 370 | 375 | |
| ... | ... | @@ -436,7 +441,7 @@ void initIOManager(void) |
| 436 | 441 | /* Called from forkProcess in the child process on the surviving capability.
|
| 437 | 442 | */
|
| 438 | 443 | void
|
| 439 | -initIOManagerAfterFork(Capability **pcap)
|
|
| 444 | +initIOManagerAfterFork(CapIOManager *iomgr, Capability **pcap)
|
|
| 440 | 445 | {
|
| 441 | 446 | |
| 442 | 447 | switch (iomgr_type) {
|
| ... | ... | @@ -467,7 +472,7 @@ initIOManagerAfterFork(Capability **pcap) |
| 467 | 472 | |
| 468 | 473 | /* Called from setNumCapabilities.
|
| 469 | 474 | */
|
| 470 | -void notifyIOManagerCapabilitiesChanged(Capability **pcap)
|
|
| 475 | +void notifyIOManagerCapabilitiesChanged(CapIOManager *iomgr, Capability **pcap)
|
|
| 471 | 476 | {
|
| 472 | 477 | switch (iomgr_type) {
|
| 473 | 478 | #if defined(IOMGR_ENABLED_MIO_POSIX)
|
| ... | ... | @@ -572,38 +577,29 @@ void wakeupIOManager(void) |
| 572 | 577 | }
|
| 573 | 578 | }
|
| 574 | 579 | |
| 575 | -void markCapabilityIOManager(evac_fn evac, void *user, Capability *cap)
|
|
| 580 | +void markCapabilityIOManager(evac_fn evac, void *user, CapIOManager *iomgr)
|
|
| 576 | 581 | {
|
| 577 | 582 | switch (iomgr_type) {
|
| 578 | 583 | #if defined(IOMGR_ENABLED_SELECT)
|
| 579 | 584 | case IO_MANAGER_SELECT:
|
| 580 | - {
|
|
| 581 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 582 | 585 | evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_hd);
|
| 583 | 586 | evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_tl);
|
| 584 | 587 | evac(user, (StgClosure **)(void *)&iomgr->sleeping_queue);
|
| 585 | 588 | break;
|
| 586 | - }
|
|
| 587 | 589 | #endif
|
| 588 | 590 | |
| 589 | 591 | #if defined(IOMGR_ENABLED_POLL)
|
| 590 | 592 | case IO_MANAGER_POLL:
|
| 591 | - {
|
|
| 592 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 593 | 593 | markClosureTable(evac, user, &iomgr->aiop_table);
|
| 594 | 594 | evac(user, (StgClosure **)(void *)&iomgr->timeout_queue);
|
| 595 | 595 | break;
|
| 596 | - }
|
|
| 597 | 596 | #endif
|
| 598 | 597 | |
| 599 | 598 | #if defined(IOMGR_ENABLED_WIN32_LEGACY)
|
| 600 | 599 | case IO_MANAGER_WIN32_LEGACY:
|
| 601 | - {
|
|
| 602 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 603 | 600 | evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_hd);
|
| 604 | 601 | evac(user, (StgClosure **)(void *)&iomgr->blocked_queue_tl);
|
| 605 | 602 | break;
|
| 606 | - }
|
|
| 607 | 603 | #endif
|
| 608 | 604 | default:
|
| 609 | 605 | break;
|
| ... | ... | @@ -665,29 +661,23 @@ setIOManagerControlFd(uint32_t cap_no, int fd) { |
| 665 | 661 | #endif
|
| 666 | 662 | |
| 667 | 663 | |
| 668 | -bool anyPendingTimeoutsOrIO(Capability *cap)
|
|
| 664 | +bool anyPendingTimeoutsOrIO(CapIOManager *iomgr)
|
|
| 669 | 665 | {
|
| 670 | 666 | switch (iomgr_type) {
|
| 671 | 667 | #if defined(IOMGR_ENABLED_SELECT)
|
| 672 | 668 | case IO_MANAGER_SELECT:
|
| 673 | - {
|
|
| 674 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 675 | 669 | return (iomgr->blocked_queue_hd != END_TSO_QUEUE)
|
| 676 | 670 | || (iomgr->sleeping_queue != END_TSO_QUEUE);
|
| 677 | - }
|
|
| 678 | 671 | #endif
|
| 679 | 672 | |
| 680 | 673 | #if defined(IOMGR_ENABLED_POLL)
|
| 681 | 674 | case IO_MANAGER_POLL:
|
| 682 | - return anyPendingTimeoutsOrIOPoll(cap->iomgr);
|
|
| 675 | + return anyPendingTimeoutsOrIOPoll(iomgr);
|
|
| 683 | 676 | #endif
|
| 684 | 677 | |
| 685 | 678 | #if defined(IOMGR_ENABLED_WIN32_LEGACY)
|
| 686 | 679 | case IO_MANAGER_WIN32_LEGACY:
|
| 687 | - {
|
|
| 688 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 689 | 680 | return (iomgr->blocked_queue_hd != END_TSO_QUEUE);
|
| 690 | - }
|
|
| 691 | 681 | #endif
|
| 692 | 682 | |
| 693 | 683 | /* For the purpose of the scheduler, the threaded I/O managers never have
|
| ... | ... | @@ -729,19 +719,19 @@ bool anyPendingTimeoutsOrIO(Capability *cap) |
| 729 | 719 | }
|
| 730 | 720 | |
| 731 | 721 | |
| 732 | -void pollCompletedTimeoutsOrIO(Capability *cap)
|
|
| 722 | +void pollCompletedTimeoutsOrIO(CapIOManager *iomgr)
|
|
| 733 | 723 | {
|
| 734 | 724 | debugTrace(DEBUG_iomanager, "polling for completed IO or timeouts");
|
| 735 | 725 | switch (iomgr_type) {
|
| 736 | 726 | #if defined(IOMGR_ENABLED_SELECT)
|
| 737 | 727 | case IO_MANAGER_SELECT:
|
| 738 | - awaitCompletedTimeoutsOrIOSelect(cap, false);
|
|
| 728 | + awaitCompletedTimeoutsOrIOSelect(iomgr, false);
|
|
| 739 | 729 | break;
|
| 740 | 730 | #endif
|
| 741 | 731 | |
| 742 | 732 | #if defined(IOMGR_ENABLED_POLL)
|
| 743 | 733 | case IO_MANAGER_POLL:
|
| 744 | - pollCompletedTimeoutsOrIOPoll(cap);
|
|
| 734 | + pollCompletedTimeoutsOrIOPoll(iomgr);
|
|
| 745 | 735 | break;
|
| 746 | 736 | #endif
|
| 747 | 737 | |
| ... | ... | @@ -753,7 +743,7 @@ void pollCompletedTimeoutsOrIO(Capability *cap) |
| 753 | 743 | #if defined(IOMGR_ENABLED_WINIO)
|
| 754 | 744 | case IO_MANAGER_WINIO:
|
| 755 | 745 | #endif
|
| 756 | - awaitCompletedTimeoutsOrIOWin32(cap, false);
|
|
| 746 | + awaitCompletedTimeoutsOrIOWin32(iomgr->cap, false);
|
|
| 757 | 747 | break;
|
| 758 | 748 | #endif
|
| 759 | 749 | default:
|
| ... | ... | @@ -762,19 +752,19 @@ void pollCompletedTimeoutsOrIO(Capability *cap) |
| 762 | 752 | }
|
| 763 | 753 | |
| 764 | 754 | |
| 765 | -void awaitCompletedTimeoutsOrIO(Capability *cap)
|
|
| 755 | +void awaitCompletedTimeoutsOrIO(CapIOManager *iomgr)
|
|
| 766 | 756 | {
|
| 767 | 757 | debugTrace(DEBUG_iomanager, "waiting for completed IO or timeouts");
|
| 768 | 758 | switch (iomgr_type) {
|
| 769 | 759 | #if defined(IOMGR_ENABLED_SELECT)
|
| 770 | 760 | case IO_MANAGER_SELECT:
|
| 771 | - awaitCompletedTimeoutsOrIOSelect(cap, true);
|
|
| 761 | + awaitCompletedTimeoutsOrIOSelect(iomgr, true);
|
|
| 772 | 762 | break;
|
| 773 | 763 | #endif
|
| 774 | 764 | |
| 775 | 765 | #if defined(IOMGR_ENABLED_POLL)
|
| 776 | 766 | case IO_MANAGER_POLL:
|
| 777 | - awaitCompletedTimeoutsOrIOPoll(cap);
|
|
| 767 | + awaitCompletedTimeoutsOrIOPoll(iomgr);
|
|
| 778 | 768 | break;
|
| 779 | 769 | #endif
|
| 780 | 770 | |
| ... | ... | @@ -786,17 +776,18 @@ void awaitCompletedTimeoutsOrIO(Capability *cap) |
| 786 | 776 | #if defined(IOMGR_ENABLED_WINIO)
|
| 787 | 777 | case IO_MANAGER_WINIO:
|
| 788 | 778 | #endif
|
| 789 | - awaitCompletedTimeoutsOrIOWin32(cap, true);
|
|
| 779 | + awaitCompletedTimeoutsOrIOWin32(iomgr->cap, true);
|
|
| 790 | 780 | break;
|
| 791 | 781 | #endif
|
| 792 | 782 | default:
|
| 793 | 783 | barf("pollCompletedTimeoutsOrIO not implemented");
|
| 794 | 784 | }
|
| 795 | - ASSERT(!emptyRunQueue(cap) || getSchedState() != SCHED_RUNNING);
|
|
| 785 | + ASSERT(!emptyRunQueue(iomgr->cap) || getSchedState() != SCHED_RUNNING);
|
|
| 796 | 786 | }
|
| 797 | 787 | |
| 798 | 788 | |
| 799 | -bool syncIOWaitReady(Capability *cap,
|
|
| 789 | +/* CMM primop. Result is true on success, or false on allocation failure. */
|
|
| 790 | +bool syncIOWaitReady(CapIOManager *iomgr,
|
|
| 800 | 791 | StgTSO *tso,
|
| 801 | 792 | IOReadOrWrite rw,
|
| 802 | 793 | HsInt fd)
|
| ... | ... | @@ -812,14 +803,14 @@ bool syncIOWaitReady(Capability *cap, |
| 812 | 803 | StgWord why_blocked = rw == IORead ? BlockedOnRead : BlockedOnWrite;
|
| 813 | 804 | tso->block_info.fd = fd;
|
| 814 | 805 | RELEASE_STORE(&tso->why_blocked, why_blocked);
|
| 815 | - appendToIOBlockedQueue(cap, tso);
|
|
| 806 | + appendToIOBlockedQueue(iomgr, tso);
|
|
| 816 | 807 | return true;
|
| 817 | 808 | }
|
| 818 | 809 | #endif
|
| 819 | 810 | #if defined(IOMGR_ENABLED_POLL)
|
| 820 | 811 | case IO_MANAGER_POLL:
|
| 821 | 812 | ASSERT(tso->why_blocked == NotBlocked);
|
| 822 | - return syncIOWaitReadyPoll(cap, tso, rw, fd);
|
|
| 813 | + return syncIOWaitReadyPoll(iomgr, tso, rw, fd);
|
|
| 823 | 814 | #endif
|
| 824 | 815 | default:
|
| 825 | 816 | barf("waitRead# / waitWrite# not available for current I/O manager");
|
| ... | ... | @@ -827,25 +818,29 @@ bool syncIOWaitReady(Capability *cap, |
| 827 | 818 | }
|
| 828 | 819 | |
| 829 | 820 | |
| 830 | -void syncIOCancel(Capability *cap, StgTSO *tso)
|
|
| 821 | +void syncIOCancel(CapIOManager *iomgr, StgTSO *tso)
|
|
| 831 | 822 | {
|
| 832 | 823 | debugTrace(DEBUG_iomanager, "cancelling I/O for thread %ld", (long) tso->id);
|
| 833 | 824 | switch (iomgr_type) {
|
| 834 | 825 | #if defined(IOMGR_ENABLED_SELECT)
|
| 835 | 826 | case IO_MANAGER_SELECT:
|
| 836 | - removeThreadFromDeQueue(cap, &cap->iomgr->blocked_queue_hd,
|
|
| 837 | - &cap->iomgr->blocked_queue_tl, tso);
|
|
| 827 | + removeThreadFromDeQueue(iomgr->cap,
|
|
| 828 | + &iomgr->blocked_queue_hd,
|
|
| 829 | + &iomgr->blocked_queue_tl,
|
|
| 830 | + tso);
|
|
| 838 | 831 | break;
|
| 839 | 832 | #endif
|
| 840 | 833 | #if defined(IOMGR_ENABLED_POLL)
|
| 841 | 834 | case IO_MANAGER_POLL:
|
| 842 | - syncIOCancelPoll(cap, tso);
|
|
| 835 | + syncIOCancelPoll(iomgr, tso);
|
|
| 843 | 836 | break;
|
| 844 | 837 | #endif
|
| 845 | 838 | #if defined(IOMGR_ENABLED_WIN32_LEGACY)
|
| 846 | 839 | case IO_MANAGER_WIN32_LEGACY:
|
| 847 | - removeThreadFromDeQueue(cap, &cap->iomgr->blocked_queue_hd,
|
|
| 848 | - &cap->iomgr->blocked_queue_tl, tso);
|
|
| 840 | + removeThreadFromDeQueue(iomgr->cap,
|
|
| 841 | + &iomgr->blocked_queue_hd,
|
|
| 842 | + &iomgr->blocked_queue_tl,
|
|
| 843 | + tso);
|
|
| 849 | 844 | abandonWorkRequest(tso->block_info.async_result->reqID);
|
| 850 | 845 | break;
|
| 851 | 846 | #endif
|
| ... | ... | @@ -856,11 +851,12 @@ void syncIOCancel(Capability *cap, StgTSO *tso) |
| 856 | 851 | |
| 857 | 852 | |
| 858 | 853 | #if defined(IOMGR_ENABLED_SELECT)
|
| 859 | -static void insertIntoSleepingQueue(Capability *cap, StgTSO *tso, LowResTime target);
|
|
| 854 | +static void insertIntoSleepingQueue(CapIOManager *iomgr, StgTSO *tso, LowResTime target);
|
|
| 860 | 855 | #endif
|
| 861 | 856 | |
| 862 | 857 | |
| 863 | -bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay)
|
|
| 858 | +/* CMM primop. Result is true on success, or false on allocation failure. */
|
|
| 859 | +bool syncDelay(CapIOManager *iomgr, StgTSO *tso, HsInt us_delay)
|
|
| 864 | 860 | {
|
| 865 | 861 | debugTrace(DEBUG_iomanager, "thread %ld waiting for %lld us", tso->id, us_delay);
|
| 866 | 862 | ASSERT(tso->why_blocked == NotBlocked);
|
| ... | ... | @@ -871,13 +867,13 @@ bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay) |
| 871 | 867 | LowResTime target = getDelayTarget(us_delay);
|
| 872 | 868 | tso->block_info.target = target;
|
| 873 | 869 | RELEASE_STORE(&tso->why_blocked, BlockedOnDelay);
|
| 874 | - insertIntoSleepingQueue(cap, tso, target);
|
|
| 870 | + insertIntoSleepingQueue(iomgr, tso, target);
|
|
| 875 | 871 | return true;
|
| 876 | 872 | }
|
| 877 | 873 | #endif
|
| 878 | 874 | #if defined(IOMGR_ENABLED_POLL)
|
| 879 | 875 | case IO_MANAGER_POLL:
|
| 880 | - return syncDelayTimeout(cap, tso, us_delay);
|
|
| 876 | + return syncDelayTimeout(iomgr, tso, us_delay);
|
|
| 881 | 877 | #endif
|
| 882 | 878 | #if defined(IOMGR_ENABLED_WIN32_LEGACY)
|
| 883 | 879 | case IO_MANAGER_WIN32_LEGACY:
|
| ... | ... | @@ -897,7 +893,7 @@ bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay) |
| 897 | 893 | * delayed thread on the blocked_queue.
|
| 898 | 894 | */
|
| 899 | 895 | RELEASE_STORE(&tso->why_blocked, BlockedOnDoProc);
|
| 900 | - appendToIOBlockedQueue(cap, tso);
|
|
| 896 | + appendToIOBlockedQueue(iomgr, tso);
|
|
| 901 | 897 | return true;
|
| 902 | 898 | }
|
| 903 | 899 | #endif
|
| ... | ... | @@ -907,18 +903,18 @@ bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay) |
| 907 | 903 | }
|
| 908 | 904 | |
| 909 | 905 | |
| 910 | -void syncDelayCancel(Capability *cap, StgTSO *tso)
|
|
| 906 | +void syncDelayCancel(CapIOManager *iomgr, StgTSO *tso)
|
|
| 911 | 907 | {
|
| 912 | 908 | debugTrace(DEBUG_iomanager, "cancelling delay for thread %ld", (long) tso->id);
|
| 913 | 909 | switch (iomgr_type) {
|
| 914 | 910 | #if defined(IOMGR_ENABLED_SELECT)
|
| 915 | 911 | case IO_MANAGER_SELECT:
|
| 916 | - removeThreadFromQueue(cap, &cap->iomgr->sleeping_queue, tso);
|
|
| 912 | + removeThreadFromQueue(iomgr->cap, &iomgr->sleeping_queue, tso);
|
|
| 917 | 913 | break;
|
| 918 | 914 | #endif
|
| 919 | 915 | #if defined(IOMGR_ENABLED_POLL)
|
| 920 | 916 | case IO_MANAGER_POLL:
|
| 921 | - syncDelayCancelTimeout(cap, tso);
|
|
| 917 | + syncDelayCancelTimeout(iomgr, tso);
|
|
| 922 | 918 | break;
|
| 923 | 919 | #endif
|
| 924 | 920 | /* Note: no case for IO_MANAGER_WIN32_LEGACY despite it having a case
|
| ... | ... | @@ -935,14 +931,13 @@ void syncDelayCancel(Capability *cap, StgTSO *tso) |
| 935 | 931 | |
| 936 | 932 | |
| 937 | 933 | #if defined(IOMGR_ENABLED_SELECT) || defined(IOMGR_ENABLED_WIN32_LEGACY)
|
| 938 | -void appendToIOBlockedQueue(Capability *cap, StgTSO *tso)
|
|
| 934 | +void appendToIOBlockedQueue(CapIOManager *iomgr, StgTSO *tso)
|
|
| 939 | 935 | {
|
| 940 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 941 | 936 | ASSERT(tso->_link == END_TSO_QUEUE);
|
| 942 | 937 | if (iomgr->blocked_queue_hd == END_TSO_QUEUE) {
|
| 943 | 938 | iomgr->blocked_queue_hd = tso;
|
| 944 | 939 | } else {
|
| 945 | - setTSOLink(cap, iomgr->blocked_queue_tl, tso);
|
|
| 940 | + setTSOLink(iomgr->cap, iomgr->blocked_queue_tl, tso);
|
|
| 946 | 941 | }
|
| 947 | 942 | iomgr->blocked_queue_tl = tso;
|
| 948 | 943 | }
|
| ... | ... | @@ -957,9 +952,8 @@ void appendToIOBlockedQueue(Capability *cap, StgTSO *tso) |
| 957 | 952 | * used. This is a wart that should be excised.
|
| 958 | 953 | */
|
| 959 | 954 | // TODO: move to Select.c and rename
|
| 960 | -static void insertIntoSleepingQueue(Capability *cap, StgTSO *tso, LowResTime target)
|
|
| 955 | +static void insertIntoSleepingQueue(CapIOManager *iomgr, StgTSO *tso, LowResTime target)
|
|
| 961 | 956 | {
|
| 962 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 963 | 957 | StgTSO *prev = NULL;
|
| 964 | 958 | StgTSO *t = iomgr->sleeping_queue;
|
| 965 | 959 | while (t != END_TSO_QUEUE && t->block_info.target < target) {
|
| ... | ... | @@ -971,7 +965,7 @@ static void insertIntoSleepingQueue(Capability *cap, StgTSO *tso, LowResTime tar |
| 971 | 965 | if (prev == NULL) {
|
| 972 | 966 | iomgr->sleeping_queue = tso;
|
| 973 | 967 | } else {
|
| 974 | - setTSOLink(cap, prev, tso);
|
|
| 968 | + setTSOLink(iomgr->cap, prev, tso);
|
|
| 975 | 969 | }
|
| 976 | 970 | }
|
| 977 | 971 | #endif
|
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | |
| 20 | 20 | #pragma once
|
| 21 | 21 | |
| 22 | +#include "Capability.h"
|
|
| 22 | 23 | #include "sm/GC.h" // for evac_fn
|
| 23 | 24 | |
| 24 | 25 | #include "BeginPrivate.h"
|
| ... | ... | @@ -227,11 +228,19 @@ enum IOOpOutcome { |
| 227 | 228 | void selectIOManager(void);
|
| 228 | 229 | |
| 229 | 230 | |
| 230 | -/* Allocate and initialise the per-capability CapIOManager that lives in each
|
|
| 231 | - * Capability. Called from initCapability(), which is done in the RTS startup
|
|
| 232 | - * in initCapabilities(), and later at runtime via setNumCapabilities().
|
|
| 231 | +/* Allocate a CapIOManager for a given Capability. Having this helps us keep
|
|
| 232 | + * struct CapIOManager opaque from most of the rest of the RTS.
|
|
| 233 | 233 | */
|
| 234 | -void initCapabilityIOManager(Capability *cap);
|
|
| 234 | +CapIOManager *allocCapabilityIOManager(Capability *cap);
|
|
| 235 | + |
|
| 236 | +/* Initialise the per-capability CapIOManager that lives in each Capability.
|
|
| 237 | + * Called from initCapability(), which is done in the RTS startup in
|
|
| 238 | + * initCapabilities(), and later at runtime via setNumCapabilities().
|
|
| 239 | + *
|
|
| 240 | + * This is separate from allocCapabilityIOManager so that we can re-initialise
|
|
| 241 | + * I/O managers after forkProcess.
|
|
| 242 | + */
|
|
| 243 | +void initCapabilityIOManager(CapIOManager *iomgr);
|
|
| 235 | 244 | |
| 236 | 245 | |
| 237 | 246 | /* Init hook: called from hs_init_ghc, very late in the startup after almost
|
| ... | ... | @@ -243,10 +252,11 @@ void initIOManager(void); |
| 243 | 252 | /* Init hook: called from forkProcess in the child process on the surviving
|
| 244 | 253 | * capability.
|
| 245 | 254 | *
|
| 246 | - * Note that this is synchronous and can run Haskell code, so can change the
|
|
| 247 | - * given cap.
|
|
| 255 | + * This is synchronous and can run Haskell code, so can change the given cap.
|
|
| 256 | + * TODO: it would make for a cleaner API here if this were made asynchronous.
|
|
| 248 | 257 | */
|
| 249 | -void initIOManagerAfterFork(/* inout */ Capability **pcap);
|
|
| 258 | +void initIOManagerAfterFork(CapIOManager *iomgr,
|
|
| 259 | + /* inout */ Capability **pcap);
|
|
| 250 | 260 | |
| 251 | 261 | /* TODO: rationalise initIOManager and initIOManagerAfterFork into a single
|
| 252 | 262 | per-capability init function.
|
| ... | ... | @@ -254,8 +264,12 @@ void initIOManagerAfterFork(/* inout */ Capability **pcap); |
| 254 | 264 | |
| 255 | 265 | |
| 256 | 266 | /* Called from setNumCapabilities.
|
| 267 | + *
|
|
| 268 | + * This is synchronous and can run Haskell code, so can change the given cap.
|
|
| 269 | + * TODO: it would make for a cleaner API here if this were made asynchronous.
|
|
| 257 | 270 | */
|
| 258 | -void notifyIOManagerCapabilitiesChanged(Capability **pcap);
|
|
| 271 | +void notifyIOManagerCapabilitiesChanged(CapIOManager *iomgr,
|
|
| 272 | + /* inout */ Capability **pcap);
|
|
| 259 | 273 | |
| 260 | 274 | |
| 261 | 275 | /* Shutdown hooks: called from hs_exit_ before and after the scheduler exits.
|
| ... | ... | @@ -288,7 +302,7 @@ void wakeupIOManager(void); |
| 288 | 302 | |
| 289 | 303 | /* GC hook: mark any per-capability GC roots the I/O manager uses.
|
| 290 | 304 | */
|
| 291 | -void markCapabilityIOManager(evac_fn evac, void *user, Capability *cap);
|
|
| 305 | +void markCapabilityIOManager(evac_fn evac, void *user, CapIOManager *iomgr);
|
|
| 292 | 306 | |
| 293 | 307 | |
| 294 | 308 | /* GC hook: scavenge I/O related tso->block_info. Used by scavengeTSO.
|
| ... | ... | @@ -305,21 +319,20 @@ typedef enum { IORead, IOWrite } IOReadOrWrite; |
| 305 | 319 | * necessarily operate on threads. The thread is suspended until the operation
|
| 306 | 320 | * completes.
|
| 307 | 321 | *
|
| 308 | - * These are called from CMM primops. The ones returing int can perform heap
|
|
| 309 | - * allocation, which might fail. They return 0 on success, or n > 0 on heap
|
|
| 310 | - * allocation failure, needing n words. The CMM primops should invoke the
|
|
| 311 | - * GC to free up at least n words and then retry the operation.
|
|
| 322 | + * Some of these are called from CMM primops. The primops returing bool can
|
|
| 323 | + * perform heap allocation, which might fail. They return true on success, or
|
|
| 324 | + * false on heap allocation failure.
|
|
| 312 | 325 | */
|
| 313 | 326 | |
| 314 | -/* Result is true on success, or false on allocation failure. */
|
|
| 315 | -bool syncIOWaitReady(Capability *cap, StgTSO *tso, IOReadOrWrite rw, HsInt fd);
|
|
| 327 | +/* Called from CMM primop */
|
|
| 328 | +bool syncIOWaitReady(CapIOManager *iomgr, StgTSO *tso, IOReadOrWrite rw, HsInt fd);
|
|
| 316 | 329 | |
| 317 | -void syncIOCancel(Capability *cap, StgTSO *tso);
|
|
| 330 | +void syncIOCancel(CapIOManager *iomgr, StgTSO *tso);
|
|
| 318 | 331 | |
| 319 | -/* Result is true on success, or false on allocation failure. */
|
|
| 320 | -bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay);
|
|
| 332 | +/* Called from CMM primop */
|
|
| 333 | +bool syncDelay(CapIOManager *iomgr, StgTSO *tso, HsInt us_delay);
|
|
| 321 | 334 | |
| 322 | -void syncDelayCancel(Capability *cap, StgTSO *tso);
|
|
| 335 | +void syncDelayCancel(CapIOManager *iomgr, StgTSO *tso);
|
|
| 323 | 336 | |
| 324 | 337 | #if defined(IOMGR_ENABLED_SELECT) || defined(IOMGR_ENABLED_WIN32_LEGACY)
|
| 325 | 338 | /* Add a thread to the end of the queue of threads blocked on I/O.
|
| ... | ... | @@ -327,7 +340,7 @@ void syncDelayCancel(Capability *cap, StgTSO *tso); |
| 327 | 340 | * This is used by the select() and the Windows MIO non-threaded I/O manager
|
| 328 | 341 | * implementation. Called from CMM code.
|
| 329 | 342 | */
|
| 330 | -void appendToIOBlockedQueue(Capability *cap, StgTSO *tso);
|
|
| 343 | +void appendToIOBlockedQueue(CapIOManager *iomgr, StgTSO *tso);
|
|
| 331 | 344 | #endif
|
| 332 | 345 | |
| 333 | 346 | /* Check to see if there are any pending timeouts or I/O operations
|
| ... | ... | @@ -336,7 +349,7 @@ void appendToIOBlockedQueue(Capability *cap, StgTSO *tso); |
| 336 | 349 | * This is used by the scheduler as part of deadlock-detection, and the
|
| 337 | 350 | * "context switch as often as possible" test.
|
| 338 | 351 | */
|
| 339 | -bool anyPendingTimeoutsOrIO(Capability *cap);
|
|
| 352 | +bool anyPendingTimeoutsOrIO(CapIOManager *iomgr);
|
|
| 340 | 353 | |
| 341 | 354 | /* If there are any completed I/O operations or expired timers, process the
|
| 342 | 355 | * completions as appropriate (which will typically unblock some waiting
|
| ... | ... | @@ -344,7 +357,7 @@ bool anyPendingTimeoutsOrIO(Capability *cap); |
| 344 | 357 | *
|
| 345 | 358 | * Called from schedule() both *before* and *after* scheduleDetectDeadlock().
|
| 346 | 359 | */
|
| 347 | -void pollCompletedTimeoutsOrIO(Capability *cap);
|
|
| 360 | +void pollCompletedTimeoutsOrIO(CapIOManager *iomgr);
|
|
| 348 | 361 | |
| 349 | 362 | /* If there are any completed I/O operations or expired timers, process the
|
| 350 | 363 | * completions as appropriate. If there are none, wait until I/O or a timer
|
| ... | ... | @@ -360,6 +373,6 @@ void pollCompletedTimeoutsOrIO(Capability *cap); |
| 360 | 373 | *
|
| 361 | 374 | * Called from schedule() both *before* and *after* scheduleDetectDeadlock().
|
| 362 | 375 | */
|
| 363 | -void awaitCompletedTimeoutsOrIO(Capability *cap);
|
|
| 376 | +void awaitCompletedTimeoutsOrIO(CapIOManager *iomgr);
|
|
| 364 | 377 | |
| 365 | 378 | #include "EndPrivate.h" |
| ... | ... | @@ -24,7 +24,8 @@ |
| 24 | 24 | |
| 25 | 25 | /* The per-capability data structures belonging to the I/O manager.
|
| 26 | 26 | *
|
| 27 | - * It can be accessed as cap->iomgr.
|
|
| 27 | + * It can be accessed as cap->iomgr. Or given just the iomgr, you can access
|
|
| 28 | + * the owning cap as iomgr->cap.
|
|
| 28 | 29 | *
|
| 29 | 30 | * The content of the structure is defined conditionally so it is different for
|
| 30 | 31 | * each I/O manager implementation.
|
| ... | ... | @@ -33,6 +34,9 @@ |
| 33 | 34 | */
|
| 34 | 35 | struct _CapIOManager {
|
| 35 | 36 | |
| 37 | + /* Back reference to the containing capability */
|
|
| 38 | + Capability *cap;
|
|
| 39 | + |
|
| 36 | 40 | #if defined(IOMGR_ENABLED_SELECT)
|
| 37 | 41 | /* Thread queue for threads blocked on I/O completion. */
|
| 38 | 42 | StgTSO *blocked_queue_hd;
|
| ... | ... | @@ -2279,7 +2279,8 @@ stg_waitReadzh ( W_ fd ) |
| 2279 | 2279 | {
|
| 2280 | 2280 | CBool ok; /* Ok, or heap alloc failure. */
|
| 2281 | 2281 | |
| 2282 | - (ok) = ccall syncIOWaitReady(MyCapability() "ptr", CurrentTSO "ptr",
|
|
| 2282 | + (ok) = ccall syncIOWaitReady(Capability_iomgr(MyCapability()) "ptr",
|
|
| 2283 | + CurrentTSO "ptr",
|
|
| 2283 | 2284 | /* IORead */ 0::I32, fd);
|
| 2284 | 2285 | if (ok != 0::CBool) (likely: True) {
|
| 2285 | 2286 | jump stg_block_noregs();
|
| ... | ... | @@ -2292,7 +2293,8 @@ stg_waitWritezh ( W_ fd ) |
| 2292 | 2293 | {
|
| 2293 | 2294 | CBool ok; /* Ok, or heap alloc failure. */
|
| 2294 | 2295 | |
| 2295 | - (ok) = ccall syncIOWaitReady(MyCapability() "ptr", CurrentTSO "ptr",
|
|
| 2296 | + (ok) = ccall syncIOWaitReady(Capability_iomgr(MyCapability()) "ptr",
|
|
| 2297 | + CurrentTSO "ptr",
|
|
| 2296 | 2298 | /* IOWrite */ 1::I32, fd);
|
| 2297 | 2299 | if (ok != 0::CBool) (likely: True) {
|
| 2298 | 2300 | jump stg_block_noregs();
|
| ... | ... | @@ -2305,7 +2307,8 @@ stg_delayzh ( W_ us_delay ) |
| 2305 | 2307 | {
|
| 2306 | 2308 | CBool ok; /* Ok, or heap alloc failure. */
|
| 2307 | 2309 | |
| 2308 | - (ok) = ccall syncDelay(MyCapability() "ptr", CurrentTSO "ptr", us_delay);
|
|
| 2310 | + (ok) = ccall syncDelay(Capability_iomgr(MyCapability()) "ptr",
|
|
| 2311 | + CurrentTSO "ptr", us_delay);
|
|
| 2309 | 2312 | |
| 2310 | 2313 | if (ok != 0::CBool) (likely: True) {
|
| 2311 | 2314 | /* Annoyingly, we cannot be consistent with how we wait and resume the
|
| ... | ... | @@ -708,12 +708,12 @@ removeFromQueues(Capability *cap, StgTSO *tso) |
| 708 | 708 | case BlockedOnWrite:
|
| 709 | 709 | case BlockedOnDoProc:
|
| 710 | 710 | // These blocking reasons are only used by some I/O managers
|
| 711 | - syncIOCancel(cap, tso);
|
|
| 711 | + syncIOCancel(cap->iomgr, tso);
|
|
| 712 | 712 | goto done;
|
| 713 | 713 | |
| 714 | 714 | case BlockedOnDelay:
|
| 715 | 715 | // This blocking reasons is only used by some I/O managers
|
| 716 | - syncDelayCancel(cap, tso);
|
|
| 716 | + syncDelayCancel(cap->iomgr, tso);
|
|
| 717 | 717 | goto done;
|
| 718 | 718 | |
| 719 | 719 | default:
|
| ... | ... | @@ -409,7 +409,7 @@ schedule (Capability *initialCapability, Task *task) |
| 409 | 409 | */
|
| 410 | 410 | if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0 &&
|
| 411 | 411 | (!emptyRunQueue(cap) ||
|
| 412 | - anyPendingTimeoutsOrIO(cap))) {
|
|
| 412 | + anyPendingTimeoutsOrIO(cap->iomgr))) {
|
|
| 413 | 413 | RELAXED_STORE(&cap->context_switch, 1);
|
| 414 | 414 | }
|
| 415 | 415 | |
| ... | ... | @@ -923,14 +923,14 @@ scheduleCheckBlockedThreads(Capability *cap USED_IF_NOT_THREADS) |
| 923 | 923 | * awaitCompletedTimeoutsOrIO below for the case of !defined(THREADED_RTS)
|
| 924 | 924 | * && defined(mingw32_HOST_OS).
|
| 925 | 925 | */
|
| 926 | - if (anyPendingTimeoutsOrIO(cap))
|
|
| 926 | + if (anyPendingTimeoutsOrIO(cap->iomgr))
|
|
| 927 | 927 | {
|
| 928 | 928 | if (emptyRunQueue(cap)) {
|
| 929 | 929 | // block and wait
|
| 930 | - awaitCompletedTimeoutsOrIO(cap);
|
|
| 930 | + awaitCompletedTimeoutsOrIO(cap->iomgr);
|
|
| 931 | 931 | } else {
|
| 932 | 932 | // poll but do not wait
|
| 933 | - pollCompletedTimeoutsOrIO(cap);
|
|
| 933 | + pollCompletedTimeoutsOrIO(cap->iomgr);
|
|
| 934 | 934 | }
|
| 935 | 935 | }
|
| 936 | 936 | #endif
|
| ... | ... | @@ -950,7 +950,7 @@ scheduleDetectDeadlock (Capability **pcap, Task *task) |
| 950 | 950 | * other tasks are waiting for work, we must have a deadlock of
|
| 951 | 951 | * some description.
|
| 952 | 952 | */
|
| 953 | - if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap) )
|
|
| 953 | + if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap->iomgr) )
|
|
| 954 | 954 | {
|
| 955 | 955 | #if defined(THREADED_RTS)
|
| 956 | 956 | /*
|
| ... | ... | @@ -2232,7 +2232,7 @@ forkProcess(HsStablePtr *entry |
| 2232 | 2232 | // like startup event, capabilities, process info etc
|
| 2233 | 2233 | traceTaskCreate(task, cap);
|
| 2234 | 2234 | |
| 2235 | - initIOManagerAfterFork(&cap);
|
|
| 2235 | + initIOManagerAfterFork(cap->iomgr, &cap);
|
|
| 2236 | 2236 | |
| 2237 | 2237 | // start timer after the IOManager is initialized
|
| 2238 | 2238 | // (the idle GC may wake up the IOManager)
|
| ... | ... | @@ -2392,7 +2392,7 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS) |
| 2392 | 2392 | }
|
| 2393 | 2393 | |
| 2394 | 2394 | // Notify IO manager that the number of capabilities has changed.
|
| 2395 | - notifyIOManagerCapabilitiesChanged(&cap);
|
|
| 2395 | + notifyIOManagerCapabilitiesChanged(cap->iomgr, &cap);
|
|
| 2396 | 2396 | |
| 2397 | 2397 | startTimer();
|
| 2398 | 2398 |
| ... | ... | @@ -120,9 +120,9 @@ also allows the signal mask to be adjusted, but we do not make use of this. |
| 120 | 120 | ******************************************************************************/
|
| 121 | 121 | |
| 122 | 122 | /* Forward declarations */
|
| 123 | -static bool enlargeTables(Capability *cap, CapIOManager *iomgr);
|
|
| 124 | -static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop);
|
|
| 125 | -static void ioCancel(Capability *cap, StgAsyncIOOp *aiop);
|
|
| 123 | +static bool enlargeTables(CapIOManager *iomgr);
|
|
| 124 | +static void notifyIOCompletion(CapIOManager *iomgr, StgAsyncIOOp *aiop);
|
|
| 125 | +static void ioCancel(CapIOManager *iomgr, StgAsyncIOOp *aiop);
|
|
| 126 | 126 | static void reportPollError(int res, nfds_t nfds) STG_NORETURN;
|
| 127 | 127 | |
| 128 | 128 | |
| ... | ... | @@ -136,32 +136,31 @@ void initCapabilityIOManagerPoll(CapIOManager *iomgr) |
| 136 | 136 | |
| 137 | 137 | /* Used to implement syncIOWaitReady.
|
| 138 | 138 | * Result is true on success, or false on allocation failure. */
|
| 139 | -bool syncIOWaitReadyPoll(Capability *cap, StgTSO *tso,
|
|
| 139 | +bool syncIOWaitReadyPoll(CapIOManager *iomgr, StgTSO *tso,
|
|
| 140 | 140 | IOReadOrWrite rw, HsInt fd)
|
| 141 | 141 | {
|
| 142 | 142 | StgAsyncIOOp *aiop;
|
| 143 | - aiop = (StgAsyncIOOp *)allocateMightFail(cap, sizeofW(StgAsyncIOOp));
|
|
| 143 | + aiop = (StgAsyncIOOp *)allocateMightFail(iomgr->cap, sizeofW(StgAsyncIOOp));
|
|
| 144 | 144 | if (RTS_UNLIKELY(aiop == NULL)) return false;
|
| 145 | - SET_HDR(aiop, &stg_ASYNCIOOP_info, cap->r.rCCCS);
|
|
| 145 | + SET_HDR(aiop, &stg_ASYNCIOOP_info, iomgr->cap->r.rCCCS);
|
|
| 146 | 146 | aiop->notify.tso = tso;
|
| 147 | 147 | aiop->notify_type = NotifyTSO;
|
| 148 | 148 | aiop->live = &stg_ASYNCIO_LIVE0_closure;
|
| 149 | 149 | tso->why_blocked = rw == IORead ? BlockedOnRead : BlockedOnWrite;
|
| 150 | 150 | tso->block_info.aiop = aiop;
|
| 151 | - return asyncIOWaitReadyPoll(cap, aiop, rw, fd);
|
|
| 151 | + return asyncIOWaitReadyPoll(iomgr, aiop, rw, fd);
|
|
| 152 | 152 | }
|
| 153 | 153 | |
| 154 | 154 | /* Result is true on success, or false on allocation failure. */
|
| 155 | -bool asyncIOWaitReadyPoll(Capability *cap, StgAsyncIOOp *aiop,
|
|
| 155 | +bool asyncIOWaitReadyPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop,
|
|
| 156 | 156 | IOReadOrWrite rw, int fd)
|
| 157 | 157 | {
|
| 158 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 159 | 158 | if (RTS_UNLIKELY(isFullClosureTable(&iomgr->aiop_table))) {
|
| 160 | - bool ok = enlargeTables(cap, iomgr);
|
|
| 159 | + bool ok = enlargeTables(iomgr);
|
|
| 161 | 160 | if (RTS_UNLIKELY(!ok)) return false;
|
| 162 | 161 | }
|
| 163 | 162 | |
| 164 | - int ix = insertClosureTable(cap, &iomgr->aiop_table, aiop);
|
|
| 163 | + int ix = insertClosureTable(iomgr->cap, &iomgr->aiop_table, aiop);
|
|
| 165 | 164 | |
| 166 | 165 | /* We use the aiop_table and aiop_poll_table densely. */
|
| 167 | 166 | ASSERT(ix == sizeClosureTable(&iomgr->aiop_table) - 1);
|
| ... | ... | @@ -169,7 +168,7 @@ bool asyncIOWaitReadyPoll(Capability *cap, StgAsyncIOOp *aiop, |
| 169 | 168 | /* The syncIO wrapper or CMM primop filled in the notify and live fields,
|
| 170 | 169 | * we fill the rest.
|
| 171 | 170 | */
|
| 172 | - aiop->capno = cap->no;
|
|
| 171 | + aiop->capno = iomgr->cap->no;
|
|
| 173 | 172 | aiop->index = ix;
|
| 174 | 173 | aiop->outcome = IOOpOutcomeInFlight;
|
| 175 | 174 | |
| ... | ... | @@ -183,12 +182,12 @@ bool asyncIOWaitReadyPoll(Capability *cap, StgAsyncIOOp *aiop, |
| 183 | 182 | }
|
| 184 | 183 | |
| 185 | 184 | |
| 186 | -void syncIOCancelPoll(Capability *cap, StgTSO *tso)
|
|
| 185 | +void syncIOCancelPoll(CapIOManager *iomgr, StgTSO *tso)
|
|
| 187 | 186 | {
|
| 188 | 187 | StgAsyncIOOp *aiop = tso->block_info.aiop;
|
| 189 | 188 | ASSERT(aiop->notify_type == NotifyTSO);
|
| 190 | - ASSERT(indexClosureTable(&cap->iomgr->aiop_table, aiop->index) == aiop);
|
|
| 191 | - ioCancel(cap, aiop);
|
|
| 189 | + ASSERT(indexClosureTable(&iomgr->aiop_table, aiop->index) == aiop);
|
|
| 190 | + ioCancel(iomgr, aiop);
|
|
| 192 | 191 | /* We cannot use the normal notifyIOCompletion here. We are in the context
|
| 193 | 192 | * of throwTo, interrupting a thread blocked on IO via an async exception.
|
| 194 | 193 | * We don't put the TSO back on the run queue or change the why_blocked
|
| ... | ... | @@ -198,7 +197,7 @@ void syncIOCancelPoll(Capability *cap, StgTSO *tso) |
| 198 | 197 | }
|
| 199 | 198 | |
| 200 | 199 | |
| 201 | -void asyncIOCancelPoll(Capability *cap, StgAsyncIOOp *aiop)
|
|
| 200 | +void asyncIOCancelPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop)
|
|
| 202 | 201 | {
|
| 203 | 202 | /* We can reliably determine if the aiop is still in progress by checking
|
| 204 | 203 | * if the aiop_table still points to this aiop object. This is reliable
|
| ... | ... | @@ -206,20 +205,18 @@ void asyncIOCancelPoll(Capability *cap, StgAsyncIOOp *aiop) |
| 206 | 205 | * is no longer retained by the application.
|
| 207 | 206 | */
|
| 208 | 207 | ASSERT(aiop->notify_type != NotifyTSO);
|
| 209 | - if (indexClosureTable(&cap->iomgr->aiop_table, aiop->index) == aiop) {
|
|
| 210 | - ioCancel(cap, aiop);
|
|
| 211 | - notifyIOCompletion(cap, aiop);
|
|
| 208 | + if (indexClosureTable(&iomgr->aiop_table, aiop->index) == aiop) {
|
|
| 209 | + ioCancel(iomgr, aiop);
|
|
| 210 | + notifyIOCompletion(iomgr, aiop);
|
|
| 212 | 211 | }
|
| 213 | 212 | }
|
| 214 | 213 | |
| 215 | 214 | |
| 216 | -static void ioCancel(Capability *cap, StgAsyncIOOp *aiop)
|
|
| 215 | +static void ioCancel(CapIOManager *iomgr, StgAsyncIOOp *aiop)
|
|
| 217 | 216 | {
|
| 218 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 219 | - |
|
| 220 | 217 | int ix = aiop->index;
|
| 221 | 218 | int ix_from; int ix_to;
|
| 222 | - removeCompactClosureTable(cap, &iomgr->aiop_table, ix,
|
|
| 219 | + removeCompactClosureTable(iomgr->cap, &iomgr->aiop_table, ix,
|
|
| 223 | 220 | &ix_from, &ix_to);
|
| 224 | 221 | if (ix_to != ix_from) {
|
| 225 | 222 | StgAsyncIOOp *aiop_to = indexClosureTable(&iomgr->aiop_table, ix_to);
|
| ... | ... | @@ -237,7 +234,7 @@ bool anyPendingTimeoutsOrIOPoll(CapIOManager *iomgr) |
| 237 | 234 | }
|
| 238 | 235 | |
| 239 | 236 | |
| 240 | -static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop)
|
|
| 237 | +static void notifyIOCompletion(CapIOManager *iomgr, StgAsyncIOOp *aiop)
|
|
| 241 | 238 | {
|
| 242 | 239 | ASSERT(aiop->outcome != IOOpOutcomeInFlight);
|
| 243 | 240 | switch (aiop->notify_type) {
|
| ... | ... | @@ -251,7 +248,8 @@ static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop) |
| 251 | 248 | debugTrace(DEBUG_iomanager,
|
| 252 | 249 | "Raising exception in thread %" FMT_StgThreadID
|
| 253 | 250 | " blocked on an invalid fd", tso->id);
|
| 254 | - raiseAsync(cap, tso, (StgClosure *)blockedOnBadFD_closure,
|
|
| 251 | + raiseAsync(iomgr->cap, tso,
|
|
| 252 | + (StgClosure *)blockedOnBadFD_closure,
|
|
| 255 | 253 | false, NULL);
|
| 256 | 254 | break;
|
| 257 | 255 | } else {
|
| ... | ... | @@ -262,7 +260,7 @@ static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop) |
| 262 | 260 | StgTSO *tso = aiop->notify.tso;
|
| 263 | 261 | tso->why_blocked = NotBlocked;
|
| 264 | 262 | tso->_link = END_TSO_QUEUE;
|
| 265 | - pushOnRunQueue(cap, tso);
|
|
| 263 | + pushOnRunQueue(iomgr->cap, tso);
|
|
| 266 | 264 | }
|
| 267 | 265 | break;
|
| 268 | 266 | }
|
| ... | ... | @@ -277,8 +275,7 @@ static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop) |
| 277 | 275 | }
|
| 278 | 276 | |
| 279 | 277 | |
| 280 | -static void processIOCompletions(Capability *cap, CapIOManager *iomgr,
|
|
| 281 | - int ncompletions)
|
|
| 278 | +static void processIOCompletions(CapIOManager *iomgr, int ncompletions)
|
|
| 282 | 279 | {
|
| 283 | 280 | /* The scheme we use with poll is that we have a dense poll table, and a
|
| 284 | 281 | * corresponding table that maps to the closure table index. The poll
|
| ... | ... | @@ -320,7 +317,7 @@ static void processIOCompletions(Capability *cap, CapIOManager *iomgr, |
| 320 | 317 | * apply the same compacting to the aiop_poll_table.
|
| 321 | 318 | */
|
| 322 | 319 | int ix_from; int ix_to;
|
| 323 | - removeCompactClosureTable(cap, &iomgr->aiop_table, i,
|
|
| 320 | + removeCompactClosureTable(iomgr->cap, &iomgr->aiop_table, i,
|
|
| 324 | 321 | &ix_from, &ix_to);
|
| 325 | 322 | if (ix_to != ix_from) {
|
| 326 | 323 | StgAsyncIOOp *aiop_to;
|
| ... | ... | @@ -329,7 +326,7 @@ static void processIOCompletions(Capability *cap, CapIOManager *iomgr, |
| 329 | 326 | aiop_poll_table[ix_to] = aiop_poll_table[ix_from];
|
| 330 | 327 | }
|
| 331 | 328 | |
| 332 | - notifyIOCompletion(cap, aiop);
|
|
| 329 | + notifyIOCompletion(iomgr, aiop);
|
|
| 333 | 330 | n--;
|
| 334 | 331 | } else {
|
| 335 | 332 | /* You'd expect incrementing the poll table index to be
|
| ... | ... | @@ -343,13 +340,11 @@ static void processIOCompletions(Capability *cap, CapIOManager *iomgr, |
| 343 | 340 | }
|
| 344 | 341 | |
| 345 | 342 | |
| 346 | -void pollCompletedTimeoutsOrIOPoll(Capability *cap)
|
|
| 343 | +void pollCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
|
|
| 347 | 344 | {
|
| 348 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 349 | - |
|
| 350 | 345 | if (!isEmptyTimeoutQueue(iomgr->timeout_queue)) {
|
| 351 | 346 | Time now = getProcessElapsedTime();
|
| 352 | - processTimeoutCompletions(cap, now);
|
|
| 347 | + processTimeoutCompletions(iomgr, now);
|
|
| 353 | 348 | }
|
| 354 | 349 | |
| 355 | 350 | if (!isEmptyClosureTable(&iomgr->aiop_table)) {
|
| ... | ... | @@ -379,7 +374,7 @@ void pollCompletedTimeoutsOrIOPoll(Capability *cap) |
| 379 | 374 | } else if (res > 0) {
|
| 380 | 375 | int ncompletions = res;
|
| 381 | 376 | ASSERT(ncompletions <= (int)nfds);
|
| 382 | - processIOCompletions(cap, iomgr, ncompletions);
|
|
| 377 | + processIOCompletions(iomgr, ncompletions);
|
|
| 383 | 378 | |
| 384 | 379 | } else if (errno == EINTR) {
|
| 385 | 380 | /* We got interrupted by a signal. This is unlikely since we asked
|
| ... | ... | @@ -393,10 +388,8 @@ void pollCompletedTimeoutsOrIOPoll(Capability *cap) |
| 393 | 388 | }
|
| 394 | 389 | |
| 395 | 390 | |
| 396 | -void awaitCompletedTimeoutsOrIOPoll(Capability *cap)
|
|
| 391 | +void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
|
|
| 397 | 392 | {
|
| 398 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 399 | - |
|
| 400 | 393 | /* Loop until we've woken up some threads. This loop is needed because the
|
| 401 | 394 | * poll() timing isn't accurate, we sometimes sleep for a while but not
|
| 402 | 395 | * long enough to wake up a thread in a threadDelay. Or we may need to
|
| ... | ... | @@ -409,14 +402,14 @@ void awaitCompletedTimeoutsOrIOPoll(Capability *cap) |
| 409 | 402 | !isEmptyClosureTable(&iomgr->aiop_table));
|
| 410 | 403 | |
| 411 | 404 | Time now = getProcessElapsedTime();
|
| 412 | - processTimeoutCompletions(cap, now);
|
|
| 405 | + processTimeoutCompletions(iomgr, now);
|
|
| 413 | 406 | |
| 414 | 407 | /* If we didn't wake any threads due to expiring timeouts, then we need
|
| 415 | 408 | * to wait on I/O. Or to put it another way, even if we did wake some
|
| 416 | 409 | * threads, we'll still poll (but not wait) for I/O. This is to ensure
|
| 417 | 410 | * we avoid starving threads blocked on I/O.
|
| 418 | 411 | */
|
| 419 | - bool wait = emptyRunQueue(cap);
|
|
| 412 | + bool wait = emptyRunQueue(iomgr->cap);
|
|
| 420 | 413 | |
| 421 | 414 | /* Decide if we are going to wait if no I/O is ready, either:
|
| 422 | 415 | * poll only, wait indefinitely, or wait until a timeout.
|
| ... | ... | @@ -461,7 +454,7 @@ void awaitCompletedTimeoutsOrIOPoll(Capability *cap) |
| 461 | 454 | } else if (res > 0) {
|
| 462 | 455 | int ncompletions = res;
|
| 463 | 456 | ASSERT(ncompletions <= (int)nfds);
|
| 464 | - processIOCompletions(cap, iomgr, ncompletions);
|
|
| 457 | + processIOCompletions(iomgr, ncompletions);
|
|
| 465 | 458 | |
| 466 | 459 | } else if (errno == EINTR) {
|
| 467 | 460 | /* We got interrupted by a signal. In the non-threaded RTS, if the
|
| ... | ... | @@ -471,7 +464,7 @@ void awaitCompletedTimeoutsOrIOPoll(Capability *cap) |
| 471 | 464 | * signal is serviced.
|
| 472 | 465 | */
|
| 473 | 466 | #if defined(RTS_USER_SIGNALS)
|
| 474 | - if (startPendingSignalHandlers(cap)) break;
|
|
| 467 | + if (startPendingSignalHandlers(iomgr->cap)) break;
|
|
| 475 | 468 | #endif
|
| 476 | 469 | |
| 477 | 470 | /* We can also be interrupted by the shutdown signal handler, which
|
| ... | ... | @@ -485,7 +478,7 @@ void awaitCompletedTimeoutsOrIOPoll(Capability *cap) |
| 485 | 478 | reportPollError(res, nfds);
|
| 486 | 479 | }
|
| 487 | 480 | |
| 488 | - } while (emptyRunQueue(cap)
|
|
| 481 | + } while (emptyRunQueue(iomgr->cap)
|
|
| 489 | 482 | && (getSchedState() == SCHED_RUNNING));
|
| 490 | 483 | }
|
| 491 | 484 | |
| ... | ... | @@ -507,12 +500,12 @@ static void reportPollError(int res, nfds_t nfds) |
| 507 | 500 | |
| 508 | 501 | /* Helper function to double the size of the aiop_table and aiop_poll_table.
|
| 509 | 502 | */
|
| 510 | -static bool enlargeTables(Capability *cap, CapIOManager *iomgr)
|
|
| 503 | +static bool enlargeTables(CapIOManager *iomgr)
|
|
| 511 | 504 | {
|
| 512 | 505 | int oldcapacity = capacityClosureTable(&iomgr->aiop_table);
|
| 513 | 506 | int newcapacity = (oldcapacity == 0) ? 1 : (oldcapacity * 2);
|
| 514 | 507 | |
| 515 | - bool ok = enlargeClosureTable(cap, &iomgr->aiop_table, newcapacity);
|
|
| 508 | + bool ok = enlargeClosureTable(iomgr->cap, &iomgr->aiop_table, newcapacity);
|
|
| 516 | 509 | if (RTS_UNLIKELY(!ok)) return false;
|
| 517 | 510 | |
| 518 | 511 | /* Update the auxiliary aiop_poll_table to match */
|
| ... | ... | @@ -19,19 +19,19 @@ |
| 19 | 19 | void initCapabilityIOManagerPoll(CapIOManager *iomgr);
|
| 20 | 20 | |
| 21 | 21 | /* Synchronous I/O and timer operations */
|
| 22 | -bool syncIOWaitReadyPoll(Capability *cap, StgTSO *tso,
|
|
| 22 | +bool syncIOWaitReadyPoll(CapIOManager *iomgr, StgTSO *tso,
|
|
| 23 | 23 | IOReadOrWrite rw, HsInt fd);
|
| 24 | -void syncIOCancelPoll(Capability *cap, StgTSO *tso);
|
|
| 24 | +void syncIOCancelPoll(CapIOManager *iomgr, StgTSO *tso);
|
|
| 25 | 25 | |
| 26 | 26 | /* Asynchronous operations */
|
| 27 | -bool asyncIOWaitReadyPoll(Capability *cap, StgAsyncIOOp *aiop,
|
|
| 27 | +bool asyncIOWaitReadyPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop,
|
|
| 28 | 28 | IOReadOrWrite rw, int fd);
|
| 29 | -void asyncIOCancelPoll(Capability *cap, StgAsyncIOOp *aiop);
|
|
| 29 | +void asyncIOCancelPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop);
|
|
| 30 | 30 | |
| 31 | 31 | /* Scheduler operations */
|
| 32 | 32 | bool anyPendingTimeoutsOrIOPoll(CapIOManager *iomgr);
|
| 33 | -void pollCompletedTimeoutsOrIOPoll(Capability *cap);
|
|
| 34 | -void awaitCompletedTimeoutsOrIOPoll(Capability *cap);
|
|
| 33 | +void pollCompletedTimeoutsOrIOPoll(CapIOManager *iomgr);
|
|
| 34 | +void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr);
|
|
| 35 | 35 | |
| 36 | 36 | #endif /* IOMGR_ENABLED_POLL */
|
| 37 | 37 |
| ... | ... | @@ -93,9 +93,8 @@ LowResTime getDelayTarget (HsInt us) |
| 93 | 93 | * if this is true, then our time has expired.
|
| 94 | 94 | * (idea due to Andy Gill).
|
| 95 | 95 | */
|
| 96 | -static bool wakeUpSleepingThreads (Capability *cap, LowResTime now)
|
|
| 96 | +static bool wakeUpSleepingThreads (CapIOManager *iomgr, LowResTime now)
|
|
| 97 | 97 | {
|
| 98 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 99 | 98 | StgTSO *tso;
|
| 100 | 99 | bool flag = false;
|
| 101 | 100 | |
| ... | ... | @@ -109,7 +108,7 @@ static bool wakeUpSleepingThreads (Capability *cap, LowResTime now) |
| 109 | 108 | tso->_link = END_TSO_QUEUE;
|
| 110 | 109 | IF_DEBUG(scheduler, debugBelch("Waking up sleeping thread %"
|
| 111 | 110 | FMT_StgThreadID "\n", tso->id));
|
| 112 | - pushOnRunQueue(cap,tso);
|
|
| 111 | + pushOnRunQueue(iomgr->cap,tso);
|
|
| 113 | 112 | flag = true;
|
| 114 | 113 | }
|
| 115 | 114 | return flag;
|
| ... | ... | @@ -217,9 +216,8 @@ static enum FdState fdPollWriteState (int fd) |
| 217 | 216 | *
|
| 218 | 217 | */
|
| 219 | 218 | void
|
| 220 | -awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
|
|
| 219 | +awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait)
|
|
| 221 | 220 | {
|
| 222 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 223 | 221 | StgTSO *tso, *prev, *next;
|
| 224 | 222 | fd_set rfd,wfd;
|
| 225 | 223 | int numFound;
|
| ... | ... | @@ -244,7 +242,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait) |
| 244 | 242 | do {
|
| 245 | 243 | |
| 246 | 244 | now = getLowResTimeOfDay();
|
| 247 | - if (wakeUpSleepingThreads(cap, now)) {
|
|
| 245 | + if (wakeUpSleepingThreads(iomgr, now)) {
|
|
| 248 | 246 | return;
|
| 249 | 247 | }
|
| 250 | 248 | |
| ... | ... | @@ -355,7 +353,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait) |
| 355 | 353 | */
|
| 356 | 354 | #if defined(RTS_USER_SIGNALS)
|
| 357 | 355 | if (RtsFlags.MiscFlags.install_signal_handlers && signals_pending()) {
|
| 358 | - startSignalHandlers(cap);
|
|
| 356 | + startSignalHandlers(iomgr->cap);
|
|
| 359 | 357 | return; /* still hold the lock */
|
| 360 | 358 | }
|
| 361 | 359 | #endif
|
| ... | ... | @@ -368,12 +366,12 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait) |
| 368 | 366 | |
| 369 | 367 | /* check for threads that need waking up
|
| 370 | 368 | */
|
| 371 | - wakeUpSleepingThreads(cap, getLowResTimeOfDay());
|
|
| 369 | + wakeUpSleepingThreads(iomgr, getLowResTimeOfDay());
|
|
| 372 | 370 | |
| 373 | 371 | /* If new runnable threads have arrived, stop waiting for
|
| 374 | 372 | * I/O and run them.
|
| 375 | 373 | */
|
| 376 | - if (!emptyRunQueue(cap)) {
|
|
| 374 | + if (!emptyRunQueue(iomgr->cap)) {
|
|
| 377 | 375 | return; /* still hold the lock */
|
| 378 | 376 | }
|
| 379 | 377 | }
|
| ... | ... | @@ -429,7 +427,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait) |
| 429 | 427 | IF_DEBUG(scheduler,
|
| 430 | 428 | debugBelch("Killing blocked thread %" FMT_StgThreadID
|
| 431 | 429 | " on bad fd=%i\n", tso->id, fd));
|
| 432 | - raiseAsync(cap, tso,
|
|
| 430 | + raiseAsync(iomgr->cap, tso,
|
|
| 433 | 431 | (StgClosure *)blockedOnBadFD_closure, false, NULL);
|
| 434 | 432 | break;
|
| 435 | 433 | case RTS_FD_IS_READY:
|
| ... | ... | @@ -438,13 +436,13 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait) |
| 438 | 436 | tso->id));
|
| 439 | 437 | tso->why_blocked = NotBlocked;
|
| 440 | 438 | tso->_link = END_TSO_QUEUE;
|
| 441 | - pushOnRunQueue(cap,tso);
|
|
| 439 | + pushOnRunQueue(iomgr->cap,tso);
|
|
| 442 | 440 | break;
|
| 443 | 441 | case RTS_FD_IS_BLOCKING:
|
| 444 | 442 | if (prev == NULL)
|
| 445 | 443 | iomgr->blocked_queue_hd = tso;
|
| 446 | 444 | else
|
| 447 | - setTSOLink(cap, prev, tso);
|
|
| 445 | + setTSOLink(iomgr->cap, prev, tso);
|
|
| 448 | 446 | prev = tso;
|
| 449 | 447 | break;
|
| 450 | 448 | }
|
| ... | ... | @@ -460,7 +458,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait) |
| 460 | 458 | }
|
| 461 | 459 | |
| 462 | 460 | } while (wait && getSchedState() == SCHED_RUNNING
|
| 463 | - && emptyRunQueue(cap));
|
|
| 461 | + && emptyRunQueue(iomgr->cap));
|
|
| 464 | 462 | }
|
| 465 | 463 | |
| 466 | 464 | #endif /* IOMGR_ENABLED_SELECT */ |
| ... | ... | @@ -15,7 +15,7 @@ typedef StgWord LowResTime; |
| 15 | 15 | |
| 16 | 16 | LowResTime getDelayTarget (HsInt us);
|
| 17 | 17 | |
| 18 | -void awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait);
|
|
| 18 | +void awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait);
|
|
| 19 | 19 | |
| 20 | 20 | #include "EndPrivate.h"
|
| 21 | 21 |
| ... | ... | @@ -26,7 +26,7 @@ |
| 26 | 26 | */
|
| 27 | 27 | #if defined(IOMGR_ENABLED_POLL)
|
| 28 | 28 | |
| 29 | -bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay)
|
|
| 29 | +bool syncDelayTimeout(CapIOManager *iomgr, StgTSO *tso, HsInt us_delay)
|
|
| 30 | 30 | {
|
| 31 | 31 | Time now = getProcessElapsedTime();
|
| 32 | 32 | Time target;
|
| ... | ... | @@ -42,16 +42,16 @@ bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay) |
| 42 | 42 | |
| 43 | 43 | /* fill in a new timeout queue entry */
|
| 44 | 44 | StgTimeout *timeout;
|
| 45 | - timeout = (StgTimeout *)allocateMightFail(cap, sizeofW(StgTimeout));
|
|
| 45 | + timeout = (StgTimeout *)allocateMightFail(iomgr->cap, sizeofW(StgTimeout));
|
|
| 46 | 46 | if (RTS_UNLIKELY(timeout == NULL)) { return false; }
|
| 47 | 47 | union NotifyCompletion notify = { .tso = tso };
|
| 48 | - initElemTimeoutQueue(timeout, notify, NotifyTSO, cap->r.rCCCS);
|
|
| 48 | + initElemTimeoutQueue(timeout, notify, NotifyTSO, iomgr->cap->r.rCCCS);
|
|
| 49 | 49 | |
| 50 | 50 | ASSERT(tso->why_blocked == NotBlocked);
|
| 51 | 51 | tso->why_blocked = BlockedOnDelay;
|
| 52 | 52 | tso->block_info.timeout = timeout;
|
| 53 | 53 | |
| 54 | - insertTimeoutQueue(&cap->iomgr->timeout_queue, timeout, target);
|
|
| 54 | + insertTimeoutQueue(&iomgr->timeout_queue, timeout, target);
|
|
| 55 | 55 | |
| 56 | 56 | debugTrace(DEBUG_iomanager,
|
| 57 | 57 | "timer for delay of %lld usec installed at time %lld ns",
|
| ... | ... | @@ -60,18 +60,18 @@ bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay) |
| 60 | 60 | }
|
| 61 | 61 | |
| 62 | 62 | |
| 63 | -void syncDelayCancelTimeout(Capability *cap, StgTSO *tso)
|
|
| 63 | +void syncDelayCancelTimeout(CapIOManager *iomgr, StgTSO *tso)
|
|
| 64 | 64 | {
|
| 65 | 65 | ASSERT(tso->why_blocked == BlockedOnDelay);
|
| 66 | 66 | StgTimeoutQueue *timeout = tso->block_info.timeout;
|
| 67 | 67 | |
| 68 | - deleteTimeoutQueue(&cap->iomgr->timeout_queue, timeout);
|
|
| 68 | + deleteTimeoutQueue(&iomgr->timeout_queue, timeout);
|
|
| 69 | 69 | |
| 70 | 70 | tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
|
| 71 | 71 | |
| 72 | 72 | /* the timeout is no longer accessible from anywhere (except here) */
|
| 73 | 73 | IF_NONMOVING_WRITE_BARRIER_ENABLED {
|
| 74 | - updateRemembSetPushClosure(cap, (StgClosure *)timeout);
|
|
| 74 | + updateRemembSetPushClosure(iomgr->cap, (StgClosure *)timeout);
|
|
| 75 | 75 | }
|
| 76 | 76 | |
| 77 | 77 | /* We don't put the TSO back on the run queue or change the why_blocked
|
| ... | ... | @@ -79,7 +79,7 @@ void syncDelayCancelTimeout(Capability *cap, StgTSO *tso) |
| 79 | 79 | */
|
| 80 | 80 | }
|
| 81 | 81 | |
| 82 | -static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout);
|
|
| 82 | +static void notifyTimeoutCompletion(CapIOManager *iomgr, StgTimeout *timeout);
|
|
| 83 | 83 | |
| 84 | 84 | /* We use the 64bit Time type from rts/Time.h so our max time (in nanosecond
|
| 85 | 85 | * precision) is over 290 years from the epoch of the monotonic clock.
|
| ... | ... | @@ -90,10 +90,8 @@ static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout); |
| 90 | 90 | * With 64bit Time we do not need to worry about clock wraparound and can just
|
| 91 | 91 | * use the simple formula.
|
| 92 | 92 | */
|
| 93 | -void processTimeoutCompletions(Capability *cap, Time now)
|
|
| 93 | +void processTimeoutCompletions(CapIOManager *iomgr, Time now)
|
|
| 94 | 94 | {
|
| 95 | - CapIOManager *iomgr = cap->iomgr;
|
|
| 96 | - |
|
| 97 | 95 | /* Pop entries from the front of the sleeping queue that are past their
|
| 98 | 96 | * wake time, and unblock the corresponding MVars.
|
| 99 | 97 | */
|
| ... | ... | @@ -105,17 +103,17 @@ void processTimeoutCompletions(Capability *cap, Time now) |
| 105 | 103 | debugTrace(DEBUG_iomanager,"timer expired at %lld ns", waketime);
|
| 106 | 104 | StgTimeout *timeout;
|
| 107 | 105 | deleteMinTimeoutQueue(&iomgr->timeout_queue, &timeout);
|
| 108 | - notifyTimeoutCompletion(cap, timeout);
|
|
| 106 | + notifyTimeoutCompletion(iomgr, timeout);
|
|
| 109 | 107 | |
| 110 | 108 | /* the timeout is no longer accessible from anywhere (except here) */
|
| 111 | 109 | IF_NONMOVING_WRITE_BARRIER_ENABLED {
|
| 112 | - updateRemembSetPushClosure(cap, (StgClosure *)timeout);
|
|
| 110 | + updateRemembSetPushClosure(iomgr->cap, (StgClosure *)timeout);
|
|
| 113 | 111 | }
|
| 114 | 112 | }
|
| 115 | 113 | }
|
| 116 | 114 | |
| 117 | 115 | |
| 118 | -static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout)
|
|
| 116 | +static void notifyTimeoutCompletion(CapIOManager *iomgr, StgTimeout *timeout)
|
|
| 119 | 117 | {
|
| 120 | 118 | switch (timeout->notify_type) {
|
| 121 | 119 | case NotifyTSO:
|
| ... | ... | @@ -123,11 +121,11 @@ static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout) |
| 123 | 121 | StgTSO *tso = timeout->notify.tso;
|
| 124 | 122 | tso->why_blocked = NotBlocked;
|
| 125 | 123 | tso->_link = END_TSO_QUEUE;
|
| 126 | - pushOnRunQueue(cap, tso);
|
|
| 124 | + pushOnRunQueue(iomgr->cap, tso);
|
|
| 127 | 125 | break;
|
| 128 | 126 | }
|
| 129 | 127 | case NotifyMVar:
|
| 130 | - performTryPutMVar(cap, timeout->notify.mvar, Unit_closure);
|
|
| 128 | + performTryPutMVar(iomgr->cap, timeout->notify.mvar, Unit_closure);
|
|
| 131 | 129 | break;
|
| 132 | 130 | |
| 133 | 131 | case NotifyTVar:
|
| ... | ... | @@ -12,9 +12,9 @@ |
| 12 | 12 | |
| 13 | 13 | #include "BeginPrivate.h"
|
| 14 | 14 | |
| 15 | -bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay);
|
|
| 15 | +bool syncDelayTimeout(CapIOManager *iomgr, StgTSO *tso, HsInt us_delay);
|
|
| 16 | 16 | |
| 17 | -void syncDelayCancelTimeout(Capability *cap, StgTSO *tso);
|
|
| 17 | +void syncDelayCancelTimeout(CapIOManager *iomgr, StgTSO *tso);
|
|
| 18 | 18 | |
| 19 | 19 | /* Process the completion of any timeouts that have expired: this means
|
| 20 | 20 | * notifying whatever is waiting on the timeout, a thread, an MVar or TVar.
|
| ... | ... | @@ -24,7 +24,7 @@ void syncDelayCancelTimeout(Capability *cap, StgTSO *tso); |
| 24 | 24 | * No result is returned: callers can check if there are now any runnable
|
| 25 | 25 | * threads by consulting the scheduler's run queue.
|
| 26 | 26 | */
|
| 27 | -void processTimeoutCompletions(Capability *cap, Time now);
|
|
| 27 | +void processTimeoutCompletions(CapIOManager *iomgr, Time now);
|
|
| 28 | 28 | |
| 29 | 29 | /* Utility to compute the timeout wait time (in milliseconds) between now and
|
| 30 | 30 | * the next timer expiry (if any), or no waiting (if !wait).
|