diff --git a/build.sbt b/build.sbt
index 1187d31bd8..b71524a1a9 100644
--- a/build.sbt
+++ b/build.sbt
@@ -937,7 +937,7 @@ lazy val tests: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatf
)
.jvmSettings(
fork := true,
- Test / javaOptions += "-Dcats.effect.ioLocalPropagation=true"
+ Test / javaOptions += "-Dcats.effect.trackFiberContext=true"
)
.nativeSettings(
Compile / mainClass := Some("catseffect.examples.NativeRunner")
diff --git a/core/js-native/src/main/scala/cats/effect/IOFiberConstants.scala b/core/js-native/src/main/scala/cats/effect/IOFiberConstants.scala
index efd9594bb0..69a1483d68 100644
--- a/core/js-native/src/main/scala/cats/effect/IOFiberConstants.scala
+++ b/core/js-native/src/main/scala/cats/effect/IOFiberConstants.scala
@@ -46,7 +46,7 @@ private object IOFiberConstants {
final val AutoCedeR = 7
final val DoneR = 8
- final val ioLocalPropagation = false
+ final val TrackFiberContext = false
@nowarn212
@inline def isVirtualThread(t: Thread): Boolean = false
diff --git a/core/jvm/src/main/java/cats/effect/IOFiberConstants.java b/core/jvm/src/main/java/cats/effect/IOFiberConstants.java
index 7cb6585b3d..1286844633 100644
--- a/core/jvm/src/main/java/cats/effect/IOFiberConstants.java
+++ b/core/jvm/src/main/java/cats/effect/IOFiberConstants.java
@@ -48,7 +48,7 @@ final class IOFiberConstants {
static final byte AutoCedeR = 7;
static final byte DoneR = 8;
- static final boolean ioLocalPropagation = Boolean.getBoolean("cats.effect.ioLocalPropagation");
+ static final boolean TrackFiberContext = Boolean.getBoolean("cats.effect.trackFiberContext");
static boolean isVirtualThread(final Thread thread) {
try {
diff --git a/core/jvm/src/main/scala/cats/effect/IOLocalPlatform.scala b/core/jvm/src/main/scala/cats/effect/IOLocalPlatform.scala
index 4a66d31b23..17e89e8e22 100644
--- a/core/jvm/src/main/scala/cats/effect/IOLocalPlatform.scala
+++ b/core/jvm/src/main/scala/cats/effect/IOLocalPlatform.scala
@@ -16,17 +16,17 @@
package cats.effect
-import IOFiberConstants.ioLocalPropagation
+import IOFiberConstants.TrackFiberContext
private[effect] trait IOLocalPlatform[A] { self: IOLocal[A] =>
/**
* Returns a [[java.lang.ThreadLocal]] view of this [[IOLocal]] that allows to unsafely get,
* set, and remove (aka reset) the value in the currently running fiber. The system property
- * `cats.effect.ioLocalPropagation` must be `true`, otherwise throws an
+ * `cats.effect.trackFiberContext` must be `true`, otherwise throws an
* [[java.lang.UnsupportedOperationException]].
*/
- def unsafeThreadLocal(): ThreadLocal[A] = if (ioLocalPropagation)
+ def unsafeThreadLocal(): ThreadLocal[A] = if (TrackFiberContext)
new ThreadLocal[A] {
override def get(): A = {
val fiber = IOFiber.currentIOFiber()
@@ -51,7 +51,7 @@ private[effect] trait IOLocalPlatform[A] { self: IOLocal[A] =>
else
throw new UnsupportedOperationException(
"IOLocal-ThreadLocal propagation is disabled.\n" +
- "Enable by setting cats.effect.ioLocalPropagation=true."
+ "Enable by setting cats.effect.trackFiberContext=true."
)
}
diff --git a/core/jvm/src/main/scala/cats/effect/IOPlatform.scala b/core/jvm/src/main/scala/cats/effect/IOPlatform.scala
index c53654eafc..7dd0115d38 100644
--- a/core/jvm/src/main/scala/cats/effect/IOPlatform.scala
+++ b/core/jvm/src/main/scala/cats/effect/IOPlatform.scala
@@ -83,7 +83,7 @@ abstract private[effect] class IOPlatform[+A] extends Serializable { self: IO[A]
case _: InterruptedException =>
None
} finally {
- if (IOFiberConstants.ioLocalPropagation)
+ if (IOFiberConstants.TrackFiberContext)
IOLocal.setThreadLocalState(fiber.getLocalState())
}
}
diff --git a/core/shared/src/main/scala/cats/effect/IO.scala b/core/shared/src/main/scala/cats/effect/IO.scala
index a4c597547c..0104cd7571 100644
--- a/core/shared/src/main/scala/cats/effect/IO.scala
+++ b/core/shared/src/main/scala/cats/effect/IO.scala
@@ -1123,7 +1123,7 @@ sealed abstract class IO[+A] private () extends IOPlatform[A] {
implicit runtime: unsafe.IORuntime): IOFiber[A @uncheckedVariance] = {
val fiber = new IOFiber[A](
- if (IOFiberConstants.ioLocalPropagation) IOLocal.getThreadLocalState()
+ if (IOFiberConstants.TrackFiberContext) IOLocal.getThreadLocalState()
else IOLocalState.empty,
{ oc =>
if (registerCallback) {
diff --git a/core/shared/src/main/scala/cats/effect/IOFiber.scala b/core/shared/src/main/scala/cats/effect/IOFiber.scala
index 8d095587fe..9e0357b734 100644
--- a/core/shared/src/main/scala/cats/effect/IOFiber.scala
+++ b/core/shared/src/main/scala/cats/effect/IOFiber.scala
@@ -115,7 +115,7 @@ private final class IOFiber[A](
// insert a read barrier after every async boundary
readBarrier()
- if (ioLocalPropagation) {
+ if (TrackFiberContext) {
IOFiber.setCurrentIOFiber(this)
}
@@ -131,7 +131,7 @@ private final class IOFiber[A](
case 8 => () // DoneR
}
- if (ioLocalPropagation) {
+ if (TrackFiberContext) {
IOFiber.setCurrentIOFiber(null)
}
}
diff --git a/core/shared/src/main/scala/cats/effect/IOLocal.scala b/core/shared/src/main/scala/cats/effect/IOLocal.scala
index e045cdd625..fe76093544 100644
--- a/core/shared/src/main/scala/cats/effect/IOLocal.scala
+++ b/core/shared/src/main/scala/cats/effect/IOLocal.scala
@@ -271,7 +271,7 @@ object IOLocal {
/**
* `true` if IOLocal-Threadlocal propagation is enabled
*/
- def isPropagating: Boolean = IOFiberConstants.ioLocalPropagation
+ def isPropagating: Boolean = IOFiberConstants.TrackFiberContext
private[effect] def getThreadLocalState() = {
val fiber = IOFiber.currentIOFiber()
diff --git a/core/shared/src/main/scala/cats/effect/unsafe/IORuntime.scala b/core/shared/src/main/scala/cats/effect/unsafe/IORuntime.scala
index 64d1f34c76..3b405504c6 100644
--- a/core/shared/src/main/scala/cats/effect/unsafe/IORuntime.scala
+++ b/core/shared/src/main/scala/cats/effect/unsafe/IORuntime.scala
@@ -116,6 +116,14 @@ object IORuntime extends IORuntimeCompanionPlatform {
def builder(): IORuntimeBuilder =
IORuntimeBuilder()
+ /**
+ * Returns `true` if invoked within an executing `IOFiber`. If the property
+ * `cats.effect.trackFiberContext=true` then this method is always accurate. Otherwise, it is
+ * best-effort and may return `false` even when you are executing within an `IOFiber`.
+ */
+ @static def isUnderFiberContext(): Boolean =
+ IOFiber.currentIOFiber() ne null
+
private[effect] def testRuntime(ec: ExecutionContext, scheduler: Scheduler): IORuntime = {
val config = IORuntimeConfig()
val metrics = IORuntimeMetrics(ec)
diff --git a/docs/core/io-local.md b/docs/core/io-local.md
index af3af30284..e735f62537 100644
--- a/docs/core/io-local.md
+++ b/docs/core/io-local.md
@@ -185,4 +185,4 @@ TraceIdScope.fromIOLocal.flatMap { implicit traceIdScope: TraceIdScope[IO] =>
To support integration with Java libraries, `IOLocal` interoperates with the JDK `ThreadLocal` API via `IOLocal#unsafeThreadLocal`. This makes it possible to unsafely read and write the value of an `IOLocal` on the currently running fiber within a suspended side-effect (e.g. `IO.delay` or `IO.blocking`).
-To use this feature you must set the property `cats.effect.ioLocalPropagation=true`. Note that enabling propagation causes a performance hit of up to 25% in some of our microbenchmarks. However, it is not clear that this performance impact matters in practice.
+To use this feature you must set the property `cats.effect.trackFiberContext=true`. Note that enabling propagation causes a performance hit of up to 25% in some of our microbenchmarks. However, it is not clear that this performance impact matters in practice.
diff --git a/docs/core/io-runtime-config.md b/docs/core/io-runtime-config.md
index 3810cab0c0..4a4c2163d1 100644
--- a/docs/core/io-runtime-config.md
+++ b/docs/core/io-runtime-config.md
@@ -37,4 +37,4 @@ This can be done for example with the [EnvironmentPlugin for Webpack](https://we
| `cats.effect.cpu.starvation.check.interval`
`CATS_EFFECT_CPU_STARVATION_CHECK_INTERVAL` | `FiniteDuration` (`1.second`) | The starvation checker repeatedly sleeps for this interval and then checks `monotonic` time when it awakens. It will then print a warning to stderr if it finds that the current time is greater than expected (see `threshold` below). |
| `cats.effect.cpu.starvation.check.initialDelay`
`CATS_EFFECT_CPU_STARVATION_CHECK_INITIAL_DELAY` | `Duration` (`10.seconds`) | The initial delay before the CPU starvation checker starts running. Avoids spurious warnings due to the JVM not being warmed up yet. Set to `Duration.Inf` to disable CPU starvation checking. |
| `cats.effect.cpu.starvation.check.threshold`
`CATS_EFFECT_CPU_STARVATION_CHECK_THRESHOLD` | `Double` (`0.1`) | The starvation checker will print a warning if it finds that it has been asleep for at least `interval * (1 + threshold)` (where `interval` from above is the expected time to be asleep for). Sleeping for too long is indicative of fibers hogging a worker thread either by performing blocking operations on it or by `cede`ing insufficiently frequently. |
-| `cats.effect.ioLocalPropagation`
N/A | `Boolean` (`false`) | Enables `IOLocal`s to be propagated as `ThreadLocal`s. |
+| `cats.effect.trackFiberContext`
N/A | `Boolean` (`false`) | Tracks the currently running fiber on each thread. Necessary for `IOLocal`s to be propagated as `ThreadLocal`s. |