Skip to content

Commit

Permalink
feat!: don't use coroutines in common sources, make them optional for…
Browse files Browse the repository at this point in the history
… JVM targets

- fix KT-69529 by avoiding coroutines in WASM target (JS included by convenience)
- `stately-concurrent-collections` now used for native targets

Signed-off-by: Art Shendrik <[email protected]>
  • Loading branch information
amal committed Jun 29, 2024
1 parent 53a43db commit 19985c5
Show file tree
Hide file tree
Showing 22 changed files with 81 additions and 56 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ jobs:
# Prefix the list with "+" to use these queries, and those in the config file.
#
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended, security-and-quality
# queries: security-extended, security-and-quality.

- name: 'Build and check'
timeout-minutes: 18
Expand Down
4 changes: 3 additions & 1 deletion .run/check.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="--stacktrace --continue" />
<option name="scriptParameters" value="--continue --stacktrace" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="build" />
<option value="assemble" />
<option value="check" />
</list>
</option>
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ Different platform-specific implementations are provided.
| [() -> ReadableByteChannel] Factory | JVM, Android | JVM, Android |
| [AsynchronousFileChannel] | JVM, Android | JVM, Android |


> [!IMPORTANT]
> For using [AsynchronousFileChannel], you need to add Kotlin Coroutines dependency to your project.
[RandomAccessData]: fluxo-io-rad/src/commonMain/kotlin/fluxo/io/rad/RandomAccessData.common.kt#L29

