Duncan Coutts pushed to branch wip/io-manager-deadlock-detection at Glasgow Haskell Compiler / GHC

Commits:

13 changed files:

Changes:

  • rts/Capability.c
    ... ... @@ -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);
    

  • rts/IOManager.c
    ... ... @@ -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
    

  • rts/IOManager.h
    ... ... @@ -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"

  • rts/IOManagerInternals.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;
    

  • rts/PrimOps.cmm
    ... ... @@ -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
    

  • rts/RaiseAsync.c
    ... ... @@ -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:
    

  • rts/Schedule.c
    ... ... @@ -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
     
    

  • rts/posix/Poll.c
    ... ... @@ -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 */
    

  • rts/posix/Poll.h
    ... ... @@ -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
     
    

  • rts/posix/Select.c
    ... ... @@ -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 */

  • rts/posix/Select.h
    ... ... @@ -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
     

  • rts/posix/Timeout.c
    ... ... @@ -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:
    

  • rts/posix/Timeout.h
    ... ... @@ -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).