Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- ubuntu-latest
- ubuntu-22.04-arm
- windows-2022
- macos-14
- macos-15
scala: [3.3.4, 2.12.20, 2.13.18]
java:
- temurin@8
Expand Down Expand Up @@ -64,18 +64,18 @@ jobs:
- os: windows-2022
scala: 3.3.4
ci: ciJVM
- os: macos-14
- os: macos-15
scala: 3.3.4
ci: ciJVM
- os: windows-2022
scala: 2.12.20
ci: ciJVM
- os: macos-14
- os: macos-15
scala: 2.12.20
ci: ciJVM
- os: macos-14
- os: macos-15
java: temurin@8
- os: macos-14
- os: macos-15
java: temurin@11
- ci: ciFirefox
scala: 3.3.4
Expand All @@ -97,7 +97,7 @@ jobs:
ci: ciJS
- os: windows-2022
ci: ciJS
- os: macos-14
- os: macos-15
ci: ciJS
- ci: ciFirefox
java: temurin@11
Expand All @@ -111,7 +111,7 @@ jobs:
ci: ciFirefox
- os: windows-2022
ci: ciFirefox
- os: macos-14
- os: macos-15
ci: ciFirefox
- ci: ciChrome
java: temurin@11
Expand All @@ -125,7 +125,7 @@ jobs:
ci: ciChrome
- os: windows-2022
ci: ciChrome
- os: macos-14
- os: macos-15
ci: ciChrome
- ci: ciNative
java: temurin@11
Expand All @@ -138,7 +138,7 @@ jobs:
os: windows-2022
- ci: ciNative
java: temurin@11
os: macos-14
os: macos-15
- ci: ciNative
java: temurin@17
os: ubuntu-latest
Expand All @@ -156,7 +156,7 @@ jobs:
os: windows-2022
- ci: ciNative
java: temurin@21
os: macos-14
os: macos-15
- ci: ciNative
java: graalvm@21
os: ubuntu-latest
Expand All @@ -168,13 +168,13 @@ jobs:
os: windows-2022
- ci: ciNative
java: graalvm@21
os: macos-14
os: macos-15
- os: ubuntu-22.04-arm
ci: ciNative
scala: 2.12.20
- os: windows-2022
ci: ciNative
- os: macos-14
- os: macos-15
ci: ciNative
scala: 2.12.20
runs-on: ${{ matrix.os }}
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ ThisBuild / developers := List(
val PrimaryOS = "ubuntu-latest"
val ArmOS = "ubuntu-22.04-arm"
val Windows = "windows-2022"
val MacOS = "macos-14"
val MacOS = "macos-15"

val Scala212 = "2.12.20"
val Scala213 = "2.13.18"
Expand Down
18 changes: 11 additions & 7 deletions core/shared/src/main/scala/cats/effect/IOFiber.scala
Original file line number Diff line number Diff line change
Expand Up @@ -785,20 +785,24 @@ private final class IOFiber[A](
finalizers.push(fin)
conts = ByteStack.push(conts, OnCancelK)

/*
* We set the finalizing check to the *suspension* point, which may
* be in a different finalizer scope than the cont itself. This must be
* written before publishing "waiting", or a racing `cb` could see a
* stale value from an earlier `get` and drop the wakeup.
* `wasFinalizing` is published by a volatile store on `suspended`, below.
*/
if (state.get() eq null) {
state.wasFinalizing = finalizing
}

if (state.compareAndSet(null, state.waiting)) {
/*
* `state` was "initial" (null), so `get` has arrived before the callback,
* it needs to set the state to "waiting" and suspend: `cb` will
* resume with the result once that's ready
*/

/*
* we set the finalizing check to the *suspension* point, which may
* be in a different finalizer scope than the cont itself.
* `wasFinalizing` is published by a volatile store on `suspended`.
*/
state.wasFinalizing = finalizing

if (isStackTracing) {
state.handle = monitor()
finalizers.push(IO {
Expand Down
20 changes: 20 additions & 0 deletions tests/shared/src/test/scala/cats/effect/IOSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,26 @@ class IOSuite extends BaseScalaCheckSuite with DisciplineSuite with IOPlatformSu
} yield result
}

// a second `get` in a finalizer must not miss a callback that races with cancelation
real("cont - second get in onCancel finalizer does not hang") {
val cont = IO.cont[Unit, Unit](new Cont[IO, Unit, Unit] {
def apply[G[_]](implicit G: MonadCancel[G, Throwable]) = { (resume, get, lift) =>
G.uncancelable { poll =>
lift(IO.cede.productR(IO(resume(Right(())))).start) *>
poll(get).onCancel(get)
}
}
})

val one = for {
fiber <- cont.start
_ <- IO.cede
_ <- fiber.cancel
} yield ()

one.parReplicateA_(if (!isJS) 8 else 1).replicateA_(50000)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does take a significant number of tries to fail locally.

}

ticked("async - allow for misordered nesting") { implicit ticker =>
var outerR = 0
var innerR = 0
Expand Down
Loading