[ByteArray]: fluxo-io-rad/src/commonMain/kotlin/fluxo/io/rad/RadByteArrayAccessor.kt#L21
Expand Down
3 changes: 2 additions & 1 deletion fluxo-io-rad/api/android/fluxo-io-rad.api
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ public final class fluxo/io/FluxoIoLogger {

public abstract class fluxo/io/SharedCloseable : java/io/Closeable {
public fun <init> ()V
public final fun addOnSharedCloseListener (Lkotlin/jvm/functions/Function1;)V
public final fun close ()V
public final fun isOpen ()Z
protected abstract fun onSharedClose ()V
public final fun onSharedClose (Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/DisposableHandle;
public final fun removeOnSharedCloseListener (Lkotlin/jvm/functions/Function1;)V
public final fun retain ()V
}

Expand Down
3 changes: 2 additions & 1 deletion fluxo-io-rad/api/fluxo-io-rad.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ abstract class fluxo.io/SharedCloseable : kotlin/AutoCloseable { // fluxo.io/Sha
final fun <get-isOpen>(): kotlin/Boolean // fluxo.io/SharedCloseable.isOpen.<get-isOpen>|<get-isOpen>(){}[0]

abstract fun onSharedClose() // fluxo.io/SharedCloseable.onSharedClose|onSharedClose(){}[0]
final fun addOnSharedCloseListener(kotlin/Function1<kotlin/Throwable?, kotlin/Unit>) // fluxo.io/SharedCloseable.addOnSharedCloseListener|addOnSharedCloseListener(kotlin.Function1<kotlin.Throwable?,kotlin.Unit>){}[0]
final fun close() // fluxo.io/SharedCloseable.close|close(){}[0]
final fun onSharedClose(kotlin/Function1<kotlin/Throwable?, kotlin/Unit>): kotlinx.coroutines/DisposableHandle // fluxo.io/SharedCloseable.onSharedClose|onSharedClose(kotlin.Function1<kotlin.Throwable?,kotlin.Unit>){}[0]
final fun removeOnSharedCloseListener(kotlin/Function1<kotlin/Throwable?, kotlin/Unit>) // fluxo.io/SharedCloseable.removeOnSharedCloseListener|removeOnSharedCloseListener(kotlin.Function1<kotlin.Throwable?,kotlin.Unit>){}[0]
final fun retain() // fluxo.io/SharedCloseable.retain|retain(){}[0]
}

Expand Down
3 changes: 2 additions & 1 deletion fluxo-io-rad/api/jvm/fluxo-io-rad.api
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ public final class fluxo/io/FluxoIoLogger {

public abstract class fluxo/io/SharedCloseable : java/io/Closeable {
public fun <init> ()V
public final fun addOnSharedCloseListener (Lkotlin/jvm/functions/Function1;)V
public final fun close ()V
public final fun isOpen ()Z
protected abstract fun onSharedClose ()V
public final fun onSharedClose (Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/DisposableHandle;
public final fun removeOnSharedCloseListener (Lkotlin/jvm/functions/Function1;)V
public final fun retain ()V
}

Expand Down
12 changes: 5 additions & 7 deletions fluxo-io-rad/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,24 @@ fkcSetupMultiplatform(
},
) {
common.main.dependencies {
implementation(libs.coroutines)
// implementation(libs.kotlinx.io.core)
}

val commonJvm = commonJvm
commonJvm.main.dependencies {
compileOnly(rootProject.extra["androidJar"]!!)
compileOnly(libs.androidx.annotation)
compileOnly(libs.jetbrains.annotation)
compileOnly(libs.coroutines)
}

val commonJs = commonJs
commonJs.main.dependencies {
api(libs.kotlinx.atomicfu)
// Fix JS build KLIB issue
implementation(libs.kotlinx.atomicfu)
}

arrayOf(commonJvm, commonApple, commonJs, commonLinux, commonMingw).forEach {
it.main.dependencies {
// implementation(libs.okio)
}
commonNative.main.dependencies {
implementation(libs.stately.concurrent.collections)
}
}

Expand Down
4 changes: 0 additions & 4 deletions fluxo-io-rad/dependencies/androidDebugRuntimeClasspath.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
org.jetbrains:annotations:23.0.0
4 changes: 0 additions & 4 deletions fluxo-io-rad/dependencies/androidReleaseRuntimeClasspath.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
org.jetbrains:annotations:23.0.0
4 changes: 0 additions & 4 deletions fluxo-io-rad/dependencies/debugRuntimeClasspath.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
org.jetbrains:annotations:24.1.0
2 changes: 0 additions & 2 deletions fluxo-io-rad/dependencies/jsCompileClasspath.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlin:kotlinx-atomicfu-runtime:2.0.20-Beta1
org.jetbrains.kotlinx:atomicfu-js:0.25.0
org.jetbrains.kotlinx:atomicfu:0.25.0
org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
2 changes: 0 additions & 2 deletions fluxo-io-rad/dependencies/jsRuntimeClasspath.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlin:kotlinx-atomicfu-runtime:2.0.20-Beta1
org.jetbrains.kotlinx:atomicfu-js:0.25.0
org.jetbrains.kotlinx:atomicfu:0.25.0
org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
4 changes: 0 additions & 4 deletions fluxo-io-rad/dependencies/jvmRuntimeClasspath.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
org.jetbrains:annotations:23.0.0
4 changes: 0 additions & 4 deletions fluxo-io-rad/dependencies/releaseRuntimeClasspath.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
org.jetbrains:annotations:24.1.0
2 changes: 0 additions & 2 deletions fluxo-io-rad/dependencies/wasmJsCompileClasspath.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@ org.jetbrains.kotlin:kotlin-stdlib-wasm-js:2.0.20-Beta1
org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlinx:atomicfu-wasm-js:0.25.0
org.jetbrains.kotlinx:atomicfu:0.25.0
org.jetbrains.kotlinx:kotlinx-coroutines-core-wasm-js:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
2 changes: 0 additions & 2 deletions fluxo-io-rad/dependencies/wasmJsRuntimeClasspath.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@ org.jetbrains.kotlin:kotlin-stdlib-wasm-js:2.0.20-Beta1
org.jetbrains.kotlin:kotlin-stdlib:2.0.20-Beta1
org.jetbrains.kotlinx:atomicfu-wasm-js:0.25.0
org.jetbrains.kotlinx:atomicfu:0.25.0
org.jetbrains.kotlinx:kotlinx-coroutines-core-wasm-js:1.9.0-RC
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@file:Suppress("FunctionName")

package fluxo.io.util

// WASM and JS are single-threaded, we can use a regular HashMap.
internal actual fun <K, V> ConcurrentHashMap(): MutableMap<K, V> = HashMap()
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@file:Suppress("FunctionName")

package fluxo.io.util

internal actual fun <K, V> ConcurrentHashMap(): MutableMap<K, V> =
java.util.concurrent.ConcurrentHashMap()
53 changes: 37 additions & 16 deletions fluxo-io-rad/src/commonMain/kotlin/fluxo/io/SharedCloseable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
package fluxo.io

import fluxo.io.internal.ThreadSafe
import fluxo.io.util.ConcurrentHashMap
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.CompletableJob
import kotlinx.coroutines.CompletionHandler
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.Job

/**
* A [SharedCloseable] is a resource that can be shared between multiple consumers.
Expand All @@ -23,19 +20,45 @@ public abstract class SharedCloseable : Closeable {
public val isOpen: Boolean
get() = retainsCount.value > 0

// Job is used to handle shared close listeners.
private val job: CompletableJob = Job()

private val sharedCloseListeners = ConcurrentHashMap<(cause: Throwable?) -> Unit, Boolean>()

public fun addOnSharedCloseListener(cb: (cause: Throwable?) -> Unit) {
sharedCloseListeners[cb] = true
}

public fun removeOnSharedCloseListener(cb: (cause: Throwable?) -> Unit) {
sharedCloseListeners.remove(cb)
}


public final override fun close() {
if (retainsCount.decrementAndGet() == 0) {
@Suppress("TooGenericExceptionCaught")
try {
onSharedClose()
job.complete()
} catch (e: Throwable) {
job.completeExceptionally(e)
throw e
if (retainsCount.decrementAndGet() != 0) {
return
}

@Suppress("TooGenericExceptionCaught")
try {
onSharedClose()
notifyListenersOnce(e = null)
} catch (e: Throwable) {
while (true) {
try {
notifyListenersOnce(e)
break
} catch (e2: Throwable) {
e.addSuppressed(e2)
}
}
throw e
}
}

private fun notifyListenersOnce(e: Throwable?) {
val iterator = sharedCloseListeners.keys.iterator()
for (listener in iterator) {
iterator.remove()
listener(e)
}
}

Expand All @@ -49,8 +72,6 @@ public abstract class SharedCloseable : Closeable {
@Throws(IOException::class)
protected abstract fun onSharedClose()

public fun onSharedClose(cb: CompletionHandler): DisposableHandle =
job.invokeOnCompletion(cb)

public fun retain() {
while (true) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@file:Suppress("FunctionName")

package fluxo.io.util

internal expect fun <K, V> ConcurrentHashMap(): MutableMap<K, V>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@file:Suppress("FunctionName")

package fluxo.io.util

internal actual fun <K, V> ConcurrentHashMap(): MutableMap<K, V> =
co.touchlab.stately.collections.ConcurrentMutableMap()
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ okio = { module = "com.squareup.okio:okio", version.ref = "okio" }
kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" }
kotlinx-io-bytestring = { module = "org.jetbrains.kotlinx:kotlinx-io-bytestring", version.ref = "kotlinx-io" }

stately-concurrent-collections = { module = "co.touchlab:stately-concurrent-collections", version = "2.0.7" }

# https://developer.android.com/jetpack/androidx/releases/annotation
# https://mvnrepository.com/artifact/androidx.annotation/annotation
androidx-annotation = { module = "androidx.annotation:annotation", version = "1.8.0" }
Expand Down

0 comments on commit 19985c5

Please sign in to comment.