Mark all Worker-related API as obsolete.

* Explain what obsolete means and why workers are obsolete
* Add some documentation to workers to explain its common pitfalls

^KT-54702


Merge-request: KT-MR-9563
Merged-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
This commit is contained in:
Vsevolod Tolstopyatov
2023-04-19 09:28:23 +00:00
committed by Space Team
parent ec4fab57a7
commit af9252aa96
59 changed files with 174 additions and 68 deletions
@@ -20,6 +20,7 @@ val z1 = Z(42)
val z2 = Z(x.s.length)
// FILE: main.kt
@file:OptIn(ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
fun foo() {
@@ -32,4 +33,4 @@ fun foo() {
fun main() {
foo()
println(z2.x)
}
}
@@ -12,6 +12,7 @@ class Z(val x: Int)
val z = Z(42)
// FILE: main.kt
@file:OptIn(ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
fun main() {
@@ -20,4 +21,4 @@ fun main() {
worker.execute(TransferMode.SAFE, { -> }, {
it -> println(z.x)
}).consume { }
}
}
@@ -1,4 +1,5 @@
import kotlin.native.concurrent.Worker
@file:OptIn(ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
object RuntimeState {
fun produceChange() {
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
import kotlin.test.*
@@ -1,3 +1,4 @@
@file:OptIn(ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
import kotlinx.cinterop.autoreleasepool
import objclib.*
@@ -1,4 +1,4 @@
@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class
import objclib.*
import kotlin.native.concurrent.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class, kotlin.native.runtime.NativeRuntimeApi::class)
@file:OptIn(FreezingIsDeprecated::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
@@ -16,4 +16,4 @@ fun nsArrayOf(vararg elements: Any): NSArray = NSMutableArray().apply {
elements.forEach {
this.addObject(it as ObjCObject)
}
}
}
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
import kotlinx.cinterop.*
@@ -1,4 +1,4 @@
@file:OptIn(kotlin.ExperimentalStdlibApi::class)
@file:OptIn(kotlin.ExperimentalStdlibApi::class, ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
import kotlin.test.*
@@ -2,7 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class, kotlin.native.runtime.NativeRuntimeApi::class)
@file:OptIn(ExperimentalStdlibApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
import kotlin.test.*
@@ -2,7 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class)
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
package runtime.basic.cleaner_workers
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
package runtime.basic.initializers6
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
package runtime.basic.worker_random
import kotlin.native.concurrent.*
@@ -39,4 +40,4 @@ fun testRandomWorkers() {
workers.forEach {
it.requestTermination().result
}
}
}
@@ -2,7 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class, kotlin.native.runtime.NativeRuntimeApi::class)
@file:OptIn(FreezingIsDeprecated::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
package runtime.concurrent.worker_bound_reference0
@@ -2,7 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.memory.stable_ref_cross_thread_check
@@ -3,7 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.atomic0
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
package runtime.workers.enum_identity
import kotlin.test.*
@@ -21,4 +22,4 @@ fun runTest() {
input.kind == A.B
}).result
println(result)
}
}
@@ -2,7 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.freeze0
@@ -30,4 +30,4 @@ data class SharedData(val string: String, val int: Int, val member: SharedDataMe
}
worker.requestTermination().result
println("OK")
}
}
@@ -2,7 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.freeze2
@@ -2,7 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.freeze3
@@ -3,7 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.lazy0
import kotlin.test.*
@@ -3,7 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.lazy4
import kotlin.test.*
@@ -1,3 +1,4 @@
@file:OptIn(ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
import kotlin.native.Platform
import kotlinx.cinterop.*
@@ -1,3 +1,4 @@
@file:OptIn(ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
import kotlin.native.Platform
import kotlinx.cinterop.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.mutableData1
import kotlin.native.concurrent.*
@@ -45,4 +45,4 @@ private fun assertContentsEquals(expected: ByteArray, actual: MutableData) {
expected.forEachIndexed { index, byte ->
assertEquals(byte, actual.get(index))
}
}
}
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
package runtime.workers.worker0
import kotlin.test.*
@@ -22,4 +23,4 @@ import kotlin.native.concurrent.*
}
worker.requestTermination().result
println("OK")
}
}
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
package runtime.workers.worker1
import kotlin.test.*
@@ -32,4 +33,4 @@ import kotlin.native.concurrent.*
it.requestTermination().result
}
println("OK")
}
}
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class)
@file:OptIn(FreezingIsDeprecated::class, kotlin.experimental.ExperimentalNativeApi::class, kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
package runtime.workers.worker10
import kotlin.test.*
@@ -3,7 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker11
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
package runtime.workers.worker2
import kotlin.test.*
@@ -42,4 +43,4 @@ data class WorkerResult(val intResult: Int, val stringResult: String)
it.requestTermination().result
}
println("OK")
}
}
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
package runtime.workers.worker3
import kotlin.test.*
@@ -33,4 +34,4 @@ fun main(args: Array<String>) {
if (dataParam.int != 17) println("Fail 2")
worker.requestTermination().result
println("OK")
}
}
@@ -3,7 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker4
import kotlin.test.*
@@ -2,7 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
import kotlin.test.*
@@ -50,4 +50,4 @@ fun main() {
runTest0()
runTest1()
runTest2()
}
}
@@ -3,7 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker6
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
package runtime.workers.worker7
import kotlin.test.*
@@ -25,4 +26,4 @@ import kotlin.native.concurrent.*
worker.requestTermination().result
println("OK")
}
}
@@ -2,7 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker8
@@ -30,4 +30,4 @@ data class SharedData(val string: String, val int: Int, val member: SharedDataMe
}
worker.requestTermination().result
println("OK")
}
}
@@ -3,7 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker9
import kotlin.test.*
@@ -3,7 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker9_experimentalMM
import kotlin.test.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker_exception_messages
import kotlin.test.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker_exceptions
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
package runtime.workers.worker_exceptions_legacy
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class)
@file:OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class, ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
@@ -1,4 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class)
@file:OptIn(FreezingIsDeprecated::class, ExperimentalStdlibApi::class, ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
@@ -1,4 +1,4 @@
@file:OptIn(kotlin.ExperimentalStdlibApi::class)
@file:OptIn(kotlin.ExperimentalStdlibApi::class, ObsoleteWorkersApi::class)
package runtime.workers.worker_list_workers
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(ObsoleteWorkersApi::class)
import kotlin.native.concurrent.*
import kotlin.native.Platform
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@@ -10,6 +10,7 @@ import kotlin.native.internal.Frozen
/**
* State of the future object.
*/
@ObsoleteWorkersApi
enum class FutureState(val value: Int) {
INVALID(0),
/** Future is scheduled for execution. */
@@ -26,6 +27,7 @@ enum class FutureState(val value: Int) {
* Class representing abstract computation, whose result may become available in the future.
*/
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
@ObsoleteWorkersApi
public value class Future<T> @PublishedApi internal constructor(val id: Int) {
/**
* Blocks execution until the future is ready.
@@ -70,6 +72,7 @@ public value class Future<T> @PublishedApi internal constructor(val id: Int) {
@Deprecated("Use 'waitForMultipleFutures' top-level function instead", ReplaceWith("waitForMultipleFutures(this, millis)"), DeprecationLevel.ERROR)
@ObsoleteWorkersApi
public fun <T> Collection<Future<T>>.waitForMultipleFutures(millis: Int): Set<Future<T>> = waitForMultipleFutures(this, millis)
@@ -79,6 +82,7 @@ public fun <T> Collection<Future<T>>.waitForMultipleFutures(millis: Int): Set<Fu
*
* @param timeoutMillis the amount of time in milliseconds to wait for the computed future
*/
@ObsoleteWorkersApi
public fun <T> waitForMultipleFutures(futures: Collection<Future<T>>, timeoutMillis: Int): Set<Future<T>> {
val result = mutableSetOf<Future<T>>()
@@ -101,4 +105,4 @@ public fun <T> waitForMultipleFutures(futures: Collection<Future<T>>, timeoutMil
}
return result
}
}
@@ -21,77 +21,98 @@ external internal fun Any?.isShareable(): Boolean
// Implementation details.
@GCUnsafeCall("Kotlin_Worker_stateOfFuture")
@ObsoleteWorkersApi
external internal fun stateOfFuture(id: Int): Int
@GCUnsafeCall("Kotlin_Worker_consumeFuture")
@PublishedApi
@ObsoleteWorkersApi
external internal fun consumeFuture(id: Int): Any?
@GCUnsafeCall("Kotlin_Worker_waitForAnyFuture")
@ObsoleteWorkersApi
external internal fun waitForAnyFuture(versionToken: Int, millis: Int): Boolean
@GCUnsafeCall("Kotlin_Worker_versionToken")
@ObsoleteWorkersApi
external internal fun versionToken(): Int
@kotlin.native.internal.ExportForCompiler
@ObsoleteWorkersApi
internal fun executeImpl(worker: Worker, mode: TransferMode, producer: () -> Any?,
job: CPointer<CFunction<*>>): Future<Any?> =
Future<Any?>(executeInternal(worker.id, mode.value, producer, job))
@GCUnsafeCall("Kotlin_Worker_startInternal")
@ObsoleteWorkersApi
external internal fun startInternal(errorReporting: Boolean, name: String?): Int
@GCUnsafeCall("Kotlin_Worker_currentInternal")
@ObsoleteWorkersApi
external internal fun currentInternal(): Int
@GCUnsafeCall("Kotlin_Worker_requestTerminationWorkerInternal")
@ObsoleteWorkersApi
external internal fun requestTerminationInternal(id: Int, processScheduledJobs: Boolean): Int
@GCUnsafeCall("Kotlin_Worker_executeInternal")
@ObsoleteWorkersApi
external internal fun executeInternal(
id: Int, mode: Int, producer: () -> Any?, job: CPointer<CFunction<*>>): Int
@GCUnsafeCall("Kotlin_Worker_executeAfterInternal")
@ObsoleteWorkersApi
external internal fun executeAfterInternal(id: Int, operation: () -> Unit, afterMicroseconds: Long): Unit
@GCUnsafeCall("Kotlin_Worker_processQueueInternal")
@ObsoleteWorkersApi
external internal fun processQueueInternal(id: Int): Boolean
@GCUnsafeCall("Kotlin_Worker_parkInternal")
@ObsoleteWorkersApi
external internal fun parkInternal(id: Int, timeoutMicroseconds: Long, process: Boolean): Boolean
@GCUnsafeCall("Kotlin_Worker_getNameInternal")
@ObsoleteWorkersApi
external internal fun getWorkerNameInternal(id: Int): String?
@ExportForCppRuntime
@ObsoleteWorkersApi
internal fun ThrowWorkerAlreadyTerminated(): Unit =
throw IllegalStateException("Worker is already terminated")
@ExportForCppRuntime
@ObsoleteWorkersApi
internal fun ThrowWrongWorkerOrAlreadyTerminated(): Unit =
throw IllegalStateException("Worker is not current or already terminated")
@ExportForCppRuntime
@ObsoleteWorkersApi
internal fun ThrowCannotTransferOwnership(): Unit =
throw IllegalStateException("Unable to transfer object: it is still owned elsewhere")
@ExportForCppRuntime
@ObsoleteWorkersApi
internal fun ThrowFutureInvalidState(): Unit =
throw IllegalStateException("Future is in an invalid state")
@ExportForCppRuntime
@ObsoleteWorkersApi
internal fun ThrowWorkerUnsupported(): Unit =
throw UnsupportedOperationException("Workers are not supported")
@ExportForCppRuntime
@ObsoleteWorkersApi
internal fun WorkerLaunchpad(function: () -> Any?) = function()
@PublishedApi
@GCUnsafeCall("Kotlin_Worker_detachObjectGraphInternal")
@ObsoleteWorkersApi
external internal fun detachObjectGraphInternal(mode: Int, producer: () -> Any?): NativePtr
@PublishedApi
@GCUnsafeCall("Kotlin_Worker_attachObjectGraphInternal")
@ObsoleteWorkersApi
external internal fun attachObjectGraphInternal(stable: NativePtr): Any?
@GCUnsafeCall("Kotlin_Worker_freezeInternal")
@@ -128,10 +149,13 @@ external internal fun checkIfFrozen(ref: Any?)
@InternalForKotlinNative
@GCUnsafeCall("Kotlin_Worker_waitTermination")
@ObsoleteWorkersApi
external public fun waitWorkerTermination(worker: Worker)
@GCUnsafeCall("Kotlin_Worker_getPlatformThreadIdInternal")
@ObsoleteWorkersApi
external internal fun getPlatfromThreadIdInternal(id: Int): ULong
@GCUnsafeCall("Kotlin_Worker_getActiveWorkersInternal")
@ObsoleteWorkersApi
external internal fun getActiveWorkersInternal(): IntArray
@@ -36,6 +36,7 @@ import kotlin.native.internal.Frozen
* @see [kotlin.native.runtime.GC.collect].
*/
// Not @FreezingIsDeprecated: every `Worker.execute` uses this.
@ObsoleteWorkersApi
public enum class TransferMode(val value: Int) {
/**
* Reachability check is performed.
@@ -54,6 +55,7 @@ public enum class TransferMode(val value: Int) {
*/
@Frozen
@FreezingIsDeprecated
@ObsoleteWorkersApi
public class DetachedObjectGraph<T> internal constructor(pointer: NativePtr) {
@PublishedApi
internal val stable = AtomicNativePtr(pointer)
@@ -84,6 +86,7 @@ public class DetachedObjectGraph<T> internal constructor(pointer: NativePtr) {
* happen once.
*/
@FreezingIsDeprecated
@ObsoleteWorkersApi
public inline fun <reified T> DetachedObjectGraph<T>.attach(): T {
var rawStable: NativePtr
do {
@@ -12,22 +12,28 @@ import kotlin.native.internal.IntrinsicType
import kotlin.native.internal.TypedIntrinsic
import kotlinx.cinterop.*
/**
* ## Workers: theory of operations.
*
* [Worker] represents asynchronous and concurrent computation, usually performed by other threads
* in the same process. Object passing between workers is performed using transfer operation, so that
* object graph belongs to one worker at the time, but can be disconnected and reconnected as needed.
* See 'Object Transfer Basics' and [TransferMode] for more details on how objects shall be transferred.
* This approach ensures that no concurrent access happens to same object, while data may flow between
* workers as needed.
*/
/**
* Class representing worker.
* Class representing a worker.
*
* [Worker] represents a thread of execution _and_ a queue of work sent to this worker.
* Once started, the worker processes its own queue until it is explicitly [terminated][requestTermination].
*
* Worker's API resembles both executor and threads API:
*
* - It is a resource that has to be [closed][requestTermination].
* - Failure to terminatae **and** join the termination request leads to native memory leak.
* - It cannot be terminated externally while processing the work queue, leading to a crash.
* - It can be [parked][park], but while parked, worker is allowed to process its own tasks' queue.
* - In order to unpark a worker, any task has to be submited to the worker.
* - The work can be sent to the worker both in forms of regular [runnables][execute] and [delayed (timed)][executeAfter] runnables.
* - There is no mechanism to cancel delayed runnables.
* - Attempts to invoke any method of worker being terminated lead to a runtime exception.
* - It includes such things as innocuous [Worker.current] from the **current** worker.
*/
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
@OptIn(FreezingIsDeprecated::class)
@ObsoleteWorkersApi
public value class Worker @PublishedApi internal constructor(val id: Int) {
companion object {
/**
@@ -75,6 +81,9 @@ public value class Worker @PublishedApi internal constructor(val id: Int) {
/**
* Requests termination of the worker.
*
* Returns [Future] that **must** be joined with [Future.result] blocking call.
* Failure to do so will leak native memory and underlying native thread handles.
*
* @param processScheduledJobs controls is we shall wait until all scheduled jobs processed,
* or terminate immediately. If there are jobs to be execucted with [executeAfter] their execution
* is awaited for.
@@ -213,6 +222,7 @@ public value class Worker @PublishedApi internal constructor(val id: Int) {
* @param block to be executed.
* @return value returned by the block.
*/
@ObsoleteWorkersApi
public inline fun <R> withWorker(name: String? = null, errorReporting: Boolean = true, block: Worker.() -> R): R {
val worker = Worker.start(errorReporting, name)
try {
@@ -8,12 +8,15 @@ package kotlin.native.concurrent
import kotlin.native.internal.*
@GCUnsafeCall("Kotlin_WorkerBoundReference_create")
@ObsoleteWorkersApi
external private fun createWorkerBoundReference(value: Any): NativePtr
@GCUnsafeCall("Kotlin_WorkerBoundReference_deref")
@ObsoleteWorkersApi
external private fun derefWorkerBoundReference(ref: NativePtr): Any?
@GCUnsafeCall("Kotlin_WorkerBoundReference_describe")
@ObsoleteWorkersApi
external private fun describeWorkerBoundReference(ref: NativePtr): String
/**
@@ -31,6 +34,7 @@ external private fun describeWorkerBoundReference(ref: NativePtr): String
@HasFinalizer
@HasFreezeHook
@FreezingIsDeprecated
@ObsoleteWorkersApi
public class WorkerBoundReference<out T : Any>(value: T) {
private var ptr = NativePtr.NULL
@@ -76,7 +76,7 @@ public interface Cleaner
@Suppress("DEPRECATION")
@ExperimentalStdlibApi
@ExportForCompiler
@OptIn(ExperimentalNativeApi::class)
@OptIn(ExperimentalNativeApi::class, ObsoleteWorkersApi::class)
fun <T> createCleaner(argument: T, block: (T) -> Unit): Cleaner =
kotlin.native.ref.createCleanerImpl(argument, block) as Cleaner
@@ -84,7 +84,7 @@ fun <T> createCleaner(argument: T, block: (T) -> Unit): Cleaner =
* Perform GC on a worker that executes Cleaner blocks.
*/
@InternalForKotlinNative
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class, ObsoleteWorkersApi::class)
fun performGCOnCleanerWorker() =
getCleanerWorker().execute(TransferMode.SAFE, {}) {
GC.collect()
@@ -94,20 +94,24 @@ fun performGCOnCleanerWorker() =
* Wait for a worker that executes Cleaner blocks to complete its scheduled tasks.
*/
@InternalForKotlinNative
@OptIn(ObsoleteWorkersApi::class)
fun waitCleanerWorker() =
getCleanerWorker().execute(TransferMode.SAFE, {}) {
Unit
}.result
@GCUnsafeCall("Kotlin_CleanerImpl_getCleanerWorker")
@OptIn(ObsoleteWorkersApi::class)
external internal fun getCleanerWorker(): Worker
@ExportForCppRuntime("Kotlin_CleanerImpl_shutdownCleanerWorker")
@OptIn(ObsoleteWorkersApi::class)
private fun shutdownCleanerWorker(worker: Worker, executeScheduledCleaners: Boolean) {
worker.requestTermination(executeScheduledCleaners).result
}
@ExportForCppRuntime("Kotlin_CleanerImpl_createCleanerWorker")
@OptIn(ObsoleteWorkersApi::class)
private fun createCleanerWorker(): Worker {
return Worker.start(errorReporting = false, name = "Cleaner worker")
}
@@ -43,6 +43,7 @@ fun main(args: Array<String>) {
@OptIn(FreezingIsDeprecated::class)
@ExperimentalNativeApi
@ObsoleteWorkersApi
fun worker(args: Array<String>) {
val worker = Worker.start()
val exitCode = worker.execute(TransferMode.SAFE, { args.freeze() }) {
@@ -6,8 +6,7 @@
package kotlin.native.ref
import kotlin.experimental.ExperimentalNativeApi
import kotlin.native.concurrent.isShareable
import kotlin.native.concurrent.freeze
import kotlin.native.concurrent.*
import kotlin.native.internal.*
import kotlinx.cinterop.NativePtr
@@ -91,7 +90,7 @@ public fun <T> createCleaner(resource: T, cleanupAction: (resource: T) -> Unit):
createCleanerImpl(resource, cleanupAction)
@ExperimentalNativeApi
@OptIn(FreezingIsDeprecated::class)
@OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
internal fun <T> createCleanerImpl(resource: T, cleanupAction: (T) -> Unit): Cleaner {
if (!resource.isShareable())
throw IllegalArgumentException("$resource must be shareable")
@@ -121,4 +120,5 @@ private class CleanerImpl(
@GCUnsafeCall("CreateStablePointer")
external private fun createStablePointer(obj: Any): NativePtr
external private fun createStablePointer(obj: Any): NativePtr
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.native.concurrent
/**
* Marks all `Worker`-related API as obsolete.
*
* Workers are considered **obsolete**: their API shape, design, and behaviour
* have known flaws and pitfalls that are impossible to address in Worker's current form.
*
* Workers continue being supported and maintained, but they eventually will
* be replaced with threads API and then deprecated.
*
* It is not recommended to expose workers in public API or to have high coupling with Workers API,
* and instead, we suggest encapsulating them in a domain-specific API to simplify
* future migration and reduce potential exposure to dangerous API.
*/
@SinceKotlin("1.9")
@RequiresOptIn(
message = "Workers API is obsolete and will be replaced with threads eventually",
level = RequiresOptIn.Level.WARNING
)
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.PROPERTY,
AnnotationTarget.FIELD,
AnnotationTarget.LOCAL_VARIABLE,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.TYPEALIAS,
)
@Retention(AnnotationRetention.BINARY)
public annotation class ObsoleteWorkersApi
@@ -130,3 +130,4 @@ public expect annotation class RefinesInSwift()
@ExperimentalObjCRefinement
@SinceKotlin("1.8")
public expect annotation class ShouldRefineInSwift()