Duncan Coutts pushed to branch wip/dcoutts/issue-27105-stopTicker-2 at Glasgow Haskell Compiler / GHC

Commits:

15 changed files:

Changes:

  • changelog.d/T27046
    1
    +section: compiler
    
    2
    +issues: #27046
    
    3
    +mrs: !16031
    
    4
    +synopsis:
    
    5
    +  Avoid AArch64 register clobbering bug in MUL2
    
    6
    +description:
    
    7
    +  Fixes an issue in which, on AArch64, code generation for the MUL2 operation
    
    8
    +  could clobber one of the input operands when computing the lower bits, which
    
    9
    +  rendered invalid the subsequent computation of the high bits.

  • changelog.d/hadrian-stale-package-confs-26661
    1
    +section: packaging
    
    2
    +synopsis: Hadrian no longer leaves stale `.conf` files in its package databases
    
    3
    +  when rebuilding in the same build root with different settings (e.g. another
    
    4
    +  flavour, or when hashes change with +hash-unit-ids).
    
    5
    +issues: #26661
    
    6
    +mrs: !15186

  • compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
    ... ... @@ -2300,11 +2300,19 @@ genCCall target dest_regs arg_regs = do
    2300 2300
                   let lo = getRegisterReg platform (CmmLocal dst_lo)
    
    2301 2301
                       hi = getRegisterReg platform (CmmLocal dst_hi)
    
    2302 2302
                       nd = getRegisterReg platform (CmmLocal dst_needed)
    
    2303
    +
    
    2304
    +              -- Generate a fresh virtual register for the low word computation.
    
    2305
    +              -- This avoids clobbering reg_a or reg_b in the first MUL instruction,
    
    2306
    +              -- which could for example happen if 'lo' and 'reg_a' are the same
    
    2307
    +              -- virtual register.
    
    2308
    +              tmp_lo <- getNewRegNat II64
    
    2309
    +
    
    2303 2310
                   return $
    
    2304 2311
                       code_x `appOL`
    
    2305 2312
                       code_y `snocOL`
    
    2306
    -                  MUL   II64 (OpReg W64 lo) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
    
    2313
    +                  MUL   II64 (OpReg W64 tmp_lo) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
    
    2307 2314
                       SMULH (OpReg W64 hi) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
    
    2315
    +                  MOV   (OpReg W64 lo) (OpReg W64 tmp_lo) `snocOL`
    
    2308 2316
                       -- Are all high bits equal to the sign bit of the low word?
    
    2309 2317
                       -- nd = (hi == ASR(lo,width-1)) ? 1 : 0
    
    2310 2318
                       CMP   (OpReg W64 hi) (OpRegShift W64 lo SASR (widthInBits w - 1)) `snocOL`
    

  • hadrian/src/Hadrian/Haskell/Cabal/Parse.hs
    ... ... @@ -15,6 +15,7 @@ module Hadrian.Haskell.Cabal.Parse (
    15 15
         ) where
    
    16 16
     
    
    17 17
     import Data.Bifunctor
    
    18
    +import Data.Char (isDigit)
    
    18 19
     import Data.List.Extra
    
    19 20
     import Development.Shake
    
    20 21
     import qualified Distribution.Compat.Graph                     as Graph
    
    ... ... @@ -55,6 +56,8 @@ import Builder
    55 56
     import Context
    
    56 57
     import Settings
    
    57 58
     import Distribution.Simple.LocalBuildInfo
    
    59
    +import Distribution.Types.LocalBuildInfo (allTargetsInBuildOrder')
    
    60
    +import Distribution.Types.TargetInfo (TargetInfo (..))
    
    58 61
     import qualified Distribution.Simple.Register as C
    
    59 62
     import System.Directory (getCurrentDirectory)
    
    60 63
     import qualified Distribution.InstalledPackageInfo as CP
    
    ... ... @@ -394,35 +397,48 @@ registerPackage rs context = do
    394 397
         -- Note: the @cPath@ is ignored. The path that's used is the 'buildDir' path
    
    395 398
         -- from the local build info @lbi@.
    
    396 399
         lbi <- liftIO $ C.getPersistBuildConfig Nothing (C.makeSymbolicPath cPath)
    
    397
    -    liftIO $ register db_path pid pd lbi
    
    400
    +    -- This runs `ghc --abi-hash`, so do it outside the critical section below.
    
    401
    +    installedPkgInfo <- liftIO $ generateRegistrationInfo pd lbi
    
    402
    +
    
    403
    +    let pkg_name = pkgName (package context)
    
    404
    +        -- Is this a pkg.conf for a previous build?
    
    405
    +        -- we want to match "ghc-9.15.1-abcd.conf" but not "ghc-boot-9.15.1.conf"
    
    406
    +        isPkgConf f = case stripPrefix (pkg_name ++ "-") (takeBaseName f) of
    
    407
    +            Just (c:_) -> isDigit c
    
    408
    +            _          -> takeBaseName f == pkg_name
    
    409
    +
    
    410
    +    -- Unlike `ghc-pkg update/register` (used to populate the inplace and stage0
    
    411
    +    -- databases), writing the .conf file directly doesn't remove units this
    
    412
    +    -- package was previously registered under. Stale .conf files from earlier
    
    413
    +    -- builds make this package's modules ambiguous (#26661), so delete them
    
    414
    +    -- before writing the new .conf file.
    
    415
    +    withResources rs $ do
    
    416
    +        confs <- liftIO $ getDirectoryFilesIO db_path ["*.conf"]
    
    417
    +        mapM_ (removeFile . (db_path </>))
    
    418
    +              [ f | f <- confs, isPkgConf f, takeBaseName f /= pid ]
    
    419
    +        liftIO $ writeUTF8File (db_path </> pid <.> "conf")
    
    420
    +                               (CP.showInstalledPackageInfo installedPkgInfo)
    
    398 421
         -- Then after the register, which just writes the .conf file, do the recache step.
    
    399 422
         buildWithResources rs $
    
    400 423
           target context (GhcPkg Recache (stage context)) [] []
    
    401 424
     
    
    402 425
     -- This is copied and simplified from Cabal, because we want to install the package
    
    403 426
     -- into a different package database to the one it was configured against.
    
    404
    -register :: FilePath
    
    405
    -         -> String -- ^ Package Identifier
    
    406
    -         -> C.PackageDescription
    
    407
    -         -> LocalBuildInfo
    
    408
    -         -> IO ()
    
    409
    -register pkg_db pid pd lbi
    
    410
    -  = withLibLBI pd lbi $ \lib clbi -> do
    
    411
    -
    
    412
    -    when reloc $ error "register does not support reloc"
    
    413
    -    installedPkgInfo <- generateRegistrationInfo pd lbi lib clbi
    
    414
    -    writeRegistrationFile installedPkgInfo
    
    415
    -
    
    416
    -  where
    
    417
    -    regFile   = pkg_db </> pid <.> "conf"
    
    418
    -    reloc     = relocatable lbi
    
    419
    -
    
    420
    -    generateRegistrationInfo pkg lbi lib clbi = do
    
    421
    -      abi_hash <- C.mkAbiHash <$> GHC.libAbiHash C.silent pkg lbi lib clbi
    
    422
    -      return (C.absoluteInstalledPackageInfo pkg abi_hash lib lbi clbi)
    
    423
    -
    
    424
    -    writeRegistrationFile installedPkgInfo = do
    
    425
    -      writeUTF8File regFile (CP.showInstalledPackageInfo installedPkgInfo)
    
    427
    +-- See generateRegistrationInfo in Distribution.Simple.Register. we can't use it
    
    428
    +-- directly because it computes the abi-hash using Cabal's internal package
    
    429
    +-- database, which hadrian never creates.
    
    430
    +generateRegistrationInfo :: C.PackageDescription
    
    431
    +                         -> LocalBuildInfo
    
    432
    +                         -> IO Installed.InstalledPackageInfo
    
    433
    +generateRegistrationInfo pd lbi = do
    
    434
    +    when (relocatable lbi) $ error "register does not support reloc"
    
    435
    +    case [ (lib, targetCLBI tgt) | tgt <- allTargetsInBuildOrder' pd lbi
    
    436
    +                                 , CLib lib <- [targetComponent tgt] ] of
    
    437
    +      [(lib, clbi)] -> do
    
    438
    +        abi_hash <- C.mkAbiHash <$> GHC.libAbiHash C.silent pd lbi lib clbi
    
    439
    +        return (C.absoluteInstalledPackageInfo pd abi_hash lib lbi clbi)
    
    440
    +      libs -> error $ "generateRegistrationInfo: expected exactly one library for "
    
    441
    +                   ++ C.display (C.package pd) ++ ", got " ++ show (length libs)
    
    426 442
     
    
    427 443
     
    
    428 444
     -- | Build autogenerated files @autogen/cabal_macros.h@ and @autogen/Paths_*.hs@.
    

  • rts/Capability.c
    ... ... @@ -443,13 +443,6 @@ void
    443 443
     moreCapabilities (uint32_t from USED_IF_THREADS, uint32_t to USED_IF_THREADS)
    
    444 444
     {
    
    445 445
     #if defined(THREADED_RTS)
    
    446
    -    // We must disable the timer while we do this since the tick handler may
    
    447
    -    // call contextSwitchAllCapabilities, which may see the capabilities array
    
    448
    -    // as we free it. The alternative would be to protect the capabilities
    
    449
    -    // array with a lock but this seems more expensive than necessary.
    
    450
    -    // See #17289.
    
    451
    -    stopTimer();
    
    452
    -
    
    453 446
         if (to == 1) {
    
    454 447
             // THREADED_RTS must work on builds that don't have a mutable
    
    455 448
             // BaseReg (eg. unregisterised), so in this case
    
    ... ... @@ -470,8 +463,6 @@ moreCapabilities (uint32_t from USED_IF_THREADS, uint32_t to USED_IF_THREADS)
    470 463
         }
    
    471 464
     
    
    472 465
         debugTrace(DEBUG_sched, "allocated %d more capabilities", to - from);
    
    473
    -
    
    474
    -    startTimer();
    
    475 466
     #endif
    
    476 467
     }
    
    477 468
     
    

  • rts/Schedule.c
    ... ... @@ -37,6 +37,7 @@
    37 37
     #include "win32/AsyncWinIO.h"
    
    38 38
     #endif
    
    39 39
     #include "Trace.h"
    
    40
    +#include "eventlog/EventLog.h"
    
    40 41
     #include "RaiseAsync.h"
    
    41 42
     #include "Threads.h"
    
    42 43
     #include "Timer.h"
    
    ... ... @@ -2100,24 +2101,31 @@ forkProcess(HsStablePtr *entry
    2100 2101
         ACQUIRE_LOCK(&all_tasks_mutex);
    
    2101 2102
     #endif
    
    2102 2103
     
    
    2103
    -    stopTimer(); // See #4074
    
    2104
    -
    
    2105 2104
     #if defined(TRACING)
    
    2106
    -    flushAllCapsEventsBufs(); // so that child won't inherit dirty file buffers
    
    2105
    +#if defined(HAVE_PREEMPTION)
    
    2106
    +    // We must hold the eventlog global mutex over the fork to prevent the
    
    2107
    +    // timer thread from trying to post events. While holding the mutex we need
    
    2108
    +    // to flush the eventlogs (global and per-cap) so that child won't inherit
    
    2109
    +    // dirty eventlog buffers or file buffers.
    
    2110
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    2111
    +#endif
    
    2112
    +    flushAllCapsEventsBufs_();
    
    2107 2113
     #endif
    
    2108 2114
     
    
    2109 2115
         pid = fork();
    
    2110 2116
     
    
    2111 2117
         if (pid) { // parent
    
    2112 2118
     
    
    2113
    -        startTimer(); // #4074
    
    2114
    -
    
    2115 2119
             RELEASE_LOCK(&sched_mutex);
    
    2116 2120
             RELEASE_LOCK(&sm_mutex);
    
    2117 2121
             RELEASE_LOCK(&stable_ptr_mutex);
    
    2118 2122
             RELEASE_LOCK(&stable_name_mutex);
    
    2119 2123
             RELEASE_LOCK(&task->lock);
    
    2120 2124
     
    
    2125
    +#if defined(TRACING) && defined(HAVE_PREEMPTION)
    
    2126
    +        RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    2127
    +#endif
    
    2128
    +
    
    2121 2129
     #if defined(THREADED_RTS)
    
    2122 2130
             /* N.B. releaseCapability_ below may need to take all_tasks_mutex */
    
    2123 2131
             RELEASE_LOCK(&all_tasks_mutex);
    
    ... ... @@ -2303,12 +2311,6 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
    2303 2311
         cap = rts_lock();
    
    2304 2312
         task = cap->running_task;
    
    2305 2313
     
    
    2306
    -
    
    2307
    -    // N.B. We must stop the interval timer while we are changing the
    
    2308
    -    // capabilities array lest handle_tick may try to context switch
    
    2309
    -    // an old capability. See #17289.
    
    2310
    -    stopTimer();
    
    2311
    -
    
    2312 2314
         stopAllCapabilities(&cap, task);
    
    2313 2315
     
    
    2314 2316
         if (new_n_capabilities < enabled_capabilities)
    
    ... ... @@ -2364,9 +2366,7 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
    2364 2366
                 tracingAddCapabilities(n_capabilities, new_n_capabilities);
    
    2365 2367
     #endif
    
    2366 2368
     
    
    2367
    -            // Resize the capabilities array
    
    2368
    -            // NB. after this, capabilities points somewhere new.  Any pointers
    
    2369
    -            // of type (Capability *) are now invalid.
    
    2369
    +            // Allocate and initialise the extra capabilities
    
    2370 2370
                 moreCapabilities(n_capabilities, new_n_capabilities);
    
    2371 2371
     
    
    2372 2372
                 // Resize and update storage manager data structures
    
    ... ... @@ -2394,8 +2394,6 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
    2394 2394
         // Notify IO manager that the number of capabilities has changed.
    
    2395 2395
         notifyIOManagerCapabilitiesChanged(&cap);
    
    2396 2396
     
    
    2397
    -    startTimer();
    
    2398
    -
    
    2399 2397
         rts_unlock(cap);
    
    2400 2398
     
    
    2401 2399
     #endif // THREADED_RTS
    

  • rts/Timer.c
    ... ... @@ -28,11 +28,6 @@
    28 28
     #include "RtsSignals.h"
    
    29 29
     #include "rts/EventLogWriter.h"
    
    30 30
     
    
    31
    -// See Note [No timer on wasm32]
    
    32
    -#if !defined(wasm32_HOST_ARCH)
    
    33
    -#define HAVE_PREEMPTION
    
    34
    -#endif
    
    35
    -
    
    36 31
     // This global counter is used to allow multiple threads to stop the
    
    37 32
     // timer temporarily with a stopTimer()/startTimer() pair.  If
    
    38 33
     //      timer_enabled  == 0          timer is enabled
    

  • rts/eventlog/EventLog.c
    ... ... @@ -129,8 +129,11 @@ typedef struct _EventsBuf {
    129 129
     static EventsBuf *capEventBuf; // one EventsBuf for each Capability
    
    130 130
     
    
    131 131
     static EventsBuf eventBuf; // an EventsBuf not associated with any Capability
    
    132
    -#if defined(THREADED_RTS)
    
    133
    -static Mutex eventBufMutex; // protected by this mutex
    
    132
    +#if defined(HAVE_PREEMPTION)
    
    133
    +// Note that this mutex is used even in the non-threaded RTS, since the timer
    
    134
    +// thread posts events and flushes. So _all_ uses of this mutex must use
    
    135
    +// ACQUIRE_LOCK_ALWAYS/RELEASE_LOCK_ALWAYS.
    
    136
    +Mutex eventBufMutex; // protects eventBuf above
    
    134 137
     #endif
    
    135 138
     
    
    136 139
     // Event type
    
    ... ... @@ -393,8 +396,10 @@ initEventLogging(void)
    393 396
         moreCapEventBufs(0, get_n_capabilities());
    
    394 397
     
    
    395 398
         initEventsBuf(&eventBuf, EVENT_LOG_SIZE, (EventCapNo)(-1));
    
    396
    -#if defined(THREADED_RTS)
    
    399
    +#if defined(HAVE_PREEMPTION)
    
    397 400
         initMutex(&eventBufMutex);
    
    401
    +#endif
    
    402
    +#if defined(THREADED_RTS)
    
    398 403
         initMutex(&state_change_mutex);
    
    399 404
     #endif
    
    400 405
     }
    
    ... ... @@ -416,7 +421,7 @@ startEventLogging_(void)
    416 421
     {
    
    417 422
         initEventLogWriter();
    
    418 423
     
    
    419
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    424
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    420 425
         postHeaderEvents();
    
    421 426
     
    
    422 427
         /*
    
    ... ... @@ -425,7 +430,7 @@ startEventLogging_(void)
    425 430
          */
    
    426 431
         printAndClearEventBuf(&eventBuf);
    
    427 432
     
    
    428
    -    RELEASE_LOCK(&eventBufMutex);
    
    433
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    429 434
     
    
    430 435
         return true;
    
    431 436
     }
    
    ... ... @@ -495,7 +500,7 @@ endEventLogging(void)
    495 500
     
    
    496 501
         flushEventLog_(NULL);
    
    497 502
     
    
    498
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    503
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    499 504
     
    
    500 505
         // Mark end of events (data).
    
    501 506
         postEventTypeNum(&eventBuf, EVENT_DATA_END);
    
    ... ... @@ -503,7 +508,7 @@ endEventLogging(void)
    503 508
         // Flush the end of data marker.
    
    504 509
         printAndClearEventBuf(&eventBuf);
    
    505 510
     
    
    506
    -    RELEASE_LOCK(&eventBufMutex);
    
    511
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    507 512
     
    
    508 513
         stopEventLogWriter();
    
    509 514
         event_log_writer = NULL;
    
    ... ... @@ -666,7 +671,7 @@ void
    666 671
     postCapEvent (EventTypeNum  tag,
    
    667 672
                   EventCapNo    capno)
    
    668 673
     {
    
    669
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    674
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    670 675
         ensureRoomForEvent(&eventBuf, tag);
    
    671 676
     
    
    672 677
         postEventHeader(&eventBuf, tag);
    
    ... ... @@ -685,14 +690,14 @@ postCapEvent (EventTypeNum tag,
    685 690
             barf("postCapEvent: unknown event tag %d", tag);
    
    686 691
         }
    
    687 692
     
    
    688
    -    RELEASE_LOCK(&eventBufMutex);
    
    693
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    689 694
     }
    
    690 695
     
    
    691 696
     void postCapsetEvent (EventTypeNum tag,
    
    692 697
                           EventCapsetID capset,
    
    693 698
                           StgWord info)
    
    694 699
     {
    
    695
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    700
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    696 701
         ensureRoomForEvent(&eventBuf, tag);
    
    697 702
     
    
    698 703
         postEventHeader(&eventBuf, tag);
    
    ... ... @@ -726,7 +731,7 @@ void postCapsetEvent (EventTypeNum tag,
    726 731
             barf("postCapsetEvent: unknown event tag %d", tag);
    
    727 732
         }
    
    728 733
     
    
    729
    -    RELEASE_LOCK(&eventBufMutex);
    
    734
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    730 735
     }
    
    731 736
     
    
    732 737
     void postCapsetStrEvent (EventTypeNum tag,
    
    ... ... @@ -740,14 +745,14 @@ void postCapsetStrEvent (EventTypeNum tag,
    740 745
             return;
    
    741 746
         }
    
    742 747
     
    
    743
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    748
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    744 749
     
    
    745 750
         if (!hasRoomForVariableEvent(&eventBuf, size)){
    
    746 751
             printAndClearEventBuf(&eventBuf);
    
    747 752
     
    
    748 753
             if (!hasRoomForVariableEvent(&eventBuf, size)){
    
    749 754
                 errorBelch("Event size exceeds buffer size, bail out");
    
    750
    -            RELEASE_LOCK(&eventBufMutex);
    
    755
    +            RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    751 756
                 return;
    
    752 757
             }
    
    753 758
         }
    
    ... ... @@ -758,7 +763,7 @@ void postCapsetStrEvent (EventTypeNum tag,
    758 763
     
    
    759 764
         postBuf(&eventBuf, (StgWord8*) msg, strsize);
    
    760 765
     
    
    761
    -    RELEASE_LOCK(&eventBufMutex);
    
    766
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    762 767
     }
    
    763 768
     
    
    764 769
     void postCapsetVecEvent (EventTypeNum tag,
    
    ... ... @@ -783,14 +788,14 @@ void postCapsetVecEvent (EventTypeNum tag,
    783 788
             }
    
    784 789
         }
    
    785 790
     
    
    786
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    791
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    787 792
     
    
    788 793
         if (!hasRoomForVariableEvent(&eventBuf, size)){
    
    789 794
             printAndClearEventBuf(&eventBuf);
    
    790 795
     
    
    791 796
             if(!hasRoomForVariableEvent(&eventBuf, size)){
    
    792 797
                 errorBelch("Event size exceeds buffer size, bail out");
    
    793
    -            RELEASE_LOCK(&eventBufMutex);
    
    798
    +            RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    794 799
                 return;
    
    795 800
             }
    
    796 801
         }
    
    ... ... @@ -804,7 +809,7 @@ void postCapsetVecEvent (EventTypeNum tag,
    804 809
             postBuf(&eventBuf, (StgWord8*) argv[i], 1 + strlen(argv[i]));
    
    805 810
         }
    
    806 811
     
    
    807
    -    RELEASE_LOCK(&eventBufMutex);
    
    812
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    808 813
     }
    
    809 814
     
    
    810 815
     void postWallClockTime (EventCapsetID capset)
    
    ... ... @@ -813,7 +818,7 @@ void postWallClockTime (EventCapsetID capset)
    813 818
         StgWord64 sec;
    
    814 819
         StgWord32 nsec;
    
    815 820
     
    
    816
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    821
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    817 822
     
    
    818 823
         /* The EVENT_WALL_CLOCK_TIME event is intended to allow programs
    
    819 824
            reading the eventlog to match up the event timestamps with wall
    
    ... ... @@ -846,7 +851,7 @@ void postWallClockTime (EventCapsetID capset)
    846 851
         postWord64(&eventBuf, sec);
    
    847 852
         postWord32(&eventBuf, nsec);
    
    848 853
     
    
    849
    -    RELEASE_LOCK(&eventBufMutex);
    
    854
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    850 855
     }
    
    851 856
     
    
    852 857
     /*
    
    ... ... @@ -885,7 +890,7 @@ void postEventHeapInfo (EventCapsetID heap_capset,
    885 890
                             W_          mblockSize,
    
    886 891
                             W_          blockSize)
    
    887 892
     {
    
    888
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    893
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    889 894
         ensureRoomForEvent(&eventBuf, EVENT_HEAP_INFO_GHC);
    
    890 895
     
    
    891 896
         postEventHeader(&eventBuf, EVENT_HEAP_INFO_GHC);
    
    ... ... @@ -899,7 +904,7 @@ void postEventHeapInfo (EventCapsetID heap_capset,
    899 904
         postWord64(&eventBuf, mblockSize);
    
    900 905
         postWord64(&eventBuf, blockSize);
    
    901 906
     
    
    902
    -    RELEASE_LOCK(&eventBufMutex);
    
    907
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    903 908
     }
    
    904 909
     
    
    905 910
     void postEventGcStats  (Capability    *cap,
    
    ... ... @@ -952,7 +957,7 @@ void postTaskCreateEvent (EventTaskId taskId,
    952 957
                               EventCapNo capno,
    
    953 958
                               EventKernelThreadId tid)
    
    954 959
     {
    
    955
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    960
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    956 961
         ensureRoomForEvent(&eventBuf, EVENT_TASK_CREATE);
    
    957 962
     
    
    958 963
         postEventHeader(&eventBuf, EVENT_TASK_CREATE);
    
    ... ... @@ -961,14 +966,14 @@ void postTaskCreateEvent (EventTaskId taskId,
    961 966
         postCapNo(&eventBuf, capno);
    
    962 967
         postKernelThreadId(&eventBuf, tid);
    
    963 968
     
    
    964
    -    RELEASE_LOCK(&eventBufMutex);
    
    969
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    965 970
     }
    
    966 971
     
    
    967 972
     void postTaskMigrateEvent (EventTaskId taskId,
    
    968 973
                                EventCapNo capno,
    
    969 974
                                EventCapNo new_capno)
    
    970 975
     {
    
    971
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    976
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    972 977
         ensureRoomForEvent(&eventBuf, EVENT_TASK_MIGRATE);
    
    973 978
     
    
    974 979
         postEventHeader(&eventBuf, EVENT_TASK_MIGRATE);
    
    ... ... @@ -977,28 +982,28 @@ void postTaskMigrateEvent (EventTaskId taskId,
    977 982
         postCapNo(&eventBuf, capno);
    
    978 983
         postCapNo(&eventBuf, new_capno);
    
    979 984
     
    
    980
    -    RELEASE_LOCK(&eventBufMutex);
    
    985
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    981 986
     }
    
    982 987
     
    
    983 988
     void postTaskDeleteEvent (EventTaskId taskId)
    
    984 989
     {
    
    985
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    990
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    986 991
         ensureRoomForEvent(&eventBuf, EVENT_TASK_DELETE);
    
    987 992
     
    
    988 993
         postEventHeader(&eventBuf, EVENT_TASK_DELETE);
    
    989 994
         /* EVENT_TASK_DELETE (taskID) */
    
    990 995
         postTaskId(&eventBuf, taskId);
    
    991 996
     
    
    992
    -    RELEASE_LOCK(&eventBufMutex);
    
    997
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    993 998
     }
    
    994 999
     
    
    995 1000
     void
    
    996 1001
     postEventNoCap (EventTypeNum tag)
    
    997 1002
     {
    
    998
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1003
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    999 1004
         ensureRoomForEvent(&eventBuf, tag);
    
    1000 1005
         postEventHeader(&eventBuf, tag);
    
    1001
    -    RELEASE_LOCK(&eventBufMutex);
    
    1006
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1002 1007
     }
    
    1003 1008
     
    
    1004 1009
     void
    
    ... ... @@ -1042,9 +1047,9 @@ void postLogMsg(EventsBuf *eb, EventTypeNum type, char *msg, va_list ap)
    1042 1047
     
    
    1043 1048
     void postMsg(char *msg, va_list ap)
    
    1044 1049
     {
    
    1045
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1050
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1046 1051
         postLogMsg(&eventBuf, EVENT_LOG_MSG, msg, ap);
    
    1047
    -    RELEASE_LOCK(&eventBufMutex);
    
    1052
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1048 1053
     }
    
    1049 1054
     
    
    1050 1055
     void postCapMsg(Capability *cap, char *msg, va_list ap)
    
    ... ... @@ -1138,32 +1143,32 @@ void postConcUpdRemSetFlush(Capability *cap)
    1138 1143
     
    
    1139 1144
     void postConcMarkEnd(StgWord32 marked_obj_count)
    
    1140 1145
     {
    
    1141
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1146
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1142 1147
         ensureRoomForEvent(&eventBuf, EVENT_CONC_MARK_END);
    
    1143 1148
         postEventHeader(&eventBuf, EVENT_CONC_MARK_END);
    
    1144 1149
         postWord32(&eventBuf, marked_obj_count);
    
    1145
    -    RELEASE_LOCK(&eventBufMutex);
    
    1150
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1146 1151
     }
    
    1147 1152
     
    
    1148 1153
     void postNonmovingHeapCensus(uint16_t blk_size,
    
    1149 1154
                                  const struct NonmovingAllocCensus *census)
    
    1150 1155
     {
    
    1151
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1156
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1152 1157
         postEventHeader(&eventBuf, EVENT_NONMOVING_HEAP_CENSUS);
    
    1153 1158
         postWord16(&eventBuf, blk_size);
    
    1154 1159
         postWord32(&eventBuf, census->n_active_segs);
    
    1155 1160
         postWord32(&eventBuf, census->n_filled_segs);
    
    1156 1161
         postWord32(&eventBuf, census->n_live_blocks);
    
    1157
    -    RELEASE_LOCK(&eventBufMutex);
    
    1162
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1158 1163
     }
    
    1159 1164
     
    
    1160 1165
     void postNonmovingPrunedSegments(uint32_t pruned_segments, uint32_t free_segments)
    
    1161 1166
     {
    
    1162
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1167
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1163 1168
         postEventHeader(&eventBuf, EVENT_NONMOVING_PRUNED_SEGMENTS);
    
    1164 1169
         postWord32(&eventBuf, pruned_segments);
    
    1165 1170
         postWord32(&eventBuf, free_segments);
    
    1166
    -    RELEASE_LOCK(&eventBufMutex);
    
    1171
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1167 1172
     }
    
    1168 1173
     
    
    1169 1174
     void closeBlockMarker (EventsBuf *ebuf)
    
    ... ... @@ -1224,7 +1229,7 @@ static HeapProfBreakdown getHeapProfBreakdown(void)
    1224 1229
     
    
    1225 1230
     void postHeapProfBegin(void)
    
    1226 1231
     {
    
    1227
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1232
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1228 1233
         PROFILING_FLAGS *flags = &RtsFlags.ProfFlags;
    
    1229 1234
         StgWord modSelector_len   =
    
    1230 1235
             flags->modSelector ? strlen(flags->modSelector) : 0;
    
    ... ... @@ -1258,42 +1263,42 @@ void postHeapProfBegin(void)
    1258 1263
         postStringLen(&eventBuf, flags->ccsSelector, ccsSelector_len);
    
    1259 1264
         postStringLen(&eventBuf, flags->retainerSelector, retainerSelector_len);
    
    1260 1265
         postStringLen(&eventBuf, flags->bioSelector, bioSelector_len);
    
    1261
    -    RELEASE_LOCK(&eventBufMutex);
    
    1266
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1262 1267
     }
    
    1263 1268
     
    
    1264 1269
     void postHeapProfSampleBegin(StgInt era)
    
    1265 1270
     {
    
    1266
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1271
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1267 1272
         ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN);
    
    1268 1273
         postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_BEGIN);
    
    1269 1274
         postWord64(&eventBuf, era);
    
    1270
    -    RELEASE_LOCK(&eventBufMutex);
    
    1275
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1271 1276
     }
    
    1272 1277
     
    
    1273 1278
     
    
    1274 1279
     void postHeapBioProfSampleBegin(StgInt era, StgWord64 time)
    
    1275 1280
     {
    
    1276
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1281
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1277 1282
         ensureRoomForEvent(&eventBuf, EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN);
    
    1278 1283
         postEventHeader(&eventBuf, EVENT_HEAP_BIO_PROF_SAMPLE_BEGIN);
    
    1279 1284
         postWord64(&eventBuf, era);
    
    1280 1285
         postWord64(&eventBuf, time);
    
    1281
    -    RELEASE_LOCK(&eventBufMutex);
    
    1286
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1282 1287
     }
    
    1283 1288
     
    
    1284 1289
     void postHeapProfSampleEnd(StgInt era)
    
    1285 1290
     {
    
    1286
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1291
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1287 1292
         ensureRoomForEvent(&eventBuf, EVENT_HEAP_PROF_SAMPLE_END);
    
    1288 1293
         postEventHeader(&eventBuf, EVENT_HEAP_PROF_SAMPLE_END);
    
    1289 1294
         postWord64(&eventBuf, era);
    
    1290
    -    RELEASE_LOCK(&eventBufMutex);
    
    1295
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1291 1296
     }
    
    1292 1297
     
    
    1293 1298
     void postHeapProfSampleString(const char *label,
    
    1294 1299
                                   StgWord64 residency)
    
    1295 1300
     {
    
    1296
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1301
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1297 1302
         StgWord label_len = strlen(label);
    
    1298 1303
         StgWord len = 1+8+label_len+1;
    
    1299 1304
         CHECK(!ensureRoomForVariableEvent(&eventBuf, len));
    
    ... ... @@ -1303,7 +1308,7 @@ void postHeapProfSampleString(const char *label,
    1303 1308
         postWord8(&eventBuf, 0);
    
    1304 1309
         postWord64(&eventBuf, residency);
    
    1305 1310
         postStringLen(&eventBuf, label, label_len);
    
    1306
    -    RELEASE_LOCK(&eventBufMutex);
    
    1311
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1307 1312
     }
    
    1308 1313
     
    
    1309 1314
     #if defined(PROFILING)
    
    ... ... @@ -1313,7 +1318,7 @@ void postHeapProfCostCentre(StgWord32 ccID,
    1313 1318
                                 const char *srcloc,
    
    1314 1319
                                 StgBool is_caf)
    
    1315 1320
     {
    
    1316
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1321
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1317 1322
         StgWord label_len = strlen(label);
    
    1318 1323
         StgWord module_len = strlen(module);
    
    1319 1324
         StgWord srcloc_len = strlen(srcloc);
    
    ... ... @@ -1326,13 +1331,13 @@ void postHeapProfCostCentre(StgWord32 ccID,
    1326 1331
         postStringLen(&eventBuf, module, module_len);
    
    1327 1332
         postStringLen(&eventBuf, srcloc, srcloc_len);
    
    1328 1333
         postWord8(&eventBuf, is_caf);
    
    1329
    -    RELEASE_LOCK(&eventBufMutex);
    
    1334
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1330 1335
     }
    
    1331 1336
     
    
    1332 1337
     void postHeapProfSampleCostCentre(CostCentreStack *stack,
    
    1333 1338
                                       StgWord64 residency)
    
    1334 1339
     {
    
    1335
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1340
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1336 1341
         StgWord depth = 0;
    
    1337 1342
         CostCentreStack *ccs;
    
    1338 1343
         for (ccs = stack; ccs != NULL && ccs != CCS_MAIN; ccs = ccs->prevStack)
    
    ... ... @@ -1351,7 +1356,7 @@ void postHeapProfSampleCostCentre(CostCentreStack *stack,
    1351 1356
              depth>0 && ccs != NULL && ccs != CCS_MAIN;
    
    1352 1357
              ccs = ccs->prevStack, depth--)
    
    1353 1358
             postWord32(&eventBuf, ccs->cc->ccID);
    
    1354
    -    RELEASE_LOCK(&eventBufMutex);
    
    1359
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1355 1360
     }
    
    1356 1361
     
    
    1357 1362
     
    
    ... ... @@ -1359,7 +1364,7 @@ void postProfSampleCostCentre(Capability *cap,
    1359 1364
                                   CostCentreStack *stack,
    
    1360 1365
                                   StgWord64 tick)
    
    1361 1366
     {
    
    1362
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1367
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1363 1368
         StgWord depth = 0;
    
    1364 1369
         CostCentreStack *ccs;
    
    1365 1370
         for (ccs = stack; ccs != NULL && ccs != CCS_MAIN; ccs = ccs->prevStack)
    
    ... ... @@ -1377,7 +1382,7 @@ void postProfSampleCostCentre(Capability *cap,
    1377 1382
              depth>0 && ccs != NULL && ccs != CCS_MAIN;
    
    1378 1383
              ccs = ccs->prevStack, depth--)
    
    1379 1384
             postWord32(&eventBuf, ccs->cc->ccID);
    
    1380
    -    RELEASE_LOCK(&eventBufMutex);
    
    1385
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1381 1386
     }
    
    1382 1387
     
    
    1383 1388
     // This event is output at the start of profiling so the tick interval can
    
    ... ... @@ -1385,11 +1390,11 @@ void postProfSampleCostCentre(Capability *cap,
    1385 1390
     // can be calculated from how many samples there are.
    
    1386 1391
     void postProfBegin(void)
    
    1387 1392
     {
    
    1388
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1393
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1389 1394
         postEventHeader(&eventBuf, EVENT_PROF_BEGIN);
    
    1390 1395
         // The interval that each tick was sampled, in nanoseconds
    
    1391 1396
         postWord64(&eventBuf, TimeToNS(RtsFlags.MiscFlags.tickInterval));
    
    1392
    -    RELEASE_LOCK(&eventBufMutex);
    
    1397
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1393 1398
     }
    
    1394 1399
     #endif /* PROFILING */
    
    1395 1400
     
    
    ... ... @@ -1415,11 +1420,11 @@ static void postTickyCounterDef(EventsBuf *eb, StgEntCounter *p)
    1415 1420
     
    
    1416 1421
     void postTickyCounterDefs(StgEntCounter *counters)
    
    1417 1422
     {
    
    1418
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1423
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1419 1424
         for (StgEntCounter *p = counters; p != NULL; p = p->link) {
    
    1420 1425
             postTickyCounterDef(&eventBuf, p);
    
    1421 1426
         }
    
    1422
    -    RELEASE_LOCK(&eventBufMutex);
    
    1427
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1423 1428
     }
    
    1424 1429
     
    
    1425 1430
     static void postTickyCounterSample(EventsBuf *eb, StgEntCounter *p)
    
    ... ... @@ -1443,13 +1448,13 @@ static void postTickyCounterSample(EventsBuf *eb, StgEntCounter *p)
    1443 1448
     
    
    1444 1449
     void postTickyCounterSamples(StgEntCounter *counters)
    
    1445 1450
     {
    
    1446
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1451
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1447 1452
         ensureRoomForEvent(&eventBuf, EVENT_TICKY_COUNTER_SAMPLE);
    
    1448 1453
         postEventHeader(&eventBuf, EVENT_TICKY_COUNTER_BEGIN_SAMPLE);
    
    1449 1454
         for (StgEntCounter *p = counters; p != NULL; p = p->link) {
    
    1450 1455
             postTickyCounterSample(&eventBuf, p);
    
    1451 1456
         }
    
    1452
    -    RELEASE_LOCK(&eventBufMutex);
    
    1457
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1453 1458
     }
    
    1454 1459
     #endif /* TICKY_TICKY */
    
    1455 1460
     void postIPE(const InfoProvEnt *ipe)
    
    ... ... @@ -1459,7 +1464,7 @@ void postIPE(const InfoProvEnt *ipe)
    1459 1464
     
    
    1460 1465
         // See Note [Maximum event length].
    
    1461 1466
         const StgWord MAX_IPE_STRING_LEN = 65535;
    
    1462
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1467
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1463 1468
         StgWord table_name_len = MIN(strlen(ipe->prov.table_name), MAX_IPE_STRING_LEN);
    
    1464 1469
         StgWord closure_desc_len = MIN(strlen(closure_desc_buf), MAX_IPE_STRING_LEN);
    
    1465 1470
         StgWord ty_desc_len = MIN(strlen(ipe->prov.ty_desc), MAX_IPE_STRING_LEN);
    
    ... ... @@ -1489,7 +1494,7 @@ void postIPE(const InfoProvEnt *ipe)
    1489 1494
         postBuf(&eventBuf, &colon, 1);
    
    1490 1495
         postStringLen(&eventBuf, ipe->prov.src_span, src_span_len);
    
    1491 1496
     
    
    1492
    -    RELEASE_LOCK(&eventBufMutex);
    
    1497
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1493 1498
     }
    
    1494 1499
     
    
    1495 1500
     void printAndClearEventBuf (EventsBuf *ebuf)
    
    ... ... @@ -1601,14 +1606,21 @@ void flushLocalEventsBuf(Capability *cap)
    1601 1606
     // Flush all capabilities' event buffers when we already hold all capabilities.
    
    1602 1607
     // Used during forkProcess.
    
    1603 1608
     void flushAllCapsEventsBufs(void)
    
    1609
    +{
    
    1610
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1611
    +    flushAllCapsEventsBufs_();
    
    1612
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1613
    +}
    
    1614
    +
    
    1615
    +// Unsafe version that does not acquire/release eventBufMutex. You must
    
    1616
    +// hold the eventBufMutex, which you must acquire with ACQUIRE_LOCK_ALWAYS!
    
    1617
    +void flushAllCapsEventsBufs_(void)
    
    1604 1618
     {
    
    1605 1619
         if (!event_log_writer) {
    
    1606 1620
             return;
    
    1607 1621
         }
    
    1608 1622
     
    
    1609
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1610 1623
         printAndClearEventBuf(&eventBuf);
    
    1611
    -    RELEASE_LOCK(&eventBufMutex);
    
    1612 1624
     
    
    1613 1625
         for (unsigned int i=0; i < getNumCapabilities(); i++) {
    
    1614 1626
             flushLocalEventsBuf(getCapability(i));
    
    ... ... @@ -1641,9 +1653,9 @@ static void flushEventLog_(Capability **cap USED_IF_THREADS)
    1641 1653
           return;
    
    1642 1654
         }
    
    1643 1655
     
    
    1644
    -    ACQUIRE_LOCK(&eventBufMutex);
    
    1656
    +    ACQUIRE_LOCK_ALWAYS(&eventBufMutex);
    
    1645 1657
         printAndClearEventBuf(&eventBuf);
    
    1646
    -    RELEASE_LOCK(&eventBufMutex);
    
    1658
    +    RELEASE_LOCK_ALWAYS(&eventBufMutex);
    
    1647 1659
     
    
    1648 1660
     #if defined(THREADED_RTS)
    
    1649 1661
         Task *task = newBoundTask();
    

  • rts/eventlog/EventLog.h
    ... ... @@ -18,6 +18,13 @@
    18 18
     #if defined(TRACING)
    
    19 19
     
    
    20 20
     extern bool eventlog_enabled;
    
    21
    +#if defined(HAVE_PREEMPTION)
    
    22
    +// Avoid using this mutex directly if at all possible. It is needed in the
    
    23
    +// implementation of forkProcess.
    
    24
    +//
    
    25
    +// All uses of this mutex must use ACQUIRE_LOCK_ALWAYS/RELEASE_LOCK_ALWAYS.
    
    26
    +extern Mutex eventBufMutex;
    
    27
    +#endif
    
    21 28
     
    
    22 29
     void initEventLogging(void);
    
    23 30
     void restartEventLogging(void);
    
    ... ... @@ -27,6 +34,7 @@ void abortEventLogging(void); // #4512 - after fork child needs to abort
    27 34
     void moreCapEventBufs (uint32_t from, uint32_t to);
    
    28 35
     void flushLocalEventsBuf(Capability *cap);
    
    29 36
     void flushAllCapsEventsBufs(void);
    
    37
    +void flushAllCapsEventsBufs_(void);
    
    30 38
     void flushAllEventsBufs(Capability *cap);
    
    31 39
     
    
    32 40
     typedef void (*EventlogInitPost)(void);
    

  • rts/include/rts/OSThreads.h
    ... ... @@ -14,6 +14,46 @@
    14 14
     
    
    15 15
     #pragma once
    
    16 16
     
    
    17
    +/* Note [Threads and preemption]
    
    18
    +   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    19
    +   All full-fat OSs that GHC works on have OS threads, and we use them even in
    
    20
    +   the non-threaded RTS for a few features:
    
    21
    +    * Haskell thread preemption;
    
    22
    +    * sample-based profiling;
    
    23
    +    * idle GC;
    
    24
    +    * periodic eventlog flushing.
    
    25
    +
    
    26
    +   We use defined(HAVE_PREEMPTION) to decide if these features are implemented
    
    27
    +   via OS threads.
    
    28
    +
    
    29
    +   On platforms like WASM/js we do not have OS threads in any conventional
    
    30
    +   sense, and the features above are either not available or are implemented
    
    31
    +   differently. See Note [No timer on wasm32].
    
    32
    +
    
    33
    +   In future if GHC is ported to platforms like bare-metal micro-controllers,
    
    34
    +   RTOSs or to run directly under hypervisors then such platforms may also not
    
    35
    +   have threads available and they should not define HAVE_PREEMPTION here. Or
    
    36
    +   for some micro-controller RTOSs like Zeypher one may have a choice about
    
    37
    +   whether to use threads or not (at a size cost). Here would be the right
    
    38
    +   place to control whether the feature list above is supported.
    
    39
    + */
    
    40
    +#if defined(wasm32_HOST_ARCH)
    
    41
    +  // See Note [No timer on wasm32]
    
    42
    +  // To confuse matters, WASM _does_ have pthread.h but it doesnt work.
    
    43
    +#elif defined(HAVE_PTHREAD_H) || defined(HAVE_WINDOWS_H)
    
    44
    +#define HAVE_PREEMPTION
    
    45
    +#else
    
    46
    +#error Decide if this platform has threads and pre-emption or not.
    
    47
    +#endif
    
    48
    +// And JS does all of this differently, without using this bit of the RTS.
    
    49
    +
    
    50
    +// Configuration sanity check
    
    51
    +#if defined(THREADED_RTS) && !defined(HAVE_PREEMPTION)
    
    52
    +//TODO we would like to be able to assert this:
    
    53
    +// #error Configuration error: THREADED_RTS should imply HAVE_PREEMPTION
    
    54
    +// however at the moment we cannot due to issue #27346.
    
    55
    +#endif
    
    56
    +
    
    17 57
     #if defined(HAVE_PTHREAD_H) && !defined(mingw32_HOST_OS)
    
    18 58
     
    
    19 59
     #if defined(CMINUSMINUS)
    
    ... ... @@ -210,9 +250,29 @@ extern bool timedWaitCondition ( Condition* pCond, Mutex* pMut, Time timeout)
    210 250
     //
    
    211 251
     // Mutexes
    
    212 252
     //
    
    253
    +// Even in the non-threaded RTS we use threads and mutexes! In particular the
    
    254
    +// timer/ticker is implemented using a thread. And using threads needs locks.
    
    255
    +// In particular we need locks for the data shared between the timer/ticker
    
    256
    +// thread and the thread running the main capability.
    
    257
    +#if defined(HAVE_PREEMPTION)
    
    213 258
     extern void initMutex             ( Mutex* pMut );
    
    214 259
     extern void closeMutex            ( Mutex* pMut );
    
    215 260
     
    
    261
    +// The "always" variants do locking in the threaded and non-threaded RTS.
    
    262
    +// The normal variants below are no-ops in the non-threaded RTS.
    
    263
    +#define ACQUIRE_LOCK_ALWAYS(l) OS_ACQUIRE_LOCK(l)
    
    264
    +#define TRY_ACQUIRE_LOCK_ALWAYS(l) OS_TRY_ACQUIRE_LOCK(l)
    
    265
    +#define RELEASE_LOCK_ALWAYS(l) OS_RELEASE_LOCK(l)
    
    266
    +#define ASSERT_LOCK_HELD_ALWAYS(l) OS_ASSERT_LOCK_HELD(l)
    
    267
    +#else
    
    268
    +// And just to be a bit confusing, the always variants are still no-ops when we
    
    269
    +// do not HAVE_PREEMPTION, since then we don't have threads or mutexes at all.
    
    270
    +#define ACQUIRE_LOCK_ALWAYS(l)
    
    271
    +#define TRY_ACQUIRE_LOCK_ALWAYS(l) 0
    
    272
    +#define RELEASE_LOCK_ALWAYS(l)
    
    273
    +#define ASSERT_LOCK_HELD_ALWAYS(l)
    
    274
    +#endif
    
    275
    +
    
    216 276
     // Processors and affinity
    
    217 277
     void setThreadAffinity (uint32_t n, uint32_t m);
    
    218 278
     void setThreadNode (uint32_t node);
    
    ... ... @@ -228,6 +288,7 @@ void releaseThreadNode (void);
    228 288
     
    
    229 289
     #else
    
    230 290
     
    
    291
    +// No-ops in the non-threaded RTS. See also the _ALWAYS variants above.
    
    231 292
     #define ACQUIRE_LOCK(l)
    
    232 293
     #define TRY_ACQUIRE_LOCK(l) 0
    
    233 294
     #define RELEASE_LOCK(l)
    

  • testsuite/tests/codeGen/should_run/T27046.hs
    1
    +{-# LANGUAGE MagicHash #-}
    
    2
    +{-# LANGUAGE ForeignFunctionInterface, GHCForeignImportPrim, UnliftedFFITypes #-}
    
    3
    +
    
    4
    +module Main where
    
    5
    +
    
    6
    +import Control.Monad
    
    7
    +  ( unless )
    
    8
    +import Data.Bits
    
    9
    +  ( shiftL )
    
    10
    +import GHC.Exts
    
    11
    +  ( Int64# )
    
    12
    +import GHC.Int
    
    13
    +  ( Int64(..) )
    
    14
    +
    
    15
    +foreign import prim "test_mul2_clobber"
    
    16
    +  test_mul2_clobber :: Int64# -> Int64# -> Int64#
    
    17
    +
    
    18
    +main :: IO ()
    
    19
    +main = do
    
    20
    +  let
    
    21
    +    I64# x = 1 `shiftL` 32
    
    22
    +    hi = I64# $ test_mul2_clobber x x
    
    23
    +
    
    24
    +  unless ( hi == 1 ) $
    
    25
    +    error $ unlines
    
    26
    +      [ "Incorrect result for Mul2 operation."
    
    27
    +      , "Expected high word: 1"
    
    28
    +      , "  Actual high word: " ++ show hi
    
    29
    +      ]

  • testsuite/tests/codeGen/should_run/T27046_cmm.cmm
    1
    +#include "Cmm.h"
    
    2
    +
    
    3
    +// Test for #27046
    
    4
    +test_mul2_clobber (bits64 x, bits64 y)
    
    5
    +{
    
    6
    +    bits64 hi, nd;
    
    7
    +
    
    8
    +    // Deliberately alias the destination 'lo' with the source 'x'
    
    9
    +    // This forces the NCG to use the same virtual register for both.
    
    10
    +    (nd, hi, x) = prim %mul2_64(x, y);
    
    11
    +
    
    12
    +    return (hi);
    
    13
    +}

  • testsuite/tests/codeGen/should_run/all.T
    ... ... @@ -260,6 +260,13 @@ test('T25364', normal, compile_and_run, [''])
    260 260
     test('T26061', normal, compile_and_run, [''])
    
    261 261
     test('T26537', normal, compile_and_run, ['-O2 -fregs-graph'])
    
    262 262
     test('T24016', normal, compile_and_run, ['-O1 -fPIC'])
    
    263
    +test('T27046',
    
    264
    +     [ req_cmm
    
    265
    +     , when(arch('i386'), skip) # i386 does not support MO_S_Mul2 W64
    
    266
    +     , when(arch('wasm32'), skip)
    
    267
    +     , js_skip
    
    268
    +     , when(unregisterised(), skip) # pprCallishMachOp_for_C: MO_S_Mul2 W64 not supported
    
    269
    +     ], compile_and_run, ['T27046_cmm.cmm'])
    
    263 270
     
    
    264 271
     # Check that GHC-generated finalizers run on Darwin. The Apple linker doesn't
    
    265 272
     # support --wrap, so we can't intercept hs_spt_remove directly.  Instead we
    

  • testsuite/tests/rts/T27131.hs
    ... ... @@ -30,16 +30,22 @@ foreign import ccall unsafe "has_local_stop_after_return"
    30 30
     main :: IO ()
    
    31 31
     main = do
    
    32 32
       setNumCapabilities 2
    
    33
    -  checkFlag
    
    34
    -    "TSO_STOP_NEXT_BREAKPOINT"
    
    35
    -    rts_enableStopNextBreakpoint
    
    36
    -    rts_disableStopNextBreakpoint
    
    37
    -    c_hasLocalStopNextBreakpoint
    
    38
    -  checkFlag
    
    39
    -    "TSO_STOP_AFTER_RETURN"
    
    40
    -    rts_enableStopAfterReturn
    
    41
    -    rts_disableStopAfterReturn
    
    42
    -    c_hasLocalStopAfterReturn
    
    33
    +  -- Bind to capability 0 so it can't float between capabilities while the
    
    34
    +  -- target thread runs on capability 1.
    
    35
    +  doneVar <- newEmptyMVar
    
    36
    +  _ <- forkOn 0 $ do
    
    37
    +    checkFlag
    
    38
    +      "TSO_STOP_NEXT_BREAKPOINT"
    
    39
    +      rts_enableStopNextBreakpoint
    
    40
    +      rts_disableStopNextBreakpoint
    
    41
    +      c_hasLocalStopNextBreakpoint
    
    42
    +    checkFlag
    
    43
    +      "TSO_STOP_AFTER_RETURN"
    
    44
    +      rts_enableStopAfterReturn
    
    45
    +      rts_disableStopAfterReturn
    
    46
    +      c_hasLocalStopAfterReturn
    
    47
    +    putMVar doneVar ()
    
    48
    +  takeMVar doneVar
    
    43 49
     
    
    44 50
     checkFlag
    
    45 51
       :: String
    
    ... ... @@ -58,6 +64,7 @@ checkFlag label enable disable isMyThreadFlagSet = do
    58 64
       ThreadId tid# <- forkOn 1 $ do
    
    59 65
         replicateM_ 2 $ do
    
    60 66
           replyVar <- takeMVar targetCheckVar
    
    67
    +      yield -- make sure we reprocess the mailbox
    
    61 68
           isSet <- (/= 0) <$> isMyThreadFlagSet
    
    62 69
           putMVar replyVar isSet
    
    63 70
     
    

  • testsuite/tests/rts/T27131.stdout
    1
    -(0,False)
    
    1
    +(0,True)
    
    2 2
     TSO_STOP_NEXT_BREAKPOINT set: ok
    
    3 3
     TSO_STOP_NEXT_BREAKPOINT unset: ok
    
    4
    -(0,False)
    
    4
    +(0,True)
    
    5 5
     TSO_STOP_AFTER_RETURN set: ok
    
    6 6
     TSO_STOP_AFTER_RETURN unset: ok