-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce CoroutineStackFrame and implement it in SuspendFunctionGun …
…reusable completion in order to properly walk through stackframes of interceptors
- Loading branch information
Showing
6 changed files
with
113 additions
and
1 deletion.
There are no files selected for viewing
10 changes: 10 additions & 0 deletions
10
ktor-utils/ktor-utils-ios/src/io/ktor/util/StackFramesIos.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package io.ktor.util | ||
|
||
@Suppress("UNUSED") | ||
internal actual interface CoroutineStackFrame { | ||
public actual val callerFrame: CoroutineStackFrame? | ||
public actual fun getStackTraceElement(): StackTraceElement? | ||
} | ||
|
||
@Suppress("ACTUAL_WITHOUT_EXPECT") | ||
actual typealias StackTraceElement = Any |
10 changes: 10 additions & 0 deletions
10
ktor-utils/ktor-utils-js/src/io/ktor/util/StackFramesJs.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package io.ktor.util | ||
|
||
@Suppress("UNUSED") | ||
internal actual interface CoroutineStackFrame { | ||
public actual val callerFrame: CoroutineStackFrame? | ||
public actual fun getStackTraceElement(): StackTraceElement? | ||
} | ||
|
||
@Suppress("ACTUAL_WITHOUT_EXPECT") | ||
actual typealias StackTraceElement = Any |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package io.ktor.util | ||
|
||
@Suppress("ACTUAL_WITHOUT_EXPECT") | ||
actual typealias CoroutineStackFrame = kotlin.coroutines.jvm.internal.CoroutineStackFrame | ||
|
||
@Suppress("ACTUAL_WITHOUT_EXPECT") | ||
actual typealias StackTraceElement = java.lang.StackTraceElement |
69 changes: 69 additions & 0 deletions
69
ktor-utils/ktor-utils-jvm/test/io/ktor/tests/utils/PipelineStackFramesTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package io.ktor.tests.utils | ||
|
||
import io.ktor.util.* | ||
import io.ktor.util.pipeline.* | ||
import kotlinx.coroutines.* | ||
import org.junit.Test | ||
import kotlin.coroutines.* | ||
import kotlin.coroutines.intrinsics.* | ||
import kotlin.test.* | ||
|
||
class PipelineStackFramesTest { | ||
private val phase = PipelinePhase("StubPhase") | ||
private lateinit var interceptorContinuation: Continuation<Unit> | ||
|
||
@Test | ||
fun testStackTraceWalking() { | ||
val pipeline = Pipeline<Unit, Unit>(phase) | ||
pipeline.intercept(phase) { | ||
captureContinuation() | ||
} | ||
|
||
runBlocking { | ||
runPipeline(pipeline) | ||
} | ||
|
||
val frame = interceptorContinuation as CoroutineStackFrame | ||
val stacktrace = buildString { | ||
var currentTop: CoroutineStackFrame? = frame | ||
while (currentTop != null) { | ||
val element = currentTop.getStackTraceElement() | ||
if (element != null) { | ||
append(element) | ||
append('\n') | ||
} | ||
currentTop = currentTop.callerFrame | ||
} | ||
} | ||
|
||
val filtered = stacktrace | ||
.replace(Regex(":[0-9]+"), "") // line numbers | ||
.replace(Regex("\n.*invokeSuspend.*\n"), "\n") // lambdas | ||
assertEquals(filtered, | ||
"io/ktor/tests/utils/PipelineStackFramesTest.nestedCapture(PipelineStackFramesTest.kt)\n" + | ||
"io/ktor/tests/utils/PipelineStackFramesTest.captureContinuation(PipelineStackFramesTest.kt)\n" + | ||
"io/ktor/tests/utils/PipelineStackFramesTest.runPipeline(PipelineStackFramesTest.kt)\n" | ||
) | ||
} | ||
|
||
private suspend fun runPipeline(pipeline: Pipeline<Unit, Unit>) { | ||
pipeline.execute(Unit, Unit) | ||
preventTailCall() | ||
} | ||
|
||
private suspend fun captureContinuation() { | ||
nestedCapture() | ||
preventTailCall() | ||
} | ||
|
||
private suspend fun nestedCapture() { | ||
suspendCoroutineUninterceptedOrReturn<Unit> { | ||
interceptorContinuation = it | ||
Unit | ||
} | ||
preventTailCall() | ||
} | ||
|
||
private fun preventTailCall() { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package io.ktor.util | ||
|
||
internal expect class StackTraceElement | ||
|
||
internal expect interface CoroutineStackFrame { | ||
public val callerFrame: CoroutineStackFrame? | ||
public fun getStackTraceElement(): StackTraceElement? | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters