suspendCoroutine

Suspend without resume

Example of suspendCoroutine without resume.

Explanation

In this example we will not get to the After never called since we have suspended the co-routine without ever resuming it.

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import kotlin.coroutines.suspendCoroutine

val out = Out.standard()

suspend fun main() {
  out.info("Before-1")

  suspendCoroutine<Unit> { continuation ->
    // This lambda function is called right before the suspension
    // takes place.
    out.infoNonSuspend(continuation.toString())

    out.infoNonSuspend("Before-2")
  }

  out.info("After never called")
}

Command to reproduce:

gt.sandbox.checkout.commit 7a97d782ce5c34e307b0 \
&& cd "${GT_SANDBOX_REPO}"

Output:

[elapsed:   19ms][tname:main/tid:1][coroutine:unnamed] Before-1
[elapsed:   41ms][tname:main/tid:1] SafeContinuation for Continuation at com.glassthought.sandbox.MainKt.main(Main.kt:11)
[elapsed:   42ms][tname:main/tid:1] Before-2

Resume

Immediately resume

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

val out = Out.standard()

suspend fun main() {
  out.info("Before-1")

  suspendCoroutine<String>{ continuation ->
    // This lambda function is called right before the suspension
    // takes place.
    out.infoNonSuspend(continuation.toString())

    out.infoNonSuspend("Before-2")

    // Question: where can we catch the result that we resumed with?
    continuation.resume("Hello from suspended coroutine")
  }

  out.info("After called because we resumed")
}

Command to reproduce:

gt.sandbox.checkout.commit f9282b62d211089b4a16 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

[elapsed:   23ms][tname:main/tid:1][coroutine:unnamed] Before-1
[elapsed:   46ms][tname:main/tid:1] SafeContinuation for Continuation at com.glassthought.sandbox.MainKt.main(Main.kt:12)
[elapsed:   47ms][tname:main/tid:1] Before-2
[elapsed:   47ms][tname:main/tid:1][coroutine:unnamed] After called because we resumed
Resume on a thread after thread sleep

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import kotlin.concurrent.thread
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

val out = Out.standard()

suspend fun main() {
  out.info("Before-1")

  suspendCoroutine<String> { continuation ->
    // This lambda function is called right before the suspension
    // takes place.
    out.infoNonSuspend(continuation.toString())
    out.infoNonSuspend("Before-2a")
    thread {
      Thread.sleep(500)

      out.infoNonSuspend("Before-2b")

      // Question: where can we catch the result that we resumed with?
      continuation.resume("Hello from suspended coroutine")
    }
  }

  out.info("After called because we resumed")
}

Command to reproduce:

gt.sandbox.checkout.commit 155537f9e5c8d89bd00e \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

[elapsed:   23ms][tname:main/tid:1][coroutine:unnamed] Before-1
[elapsed:   46ms][tname:main/tid:1] SafeContinuation for Continuation at com.glassthought.sandbox.MainKt.main(Main.kt:13)
[elapsed:   47ms][tname:main/tid:1] Before-2a
[elapsed:  553ms][tname:Thread-0/tid:20] Before-2b
[elapsed:  554ms][tname:Thread-0/tid:20][coroutine:unnamed] After called because we resumed
Resume called from a scheduler executor

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

val out = Out.standard()

private val executor = Executors.newSingleThreadScheduledExecutor {
  Thread(it, "my-scheduler").apply { isDaemon = true }
}


suspend fun main() {
  out.info("Before-1")

  suspendCoroutine<Unit> { continuation ->
    // This lambda function is called right before the suspension
    // takes place.
    out.infoNonSuspend(continuation.toString())
    out.infoNonSuspend("Before-2a")

    executor.schedule({
      out.infoNonSuspend("Resuming")

      continuation.resume(Unit)
    }, 1000, TimeUnit.MILLISECONDS)
  }

  out.info("After called because we resumed")
}

Command to reproduce:

gt.sandbox.checkout.commit fea7d94468e209cd1678 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

[elapsed:   29ms][tname:main/tid:1][coroutine:unnamed] Before-1
[elapsed:   51ms][tname:main/tid:1] SafeContinuation for Continuation at com.glassthought.sandbox.MainKt.main(Main.kt:19)
[elapsed:   52ms][tname:main/tid:1] Before-2a
[elapsed: 1057ms][tname:my-scheduler/tid:20] Resuming
[elapsed: 1058ms][tname:my-scheduler/tid:20][coroutine:unnamed] After called because we resumed
Capturing resumed value

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import kotlin.concurrent.thread
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

val out = Out.standard()

suspend fun main() {
  out.info("Before-1")

  val valueFromCoRoutine = suspendCoroutine { continuation ->
    out.infoNonSuspend("Before-2a")

    thread{
      Thread.sleep(500)

      out.infoNonSuspend("resuming...")
      continuation.resume("resumed-value")

    }
  }

  out.info("After called. Value from co-routine: $valueFromCoRoutine")
}

Command to reproduce:

gt.sandbox.checkout.commit 7d5c25d85bef0efdbd87 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

[elapsed:   24ms][tname:main/tid:1][coroutine:unnamed] Before-1
[elapsed:   38ms][tname:main/tid:1] Before-2a
[elapsed:  542ms][tname:Thread-0/tid:20] resuming...
[elapsed:  545ms][tname:Thread-0/tid:20][coroutine:unnamed] After called. Value from co-routine: resumed-value
Resume with exception

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

val out = Out.standard()

class MyException(msg: String) : Throwable(msg)

suspend fun main() {
  try {
    suspendCoroutine<Unit> { cont ->
      out.infoNonSuspend("About to resumeWithException")
      cont.resumeWithException(MyException("msg-from-resumeWithException"))
    }
  } catch (e: MyException) {
    out.info("Caught! exc-msg: " + e.message)
  }
}

Command to reproduce:

gt.sandbox.checkout.commit 32ecde1f5442756e833d \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

[elapsed:   24ms][tname:main/tid:1] About to resumeWithException
[elapsed:   38ms][tname:main/tid:1][coroutine:unnamed] Caught! exc-msg: msg-from-resumeWithException

Children
  1. works-at-coroutine-leve