summaryrefslogtreecommitdiff
path: root/rts/include/RtsAPI.h
diff options
context:
space:
mode:
Diffstat (limited to 'rts/include/RtsAPI.h')
-rw-r--r--rts/include/RtsAPI.h607
1 files changed, 607 insertions, 0 deletions
diff --git a/rts/include/RtsAPI.h b/rts/include/RtsAPI.h
new file mode 100644
index 0000000000..e2d1845819
--- /dev/null
+++ b/rts/include/RtsAPI.h
@@ -0,0 +1,607 @@
+/* ----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * API for invoking Haskell functions via the RTS
+ *
+ * To understand the structure of the RTS headers, see the wiki:
+ * https://gitlab.haskell.org/ghc/ghc/wikis/commentary/source-tree/includes
+ *
+ * --------------------------------------------------------------------------*/
+
+#pragma once
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "HsFFI.h"
+#include "rts/Time.h"
+#include "rts/Types.h"
+
+/*
+ * Running the scheduler
+ */
+typedef enum {
+ NoStatus, /* not finished yet */
+ Success, /* completed successfully */
+ Killed, /* uncaught exception */
+ Interrupted, /* stopped in response to a call to interruptStgRts */
+ HeapExhausted /* out of memory */
+} SchedulerStatus;
+
+typedef struct StgClosure_ *HaskellObj;
+
+/*
+ * An abstract type representing the token returned by rts_lock() and
+ * used when allocating objects and threads in the RTS.
+ */
+typedef struct Capability_ Capability;
+
+/*
+ * An abstract type representing the token returned by rts_pause().
+ */
+typedef struct PauseToken_ PauseToken;
+
+/*
+ * From a PauseToken, get a Capability token used when allocating objects and
+ * threads in the RTS.
+ */
+Capability *pauseTokenCapability(PauseToken *pauseToken);
+
+/*
+ * The public view of a Capability: we can be sure it starts with
+ * these two components (but it may have more private fields).
+ */
+typedef struct CapabilityPublic_ {
+ StgFunTable f;
+ StgRegTable r;
+} CapabilityPublic;
+
+/* N.B. this needs the Capability declaration above. */
+#include "rts/EventLogWriter.h"
+
+/* ----------------------------------------------------------------------------
+ RTS configuration settings, for passing to hs_init_ghc()
+ ------------------------------------------------------------------------- */
+
+typedef enum {
+ RtsOptsNone, // +RTS causes an error
+ RtsOptsIgnore, // Ignore command line arguments
+ RtsOptsIgnoreAll, // Ignore command line and Environment arguments
+ RtsOptsSafeOnly, // safe RTS options allowed; others cause an error
+ RtsOptsAll // all RTS options allowed
+ } RtsOptsEnabledEnum;
+
+struct GCDetails_;
+
+// The RtsConfig struct is passed (by value) to hs_init_ghc(). The
+// reason for using a struct is extensibility: we can add more
+// fields to this later without breaking existing client code.
+typedef struct {
+
+ // Whether to interpret +RTS options on the command line
+ RtsOptsEnabledEnum rts_opts_enabled;
+
+ // Whether to give RTS flag suggestions
+ HsBool rts_opts_suggestions;
+
+ // additional RTS options
+ const char *rts_opts;
+
+ // True if GHC was not passed -no-hs-main
+ HsBool rts_hs_main;
+
+ // Whether to retain CAFs (default: false)
+ HsBool keep_cafs;
+
+ // Writer a for eventlog.
+ const EventLogWriter *eventlog_writer;
+
+ // Called before processing command-line flags, so that default
+ // settings for RtsFlags can be provided.
+ void (* defaultsHook) (void);
+
+ // Called just before exiting
+ void (* onExitHook) (void);
+
+ // Called on a stack overflow, before exiting
+ void (* stackOverflowHook) (W_ stack_size);
+
+ // Called on heap overflow, before exiting
+ void (* outOfHeapHook) (W_ request_size, W_ heap_size);
+
+ // Called when malloc() fails, before exiting
+ void (* mallocFailHook) (W_ request_size /* in bytes */, const char *msg);
+
+ // Called for every GC
+ void (* gcDoneHook) (const struct GCDetails_ *stats);
+
+ // Called when GC sync takes too long (+RTS --long-gc-sync=<time>)
+ void (* longGCSync) (uint32_t this_cap, Time time_ns);
+ void (* longGCSyncEnd) (Time time_ns);
+} RtsConfig;
+
+// Clients should start with defaultRtsConfig and then customise it.
+// Bah, I really wanted this to be a const struct value, but it seems
+// you can't do that in C (it generates code).
+extern const RtsConfig defaultRtsConfig;
+
+/* -----------------------------------------------------------------------------
+ Statistics
+ -------------------------------------------------------------------------- */
+
+//
+// Stats about a single GC
+//
+typedef struct GCDetails_ {
+ // The generation number of this GC
+ uint32_t gen;
+ // Number of threads used in this GC
+ uint32_t threads;
+ // Number of bytes allocated since the previous GC
+ uint64_t allocated_bytes;
+ // Total amount of live data in the heap (incliudes large + compact data).
+ // Updated after every GC. Data in uncollected generations (in minor GCs)
+ // are considered live.
+ uint64_t live_bytes;
+ // Total amount of live data in large objects
+ uint64_t large_objects_bytes;
+ // Total amount of live data in compact regions
+ uint64_t compact_bytes;
+ // Total amount of slop (wasted memory)
+ uint64_t slop_bytes;
+ // Total amount of memory in use by the RTS
+ uint64_t mem_in_use_bytes;
+ // Total amount of data copied during this GC
+ uint64_t copied_bytes;
+ // In parallel GC, the max amount of data copied by any one thread
+ uint64_t par_max_copied_bytes;
+ // In parallel GC, the amount of balanced data copied by all threads
+ uint64_t par_balanced_copied_bytes;
+ // The time elapsed during synchronisation before GC
+ Time sync_elapsed_ns;
+ // The CPU time used during GC itself
+ Time cpu_ns;
+ // The time elapsed during GC itself
+ Time elapsed_ns;
+
+ //
+ // Concurrent garbage collector
+ //
+
+ // The CPU time used during the post-mark pause phase of the concurrent
+ // nonmoving GC.
+ Time nonmoving_gc_sync_cpu_ns;
+ // The time elapsed during the post-mark pause phase of the concurrent
+ // nonmoving GC.
+ Time nonmoving_gc_sync_elapsed_ns;
+ // The CPU time used during the post-mark pause phase of the concurrent
+ // nonmoving GC.
+ Time nonmoving_gc_cpu_ns;
+ // The time elapsed during the post-mark pause phase of the concurrent
+ // nonmoving GC.
+ Time nonmoving_gc_elapsed_ns;
+} GCDetails;
+
+//
+// Stats about the RTS currently, and since the start of execution
+//
+typedef struct _RTSStats {
+
+ // -----------------------------------
+ // Cumulative stats about memory use
+
+ // Total number of GCs
+ uint32_t gcs;
+ // Total number of major (oldest generation) GCs
+ uint32_t major_gcs;
+ // Total bytes allocated
+ uint64_t allocated_bytes;
+ // Maximum live data (including large objects + compact regions) in the
+ // heap. Updated after a major GC.
+ uint64_t max_live_bytes;
+ // Maximum live data in large objects
+ uint64_t max_large_objects_bytes;
+ // Maximum live data in compact regions
+ uint64_t max_compact_bytes;
+ // Maximum slop
+ uint64_t max_slop_bytes;
+ // Maximum memory in use by the RTS
+ uint64_t max_mem_in_use_bytes;
+ // Sum of live bytes across all major GCs. Divided by major_gcs
+ // gives the average live data over the lifetime of the program.
+ uint64_t cumulative_live_bytes;
+ // Sum of copied_bytes across all GCs
+ uint64_t copied_bytes;
+ // Sum of copied_bytes across all parallel GCs
+ uint64_t par_copied_bytes;
+ // Sum of par_max_copied_bytes across all parallel GCs
+ uint64_t cumulative_par_max_copied_bytes;
+ // Sum of par_balanced_copied_byes across all parallel GCs.
+ uint64_t cumulative_par_balanced_copied_bytes;
+
+ // -----------------------------------
+ // Cumulative stats about time use
+ // (we use signed values here because due to inaccuracies in timers
+ // the values can occasionally go slightly negative)
+
+ // Total CPU time used by the init phase
+ Time init_cpu_ns;
+ // Total elapsed time used by the init phase
+ Time init_elapsed_ns;
+ // Total CPU time used by the mutator
+ Time mutator_cpu_ns;
+ // Total elapsed time used by the mutator
+ Time mutator_elapsed_ns;
+ // Total CPU time used by the GC
+ Time gc_cpu_ns;
+ // Total elapsed time used by the GC
+ Time gc_elapsed_ns;
+ // Total CPU time (at the previous GC)
+ Time cpu_ns;
+ // Total elapsed time (at the previous GC)
+ Time elapsed_ns;
+
+ // -----------------------------------
+ // Stats about the most recent GC
+
+ GCDetails gc;
+
+ // -----------------------------------
+ // Internal Counters
+
+ uint64_t any_work;
+ // The number of times a GC thread has iterated it's outer loop across all
+ // parallel GCs
+ uint64_t scav_find_work;
+
+ uint64_t max_n_todo_overflow;
+
+ // ----------------------------------
+ // Concurrent garbage collector
+
+ // The CPU time used during the post-mark pause phase of the concurrent
+ // nonmoving GC.
+ Time nonmoving_gc_sync_cpu_ns;
+ // The time elapsed during the post-mark pause phase of the concurrent
+ // nonmoving GC.
+ Time nonmoving_gc_sync_elapsed_ns;
+ // The maximum time elapsed during the post-mark pause phase of the
+ // concurrent nonmoving GC.
+ Time nonmoving_gc_sync_max_elapsed_ns;
+ // The CPU time used during the post-mark pause phase of the concurrent
+ // nonmoving GC.
+ Time nonmoving_gc_cpu_ns;
+ // The time elapsed during the post-mark pause phase of the concurrent
+ // nonmoving GC.
+ Time nonmoving_gc_elapsed_ns;
+ // The maximum time elapsed during the post-mark pause phase of the
+ // concurrent nonmoving GC.
+ Time nonmoving_gc_max_elapsed_ns;
+} RTSStats;
+
+void getRTSStats (RTSStats *s);
+int getRTSStatsEnabled (void);
+
+// Returns the total number of bytes allocated since the start of the program.
+// TODO: can we remove this?
+uint64_t getAllocations (void);
+
+/* ----------------------------------------------------------------------------
+ Starting up and shutting down the Haskell RTS.
+ ------------------------------------------------------------------------- */
+
+/* DEPRECATED, use hs_init() or hs_init_ghc() instead */
+extern void startupHaskell ( int argc, char *argv[],
+ void (*init_root)(void) );
+
+/* DEPRECATED, use hs_exit() instead */
+extern void shutdownHaskell ( void );
+
+/* Like hs_init(), but allows rtsopts. For more complicated usage,
+ * use hs_init_ghc. */
+extern void hs_init_with_rtsopts (int *argc, char **argv[]);
+
+/*
+ * GHC-specific version of hs_init() that allows specifying whether
+ * +RTS ... -RTS options are allowed or not (default: only "safe"
+ * options are allowed), and allows passing an option string that is
+ * to be interpreted by the RTS only, not passed to the program.
+ */
+extern void hs_init_ghc (int *argc, char **argv[], // program arguments
+ RtsConfig rts_config); // RTS configuration
+
+extern void shutdownHaskellAndExit (int exitCode, int fastExit)
+ GNUC3_ATTRIBUTE(__noreturn__);
+
+#if !defined(mingw32_HOST_OS)
+extern void shutdownHaskellAndSignal (int sig, int fastExit)
+ GNUC3_ATTRIBUTE(__noreturn__);
+#endif
+
+extern void getProgArgv ( int *argc, char **argv[] );
+extern void setProgArgv ( int argc, char *argv[] );
+extern void getFullProgArgv ( int *argc, char **argv[] );
+extern void setFullProgArgv ( int argc, char *argv[] );
+extern void freeFullProgArgv ( void ) ;
+
+/* exit() override */
+extern void (*exitFn)(int);
+
+/* Note [Locking and Pausing the RTS]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You have to surround all access to the RtsAPI with rts_lock/rts_unlock or
+with rts_pause/rts_resume.
+
+
+# rts_lock / rts_unlock
+
+Use `rts_lock` to acquire a token which may be used to call other RtsAPI
+functions and call `rts_unlock` to return the token. When locked, garbage
+collection will not occur. As long as 1 or more capabilities are not locked,
+haskell threads will continue to execute. If you want to pause execution of
+all haskell threads then use rts_pause/rts_resume instead.
+
+The implementation of `rts_lock` acquires a capability for this thread. Hence,
+at most n locks can be held simultaneously, where n is the number of
+capabilities. It is an error to call `rts_lock` when the rts is already
+paused by the current OS thread (see rts_pause/rts_resume below).
+
+
+# rts_pause / rts_resume
+
+Use `rts_pause` to pause execution of all Haskell threads and `rts_resume` to
+resume them. The implementation acquires all capabilities. `rts_resume`
+must be called on the same thread as `rts_pause`. `rts_pause`, much like
+rts_lock, returns a token. A `Capability` can be extracted from that token using
+`pauseTokenCapability()`. The `Capability` can then be used to call other RtsAPI
+functions.
+
+* With the RTS paused, garbage collections will not occur and haskell threads
+ will not execute, allocate, nor mutate their stacks.
+* Non-Haskell (i.e. non-worker) threads such as those running safe FFI calls
+ will NOT be paused and can still mutate pinned mutable data such as pinned
+ `MutableByteArray#`s.
+* You may call `rts_pause` from within a non-worker OS thread.
+* You may call `rts_pause` from within a *safe* FFI call. In this case, make
+ sure to call `rts_resume` within the same FFI call or the RTS will deadlock.
+* Calling `rts_pause` from an *unsafe* FFI call will cause an error.
+* On return, the rts will be fully paused: all haskell threads are stopped
+ and all capabilities are acquired by the current OS thread.
+* Calling `rts_pause` in between rts_lock/rts_unlock on the same thread will
+ cause an error.
+* Calling `rts_pause` results in an error if the RTS is already paused by the
+ current OS thread.
+* Only one OS thread at a time can keep the rts paused.
+* `rts_pause` will block while another thread is pausing the RTS, and
+ continue when the current thread is given exclusive permission to pause the
+ RTS.
+
+## Note on implementation.
+
+Thread safety is achieved almost entirely by the mechanism of acquiring and
+releasing Capabilities, resulting in a sort of mutex / critical section pattern.
+This has the following consequences:
+
+* There are at most `n_capabilities` threads currently in a
+ rts_lock/rts_unlock section.
+* There is at most 1 threads in a rts_pause/rts_resume section. In that case
+ there will be no threads in a rts_lock/rts_unlock section.
+* rts_pause and rts_lock may block in order to enforce the above 2
+ invariants.
+
+*/
+
+// Acquires a token which may be used to create new objects and evaluate them.
+// See Note [Locking and Pausing the RTS] for correct usage.
+Capability *rts_lock (void);
+
+// releases the token acquired with rts_lock().
+// See Note [Locking and Pausing the RTS] for correct usage.
+void rts_unlock (Capability *token);
+
+// If you are in a context where you know you have a current capability but
+// do not know what it is, then use this to get it. Basically this only
+// applies to "unsafe" foreign calls (as unsafe foreign calls are made with
+// the capability held).
+//
+// WARNING: There is *no* guarantee this returns anything sensible (eg NULL)
+// when there is no current capability.
+Capability *rts_unsafeGetMyCapability (void);
+
+/* ----------------------------------------------------------------------------
+ Which cpu should the OS thread and Haskell thread run on?
+
+ 1. Run the current thread on the given capability:
+ rts_setInCallCapability(cap, 0);
+
+ 2. Run the current thread on the given capability and set the cpu affinity
+ for this thread:
+ rts_setInCallCapability(cap, 1);
+
+ 3. Run the current thread on the given numa node:
+ rts_pinThreadToNumaNode(node);
+
+ 4. Run the current thread on the given capability and on the given numa node:
+ rts_setInCallCapability(cap, 0);
+ rts_pinThreadToNumaNode(cap);
+ ------------------------------------------------------------------------- */
+
+// Specify the Capability that the current OS thread should run on when it calls
+// into Haskell. The actual capability will be calculated as the supplied
+// value modulo the number of enabled Capabilities.
+//
+// If affinity is non-zero, the current thread will be bound to
+// specific CPUs according to the prevailing affinity policy for the
+// specified capability, set by either +RTS -qa or +RTS --numa.
+void rts_setInCallCapability (int preferred_capability, int affinity);
+
+// Specify the CPU Node that the current OS thread should run on when it calls
+// into Haskell. The argument can be either a node number or capability number.
+// The actual node will be calculated as the supplied value modulo the number
+// of numa nodes.
+void rts_pinThreadToNumaNode (int node);
+
+/* ----------------------------------------------------------------------------
+ Building Haskell objects from C datatypes.
+ ------------------------------------------------------------------------- */
+HaskellObj rts_mkChar ( Capability *, HsChar c );
+HaskellObj rts_mkInt ( Capability *, HsInt i );
+HaskellObj rts_mkInt8 ( Capability *, HsInt8 i );
+HaskellObj rts_mkInt16 ( Capability *, HsInt16 i );
+HaskellObj rts_mkInt32 ( Capability *, HsInt32 i );
+HaskellObj rts_mkInt64 ( Capability *, HsInt64 i );
+HaskellObj rts_mkWord ( Capability *, HsWord w );
+HaskellObj rts_mkWord8 ( Capability *, HsWord8 w );
+HaskellObj rts_mkWord16 ( Capability *, HsWord16 w );
+HaskellObj rts_mkWord32 ( Capability *, HsWord32 w );
+HaskellObj rts_mkWord64 ( Capability *, HsWord64 w );
+HaskellObj rts_mkPtr ( Capability *, HsPtr a );
+HaskellObj rts_mkFunPtr ( Capability *, HsFunPtr a );
+HaskellObj rts_mkFloat ( Capability *, HsFloat f );
+HaskellObj rts_mkDouble ( Capability *, HsDouble f );
+HaskellObj rts_mkStablePtr ( Capability *, HsStablePtr s );
+HaskellObj rts_mkBool ( Capability *, HsBool b );
+HaskellObj rts_mkString ( Capability *, char *s );
+
+HaskellObj rts_apply ( Capability *, HaskellObj, HaskellObj );
+
+/* ----------------------------------------------------------------------------
+ Deconstructing Haskell objects
+ ------------------------------------------------------------------------- */
+HsChar rts_getChar ( HaskellObj );
+HsInt rts_getInt ( HaskellObj );
+HsInt8 rts_getInt8 ( HaskellObj );
+HsInt16 rts_getInt16 ( HaskellObj );
+HsInt32 rts_getInt32 ( HaskellObj );
+HsInt64 rts_getInt64 ( HaskellObj );
+HsWord rts_getWord ( HaskellObj );
+HsWord8 rts_getWord8 ( HaskellObj );
+HsWord16 rts_getWord16 ( HaskellObj );
+HsWord32 rts_getWord32 ( HaskellObj );
+HsWord64 rts_getWord64 ( HaskellObj );
+HsPtr rts_getPtr ( HaskellObj );
+HsFunPtr rts_getFunPtr ( HaskellObj );
+HsFloat rts_getFloat ( HaskellObj );
+HsDouble rts_getDouble ( HaskellObj );
+HsStablePtr rts_getStablePtr ( HaskellObj );
+HsBool rts_getBool ( HaskellObj );
+
+/* ----------------------------------------------------------------------------
+ Evaluating Haskell expressions
+
+ The versions ending in '_' allow you to specify an initial stack size.
+ Note that these calls may cause Garbage Collection, so all HaskellObj
+ references are rendered invalid by these calls.
+
+ All of these functions take a (Capability **) - there is a
+ Capability pointer both input and output. We use an inout
+ parameter because this is less error-prone for the client than a
+ return value - the client could easily forget to use the return
+ value, whereas incorrectly using an inout parameter will usually
+ result in a type error.
+ ------------------------------------------------------------------------- */
+
+void rts_eval (/* inout */ Capability **,
+ /* in */ HaskellObj p,
+ /* out */ HaskellObj *ret);
+
+void rts_eval_ (/* inout */ Capability **,
+ /* in */ HaskellObj p,
+ /* in */ unsigned int stack_size,
+ /* out */ HaskellObj *ret);
+
+void rts_evalIO (/* inout */ Capability **,
+ /* in */ HaskellObj p,
+ /* out */ HaskellObj *ret);
+
+void rts_evalStableIOMain (/* inout */ Capability **,
+ /* in */ HsStablePtr s,
+ /* out */ HsStablePtr *ret);
+
+void rts_evalStableIO (/* inout */ Capability **,
+ /* in */ HsStablePtr s,
+ /* out */ HsStablePtr *ret);
+
+void rts_evalLazyIO (/* inout */ Capability **,
+ /* in */ HaskellObj p,
+ /* out */ HaskellObj *ret);
+
+void rts_evalLazyIO_ (/* inout */ Capability **,
+ /* in */ HaskellObj p,
+ /* in */ unsigned int stack_size,
+ /* out */ HaskellObj *ret);
+
+void rts_inCall (/* inout */ Capability **,
+ /* in */ HaskellObj p,
+ /* out */ HaskellObj *ret);
+
+void rts_checkSchedStatus (char* site, Capability *);
+
+SchedulerStatus rts_getSchedStatus (Capability *cap);
+
+// Halt execution of all Haskell threads.
+// See Note [Locking and Pausing the RTS] for correct usage.
+PauseToken *rts_pause (void);
+
+// Counterpart of rts_pause: Continue from a pause.
+// See Note [Locking and Pausing the RTS] for correct usage.
+// [in] pauseToken: the token returned by rts_pause.
+void rts_resume (PauseToken *pauseToken);
+
+// Returns true if the rts is paused. See rts_pause() and rts_resume().
+bool rts_isPaused(void);
+
+// List all live threads. The RTS must be paused and this must be called on the
+// same thread that called rts_pause().
+typedef void (*ListThreadsCb)(void *user, StgTSO *);
+void rts_listThreads(ListThreadsCb cb, void *user);
+
+// List all non-thread GC roots. The RTS must be paused and this must be called
+// on the same thread that called rts_pause().
+typedef void (*ListRootsCb)(void *user, StgClosure *);
+void rts_listMiscRoots(ListRootsCb cb, void *user);
+
+/*
+ * The RTS allocates some thread-local data when you make a call into
+ * Haskell using one of the rts_eval() functions. This data is not
+ * normally freed until hs_exit(). If you want to free it earlier
+ * than this, perhaps because the thread is about to exit, then call
+ * rts_done() from the thread.
+ *
+ * It is safe to make more rts_eval() calls after calling rts_done(),
+ * but the next one will cause allocation of the thread-local memory
+ * again.
+ */
+void rts_done (void);
+
+/* --------------------------------------------------------------------------
+ Wrapper closures
+
+ These are used by foreign export and foreign import "wrapper" stubs.
+ ----------------------------------------------------------------------- */
+
+// When producing Windows DLLs the we need to know which symbols are in the
+// local package/DLL vs external ones.
+//
+// Note that RtsAPI.h is also included by foreign export stubs in
+// the base package itself.
+//
+#if defined(COMPILING_WINDOWS_DLL) && !defined(COMPILING_BASE_PACKAGE)
+__declspec(dllimport) extern StgWord base_GHCziTopHandler_runIO_closure[];
+__declspec(dllimport) extern StgWord base_GHCziTopHandler_runNonIO_closure[];
+#else
+extern StgWord base_GHCziTopHandler_runIO_closure[];
+extern StgWord base_GHCziTopHandler_runNonIO_closure[];
+#endif
+
+#define runIO_closure base_GHCziTopHandler_runIO_closure
+#define runNonIO_closure base_GHCziTopHandler_runNonIO_closure
+
+/* ------------------------------------------------------------------------ */
+
+#if defined(__cplusplus)
+}
+#endif