[Git][ghc/ghc][wip/io-manager-deadlock-detection] 24 commits: Split posix/MIO.c out of posix/Signals.c
by Duncan Coutts (@dcoutts) 11 Mar '26
by Duncan Coutts (@dcoutts) 11 Mar '26
11 Mar '26
Duncan Coutts pushed to branch wip/io-manager-deadlock-detection at Glasgow Haskell Compiler / GHC
Commits:
d1c0af25 by Duncan Coutts at 2026-03-10T22:56:32+00:00
Split posix/MIO.c out of posix/Signals.c
The MIO I/O manager was secretly living inside the Signals file.
Now it gets its own file, like any other self-respecting I/O manager.
- - - - -
21dc121a by Duncan Coutts at 2026-03-10T22:56:32+00:00
Rationalise some scheduler run queue utilities
Move them all to the same place in the file.
Make some static that were used only internally.
Also remove a redundant assignment after calling truncateRunQueue that
is already done within truncateRunQueue.
- - - - -
92e1c233 by Duncan Coutts at 2026-03-10T22:56:32+00:00
Rename initIOManager{AfterFork} to {re}startIOManager
These are more accurate names, since these actions happen after
initialisation and are really about starting (or restarting) background
threads.
- - - - -
f84cc4bd by Duncan Coutts at 2026-03-10T22:56:32+00:00
Add a TODO to the MIO I/O manager
The direction of travel is to make I/O managers per-capability and have
all their state live in the struct CapIOManager. The MIO I/O manager
however still has a number of global variables.
It's not obvious how handle these globals however.
- - - - -
4aa7cd1c by Duncan Coutts at 2026-03-10T22:56:32+00:00
Free per-cap I/O managers during shutdown and forkProcess
Historically this was not strictly necessary. The select and win32
legacy I/O managers did not maintain any dynamically allocated
resources. The new poll one does (an auxillary table), and so this
should be freed.
After forkProcess, all threads get deleted. This includes threads
waiting on I/O or timers. So as of this patch, resetting the I/O
manager is just about tidying things up. For example, for the poll
I/O manager this will reset the size of the AIOP table (which
otherwise grows but never shrinks).
In future however the re-initialising will become neeecessary for
functionality, since some I/O managers will need to re-initialise
wakeup fds that are set CLOEXEC.
- - - - -
8f33ef3a by Duncan Coutts at 2026-03-10T22:56:32+00:00
Add an FdWakup module for posix I/O managers
This will be used to implement wakeupIOManager for in-RTS I/O managers.
It provides a notification/wakeup mechanism using FDs, suitable for
situations when I/O managers are blocked on a set of fds anyway.
- - - - -
7c193c28 by Duncan Coutts at 2026-03-10T22:56:32+00:00
Add wakeupIOManager support for select I/O manager
Uses the FdWakup mechanism.
- - - - -
1028c963 by Duncan Coutts at 2026-03-10T22:56:33+00:00
Add wakeupIOManager support for poll I/O manager
Uses the FdWakup mechanism.
A quirk we have to cope with is that we now need to poll one more fd --
the wakeup_fd_r -- but this fd has no corresponding entry in the
aiop_table. This is awkward since we have set up our aiop_poll_table to
be an auxilliary table with matching indicies.
The solution this patch uses (and described in the comments) is to have
two tables: struct pollfd *aiop_poll_table, *full_poll_table;
and to have the aiop_poll_table alias the tail of the full_poll_table.
The head entry in the full_poll_table is the extra fd. So we poll the
full_poll_table, while the aiop_poll_table still has matching indicies
with the aiop_table.
Hurrah for C aliasing rules.
- - - - -
0d1aeb0c by Duncan Coutts at 2026-03-10T22:56:33+00:00
Add wakeupIOManager support for win32 legacy I/O manager
- - - - -
83e9ccc5 by Duncan Coutts at 2026-03-10T22:56:33+00:00
wakeupIOManager is now required for all I/O managers
We are going to rely on it. Previously it could be a no-op. Update the
docs in the header file.
Also, temporarily disable awaitCompletedTimeoutsOrIO post-condition
assertion. It will become more complicated due to wakeupIOManager, and
it's not yet clear how to express it.
We will re-introduce a post condition after a few more changes.
- - - - -
b8a005b8 by Duncan Coutts at 2026-03-10T22:56:33+00:00
Make signal handling be a respondibility of the I/O manager(s)
Previously it was scattered between I/O managers and the scheduler, and
especially the scheduler's deadlock detection.
Previously the scheduler would poll for pending signals each iteration
of the scheduler loop. The scheduler also had some hairy signal
functionality in the deadlock detection: in the non-threaded RTS (only)
if there were still no threads running after deadlock detection then it
would block waiting for signals.
But signals can and (in my opinion) should be thought of as just a funny
kind of I/O, and thus should be a responsibility of the I/O manager.
So now we have the I/O managers poll for signals when they are polling
for I/O completion (and removing the separate poll in the scheduler).
And when I/O managers block waiting for I/O then they now also start
signal handlers if they get interrupted by a signal. Crucially, if there
is no pending I/O or timers, the awaitCompletedTimeoutsOrIO will still
block waiting for signals.
This patch puts us into an intermediate state: it temporarily breaks
deadlock detection in the non-threaded RTS. The waiting on I/O currently
happens before deadlock detection. This means we'll now wait forever on
signals before doing deadlock detection. We need to move waiting after
deadlock detection. We'll do that in a later patch.
- - - - -
c5d0190e by Duncan Coutts at 2026-03-10T22:56:33+00:00
Clean up signal handling internal API
Now that the I/O manager is responsible for signals, we can simplify the
API we present for signal handling.
We now just need startPendingSignalHandlers, which is called from the
I/O managers. We can get rid of awaitUserSignals. We also don't need
RtsSignals.h to re-export the platform-specific posix/Signals.h or
win32/ConsoleHandler.h
We can also hide more of the implementation of signals. Less has to be
exposed in posix/Signals.h or win32/ConsoleHandler.h. Partly this is
because we don't need inline functions (or macros) in the interface.
Also remove signal_handlers from RTS ABI exported symbols list. It does
not appear to have any users in the core libs, and its really an
internal implementation detail. It should not be exposed unless its
really necessary.
- - - - -
b2d5a452 by Duncan Coutts at 2026-03-10T22:56:33+00:00
In the scheduler, move I/O blocking after deadlock detection
To make deadlock detection effective in the non-threaded RTS when there
are deadlocked threads and other unrelated threads waiting on I/O, we
need to arrange to do deadlock detection before we block in scheduler
to wait on I/O.
The solution is to:
1. adjust scheduleFindWork, which runs before deadlock detection, to
only poll for I/O and not block; and
2. add a step after deadlock detection to wait on I/O if there are
still no threads to run (and there's any I/O or timeouts outstanding)
The scheduleCheckBlockedThreads is now so simple that it made more sense
to inline it into scheduleFindWork.
- - - - -
198a9d50 by Duncan Coutts at 2026-03-10T22:56:33+00:00
Remove bogus anyPendingTimeoutsOrIO guard from scheduleDetectDeadlock
The deadlock detection was only invoked if both of these conditions
hold:
1. the run queue is empty
2. there is no pending I/O or timeouts
The second condition is unnecessary. The deadlock detection mechanism
can find deadlocks even if there are other threads waiting on I/O or
timers. Having this extra condition means that we fail to detect
blocked threads if there are any threads waiting on I/O or timers.
Part of fixing issue #26408
- - - - -
67ebecf0 by Duncan Coutts at 2026-03-10T22:56:33+00:00
Don't consider pending I/O for early context switch optimisation
Context switches are normally initiated by the timer signal. If however
the user specifies "context switch as often as possible", with +RTS -C0
then the scheduler arranges for an early context switch (when it's just
about to run a Haskell thread).
Context switching very often is expensive, so as an optimisation there
cases where we do not arrange an early context switch:
1. if there's no other threads to run
2. if there is no pending I/O or timers
This patch eliminates case 2, leaving only case 1.
The rationale is as follows. The use of this was inconsistent across
platforms and threaded/non-threaded RTS ways. It only worked on the
non-threaded RTS and on Windows only worked for the win32-legacy I/O
manager. On all other combinations anyPendingTimeoutsOrIO would always
return false. The fact that nobody noticed and complained about this
inconsistency suggests that the feature is not relied upon.
If however it turns out that applications do rely on this, then the
proper thing to do is not to restore this check, but to add a new I/O
manager hint function that returns if there is any pending events that
are likely to happen *soon*: for example timeouts expiring within one
timeslice, or I/O waits on things likely to complete soon like disk I/O,
but not for example socket/pipe I/O.
The motivation to avoid this use of anyPendingTimeoutsOrIO is to
allow us to eliminate anyPendingTimeoutsOrIO entirely. All other uses
of this are just guards on {await,poll}CompletedTimeoutsOrIO and
the guards can safely be folded into those functions. This will better
cope with some I/O managers having no proper implementation of
anyPendingTimeoutsOrIO.
Ultimately this will let us simplify the scheduler which currently has
to have special #ifdef mingw32_HOST_OS cases to cope with the lack of a
working anyPendingTimeoutsOrIO for some Windows I/O managers
- - - - -
bbb1cdba by Duncan Coutts at 2026-03-10T22:56:33+00:00
Remove anyPendingTimeoutsOrIO guarding {poll,await}CompletedTimeoutsOrIO
Previously the API of the I/O manager used a two step process: check
anyPendingTimeoutsOrIO and then call {poll,await}CompletedTimeoutsOrIO.
This was primarily there as a performance thing, to cheaply check if we
need to do anything.
And then because anyPendingTimeoutsOrIO existed, it was used for other
things too. We have now eliminated the other uses, and are just left
with the performance pattern.
But this was problematic because not all I/O managers correctly
implement anyPendingTimeoutsOrIO (specifically the win32 ones), and now
that we also make I/O managers responsible for signals then we need to
poll/await even if there is no pending I/O or timeouts. If there is no
pending I/O or timeouts then poll/await needs to degenerate to just
waiting forever for any signals.
- - - - -
a3c422f3 by Duncan Coutts at 2026-03-10T22:56:33+00:00
Remove anyPendingTimeoutsOrIO, it is no longer used
And this avoids the problems arising from the win32 I/O managers having
had a bogus implementation.
- - - - -
298694d9 by Duncan Coutts at 2026-03-10T22:59:04+00:00
Remove second scheduler call to awaitCompletedTimeoutsOrIO
Previously awaitCompletedTimeoutsOrIO was called both before and after
deadlock detection in the scheduler. The reason for that was that the
win32 I/O managers had a bogus implementation of anyPendingTimeoutsOrIO
and this was used to guard the call of awaitCompletedTimeoutsOrIO prior
to deadlock detection. This meant the first call site was never actually
called when using the win32 I/O managers. This was the reason for the
second call: the first one was never used. What a mess.
So now we have a simple design in the scheduler:
1. poll for completed I/O, timers or signals
2. if no runnable threads: do deadlock detection
3. if still no runnable threads: block waiting for I/O, timers or
signals.
- - - - -
f3684344 by Duncan Coutts at 2026-03-10T22:59:07+00:00
Lift emptyRunQueue guard out of scheduleDetectDeadlock
this improved the clarity of the logic when reading the scheduler code.
- - - - -
0b1fab72 by Duncan Coutts at 2026-03-10T22:59:07+00:00
Make non-threaded deadlock detection also rely on idle GC
Only do deadlock detection GC when idle GC kicks in. This also relies on
using wakeUpRts, so now do this unconditionally. Previously wakeUpRts
was for the threaded rts only.
- - - - -
5a5c128e by Duncan Coutts at 2026-03-10T22:59:07+00:00
Enable idle GC by default on non-threaded RTS.
The behaviour is now uniform between threaded and non-threaded. The
deadlock detection now relies on idle GC for both threaded and
non-threaded ways. Previously deadlock detection did not rely on idle
GC for the non-threaded way.
- - - - -
b29a5ae2 by Duncan Coutts at 2026-03-10T22:59:07+00:00
Add a long Note [Deadlock detection]
It describes the historical and modern designs and their trade-offs.
The point is we've now unified the code for deadlock detection between
the threaded and non-threaded ways, by changing the non-threaded to
follow the same design as the threaded.
- - - - -
f7a336ee by Duncan Coutts at 2026-03-10T22:59:07+00:00
Add a test for deadlock detection, issue #26408
- - - - -
9e15419e by Duncan Coutts at 2026-03-10T22:59:07+00:00
Update the user guide with the revised idle GC behaviour
i.e. it's now not just for the threaded RTS, but general.
Also document the fact that disabling idle GC also disables deadlock
detection.
- - - - -
29 changed files:
- docs/users_guide/runtime_control.rst
- rts/Capability.c
- rts/IOManager.c
- rts/IOManager.h
- rts/IOManagerInternals.h
- rts/RtsFlags.c
- rts/RtsSignals.h
- rts/RtsStartup.c
- rts/RtsSymbols.c
- rts/Schedule.c
- rts/Schedule.h
- rts/Timer.c
- + rts/posix/FdWakeup.c
- + rts/posix/FdWakeup.h
- + rts/posix/MIO.c
- + rts/posix/MIO.h
- rts/posix/Poll.c
- rts/posix/Poll.h
- rts/posix/Select.c
- rts/posix/Select.h
- rts/posix/Signals.c
- rts/posix/Signals.h
- rts/rts.cabal
- rts/win32/AwaitEvent.c
- rts/win32/ConsoleHandler.c
- rts/win32/ConsoleHandler.h
- + testsuite/tests/rts/T26408.hs
- + testsuite/tests/rts/T26408.stderr
- testsuite/tests/rts/all.T
Changes:
=====================================
docs/users_guide/runtime_control.rst
=====================================
@@ -739,18 +739,18 @@ performance.
.. rts-flag:: -I ⟨seconds⟩
- :default: 0.3 seconds in the threaded runtime, 0 in the non-threaded runtime
+ :default: 0.3 seconds
.. index::
single: idle GC
- Set the amount of idle time which must pass before a idle GC is
- performed. Setting ``-I0`` disables the idle GC.
+ A major GC is automatically performed if the runtime has been idle (no
+ Haskell computation has been running) for a period of time. Set the amount
+ of idle time which must pass before a idle GC is performed.
- In the threaded and SMP versions of the RTS (see :ghc-flag:`-threaded`,
- :ref:`options-linker`), a major GC is automatically performed if the
- runtime has been idle (no Haskell computation has been running) for a
- period of time.
+ Setting ``-I0`` disables the idle GC. This also has the unfortunate side
+ effect of disabling thread deadlock detection (the implementation of which
+ uses the idle GC).
For an interactive application, it is probably a good idea to use
the idle GC, because this will allow finalizers to run and
@@ -767,8 +767,8 @@ performance.
after the first idle collection is triggered then no more future collections
will be scheduled until more work is performed.
- This is an experimental feature, please let us know if it causes
- problems and/or could benefit from further tuning.
+ Please let us know if it causes problems and/or could benefit from further
+ tuning.
.. rts-flag:: -Iw ⟨seconds⟩
@@ -779,7 +779,7 @@ performance.
Set the minimum wait time between runs of the idle GC.
- By default, if idle GC is enabled in the threaded runtime, a major
+ By default (and if idle GC is not disabled) a major
GC will be performed every time the process goes idle for a
sufficiently long duration (see :rts-flag:`-I ⟨seconds⟩`). For
large server processes accepting regular but infrequent requests
=====================================
rts/Capability.c
=====================================
@@ -1280,6 +1280,7 @@ shutdownCapabilities(Task *task, bool safe)
static void
freeCapability (Capability *cap)
{
+ freeCapabilityIOManager(cap->iomgr);
stgFree(cap->mut_lists);
stgFree(cap->saved_mut_lists);
if (cap->current_segments) {
=====================================
rts/IOManager.c
=====================================
@@ -39,7 +39,7 @@
#endif
#if defined(IOMGR_ENABLED_MIO_POSIX)
-#include "posix/Signals.h"
+#include "posix/MIO.h"
#include "Prelude.h"
#endif
@@ -343,9 +343,7 @@ void initCapabilityIOManager(CapIOManager *iomgr)
switch (iomgr_type) {
#if defined(IOMGR_ENABLED_SELECT)
case IO_MANAGER_SELECT:
- iomgr->blocked_queue_hd = END_TSO_QUEUE;
- iomgr->blocked_queue_tl = END_TSO_QUEUE;
- iomgr->sleeping_queue = END_TSO_QUEUE;
+ initCapabilityIOManagerSelect(iomgr);
break;
#endif
@@ -373,11 +371,31 @@ void initCapabilityIOManager(CapIOManager *iomgr)
}
+void freeCapabilityIOManager(CapIOManager *iomgr)
+{
+ switch (iomgr_type) {
+#if defined(IOMGR_ENABLED_SELECT)
+ case IO_MANAGER_SELECT:
+ freeCapabilityIOManagerSelect(iomgr);
+ break;
+#endif
+
+#if defined(IOMGR_ENABLED_POLL)
+ case IO_MANAGER_POLL:
+ freeCapabilityIOManagerPoll(iomgr);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+
/* Called late in the RTS initialisation
*/
-void initIOManager(void)
+void startIOManager(void)
{
- debugTrace(DEBUG_iomanager, "initialising %s I/O manager", showIOManager());
+ debugTrace(DEBUG_iomanager, "starting %s I/O manager", showIOManager());
switch (iomgr_type) {
@@ -441,7 +459,7 @@ void initIOManager(void)
/* Called from forkProcess in the child process on the surviving capability.
*/
void
-initIOManagerAfterFork(CapIOManager *iomgr, Capability **pcap)
+restartIOManager(CapIOManager *iomgr, Capability **pcap)
{
switch (iomgr_type) {
@@ -541,13 +559,25 @@ exitIOManager(bool wait_threads)
}
}
-/* Wakeup hook: called from the scheduler's wakeUpRts (currently only in
- * threaded mode).
+/* Wakeup hook: called from the scheduler's wakeUpRts
*/
void wakeupIOManager(void)
{
+ debugTrace(DEBUG_iomanager, "Sending wakeup to I/O manager...");
switch (iomgr_type) {
+#if defined(IOMGR_ENABLED_SELECT)
+ case IO_MANAGER_SELECT:
+ wakeupIOManagerSelect(MainCapability.iomgr);
+ break;
+#endif
+
+#if defined(IOMGR_ENABLED_POLL)
+ case IO_MANAGER_POLL:
+ wakeupIOManagerPoll(MainCapability.iomgr);
+ break;
+#endif
+
#if defined(IOMGR_ENABLED_MIO_POSIX)
case IO_MANAGER_MIO_POSIX:
/* MIO Posix implementation in posix/Signals.c */
@@ -572,8 +602,13 @@ void wakeupIOManager(void)
#endif
break;
#endif
- default:
+#if defined(IOMGR_ENABLED_WIN32_LEGACY)
+ case IO_MANAGER_WIN32_LEGACY:
+ abandonRequestWait();
break;
+#endif
+ default:
+ barf("wakeupIOManager not implemented");
}
}
@@ -661,64 +696,6 @@ setIOManagerControlFd(uint32_t cap_no, int fd) {
#endif
-bool anyPendingTimeoutsOrIO(CapIOManager *iomgr)
-{
- switch (iomgr_type) {
-#if defined(IOMGR_ENABLED_SELECT)
- case IO_MANAGER_SELECT:
- return (iomgr->blocked_queue_hd != END_TSO_QUEUE)
- || (iomgr->sleeping_queue != END_TSO_QUEUE);
-#endif
-
-#if defined(IOMGR_ENABLED_POLL)
- case IO_MANAGER_POLL:
- return anyPendingTimeoutsOrIOPoll(iomgr);
-#endif
-
-#if defined(IOMGR_ENABLED_WIN32_LEGACY)
- case IO_MANAGER_WIN32_LEGACY:
- return (iomgr->blocked_queue_hd != END_TSO_QUEUE);
-#endif
-
- /* For the purpose of the scheduler, the threaded I/O managers never have
- pending I/O or timers. Of course in reality they do, but they're
- managed via other primitives that the scheduler can see into (threads,
- MVars and foreign blocking calls).
- */
-#if defined(IOMGR_ENABLED_MIO_POSIX)
- case IO_MANAGER_MIO_POSIX:
- return false;
-#endif
-
-#if defined(IOMGR_ENABLED_MIO_WIN32)
- case IO_MANAGER_MIO_WIN32:
- return false;
-#endif
-
-#if defined(IOMGR_ENABLED_WINIO)
-#if defined(THREADED_RTS)
- /* As above, the threaded variants never have pending I/O or timers */
- case IO_MANAGER_WINIO:
- return false;
-#else
- case IO_MANAGER_WINIO:
- return false;
- /* FIXME: But what is this? The WinIO I/O manager *also* returns false
- in the non-threaded case! This is *totally bogus*! In the
- non-threaded RTS the scheduler expects to be able to poll for IO.
- The fact that this gives a wrong and useless answer for WinIO is
- probably the cause of the complication in the scheduler with having
- to call awaitCompletedTimeoutsOrIO() in multiple places (on Windows,
- non-threaded).
- */
-#endif
-#endif
- default:
- barf("anyPendingTimeoutsOrIO not implemented");
- }
-}
-
-
void pollCompletedTimeoutsOrIO(CapIOManager *iomgr)
{
debugTrace(DEBUG_iomanager, "polling for completed IO or timeouts");
@@ -782,7 +759,9 @@ void awaitCompletedTimeoutsOrIO(CapIOManager *iomgr)
default:
barf("pollCompletedTimeoutsOrIO not implemented");
}
- ASSERT(!emptyRunQueue(iomgr->cap) || getSchedState() != SCHED_RUNNING);
+ // FIXME: the post condition is now more complicated. Await can now simply
+ // be interrupted by wakeupIOManager.
+ // ASSERT(!emptyRunQueue(iomgr->cap) || getSchedState() != SCHED_RUNNING);
}
=====================================
rts/IOManager.h
=====================================
@@ -15,6 +15,11 @@
* subsystem implementations are centralised here. Not all implementations use
* all hooks.
*
+ * I/O manager are responsible for:
+ * - threads waiting on I/O
+ * - threads waiting on timeouts
+ * - signals (unix, and win32 console) starting handlers
+ *
* -------------------------------------------------------------------------*/
#pragma once
@@ -242,11 +247,33 @@ CapIOManager *allocCapabilityIOManager(Capability *cap);
*/
void initCapabilityIOManager(CapIOManager *iomgr);
+/* When shutting down a capability, or after forkProcess, free the resources
+ * held by a CapIOManager to put it back into a state in which either it can be
+ * re-initialised using initCapabilityIOManager, or the whole structure freed.
+ *
+ * Note that this does not free the CapIOManager structure itself, just the
+ * contents.
+ *
+ * This is used during capability shutdown, during RTS shutdown. It is not used
+ * when reducing the number of capabilities. Capabilities are disabled rather
+ * than freed entirely: the I/O manager keeps running but threads that become
+ * runnable are migrated away.
+ *
+ * It is also used after forkProcess.
+ */
+void freeCapabilityIOManager(CapIOManager *iomgr);
+
+/* CapIOManager life cycle:
+ *
+ * alloc -> init -> free -> free struct
+ * ^ |
+ * +--------+
+ */
/* Init hook: called from hs_init_ghc, very late in the startup after almost
* everything else is done.
*/
-void initIOManager(void);
+void startIOManager(void);
/* Init hook: called from forkProcess in the child process on the surviving
@@ -255,8 +282,8 @@ void initIOManager(void);
* This is synchronous and can run Haskell code, so can change the given cap.
* TODO: it would make for a cleaner API here if this were made asynchronous.
*/
-void initIOManagerAfterFork(CapIOManager *iomgr,
- /* inout */ Capability **pcap);
+void restartIOManager(CapIOManager *iomgr,
+ /* inout */ Capability **pcap);
/* TODO: rationalise initIOManager and initIOManagerAfterFork into a single
per-capability init function.
@@ -283,19 +310,13 @@ void stopIOManager(void);
void exitIOManager(bool wait_threads);
-/* Wakeup hook: called from the scheduler's wakeUpRts (currently only in
- * threaded mode).
+/* Wakeup hook: called from the scheduler's wakeUpRts().
*
* The I/O manager can be blocked waiting on I/O or timers. Sometimes there are
* other external events where we need to wake up the I/O manager and return
- * to the schedulr.
- *
- * At the moment, all the non-threaded I/O managers will do this automagically
- * since a signal will interrupt any waiting system calls, so at the moment
- * the implementation for the non-threaded I/O managers does nothing.
+ * to the scheduler.
*
- * For the I/O managers in threaded mode, this arranges to unblock the I/O
- * manager if it waa blocked waiting.
+ * This arranges to unblock the I/O manager if it was blocked waiting.
*/
void wakeupIOManager(void);
@@ -343,35 +364,27 @@ void syncDelayCancel(CapIOManager *iomgr, StgTSO *tso);
void appendToIOBlockedQueue(CapIOManager *iomgr, StgTSO *tso);
#endif
-/* Check to see if there are any pending timeouts or I/O operations
- * in progress with the I/O manager.
+/* Poll for any completed I/O operations, expired timers or pending signals
+ * with handlers. If there are any, process the completions as appropriate
+ * (which will typically unblock some waiting threads).
*
- * This is used by the scheduler as part of deadlock-detection, and the
- * "context switch as often as possible" test.
- */
-bool anyPendingTimeoutsOrIO(CapIOManager *iomgr);
-
-/* If there are any completed I/O operations or expired timers, process the
- * completions as appropriate (which will typically unblock some waiting
- * threads, but no guarantee). If there are none, return without waiting.
+ * This polls, but does not block.
+ *
+ * No post-condition. It does not guarantee anything such as there being
+ * runnable threads, since this does not wait.
*
- * Called from schedule() both *before* and *after* scheduleDetectDeadlock().
+ * Called from schedule() before scheduleDetectDeadlock().
*/
void pollCompletedTimeoutsOrIO(CapIOManager *iomgr);
- /* If there are any completed I/O operations or expired timers, process the
- * completions as appropriate. If there are none, wait until I/O or a timer
- * does complete (or we get a signal with a handler) and process the
- * completions as appropriate.
+/* Wait for completed I/O operations, expired timers or signals and process
+ * the completions as appropriate.
*
* Upon return this guarantees that the scheduler run queue is non-empty or
* that the scheduler is no longer in the running state. Succinctly, the
* post-condition is (!emptyRunQueue(cap) || getSchedState() != SCHED_RUNNING).
*
- * This is only expected to be called if anyPendingTimeoutsOrIO() returns true,
- * i.e. there actually is something to wait for.
- *
- * Called from schedule() both *before* and *after* scheduleDetectDeadlock().
+ * Called from schedule() after scheduleDetectDeadlock().
*/
void awaitCompletedTimeoutsOrIO(CapIOManager *iomgr);
=====================================
rts/IOManagerInternals.h
=====================================
@@ -46,6 +46,11 @@ struct _CapIOManager {
StgTSO *sleeping_queue;
#endif
+#if defined(IOMGR_ENABLED_SELECT) || defined(IOMGR_ENABLED_POLL)
+ /* FDs for waking up the I/O manager when it is blocked waiting */
+ int wakeup_fd_r, wakeup_fd_w;
+#endif
+
#if defined(IOMGR_ENABLED_POLL)
/* AIOP and timeout collections shared by several I/O manager impls */
ClosureTable aiop_table;
@@ -53,8 +58,11 @@ struct _CapIOManager {
#endif
#if defined(IOMGR_ENABLED_POLL)
- /* Auxiliary table with size and indexes matching the aiop_table */
- struct pollfd *aiop_poll_table;
+ /* Auxiliary table with size and indexes matching the aiop_table. This is
+ * aliased to the tail of the full poll table, which has a head entry for
+ * the wakeup_fd_r above, so we can also poll that fd.
+ */
+ struct pollfd *aiop_poll_table, *full_poll_table;
#endif
#if defined(IOMGR_ENABLED_WIN32_LEGACY)
=====================================
rts/RtsFlags.c
=====================================
@@ -173,11 +173,7 @@ void initRtsFlagsDefaults(void)
RtsFlags.GcFlags.sweep = false;
RtsFlags.GcFlags.idleGCDelayTime = USToTime(300000); // 300ms
RtsFlags.GcFlags.interIdleGCWait = 0;
-#if defined(THREADED_RTS)
RtsFlags.GcFlags.doIdleGC = true;
-#else
- RtsFlags.GcFlags.doIdleGC = false;
-#endif
RtsFlags.GcFlags.heapBase = 0; /* means don't care */
RtsFlags.GcFlags.allocLimitGrace = (100*1024) / BLOCK_SIZE;
RtsFlags.GcFlags.numa = false;
=====================================
rts/RtsSignals.h
=====================================
@@ -2,26 +2,15 @@
*
* (c) The GHC Team, 1998-2005
*
- * Signal processing / handling.
+ * Signal processing / handling. This is the shared API to the subsystems for
+ * POSIX signals and Win32 console events.
+ *
+ * Platform specific APIs live in posix/Signals.h and win32/ConsoleHandler.h
*
* ---------------------------------------------------------------------------*/
#pragma once
-#if !defined(mingw32_HOST_OS) && defined(HAVE_SIGNAL_H)
-
-#include "posix/Signals.h"
-
-#elif defined(mingw32_HOST_OS)
-
-#include "win32/ConsoleHandler.h"
-
-#else
-
-#define signals_pending() (false)
-
-#endif
-
#if defined(RTS_USER_SIGNALS)
#include "BeginPrivate.h"
@@ -44,39 +33,20 @@ void resetDefaultHandlers(void);
void freeSignalHandlers(void);
-/*
- * Function: awaitUserSignals()
- *
- * Wait for the next console event. Currently a NOP (returns immediately.)
+/* Tear down and shut down user signal processing.
+ * This is called *after* freeSignalHandlers, but unconditionally!
+ * TODO: unify this and freeSignalHandlers together, and make them make sense!
*/
-void awaitUserSignals(void);
+void finiUserSignals(void);
/*
* Function: startPendingSignalHandlers()
*
- * Start any pending signal handlers. This is used by the scheduler and some
- * in-RTS I/O managers. It does nothing (returns false) in the threaded RTS.
- *
- * Returns true if any signal handlers were pending and thus started.
+ * If there are any queued up posix signals or win32 console events, run the
+ * handlers associated with them. This is used by some in-RTS I/O managers.
*/
-INLINE_HEADER bool startPendingSignalHandlers(Capability *cap);
-
#if !defined(THREADED_RTS)
-INLINE_HEADER bool startPendingSignalHandlers(Capability *cap)
-{
- if (RtsFlags.MiscFlags.install_signal_handlers && signals_pending()) {
- // safe outside the lock
- startSignalHandlers(cap);
- return true;
- } else {
- return false;
- }
-}
-#else
-INLINE_HEADER bool startPendingSignalHandlers(Capability *cap STG_UNUSED)
-{
- return false;
-}
+void startPendingSignalHandlers(Capability *cap);
#endif
#include "EndPrivate.h"
=====================================
rts/RtsStartup.c
=====================================
@@ -70,6 +70,10 @@
#include <locale.h>
#endif
+#if !defined(mingw32_HOST_OS) && defined(HAVE_SIGNAL_H)
+#include <signal.h>
+#endif
+
// Count of how many outstanding hs_init()s there have been.
static StgWord hs_init_count = 0;
static bool rts_shutdown = false;
@@ -427,7 +431,7 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
}
#endif
- initIOManager();
+ startIOManager();
x86_init_fpu();
@@ -619,9 +623,10 @@ hs_exit_(bool wait_foreign)
#if defined(mingw32_HOST_OS)
if (is_io_mng_native_p())
hs_restoreConsoleCP();
+#endif
- /* Disable console signal handlers, we're going down!. */
- finiUserSignals ();
+#if defined(RTS_USER_SIGNALS)
+ finiUserSignals();
#endif
/* tear down statistics subsystem */
=====================================
rts/RtsSymbols.c
=====================================
@@ -71,7 +71,6 @@ extern char **environ;
SymI_HasProto(__hscore_get_saved_termios) \
SymI_HasProto(__hscore_set_saved_termios) \
SymI_HasProto(shutdownHaskellAndSignal) \
- SymI_HasProto(signal_handlers) \
SymI_HasProto(stg_sig_install) \
SymI_HasProto(rtsTimerSignal) \
SymI_NeedsDataProto(nocldstop)
=====================================
rts/Schedule.c
=====================================
@@ -146,7 +146,6 @@ static void acquireAllCapabilities(Capability *cap, Task *task);
static void startWorkerTasks (uint32_t from USED_IF_THREADS,
uint32_t to USED_IF_THREADS);
#endif
-static void scheduleCheckBlockedThreads (Capability *cap);
static void scheduleProcessInbox(Capability **cap);
static void scheduleDetectDeadlock (Capability **pcap, Task *task);
static void schedulePushWork(Capability *cap, Task *task);
@@ -174,6 +173,11 @@ static void deleteAllThreads (void);
static void deleteThread_(StgTSO *tso);
#endif
+#if defined(FORKPROCESS_PRIMOP_SUPPORTED)
+static void truncateRunQueue(Capability *cap);
+#endif
+static StgTSO *popRunQueue (Capability *cap);
+
/* ---------------------------------------------------------------------------
Main scheduling loop.
@@ -295,21 +299,21 @@ schedule (Capability *initialCapability, Task *task)
(pushes threads, wakes up idle capabilities for stealing) */
schedulePushWork(cap,task);
- scheduleDetectDeadlock(&cap,task);
+ if (emptyRunQueue(cap)) {
+ /* When we have no threads to run, we *might* have a deadlock. */
+ scheduleDetectDeadlock(&cap,task);
+ }
- // Normally, the only way we can get here with no threads to
- // run is if a keyboard interrupt received during
- // scheduleCheckBlockedThreads() or scheduleDetectDeadlock().
- // Additionally, it is not fatal for the
- // threaded RTS to reach here with no threads to run.
- //
- // Since IOPorts have no deadlock avoidance guarantees you may also reach
- // this point when blocked on an IO Port. If this is the case the only
- // thing that could unblock it is an I/O event.
- //
- // win32: might be here due to awaitCompletedTimeoutsOrIO() being abandoned
- // as a result of a console event having been delivered or as a result of
- // waiting on an async I/O to complete with WinIO.
+#if !defined(THREADED_RTS)
+ /* scheduleFindWork checks for completed I/O but does not block. If there
+ * is nothing to do now, we block and wait for I/O, timeouts or signals.
+ * Importantly, we only block /after/ checking for deadlocks. See #26408.
+ */
+ if (emptyRunQueue(cap)) {
+ awaitCompletedTimeoutsOrIO(cap->iomgr);
+ if (emptyRunQueue(cap)) continue; // look for work again
+ }
+#endif
#if defined(THREADED_RTS)
scheduleYield(&cap,task);
@@ -317,22 +321,6 @@ schedule (Capability *initialCapability, Task *task)
if (emptyRunQueue(cap)) continue; // look for work again
#endif
-#if !defined(THREADED_RTS)
- if ( emptyRunQueue(cap) ) {
-#if defined(mingw32_HOST_OS)
- /* Notify the I/O manager that we have nothing to do. If there are
- any outstanding I/O requests we'll block here. If there are not
- then this is a user error and we will abort soon. */
- /* TODO: see if we can rationalise these two awaitCompletedTimeoutsOrIO
- * calls before and after scheduleDetectDeadlock().
- */
- awaitCompletedTimeoutsOrIO(cap->iomgr);
-#else
- ASSERT(getSchedState() >= SCHED_INTERRUPTING);
-#endif
- }
-#endif
-
//
// Get a thread to run
//
@@ -403,13 +391,12 @@ schedule (Capability *initialCapability, Task *task)
}
#endif
- /* context switches are initiated by the timer signal, unless
- * the user specified "context switch as often as possible", with
- * +RTS -C0
- */
- if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0 &&
- (!emptyRunQueue(cap) ||
- anyPendingTimeoutsOrIO(cap->iomgr))) {
+ // Context switches are normally initiated by the timer signal. If however
+ // the user specified "context switch as often as possible", with +RTS -C0
+ // then we now arrange for an early context switch. Context switching very
+ // often is expensive, so as an optimisation if there's no other threads
+ // to run then we don't arrange a context switch.
+ if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0 && !emptyRunQueue(cap)) {
RELAXED_STORE(&cap->context_switch, 1);
}
@@ -591,42 +578,12 @@ run_thread:
} /* end of while() */
}
-/* -----------------------------------------------------------------------------
- * Run queue operations
- * -------------------------------------------------------------------------- */
-
-static void
-removeFromRunQueue (Capability *cap, StgTSO *tso)
-{
- if (tso->block_info.prev == END_TSO_QUEUE) {
- ASSERT(cap->run_queue_hd == tso);
- cap->run_queue_hd = tso->_link;
- } else {
- setTSOLink(cap, tso->block_info.prev, tso->_link);
- }
- if (tso->_link == END_TSO_QUEUE) {
- ASSERT(cap->run_queue_tl == tso);
- cap->run_queue_tl = tso->block_info.prev;
- } else {
- setTSOPrev(cap, tso->_link, tso->block_info.prev);
- }
- tso->_link = tso->block_info.prev = END_TSO_QUEUE;
- cap->n_run_queue--;
-
- IF_DEBUG(sanity, checkRunQueue(cap));
-}
-
-void
-promoteInRunQueue (Capability *cap, StgTSO *tso)
-{
- removeFromRunQueue(cap, tso);
- pushOnRunQueue(cap, tso);
-}
-
/* -----------------------------------------------------------------------------
* scheduleFindWork()
*
* Search for work to do, and handle messages from elsewhere.
+ *
+ * This does *not* block/wait, even in the non-threaded case.
* -------------------------------------------------------------------------- */
static void
@@ -635,16 +592,17 @@ scheduleFindWork (Capability **pcap)
#if defined(mingw32_HOST_OS) && !defined(THREADED_RTS)
queueIOThread();
#endif
-#if defined(RTS_USER_SIGNALS)
- startPendingSignalHandlers(*pcap);
-#endif
-
scheduleProcessInbox(pcap);
- scheduleCheckBlockedThreads(*pcap);
+ /* From here on, the cap can't change. */
+ Capability *cap = *pcap;
+
+#if !defined(THREADED_RTS)
+ pollCompletedTimeoutsOrIO(cap->iomgr);
+#endif
#if defined(THREADED_RTS)
- if (emptyRunQueue(*pcap)) { scheduleActivateSpark(*pcap); }
+ if (emptyRunQueue(cap)) { scheduleActivateSpark(cap); }
#endif
}
@@ -889,115 +847,158 @@ schedulePushWork(Capability *cap USED_IF_THREADS,
}
-/* ----------------------------------------------------------------------------
- * Check for blocked threads that can be woken up.
- * ------------------------------------------------------------------------- */
-
-static void
-scheduleCheckBlockedThreads(Capability *cap USED_IF_NOT_THREADS)
-{
-#if !defined(THREADED_RTS)
- /* Check whether there is any completed I/O or expired timers. If so,
- * process the competions as appropriate, which will typically cause some
- * waiting threads to be woken up.
- *
- * If the run queue is empty, and there are no other threads running, we
- * can wait indefinitely for something to happen.
- *
- * TODO: see if we can rationalise these two awaitCompletedTimeoutsOrIO
- * calls before and after scheduleDetectDeadlock()
- *
- * TODO: this test anyPendingTimeoutsOrIO does not have a proper
- * implementation the WinIO I/O manager!
- *
- * The select() I/O manager uses the sleeping_queue and the blocked_queue,
- * and the test checks both. The legacy win32 I/O manager only consults
- * the blocked_queue, but then it puts threads waiting on delay# on the
- * blocked_queue too, so that's ok.
- *
- * The WinIO I/O manager does not use either the sleeping_queue or the
- * blocked_queue, but it's implementation of anyPendingTimeoutsOrIO still
- * checks both! Since both queues will _always_ be empty then it will
- * _always_ return false and so awaitCompletedTimeoutsOrIO will _never_ be
- * called here for WinIO. This may explain why there is a second call to
- * awaitCompletedTimeoutsOrIO below for the case of !defined(THREADED_RTS)
- * && defined(mingw32_HOST_OS).
- */
- if (anyPendingTimeoutsOrIO(cap->iomgr))
- {
- if (emptyRunQueue(cap)) {
- // block and wait
- awaitCompletedTimeoutsOrIO(cap->iomgr);
- } else {
- // poll but do not wait
- pollCompletedTimeoutsOrIO(cap->iomgr);
- }
- }
-#endif
-}
-
/* ----------------------------------------------------------------------------
* Detect deadlock conditions and attempt to resolve them.
* ------------------------------------------------------------------------- */
+/* Note [Deadlock detection]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For the purpose of this explanation we define:
+ * a /partial deadlock/ to be a set of threads that are deadlocked; and
+ * a /system deadlock/ is when all threads are deadlocked.
+
+Obviously, we can have a partial deadlock without having a system
+deadlock. The design goal of deadlock detection is to guarantee to
+detect (and resolve) system deadlock, but to also try to detect (and
+resolve) partial deadlocks.
+
+There are two designs that the RTS has used for deadlock detection: a
+simple historical design originally used in the non-threaded RTS and a
+modern design for the threaded RTS. These days we use the modern design
+in both the threaded and non-threaded RTS.
+
+A high level way to think about the two designs is as follows:
+ 1. the historical design looks for situations in which there *must* be
+ a system deadlock; whereas
+ 2. the modern design looks for partial deadlocks opportunistically,
+ with the guarantee that if the overall system is deadlocked that we
+ will *eventually* detect this.
+
+An advantage of the historical design is that it will detect system
+deadlock promptly. A disadvantage is that it will never detect a
+partial deadlock (that isn't also a system deadlock).
+
+The modern design can detect partial deadlock, but it is not guaranteed
+to detect system deadlock promptly, just eventually.
+
+The mechanism for deadlock detection is garbage collection. GC can be
+instructed to look for deadlocked threads and if it finds them to throw
+exceptions to one or more threads involved in the deadlock. This
+mechanism can find partial deadlocks. It is however expensive -- more
+expensive than a normal major GC. So the difference in the historical
+and modern designs is in when we do this expensive GC check.
+
+The historical design
+---------------------
+
+When there was just one capability, as in the single threaded RTS, it
+is possible to follow a very simple design. When there are no runnable
+threads, and no threads blocked on pending I/O or on timers then there
+*must* be a deadlock. And thus running deadlock detection promptly in
+this situation is guaranteed to find the deadlock and wake up one or
+more threads. Thus we can guarantee afterwards that there are runnable
+threads.
+
+There are a couple problems with this design, but the biggest problem
+is that it cannot be extended to multiple capabilities. When there are
+multiple capabilities then the fact that there are no runnable threads
+on the current capability says nothing about runnable threads on other
+capabilities. Runnable threads elsewhere might wake up threads on this
+capability, and so there is no implication that there is a deadlock.
+
+The other problems with this design are:
+ 1. it cannot find genuine deadlocks when there are any unrelated
+ threads blocked on I/O or timers (see issue #26408); and
+ 2. it requires treating signals specially.
+
+The problem with signals is that they're a weird kind of I/O. Threads
+do not block waiting on signals. Rather signals can have handlers such
+that when a signal arrives, a new thread is started to execute the
+handler. This means it doesn't neatly fit into the condition "no
+threads blocked on pending I/O or on timers". And if we did shoehorn it
+into that definition then we would not look for deadlocks if there were
+any signal handlers registered, and we would still end up with no
+runnable threads after skipping deadlock detection, which violates the
+post-condition that there be runnable threads. So the solution was that
+after deadlock detection, if there are still no runnable threads and
+there are registered signal handlers then we conclude we must wait for
+a signal to be received -- which will start a thread and thus we will
+end up with runnable threads. But of course this is horrible: we have
+entangled two features far too tightly: deadlock detection with a weird
+-- and platform specific -- kind of I/O.
+
+The modern design
+-----------------
+
+A change of perspective is required. Instead of thinking of conditions
+in which there must be a deadlock, we simply look for deadlocks in such
+a way in which we will eventually find deadlocks if they exist. A
+benefit of this approach is that we can find deadlocks that the simple
+approach cannot. For example we can find deadlocks when there unrelated
+threads blocked on I/O or timers (see issue #26408).
+
+The question is when to run GC it its more expensive deadlock detection
+mode. We obviously do not want to do it too frequently. The design
+choice is to do it during idle GC, at least sometimes. Idle GC is only
+run some time after a capability goes idle. This is a good opportunity.
+We know there are no runnable threads on the capability, so there
+*might* be a deadlock, and when there's nothing else to do is also a
+good moment to do a more expensive GC.
+
+The idle GC is controlled by the RecentActivity status, which
+progresses through 4 stages: yes, maybe_no, inactive, done_gc. We only
+invoke a deadlock-detecting major GC in the inactive state. We get into
+the inactive state when:
+ * the timer tick goes off
+ * we were already in the maybe_no state (which itself requires no
+ activity on any capability for a whole timer tick)
+ * idle GC is enabled
+ * it's been long enough since the most recent idle GC.
+This timer tick also wakes up the I/O manager to ensue we get back to
+the scheduler, and thus to scheduleDetectDeadlock.
+
+Note that this means that deadlock detection is disabled if users
+disable idle GC (by setting +RTS -I0). Historically, idle GC was not
+used by default in the non-threaded RTS, but the modern design relies
+on it, so it is enabled by default in all cases.
+
+But if idle GC is enabled, then if there is a full system deadlock then
+eventually we will run a major GC with deadlock detection and detect
+and resolve the deadlock. It is not prompt. It must wait at least for
+an idle GC, which by default is 0.3s after all capabilities go idle.
+
+Furthermore, there is no post-condition for scheduleDetectDeadlock,
+because of the non-prompt "eventually" nature of the deadlock detection
+design. In particular there can still be no runnable threads. In the
+threaded RTS if there's no runnable threads after this we will yield the
+capability, while in the non-threaded we will ask the I/O manager to
+block and wait for I/O, timers or signals.
+*/
+
static void
scheduleDetectDeadlock (Capability **pcap, Task *task)
{
- Capability *cap = *pcap;
- /*
- * Detect deadlock: when we have no threads to run, there are no
- * threads blocked, waiting for I/O, or sleeping, and all the
- * other tasks are waiting for work, we must have a deadlock of
- * some description.
- */
- if ( emptyRunQueue(cap) && !anyPendingTimeoutsOrIO(cap->iomgr) )
- {
-#if defined(THREADED_RTS)
- /*
- * In the threaded RTS, we only check for deadlock if there
- * has been no activity in a complete timeslice. This means
- * we won't eagerly start a full GC just because we don't have
- * any threads to run currently.
- */
- if (getRecentActivity() != ACTIVITY_INACTIVE) return;
-#endif
-
- debugTrace(DEBUG_sched, "deadlocked, forcing major GC...");
-
- // Garbage collection can release some new threads due to
- // either (a) finalizers or (b) threads resurrected because
- // they are unreachable and will therefore be sent an
- // exception. Any threads thus released will be immediately
- // runnable.
- scheduleDoGC (pcap, task, true/*force major GC*/, false /* Whether it is an overflow GC */, true/*deadlock detection*/, false/*nonconcurrent*/);
- cap = *pcap;
- // when force_major == true. scheduleDoGC sets
- // recent_activity to ACTIVITY_DONE_GC and turns off the timer
- // signal.
+ /* See Note [Deadlock detection] */
+ if (getRecentActivity() == ACTIVITY_INACTIVE) {
- if ( !emptyRunQueue(cap) ) return;
+ debugTrace(DEBUG_sched, "maybe deadlocked, forcing major GC...");
-#if defined(RTS_USER_SIGNALS) && !defined(THREADED_RTS)
- /* If we have user-installed signal handlers, then wait
- * for signals to arrive rather then bombing out with a
- * deadlock.
+ /* Garbage collection can release some new threads due to
+ * either (a) finalizers or (b) threads resurrected because
+ * they are unreachable and will therefore be sent an
+ * exception. Any threads thus released will be immediately
+ * runnable.
+ */
+ scheduleDoGC (pcap, task,
+ true /* force major GC */,
+ false /* Whether it is an overflow GC */,
+ true /* deadlock detection */,
+ false /* nonconcurrent */);
+ /* When force_major == true, scheduleDoGC sets recent activity to
+ * getRecentActivity() == ACTIVITY_DONE_GC and turns off the timer
+ * signal.
*/
- if ( RtsFlags.MiscFlags.install_signal_handlers && anyUserHandlers() ) {
- debugTrace(DEBUG_sched,
- "still deadlocked, waiting for signals...");
-
- awaitUserSignals();
-
- if (signals_pending()) {
- startSignalHandlers(cap);
- }
-
- // either we have threads to run, or we were interrupted:
- ASSERT(!emptyRunQueue(cap) || getSchedState() >= SCHED_INTERRUPTING);
-
- return;
- }
-#endif
}
}
@@ -2191,7 +2192,15 @@ forkProcess(HsStablePtr *entry
// bound threads for which the corresponding Task does not
// exist.
truncateRunQueue(cap);
- cap->n_run_queue = 0;
+
+ // Reset and re-initialise the capability's I/O manager,
+ // to get the I/O manager ready again.
+ //
+ // Any threads waiting on I/O or timers should have been
+ // removed from I/O manager queues by deleteThread_ above.
+ // TODO: but we could assert that here.
+ freeCapabilityIOManager(cap->iomgr);
+ initCapabilityIOManager(cap->iomgr);
// Any suspended C-calling Tasks are no more, their OS threads
// don't exist now:
@@ -2208,7 +2217,7 @@ forkProcess(HsStablePtr *entry
cap->n_returning_tasks = 0;
#endif
- // Release all caps except 0, we'll use that for starting
+ // Release all caps except 0, we'll use that for restarting
// the IO manager and running the client action below.
if (cap->no != 0) {
task->cap = cap;
@@ -2232,7 +2241,7 @@ forkProcess(HsStablePtr *entry
// like startup event, capabilities, process info etc
traceTaskCreate(task, cap);
- initIOManagerAfterFork(cap->iomgr, &cap);
+ restartIOManager(cap->iomgr, &cap);
// start timer after the IOManager is initialized
// (the idle GC may wake up the IOManager)
@@ -2337,6 +2346,10 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
// the capability; we don't have to worry about GC data
// structures, the nursery, etc.
//
+ // This approach also handles threads blocked on I/O. Such threads
+ // remain blocked, and when I/O completes and threads become runnable
+ // then they are migrated away.
+ //
for (n = new_n_capabilities; n < enabled_capabilities; n++) {
getCapability(n)->disabled = true;
traceCapDisable(getCapability(n));
@@ -2897,9 +2910,7 @@ interruptStgRts(void)
ASSERT(getSchedState() != SCHED_SHUTTING_DOWN);
setSchedState(SCHED_INTERRUPTING);
interruptAllCapabilities();
-#if defined(THREADED_RTS)
wakeUpRts();
-#endif
}
/* -----------------------------------------------------------------------------
@@ -2915,15 +2926,13 @@ interruptStgRts(void)
will have interrupted any blocking system call in progress anyway.
-------------------------------------------------------------------------- */
-#if defined(THREADED_RTS)
void wakeUpRts(void)
{
- // This forces the IO Manager thread to wakeup, which will
+ // This forces the IO Manager to wakeup, which will
// in turn ensure that some OS thread wakes up and runs the
// scheduler loop, which will cause a GC and deadlock check.
wakeupIOManager();
}
-#endif
/* -----------------------------------------------------------------------------
Deleting threads
@@ -2997,7 +3006,7 @@ pushOnRunQueue (Capability *cap, StgTSO *tso)
cap->n_run_queue++;
}
-StgTSO *popRunQueue (Capability *cap)
+static StgTSO *popRunQueue (Capability *cap)
{
ASSERT(cap->n_run_queue > 0);
StgTSO *t = cap->run_queue_hd;
@@ -3017,6 +3026,45 @@ StgTSO *popRunQueue (Capability *cap)
return t;
}
+#if defined(FORKPROCESS_PRIMOP_SUPPORTED)
+static void truncateRunQueue(Capability *cap)
+{
+ // Can only be called by the task owning the capability.
+ TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_hd, "truncateRunQueue");
+ TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_tl, "truncateRunQueue");
+ TSAN_ANNOTATE_BENIGN_RACE(&cap->n_run_queue, "truncateRunQueue");
+ cap->run_queue_hd = END_TSO_QUEUE;
+ cap->run_queue_tl = END_TSO_QUEUE;
+ cap->n_run_queue = 0;
+}
+#endif
+
+static void removeFromRunQueue (Capability *cap, StgTSO *tso)
+{
+ if (tso->block_info.prev == END_TSO_QUEUE) {
+ ASSERT(cap->run_queue_hd == tso);
+ cap->run_queue_hd = tso->_link;
+ } else {
+ setTSOLink(cap, tso->block_info.prev, tso->_link);
+ }
+ if (tso->_link == END_TSO_QUEUE) {
+ ASSERT(cap->run_queue_tl == tso);
+ cap->run_queue_tl = tso->block_info.prev;
+ } else {
+ setTSOPrev(cap, tso->_link, tso->block_info.prev);
+ }
+ tso->_link = tso->block_info.prev = END_TSO_QUEUE;
+ cap->n_run_queue--;
+
+ IF_DEBUG(sanity, checkRunQueue(cap));
+}
+
+void promoteInRunQueue (Capability *cap, StgTSO *tso)
+{
+ removeFromRunQueue(cap, tso);
+ pushOnRunQueue(cap, tso);
+}
+
/* -----------------------------------------------------------------------------
raiseExceptionHelper
=====================================
rts/Schedule.h
=====================================
@@ -39,9 +39,7 @@ void scheduleThreadOn(Capability *cap, StgWord cpu, StgTSO *tso);
*
* Causes an OS thread to wake up and run the scheduler, if necessary.
*/
-#if defined(THREADED_RTS)
void wakeUpRts(void);
-#endif
/* raiseExceptionHelper */
StgWord raiseExceptionHelper (StgRegTable *reg, StgTSO *tso, StgClosure *exception);
@@ -164,10 +162,6 @@ void appendToRunQueue (Capability *cap, StgTSO *tso);
*/
void pushOnRunQueue (Capability *cap, StgTSO *tso);
-/* Pop the first thread off the runnable queue.
- */
-StgTSO *popRunQueue (Capability *cap);
-
INLINE_HEADER StgTSO *
peekRunQueue (Capability *cap)
{
@@ -184,18 +178,6 @@ emptyRunQueue(Capability *cap)
return cap->n_run_queue == 0;
}
-INLINE_HEADER void
-truncateRunQueue(Capability *cap)
-{
- // Can only be called by the task owning the capability.
- TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_hd, "truncateRunQueue");
- TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_tl, "truncateRunQueue");
- TSAN_ANNOTATE_BENIGN_RACE(&cap->n_run_queue, "truncateRunQueue");
- cap->run_queue_hd = END_TSO_QUEUE;
- cap->run_queue_tl = END_TSO_QUEUE;
- cap->n_run_queue = 0;
-}
-
#endif /* !IN_STG_CODE */
#include "EndPrivate.h"
=====================================
rts/Timer.c
=====================================
@@ -149,11 +149,9 @@ handle_tick(int unused STG_UNUSED)
setRecentActivity(ACTIVITY_INACTIVE);
inter_gc_ticks_to_gc = RtsFlags.GcFlags.interIdleGCWait /
RtsFlags.MiscFlags.tickInterval;
-#if defined(THREADED_RTS)
wakeUpRts();
// The scheduler will call stopTimer() when it has done
// the GC.
-#endif
} else {
setRecentActivity(ACTIVITY_DONE_GC);
// disable timer signals (see #1623, #5991, #9105)
=====================================
rts/posix/FdWakeup.c
=====================================
@@ -0,0 +1,132 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team 2025
+ *
+ * Utilities for a simple fd-based cross-thread wakeup mechanism.
+ *
+ * This is used in I/O managers, to provide a mechanism to wake them when they
+ * are blocked waiting on fds and timeouts. The mechanism works by including
+ * the read end fd into the set of fds the I/O manager waits on, and when a
+ * wake up is needed, the write end fd is used.
+ *
+ * This is implemented using either eventfd() or pipe().
+ *
+ * Linux 2.6.22+ and FreeBSD 13+ support eventfd. It is a single fd with a
+ * 64bit counter. It uses less resources than a pipe, and is probably a tad
+ * faster. Using write() adds to the counter, while read() reads and resets
+ * it. This gives us event combining.
+ *
+ * Otherwise we use a classic unix pipe.
+ *
+ * -------------------------------------------------------------------------*/
+
+#include "rts/PosixSource.h"
+#include "Rts.h"
+
+#include "FdWakeup.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_EVENTFD_H
+#include <sys/eventfd.h>
+#endif
+
+#if !defined(HAVE_EVENTFD) \
+ || (defined(HAVE_EVENTFD) && !(defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)))
+static void fcntl_CLOEXEC_NONBLOCK(int fd)
+{
+ int res1 = fcntl(fd, F_SETFD, FD_CLOEXEC);
+ int res2 = fcntl(fd, F_SETFL, O_NONBLOCK);
+ if (RTS_UNLIKELY(res1 < 0 || res2 < 0)) {
+ sysErrorBelch("newFdWakeup fcntl()");
+ stg_exit(EXIT_FAILURE);
+ }
+}
+#endif
+
+void newFdWakeup(int *wakeup_fd_r, int *wakeup_fd_w)
+{
+#if defined(HAVE_EVENTFD)
+ int wakeup_fd;
+#if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+ wakeup_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+#else
+ wakeup_fd = eventfd(0, 0);
+ if (wakeup_fd >= 0) fcntl_CLOEXEC_NONBLOCK(wakeup_fd);
+#endif
+ if (RTS_UNLIKELY(wakeup_fd < 0)) {
+ sysErrorBelch("newFdWakeup eventfd()");
+ stg_exit(EXIT_FAILURE);
+ }
+ /* eventfd uses the same fd for each end */
+ *wakeup_fd_r = wakeup_fd;
+ *wakeup_fd_w = wakeup_fd;
+#else
+ int pipefd[2];
+ int res;
+ res = pipe(pipefd);
+ if (RTS_UNLIKELY(res < 0)) {
+ sysErrorBelch("newFdWakeup pipe");
+ stg_exit(EXIT_FAILURE);
+ }
+ fcntl_CLOEXEC_NONBLOCK(pipefd[0]);
+ fcntl_CLOEXEC_NONBLOCK(pipefd[1]);
+ *wakeup_fd_r = pipefd[0]; /* read end */
+ *wakeup_fd_w = pipefd[1]; /* write end */
+#endif
+}
+
+void closeFdWakeup(int wakeup_fd_r, int wakeup_fd_w)
+{
+#if defined(HAVE_EVENTFD)
+ ASSERT(wakeup_fd_r == wakeup_fd_w);
+ close(wakeup_fd_r);
+#else
+ ASSERT(wakeup_fd_r != wakeup_fd_w);
+ close(wakeup_fd_r);
+ close(wakeup_fd_w);
+#endif
+}
+
+void sendFdWakeup(int wakeup_fd_w)
+{
+ int res;
+#if defined(HAVE_EVENTFD)
+ uint64_t val = 1;
+ res = write(wakeup_fd_w, &val, 8);
+#else
+ unsigned char buf = 1;
+ res = write(wakeup_fd_w, &buf, 1);
+#endif
+ if (RTS_UNLIKELY(res < 0)) {
+ /* Unlikely the pipe buffer will fill, but it would not be an error. */
+ if (errno == EAGAIN) return;
+ sysErrorBelch("sendFdWakeup write");
+ stg_exit(EXIT_FAILURE);
+ }
+}
+
+void collectFdWakeup(int wakeup_fd_r)
+{
+ int res;
+#if defined(HAVE_EVENTFD)
+ uint64_t buf;
+ /* eventfd combines events into one counter, so a single read is enough */
+ res = read(wakeup_fd_r, &buf, 8);
+#else
+ /* Drain the pipe buffer. Multiple wakeup notifications could
+ * have been sent before we have a chance to collect them.
+ */
+ uint64_t buf;
+ do {
+ res = read(wakeup_fd_r, &buf, 8);
+ } while (res == 8);
+#endif
+ if (RTS_UNLIKELY(res < 0)) {
+ /* After the first pipe read, it could block */
+ if (errno == EAGAIN) return;
+ sysErrorBelch("collectFdWakeup read");
+ stg_exit(EXIT_FAILURE);
+ }
+}
=====================================
rts/posix/FdWakeup.h
=====================================
@@ -0,0 +1,27 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team 2025
+ *
+ * Utilities for a simple fd-based cross-thread wakeup mechanism.
+ *
+ * This is used in I/O managers, to provide a mechanism to wake them when they
+ * are blocked waiting on fds and timeouts. The mechanism works by including
+ * the read end fd into the set of fds the I/O manager waits on, and when a
+ * wake up is needed, the write end fd is used.
+ *
+ * Prototypes for functions in FdWakeup.c
+ *
+ * -------------------------------------------------------------------------*/
+
+#pragma once
+
+#include "BeginPrivate.h"
+
+void newFdWakeup(int *fd_r, int *fd_w);
+void closeFdWakeup(int fd_r, int fd_w);
+
+void sendFdWakeup(int fd_w);
+void collectFdWakeup(int fd_r);
+
+#include "EndPrivate.h"
+
=====================================
rts/posix/MIO.c
=====================================
@@ -0,0 +1,163 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2005
+ *
+ * Signal processing / handling.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "rts/PosixSource.h"
+#include "Rts.h"
+
+#include "Schedule.h"
+#include "RtsUtils.h"
+#include "Prelude.h"
+#include "ThreadLabels.h"
+
+#include "MIO.h"
+#include "IOManager.h"
+#include "IOManagerInternals.h"
+
+#if defined(HAVE_ERRNO_H)
+# include <errno.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+
+// Here's the pipe into which we will send our signals
+static int io_manager_wakeup_fd = -1;
+static int timer_manager_control_wr_fd = -1;
+// TODO: Eliminate these globals. Put then into the CapIOManager, but the
+// problem is these are shared across all caps, not per cap.
+
+#define IO_MANAGER_WAKEUP 0xff
+#define IO_MANAGER_DIE 0xfe
+#define IO_MANAGER_SYNC 0xfd
+
+void setTimerManagerControlFd(int fd) {
+ RELAXED_STORE(&timer_manager_control_wr_fd, fd);
+}
+
+void
+setIOManagerWakeupFd (int fd)
+{
+ // only called when THREADED_RTS, but unconditionally
+ // compiled here because GHC.Event.Control depends on it.
+ SEQ_CST_STORE(&io_manager_wakeup_fd, fd);
+}
+
+#if defined(THREADED_RTS)
+void timerManagerNotifySignal(int sig, siginfo_t *info)
+{
+ StgWord8 buf[sizeof(siginfo_t) + 1];
+ int r;
+
+ buf[0] = sig;
+ if (info == NULL) {
+ // info may be NULL on Solaris (see #3790)
+ memset(buf+1, 0, sizeof(siginfo_t));
+ } else {
+ memcpy(buf+1, info, sizeof(siginfo_t));
+ }
+
+ int timer_control_fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
+ if (0 <= timer_control_fd)
+ {
+ r = write(timer_control_fd, buf, sizeof(siginfo_t)+1);
+ if (r == -1 && errno == EAGAIN) {
+ errorBelch("lost signal due to full pipe: %d\n", sig);
+ }
+ }
+
+ // If the IO manager hasn't told us what the FD of the write end
+ // of its pipe is, there's not much we can do here, so just ignore
+ // the signal..
+}
+#endif
+
+
+/* -----------------------------------------------------------------------------
+ * Wake up at least one IO or timer manager HS thread.
+ * -------------------------------------------------------------------------- */
+void
+ioManagerWakeup (void)
+{
+ int r;
+ const int wakeup_fd = SEQ_CST_LOAD(&io_manager_wakeup_fd);
+ // Wake up the IO Manager thread by sending a byte down its pipe
+ if (wakeup_fd >= 0) {
+#if defined(HAVE_EVENTFD)
+ StgWord64 n = (StgWord64)IO_MANAGER_WAKEUP;
+ r = write(wakeup_fd, (char *) &n, 8);
+#else
+ StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
+ r = write(wakeup_fd, &byte, 1);
+#endif
+ /* N.B. If the TimerManager is shutting down as we run this
+ * then there is a possibility that our first read of
+ * io_manager_wakeup_fd is non-negative, but before we get to the
+ * write the file is closed. If this occurs, io_manager_wakeup_fd
+ * will be written into with -1 (GHC.Event.Control does this prior
+ * to closing), so checking this allows us to distinguish this case.
+ * To ensure we observe the correct ordering, we declare the
+ * io_manager_wakeup_fd as volatile.
+ * Since this is not an error condition, we do not print the error
+ * message in this case.
+ */
+ if (r == -1 && SEQ_CST_LOAD(&io_manager_wakeup_fd) >= 0) {
+ sysErrorBelch("ioManagerWakeup: write");
+ }
+ }
+}
+
+#if defined(THREADED_RTS)
+void
+ioManagerDie (void)
+{
+ StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
+ uint32_t i;
+ int r;
+
+ {
+ // Shut down timer manager
+ const int fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
+ if (0 <= fd) {
+ r = write(fd, &byte, 1);
+ if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
+ RELAXED_STORE(&timer_manager_control_wr_fd, -1);
+ }
+ }
+
+ {
+ // Shut down IO managers
+ for (i=0; i < getNumCapabilities(); i++) {
+ const int fd = RELAXED_LOAD(&getCapability(i)->iomgr->control_fd);
+ if (0 <= fd) {
+ r = write(fd, &byte, 1);
+ if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
+ RELAXED_STORE(&getCapability(i)->iomgr->control_fd, -1);
+ }
+ }
+ }
+}
+
+void
+ioManagerStartCap (Capability **cap)
+{
+ rts_evalIO(cap,ensureIOManagerIsRunning_closure,NULL);
+}
+
+void
+ioManagerStart (void)
+{
+ // Make sure the IO manager thread is running
+ Capability *cap;
+ if (SEQ_CST_LOAD(&timer_manager_control_wr_fd) < 0 || SEQ_CST_LOAD(&io_manager_wakeup_fd) < 0) {
+ cap = rts_lock();
+ ioManagerStartCap(&cap);
+ rts_unlock(cap);
+ }
+}
+#endif
+
=====================================
rts/posix/MIO.h
=====================================
@@ -0,0 +1,30 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2005
+ *
+ * Signal processing / handling.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#pragma once
+
+#include "IOManager.h"
+
+#if defined(HAVE_SIGNAL_H)
+# include <signal.h>
+#endif
+
+#include "BeginPrivate.h"
+
+/* Communicating with the IO manager thread (see GHC.Conc).
+ */
+void ioManagerWakeup (void);
+#if defined(THREADED_RTS)
+void ioManagerDie (void);
+void ioManagerStart (void);
+void ioManagerStartCap (/* inout */ Capability **cap);
+
+void timerManagerNotifySignal(int sig, siginfo_t *info);
+#endif
+
+#include "EndPrivate.h"
=====================================
rts/posix/Poll.c
=====================================
@@ -41,6 +41,7 @@
#include "IOManagerInternals.h"
#include "Timeout.h"
+#include "FdWakeup.h"
/******************************************************************************
@@ -107,8 +108,9 @@ timeout (if any) as the poll() timeout parameter.
The CapIOManager structure for this I/O manager contains:
ClosureTable aiop_table;
- struct pollfd *aiop_poll_table;
+ struct pollfd *aiop_poll_table, *full_poll_table;
StgTimeoutQueue *timeout_queue;
+ int wakeup_fd_r, wakeup_fd_w;
We also support the Linux-specific ppoll API which supports higher resolution
time delays -- nanoseconds rather than milliseconds as in classic poll(). It
@@ -117,6 +119,15 @@ also allows the signal mask to be adjusted, but we do not make use of this.
int ppoll(struct pollfd *fds, nfds_t nfds,
const struct timespec *tmo_p, const sigset_t *sigmask);
+We have both aiop_poll_table and full_poll_table. This is to cope with needing
+to wait on the special extra file descriptor wakeup_fd_r. This fd is used to
+support waking the I/O manager when we are blocked in a poll call. This
+requires waiting on an extra fd that has no corresponding entry in the
+aiop_table. To manage this quirk, we alias the aiop_poll_table to be the tail
+of the full_poll_table and have the first entry of the full_poll_table be the
+wakeup_fd_r. This means the aiop_poll_table indicies match up exactly with the
+aiop_table, but still allows the full_poll_table to have an extra entry.
+
******************************************************************************/
/* Forward declarations */
@@ -129,8 +140,31 @@ static void reportPollError(int res, nfds_t nfds) STG_NORETURN;
void initCapabilityIOManagerPoll(CapIOManager *iomgr)
{
initClosureTable(&iomgr->aiop_table, ClosureTableCompact);
- iomgr->aiop_poll_table = NULL;
iomgr->timeout_queue = emptyTimeoutQueue();
+
+ newFdWakeup(&iomgr->wakeup_fd_r, &iomgr->wakeup_fd_w);
+
+ iomgr->full_poll_table = stgMallocBytes(sizeof(struct pollfd) /* size 1 */,
+ "initCapabilityIOManagerPoll");
+ iomgr->full_poll_table[0] = (struct pollfd) {
+ .fd = iomgr->wakeup_fd_r,
+ .events = POLLIN,
+ .revents = 0
+ };
+ iomgr->aiop_poll_table = iomgr->full_poll_table+1; /* hence empty */
+}
+
+
+void freeCapabilityIOManagerPoll(CapIOManager *iomgr)
+{
+ stgFree(iomgr->full_poll_table);
+ closeFdWakeup(iomgr->wakeup_fd_r, iomgr->wakeup_fd_w);
+}
+
+
+void wakeupIOManagerPoll(CapIOManager *iomgr)
+{
+ sendFdWakeup(iomgr->wakeup_fd_w);
}
@@ -227,13 +261,6 @@ static void ioCancel(CapIOManager *iomgr, StgAsyncIOOp *aiop)
}
-bool anyPendingTimeoutsOrIOPoll(CapIOManager *iomgr)
-{
- return !isEmptyTimeoutQueue(iomgr->timeout_queue)
- || !isEmptyClosureTable(&iomgr->aiop_table);
-}
-
-
static void notifyIOCompletion(CapIOManager *iomgr, StgAsyncIOOp *aiop)
{
ASSERT(aiop->outcome != IOOpOutcomeInFlight);
@@ -275,7 +302,7 @@ static void notifyIOCompletion(CapIOManager *iomgr, StgAsyncIOOp *aiop)
}
-static void processIOCompletions(CapIOManager *iomgr, int ncompletions)
+static bool processIOCompletions(CapIOManager *iomgr, int ncompletions)
{
/* The scheme we use with poll is that we have a dense poll table, and a
* corresponding table that maps to the closure table index. The poll
@@ -285,6 +312,19 @@ static void processIOCompletions(CapIOManager *iomgr, int ncompletions)
*/
debugTrace(DEBUG_iomanager, "processIOCompletions(ncompletions = %d)",
ncompletions);
+
+ bool wakeup;
+ /* If the wakeup_fd_r is ready, collect it */
+ if (iomgr->full_poll_table[0].revents) {
+ ASSERT(iomgr->full_poll_table[0].fd == iomgr->wakeup_fd_r);
+ collectFdWakeup(iomgr->wakeup_fd_r);
+ ncompletions--;
+ wakeup = true;
+ debugTrace(DEBUG_iomanager, "Received wakeup in poll I/O manager.");
+ } else {
+ wakeup = false;
+ }
+
struct pollfd *aiop_poll_table = iomgr->aiop_poll_table;
int n = ncompletions;
int i = 0;
@@ -337,11 +377,14 @@ static void processIOCompletions(CapIOManager *iomgr, int ncompletions)
i++;
}
}
+ return wakeup;
}
void pollCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
{
+ ASSERT(iomgr->aiop_poll_table == iomgr->full_poll_table+1);
+
if (!isEmptyTimeoutQueue(iomgr->timeout_queue)) {
Time now = getProcessElapsedTime();
processTimeoutCompletions(iomgr, now);
@@ -349,20 +392,20 @@ void pollCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
if (!isEmptyClosureTable(&iomgr->aiop_table)) {
- nfds_t nfds = sizeClosureTable(&iomgr->aiop_table);
+ nfds_t nfds = sizeClosureTable(&iomgr->aiop_table) + 1;
/* Poll for I/O readiness, without waiting. */
#if defined(HAVE_DECL_PPOLL) && HAVE_DECL_PPOLL == 1
/* We could use poll here, since we use no timeout, but for
consistency we use the same syscall as at the other call site. */
struct timespec tv = (struct timespec) { .tv_sec = 0, .tv_nsec = 0 };
- int res = ppoll(iomgr->aiop_poll_table, nfds, &tv, NULL);
+ int res = ppoll(iomgr->full_poll_table, nfds, &tv, NULL);
debugTrace(DEBUG_iomanager,
"ppoll(nfds = %d, timeout.sec = 0, timeout.nsec = 0) = %d",
nfds, res);
#else
- int res = poll(iomgr->aiop_poll_table, nfds, 0);
+ int res = poll(iomgr->full_poll_table, nfds, 0);
debugTrace(DEBUG_iomanager,
"poll(nfds = %d, timeout_ms = 0) = %d",
@@ -385,11 +428,19 @@ void pollCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
reportPollError(res, nfds);
}
}
+
+#if defined(RTS_USER_SIGNALS)
+ startPendingSignalHandlers(iomgr->cap);
+#endif
}
void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
{
+ bool wakeup = false; /* got woken up via wakeupIOManager */
+
+ ASSERT(iomgr->aiop_poll_table == iomgr->full_poll_table+1);
+
/* Loop until we've woken up some threads. This loop is needed because the
* poll() timing isn't accurate, we sometimes sleep for a while but not
* long enough to wake up a thread in a threadDelay. Or we may need to
@@ -397,9 +448,10 @@ void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
* that select() supports.
*/
do {
- /* There is either pending I/O or pending timers. */
- ASSERT(!isEmptyTimeoutQueue(iomgr->timeout_queue) ||
- !isEmptyClosureTable(&iomgr->aiop_table));
+ /* We do /not/ require that there be pending I/O or pending timers.
+ * If there is neither, it's because the scheduler wants us to wait
+ * on signals only.
+ */
Time now = getProcessElapsedTime();
processTimeoutCompletions(iomgr, now);
@@ -422,9 +474,9 @@ void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
#endif
/* Check for I/O readiness, possibly waiting. */
- nfds_t nfds = sizeClosureTable(&iomgr->aiop_table);
+ nfds_t nfds = sizeClosureTable(&iomgr->aiop_table) + 1;
#if defined(HAVE_DECL_PPOLL) && HAVE_DECL_PPOLL == 1
- int res = ppoll(iomgr->aiop_poll_table, nfds, timeout_ns, NULL);
+ int res = ppoll(iomgr->full_poll_table, nfds, timeout_ns, NULL);
debugTrace(DEBUG_iomanager,
"ppoll(nfds = %d, timeout.sec = %d, timeout.nsec = %d) = %d",
@@ -432,7 +484,7 @@ void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
timeout_ns == NULL ? 0 : timeout_ns->tv_nsec,
res);
#else
- int res = poll(iomgr->aiop_poll_table, nfds, timeout_ms);
+ int res = poll(iomgr->full_poll_table, nfds, timeout_ms);
debugTrace(DEBUG_iomanager,
"poll(nfds = %d, timeout_ms = %d) = %d",
@@ -454,17 +506,16 @@ void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
} else if (res > 0) {
int ncompletions = res;
ASSERT(ncompletions <= (int)nfds);
- processIOCompletions(iomgr, ncompletions);
+ wakeup = processIOCompletions(iomgr, ncompletions);
} else if (errno == EINTR) {
- /* We got interrupted by a signal. In the non-threaded RTS, if the
- * signal is one of ours we need to return to the scheduler to let
- * it handle it. Otherwise we would loop and keep waiting for I/O
- * or timeouts, meaning we would block for a long time before the
- * signal is serviced.
- */
+ /* We got interrupted by a signal. */
+
#if defined(RTS_USER_SIGNALS)
- if (startPendingSignalHandlers(iomgr->cap)) break;
+ /* Start any corresponding user signal handlers. If any, the run
+ * queue will become non-empty and we will drop out of the loop.
+ */
+ startPendingSignalHandlers(iomgr->cap);
#endif
/* We can also be interrupted by the shutdown signal handler, which
@@ -479,6 +530,7 @@ void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
}
} while (emptyRunQueue(iomgr->cap)
+ && !wakeup
&& (getSchedState() == SCHED_RUNNING));
}
@@ -508,13 +560,17 @@ static bool enlargeTables(CapIOManager *iomgr)
bool ok = enlargeClosureTable(iomgr->cap, &iomgr->aiop_table, newcapacity);
if (RTS_UNLIKELY(!ok)) return false;
- /* Update the auxiliary aiop_poll_table to match */
- struct pollfd *aiop_poll_table;
- aiop_poll_table = stgReallocBytes(iomgr->aiop_poll_table,
- sizeof(struct pollfd) * newcapacity,
- "Poll.c: enlargeTables");
- iomgr->aiop_poll_table = aiop_poll_table;
+ /* Update the auxiliary aiop_poll_table to match. The full_poll_table is
+ * one bigger than the aiop_poll_table, since it has an extra entry at the
+ * front for wakeup_fd_r, with no corresponding aiop. */
+ iomgr->full_poll_table =
+ stgReallocBytes(iomgr->full_poll_table,
+ sizeof(struct pollfd) * (newcapacity+1),
+ "Poll.c: enlargeTables");
+ iomgr->aiop_poll_table = iomgr->full_poll_table+1;
+
/* Initialise the new part of the aiop_poll_table */
+ struct pollfd *aiop_poll_table = iomgr->aiop_poll_table;
for (int i = oldcapacity; i < newcapacity; i++) {
aiop_poll_table[i] = (struct pollfd) {
.fd = -1,
=====================================
rts/posix/Poll.h
=====================================
@@ -17,6 +17,8 @@
#if defined(IOMGR_ENABLED_POLL)
void initCapabilityIOManagerPoll(CapIOManager *iomgr);
+void freeCapabilityIOManagerPoll(CapIOManager *iomgr);
+void wakeupIOManagerPoll(CapIOManager *iomgr);
/* Synchronous I/O and timer operations */
bool syncIOWaitReadyPoll(CapIOManager *iomgr, StgTSO *tso,
@@ -29,7 +31,6 @@ bool asyncIOWaitReadyPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop,
void asyncIOCancelPoll(CapIOManager *iomgr, StgAsyncIOOp *aiop);
/* Scheduler operations */
-bool anyPendingTimeoutsOrIOPoll(CapIOManager *iomgr);
void pollCompletedTimeoutsOrIOPoll(CapIOManager *iomgr);
void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr);
=====================================
rts/posix/Select.c
=====================================
@@ -12,7 +12,7 @@
#include "rts/PosixSource.h"
#include "Rts.h"
-#include "Signals.h"
+#include "RtsSignals.h"
#include "Schedule.h"
#include "Prelude.h"
#include "RaiseAsync.h"
@@ -22,6 +22,7 @@
#include "IOManagerInternals.h"
#include "Stats.h"
#include "GetTime.h"
+#include "FdWakeup.h"
# if defined(HAVE_SYS_SELECT_H)
# include <sys/select.h>
@@ -54,6 +55,25 @@
#define TimeToLowResTimeRoundUp(t) (t)
#endif
+void initCapabilityIOManagerSelect(CapIOManager *iomgr)
+{
+ iomgr->blocked_queue_hd = END_TSO_QUEUE;
+ iomgr->blocked_queue_tl = END_TSO_QUEUE;
+ iomgr->sleeping_queue = END_TSO_QUEUE;
+
+ newFdWakeup(&iomgr->wakeup_fd_r, &iomgr->wakeup_fd_w);
+}
+
+void freeCapabilityIOManagerSelect(CapIOManager *iomgr)
+{
+ closeFdWakeup(iomgr->wakeup_fd_r, iomgr->wakeup_fd_w);
+}
+
+void wakeupIOManagerSelect(CapIOManager *iomgr)
+{
+ sendFdWakeup(iomgr->wakeup_fd_w);
+}
+
/*
* Return the time since the program started, in LowResTime,
* rounded down.
@@ -225,6 +245,7 @@ awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait)
bool seen_bad_fd = false;
struct timeval tv, *ptv;
LowResTime now;
+ bool wakeup = false; /* got woken up via wakeupIOManager */
IF_DEBUG(scheduler,
debugBelch("scheduler: checking for threads blocked on I/O");
@@ -252,6 +273,13 @@ awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait)
FD_ZERO(&rfd);
FD_ZERO(&wfd);
+ /* We're always interested in our wakeup fd */
+ {
+ int fd = iomgr->wakeup_fd_r;
+ maxfd = (fd > maxfd) ? fd : maxfd;
+ FD_SET(fd, &rfd);
+ }
+
for(tso = iomgr->blocked_queue_hd;
tso != END_TSO_QUEUE;
tso = next) {
@@ -346,16 +374,11 @@ awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait)
}
}
- /* We got a signal; could be one of ours. If so, we need
- * to start up the signal handler straight away, otherwise
- * we could block for a long time before the signal is
- * serviced.
- */
#if defined(RTS_USER_SIGNALS)
- if (RtsFlags.MiscFlags.install_signal_handlers && signals_pending()) {
- startSignalHandlers(iomgr->cap);
- return; /* still hold the lock */
- }
+ /* Start any corresponding user signal handlers. If any, the run
+ * queue will become non-empty and we will drop out of the loop.
+ */
+ startPendingSignalHandlers(iomgr->cap);
#endif
/* we were interrupted, return to the scheduler immediately.
@@ -376,6 +399,13 @@ awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait)
}
}
+ /* If the wakeup_fd_r is ready, collect it */
+ if (FD_ISSET(iomgr->wakeup_fd_r, &rfd)) {
+ collectFdWakeup(iomgr->wakeup_fd_r);
+ wakeup = true;
+ debugTrace(DEBUG_iomanager, "Received wakeup in select I/O manager.");
+ }
+
/* Step through the waiting queue, unblocking every thread that now has
* a file descriptor in a ready state.
*/
@@ -458,7 +488,8 @@ awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait)
}
} while (wait && getSchedState() == SCHED_RUNNING
- && emptyRunQueue(iomgr->cap));
+ && emptyRunQueue(iomgr->cap)
+ && !wakeup);
}
#endif /* IOMGR_ENABLED_SELECT */
=====================================
rts/posix/Select.h
=====================================
@@ -15,6 +15,10 @@ typedef StgWord LowResTime;
LowResTime getDelayTarget (HsInt us);
+void initCapabilityIOManagerSelect(CapIOManager *iomgr);
+void freeCapabilityIOManagerSelect(CapIOManager *iomgr);
+void wakeupIOManagerSelect(CapIOManager *iomgr);
+
void awaitCompletedTimeoutsOrIOSelect(CapIOManager *iomgr, bool wait);
#include "EndPrivate.h"
=====================================
rts/posix/Signals.c
=====================================
@@ -9,21 +9,13 @@
#include "rts/PosixSource.h"
#include "Rts.h"
-#include "Schedule.h"
#include "RtsSignals.h"
-#include "Signals.h"
-#include "IOManager.h"
+#include "posix/Signals.h"
#include "RtsUtils.h"
+#include "Schedule.h"
#include "Prelude.h"
-#include "Ticker.h"
#include "ThreadLabels.h"
-#include "Libdw.h"
-
-/* TODO: eliminate this include. This file should be about signals, not be
- * part of an I/O manager implementation. The code here that are really part
- * of an I/O manager should be moved into an appropriate I/O manager impl.
- */
-#include "IOManagerInternals.h"
+#include "MIO.h"
#if defined(alpha_HOST_ARCH)
# if defined(linux_HOST_OS)
@@ -45,10 +37,6 @@
# include <errno.h>
#endif
-#if defined(HAVE_EVENTFD_H)
-# include <sys/eventfd.h>
-#endif
-
#if defined(HAVE_TERMIOS_H)
#include <termios.h>
#endif
@@ -107,6 +95,11 @@ freeSignalHandlers(void) {
#endif
}
+void finiUserSignals(void)
+{
+ /* nothing */
+};
+
/* -----------------------------------------------------------------------------
* Allocate/resize the table of signal handlers.
* -------------------------------------------------------------------------- */
@@ -134,110 +127,6 @@ more_handlers(int sig)
nHandlers = sig + 1;
}
-// Here's the pipe into which we will send our signals
-static int io_manager_wakeup_fd = -1;
-static int timer_manager_control_wr_fd = -1;
-
-#define IO_MANAGER_WAKEUP 0xff
-#define IO_MANAGER_DIE 0xfe
-#define IO_MANAGER_SYNC 0xfd
-
-void setTimerManagerControlFd(int fd) {
- RELAXED_STORE(&timer_manager_control_wr_fd, fd);
-}
-
-void
-setIOManagerWakeupFd (int fd)
-{
- // only called when THREADED_RTS, but unconditionally
- // compiled here because GHC.Event.Control depends on it.
- SEQ_CST_STORE(&io_manager_wakeup_fd, fd);
-}
-
-/* -----------------------------------------------------------------------------
- * Wake up at least one IO or timer manager HS thread.
- * -------------------------------------------------------------------------- */
-void
-ioManagerWakeup (void)
-{
- int r;
- const int wakeup_fd = SEQ_CST_LOAD(&io_manager_wakeup_fd);
- // Wake up the IO Manager thread by sending a byte down its pipe
- if (wakeup_fd >= 0) {
-#if defined(HAVE_EVENTFD)
- StgWord64 n = (StgWord64)IO_MANAGER_WAKEUP;
- r = write(wakeup_fd, (char *) &n, 8);
-#else
- StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
- r = write(wakeup_fd, &byte, 1);
-#endif
- /* N.B. If the TimerManager is shutting down as we run this
- * then there is a possibility that our first read of
- * io_manager_wakeup_fd is non-negative, but before we get to the
- * write the file is closed. If this occurs, io_manager_wakeup_fd
- * will be written into with -1 (GHC.Event.Control does this prior
- * to closing), so checking this allows us to distinguish this case.
- * To ensure we observe the correct ordering, we declare the
- * io_manager_wakeup_fd as volatile.
- * Since this is not an error condition, we do not print the error
- * message in this case.
- */
- if (r == -1 && SEQ_CST_LOAD(&io_manager_wakeup_fd) >= 0) {
- sysErrorBelch("ioManagerWakeup: write");
- }
- }
-}
-
-#if defined(THREADED_RTS)
-void
-ioManagerDie (void)
-{
- StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
- uint32_t i;
- int r;
-
- {
- // Shut down timer manager
- const int fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
- if (0 <= fd) {
- r = write(fd, &byte, 1);
- if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
- RELAXED_STORE(&timer_manager_control_wr_fd, -1);
- }
- }
-
- {
- // Shut down IO managers
- for (i=0; i < getNumCapabilities(); i++) {
- const int fd = RELAXED_LOAD(&getCapability(i)->iomgr->control_fd);
- if (0 <= fd) {
- r = write(fd, &byte, 1);
- if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
- RELAXED_STORE(&getCapability(i)->iomgr->control_fd, -1);
- }
- }
- }
-}
-
-void
-ioManagerStartCap (Capability **cap)
-{
- rts_evalIO(cap,ensureIOManagerIsRunning_closure,NULL);
-}
-
-void
-ioManagerStart (void)
-{
- // Make sure the IO manager thread is running
- Capability *cap;
- if (SEQ_CST_LOAD(&timer_manager_control_wr_fd) < 0 || SEQ_CST_LOAD(&io_manager_wakeup_fd) < 0) {
- cap = rts_lock();
- ioManagerStartCap(&cap);
- rts_unlock(cap);
- }
-}
-#endif
-
#if !defined(THREADED_RTS)
#define N_PENDING_HANDLERS 16
@@ -245,6 +134,10 @@ ioManagerStart (void)
siginfo_t pending_handler_buf[N_PENDING_HANDLERS];
siginfo_t *next_pending_handler = pending_handler_buf;
+static inline bool signals_pending(void) {
+ return (next_pending_handler != pending_handler_buf);
+}
+
#endif /* THREADED_RTS */
/* -----------------------------------------------------------------------------
@@ -260,31 +153,9 @@ generic_handler(int sig USED_IF_THREADS,
void *p STG_UNUSED)
{
#if defined(THREADED_RTS)
-
- StgWord8 buf[sizeof(siginfo_t) + 1];
- int r;
-
- buf[0] = sig;
- if (info == NULL) {
- // info may be NULL on Solaris (see #3790)
- memset(buf+1, 0, sizeof(siginfo_t));
- } else {
- memcpy(buf+1, info, sizeof(siginfo_t));
- }
-
- int timer_control_fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
- if (0 <= timer_control_fd)
- {
- r = write(timer_control_fd, buf, sizeof(siginfo_t)+1);
- if (r == -1 && errno == EAGAIN) {
- errorBelch("lost signal due to full pipe: %d\n", sig);
- }
- }
-
- // If the IO manager hasn't told us what the FD of the write end
- // of its pipe is, there's not much we can do here, so just ignore
- // the signal..
-
+ //TODO: This calls MIO directly. We should go via IOManager API.
+ // The IOManager API should be extended to cover signals.
+ timerManagerNotifySignal(sig, info);
#else /* not THREADED_RTS */
/* Can't call allocate from here. Probably can't call malloc
@@ -346,22 +217,6 @@ unblockUserSignals(void)
sigprocmask(SIG_SETMASK, &savedSignals, NULL);
}
-bool
-anyUserHandlers(void)
-{
- return n_haskell_handlers != 0;
-}
-
-#if !defined(THREADED_RTS)
-void
-awaitUserSignals(void)
-{
- while (!signals_pending() && getSchedState() == SCHED_RUNNING) {
- pause();
- }
-}
-#endif
-
/* -----------------------------------------------------------------------------
* Install a Haskell signal handler.
*
@@ -468,11 +323,13 @@ stg_sig_install(int sig, int spi, void *mask)
#if !defined(THREADED_RTS)
void
-startSignalHandlers(Capability *cap)
+startPendingSignalHandlers(Capability *cap)
{
siginfo_t *info;
int sig;
+ if (!signals_pending()) return;
+
blockUserSignals();
while (next_pending_handler != pending_handler_buf) {
@@ -484,7 +341,7 @@ startSignalHandlers(Capability *cap)
continue; // handler has been changed.
}
- info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers");
+ info = stgMallocBytes(sizeof(siginfo_t), "startPendingSignalHandlers");
// freed by runHandler
memcpy(info, next_pending_handler, sizeof(siginfo_t));
=====================================
rts/posix/Signals.h
=====================================
@@ -2,43 +2,19 @@
*
* (c) The GHC Team, 1998-2005
*
- * Signal processing / handling.
+ * POSIX signal processing / handling.
+ *
+ * Most of the API for this is common between POSIX and Win32 console events.
+ * The common part of the API lives in RtsSignals.h.
*
* ---------------------------------------------------------------------------*/
#pragma once
-#if defined(HAVE_SIGNAL_H)
-# include <signal.h>
-#endif
-
#include "Ticker.h"
#include "BeginPrivate.h"
-bool anyUserHandlers(void);
-
-#if !defined(THREADED_RTS) && defined(RTS_USER_SIGNALS)
-extern siginfo_t pending_handler_buf[];
-extern siginfo_t *next_pending_handler;
-#define signals_pending() (next_pending_handler != pending_handler_buf)
-void startSignalHandlers(Capability *cap);
-#endif
-
void install_vtalrm_handler(int sig, TickProc handle_tick);
-/* Communicating with the IO manager thread (see GHC.Conc).
- *
- * TODO: these I/O manager things are not related to signals and ought to live
- * elsewhere, e.g. in a module specifically for the I/O manager.
- */
-void ioManagerWakeup (void);
-#if defined(THREADED_RTS)
-void ioManagerDie (void);
-void ioManagerStart (void);
-void ioManagerStartCap (/* inout */ Capability **cap);
-#endif
-
-extern StgInt *signal_handlers;
-
#include "EndPrivate.h"
=====================================
rts/rts.cabal
=====================================
@@ -569,6 +569,7 @@ library
wasm/OSThreads.c
wasm/JSFFI.c
wasm/JSFFIGlobals.c
+ posix/FdWakeup.c
posix/Select.c
posix/Poll.c
posix/Timeout.c
@@ -581,6 +582,8 @@ library
posix/Ticker.c
posix/OSMem.c
posix/OSThreads.c
+ posix/FdWakeup.c
+ posix/MIO.c
posix/Poll.c
posix/Select.c
posix/Signals.c
=====================================
rts/win32/AwaitEvent.c
=====================================
@@ -14,6 +14,7 @@
*
*/
#include "Rts.h"
+#include "RtsSignals.h"
#include "RtsFlags.h"
#include "Schedule.h"
#include "IOManager.h"
@@ -41,14 +42,9 @@ awaitCompletedTimeoutsOrIOWin32(Capability *cap, bool wait)
awaitRequests(wait);
workerWaitingForRequests = false;
- // If a signal was raised, we need to service it
- // XXX the scheduler loop really should be calling
- // startSignalHandlers(), but this is the way that posix/Select.c
- // does it and I'm feeling too paranoid to refactor it today --SDM
- if (stg_pending_events != 0) {
- startSignalHandlers(cap);
- return;
- }
+ // If a signal was raised, we need to service it. This will typically
+ // start a thread, which will cause us to drop out of the loop.
+ startPendingSignalHandlers(cap);
// The return value from awaitRequests() is a red herring: ignore
// it. Return to the scheduler if !wait, or
=====================================
rts/win32/ConsoleHandler.c
=====================================
@@ -154,29 +154,18 @@ unblockUserSignals(void)
}
-/*
- * Function: awaitUserSignals()
- *
- * Wait for the next console event. Currently a NOP (returns immediately.)
- */
-void awaitUserSignals(void)
-{
- return;
-}
-
-
#if !defined(THREADED_RTS)
/*
- * Function: startSignalHandlers()
+ * Function: startPendingSignalHandlers()
*
- * Run the handlers associated with the stacked up console events. Console
- * event delivery is blocked for the duration of this call.
+ * If there are any queued up console events, run the handlers associated with
+ * them. Console event delivery is blocked for the duration of this call.
*/
-void startSignalHandlers(Capability *cap)
+void startPendingSignalHandlers(Capability *cap)
{
StgStablePtr handler;
- if (console_handler < 0) {
+ if (stg_pending_events <= 0 || console_handler < 0) {
return;
}
=====================================
rts/win32/ConsoleHandler.h
=====================================
@@ -23,36 +23,6 @@
* thread, which starts up the handler. See ThrIOManager.c.
*/
-/*
- * Function: signals_pending()
- *
- * Used by the RTS to check whether new signals have been 'recently' reported.
- * If so, the RTS arranges for the delivered signals to be handled by
- * de-queueing them from their table, running the associated Haskell
- * signal handler.
- */
-extern StgInt stg_pending_events;
-
-#define signals_pending() ( stg_pending_events > 0)
-
-/*
- * Function: anyUserHandlers()
- *
- * Used by the Scheduler to decide whether its worth its while to stick
- * around waiting for an external signal when there are no threads
- * runnable. A console handler is used to handle termination events (Ctrl+C)
- * and isn't considered a 'user handler'.
- */
-#define anyUserHandlers() (false)
-
-/*
- * Function: startSignalHandlers()
- *
- * Run the handlers associated with the queued up console events. Console
- * event delivery is blocked for the duration of this call.
- */
-extern void startSignalHandlers(Capability *cap);
-
/*
* Function: rts_waitConsoleHandlerCompletion()
*
@@ -62,10 +32,3 @@ extern void startSignalHandlers(Capability *cap);
extern int rts_waitConsoleHandlerCompletion(void);
#endif /* THREADED_RTS */
-
-/*
- * Function: finiUserSignals()
- *
- * Tear down and shut down user signal processing.
- */
-extern void finiUserSignals(void);
=====================================
testsuite/tests/rts/T26408.hs
=====================================
@@ -0,0 +1,43 @@
+import Control.Concurrent
+import Control.Concurrent.STM
+import Control.Exception
+import Control.Monad
+
+-- | Test to make sure that deadlock detection works even when there are other
+-- unrelated threads that are blocked on I\/O or timeouts.
+-- Historically however this did affect things in the non-threaded RTS which
+-- would only do deadlock detection if there were no runnable threads /and/
+-- no pending I\/O. See <https://gitlab.haskell.org/ghc/ghc/-/issues/26408>
+main :: IO ()
+main = do
+
+ -- Set up two threads that are deadlocked on each other
+ aDone <- newTVarIO False
+ bDone <- newTVarIO False
+ let blockingThread theirDone ourDone =
+ atomically $ do
+ done <- readTVar theirDone
+ guard done
+ writeTVar ourDone True
+ _ <- forkIO (blockingThread bDone aDone)
+ _ <- forkIO (blockingThread aDone bDone)
+
+ -- Set up another thread that is blocked on a long timeout.
+ --
+ -- We use a timeout rather than I/O as it's more portable, whereas I/O waits
+ -- are different between posix and windows I/O managers.
+ --
+ -- One gotcha is that when the timeout completes then the deadlock will be
+ -- detected again (since the bug is about I/O or timeouts masking deadlock
+ -- detection). So for a reliable test the timeout used here must be longer
+ -- than the test framework's own timeout. So we use maxBound, and we adjust
+ -- the test framework's timeout to be short (see run_timeout_multiplier).
+ _ <- forkIO (threadDelay maxBound)
+
+ -- Wait on the deadlocked threads to terminate. We now expect that the threads
+ -- that are deadlocked are detected as such and an exception is raised.
+ -- Note that if this fails, the test itself will effectively deadlock and
+ -- will rely on the test framework's timeout.
+ atomically $ do
+ status <- mapM readTVar [aDone, bDone]
+ guard (or status)
=====================================
testsuite/tests/rts/T26408.stderr
=====================================
@@ -0,0 +1,3 @@
+T26408: Uncaught exception ghc-internal:GHC.Internal.IO.Exception.BlockedIndefinitelyOnSTM:
+
+thread blocked indefinitely in an STM transaction
=====================================
testsuite/tests/rts/all.T
=====================================
@@ -657,6 +657,8 @@ test('T22859',
omit_ways(llvm_ways)],
compile_and_run, ['-with-rtsopts -A8K'])
+test('T26408', [exit_code(1), run_timeout_multiplier(0.1)], compile_and_run, [''])
+
# These tests need access to the internal RTS headers.
# TODO: there is probably some cleaner way to do this, and it should probably
# be guarded for in-tree tests, since it cannot work against an arbitrary
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/97cb8f22c15ee24b8486d59382a1a0…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/97cb8f22c15ee24b8486d59382a1a0…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 23 commits: chore: Merge GHC.Internal.TH.Quote into GHC.Internal.TH.Monad
by Marge Bot (@marge-bot) 10 Mar '26
by Marge Bot (@marge-bot) 10 Mar '26
10 Mar '26
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
23a50772 by Rajkumar Natarajan at 2026-03-10T14:11:37-04:00
chore: Merge GHC.Internal.TH.Quote into GHC.Internal.TH.Monad
Move the QuasiQuoter datatype from GHC.Internal.TH.Quote to
GHC.Internal.TH.Monad and delete the Quote module.
Update submodule template-haskell-quasiquoter to use the merged
upstream version that imports from the correct module.
Co-authored-by: Cursor <cursoragent(a)cursor.com>
- - - - -
a2bb6fc3 by Simon Jakobi at 2026-03-10T14:12:23-04:00
Add regression test for #16122
- - - - -
b3d4e76d by Cheng Shao at 2026-03-10T14:45:55-04:00
hadrian: remove the broken bench flavour
This patch removes the bench flavour from hadrian which has been
broken for years and not used for actual benchmarking (for which
`perf`/`release` is used instead). Closes #26825.
- - - - -
7786b4d7 by Simon Jakobi at 2026-03-10T14:46:01-04:00
Add regression test for #18186
The original TypeInType language extension is replaced with
DataKinds+PolyKinds for compatibility.
Closes #18186.
- - - - -
e4d1fe6e by Andreas Klebinger at 2026-03-10T14:46:03-04:00
Bump nofib submodule.
We accrued a number of nofib fixes we want to have here.
- - - - -
3b49c75f by Simon Jakobi at 2026-03-10T14:46:07-04:00
Add regression test for #15907
Closes #15907.
- - - - -
8aeae0eb by Simon Jakobi at 2026-03-10T14:46:11-04:00
Ensure T14272 is run in optasm way
Closes #16539.
- - - - -
362754a0 by Simon Jakobi at 2026-03-10T14:46:11-04:00
Add regression test for #24632
Closes #24632.
- - - - -
87976da6 by Simon Jakobi at 2026-03-10T14:46:11-04:00
Fix module name of T9675: T6975 -> T9675
- - - - -
b1329004 by Andreas Klebinger at 2026-03-10T14:46:12-04:00
User guide: Clarify phase control on INLINEABLE[foo] pragmas.
Fixes #26851
- - - - -
3d3b6601 by Simon Jakobi at 2026-03-10T14:46:13-04:00
Add regression test for #12694
Closes #12694.
- - - - -
29bf02a9 by Simon Jakobi at 2026-03-10T14:46:13-04:00
Add regression test for #16275
Closes #16275.
- - - - -
a07ff678 by Simon Jakobi at 2026-03-10T14:46:14-04:00
Add regression test for #14908
Closes #14908.
- - - - -
99a76346 by Simon Jakobi at 2026-03-10T14:46:14-04:00
Add regression test for #14151
Closes #14151.
- - - - -
33c6f8ad by Simon Jakobi at 2026-03-10T14:46:14-04:00
Add regression test for #12640
Closes #12640.
- - - - -
9d396bed by Simon Jakobi at 2026-03-10T14:46:14-04:00
Add regression test for #15588
Closes #15588.
- - - - -
3910775f by Simon Jakobi at 2026-03-10T14:46:14-04:00
Add regression test for #9445
Closes #9445.
- - - - -
032e7e75 by Cheng Shao at 2026-03-10T14:46:15-04:00
compiler: implement string interning logic for BCONPtrFS
This patch adds a `FastStringEnv`-based cache of `MallocStrings`
requests to `Interp`, so that when we load bytecode with many
breakpoints that share the same module names & unit ids, we reuse the
allocated remote pointers instead of issuing duplicte `MallocStrings`
requests and bloating the C heap. Closes #26995.
- - - - -
391e2a87 by Simon Jakobi at 2026-03-10T14:46:15-04:00
Add perf test for #1216
Closes #1216.
- - - - -
00de5e26 by Sylvain Henry at 2026-03-10T14:46:40-04:00
JS: check that tuple constructors are linked (#23709)
Test js-mk_tup was failing before because tuple constructors weren't
linked in. It's no longer an issue after the linker fixes.
- - - - -
d2db47c1 by Matthew Pickering at 2026-03-10T14:46:42-04:00
testsuite: Add test for foreign import prim with unboxed tuple return
This commit just adds a test that foreign import prim works with unboxed
sums.
- - - - -
28031962 by Matthew Pickering at 2026-03-10T14:46:42-04:00
Return a valid pointer in advanceStackFrameLocationzh
When there is no next stack chunk, `advanceStackFrameLocationzh` used to
return NULL in the pointer-typed StackSnapshot# result slot.
Even though the caller treats that case as "no next frame", the result is
still materialized in a GC-visible pointer slot. If a GC observes the raw
NULL there, stack decoding can crash.
Fix this by ensuring the dead pointer slot contains a valid closure
pointer. Also make the optional result explicit by returning an unboxed
sum instead of a tuple with a separate tag.
Fixes #27009
- - - - -
819a4023 by Cheng Shao at 2026-03-10T14:46:42-04:00
hadrian: build profiled dynamic objects with -dynamic-too
This patch enables hadrian to build profiled dynamic objects with
`-dynamic-too`, addressing a build parallelism bottleneck in release
pipelines. Closes #27010.
- - - - -
65 changed files:
- compiler/GHC/Builtin/Names/TH.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Runtime/Interpreter/Init.hs
- compiler/GHC/Runtime/Interpreter/Types.hs
- docs/users_guide/exts/pragmas.rst
- docs/users_guide/exts/rewrite_rules.rst
- hadrian/doc/flavours.md
- hadrian/hadrian.cabal
- hadrian/src/Rules/Compile.hs
- hadrian/src/Settings.hs
- hadrian/src/Settings/Builders/Ghc.hs
- − hadrian/src/Settings/Flavours/Benchmark.hs
- libraries/ghc-boot-th/GHC/Boot/TH/Quote.hs
- libraries/ghc-internal/cbits/Stack.cmm
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Stack/Decode.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- − libraries/ghc-internal/src/GHC/Internal/TH/Quote.hs
- libraries/template-haskell-quasiquoter
- nofib
- + testsuite/tests/corelint/T15907.hs
- + testsuite/tests/corelint/T15907A.hs
- testsuite/tests/corelint/all.T
- + testsuite/tests/dependent/should_fail/T15588.hs
- + testsuite/tests/dependent/should_fail/T15588.stderr
- testsuite/tests/dependent/should_fail/all.T
- + testsuite/tests/ffi/should_run/PrimFFIUnboxedSum.hs
- + testsuite/tests/ffi/should_run/PrimFFIUnboxedSum.stdout
- + testsuite/tests/ffi/should_run/PrimFFIUnboxedSum_cmm.cmm
- testsuite/tests/ffi/should_run/all.T
- + testsuite/tests/ghci/scripts/T24632.hs
- + testsuite/tests/ghci/scripts/T24632.script
- + testsuite/tests/ghci/scripts/T24632.stdout
- testsuite/tests/ghci/scripts/all.T
- testsuite/tests/javascript/js-mk_tup.hs
- testsuite/tests/javascript/js-mk_tup.stdout
- testsuite/tests/linters/Makefile
- testsuite/tests/perf/compiler/T9675.hs
- + testsuite/tests/perf/should_run/T1216.hs
- + testsuite/tests/perf/should_run/T1216.stdout
- testsuite/tests/perf/should_run/all.T
- testsuite/tests/plugins/plugins10.stdout
- + testsuite/tests/polykinds/T18186.hs
- + testsuite/tests/polykinds/T18186.stderr
- testsuite/tests/polykinds/all.T
- testsuite/tests/quotes/QQError.stderr
- + testsuite/tests/simplCore/should_compile/T12640.hs
- + testsuite/tests/simplCore/should_compile/T12640.stderr
- + testsuite/tests/simplCore/should_compile/T14908.hs
- + testsuite/tests/simplCore/should_compile/T14908_Deps.hs
- + testsuite/tests/simplCore/should_compile/T16122.hs
- + testsuite/tests/simplCore/should_compile/T16122.stderr
- + testsuite/tests/simplCore/should_compile/T9445.hs
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/th/QQTopError.stderr
- + testsuite/tests/typecheck/should_compile/T14151.hs
- testsuite/tests/typecheck/should_compile/all.T
- + testsuite/tests/typecheck/should_fail/T12694.hs
- + testsuite/tests/typecheck/should_fail/T12694.stderr
- + testsuite/tests/typecheck/should_fail/T16275.stderr
- + testsuite/tests/typecheck/should_fail/T16275A.hs
- + testsuite/tests/typecheck/should_fail/T16275B.hs
- + testsuite/tests/typecheck/should_fail/T16275B.hs-boot
- testsuite/tests/typecheck/should_fail/all.T
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/95f7632627cbd23727a739a98cb265…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/95f7632627cbd23727a739a98cb265…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
10 Mar '26
Cheng Shao pushed new branch wip/fix-th-redundant-import at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/fix-th-redundant-import
You're receiving this email because of your account on gitlab.haskell.org.
1
0
10 Mar '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
a2bb6fc3 by Simon Jakobi at 2026-03-10T14:12:23-04:00
Add regression test for #16122
- - - - -
3 changed files:
- + testsuite/tests/simplCore/should_compile/T16122.hs
- + testsuite/tests/simplCore/should_compile/T16122.stderr
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
testsuite/tests/simplCore/should_compile/T16122.hs
=====================================
@@ -0,0 +1,12 @@
+{-# LANGUAGE TypeApplications #-}
+-- Test that the Core for f isn't "worse" than g's.
+-- The optimized Core for f used to involve dictionary-passing. See #16122.
+module T16122 (f, g) where
+
+import Data.Int (Int64)
+
+f :: Double -> Int64
+f = round
+
+g :: Double -> Int64
+g = fromIntegral @Int @Int64 . round
=====================================
testsuite/tests/simplCore/should_compile/T16122.stderr
=====================================
@@ -0,0 +1,26 @@
+f = \ x ->
+ I64#
+ (case x of { D# ds1 ->
+ case {__ffi_static_ccall_unsafe ghc-internal:rintDouble :: Double#
+ -> State# RealWorld
+ -> (# State# RealWorld, Double# #)}
+ ds1 realWorld#
+ of
+ { (# _, ds3 #) ->
+ intToInt64# (double2Int# ds3)
+ }
+ })
+
+g = \ x ->
+ I64#
+ (case x of { D# ds1 ->
+ case {__ffi_static_ccall_unsafe ghc-internal:rintDouble :: Double#
+ -> State# RealWorld
+ -> (# State# RealWorld, Double# #)}
+ ds1 realWorld#
+ of
+ { (# _, ds3 #) ->
+ intToInt64# (double2Int# ds3)
+ }
+ })
+
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -295,6 +295,10 @@ test('T15631',
normal,
makefile_test, ['T15631'])
test('T15673', normal, compile, ['-O'])
+test('T16122', [when(wordsize(32), skip)],
+ multimod_compile_filter,
+ ['T16122', '-O -ddump-simpl -dsuppress-all -dsuppress-uniques -dno-typeable-binds',
+ "sed -n '/^f = /,/^$/p;/^g = /,/^$/p'"])
test('T16288', normal, multimod_compile, ['T16288B', '-O -dcore-lint -v0'])
test('T16348', normal, compile, ['-O'])
test('T16918', normal, compile, ['-O'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a2bb6fc35dc13cb696286a8496f72c7…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a2bb6fc35dc13cb696286a8496f72c7…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][master] chore: Merge GHC.Internal.TH.Quote into GHC.Internal.TH.Monad
by Marge Bot (@marge-bot) 10 Mar '26
by Marge Bot (@marge-bot) 10 Mar '26
10 Mar '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
23a50772 by Rajkumar Natarajan at 2026-03-10T14:11:37-04:00
chore: Merge GHC.Internal.TH.Quote into GHC.Internal.TH.Monad
Move the QuasiQuoter datatype from GHC.Internal.TH.Quote to
GHC.Internal.TH.Monad and delete the Quote module.
Update submodule template-haskell-quasiquoter to use the merged
upstream version that imports from the correct module.
Co-authored-by: Cursor <cursoragent(a)cursor.com>
- - - - -
10 changed files:
- compiler/GHC/Builtin/Names/TH.hs
- libraries/ghc-boot-th/GHC/Boot/TH/Quote.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- − libraries/ghc-internal/src/GHC/Internal/TH/Quote.hs
- libraries/template-haskell-quasiquoter
- testsuite/tests/linters/Makefile
- testsuite/tests/plugins/plugins10.stdout
- testsuite/tests/quotes/QQError.stderr
- testsuite/tests/th/QQTopError.stderr
Changes:
=====================================
compiler/GHC/Builtin/Names/TH.hs
=====================================
@@ -185,7 +185,7 @@ thSyn, thMonad, thLib, qqLib, liftLib :: Module
thSyn = mkTHModule (fsLit "GHC.Internal.TH.Syntax")
thMonad = mkTHModule (fsLit "GHC.Internal.TH.Monad")
thLib = mkTHModule (fsLit "GHC.Internal.TH.Lib")
-qqLib = mkTHModule (fsLit "GHC.Internal.TH.Quote")
+qqLib = mkTHModule (fsLit "GHC.Internal.TH.Monad")
liftLib = mkTHModule (fsLit "GHC.Internal.TH.Lift")
=====================================
libraries/ghc-boot-th/GHC/Boot/TH/Quote.hs
=====================================
@@ -1,5 +1,5 @@
{-# OPTIONS_HADDOCK not-home #-}
module GHC.Boot.TH.Quote
- (module GHC.Internal.TH.Quote) where
+ (QuasiQuoter(..)) where
-import GHC.Internal.TH.Quote
+import GHC.Internal.TH.Monad (QuasiQuoter(..))
=====================================
libraries/ghc-internal/ghc-internal.cabal.in
=====================================
@@ -306,7 +306,6 @@ Library
GHC.Internal.TH.Syntax
GHC.Internal.TH.Lib
GHC.Internal.TH.Lift
- GHC.Internal.TH.Quote
GHC.Internal.TH.Monad
GHC.Internal.TopHandler
GHC.Internal.TypeError
=====================================
libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
=====================================
@@ -20,6 +20,7 @@
-- Import "Language.Haskell.TH" or "Language.Haskell.TH.Syntax" instead!
module GHC.Internal.TH.Monad
( module GHC.Internal.TH.Monad
+ , QuasiQuoter(..)
) where
#ifdef BOOTSTRAP_TH
@@ -313,6 +314,33 @@ class Monad m => Quote m where
instance Quote Q where
newName s = Q (qNewName s)
+-----------------------------------------------------
+--
+-- The QuasiQuoter type
+--
+-----------------------------------------------------
+
+-- | The 'QuasiQuoter' type, a value @q@ of this type can be used
+-- in the syntax @[q| ... string to parse ...|]@. In fact, for
+-- convenience, a 'QuasiQuoter' actually defines multiple quasiquoters
+-- to be used in different splice contexts. In the usual case of a
+-- @QuasiQuoter@ that is only intended to be used in certain splice
+-- contexts, the unused fields should just 'fail'. This is most easily
+-- accomplished using 'namedefaultQuasiQuoter' or 'defaultQuasiQuoter'.
+--
+-- This is exposed both from the @template-haskell-quasiquoter@ and @template-haskell@ packages.
+-- Consider importing it from the more stable @template-haskell-quasiquoter@ if you don't need the full breadth of the @template-haskell@ interface.
+data QuasiQuoter = QuasiQuoter {
+ -- | Quasi-quoter for expressions, invoked by quotes like @lhs = $[q|...]@
+ quoteExp :: String -> Q Exp,
+ -- | Quasi-quoter for patterns, invoked by quotes like @f $[q|...] = rhs@
+ quotePat :: String -> Q Pat,
+ -- | Quasi-quoter for types, invoked by quotes like @f :: $[q|...]@
+ quoteType :: String -> Q Type,
+ -- | Quasi-quoter for declarations, invoked by top-level quotes
+ quoteDec :: String -> Q [Dec]
+ }
+
-----------------------------------------------------
--
-- The TExp type
=====================================
libraries/ghc-internal/src/GHC/Internal/TH/Quote.hs deleted
=====================================
@@ -1,46 +0,0 @@
-{-# LANGUAGE CPP, RankNTypes, ScopedTypeVariables, Trustworthy #-}
-{- |
-Module : GHC.Internal.TH.Quote
-Description : Quasi-quoting support for Template Haskell
-
-Template Haskell supports quasiquoting, which permits users to construct
-program fragments by directly writing concrete syntax. A quasiquoter is
-essentially a function with takes a string to a Template Haskell AST.
-This module defines the 'QuasiQuoter' datatype, which specifies a
-quasiquoter @q@ which can be invoked using the syntax
-@[q| ... string to parse ... |]@ when the @QuasiQuotes@ language
-extension is enabled, and some utility functions for manipulating
-quasiquoters. Nota bene: this package does not define any parsers,
-that is up to you.
-
-This is an internal module. Please import 'Language.Haskell.TH.Quote' instead.
--}
-module GHC.Internal.TH.Quote(
- QuasiQuoter(..),
- ) where
-
-import GHC.Internal.TH.Syntax
-import GHC.Internal.TH.Monad
-import GHC.Internal.Base hiding (Type)
-
-
--- | The 'QuasiQuoter' type, a value @q@ of this type can be used
--- in the syntax @[q| ... string to parse ...|]@. In fact, for
--- convenience, a 'QuasiQuoter' actually defines multiple quasiquoters
--- to be used in different splice contexts. In the usual case of a
--- @QuasiQuoter@ that is only intended to be used in certain splice
--- contexts, the unused fields should just 'fail'. This is most easily
--- accomplished using 'namedefaultQuasiQuoter' or 'defaultQuasiQuoter'.
---
--- This is exposed both from the @template-haskell-quasiquoter@ and @template-haskell@ packages.
--- Consider importing it from the more stable @template-haskell-quasiquoter@ if you don't need the full breadth of the @template-haskell@ interface.
-data QuasiQuoter = QuasiQuoter {
- -- | Quasi-quoter for expressions, invoked by quotes like @lhs = $[q|...]@
- quoteExp :: String -> Q Exp,
- -- | Quasi-quoter for patterns, invoked by quotes like @f $[q|...] = rhs@
- quotePat :: String -> Q Pat,
- -- | Quasi-quoter for types, invoked by quotes like @f :: $[q|...]@
- quoteType :: String -> Q Type,
- -- | Quasi-quoter for declarations, invoked by top-level quotes
- quoteDec :: String -> Q [Dec]
- }
=====================================
libraries/template-haskell-quasiquoter
=====================================
@@ -1 +1 @@
-Subproject commit a47506eca032b139d9779fb8210d408c81d3fbd6
+Subproject commit e7c7af444a467fb8d56483583987002b43317576
=====================================
testsuite/tests/linters/Makefile
=====================================
@@ -81,7 +81,6 @@ whitespace:
libraries/base/include/HsEvent.h\
libraries/base/include/md5.h\
libraries/ghc-prim/GHC/Tuple.hs\
- libraries/template-haskell/Language/Haskell/TH/Quote.hs\
rts/STM.h\
rts/Sparks.h\
rts/Threads.h\
=====================================
testsuite/tests/plugins/plugins10.stdout
=====================================
@@ -6,10 +6,9 @@ interfacePlugin: GHC.Internal.Base
interfacePlugin: GHC.Internal.Data.NonEmpty
interfacePlugin: GHC.Internal.Float
interfacePlugin: GHC.Internal.Prim.Ext
-interfacePlugin: GHC.Internal.TH.Quote
+interfacePlugin: GHC.Internal.TH.Monad
interfacePlugin: GHC.Internal.TH.Syntax
typeCheckPlugin (rn)
-interfacePlugin: GHC.Internal.TH.Monad
interfacePlugin: GHC.Internal.Stack.Types
interfacePlugin: GHC.Internal.Exception.Context
typeCheckPlugin (tc)
=====================================
testsuite/tests/quotes/QQError.stderr
=====================================
@@ -1,5 +1,5 @@
QQError.hs:5:12: error: [GHC-83865]
- • Couldn't match expected type ‘GHC.Internal.TH.Quote.QuasiQuoter’
+ • Couldn't match expected type ‘GHC.Internal.TH.Monad.QuasiQuoter’
with actual type ‘a1 -> a1’
• Probable cause: ‘id’ is applied to too few arguments
In the expression: [| [id|hello|] |]
@@ -9,7 +9,7 @@ QQError.hs:5:12: error: [GHC-83865]
| ^^
QQError.hs:7:13: error: [GHC-83865]
- • Couldn't match expected type ‘GHC.Internal.TH.Quote.QuasiQuoter’
+ • Couldn't match expected type ‘GHC.Internal.TH.Monad.QuasiQuoter’
with actual type ‘a0 -> a0’
• Probable cause: ‘id’ is applied to too few arguments
In the expression: [| [id|hello|] |]
=====================================
testsuite/tests/th/QQTopError.stderr
=====================================
@@ -1,10 +1,10 @@
QQTopError.hs:4:9: error: [GHC-83865]
- • Couldn't match expected type ‘GHC.Internal.TH.Quote.QuasiQuoter’
+ • Couldn't match expected type ‘GHC.Internal.TH.Monad.QuasiQuoter’
with actual type ‘a0 -> a0’
• Probable cause: ‘id’ is applied to too few arguments
- In the first argument of ‘GHC.Internal.TH.Quote.quoteExp’, namely
+ In the first argument of ‘GHC.Internal.TH.Monad.quoteExp’, namely
‘id’
- In the expression: GHC.Internal.TH.Quote.quoteExp id "hello"
+ In the expression: GHC.Internal.TH.Monad.quoteExp id "hello"
In the quasi-quotation: [id|hello|]
|
4 | main = [id|hello|]
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/23a50772c9c55c46b1c4ffb8ef60a08…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/23a50772c9c55c46b1c4ffb8ef60a08…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/on-exception-annotate] exceptions: annotate onException continuation with WhileHandling
by Matthew Pickering (@mpickering) 10 Mar '26
by Matthew Pickering (@mpickering) 10 Mar '26
10 Mar '26
Matthew Pickering pushed to branch wip/on-exception-annotate at Glasgow Haskell Compiler / GHC
Commits:
642000be by Matthew Pickering at 2026-03-10T16:12:33+00:00
exceptions: annotate onException continuation with WhileHandling
Before this patch, an exception thrown in the `onException` handler
would loose track of where the original exception was thrown.
```
import Control.Exception
main :: IO ()
main = failingAction `onException` failingCleanup
where
failingAction = throwIO (ErrorCall "outer failure")
failingCleanup = throwIO (ErrorCall "cleanup failure")
```
would report
```
T28399: Uncaught exception ghc-internal:GHC.Internal.Exception.ErrorCall:
cleanup failure
HasCallStack backtrace:
throwIO, called at T28399.hs:<line>:<column> in <package-id>:Main
```
notice that the "outer failure" exception is not present in the error
message.
With this patch, any exception thrown is in the handler is annotated
with WhileHandling. The resulting message looks like
```
T28399: Uncaught exception ghc-internal:GHC.Internal.Exception.ErrorCall:
cleanup failure
While handling outer failure
HasCallStack backtrace:
throwIO, called at T28399.hs:7:22 in main:Main
```
CLC Proposal: https://github.com/haskell/core-libraries-committee/issues/397
Fixes #26759
- - - - -
9 changed files:
- libraries/base/changelog.md
- libraries/ghc-internal/src/GHC/Internal/Control/Exception/Base.hs
- libraries/ghc-internal/src/GHC/Internal/IO.hs
- + testsuite/tests/exceptions/T26759.hs
- + testsuite/tests/exceptions/T26759.stderr
- + testsuite/tests/exceptions/T26759a.hs
- + testsuite/tests/exceptions/T26759a.stderr
- + testsuite/tests/exceptions/T26759a.stdout
- testsuite/tests/exceptions/all.T
Changes:
=====================================
libraries/base/changelog.md
=====================================
@@ -27,6 +27,7 @@
* Evaluate backtraces for "error" exceptions at the moment they are thrown. ([CLC proposal #383](https://github.com/haskell/core-libraries-committee/issues/383))
* Hide implementation details when throwing exceptions in throw and throwSTM. ([CLC proposal #387](https://github.com/haskell/core-libraries-committee/issues/387))
* Change `hIsReadable` and `hIsWritable` such that they always throw a respective exception when encountering a closed or semi-closed handle, not just in the case of a file handle. ([CLC proposal #371](github.com/haskell/core-libraries-committee/issues/371))
+ * Annotate `onException` continuation with `WhileHandling`. ([CLC Proposal #397](https://github.com/haskell/core-libraries-committee/issues/397))
## 4.22.0.0 *TBA*
* Shipped with GHC 9.14.1
=====================================
libraries/ghc-internal/src/GHC/Internal/Control/Exception/Base.hs
=====================================
@@ -203,7 +203,7 @@ tryJust p a = catchJust p (Right `fmap` a) (return . Left)
-- exception raised by the computation.
onException :: IO a -> IO b -> IO a
onException io what = io `catchNoPropagate` \e -> do
- _ <- what
+ _ <- annotateIO (whileHandling e) what
rethrowIO (e :: ExceptionWithContext SomeException)
-----------------------------------------------------------------------------
=====================================
libraries/ghc-internal/src/GHC/Internal/IO.hs
=====================================
@@ -52,7 +52,7 @@ module GHC.Internal.IO (
import GHC.Internal.Base
import GHC.Internal.ST
import GHC.Internal.Exception
-import GHC.Internal.Exception.Type (NoBacktrace(..), WhileHandling(..), HasExceptionContext, ExceptionWithContext(..))
+import GHC.Internal.Exception.Type (NoBacktrace(..), whileHandling, WhileHandling(..), HasExceptionContext, ExceptionWithContext(..))
import GHC.Internal.Show
import GHC.Internal.IO.Unsafe
import GHC.Internal.Unsafe.Coerce ( unsafeCoerce )
@@ -363,7 +363,7 @@ getMaskingState = IO $ \s ->
onException :: IO a -> IO b -> IO a
onException io what = io `catchExceptionNoPropagate` \e -> do
- _ <- what
+ _ <- annotateIO (whileHandling e) what
rethrowIO (e :: ExceptionWithContext SomeException)
-- | Executes an IO computation with asynchronous
=====================================
testsuite/tests/exceptions/T26759.hs
=====================================
@@ -0,0 +1,10 @@
+import Control.Exception
+
+run :: IO ()
+run = failingAction `onException` failingCleanup
+ where
+ failingAction = throwIO (ErrorCall "outer failure")
+ failingCleanup = throwIO (ErrorCall "cleanup failure")
+
+main :: IO ()
+main = run
=====================================
testsuite/tests/exceptions/T26759.stderr
=====================================
@@ -0,0 +1,9 @@
+T26759: Uncaught exception ghc-internal:GHC.Internal.Exception.ErrorCall:
+
+cleanup failure
+
+While handling outer failure
+
+HasCallStack backtrace:
+ throwIO, called at T26759.hs:7:22 in main:Main
+
=====================================
testsuite/tests/exceptions/T26759a.hs
=====================================
@@ -0,0 +1,10 @@
+import Control.Exception
+
+run :: IO ()
+run = failingAction `onException` cleanup
+ where
+ failingAction = throwIO (ErrorCall "outer failure")
+ cleanup = putStrLn "cleanup"
+
+main :: IO ()
+main = run
=====================================
testsuite/tests/exceptions/T26759a.stderr
=====================================
@@ -0,0 +1,7 @@
+T26759a: Uncaught exception ghc-internal:GHC.Internal.Exception.ErrorCall:
+
+outer failure
+
+HasCallStack backtrace:
+ throwIO, called at T26759a.hs:6:21 in main:Main
+
=====================================
testsuite/tests/exceptions/T26759a.stdout
=====================================
@@ -0,0 +1 @@
+cleanup
=====================================
testsuite/tests/exceptions/all.T
=====================================
@@ -1,2 +1,3 @@
test('T25052', normal, compile_and_run, [''])
-
+test('T26759', exit_code(1), compile_and_run, [''])
+test('T26759a', exit_code(1), compile_and_run, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/642000be5ba31e5b4af83ff2390704f…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/642000be5ba31e5b4af83ff2390704f…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/on-exception-annotate] 106 commits: PPC NCG: Use libcall for 64-bit cmpxchg on 32-bit PowerPC
by Matthew Pickering (@mpickering) 10 Mar '26
by Matthew Pickering (@mpickering) 10 Mar '26
10 Mar '26
Matthew Pickering pushed to branch wip/on-exception-annotate at Glasgow Haskell Compiler / GHC
Commits:
ce2d62fb by Jessica Clarke at 2026-01-29T19:48:51-05:00
PPC NCG: Use libcall for 64-bit cmpxchg on 32-bit PowerPC
There is no native instruction for this, and even if there were a
register pair version we could use, the implementation here is assuming
the values fit in a single register, and we end up only using / defining
the low halves of the registers.
Fixes: b4d39adbb5 ("PrimOps: Add CAS op for all int sizes")
Fixes: #23969
- - - - -
43d97761 by Michael Karcher at 2026-01-29T19:49:43-05:00
NCG for PPC: add pattern for CmmRegOff to iselExpr64
Closes #26828
- - - - -
aeeb4a20 by Matthew Pickering at 2026-01-30T11:42:47-05:00
determinism: Use deterministic map for Strings in TyLitMap
When generating typeable evidence the types we need evidence for all
cached in a TypeMap, the order terms are retrieved from a type map
determines the order the bindings appear in the program.
A TypeMap is quite diligent to use deterministic maps, apart from in the
TyLitMap, which uses a UniqFM for storing strings, whose ordering
depends on the Unique of the FastString.
This can cause non-deterministic .hi and .o files.
An unexpected side-effect is the error message but RecordDotSyntaxFail8
changing. I looked into this with Sam and this change caused the
constraints to be solved in a different order which results in a
slightly different error message. I have accepted the new test, since
the output before was non-deterministic and the new output is consistent
with the other messages in that file.
Fixes #26846
- - - - -
9e4d70c2 by Andrew Lelechenko at 2026-01-30T11:43:29-05:00
Upgrade text submodule to 2.1.4
- - - - -
631fa5ae by Recursion Ninja at 2026-01-31T22:30:11+00:00
Decouple `L.S.H.Decls` from importing `GHC.Types.Basic`
Data-types within `GHC.Types.Basic` which describe components of
the AST are migrated to `Language.Haskell.Syntax.Basic`. Related
function definitions are also moved.
Types moved to L.H.S. because they are part of the AST:
* TopLevelFlag
* RuleName
Types moved from L.H.S. to GHC.Hs. because they are not needed in the AST:
* TyConFlavour
* TypeOrData
* NewOrData
Migrated instances:
* `Outputable` instances moved to in `GHC.Utils.Outputable`
* `Binary` instance of `Boxity` moved to to `GHC.Utils.Binary`
* Other `Binary` instances are orphans to be migrated later.
The `OverlapMode` data-type is given a TTG extension point.
The `OverlapFlag` data-type, which depends on `OverlapMode`,
is updated to support `OverlapMode` with a GHC "pass" type paramerter.
In order to avoid module import cycles, `OverlapMode` and `OverlapFlag`
are migrated to new modules (no way around this).
* Migrated `OverlapMode` to new module `Language.Haskell.Syntax.Overlap`
* Migrated `OverlapFlag` to new module `GHC.Hs.Decls.Overlap`
- - - - -
9769cc03 by Simon Hengel at 2026-02-01T04:21:03-05:00
Update the documentation for MultiWayIf (fixes #25376)
(so that it matches the implementation)
- - - - -
5fc9442a by Peter Trommler at 2026-02-01T04:21:44-05:00
hadrian: Fix dependency generation for assembler
Assembler files allow # for comments unless in column 1. A modern
cpp for C treats those a preprocessor directives. We tell gcc that
a .S file is assembler with cpp and not C.
Fixes #26819
- - - - -
269c4087 by Simon Peyton Jones at 2026-02-01T19:38:10-05:00
Include current phase in the range for rule/unfoldings
This MR fixes a bad loop in the compiler: #26826.
The fix is to add (WAR2) to
Note [What is active in the RHS of a RULE or unfolding?]
in GHC.Core.Opt.Simplify.Utils
- - - - -
ddf1434f by Vladislav Zavialov at 2026-02-01T19:38:52-05:00
Refactor: merge HsMultilineString into HsString (#26860)
Before this patch, HsLit defined two separate constructors to represent
single-line and multi-line strings:
data HsLit x
...
| HsString (XHsString x) FastString
| HsMultilineString (XHsMultilineString x) FastString
I found this to be an unnecessary complication and an obstacle to unifying
HsLit with HsTyLit. Now we use HsString for both kinds of literals.
One user-facing change here is `ppr (HsString st s)` behaving differently for
single-line strings containing newlines:
x = "first line \
\asdf\n\
\second line"
Previously, the literal was fed to `ftext` with its newlines, producing an
ill-formed SDoc. This issue is now addressed by using `split` for both
single-line and multi-line strings:
vcat $ map text $ split '\n' (unpackFS src)
See the parser/should_fail/T26860ppr test.
In addition (and unrelatedly to the main payload of this patch),
drop the unused pmPprHsLit helper.
- - - - -
2b4f463c by Simon Peyton Jones at 2026-02-02T17:32:32+00:00
Remove exprIsCheap from doFloatFromRhs
See #26854 and Note [Float when expandable]
This patch simplifies the code, by removing an extra unnecessary test.
- - - - -
9db7f21f by Brandon Chinn at 2026-02-03T09:15:10-05:00
Refactor: make function patterns exhaustive
Also added missing (==) logic for:
* HsMultilineString
* HsInt{8,16,32}
* HsWord{8,16,32}
- - - - -
aa9c5e2c by Hécate Kleidukos at 2026-02-03T15:58:35-05:00
driver: Hide source paths at verbosity level 1 by default
- - - - -
c64cca1e by mangoiv at 2026-02-03T15:59:29-05:00
ExplicitLevelImports: check staging for types just like for values
Previously, imported types were entirely exempted from staging checks as
the implicit stage persistance assumed to be all imported types to be
well staged. ExplicitLevelImports' change specification, however, does
not do such an exemption. Thus we want to introduce such a check, just
like we have for values.
ExplicitLevelImports does not, however, talk about local names - from
its perspective, we could theoretically keep treating locally introduced
types specially - e.g. an ill-staged used in a quote would only emit a
warning, not an error. To allow for a potential future migration away
from such wrinkles as the staging check in notFound
(see Note [Out of scope might be a staging error]) we consistently do
the strict staging check that we also do for value if ExplicitLevelImports
is on.
Closes #26098
- - - - -
5f0dbeb6 by Simon Hengel at 2026-02-03T16:00:12-05:00
Use Haddock formatting in deprecation message of `initNameCache`
- - - - -
01ecb612 by Andreas Klebinger at 2026-02-04T09:56:25-05:00
testsuite: Explicitly use utf-8 encoding in rts-includes linter.
Not doing so caused failures on windows, as python failed to pick a
reasonable encoding even with locale set.
Fixes #26850
- - - - -
ea0d1317 by Zubin Duggal at 2026-02-04T09:57:06-05:00
Bump transformers submodule to 0.6.3.0
Fixes #26790
- - - - -
cbe4300e by Simon Peyton Jones at 2026-02-05T04:31:04-05:00
Fix subtle bug in GHC.Core.Utils.mkTick
This patch fixes a decade-old bug in `mkTick`, which
could generate type-incorrect code! See the diagnosis
in #26772.
The new code is simpler and easier to understand.
(As #26772 says, I think it could be improved further.)
- - - - -
a193a8da by Simon Peyton Jones at 2026-02-05T04:31:04-05:00
Modify a debug-trace in the Simplifier
...just to show a bit more information.
- - - - -
b579dfdc by Simon Peyton Jones at 2026-02-05T04:31:04-05:00
Fix long-standing interaction between ticks and casts
The code for Note [Eliminate Identity Cases] was simply wrong when
ticks and casts interacted. This patch fixes the interaction.
It was shown up when validating #26772, although it's not the exactly
the bug that's reported by #26772. Nor is it easy to reproduce, hence
no regression test.
- - - - -
fac0de1e by Cheng Shao at 2026-02-05T04:31:49-05:00
libraries: bump Cabal submodule to 3.16.1.0
- - - - -
00589122 by Cheng Shao at 2026-02-05T04:31:49-05:00
libraries: bump deepseq submodule to 1.5.2.0
Also:
- Get rid of usage of deprecated `NFData` function instance in the
compiler
- `T21391` still relies on `NFData` function instance, add
`-Wno-deprecations` for the time being.
- - - - -
84474c71 by Cheng Shao at 2026-02-05T04:31:50-05:00
libraries: bump directory submodule to 1.3.10.1
- - - - -
1a9f4662 by Cheng Shao at 2026-02-05T04:31:50-05:00
libraries: bump exceptions submodule to 0.10.12
- - - - -
2e39a340 by Peng Fan at 2026-02-07T03:42:01-05:00
NCG/LA64: adjust register usage to avoid src-register being clobbered
- - - - -
9faf1b35 by Teo Camarasu at 2026-02-07T03:42:43-05:00
ghc-internal: Delete unnecessary GHC.Internal.Data.Ix
This module merely re-exports GHC.Internal.Ix. It was copied from
`base` when `ghc-internal` was split, but there is no reason to have
this now. So, let's delete it.
Resolves #26848
- - - - -
d112b440 by Sven Tennie at 2026-02-07T10:47:56-05:00
Add cabal.project file to generate-ci
This fixes the HLS setup for our CI code generation script
(generate-ci).
The project file simply makes `generate-ci` of the cabal file
discoverable.
- - - - -
5339f6f0 by Andreas Klebinger at 2026-02-07T10:48:40-05:00
CI: Don't collapse test results.
This puts test output back into the primary test log instead of a
subsection removing the need to expand a section to see test results.
While the intention was good in practice the old behaviour mostly wastes time
by requiring expansion of the section.
Fixes #26882
- - - - -
0e1cd2e0 by Evan Piro at 2026-02-08T10:35:16-08:00
Linker.MacOS reduce dynflags import
- - - - -
1c79a4cd by Michael Alan Dorman at 2026-02-09T08:11:51-05:00
Remove `extra_src_files` variable from `testsuite/driver/testlib.py`
While reading through the test harness code, I noticed this variable
with a TODO attached that referenced #12223. Although that bug is
closed, it strongly implied that this special-case variable that only
affected a single test was expected to be removed at some point.
I also looked at 3415bcaa0b1903b5e12dfaadb5b774718e406eab---where it
was added---whose commit message suggested that it would have been
desirable to remove it, but that there were special circumstances that
meant it had to remain (though it doesn't elucidate what those special
circumstances are).
However, the special circumstances were mentioned as if the test was
in a different location than is currently is, so I decided to try
changing the test to use the standard `extra_files` mechanism, which
works in local testing.
This also seems like a reasonable time to remove the script that was
originally used in the transition, since it doesn't really serve a
purpose anymore.
- - - - -
0020e38a by Matthew Pickering at 2026-02-09T17:29:14-05:00
determinism: Use a stable sort in WithHsDocIdentifiers binary instance
`WithHsDocIdentifiers` is defined as
```
71 data WithHsDocIdentifiers a pass = WithHsDocIdentifiers
72 { hsDocString :: !a
73 , hsDocIdentifiers :: ![Located (IdP pass)]
74 }
```
This list of names is populated from `rnHsDocIdentifiers`, which calls
`lookupGRE`, which calls `lookupOccEnv_AllNameSpaces`, which calls
`nonDetEltsUFM` and returns the results in an order depending on
uniques.
Sorting the list with a stable sort before returning the interface makes
the output deterministic and follows the approach taken by other fields
in `Docs`.
Fixes #26858
- - - - -
89898ce6 by echoumcp1 at 2026-02-09T17:30:01-05:00
Replace putstrln with logMsg in handleSeqHValueStatus
Fixes #26549
- - - - -
7c52c4f9 by John Paul Adrian Glaubitz at 2026-02-10T13:52:43-05:00
rts: Switch prim to use modern atomic compiler builtins
The __sync_*() atomic compiler builtins have been deprecated in GCC
for a while now and also don't provide variants for 64-bit values
such as __sync_fetch_and_add_8().
Thus, replace them with the modern __atomic_*() compiler builtins and
while we're at it, also drop the helper macro CAS_NAND() which is now
no longer needed since we stopped using the __sync_*() compiler builtins
altogether.
Co-authored-by: Ilias Tsitsimpis <iliastsi(a)debian.org>
Fixes #26729
- - - - -
cf60850a by Recursion Ninja at 2026-02-10T13:53:27-05:00
Decoupling L.H.S.Decls from GHC.Types.ForeignCall
- Adding TTG extension point for 'CCallTarget'
- Adding TTG extension point for 'CType'
- Adding TTG extension point for 'Header'
- Moving ForeignCall types that do not need extension
to new L.H.S.Decls.Foreign module
- Replacing 'Bool' parameters with descriptive data-types
to increase clairty and prevent "Boolean Blindness"
- - - - -
11a04cbb by Eric Lee at 2026-02-11T09:20:46-05:00
Derive Semigroup/Monoid for instances believed could be derived in #25871
- - - - -
15d9ce44 by Eric Lee at 2026-02-11T09:20:46-05:00
add Ghc.Data.Pair deriving
- - - - -
c85dc170 by Evan Piro at 2026-02-11T09:21:45-05:00
Linker.MacOS reduce options import
- - - - -
a541dd83 by Chris Wendt at 2026-02-11T16:06:41-05:00
Initialize plugins for `:set +c` in GHCi
Fixes #23110.
- - - - -
0f5a73bc by Cheng Shao at 2026-02-11T16:07:27-05:00
compiler: add Binary Text instance
This patch adds `Binary` instance for strict `Text`, in preparation of
making `Text` usable in certain GHC API use cases (e.g. haddock). This
also introduces `text` as a direct dependency of the `ghc` package.
- - - - -
9e58b8a1 by Cheng Shao at 2026-02-11T16:08:10-05:00
ghc-toolchain: add C11 check
This patch partially reverts commit
b8307eab80c5809df5405d76c822bf86877f5960 that removed C99 check in
autoconf/ghc-toolchain. Now we:
- No longer re-implement `FP_SET_CFLAGS_C11` similar to
`FP_SET_CFLAGS_C99` in the past, since autoconf doesn't provide a
convenient `AC_PROG_CC_C11` function. ghc-toolchain will handle it
anyway.
- The Cmm CPP C99 check is relanded and repurposed for C11.
- The C99 logic in ghc-toolchain is relanded and repurposed for C11.
- The C99 check in Stg.h is corrected to check for C11. The obsolete
_ISOC99_SOURCE trick is dropped.
- Usages of `-std=gnu99` in the testsuite are corrected to use
`-std=gnu11`.
Closes #26908.
- - - - -
4df0adf6 by Simon Peyton Jones at 2026-02-11T21:50:13-05:00
Simplify the treatment of static forms
This MR implements GHC proposal 732: simplify static forms,
https://github.com/ghc-proposals/ghc-proposals/pull/732
thereby addressing #26556.
See `Note [Grand plan for static forms]` in GHC.Iface.Tidy.StaticPtrTable
The main changes are:
* There is a new, simple rule for (static e), namely that the free
term variables of `e` must be bound at top level. The check is
done in the `HsStatic` case of `GHC.Rename.Expr.rnExpr`
* That in turn substantially simplifies the info that the typechecker
carries around in its type environment. Hooray.
* The desugarer emits static bindings to top level directly; see the
`HsStatic` case of `dsExpr`.
* There is no longer any special static-related magic in the FloatOut
pass. And the main Simplifier pipeline no longer needs a special case
to run FloatOut even with -O0. Hooray.
All this forced an unexpected change to the pattern match checker. It
recursively invokes the main Hs desugarer when it wants to take a look
at a term to spot some special cases (notably constructor applications).
We don't want to emit any nested (static e) bindings to top level a
second time! Yikes.
That forced a modest refactor in GHC.HsToCore.Pmc:
* The `dsl_nablas` field of `DsLclEnv` now has a `NoPmc` case, which says
"I'm desugaring just for pattern-match checking purposes".
* When that flag is set we don't emit static binds.
That in turn forces a cascade of refactoring, but the net effect is an
improvement; less risk of duplicated (even exponential?) work.
See Note [Desugaring HsExpr during pattern-match checking].
10% metric decrease, on some architectures, of compile-time max-bytes-used on T15304.
Metric Decrease:
T15304
- - - - -
7922f728 by Teo Camarasu at 2026-02-11T21:50:58-05:00
ghc-internal: avoid depending on GHC.Internal.Exts
This module is mostly just re-exports. It made sense as a user-facing
module, but there's no good reason ghc-internal modules should depend on
it and doing so linearises the module graph
- move considerAccessible to GHC.Internal.Magic
Previously it lived in GHC.Internal.Exts, but it really deserves to live
along with the other magic function, which are already re-exported from .Exts
- move maxTupleSize to GHC.Internal.Tuple
This previously lived in GHC.Internal.Exts but a comment already said it
should be moved to .Tuple
Resolves #26832
- - - - -
b6a4a29b by Eric Lee at 2026-02-11T21:51:55-05:00
Remove unused Semigroup imports to fix GHC 9.14 bootstrapping
- - - - -
99d8c146 by Simon Peyton Jones at 2026-02-12T17:36:59+00:00
Fix subtle bug in cast worker/wrapper
See (CWw4) in Note [Cast worker/wrapper].
The true payload is in the change to the definition of
GHC.Types.Id.Info.hasInlineUnfolding
Everthing else is just documentation.
There is a 2% compile time decrease for T13056;
I'll take the win!
Metric Decrease:
T13056
- - - - -
530e8e58 by Simon Peyton Jones at 2026-02-12T20:17:23-05:00
Add regression tests for four StaticPtr bugs
Tickets #26545, #24464, #24773, #16981 are all solved by the
recently-landed MR
commit 318ee13bcffa6aa8df42ba442ccd92aa0f7e210c
Author: Simon Peyton Jones <simon.peytonjones(a)gmail.com>
Date: Mon Oct 20 23:07:20 2025 +0100
Simplify the treatment of static forms
This MR just adds regression tests for them.
- - - - -
4157160f by Cheng Shao at 2026-02-13T06:27:04-05:00
ci: remove unused hlint-ghc-and-base job definition
This patch removes the unused `hlint-ghc-and-base` job definition,
it's never run since !9806. Note that hadrian lint rules still work
locally, so anyone that wishes to run hlint on the codebase can
continue to do so in their local worktree.
- - - - -
039f1977 by Cheng Shao at 2026-02-13T06:27:47-05:00
wasm: use import.meta.main for proper distinction of nodejs main modules
This patch uses `import.meta.main` for proper distinction of nodejs
main modules, especially when the main module might be installed as a
symlink. Fixes #26916.
- - - - -
14f485ee by ARATA Mizuki at 2026-02-17T09:09:24+09:00
Support more x86 extensions: AVX-512 {BW,DQ,VL} and GFNI
Also, mark AVX-512 ER and PF as deprecated.
AVX-512 instructions can be used for certain 64-bit integer vector operations.
GFNI can be used to implement bitReverse (currently not used by NCG, but LLVM may use it).
Closes #26406
Addresses #26509
- - - - -
016f79d5 by fendor at 2026-02-17T09:16:16-05:00
Hide implementation details from base exception stack traces
Ensure we hide the implementation details of the exception throwing mechanisms:
* `undefined`
* `throwSTM`
* `throw`
* `throwIO`
* `error`
The `HasCallStackBacktrace` should always have a length of exactly 1,
not showing internal implementation details in the stack trace, as these
are vastly distracting to end users.
CLC proposal [#387](https://github.com/haskell/core-libraries-committee/issues/387)
- - - - -
4f2840f2 by Brian J. Cardiff at 2026-02-17T17:04:08-05:00
configure: Accept happy-2.2
In Jan 2026 happy-2.2 was released. The most sensible change is https://github.com/haskell/happy/issues/335 which didn't trigger in a fresh build
- - - - -
10b4d364 by Duncan Coutts at 2026-02-17T17:04:52-05:00
Fix errors in the documentation of the eventlog STOP_THREAD status codes
Fix the code for BlockedOnMsgThrowTo.
Document all the known historical warts.
Fixes issue #26867
- - - - -
c5e15b8b by Phil de Joux at 2026-02-18T05:07:36-05:00
haddock: use snippets for all list examples
- generate snippet output for docs
- reduce font size to better fit snippets
- Use only directive to guard html snippets
- Add latex snippets for lists
- - - - -
d388bac1 by Phil de Joux at 2026-02-18T05:07:36-05:00
haddock: Place the snippet input and output together
- Put the output seemingly inside the example box
- - - - -
016fa306 by Samuel Thibault at 2026-02-18T05:08:35-05:00
Fix linking against libm by moving the -lm option
For those systems that need -lm for getting math functions, this is
currently added on the link line very early, before the object files being
linked together. Newer toolchains enable --as-needed by default, which means
-lm is ignored at that point because no object requires a math function
yet. With such toolchains, we thus have to add -lm after the objects, so the
linker actually includes libm in the link.
- - - - -
68bd0805 by Teo Camarasu at 2026-02-18T05:09:19-05:00
ghc-internal: Move GHC.Internal.Data.Bool to base
This is a tiny module that only defines bool :: Bool -> a -> a -> a. We can just move this to base and delete it from ghc-internal. If we want this functionality there we can just use a case statement or if-then expression.
Resolves 26865
- - - - -
4c40df3d by fendor at 2026-02-20T10:24:48-05:00
Add optional `SrcLoc` to `StackAnnotation` class
`StackAnnotation`s give access to an optional `SrcLoc` field that
user-added stack annotations can use to provide better backtraces in both error
messages and when decoding the callstack.
We update builtin stack annotations such as `StringAnnotation` and
`ShowAnnotation` to also capture the `SrcLoc` of the current `CallStack`
to improve backtraces by default (if stack annotations are used).
This change is backwards compatible with GHC 9.14.1.
- - - - -
fd9aaa28 by Simon Hengel at 2026-02-20T10:25:33-05:00
docs: Fix grammar in explicit_namespaces.rst
- - - - -
44354255 by Vo Minh Thu at 2026-02-20T18:53:06-05:00
GHCi: add a :version command.
This looks like:
ghci> :version
GHCi, version 9.11.20240322
This closes #24576.
Co-Author: Markus Läll <markus.l2ll(a)gmail.com>
- - - - -
eab3dbba by Andreas Klebinger at 2026-02-20T18:53:51-05:00
hadrian/build-cabal: Better respect and utilize -j
* We now respect -j<n> for the cabal invocation to build hadrian rather
than hardcoding -j
* We use the --semaphore flag to ensure cabal/ghc build the hadrian
executable in parallel using the -jsem mechanism.
Saves 10-15s on fresh builds for me.
Fixes #26876
- - - - -
17839248 by Teo Camarasu at 2026-02-24T08:36:03-05:00
ghc-internal: avoid depending on GHC.Internal.Control.Monad.Fix
This module contains the definition of MonadFix, since we want an
instance for IO, that instance requires a lot of machinery and we want
to avoid an orphan instance, this will naturally be quite high up in the
dependency graph.
So we want to avoid other modules depending on it as far as possible.
On Windows, the IO manager depends on the RTSFlags type, which
transtively depends on MonadFix. We refactor things to avoid this
dependency, which would have caused a regression.
Resolves #26875
Metric Decrease:
T12227
- - - - -
fa88d09a by Wolfgang Jeltsch at 2026-02-24T08:36:47-05:00
Refine the imports of `System.IO.OS`
Commit 68bd08055594b8cbf6148a72d108786deb6c12a1 replaced the
`GHC.Internal.Data.Bool` import by a `GHC.Internal.Base` import.
However, while the `GHC.Internal.Data.Bool` import was conditional and
partial, the `GHC.Internal.Base` import is unconditional and total. As a
result, the import list is not tuned to import only the necessary bits
anymore, and furthermore GHC emits a lot of warnings about redundant
imports.
This commit makes the `GHC.Internal.Base` import conditional and partial
in the same way that the `GHC.Internal.Data.Bool` import was.
- - - - -
c951fef1 by Cheng Shao at 2026-02-25T20:58:28+00:00
wasm: add /assets endpoint to serve user-specified assets
This patch adds an `/assets` endpoint to the wasm dyld http server, so
that users can also fetch assets from the same host with sensible
default MIME types, without needing a separate http server for assets
that also introduces CORS headaches:
- A `-fghci-browser-assets-dir` driver flag is added to specify the
assets root directory (defaults to `$PWD`)
- The dyld http server fetches `mime-db` on demand and uses it as
source of truth for mime types.
Closes #26951.
- - - - -
dde22f97 by Sylvain Henry at 2026-02-26T13:14:03-05:00
Fix -fcheck-prim-bounds for non constant args (#26958)
Previously we were only checking bounds for constant (literal)
arguments!
I've refactored the code to simplify the generation of out-of-line Cmm
code for the primop composed of some inline code + some call to an
external Cmm function.
- - - - -
bd3eba86 by Vladislav Zavialov at 2026-02-27T05:48:01-05:00
Check for negative type literals in the type checker (#26861)
GHC disallows negative type literals (e.g., -1), as tested by T8306 and
T8412. This check is currently performed in the renamer:
rnHsTyLit tyLit@(HsNumTy x i) = do
when (i < 0) $
addErr $ TcRnNegativeNumTypeLiteral tyLit
However, this check can be bypassed using RequiredTypeArguments
(see the new test case T26861). Prior to this patch, such programs
caused the compiler to hang instead of reporting a proper error.
This patch addresses the issue by adding an equivalent check in
the type checker, namely in tcHsType.
The diff is deliberately minimal to facilitate backporting. A more
comprehensive rework of HsTyLit is planned for a separate commit.
- - - - -
faf14e0c by Vladislav Zavialov at 2026-02-27T05:48:45-05:00
Consistent pretty-printing of HsString, HsIsString, HsStrTy
Factor out a helper to pretty-print string literals, thus fixing newline
handling for overloaded string literals and type literals.
Test cases: T26860ppr T26860ppr_overloaded T26860ppr_tylit
Follow up to ddf1434ff9bb08cfef3c93f23de6b83ec698aa27
- - - - -
f108a972 by Arnaud Spiwack at 2026-02-27T12:53:01-05:00
Make list comprehension completely non-linear
Fixes #25081
From the note:
The usefulness of list comprehension in conjunction with linear types is dubious.
After all, statements are made to be run many times, for instance in
```haskell
[u | y <- [0,1], stmts]
```
both `u` and `stmts` are going to be run several times.
In principle, though, there are some position in a monad comprehension
expression which could be considered linear. We could try and make it so that
these positions are considered linear by the typechecker, but in practice the
desugarer doesn't take enough care to ensure that these are indeed desugared to
linear sites. We tried in the past, and it turned out that we'd miss a
desugaring corner case (#25772).
Until there's a demand for this very specific improvement, let's instead be
conservative, and consider list comprehension to be completely non-linear.
- - - - -
ae799cab by Simon Jakobi at 2026-02-27T12:53:54-05:00
PmAltConSet: Use Data.Set instead of Data.Map
...to store `PmLit`s.
The Map was only used to map keys to themselves.
Changing the Map to a Set saves a Word of memory per entry.
Resolves #26756.
- - - - -
dcd7819c by Vladislav Zavialov at 2026-02-27T18:46:03-05:00
Drop HsTyLit in favor of HsLit (#26862, #25121)
This patch is a small step towards unification of HsExpr and HsType,
taking care of literals (HsLit) and type literals (HsTyLit).
Additionally, it improves error messages for unsupported type literals,
such as unboxed or fractional literals (test cases: T26862, T26862_th).
Changes to the AST:
* Use HsLit where HsTyLit was previously used
* Use HsChar where HsCharTy was previously used
* Use HsString where HsStrTy was previously used
* Use HsNatural (NEW) where HsNumTy was previously used
* Use HsDouble (NEW) to represent unsupported fractional type literals
Changes to logic:
* Parse unboxed and fractional type literals (to be rejected later)
* Drop the check for negative literals in the renamer (rnHsTyLit)
in favor of checking in the type checker (tc_hs_lit_ty)
* Check for invalid type literals in TH (repTyLit) and report
unrepresentable literals with ThUnsupportedTyLit
* Allow negative type literals in TH (numTyLit). This is fine as
these will be taken care of at splice time (test case: T8306_th)
- - - - -
c927954f by Vladislav Zavialov at 2026-02-27T18:46:50-05:00
Increase test coverage of diagnostics
Add test cases for the previously untested diagnostics:
[GHC-01239] PsErrIfInFunAppExpr
[GHC-04807] PsErrProcInFunAppExpr
[GHC-08195] PsErrInvalidRecordCon
[GHC-16863] PsErrUnsupportedBoxedSumPat
[GHC-18910] PsErrSemiColonsInCondCmd
[GHC-24737] PsErrInvalidWhereBindInPatSynDecl
[GHC-25037] PsErrCaseInFunAppExpr
[GHC-25078] PsErrPrecedenceOutOfRange
[GHC-28021] PsErrRecordSyntaxInPatSynDecl
[GHC-35827] TcRnNonOverloadedSpecialisePragma
[GHC-40845] PsErrUnpackDataCon
[GHC-45106] PsErrInvalidInfixHole
[GHC-50396] PsErrInvalidRuleActivationMarker
[GHC-63930] MultiWayIfWithoutAlts
[GHC-65536] PsErrNoSingleWhereBindInPatSynDecl
[GHC-67630] PsErrMDoInFunAppExpr
[GHC-70526] PsErrLetCmdInFunAppCmd
[GHC-77808] PsErrDoCmdInFunAppCmd
[GHC-86934] ClassPE
[GHC-90355] PsErrLetInFunAppExpr
[GHC-91745] CasesExprWithoutAlts
[GHC-92971] PsErrCaseCmdInFunAppCmd
[GHC-95644] PsErrBangPatWithoutSpace
[GHC-97005] PsErrIfCmdInFunAppCmd
Remove unused error constructors:
[GHC-44524] PsErrExpectedHyphen
[GHC-91382] TcRnIllegalKindSignature
- - - - -
3a9470fd by Torsten Schmits at 2026-02-27T18:47:34-05:00
Avoid expensive computation for debug logging in `mergeDatabases` when log level is low
This computed and traversed a set intersection for every single
dependency unconditionally.
- - - - -
ea4c2cbd by Brandon Chinn at 2026-02-27T16:22:38-08:00
Implement QualifiedStrings (#26503)
See Note [Implementation of QualifiedStrings]
- - - - -
08bc245b by sheaf at 2026-03-01T11:11:54-05:00
Clean up join points, casts & ticks
This commit shores up the logic dealing with casts and ticks occurring
in between a join point binding and a jump.
Fixes #26642 #26929 #26693
Makes progress on #14610 #26157 #26422
Changes:
- Remove 'GHC.Types.Tickish.TickishScoping' in favour of simpler
predicates 'tickishHasNoScope'/'tickishHasSoftScope', as things were
before commit 993975d3. This makes the code easier to read and
document (fewer indirections).
- Introduce 'canCollectArgsThroughTick' for consistent handling of
ticks around PrimOps and other 'Id's that cannot be eta-reduced.
See overhauled Note [Ticks and mandatory eta expansion].
- New Note [JoinId vs TailCallInfo] in GHC.Core.SimpleOpt that explains
robustness of JoinId vs fragility of TailCallInfo.
- Allow casts/non-soft-scoped ticks to occur in between a join point
binder and a jump, but only in Core Prep.
See Note [Join points, casts, and ticks] and
Note [Join points, casts, and ticks... in Core Prep]
in GHC.Core.Opt.Simplify.Iteration.
Also update Core Lint to account for this.
See Note [Linting join points with casts or ticks] in GHC.Core.Lint.
- Update 'GHC.Core.Utils.mergeCaseAlts' to avoid pushing a cast in
between a join point binding and its jumps. This fixes #26642.
See the new (MC5) and (MC6) in Note [Merge Nested Cases].
- Update float out to properly handle source note ticks. They are now
properly floated out instead of being discarded.
This increases the number of ticks in certain tests with -g.
Test cases: T26642 and TrickyJoins.
Metric increase due to more source note ticks with -g:
-------------------------
Metric Increase:
libdir
size_hello_artifact
size_hello_unicode
-------------------------
- - - - -
476c4cdf by Sean D. Gillespie at 2026-03-02T10:14:37-05:00
Add SIMD absolute value on x86 and LLVM
On x86, absolute value of 32 bits or less is implemented with
PABSB/PABSW/PABSD if SSSE3 is available. Otherwise, there is a fallback
for SSE2. For 64 bit integers it uses VPABSQ, required by AVX-512VL,
with fallbacks for SSE4.2 and SSE2.
There is no dedicated instruction for floating point absolute value on
x86, so it is simulated using bitwise AND.
Absolute value for signed integers and floats are implemented by the
"llvm.abs/llvm.fabs" standard library intrinsics. This implementation
uses MachOps constructors, unlike non-vector floating point absolute
value, which uses CallishMachOps.
- - - - -
709448c0 by Sean D. Gillespie at 2026-03-02T10:14:46-05:00
Add SIMD floating point square root
On x86, this is implemented with the SQRTPS and SQRTPD instructions. On
LLVM, it uses the sqrt library intrinstic.
- - - - -
0deadf66 by Sean D. Gillespie at 2026-03-02T10:14:47-05:00
Improve error message for SIMD on aarch64
When encountering vector literals on aarch64, previously it would
throw:
<no location info>: error:
panic! (the 'impossible' happened)
GHC version 9.15.20251219:
getRegister' (CmmLit:CmmVec):
Now it is more consistent with the other vector operations:
<no location info>: error:
sorry! (unimplemented feature or known bug)
GHC version 9.15.20251219:
SIMD operations on AArch64 currently require the LLVM backend
- - - - -
7d64031b by Vladislav Zavialov at 2026-03-03T11:09:28-05:00
Replace maybeAddSpace with spaceIfSingleQuote
Simplify pretty-printing of HsTypes by using spaceIfSingleQuote.
This allows us to drop the unwieldy lhsTypeHasLeadingPromotionQuote
helper function.
Follow-up to 178c1fd830c78377ef5d338406a41e1d8eb5f0da
- - - - -
598db847 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Correct `hIsReadable` and `hIsWritable` for duplex handles
This contribution implements CLC proposal #371. It changes `hIsReadable`
and `hIsWritable` such that they always throw a respective exception
when encountering a closed or semi-closed handle, not just in the case
of a file handle.
- - - - -
b90201e5 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Document `SemiClosedHandle`
- - - - -
c9df72b5 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Tell users what “semi-closed” means for duplex handles
- - - - -
a8aa1868 by Ilias Tsitsimpis at 2026-03-06T06:26:29-05:00
Fix determinism of linker arguments
The switch from Data.Map to UniqMap in 3b5be05ac29 introduced
non-determinism in the order of packages passed to the linker.
This resulted in non-reproducible builds where the DT_NEEDED entries in
dynamic libraries were ordered differently across builds.
Fix the regression by explicitly sorting the package list derived from
UniqMap.
Fixes #26838
- - - - -
9b64ad3a by Matthew Pickering at 2026-03-06T06:27:16-05:00
determinism: Use a deterministic renaming when writing bytecode files
Now when writing the bytecode file, a counter and substitution are used
to provide deterministic keys to local variables (rather than relying on
uniques). This change ensures that `.gbc` are produced
deterministically.
Fixes #26499
- - - - -
d29800e0 by Teo Camarasu at 2026-03-06T06:28:46-05:00
ghc-internal: delete Version hs-boot loop
Version has a Read instance which needs Unicode but part of the Unicode interface is the unicode version. This is easy to resolve. We simply don't re-export the version from the Unicode module.
Resolves #26940
- - - - -
ad25af90 by Sylvain Henry at 2026-03-06T06:30:33-05:00
Linker: implement support for COMMON symbols (#6107)
Add some support for COMMON symbols. We don't support common symbols
having different sizes where the larger one is allocated after the
smaller one. The linker will fail with an appropriate error message if
it happens.
- - - - -
3b59f158 by Cheng Shao at 2026-03-06T06:31:16-05:00
compiler: fix redundant import of GHC.Hs.Lit
This patch removes a redundant import of `GHC.Hs.Lit` which causes a
ghc build failure with validate flavours when bootstrapping from 9.14.
Fixes #26972.
- - - - -
148d36f3 by Cheng Shao at 2026-03-06T06:32:01-05:00
compiler: avoid unneeded traversals in GHC.Unit.State
Following !15591, this patch avoids unneeded traversals in
`reportCycles`/`reportUnusable` when log verbosity is below given
threshold. Also applies `logVerbAtLeast` when appropriate.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
7e31367c by Cheng Shao at 2026-03-06T06:32:46-05:00
ghc-internal: fix redundant import in GHC.Internal.Event.Windows.ManagedThreadPool
This patch fixes redundant import in
`GHC.Internal.Event.Windows.ManagedThreadPool` that causes a
compilation error when building windows target with validate flavours
and bootstrapping from 9.14. Fixes #26976.
- - - - -
fc8b8e27 by sheaf at 2026-03-06T06:33:28-05:00
System.Info.fullCompilerVersion: add 'since' annot
Fixes #26973
- - - - -
c8238375 by Sylvain Henry at 2026-03-06T06:34:23-05:00
Hadrian: deprecate --bignum and automatically enable +native_bignum for JS
Deprecate --bignum=... to select the bignum backend. It's only used to
select the native backend, and this can be done with the +native_bignum
flavour transformer.
Additionally, we automatically enable +native_bignum for the JS target
because the GMP backend isn't supported.
- - - - -
a3ac7074 by Sylvain Henry at 2026-03-06T06:35:17-05:00
JS: fix putEnum/fromEnum (#24593)
Don't go through Word16 when serializing Enums.
- - - - -
0b36e96c by Andreas Klebinger at 2026-03-06T06:35:58-05:00
Docs: Document -fworker-wrapper-cbv default setting.
Fixes #26841
- - - - -
eca445e7 by mangoiv at 2026-03-07T05:02:36-05:00
drop deb9/10 from CI, add deb13
debian 9 and 10 are end of life, hence we drop them
from our CI, but we do add debian 13. Jobs that were
previously run on 9 and 10 run on 13, too, jobs that
were run on 10, are run on 11 now. Jobs that were
previously run on debian 12 are run on debian 13 now.
This MR also updates hadrian's bootstrap plans for that
reason.
Metric Decrease:
T9872d
- - - - -
12f8b829 by Luite Stegeman at 2026-03-07T05:03:33-05:00
Fix GHC.Internal.Prim haddock
Haddock used to parse Haskell source to generate documentation,
but switched to using interface files instead. This broke documentation
of the GHC.Internal.Prim module, since it's a wired-in interface that
didn't provide a document structure.
This patch adds the missing document structure and updates genprimopcode
to make the section headers and descriptions available.
fixes #26954
- - - - -
f87e5e57 by Luite Stegeman at 2026-03-07T05:03:33-05:00
Remove obsolete --make-haskell-source from genprimopcode
Now that haddock uses the wired-in interface for GHC.Internal.Prim,
the generated Haskell source file is no longer needed. Remove the
--make-haskell-source code generator from genprimopcode and replace
the generated GHC/Internal/Prim.hs with a minimal static source file.
- - - - -
4a7ddc7b by Sylvain Henry at 2026-03-07T05:04:59-05:00
JS: fix linking of exposed but non-preload units (#24886)
Units exposed in the unit database but not explicitly passed on the
command-line were not considered by the JS linker. This isn't an issue
for cabal which passes every unit explicitly but it is an issue when
using GHC directly (cf T24886 test).
- - - - -
689aafcd by mangoiv at 2026-03-07T05:05:52-05:00
testsuite: double foundation timeout multiplier
The runtime timeout in the foundation test was regularly hit by code
generated by the wasm backend - we increase the timout since the high
runtime is expected on the wasm backend for this rather complex test.
Resolves #26938
- - - - -
a46a1bb1 by Cheng Shao at 2026-03-09T04:50:30-04:00
compiler: add myCapabilityExpr to GHC.Cmm.Utils
This commit adds `myCapabilityExpr` to `GHC.Cmm.Utils` which is
computed from `BaseReg`. It's convenient for codegen logic where one
needs to pass the current Capability's pointer.
- - - - -
4afc65b1 by Cheng Shao at 2026-03-09T04:50:30-04:00
compiler: lower tryPutMVar# into a ccall directly
This patch addresses an old TODO of `stg_tryPutMVarzh` by removing it
completely and making the compiler lower `tryPutMVar#` into a ccall to
`performTryPutMVar` directly, without landing into an intermediate C
or Cmm function. `performTryPutMVar` is promoted to a public RTS
function with default visibility, and the compiler lowering logic
takes into account the C ABI of `performTryPutMVar` and converts from
C Bool to primop's `Int#` result properly.
- - - - -
9e3d6a58 by Simon Hengel at 2026-03-09T04:51:15-04:00
Don't use #line in haddocks
This confuses the parser. Haddock output is unaffected by this change.
(read: this still produces the same documentation)
- - - - -
f4e8fec2 by Wolfgang Jeltsch at 2026-03-09T04:52:01-04:00
Remove in-package dependencies on `GHC.Internal.System.IO`
This contribution eliminates all dependencies on
`GHC.Internal.System.IO` from within `ghc-internal`. It comprises the
following changes:
* Make `GHC.Internal.Fingerprint` independent of I/O support
* Tighten the dependencies of `GHC.Internal.Data.Version`
* Tighten the dependencies of `GHC.Internal.TH.Monad`
* Tighten the dependencies of `GHCi.Helpers`
* Move some code that needs `System.IO` to `template-haskell`
* Move the `GHC.ResponseFile` implementation into `base`
* Move the `System.Exit` implementation into `base`
* Move the `System.IO.OS` implementation into `base`
Metric Decrease:
size_hello_artifact
size_hello_artifact_gzip
size_hello_unicode
size_hello_unicode_gzip
- - - - -
91df4c82 by Sylvain Henry at 2026-03-09T04:53:20-04:00
T18832: fix Windows CI failure by dropping removeDirectoryRecursive
On Windows, open file handles prevent deletion. After killThread, the
closer thread may not have called hClose yet, causing removeDirectoryRecursive
to fail with "permission denied". The test harness cleans up the run
directory anyway, so the call is redundant.
- - - - -
d7fe9671 by Cheng Shao at 2026-03-09T04:54:04-04:00
compiler: fix redundant import in GHC.StgToJS.Object
This patch fixes a redundant import in GHC.StgToJS.Object that causes
a build failure when compiling head from 9.14 with validate flavours.
Fixes #26991.
- - - - -
0bfd29c3 by Cheng Shao at 2026-03-09T04:54:46-04:00
wasm: fix `Illegal foreign declaration` failure when ghci loads modules with JSFFI exports
This patch fixes a wasm ghci error when loading modules with JSFFI
exports; the `backendValidityOfCExport` check in `tcCheckFEType`
should only makes sense and should be performed when not checking the
JavaScript calling convention; otherwise, when the calling convention
is JavaScript, the codegen logic should be trusted to backends that
actually make use of it. Fixes #26998.
- - - - -
e659610c by Duncan Coutts at 2026-03-09T12:08:35-04:00
Apply NOINLINE pragmas to generated Typeable bindings
For context, see the existing Note [Grand plan for Typeable]
and the Note [NOINLINE on generated Typeable bindings] added in the
subsequent commit.
This is about reducing the number of exported top level names and
unfoldings, which reduces interface file sizes and reduces the number of
global/dynamic linker symbols.
Also accept the changed test output and metric decreases.
Tests that record the phase output for type checking or for simplifier
end up with different output: the generated bindings now have an
Inline [~] annotation, and many top level names are now local rather
than module-prefixed for export.
Also accept the numerous metric decreases in compile_time/bytes
allocated, and a few in compile_time/max_bytes_used.
There's also one instance of a decrease in runtime/max_bytes_used but
it's a ghci-way test and so presumably the reason is that it loads
smaller .hi files and/or links fewer symbols.
-------------------------
Metric Decrease:
CoOpt_Singletons
MultiLayerModulesTH_OneShot
MultilineStringsPerf
T10421
T10547
T12150
T12227
T12234
T12425
T13035
T13056
T13253
T13253-spj
T15304
T15703
T16875
T17836b
T17977b
T18140
T18223
T18282
T18304
T18698a
T18698b
T18730
T18923
T20049
T21839c
T24471
T24582
T24984
T3064
T4029
T5030
T5642
T5837
T6048
T9020
T9198
T9961
TcPlugin_RewritePerf
WWRec
hard_hole_fits
mhu-perf
-------------------------
- - - - -
67df5161 by Duncan Coutts at 2026-03-09T12:08:35-04:00
Add documentation Note [NOINLINE on generated Typeable bindings]
and refer to it from the code and existing documentation.
- - - - -
c4ad6167 by Duncan Coutts at 2026-03-09T12:08:35-04:00
Switch existing note to "named wrinkle" style, (GPT1)..(GPT7)
GPT = Grand plan for Typeable
- - - - -
dc84f8e2 by Cheng Shao at 2026-03-09T12:09:21-04:00
ci: only build deb13 for validate pipeline aarch64-linux jobs
This patch drops the redundant aarch64-linux deb12 job from validate pipelines
and only keeps deb13; it's still built in nightly/release pipelines. Closes #27004.
- - - - -
aea24b15 by Matthew Pickering at 2026-03-10T16:10:04+00:00
exceptions: annotate onException continuation with WhileHandling
Before this patch, an exception thrown in the `onException` handler
would loose track of where the original exception was thrown.
```
import Control.Exception
main :: IO ()
main = failingAction `onException` failingCleanup
where
failingAction = throwIO (ErrorCall "outer failure")
failingCleanup = throwIO (ErrorCall "cleanup failure")
```
would report
```
T28399: Uncaught exception ghc-internal:GHC.Internal.Exception.ErrorCall:
cleanup failure
HasCallStack backtrace:
throwIO, called at T28399.hs:<line>:<column> in <package-id>:Main
```
notice that the "outer failure" exception is not present in the error
message.
With this patch, any exception thrown is in the handler is annotated
with WhileHandling. The resulting message looks like
```
T28399: Uncaught exception ghc-internal:GHC.Internal.Exception.ErrorCall:
cleanup failure
While handling outer failure
HasCallStack backtrace:
throwIO, called at T28399.hs:7:22 in main:Main
```
CLC Proposal: https://github.com/haskell/core-libraries-committee/issues/397
Fixes #26759
- - - - -
692 changed files:
- .gitlab-ci.yml
- .gitlab/ci.sh
- + .gitlab/generate-ci/cabal.project
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/jobs.yaml
- .gitlab/rel_eng/fetch-gitlab-artifacts/fetch_gitlab.py
- .gitlab/rel_eng/mk-ghcup-metadata/mk_ghcup_metadata.py
- compiler/GHC/Builtin/Names.hs
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/Builtin/Types.hs
- compiler/GHC/Builtin/Utils.hs
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/Cmm/MachOp.hs
- compiler/GHC/Cmm/Node.hs
- compiler/GHC/Cmm/Utils.hs
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
- compiler/GHC/CmmToAsm/Config.hs
- compiler/GHC/CmmToAsm/LA64/CodeGen.hs
- compiler/GHC/CmmToAsm/PPC/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Instr.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- compiler/GHC/CmmToC.hs
- compiler/GHC/CmmToLlvm/CodeGen.hs
- compiler/GHC/Core.hs
- compiler/GHC/Core/InstEnv.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Map/Type.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/FloatIn.hs
- compiler/GHC/Core/Opt/FloatOut.hs
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/Pipeline.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Opt/WorkWrap.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Core/TyCon.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/CoreToStg.hs
- compiler/GHC/CoreToStg/AddImplicitBinds.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Data/Pair.hs
- compiler/GHC/Driver/Config/CmmToAsm.hs
- compiler/GHC/Driver/Config/Core/Lint.hs
- compiler/GHC/Driver/Config/Interpreter.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Hs/Binds.hs
- compiler/GHC/Hs/Decls.hs
- + compiler/GHC/Hs/Decls/Overlap.hs
- compiler/GHC/Hs/Doc.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Instances.hs
- compiler/GHC/Hs/Lit.hs
- compiler/GHC/Hs/Pat.hs
- compiler/GHC/Hs/Syn/Type.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/Hs/Utils.hs
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Docs.hs
- compiler/GHC/HsToCore/Errors/Ppr.hs
- compiler/GHC/HsToCore/Errors/Types.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/HsToCore/Foreign/C.hs
- compiler/GHC/HsToCore/Foreign/Call.hs
- compiler/GHC/HsToCore/Foreign/Decl.hs
- compiler/GHC/HsToCore/Foreign/JavaScript.hs
- compiler/GHC/HsToCore/Foreign/Utils.hs
- compiler/GHC/HsToCore/Foreign/Wasm.hs
- compiler/GHC/HsToCore/GuardedRHSs.hs
- compiler/GHC/HsToCore/Match.hs
- compiler/GHC/HsToCore/Match/Literal.hs
- compiler/GHC/HsToCore/Monad.hs
- compiler/GHC/HsToCore/Pmc.hs
- compiler/GHC/HsToCore/Pmc/Desugar.hs
- compiler/GHC/HsToCore/Pmc/Solver.hs
- compiler/GHC/HsToCore/Pmc/Solver/Types.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/HsToCore/Types.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Iface/Ext/Utils.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/Iface/Tidy/StaticPtrTable.hs
- compiler/GHC/Linker/Dynamic.hs
- compiler/GHC/Linker/MacOS.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Errors/Ppr.hs
- compiler/GHC/Parser/Errors/Types.hs
- compiler/GHC/Parser/Lexer.x
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Parser/PostProcess/Haddock.hs
- compiler/GHC/Parser/String.hs
- compiler/GHC/Rename/Bind.hs
- compiler/GHC/Rename/Env.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Rename/HsType.hs
- + compiler/GHC/Rename/Lit.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Rename/Names.hs
- compiler/GHC/Rename/Pat.hs
- compiler/GHC/Rename/Splice.hs
- compiler/GHC/Rename/Splice.hs-boot
- compiler/GHC/Rename/Utils.hs
- compiler/GHC/Runtime/Heap/Inspect.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/Runtime/Interpreter/Init.hs
- compiler/GHC/Runtime/Interpreter/JS.hs
- compiler/GHC/Runtime/Interpreter/Types.hs
- compiler/GHC/Runtime/Interpreter/Wasm.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToCmm/Expr.hs
- compiler/GHC/StgToCmm/Foreign.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/FFI.hs
- compiler/GHC/StgToJS/Object.hs
- compiler/GHC/StgToJS/Prim.hs
- compiler/GHC/SysTools/Cpp.hs
- compiler/GHC/Tc/Deriv.hs
- compiler/GHC/Tc/Deriv/Utils.hs
- compiler/GHC/Tc/Errors/Ppr.hs
- compiler/GHC/Tc/Errors/Types.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Bind.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Gen/Foreign.hs
- compiler/GHC/Tc/Gen/Head.hs
- compiler/GHC/Tc/Gen/HsType.hs
- compiler/GHC/Tc/Gen/Match.hs
- compiler/GHC/Tc/Gen/Pat.hs
- compiler/GHC/Tc/Gen/Sig.hs
- compiler/GHC/Tc/Instance/Class.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/TyCl.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/TyCl/PatSyn.hs
- compiler/GHC/Tc/TyCl/Utils.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Types/BasicTypes.hs
- compiler/GHC/Tc/Types/Constraint.hs
- compiler/GHC/Tc/Types/ErrCtxt.hs
- compiler/GHC/Tc/Types/Evidence.hs
- compiler/GHC/Tc/Types/Origin.hs
- compiler/GHC/Tc/Utils/Env.hs
- compiler/GHC/Tc/Utils/Instantiate.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Tc/Utils/TcMType.hs
- − compiler/GHC/Tc/Utils/TcMType.hs-boot
- compiler/GHC/Tc/Zonk/TcType.hs
- compiler/GHC/Tc/Zonk/Type.hs
- compiler/GHC/ThToHs.hs
- compiler/GHC/Types/Basic.hs
- compiler/GHC/Types/Error/Codes.hs
- compiler/GHC/Types/ForeignCall.hs
- compiler/GHC/Types/Id/Info.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/InlinePragma.hs
- compiler/GHC/Types/Name.hs
- compiler/GHC/Types/Name/Cache.hs
- compiler/GHC/Types/SourceText.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Types/Unique/DSet.hs
- compiler/GHC/Unit/Module/ModIface.hs
- compiler/GHC/Unit/State.hs
- compiler/GHC/Unit/Types.hs
- compiler/GHC/Utils/Binary.hs
- compiler/GHC/Utils/Error.hs
- compiler/GHC/Utils/Outputable.hs
- compiler/GHC/Utils/Ppr/Colour.hs
- compiler/Language/Haskell/Syntax/Basic.hs
- compiler/Language/Haskell/Syntax/Decls.hs
- + compiler/Language/Haskell/Syntax/Decls/Foreign.hs
- + compiler/Language/Haskell/Syntax/Decls/Overlap.hs
- compiler/Language/Haskell/Syntax/Expr.hs
- compiler/Language/Haskell/Syntax/Extension.hs
- compiler/Language/Haskell/Syntax/Lit.hs
- compiler/Language/Haskell/Syntax/Pat.hs
- compiler/Language/Haskell/Syntax/Type.hs
- compiler/ghc.cabal.in
- configure.ac
- distrib/configure.ac.in
- + docs/users_guide/10.0.1-notes.rst
- docs/users_guide/9.16.1-notes.rst
- docs/users_guide/eventlog-formats.rst
- docs/users_guide/exts/explicit_namespaces.rst
- docs/users_guide/exts/multiway_if.rst
- + docs/users_guide/exts/qualified_strings.rst
- docs/users_guide/ghci.rst
- docs/users_guide/phases.rst
- docs/users_guide/using-optimisation.rst
- docs/users_guide/using.rst
- docs/users_guide/wasm.rst
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Info.hs
- hadrian/README.md
- hadrian/bootstrap/generate_bootstrap_plans
- hadrian/bootstrap/plan-9_10_1.json
- hadrian/bootstrap/plan-9_10_2.json
- + hadrian/bootstrap/plan-9_10_3.json
- hadrian/bootstrap/plan-bootstrap-9_10_1.json
- hadrian/bootstrap/plan-bootstrap-9_10_2.json
- + hadrian/bootstrap/plan-bootstrap-9_10_3.json
- hadrian/build-cabal
- hadrian/src/Builder.hs
- hadrian/src/CommandLine.hs
- hadrian/src/Main.hs
- hadrian/src/Rules/Compile.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Settings.hs
- hadrian/src/Settings/Builders/Cc.hs
- hadrian/src/Settings/Builders/GenPrimopCode.hs
- hadrian/src/Settings/Builders/RunTest.hs
- hadrian/src/Settings/Packages.hs
- libraries/Cabal
- libraries/base/changelog.md
- libraries/base/src/Control/Arrow.hs
- libraries/base/src/Data/Bool.hs
- libraries/base/src/Data/Ix.hs
- libraries/base/src/Data/List.hs
- libraries/base/src/Data/List/NubOrdSet.hs
- libraries/base/src/GHC/Base.hs
- libraries/base/src/GHC/Exts.hs
- libraries/base/src/GHC/Fingerprint.hs
- libraries/base/src/GHC/ResponseFile.hs
- libraries/base/src/GHC/Unicode.hs
- libraries/base/src/System/Exit.hs
- libraries/base/src/System/IO.hs
- libraries/base/src/System/IO/OS.hs
- libraries/base/src/System/Info.hs
- libraries/base/tests/IO/T18832.hs
- libraries/deepseq
- libraries/directory
- libraries/exceptions
- libraries/ghc-experimental/CHANGELOG.md
- libraries/ghc-experimental/src/GHC/Stack/Annotation/Experimental.hs
- + libraries/ghc-experimental/tests/Makefile
- + libraries/ghc-experimental/tests/all.T
- + libraries/ghc-experimental/tests/backtraces/Makefile
- + libraries/ghc-experimental/tests/backtraces/T26806a.hs
- + libraries/ghc-experimental/tests/backtraces/T26806a.stderr
- + libraries/ghc-experimental/tests/backtraces/T26806b.hs
- + libraries/ghc-experimental/tests/backtraces/T26806b.stderr
- + libraries/ghc-experimental/tests/backtraces/T26806c.hs
- + libraries/ghc-experimental/tests/backtraces/T26806c.stderr
- + libraries/ghc-experimental/tests/backtraces/all.T
- libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Control/Arrow.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Exception/Base.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/Fix.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/ST/Lazy/Imp.hs
- − libraries/ghc-internal/src/GHC/Internal/Data/Bool.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Foldable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Function.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Identity.hs
- − libraries/ghc-internal/src/GHC/Internal/Data/Ix.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Type/Bool.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Type/Ord.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Version.hs
- − libraries/ghc-internal/src/GHC/Internal/Data/Version.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Event/Windows/ManagedThreadPool.hs
- libraries/ghc-internal/src/GHC/Internal/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/Exts.hs
- libraries/ghc-internal/src/GHC/Internal/Fingerprint.hs
- libraries/ghc-internal/src/GHC/Internal/GHCi/Helpers.hs
- libraries/ghc-internal/src/GHC/Internal/Heap/Closures.hs
- libraries/ghc-internal/src/GHC/Internal/IO.hs
- libraries/ghc-internal/src/GHC/Internal/IO/FD.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Types.hs
- libraries/ghc-internal/src/GHC/Internal/JS/Foreign/Callback.hs
- libraries/ghc-internal/src/GHC/Internal/JS/Prim.hs
- libraries/ghc-internal/src/GHC/Internal/JS/Prim/Internal/Build.hs
- libraries/ghc-internal/src/GHC/Internal/LanguageExtensions.hs
- libraries/ghc-internal/src/GHC/Internal/Magic.hs
- + libraries/ghc-internal/src/GHC/Internal/Prim.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags/Test.hsc
- − libraries/ghc-internal/src/GHC/Internal/ResponseFile.hs
- libraries/ghc-internal/src/GHC/Internal/STM.hs
- libraries/ghc-internal/src/GHC/Internal/Stack/Annotation.hs
- libraries/ghc-internal/src/GHC/Internal/Stack/Decode.hs
- − libraries/ghc-internal/src/GHC/Internal/System/Exit.hs
- libraries/ghc-internal/src/GHC/Internal/System/IO.hs
- − libraries/ghc-internal/src/GHC/Internal/System/IO/OS.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lift.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- libraries/ghc-internal/src/GHC/Internal/Tuple.hs
- libraries/ghc-internal/src/GHC/Internal/TypeError.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Version.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Exports.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Imports.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs
- + libraries/ghc-internal/tests/backtraces/T15395.hs
- + libraries/ghc-internal/tests/backtraces/T15395.stdout
- libraries/ghc-internal/tests/backtraces/all.T
- libraries/ghc-internal/tests/stack-annotation/ann_frame001.stdout
- libraries/ghc-internal/tests/stack-annotation/ann_frame002.stdout
- libraries/ghc-internal/tests/stack-annotation/ann_frame003.stdout
- libraries/ghc-internal/tests/stack-annotation/ann_frame004.stdout
- libraries/ghc-internal/tests/stack-annotation/ann_frame005.stdout
- libraries/ghc-internal/tools/ucd2haskell/exe/UCD2Haskell/ModuleGenerators.hs
- libraries/template-haskell/Language/Haskell/TH/Syntax.hs
- libraries/text
- libraries/transformers
- m4/fp_cmm_cpp_cmd_with_args.m4
- m4/fptools_happy.m4
- rts/Linker.c
- rts/LinkerInternals.h
- rts/PrimOps.cmm
- rts/RtsSymbols.c
- rts/Threads.c
- rts/Threads.h
- rts/include/Stg.h
- rts/include/rts/Threads.h
- rts/include/stg/MiscClosures.h
- rts/linker/Elf.c
- rts/linker/MachO.c
- rts/linker/PEi386.c
- rts/prim/atomic.c
- testsuite/driver/cpu_features.py
- − testsuite/driver/kill_extra_files.py
- testsuite/driver/perf_notes.py
- testsuite/driver/testlib.py
- testsuite/mk/test.mk
- testsuite/tests/arrows/should_compile/T21301.stderr
- testsuite/tests/backpack/cabal/bkpcabal08/bkpcabal08.stdout
- testsuite/tests/codeGen/should_compile/debug.stdout
- + testsuite/tests/codeGen/should_fail/T26958.hs
- testsuite/tests/codeGen/should_fail/all.T
- testsuite/tests/codeGen/should_gen_asm/all.T
- + testsuite/tests/codeGen/should_gen_asm/avx512-int64-minmax.asm
- + testsuite/tests/codeGen/should_gen_asm/avx512-int64-minmax.hs
- + testsuite/tests/codeGen/should_gen_asm/avx512-int64-mul.asm
- + testsuite/tests/codeGen/should_gen_asm/avx512-int64-mul.hs
- + testsuite/tests/codeGen/should_gen_asm/avx512-word64-minmax.asm
- + testsuite/tests/codeGen/should_gen_asm/avx512-word64-minmax.hs
- testsuite/tests/codeGen/should_run/CgStaticPointers.hs
- testsuite/tests/codeGen/should_run/CgStaticPointersNoFullLazyness.hs
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- testsuite/tests/deSugar/should_compile/T16615.stderr
- testsuite/tests/deSugar/should_compile/T2431.stderr
- testsuite/tests/deSugar/should_fail/DsStrictFail.stderr
- testsuite/tests/deSugar/should_run/T20024.stderr
- testsuite/tests/deSugar/should_run/dsrun005.stderr
- testsuite/tests/deSugar/should_run/dsrun007.stderr
- testsuite/tests/deSugar/should_run/dsrun008.stderr
- + testsuite/tests/dependent/should_fail/SelfDepCls.hs
- + testsuite/tests/dependent/should_fail/SelfDepCls.stderr
- testsuite/tests/dependent/should_fail/all.T
- testsuite/tests/deriving/should_run/T9576.stderr
- testsuite/tests/diagnostic-codes/codes.stdout
- testsuite/tests/dmdanal/should_compile/T16029.stdout
- testsuite/tests/driver/T20030/test1/all.T
- testsuite/tests/driver/T20030/test2/all.T
- testsuite/tests/driver/T20030/test3/all.T
- testsuite/tests/driver/T20030/test4/all.T
- testsuite/tests/driver/T20030/test5/all.T
- testsuite/tests/driver/T20030/test6/all.T
- testsuite/tests/driver/T4437.hs
- testsuite/tests/driver/T8526/T8526.script
- testsuite/tests/driver/bytecode-object/Makefile
- testsuite/tests/driver/bytecode-object/bytecode_object19.stdout
- testsuite/tests/driver/dynamicToo/dynamicToo001/Makefile
- testsuite/tests/driver/fat-iface/fat014.script
- testsuite/tests/driver/implicit-dyn-too/Makefile
- testsuite/tests/driver/multipleHomeUnits/all.T
- testsuite/tests/driver/multipleHomeUnits/multipleHomeUnits_recomp_th.stdout
- + testsuite/tests/exceptions/T26759.hs
- + testsuite/tests/exceptions/T26759.stderr
- + testsuite/tests/exceptions/T26759a.hs
- + testsuite/tests/exceptions/T26759a.stderr
- + testsuite/tests/exceptions/T26759a.stdout
- testsuite/tests/exceptions/all.T
- testsuite/tests/ffi/should_compile/all.T
- testsuite/tests/ffi/should_run/all.T
- + testsuite/tests/ghc-api/TypeMapStringLiteral.hs
- testsuite/tests/ghc-api/all.T
- testsuite/tests/ghc-api/annotations-literals/literals.stdout
- testsuite/tests/ghc-api/annotations-literals/parsed.hs
- + testsuite/tests/ghci-wasm/T26998.hs
- testsuite/tests/ghci-wasm/all.T
- testsuite/tests/ghci.debugger/scripts/T26042b.stdout
- testsuite/tests/ghci.debugger/scripts/T26042c.stdout
- testsuite/tests/ghci.debugger/scripts/T26042d2.stdout
- testsuite/tests/ghci.debugger/scripts/T26042f2.stdout
- − testsuite/tests/ghci/linking/T11531.stderr
- testsuite/tests/ghci/prog018/prog018.script
- testsuite/tests/ghci/scripts/Defer02.stderr
- testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout
- testsuite/tests/ghci/scripts/T10963.stderr
- testsuite/tests/ghci/scripts/T13869.script
- testsuite/tests/ghci/scripts/T13997.script
- testsuite/tests/ghci/scripts/T15325.stderr
- testsuite/tests/ghci/scripts/T17669.script
- testsuite/tests/ghci/scripts/T18330.script
- testsuite/tests/ghci/scripts/T18330.stdout
- testsuite/tests/ghci/scripts/T1914.script
- testsuite/tests/ghci/scripts/T20150.stdout
- testsuite/tests/ghci/scripts/T20217.script
- testsuite/tests/ghci/scripts/T4175.stdout
- testsuite/tests/ghci/scripts/T6105.script
- testsuite/tests/ghci/scripts/T8042.script
- testsuite/tests/ghci/scripts/T8042recomp.script
- testsuite/tests/ghci/should_run/Makefile
- testsuite/tests/ghci/should_run/all.T
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/base-exports.stdout-ws-32
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32
- testsuite/tests/interface-stability/ghc-prim-exports.stdout
- testsuite/tests/interface-stability/ghc-prim-exports.stdout-mingw32
- testsuite/tests/interface-stability/template-haskell-exports.stdout
- + testsuite/tests/javascript/T24886.hs
- + testsuite/tests/javascript/T24886.stderr
- + testsuite/tests/javascript/T24886.stdout
- testsuite/tests/javascript/all.T
- − testsuite/tests/linear/should_compile/LinearListComprehension.hs
- testsuite/tests/linear/should_compile/all.T
- testsuite/tests/linear/should_fail/T25081.hs
- testsuite/tests/linear/should_fail/T25081.stderr
- testsuite/tests/linters/regex-linters/check-rts-includes.py
- testsuite/tests/mdo/should_fail/mdofail006.stderr
- testsuite/tests/module/all.T
- + testsuite/tests/module/mod70b.hs
- + testsuite/tests/module/mod70b.stderr
- testsuite/tests/numeric/should_compile/T14170.stdout
- testsuite/tests/numeric/should_compile/T14465.stdout
- testsuite/tests/numeric/should_compile/T7116.stdout
- testsuite/tests/numeric/should_run/all.T
- testsuite/tests/overloadedrecflds/should_compile/all.T
- testsuite/tests/overloadedrecflds/should_run/all.T
- testsuite/tests/parser/should_compile/DumpRenamedAst.stderr
- testsuite/tests/parser/should_compile/T14189.stderr
- + testsuite/tests/parser/should_fail/NoBlockArgumentsFail4.hs
- + testsuite/tests/parser/should_fail/NoBlockArgumentsFail4.stderr
- testsuite/tests/parser/should_fail/NoBlockArgumentsFailArrowCmds.hs
- testsuite/tests/parser/should_fail/NoBlockArgumentsFailArrowCmds.stderr
- + testsuite/tests/parser/should_fail/NoDoAndIfThenElseArrowCmds.hs
- + testsuite/tests/parser/should_fail/NoDoAndIfThenElseArrowCmds.stderr
- testsuite/tests/parser/should_fail/RecordDotSyntaxFail8.stderr
- + testsuite/tests/parser/should_fail/T26860ppr.hs
- + testsuite/tests/parser/should_fail/T26860ppr.stderr
- + testsuite/tests/parser/should_fail/T26860ppr_overloaded.hs
- + testsuite/tests/parser/should_fail/T26860ppr_overloaded.stderr
- + testsuite/tests/parser/should_fail/T26860ppr_tylit.hs
- + testsuite/tests/parser/should_fail/T26860ppr_tylit.stderr
- testsuite/tests/parser/should_fail/all.T
- + testsuite/tests/parser/should_fail/badRuleMarker.hs
- + testsuite/tests/parser/should_fail/badRuleMarker.stderr
- + testsuite/tests/parser/should_fail/patFail010.hs
- + testsuite/tests/parser/should_fail/patFail010.stderr
- + testsuite/tests/parser/should_fail/patFail011.hs
- + testsuite/tests/parser/should_fail/patFail011.stderr
- + testsuite/tests/parser/should_fail/precOutOfRange.hs
- + testsuite/tests/parser/should_fail/precOutOfRange.stderr
- + testsuite/tests/parser/should_fail/unpack_data_con.hs
- + testsuite/tests/parser/should_fail/unpack_data_con.stderr
- testsuite/tests/patsyn/should_fail/T10426.stderr
- testsuite/tests/patsyn/should_fail/all.T
- + testsuite/tests/patsyn/should_fail/patsyn_where_fail1.hs
- + testsuite/tests/patsyn/should_fail/patsyn_where_fail1.stderr
- + testsuite/tests/patsyn/should_fail/patsyn_where_fail2.hs
- + testsuite/tests/patsyn/should_fail/patsyn_where_fail2.stderr
- + testsuite/tests/patsyn/should_fail/patsyn_where_fail3.hs
- + testsuite/tests/patsyn/should_fail/patsyn_where_fail3.stderr
- + testsuite/tests/patsyn/should_fail/patsyn_where_fail4.hs
- + testsuite/tests/patsyn/should_fail/patsyn_where_fail4.stderr
- testsuite/tests/patsyn/should_run/ghci.stderr
- + testsuite/tests/plugins/T23110.hs
- + testsuite/tests/plugins/T23110.script
- + testsuite/tests/plugins/T23110.stdout
- testsuite/tests/plugins/all.T
- testsuite/tests/pmcheck/should_compile/T11303.hs
- testsuite/tests/process/all.T
- + testsuite/tests/qualified-strings/Makefile
- + testsuite/tests/qualified-strings/should_compile/Example/Length.hs
- + testsuite/tests/qualified-strings/should_compile/all.T
- + testsuite/tests/qualified-strings/should_compile/qstrings_redundant_pattern.hs
- + testsuite/tests/qualified-strings/should_compile/qstrings_redundant_pattern.stderr
- + testsuite/tests/qualified-strings/should_fail/Example/Length.hs
- + testsuite/tests/qualified-strings/should_fail/Makefile
- + testsuite/tests/qualified-strings/should_fail/all.T
- + testsuite/tests/qualified-strings/should_fail/qstrings_bad_expr.hs
- + testsuite/tests/qualified-strings/should_fail/qstrings_bad_expr.stderr
- + testsuite/tests/qualified-strings/should_fail/qstrings_bad_pat.hs
- + testsuite/tests/qualified-strings/should_fail/qstrings_bad_pat.stderr
- + testsuite/tests/qualified-strings/should_fail/qstrings_multiline_no_ext.hs
- + testsuite/tests/qualified-strings/should_fail/qstrings_multiline_no_ext.stderr
- + testsuite/tests/qualified-strings/should_run/Example/ByteStringAscii.hs
- + testsuite/tests/qualified-strings/should_run/Example/ByteStringUtf8.hs
- + testsuite/tests/qualified-strings/should_run/Example/Text.hs
- + testsuite/tests/qualified-strings/should_run/Makefile
- + testsuite/tests/qualified-strings/should_run/all.T
- + testsuite/tests/qualified-strings/should_run/qstrings_expr.hs
- + testsuite/tests/qualified-strings/should_run/qstrings_expr.stdout
- + testsuite/tests/qualified-strings/should_run/qstrings_pat.hs
- + testsuite/tests/qualified-strings/should_run/qstrings_pat.stdout
- + testsuite/tests/qualified-strings/should_run/qstrings_th.hs
- + testsuite/tests/qualified-strings/should_run/qstrings_th.stdout
- testsuite/tests/quasiquotation/qq005/test.T
- testsuite/tests/quasiquotation/qq006/test.T
- testsuite/tests/quotes/LiftErrMsgDefer.stderr
- testsuite/tests/rename/should_fail/RnStaticPointersFail01.stderr
- testsuite/tests/rename/should_fail/RnStaticPointersFail03.stderr
- + testsuite/tests/rename/should_fail/T26545.hs
- + testsuite/tests/rename/should_fail/T26545.stderr
- testsuite/tests/rename/should_fail/all.T
- testsuite/tests/roles/should_compile/Roles1.stderr
- testsuite/tests/roles/should_compile/Roles13.stderr
- testsuite/tests/roles/should_compile/Roles14.stderr
- testsuite/tests/roles/should_compile/Roles2.stderr
- testsuite/tests/roles/should_compile/Roles3.stderr
- testsuite/tests/roles/should_compile/Roles4.stderr
- testsuite/tests/roles/should_compile/T8958.stderr
- testsuite/tests/rts/T13676.script
- testsuite/tests/rts/linker/Makefile
- + testsuite/tests/rts/linker/T6107.hs
- + testsuite/tests/rts/linker/T6107.stdout
- + testsuite/tests/rts/linker/T6107_sym1.s
- + testsuite/tests/rts/linker/T6107_sym2.s
- testsuite/tests/rts/linker/all.T
- testsuite/tests/safeHaskell/safeLanguage/SafeLang15.stderr
- testsuite/tests/saks/should_compile/all.T
- testsuite/tests/showIface/DocsInHiFile1.stdout
- testsuite/tests/showIface/HaddockSpanIssueT24378.stdout
- testsuite/tests/showIface/MagicHashInHaddocks.stdout
- testsuite/tests/showIface/all.T
- testsuite/tests/simd/should_run/all.T
- testsuite/tests/simd/should_run/doublex2_arith.hs
- testsuite/tests/simd/should_run/doublex2_arith.stdout
- testsuite/tests/simd/should_run/doublex2_arith_baseline.hs
- testsuite/tests/simd/should_run/doublex2_arith_baseline.stdout
- testsuite/tests/simd/should_run/floatx4_arith.hs
- testsuite/tests/simd/should_run/floatx4_arith.stdout
- testsuite/tests/simd/should_run/floatx4_arith_baseline.hs
- testsuite/tests/simd/should_run/floatx4_arith_baseline.stdout
- testsuite/tests/simd/should_run/int16x8_arith.hs
- testsuite/tests/simd/should_run/int16x8_arith.stdout
- testsuite/tests/simd/should_run/int16x8_arith_baseline.hs
- testsuite/tests/simd/should_run/int16x8_arith_baseline.stdout
- testsuite/tests/simd/should_run/int32x4_arith.hs
- testsuite/tests/simd/should_run/int32x4_arith.stdout
- testsuite/tests/simd/should_run/int32x4_arith_baseline.hs
- testsuite/tests/simd/should_run/int32x4_arith_baseline.stdout
- testsuite/tests/simd/should_run/int64x2_arith.hs
- testsuite/tests/simd/should_run/int64x2_arith.stdout
- testsuite/tests/simd/should_run/int64x2_arith_baseline.hs
- testsuite/tests/simd/should_run/int64x2_arith_baseline.stdout
- testsuite/tests/simd/should_run/int8x16_arith.hs
- testsuite/tests/simd/should_run/int8x16_arith.stdout
- testsuite/tests/simd/should_run/int8x16_arith_baseline.hs
- testsuite/tests/simd/should_run/int8x16_arith_baseline.stdout
- testsuite/tests/simplCore/should_compile/OpaqueNoCastWW.stderr
- testsuite/tests/simplCore/should_compile/T21391.hs
- + testsuite/tests/simplCore/should_compile/T26642.hs
- + testsuite/tests/simplCore/should_compile/T26826.hs
- + testsuite/tests/simplCore/should_compile/T26903.hs
- + testsuite/tests/simplCore/should_compile/T26903.stderr
- testsuite/tests/simplCore/should_compile/T3717.stderr
- testsuite/tests/simplCore/should_compile/T3772.stdout
- testsuite/tests/simplCore/should_compile/T4908.stderr
- testsuite/tests/simplCore/should_compile/T4930.stderr
- testsuite/tests/simplCore/should_compile/T7360.stderr
- testsuite/tests/simplCore/should_compile/T8274.stdout
- testsuite/tests/simplCore/should_compile/T8331.stderr
- testsuite/tests/simplCore/should_compile/T9400.stderr
- + testsuite/tests/simplCore/should_compile/TrickyJoins.hs
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/simplCore/should_compile/noinline01.stderr
- testsuite/tests/simplCore/should_compile/par01.stderr
- + testsuite/tests/th/T26098A_quote.hs
- + testsuite/tests/th/T26098A_splice.hs
- + testsuite/tests/th/T26098_local.hs
- + testsuite/tests/th/T26098_local.stderr
- + testsuite/tests/th/T26098_quote.hs
- + testsuite/tests/th/T26098_quote.stderr
- + testsuite/tests/th/T26098_splice.hs
- + testsuite/tests/th/T26098_splice.stderr
- + testsuite/tests/th/T26862_th.script
- + testsuite/tests/th/T26862_th.stderr
- + testsuite/tests/th/T8306_th.script
- + testsuite/tests/th/T8306_th.stderr
- + testsuite/tests/th/T8306_th.stdout
- testsuite/tests/th/T8412.stderr
- + testsuite/tests/th/TH_EmptyLamCases.hs
- + testsuite/tests/th/TH_EmptyLamCases.stderr
- + testsuite/tests/th/TH_EmptyMultiIf.hs
- + testsuite/tests/th/TH_EmptyMultiIf.stderr
- testsuite/tests/th/TH_Roles2.stderr
- testsuite/tests/th/all.T
- testsuite/tests/type-data/should_run/T22332a.stderr
- testsuite/tests/typecheck/should_compile/T13032.stderr
- testsuite/tests/typecheck/should_compile/T18406b.stderr
- testsuite/tests/typecheck/should_compile/T18529.stderr
- + testsuite/tests/typecheck/should_compile/T24464.hs
- testsuite/tests/typecheck/should_compile/all.T
- + testsuite/tests/typecheck/should_fail/T26861.hs
- + testsuite/tests/typecheck/should_fail/T26861.stderr
- + testsuite/tests/typecheck/should_fail/T26862.hs
- + testsuite/tests/typecheck/should_fail/T26862.stderr
- testsuite/tests/typecheck/should_fail/T8306.stderr
- testsuite/tests/typecheck/should_fail/all.T
- testsuite/tests/typecheck/should_run/T10284.stderr
- testsuite/tests/typecheck/should_run/T13838.stderr
- + testsuite/tests/typecheck/should_run/T16981.hs
- + testsuite/tests/typecheck/should_run/T16981.stdout
- + testsuite/tests/typecheck/should_run/T24773.hs
- + testsuite/tests/typecheck/should_run/T24773.stdout
- testsuite/tests/typecheck/should_run/T9497a-run.stderr
- testsuite/tests/typecheck/should_run/T9497b-run.stderr
- testsuite/tests/typecheck/should_run/T9497c-run.stderr
- testsuite/tests/typecheck/should_run/all.T
- testsuite/tests/unboxedsums/all.T
- + testsuite/tests/unboxedsums/unboxedsums4p.hs
- + testsuite/tests/unboxedsums/unboxedsums4p.stderr
- testsuite/tests/unsatisfiable/T23816.stderr
- testsuite/tests/unsatisfiable/UnsatDefer.stderr
- testsuite/tests/vdq-rta/should_compile/all.T
- + testsuite/tests/warnings/should_compile/SpecMultipleTysMono.hs
- + testsuite/tests/warnings/should_compile/SpecMultipleTysMono.stderr
- testsuite/tests/warnings/should_compile/all.T
- testsuite/tests/warnings/should_fail/CaretDiagnostics1.stderr
- utils/check-exact/ExactPrint.hs
- utils/genprimopcode/Main.hs
- utils/ghc-toolchain/src/GHC/Toolchain/Tools/Cc.hs
- utils/ghc-toolchain/src/GHC/Toolchain/Tools/Cpp.hs
- utils/haddock/doc/.gitignore
- utils/haddock/doc/Makefile
- + utils/haddock/doc/_static/haddock-custom.css
- utils/haddock/doc/conf.py
- utils/haddock/doc/markup.rst
- + utils/haddock/doc/snippets/.gitignore
- + utils/haddock/doc/snippets/Lists.hs
- + utils/haddock/doc/snippets/Makefile
- + utils/haddock/doc/snippets/Snippet-List-Bulleted.html
- + utils/haddock/doc/snippets/Snippet-List-Bulleted.tex
- + utils/haddock/doc/snippets/Snippet-List-Definition.html
- + utils/haddock/doc/snippets/Snippet-List-Definition.tex
- + utils/haddock/doc/snippets/Snippet-List-Enumerated.html
- + utils/haddock/doc/snippets/Snippet-List-Enumerated.tex
- + utils/haddock/doc/snippets/Snippet-List-Indentation.html
- + utils/haddock/doc/snippets/Snippet-List-Indentation.tex
- + utils/haddock/doc/snippets/Snippet-List-Multiline-Item.html
- + utils/haddock/doc/snippets/Snippet-List-Multiline-Item.tex
- + utils/haddock/doc/snippets/Snippet-List-Nested-Item.html
- + utils/haddock/doc/snippets/Snippet-List-Nested-Item.tex
- + utils/haddock/doc/snippets/Snippet-List-Not-Newline.html
- + utils/haddock/doc/snippets/Snippet-List-Not-Newline.tex
- + utils/haddock/doc/snippets/Snippet-List-Not-Separated.html
- + utils/haddock/doc/snippets/Snippet-List-Not-Separated.tex
- utils/haddock/haddock-api/src/Haddock/Backends/Hoogle.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Hyperlinker/Parser.hs
- utils/haddock/haddock-api/src/Haddock/Backends/LaTeX.hs
- utils/haddock/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs
- utils/haddock/haddock-api/src/Haddock/Convert.hs
- utils/haddock/haddock-api/src/Haddock/Interface/LexParseRn.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Rename.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
- utils/haddock/html-test/ref/A.html
- utils/haddock/html-test/ref/Bug1004.html
- utils/haddock/html-test/ref/Bug1033.html
- utils/haddock/html-test/ref/Bug1103.html
- utils/haddock/html-test/ref/Bug548.html
- utils/haddock/html-test/ref/Bug923.html
- utils/haddock/html-test/ref/ConstructorPatternExport.html
- utils/haddock/html-test/ref/FunArgs.html
- utils/haddock/html-test/ref/Hash.html
- utils/haddock/html-test/ref/Instances.html
- utils/haddock/html-test/ref/LinearTypes.html
- utils/haddock/html-test/ref/RedactTypeSynonyms.html
- utils/haddock/html-test/ref/T23616.html
- utils/haddock/html-test/ref/Test.html
- utils/haddock/html-test/ref/TypeFamilies3.html
- utils/jsffi/dyld.mjs
- utils/jsffi/post-link.mjs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/e5f071a445e97aa4bfea37fb3d6bdd…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/e5f071a445e97aa4bfea37fb3d6bdd…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/fix-26953] Apply 1 suggestion(s) to 1 file(s)
by recursion-ninja (@recursion-ninja) 10 Mar '26
by recursion-ninja (@recursion-ninja) 10 Mar '26
10 Mar '26
recursion-ninja pushed to branch wip/fix-26953 at Glasgow Haskell Compiler / GHC
Commits:
0d957a2a by recursion-ninja at 2026-03-10T15:52:05+00:00
Apply 1 suggestion(s) to 1 file(s)
Co-authored-by: Rodrigo Mesquita <rodrigo.m.mesquita(a)gmail.com>
- - - - -
1 changed file:
- compiler/GHC/Hs/Lit.hs
Changes:
=====================================
compiler/GHC/Hs/Lit.hs
=====================================
@@ -704,9 +704,6 @@ rnStringLit = convertStringLit
-- |
-- Change the GHC pass from the current 'Pass' to the 'Typechecked' pass.
--- This function can safely accept any GHC 'Pass; as the input,
--- because 'Typechecked' is the final 'Pass'. Note that this permits the
--- "no-op" of going from 'Typechecked' to 'Typechecked'.
{-# INLINE[1] tcStringLit #-}
{-# RULES "tcStringLit/id" tcStringLit = id #-}
tcStringLit :: StringLiteral (GhcPass p) -> StringLiteral GhcTc
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0d957a2a3670ce1eff4046fd04733ea…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0d957a2a3670ce1eff4046fd04733ea…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/T26930] 31 commits: Correct `hIsReadable` and `hIsWritable` for duplex handles
by Teo Camarasu (@teo) 10 Mar '26
by Teo Camarasu (@teo) 10 Mar '26
10 Mar '26
Teo Camarasu pushed to branch wip/T26930 at Glasgow Haskell Compiler / GHC
Commits:
598db847 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Correct `hIsReadable` and `hIsWritable` for duplex handles
This contribution implements CLC proposal #371. It changes `hIsReadable`
and `hIsWritable` such that they always throw a respective exception
when encountering a closed or semi-closed handle, not just in the case
of a file handle.
- - - - -
b90201e5 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Document `SemiClosedHandle`
- - - - -
c9df72b5 by Wolfgang Jeltsch at 2026-03-06T06:25:25-05:00
Tell users what “semi-closed” means for duplex handles
- - - - -
a8aa1868 by Ilias Tsitsimpis at 2026-03-06T06:26:29-05:00
Fix determinism of linker arguments
The switch from Data.Map to UniqMap in 3b5be05ac29 introduced
non-determinism in the order of packages passed to the linker.
This resulted in non-reproducible builds where the DT_NEEDED entries in
dynamic libraries were ordered differently across builds.
Fix the regression by explicitly sorting the package list derived from
UniqMap.
Fixes #26838
- - - - -
9b64ad3a by Matthew Pickering at 2026-03-06T06:27:16-05:00
determinism: Use a deterministic renaming when writing bytecode files
Now when writing the bytecode file, a counter and substitution are used
to provide deterministic keys to local variables (rather than relying on
uniques). This change ensures that `.gbc` are produced
deterministically.
Fixes #26499
- - - - -
d29800e0 by Teo Camarasu at 2026-03-06T06:28:46-05:00
ghc-internal: delete Version hs-boot loop
Version has a Read instance which needs Unicode but part of the Unicode interface is the unicode version. This is easy to resolve. We simply don't re-export the version from the Unicode module.
Resolves #26940
- - - - -
ad25af90 by Sylvain Henry at 2026-03-06T06:30:33-05:00
Linker: implement support for COMMON symbols (#6107)
Add some support for COMMON symbols. We don't support common symbols
having different sizes where the larger one is allocated after the
smaller one. The linker will fail with an appropriate error message if
it happens.
- - - - -
3b59f158 by Cheng Shao at 2026-03-06T06:31:16-05:00
compiler: fix redundant import of GHC.Hs.Lit
This patch removes a redundant import of `GHC.Hs.Lit` which causes a
ghc build failure with validate flavours when bootstrapping from 9.14.
Fixes #26972.
- - - - -
148d36f3 by Cheng Shao at 2026-03-06T06:32:01-05:00
compiler: avoid unneeded traversals in GHC.Unit.State
Following !15591, this patch avoids unneeded traversals in
`reportCycles`/`reportUnusable` when log verbosity is below given
threshold. Also applies `logVerbAtLeast` when appropriate.
Co-authored-by: Codex <codex(a)openai.com>
- - - - -
7e31367c by Cheng Shao at 2026-03-06T06:32:46-05:00
ghc-internal: fix redundant import in GHC.Internal.Event.Windows.ManagedThreadPool
This patch fixes redundant import in
`GHC.Internal.Event.Windows.ManagedThreadPool` that causes a
compilation error when building windows target with validate flavours
and bootstrapping from 9.14. Fixes #26976.
- - - - -
fc8b8e27 by sheaf at 2026-03-06T06:33:28-05:00
System.Info.fullCompilerVersion: add 'since' annot
Fixes #26973
- - - - -
c8238375 by Sylvain Henry at 2026-03-06T06:34:23-05:00
Hadrian: deprecate --bignum and automatically enable +native_bignum for JS
Deprecate --bignum=... to select the bignum backend. It's only used to
select the native backend, and this can be done with the +native_bignum
flavour transformer.
Additionally, we automatically enable +native_bignum for the JS target
because the GMP backend isn't supported.
- - - - -
a3ac7074 by Sylvain Henry at 2026-03-06T06:35:17-05:00
JS: fix putEnum/fromEnum (#24593)
Don't go through Word16 when serializing Enums.
- - - - -
0b36e96c by Andreas Klebinger at 2026-03-06T06:35:58-05:00
Docs: Document -fworker-wrapper-cbv default setting.
Fixes #26841
- - - - -
eca445e7 by mangoiv at 2026-03-07T05:02:36-05:00
drop deb9/10 from CI, add deb13
debian 9 and 10 are end of life, hence we drop them
from our CI, but we do add debian 13. Jobs that were
previously run on 9 and 10 run on 13, too, jobs that
were run on 10, are run on 11 now. Jobs that were
previously run on debian 12 are run on debian 13 now.
This MR also updates hadrian's bootstrap plans for that
reason.
Metric Decrease:
T9872d
- - - - -
12f8b829 by Luite Stegeman at 2026-03-07T05:03:33-05:00
Fix GHC.Internal.Prim haddock
Haddock used to parse Haskell source to generate documentation,
but switched to using interface files instead. This broke documentation
of the GHC.Internal.Prim module, since it's a wired-in interface that
didn't provide a document structure.
This patch adds the missing document structure and updates genprimopcode
to make the section headers and descriptions available.
fixes #26954
- - - - -
f87e5e57 by Luite Stegeman at 2026-03-07T05:03:33-05:00
Remove obsolete --make-haskell-source from genprimopcode
Now that haddock uses the wired-in interface for GHC.Internal.Prim,
the generated Haskell source file is no longer needed. Remove the
--make-haskell-source code generator from genprimopcode and replace
the generated GHC/Internal/Prim.hs with a minimal static source file.
- - - - -
4a7ddc7b by Sylvain Henry at 2026-03-07T05:04:59-05:00
JS: fix linking of exposed but non-preload units (#24886)
Units exposed in the unit database but not explicitly passed on the
command-line were not considered by the JS linker. This isn't an issue
for cabal which passes every unit explicitly but it is an issue when
using GHC directly (cf T24886 test).
- - - - -
689aafcd by mangoiv at 2026-03-07T05:05:52-05:00
testsuite: double foundation timeout multiplier
The runtime timeout in the foundation test was regularly hit by code
generated by the wasm backend - we increase the timout since the high
runtime is expected on the wasm backend for this rather complex test.
Resolves #26938
- - - - -
a46a1bb1 by Cheng Shao at 2026-03-09T04:50:30-04:00
compiler: add myCapabilityExpr to GHC.Cmm.Utils
This commit adds `myCapabilityExpr` to `GHC.Cmm.Utils` which is
computed from `BaseReg`. It's convenient for codegen logic where one
needs to pass the current Capability's pointer.
- - - - -
4afc65b1 by Cheng Shao at 2026-03-09T04:50:30-04:00
compiler: lower tryPutMVar# into a ccall directly
This patch addresses an old TODO of `stg_tryPutMVarzh` by removing it
completely and making the compiler lower `tryPutMVar#` into a ccall to
`performTryPutMVar` directly, without landing into an intermediate C
or Cmm function. `performTryPutMVar` is promoted to a public RTS
function with default visibility, and the compiler lowering logic
takes into account the C ABI of `performTryPutMVar` and converts from
C Bool to primop's `Int#` result properly.
- - - - -
9e3d6a58 by Simon Hengel at 2026-03-09T04:51:15-04:00
Don't use #line in haddocks
This confuses the parser. Haddock output is unaffected by this change.
(read: this still produces the same documentation)
- - - - -
f4e8fec2 by Wolfgang Jeltsch at 2026-03-09T04:52:01-04:00
Remove in-package dependencies on `GHC.Internal.System.IO`
This contribution eliminates all dependencies on
`GHC.Internal.System.IO` from within `ghc-internal`. It comprises the
following changes:
* Make `GHC.Internal.Fingerprint` independent of I/O support
* Tighten the dependencies of `GHC.Internal.Data.Version`
* Tighten the dependencies of `GHC.Internal.TH.Monad`
* Tighten the dependencies of `GHCi.Helpers`
* Move some code that needs `System.IO` to `template-haskell`
* Move the `GHC.ResponseFile` implementation into `base`
* Move the `System.Exit` implementation into `base`
* Move the `System.IO.OS` implementation into `base`
Metric Decrease:
size_hello_artifact
size_hello_artifact_gzip
size_hello_unicode
size_hello_unicode_gzip
- - - - -
91df4c82 by Sylvain Henry at 2026-03-09T04:53:20-04:00
T18832: fix Windows CI failure by dropping removeDirectoryRecursive
On Windows, open file handles prevent deletion. After killThread, the
closer thread may not have called hClose yet, causing removeDirectoryRecursive
to fail with "permission denied". The test harness cleans up the run
directory anyway, so the call is redundant.
- - - - -
d7fe9671 by Cheng Shao at 2026-03-09T04:54:04-04:00
compiler: fix redundant import in GHC.StgToJS.Object
This patch fixes a redundant import in GHC.StgToJS.Object that causes
a build failure when compiling head from 9.14 with validate flavours.
Fixes #26991.
- - - - -
0bfd29c3 by Cheng Shao at 2026-03-09T04:54:46-04:00
wasm: fix `Illegal foreign declaration` failure when ghci loads modules with JSFFI exports
This patch fixes a wasm ghci error when loading modules with JSFFI
exports; the `backendValidityOfCExport` check in `tcCheckFEType`
should only makes sense and should be performed when not checking the
JavaScript calling convention; otherwise, when the calling convention
is JavaScript, the codegen logic should be trusted to backends that
actually make use of it. Fixes #26998.
- - - - -
e659610c by Duncan Coutts at 2026-03-09T12:08:35-04:00
Apply NOINLINE pragmas to generated Typeable bindings
For context, see the existing Note [Grand plan for Typeable]
and the Note [NOINLINE on generated Typeable bindings] added in the
subsequent commit.
This is about reducing the number of exported top level names and
unfoldings, which reduces interface file sizes and reduces the number of
global/dynamic linker symbols.
Also accept the changed test output and metric decreases.
Tests that record the phase output for type checking or for simplifier
end up with different output: the generated bindings now have an
Inline [~] annotation, and many top level names are now local rather
than module-prefixed for export.
Also accept the numerous metric decreases in compile_time/bytes
allocated, and a few in compile_time/max_bytes_used.
There's also one instance of a decrease in runtime/max_bytes_used but
it's a ghci-way test and so presumably the reason is that it loads
smaller .hi files and/or links fewer symbols.
-------------------------
Metric Decrease:
CoOpt_Singletons
MultiLayerModulesTH_OneShot
MultilineStringsPerf
T10421
T10547
T12150
T12227
T12234
T12425
T13035
T13056
T13253
T13253-spj
T15304
T15703
T16875
T17836b
T17977b
T18140
T18223
T18282
T18304
T18698a
T18698b
T18730
T18923
T20049
T21839c
T24471
T24582
T24984
T3064
T4029
T5030
T5642
T5837
T6048
T9020
T9198
T9961
TcPlugin_RewritePerf
WWRec
hard_hole_fits
mhu-perf
-------------------------
- - - - -
67df5161 by Duncan Coutts at 2026-03-09T12:08:35-04:00
Add documentation Note [NOINLINE on generated Typeable bindings]
and refer to it from the code and existing documentation.
- - - - -
c4ad6167 by Duncan Coutts at 2026-03-09T12:08:35-04:00
Switch existing note to "named wrinkle" style, (GPT1)..(GPT7)
GPT = Grand plan for Typeable
- - - - -
dc84f8e2 by Cheng Shao at 2026-03-09T12:09:21-04:00
ci: only build deb13 for validate pipeline aarch64-linux jobs
This patch drops the redundant aarch64-linux deb12 job from validate pipelines
and only keeps deb13; it's still built in nightly/release pipelines. Closes #27004.
- - - - -
be4c2ec4 by Teo Camarasu at 2026-03-10T15:42:28+00:00
ghc-internal: Float Generics to near top of module graph
We remove GHC.Internal.Generics from the critical path of the
`ghc-internal` module graph. GHC.Internal.Generics used to be in the
middle of the module graph, but now it is nearer the top (built later).
This change thins out the module graph and allows us to get rid of the
ByteOrder hs-boot file.
We implement this by moving Generics instances from the module where the
datatype is defined to the GHC.Internal.Generics module. This trades off
increasing the compiled size of GHC.Internal.Generics with reducing the
dependency footprint of datatype modules.
Not all instances are moved to GHC.Internal.Generics. For instance,
`GHC.Internal.Control.Monad.Fix` keeps its instance as it is one of the
very last modules compiled in `ghc-internal` and so inverting the
relationship here would risk adding GHC.Internal.Generics back onto the
critical path.
We also don't change modules that are re-exported from the `template-haskell` or `ghc-heap`.
This is done to make it easy to eventually move `Generics` to `base`
once something like #26657 is implemented.
Resolves #26930
Metric Decrease:
T21839c
- - - - -
145 changed files:
- .gitlab-ci.yml
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/jobs.yaml
- .gitlab/rel_eng/fetch-gitlab-artifacts/fetch_gitlab.py
- .gitlab/rel_eng/mk-ghcup-metadata/mk_ghcup_metadata.py
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/Builtin/Utils.hs
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/Cmm/Utils.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Hs/Type.hs
- compiler/GHC/Iface/Ext/Utils.hs
- compiler/GHC/Runtime/Interpreter/JS.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/Object.hs
- compiler/GHC/Tc/Gen/Foreign.hs
- compiler/GHC/Tc/Instance/Typeable.hs
- compiler/GHC/Unit/State.hs
- compiler/GHC/Utils/Error.hs
- docs/users_guide/using-optimisation.rst
- hadrian/README.md
- hadrian/bootstrap/generate_bootstrap_plans
- hadrian/bootstrap/plan-9_10_1.json
- hadrian/bootstrap/plan-9_10_2.json
- + hadrian/bootstrap/plan-9_10_3.json
- hadrian/bootstrap/plan-bootstrap-9_10_1.json
- hadrian/bootstrap/plan-bootstrap-9_10_2.json
- + hadrian/bootstrap/plan-bootstrap-9_10_3.json
- hadrian/src/CommandLine.hs
- hadrian/src/Main.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Settings.hs
- hadrian/src/Settings/Builders/GenPrimopCode.hs
- libraries/base/changelog.md
- libraries/base/src/GHC/Fingerprint.hs
- libraries/base/src/GHC/ResponseFile.hs
- libraries/base/src/GHC/Unicode.hs
- libraries/base/src/System/Exit.hs
- libraries/base/src/System/IO/OS.hs
- libraries/base/src/System/Info.hs
- libraries/base/tests/IO/T18832.hs
- libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/ByteOrder.hs
- − libraries/ghc-internal/src/GHC/Internal/ByteOrder.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Data/Foldable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Const.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Identity.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Monoid.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Semigroup/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Traversable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Version.hs
- − libraries/ghc-internal/src/GHC/Internal/Data/Version.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Event/Windows/ManagedThreadPool.hs
- libraries/ghc-internal/src/GHC/Internal/Fingerprint.hs
- libraries/ghc-internal/src/GHC/Internal/Functor/ZipList.hs
- libraries/ghc-internal/src/GHC/Internal/GHCi/Helpers.hs
- libraries/ghc-internal/src/GHC/Internal/Generics.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Types.hs
- + libraries/ghc-internal/src/GHC/Internal/Prim.hs
- libraries/ghc-internal/src/GHC/Internal/Read.hs
- − libraries/ghc-internal/src/GHC/Internal/ResponseFile.hs
- − libraries/ghc-internal/src/GHC/Internal/System/Exit.hs
- − libraries/ghc-internal/src/GHC/Internal/System/IO/OS.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Bits.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Version.hs
- libraries/ghc-internal/tools/ucd2haskell/exe/UCD2Haskell/ModuleGenerators.hs
- libraries/template-haskell/Language/Haskell/TH/Syntax.hs
- rts/Linker.c
- rts/LinkerInternals.h
- rts/PrimOps.cmm
- rts/RtsSymbols.c
- rts/Threads.c
- rts/Threads.h
- rts/include/rts/Threads.h
- rts/include/stg/MiscClosures.h
- rts/linker/Elf.c
- rts/linker/MachO.c
- rts/linker/PEi386.c
- testsuite/driver/perf_notes.py
- testsuite/tests/deSugar/should_compile/T16615.stderr
- testsuite/tests/deSugar/should_compile/T2431.stderr
- testsuite/tests/dmdanal/should_compile/T16029.stdout
- testsuite/tests/ffi/should_compile/all.T
- + testsuite/tests/ghci-wasm/T26998.hs
- testsuite/tests/ghci-wasm/all.T
- testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout
- testsuite/tests/ghci/scripts/T10963.stderr
- testsuite/tests/ghci/scripts/ghci064.stdout
- testsuite/tests/ghci/should_run/all.T
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/base-exports.stdout-ws-32
- + testsuite/tests/javascript/T24886.hs
- + testsuite/tests/javascript/T24886.stderr
- + testsuite/tests/javascript/T24886.stdout
- testsuite/tests/javascript/all.T
- testsuite/tests/numeric/should_compile/T14170.stdout
- testsuite/tests/numeric/should_compile/T14465.stdout
- testsuite/tests/numeric/should_compile/T7116.stdout
- testsuite/tests/numeric/should_run/all.T
- testsuite/tests/overloadedrecflds/should_compile/all.T
- testsuite/tests/overloadedrecflds/should_run/all.T
- testsuite/tests/pmcheck/should_compile/T11303.hs
- testsuite/tests/quasiquotation/qq005/test.T
- testsuite/tests/quasiquotation/qq006/test.T
- testsuite/tests/roles/should_compile/Roles1.stderr
- testsuite/tests/roles/should_compile/Roles13.stderr
- testsuite/tests/roles/should_compile/Roles14.stderr
- testsuite/tests/roles/should_compile/Roles2.stderr
- testsuite/tests/roles/should_compile/Roles3.stderr
- testsuite/tests/roles/should_compile/Roles4.stderr
- testsuite/tests/roles/should_compile/T8958.stderr
- testsuite/tests/rts/linker/Makefile
- + testsuite/tests/rts/linker/T6107.hs
- + testsuite/tests/rts/linker/T6107.stdout
- + testsuite/tests/rts/linker/T6107_sym1.s
- + testsuite/tests/rts/linker/T6107_sym2.s
- testsuite/tests/rts/linker/all.T
- testsuite/tests/saks/should_compile/all.T
- testsuite/tests/showIface/all.T
- testsuite/tests/simplCore/should_compile/OpaqueNoCastWW.stderr
- testsuite/tests/simplCore/should_compile/T3717.stderr
- testsuite/tests/simplCore/should_compile/T3772.stdout
- testsuite/tests/simplCore/should_compile/T4908.stderr
- testsuite/tests/simplCore/should_compile/T4930.stderr
- testsuite/tests/simplCore/should_compile/T7360.stderr
- testsuite/tests/simplCore/should_compile/T8274.stdout
- testsuite/tests/simplCore/should_compile/T9400.stderr
- testsuite/tests/simplCore/should_compile/noinline01.stderr
- testsuite/tests/simplCore/should_compile/par01.stderr
- testsuite/tests/th/TH_Roles2.stderr
- testsuite/tests/th/all.T
- testsuite/tests/typecheck/should_compile/T13032.stderr
- testsuite/tests/typecheck/should_compile/T18406b.stderr
- testsuite/tests/typecheck/should_compile/T18529.stderr
- testsuite/tests/vdq-rta/should_compile/all.T
- utils/genprimopcode/Main.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a7eb4232369e76db5045014394666b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a7eb4232369e76db5045014394666b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc] Pushed new branch wip/stack-cloning-segfault
by Matthew Pickering (@mpickering) 10 Mar '26
by Matthew Pickering (@mpickering) 10 Mar '26
10 Mar '26
Matthew Pickering pushed new branch wip/stack-cloning-segfault at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/stack-cloning-segfault
You're receiving this email because of your account on gitlab.haskell.org.
1
0