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

WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below.

Deleted commits:

20 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
    ... ... @@ -39,7 +39,7 @@
    39 39
     #endif
    
    40 40
     
    
    41 41
     #if defined(IOMGR_ENABLED_MIO_POSIX)
    
    42
    -#include "posix/Signals.h"
    
    42
    +#include "posix/MIO.h"
    
    43 43
     #include "Prelude.h"
    
    44 44
     #endif
    
    45 45
     
    
    ... ... @@ -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,16 +370,14 @@ void initCapabilityIOManager(Capability *cap)
    363 370
             default:
    
    364 371
                 break;
    
    365 372
         }
    
    366
    -
    
    367
    -    cap->iomgr = iomgr;
    
    368 373
     }
    
    369 374
     
    
    370 375
     
    
    371 376
     /* Called late in the RTS initialisation
    
    372 377
      */
    
    373
    -void initIOManager(void)
    
    378
    +void startIOManager(void)
    
    374 379
     {
    
    375
    -    debugTrace(DEBUG_iomanager, "initialising %s I/O manager", showIOManager());
    
    380
    +    debugTrace(DEBUG_iomanager, "starting %s I/O manager", showIOManager());
    
    376 381
     
    
    377 382
         switch (iomgr_type) {
    
    378 383
     
    
    ... ... @@ -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
    +restartIOManager(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,26 +228,35 @@ 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
    
    238 247
      * everything else is done.
    
    239 248
      */
    
    240
    -void initIOManager(void);
    
    249
    +void startIOManager(void);
    
    241 250
     
    
    242 251
     
    
    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 restartIOManager(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/RtsStartup.c
    ... ... @@ -427,7 +427,7 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
    427 427
         }
    
    428 428
     #endif
    
    429 429
     
    
    430
    -    initIOManager();
    
    430
    +    startIOManager();
    
    431 431
     
    
    432 432
         x86_init_fpu();
    
    433 433
     
    

  • rts/Schedule.c
    ... ... @@ -174,6 +174,11 @@ static void deleteAllThreads (void);
    174 174
     static void deleteThread_(StgTSO *tso);
    
    175 175
     #endif
    
    176 176
     
    
    177
    +#if defined(FORKPROCESS_PRIMOP_SUPPORTED)
    
    178
    +static void truncateRunQueue(Capability *cap);
    
    179
    +#endif
    
    180
    +static StgTSO *popRunQueue (Capability *cap);
    
    181
    +
    
    177 182
     /* ---------------------------------------------------------------------------
    
    178 183
        Main scheduling loop.
    
    179 184
     
    
    ... ... @@ -409,7 +414,7 @@ schedule (Capability *initialCapability, Task *task)
    409 414
          */
    
    410 415
         if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0 &&
    
    411 416
             (!emptyRunQueue(cap) ||
    
    412
    -          anyPendingTimeoutsOrIO(cap))) {
    
    417
    +          anyPendingTimeoutsOrIO(cap->iomgr))) {
    
    413 418
             RELAXED_STORE(&cap->context_switch, 1);
    
    414 419
         }
    
    415 420
     
    
    ... ... @@ -591,38 +596,6 @@ run_thread:
    591 596
       } /* end of while() */
    
    592 597
     }
    
    593 598
     
    
    594
    -/* -----------------------------------------------------------------------------
    
    595
    - * Run queue operations
    
    596
    - * -------------------------------------------------------------------------- */
    
    597
    -
    
    598
    -static void
    
    599
    -removeFromRunQueue (Capability *cap, StgTSO *tso)
    
    600
    -{
    
    601
    -    if (tso->block_info.prev == END_TSO_QUEUE) {
    
    602
    -        ASSERT(cap->run_queue_hd == tso);
    
    603
    -        cap->run_queue_hd = tso->_link;
    
    604
    -    } else {
    
    605
    -        setTSOLink(cap, tso->block_info.prev, tso->_link);
    
    606
    -    }
    
    607
    -    if (tso->_link == END_TSO_QUEUE) {
    
    608
    -        ASSERT(cap->run_queue_tl == tso);
    
    609
    -        cap->run_queue_tl = tso->block_info.prev;
    
    610
    -    } else {
    
    611
    -        setTSOPrev(cap, tso->_link, tso->block_info.prev);
    
    612
    -    }
    
    613
    -    tso->_link = tso->block_info.prev = END_TSO_QUEUE;
    
    614
    -    cap->n_run_queue--;
    
    615
    -
    
    616
    -    IF_DEBUG(sanity, checkRunQueue(cap));
    
    617
    -}
    
    618
    -
    
    619
    -void
    
    620
    -promoteInRunQueue (Capability *cap, StgTSO *tso)
    
    621
    -{
    
    622
    -    removeFromRunQueue(cap, tso);
    
    623
    -    pushOnRunQueue(cap, tso);
    
    624
    -}
    
    625
    -
    
    626 599
     /* -----------------------------------------------------------------------------
    
    627 600
      * scheduleFindWork()
    
    628 601
      *
    
    ... ... @@ -923,14 +896,14 @@ scheduleCheckBlockedThreads(Capability *cap USED_IF_NOT_THREADS)
    923 896
          * awaitCompletedTimeoutsOrIO below for the case of !defined(THREADED_RTS)
    
    924 897
          * && defined(mingw32_HOST_OS).
    
    925 898
          */
    
    926
    -    if (anyPendingTimeoutsOrIO(cap))
    
    899
    +    if (anyPendingTimeoutsOrIO(cap->iomgr))
    
    927 900
         {
    
    928 901
             if (emptyRunQueue(cap)) {
    
    929 902
                 // block and wait
    
    930
    -            awaitCompletedTimeoutsOrIO(cap);
    
    903
    +            awaitCompletedTimeoutsOrIO(cap->iomgr);
    
    931 904
             } else {
    
    932 905
                 // poll but do not wait
    
    933
    -            pollCompletedTimeoutsOrIO(cap);
    
    906
    +            pollCompletedTimeoutsOrIO(cap->iomgr);
    
    934 907
             }
    
    935 908
         }
    
    936 909
     #endif
    
    ... ... @@ -950,7 +923,7 @@ scheduleDetectDeadlock (Capability **pcap, Task *task)
    950 923
          * other tasks are waiting for work, we must have a deadlock of
    
    951 924
          * some description.
    
    952 925
          */
    
    953
    -    if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap) )
    
    926
    +    if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap->iomgr) )
    
    954 927
         {
    
    955 928
     #if defined(THREADED_RTS)
    
    956 929
             /*
    
    ... ... @@ -2191,7 +2164,6 @@ forkProcess(HsStablePtr *entry
    2191 2164
                 // bound threads for which the corresponding Task does not
    
    2192 2165
                 // exist.
    
    2193 2166
                 truncateRunQueue(cap);
    
    2194
    -            cap->n_run_queue = 0;
    
    2195 2167
     
    
    2196 2168
                 // Any suspended C-calling Tasks are no more, their OS threads
    
    2197 2169
                 // don't exist now:
    
    ... ... @@ -2208,7 +2180,7 @@ forkProcess(HsStablePtr *entry
    2208 2180
                 cap->n_returning_tasks = 0;
    
    2209 2181
     #endif
    
    2210 2182
     
    
    2211
    -            // Release all caps except 0, we'll use that for starting
    
    2183
    +            // Release all caps except 0, we'll use that for restarting
    
    2212 2184
                 // the IO manager and running the client action below.
    
    2213 2185
                 if (cap->no != 0) {
    
    2214 2186
                     task->cap = cap;
    
    ... ... @@ -2232,7 +2204,7 @@ forkProcess(HsStablePtr *entry
    2232 2204
             // like startup event, capabilities, process info etc
    
    2233 2205
             traceTaskCreate(task, cap);
    
    2234 2206
     
    
    2235
    -        initIOManagerAfterFork(&cap);
    
    2207
    +        restartIOManager(cap->iomgr, &cap);
    
    2236 2208
     
    
    2237 2209
             // start timer after the IOManager is initialized
    
    2238 2210
             // (the idle GC may wake up the IOManager)
    
    ... ... @@ -2392,7 +2364,7 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
    2392 2364
         }
    
    2393 2365
     
    
    2394 2366
         // Notify IO manager that the number of capabilities has changed.
    
    2395
    -    notifyIOManagerCapabilitiesChanged(&cap);
    
    2367
    +    notifyIOManagerCapabilitiesChanged(cap->iomgr, &cap);
    
    2396 2368
     
    
    2397 2369
         startTimer();
    
    2398 2370
     
    
    ... ... @@ -2997,7 +2969,7 @@ pushOnRunQueue (Capability *cap, StgTSO *tso)
    2997 2969
         cap->n_run_queue++;
    
    2998 2970
     }
    
    2999 2971
     
    
    3000
    -StgTSO *popRunQueue (Capability *cap)
    
    2972
    +static StgTSO *popRunQueue (Capability *cap)
    
    3001 2973
     {
    
    3002 2974
         ASSERT(cap->n_run_queue > 0);
    
    3003 2975
         StgTSO *t = cap->run_queue_hd;
    
    ... ... @@ -3017,6 +2989,45 @@ StgTSO *popRunQueue (Capability *cap)
    3017 2989
         return t;
    
    3018 2990
     }
    
    3019 2991
     
    
    2992
    +#if defined(FORKPROCESS_PRIMOP_SUPPORTED)
    
    2993
    +static void truncateRunQueue(Capability *cap)
    
    2994
    +{
    
    2995
    +    // Can only be called by the task owning the capability.
    
    2996
    +    TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_hd, "truncateRunQueue");
    
    2997
    +    TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_tl, "truncateRunQueue");
    
    2998
    +    TSAN_ANNOTATE_BENIGN_RACE(&cap->n_run_queue, "truncateRunQueue");
    
    2999
    +    cap->run_queue_hd = END_TSO_QUEUE;
    
    3000
    +    cap->run_queue_tl = END_TSO_QUEUE;
    
    3001
    +    cap->n_run_queue = 0;
    
    3002
    +}
    
    3003
    +#endif
    
    3004
    +
    
    3005
    +static void removeFromRunQueue (Capability *cap, StgTSO *tso)
    
    3006
    +{
    
    3007
    +    if (tso->block_info.prev == END_TSO_QUEUE) {
    
    3008
    +        ASSERT(cap->run_queue_hd == tso);
    
    3009
    +        cap->run_queue_hd = tso->_link;
    
    3010
    +    } else {
    
    3011
    +        setTSOLink(cap, tso->block_info.prev, tso->_link);
    
    3012
    +    }
    
    3013
    +    if (tso->_link == END_TSO_QUEUE) {
    
    3014
    +        ASSERT(cap->run_queue_tl == tso);
    
    3015
    +        cap->run_queue_tl = tso->block_info.prev;
    
    3016
    +    } else {
    
    3017
    +        setTSOPrev(cap, tso->_link, tso->block_info.prev);
    
    3018
    +    }
    
    3019
    +    tso->_link = tso->block_info.prev = END_TSO_QUEUE;
    
    3020
    +    cap->n_run_queue--;
    
    3021
    +
    
    3022
    +    IF_DEBUG(sanity, checkRunQueue(cap));
    
    3023
    +}
    
    3024
    +
    
    3025
    +void promoteInRunQueue (Capability *cap, StgTSO *tso)
    
    3026
    +{
    
    3027
    +    removeFromRunQueue(cap, tso);
    
    3028
    +    pushOnRunQueue(cap, tso);
    
    3029
    +}
    
    3030
    +
    
    3020 3031
     
    
    3021 3032
     /* -----------------------------------------------------------------------------
    
    3022 3033
        raiseExceptionHelper
    

  • rts/Schedule.h
    ... ... @@ -164,10 +164,6 @@ void appendToRunQueue (Capability *cap, StgTSO *tso);
    164 164
      */
    
    165 165
     void pushOnRunQueue (Capability *cap, StgTSO *tso);
    
    166 166
     
    
    167
    -/* Pop the first thread off the runnable queue.
    
    168
    - */
    
    169
    -StgTSO *popRunQueue (Capability *cap);
    
    170
    -
    
    171 167
     INLINE_HEADER StgTSO *
    
    172 168
     peekRunQueue (Capability *cap)
    
    173 169
     {
    
    ... ... @@ -184,18 +180,6 @@ emptyRunQueue(Capability *cap)
    184 180
         return cap->n_run_queue == 0;
    
    185 181
     }
    
    186 182
     
    
    187
    -INLINE_HEADER void
    
    188
    -truncateRunQueue(Capability *cap)
    
    189
    -{
    
    190
    -    // Can only be called by the task owning the capability.
    
    191
    -    TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_hd, "truncateRunQueue");
    
    192
    -    TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_tl, "truncateRunQueue");
    
    193
    -    TSAN_ANNOTATE_BENIGN_RACE(&cap->n_run_queue, "truncateRunQueue");
    
    194
    -    cap->run_queue_hd = END_TSO_QUEUE;
    
    195
    -    cap->run_queue_tl = END_TSO_QUEUE;
    
    196
    -    cap->n_run_queue = 0;
    
    197
    -}
    
    198
    -
    
    199 183
     #endif /* !IN_STG_CODE */
    
    200 184
     
    
    201 185
     #include "EndPrivate.h"

  • rts/posix/MIO.c
    1
    +/* -----------------------------------------------------------------------------
    
    2
    + *
    
    3
    + * (c) The GHC Team, 1998-2005
    
    4
    + *
    
    5
    + * Signal processing / handling.
    
    6
    + *
    
    7
    + * ---------------------------------------------------------------------------*/
    
    8
    +
    
    9
    +#include "rts/PosixSource.h"
    
    10
    +#include "Rts.h"
    
    11
    +
    
    12
    +#include "Schedule.h"
    
    13
    +#include "RtsUtils.h"
    
    14
    +#include "Prelude.h"
    
    15
    +#include "ThreadLabels.h"
    
    16
    +
    
    17
    +#include "MIO.h"
    
    18
    +#include "IOManager.h"
    
    19
    +#include "IOManagerInternals.h"
    
    20
    +
    
    21
    +#if defined(HAVE_ERRNO_H)
    
    22
    +# include <errno.h>
    
    23
    +#endif
    
    24
    +
    
    25
    +#include <stdlib.h>
    
    26
    +#include <unistd.h>
    
    27
    +
    
    28
    +// Here's the pipe into which we will send our signals
    
    29
    +static int io_manager_wakeup_fd = -1;
    
    30
    +static int timer_manager_control_wr_fd = -1;
    
    31
    +// TODO: Eliminate these globals. Put then into the CapIOManager, but the
    
    32
    +// problem is these are shared across all caps, not per cap.
    
    33
    +
    
    34
    +#define IO_MANAGER_WAKEUP 0xff
    
    35
    +#define IO_MANAGER_DIE    0xfe
    
    36
    +#define IO_MANAGER_SYNC   0xfd
    
    37
    +
    
    38
    +void setTimerManagerControlFd(int fd) {
    
    39
    +    RELAXED_STORE(&timer_manager_control_wr_fd, fd);
    
    40
    +}
    
    41
    +
    
    42
    +void
    
    43
    +setIOManagerWakeupFd (int fd)
    
    44
    +{
    
    45
    +    // only called when THREADED_RTS, but unconditionally
    
    46
    +    // compiled here because GHC.Event.Control depends on it.
    
    47
    +    SEQ_CST_STORE(&io_manager_wakeup_fd, fd);
    
    48
    +}
    
    49
    +
    
    50
    +#if defined(THREADED_RTS)
    
    51
    +void timerManagerNotifySignal(int sig, siginfo_t *info)
    
    52
    +{
    
    53
    +    StgWord8 buf[sizeof(siginfo_t) + 1];
    
    54
    +    int r;
    
    55
    +
    
    56
    +    buf[0] = sig;
    
    57
    +    if (info == NULL) {
    
    58
    +        // info may be NULL on Solaris (see #3790)
    
    59
    +        memset(buf+1, 0, sizeof(siginfo_t));
    
    60
    +    } else {
    
    61
    +        memcpy(buf+1, info, sizeof(siginfo_t));
    
    62
    +    }
    
    63
    +
    
    64
    +    int timer_control_fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
    
    65
    +    if (0 <= timer_control_fd)
    
    66
    +    {
    
    67
    +        r = write(timer_control_fd, buf, sizeof(siginfo_t)+1);
    
    68
    +        if (r == -1 && errno == EAGAIN) {
    
    69
    +            errorBelch("lost signal due to full pipe: %d\n", sig);
    
    70
    +        }
    
    71
    +    }
    
    72
    +
    
    73
    +    // If the IO manager hasn't told us what the FD of the write end
    
    74
    +    // of its pipe is, there's not much we can do here, so just ignore
    
    75
    +    // the signal..
    
    76
    +}
    
    77
    +#endif
    
    78
    +
    
    79
    +
    
    80
    +/* -----------------------------------------------------------------------------
    
    81
    + * Wake up at least one IO or timer manager HS thread.
    
    82
    + * -------------------------------------------------------------------------- */
    
    83
    +void
    
    84
    +ioManagerWakeup (void)
    
    85
    +{
    
    86
    +    int r;
    
    87
    +    const int wakeup_fd = SEQ_CST_LOAD(&io_manager_wakeup_fd);
    
    88
    +    // Wake up the IO Manager thread by sending a byte down its pipe
    
    89
    +    if (wakeup_fd >= 0) {
    
    90
    +#if defined(HAVE_EVENTFD)
    
    91
    +        StgWord64 n = (StgWord64)IO_MANAGER_WAKEUP;
    
    92
    +        r = write(wakeup_fd, (char *) &n, 8);
    
    93
    +#else
    
    94
    +        StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
    
    95
    +        r = write(wakeup_fd, &byte, 1);
    
    96
    +#endif
    
    97
    +        /* N.B. If the TimerManager is shutting down as we run this
    
    98
    +         * then there is a possibility that our first read of
    
    99
    +         * io_manager_wakeup_fd is non-negative, but before we get to the
    
    100
    +         * write the file is closed. If this occurs, io_manager_wakeup_fd
    
    101
    +         * will be written into with -1 (GHC.Event.Control does this prior
    
    102
    +         * to closing), so checking this allows us to distinguish this case.
    
    103
    +         * To ensure we observe the correct ordering, we declare the
    
    104
    +         * io_manager_wakeup_fd as volatile.
    
    105
    +         * Since this is not an error condition, we do not print the error
    
    106
    +         * message in this case.
    
    107
    +         */
    
    108
    +        if (r == -1 && SEQ_CST_LOAD(&io_manager_wakeup_fd) >= 0) {
    
    109
    +            sysErrorBelch("ioManagerWakeup: write");
    
    110
    +        }
    
    111
    +    }
    
    112
    +}
    
    113
    +
    
    114
    +#if defined(THREADED_RTS)
    
    115
    +void
    
    116
    +ioManagerDie (void)
    
    117
    +{
    
    118
    +    StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
    
    119
    +    uint32_t i;
    
    120
    +    int r;
    
    121
    +
    
    122
    +    {
    
    123
    +        // Shut down timer manager
    
    124
    +        const int fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
    
    125
    +        if (0 <= fd) {
    
    126
    +            r = write(fd, &byte, 1);
    
    127
    +            if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
    
    128
    +            RELAXED_STORE(&timer_manager_control_wr_fd, -1);
    
    129
    +        }
    
    130
    +    }
    
    131
    +
    
    132
    +    {
    
    133
    +        // Shut down IO managers
    
    134
    +        for (i=0; i < getNumCapabilities(); i++) {
    
    135
    +            const int fd = RELAXED_LOAD(&getCapability(i)->iomgr->control_fd);
    
    136
    +            if (0 <= fd) {
    
    137
    +                r = write(fd, &byte, 1);
    
    138
    +                if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
    
    139
    +                RELAXED_STORE(&getCapability(i)->iomgr->control_fd, -1);
    
    140
    +            }
    
    141
    +        }
    
    142
    +    }
    
    143
    +}
    
    144
    +
    
    145
    +void
    
    146
    +ioManagerStartCap (Capability **cap)
    
    147
    +{
    
    148
    +    rts_evalIO(cap,ensureIOManagerIsRunning_closure,NULL);
    
    149
    +}
    
    150
    +
    
    151
    +void
    
    152
    +ioManagerStart (void)
    
    153
    +{
    
    154
    +    // Make sure the IO manager thread is running
    
    155
    +    Capability *cap;
    
    156
    +    if (SEQ_CST_LOAD(&timer_manager_control_wr_fd) < 0 || SEQ_CST_LOAD(&io_manager_wakeup_fd) < 0) {
    
    157
    +        cap = rts_lock();
    
    158
    +        ioManagerStartCap(&cap);
    
    159
    +        rts_unlock(cap);
    
    160
    +    }
    
    161
    +}
    
    162
    +#endif
    
    163
    +

  • rts/posix/MIO.h
    1
    +/* -----------------------------------------------------------------------------
    
    2
    + *
    
    3
    + * (c) The GHC Team, 1998-2005
    
    4
    + *
    
    5
    + * Signal processing / handling.
    
    6
    + *
    
    7
    + * ---------------------------------------------------------------------------*/
    
    8
    +
    
    9
    +#pragma once
    
    10
    +
    
    11
    +#include "IOManager.h"
    
    12
    +
    
    13
    +#if defined(HAVE_SIGNAL_H)
    
    14
    +# include <signal.h>
    
    15
    +#endif
    
    16
    +
    
    17
    +#include "BeginPrivate.h"
    
    18
    +
    
    19
    +/* Communicating with the IO manager thread (see GHC.Conc).
    
    20
    + */
    
    21
    +void ioManagerWakeup (void);
    
    22
    +#if defined(THREADED_RTS)
    
    23
    +void ioManagerDie (void);
    
    24
    +void ioManagerStart (void);
    
    25
    +void ioManagerStartCap (/* inout */ Capability **cap);
    
    26
    +
    
    27
    +void timerManagerNotifySignal(int sig, siginfo_t *info);
    
    28
    +#endif
    
    29
    +
    
    30
    +#include "EndPrivate.h"

  • 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/Signals.c
    ... ... @@ -9,21 +9,12 @@
    9 9
     #include "rts/PosixSource.h"
    
    10 10
     #include "Rts.h"
    
    11 11
     
    
    12
    -#include "Schedule.h"
    
    13 12
     #include "RtsSignals.h"
    
    14
    -#include "Signals.h"
    
    15
    -#include "IOManager.h"
    
    16 13
     #include "RtsUtils.h"
    
    14
    +#include "Schedule.h"
    
    17 15
     #include "Prelude.h"
    
    18
    -#include "Ticker.h"
    
    19 16
     #include "ThreadLabels.h"
    
    20
    -#include "Libdw.h"
    
    21
    -
    
    22
    -/* TODO: eliminate this include. This file should be about signals, not be
    
    23
    - * part of an I/O manager implementation. The code here that are really part
    
    24
    - * of an I/O manager should be moved into an appropriate I/O manager impl.
    
    25
    - */
    
    26
    -#include "IOManagerInternals.h"
    
    17
    +#include "MIO.h"
    
    27 18
     
    
    28 19
     #if defined(alpha_HOST_ARCH)
    
    29 20
     # if defined(linux_HOST_OS)
    
    ... ... @@ -45,10 +36,6 @@
    45 36
     # include <errno.h>
    
    46 37
     #endif
    
    47 38
     
    
    48
    -#if defined(HAVE_EVENTFD_H)
    
    49
    -# include <sys/eventfd.h>
    
    50
    -#endif
    
    51
    -
    
    52 39
     #if defined(HAVE_TERMIOS_H)
    
    53 40
     #include <termios.h>
    
    54 41
     #endif
    
    ... ... @@ -134,110 +121,6 @@ more_handlers(int sig)
    134 121
         nHandlers = sig + 1;
    
    135 122
     }
    
    136 123
     
    
    137
    -// Here's the pipe into which we will send our signals
    
    138
    -static int io_manager_wakeup_fd = -1;
    
    139
    -static int timer_manager_control_wr_fd = -1;
    
    140
    -
    
    141
    -#define IO_MANAGER_WAKEUP 0xff
    
    142
    -#define IO_MANAGER_DIE    0xfe
    
    143
    -#define IO_MANAGER_SYNC   0xfd
    
    144
    -
    
    145
    -void setTimerManagerControlFd(int fd) {
    
    146
    -    RELAXED_STORE(&timer_manager_control_wr_fd, fd);
    
    147
    -}
    
    148
    -
    
    149
    -void
    
    150
    -setIOManagerWakeupFd (int fd)
    
    151
    -{
    
    152
    -    // only called when THREADED_RTS, but unconditionally
    
    153
    -    // compiled here because GHC.Event.Control depends on it.
    
    154
    -    SEQ_CST_STORE(&io_manager_wakeup_fd, fd);
    
    155
    -}
    
    156
    -
    
    157
    -/* -----------------------------------------------------------------------------
    
    158
    - * Wake up at least one IO or timer manager HS thread.
    
    159
    - * -------------------------------------------------------------------------- */
    
    160
    -void
    
    161
    -ioManagerWakeup (void)
    
    162
    -{
    
    163
    -    int r;
    
    164
    -    const int wakeup_fd = SEQ_CST_LOAD(&io_manager_wakeup_fd);
    
    165
    -    // Wake up the IO Manager thread by sending a byte down its pipe
    
    166
    -    if (wakeup_fd >= 0) {
    
    167
    -#if defined(HAVE_EVENTFD)
    
    168
    -        StgWord64 n = (StgWord64)IO_MANAGER_WAKEUP;
    
    169
    -        r = write(wakeup_fd, (char *) &n, 8);
    
    170
    -#else
    
    171
    -        StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
    
    172
    -        r = write(wakeup_fd, &byte, 1);
    
    173
    -#endif
    
    174
    -        /* N.B. If the TimerManager is shutting down as we run this
    
    175
    -         * then there is a possibility that our first read of
    
    176
    -         * io_manager_wakeup_fd is non-negative, but before we get to the
    
    177
    -         * write the file is closed. If this occurs, io_manager_wakeup_fd
    
    178
    -         * will be written into with -1 (GHC.Event.Control does this prior
    
    179
    -         * to closing), so checking this allows us to distinguish this case.
    
    180
    -         * To ensure we observe the correct ordering, we declare the
    
    181
    -         * io_manager_wakeup_fd as volatile.
    
    182
    -         * Since this is not an error condition, we do not print the error
    
    183
    -         * message in this case.
    
    184
    -         */
    
    185
    -        if (r == -1 && SEQ_CST_LOAD(&io_manager_wakeup_fd) >= 0) {
    
    186
    -            sysErrorBelch("ioManagerWakeup: write");
    
    187
    -        }
    
    188
    -    }
    
    189
    -}
    
    190
    -
    
    191
    -#if defined(THREADED_RTS)
    
    192
    -void
    
    193
    -ioManagerDie (void)
    
    194
    -{
    
    195
    -    StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
    
    196
    -    uint32_t i;
    
    197
    -    int r;
    
    198
    -
    
    199
    -    {
    
    200
    -        // Shut down timer manager
    
    201
    -        const int fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
    
    202
    -        if (0 <= fd) {
    
    203
    -            r = write(fd, &byte, 1);
    
    204
    -            if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
    
    205
    -            RELAXED_STORE(&timer_manager_control_wr_fd, -1);
    
    206
    -        }
    
    207
    -    }
    
    208
    -
    
    209
    -    {
    
    210
    -        // Shut down IO managers
    
    211
    -        for (i=0; i < getNumCapabilities(); i++) {
    
    212
    -            const int fd = RELAXED_LOAD(&getCapability(i)->iomgr->control_fd);
    
    213
    -            if (0 <= fd) {
    
    214
    -                r = write(fd, &byte, 1);
    
    215
    -                if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
    
    216
    -                RELAXED_STORE(&getCapability(i)->iomgr->control_fd, -1);
    
    217
    -            }
    
    218
    -        }
    
    219
    -    }
    
    220
    -}
    
    221
    -
    
    222
    -void
    
    223
    -ioManagerStartCap (Capability **cap)
    
    224
    -{
    
    225
    -    rts_evalIO(cap,ensureIOManagerIsRunning_closure,NULL);
    
    226
    -}
    
    227
    -
    
    228
    -void
    
    229
    -ioManagerStart (void)
    
    230
    -{
    
    231
    -    // Make sure the IO manager thread is running
    
    232
    -    Capability *cap;
    
    233
    -    if (SEQ_CST_LOAD(&timer_manager_control_wr_fd) < 0 || SEQ_CST_LOAD(&io_manager_wakeup_fd) < 0) {
    
    234
    -        cap = rts_lock();
    
    235
    -        ioManagerStartCap(&cap);
    
    236
    -        rts_unlock(cap);
    
    237
    -    }
    
    238
    -}
    
    239
    -#endif
    
    240
    -
    
    241 124
     #if !defined(THREADED_RTS)
    
    242 125
     
    
    243 126
     #define N_PENDING_HANDLERS 16
    
    ... ... @@ -260,31 +143,9 @@ generic_handler(int sig USED_IF_THREADS,
    260 143
                     void *p STG_UNUSED)
    
    261 144
     {
    
    262 145
     #if defined(THREADED_RTS)
    
    263
    -
    
    264
    -    StgWord8 buf[sizeof(siginfo_t) + 1];
    
    265
    -    int r;
    
    266
    -
    
    267
    -    buf[0] = sig;
    
    268
    -    if (info == NULL) {
    
    269
    -        // info may be NULL on Solaris (see #3790)
    
    270
    -        memset(buf+1, 0, sizeof(siginfo_t));
    
    271
    -    } else {
    
    272
    -        memcpy(buf+1, info, sizeof(siginfo_t));
    
    273
    -    }
    
    274
    -
    
    275
    -    int timer_control_fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
    
    276
    -    if (0 <= timer_control_fd)
    
    277
    -    {
    
    278
    -        r = write(timer_control_fd, buf, sizeof(siginfo_t)+1);
    
    279
    -        if (r == -1 && errno == EAGAIN) {
    
    280
    -            errorBelch("lost signal due to full pipe: %d\n", sig);
    
    281
    -        }
    
    282
    -    }
    
    283
    -
    
    284
    -    // If the IO manager hasn't told us what the FD of the write end
    
    285
    -    // of its pipe is, there's not much we can do here, so just ignore
    
    286
    -    // the signal..
    
    287
    -
    
    146
    +    //TODO: This calls MIO directly. We should go via IOManager API.
    
    147
    +    // The IOManager API should be extended to cover signals.
    
    148
    +    timerManagerNotifySignal(sig, info);
    
    288 149
     #else /* not THREADED_RTS */
    
    289 150
     
    
    290 151
         /* Can't call allocate from here.  Probably can't call malloc
    

  • rts/posix/Signals.h
    ... ... @@ -27,18 +27,6 @@ void startSignalHandlers(Capability *cap);
    27 27
     
    
    28 28
     void install_vtalrm_handler(int sig, TickProc handle_tick);
    
    29 29
     
    
    30
    -/* Communicating with the IO manager thread (see GHC.Conc).
    
    31
    - *
    
    32
    - * TODO: these I/O manager things are not related to signals and ought to live
    
    33
    - * elsewhere, e.g. in a module specifically for the I/O manager.
    
    34
    - */
    
    35
    -void ioManagerWakeup (void);
    
    36
    -#if defined(THREADED_RTS)
    
    37
    -void ioManagerDie (void);
    
    38
    -void ioManagerStart (void);
    
    39
    -void ioManagerStartCap (/* inout */ Capability **cap);
    
    40
    -#endif
    
    41
    -
    
    42 30
     extern StgInt *signal_handlers;
    
    43 31
     
    
    44 32
     #include "EndPrivate.h"

  • 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).
    

  • rts/rts.cabal
    ... ... @@ -581,6 +581,7 @@ library
    581 581
                         posix/Ticker.c
    
    582 582
                         posix/OSMem.c
    
    583 583
                         posix/OSThreads.c
    
    584
    +                    posix/MIO.c
    
    584 585
                         posix/Poll.c
    
    585 586
                         posix/Select.c
    
    586 587
                         posix/Signals.c