Skip to content

Commit 44e3ba5

Browse files
committed
Quasar integration
1 parent 1025837 commit 44e3ba5

File tree

11 files changed

+360
-0
lines changed

11 files changed

+360
-0
lines changed

integration/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This directory contains modules that provide integration with various asynchrono
77
* [kotlinx-coroutines-jdk8](kotlinx-coroutines-jdk8/README.md) -- integration with JDK8 `CompletableFuture` (Android API level 24).
88
* [kotlinx-coroutines-nio](kotlinx-coroutines-nio/README.md) -- integration with asynchronous IO on JDK7+ (Android O Preview).
99
* [kotlinx-coroutines-guava](kotlinx-coroutines-guava/README.md) -- integration with Guava [ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained).
10+
* [kotlinx-coroutines-quasar](kotlinx-coroutines-quasar/README.md) -- integration with [Quasar](http://docs.paralleluniverse.co/quasar/).
1011

1112
## Contributing
1213

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Module kotlinx-coroutines-quasar
2+
3+
Integration with [Quasar](http://docs.paralleluniverse.co/quasar/).
4+
It supports invoking Quasar-instrumented suspendable code from within Kotlin
5+
coroutines via [runSuspendable] and invoking Kotlin suspending code from
6+
Quasar-instrumented code via [runFiberBlocking].
7+
8+
## Example
9+
10+
Invoke Quasar-instrumented suspendable code from Kotlin coroutine via [runSuspendable]:
11+
12+
```kotlin
13+
runSuspendable(SuspendableCallable {
14+
// Your suspendable code that will be instrumented by Quasar here
15+
})
16+
```
17+
18+
Invoke Kotlin suspending function from Quasar-instrumented suspendable code via [runFiberBlocking]:
19+
20+
```kotlin
21+
runFiberBlocking {
22+
// Your Kotlin suspending code here
23+
}
24+
```
25+
26+
# Package kotlinx.coroutines.experimental.quasar
27+
28+
Integration with [Quasar](http://docs.paralleluniverse.co/quasar/).
29+
30+
<!--- MODULE kotlinx-coroutines-core -->
31+
<!--- INDEX kotlinx.coroutines.experimental -->
32+
<!--- MODULE kotlinx-coroutines-quasar -->
33+
<!--- INDEX kotlinx.coroutines.experimental.quasar -->
34+
[runSuspendable]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-quasar/kotlinx.coroutines.experimental.quasar/run-suspendable.html
35+
[runFiberBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-quasar/kotlinx.coroutines.experimental.quasar/run-fiber-blocking.html
36+
<!--- END -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2016-2017 JetBrains s.r.o.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
18+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
19+
<modelVersion>4.0.0</modelVersion>
20+
21+
<parent>
22+
<groupId>org.jetbrains.kotlinx</groupId>
23+
<artifactId>kotlinx-coroutines</artifactId>
24+
<version>0.17-SNAPSHOT</version>
25+
<relativePath>../../pom.xml</relativePath>
26+
</parent>
27+
28+
<artifactId>kotlinx-coroutines-quasar</artifactId>
29+
<packaging>jar</packaging>
30+
31+
<build>
32+
<sourceDirectory>src/main/kotlin</sourceDirectory>
33+
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
34+
35+
<plugins>
36+
<plugin>
37+
<groupId>org.jetbrains.dokka</groupId>
38+
<artifactId>dokka-maven-plugin</artifactId>
39+
<version>${dokka.version}</version>
40+
<configuration>
41+
<externalDocumentationLinks combine.children="append">
42+
<link>
43+
<url>${core.docs.url}</url>
44+
<packageListUrl>file:///${project.parent.basedir}/kotlinx-coroutines-core/target/dokka/kotlinx-coroutines-core/package-list</packageListUrl>
45+
</link>
46+
<link>
47+
<url>https://google.github.io/guava/releases/18.0/api/docs/</url>
48+
</link>
49+
</externalDocumentationLinks>
50+
<skip>false</skip>
51+
</configuration>
52+
</plugin>
53+
<plugin>
54+
<artifactId>maven-dependency-plugin</artifactId>
55+
<executions>
56+
<execution>
57+
<id>getClasspathFilenames</id>
58+
<goals>
59+
<goal>properties</goal>
60+
</goals>
61+
</execution>
62+
</executions>
63+
</plugin>
64+
<plugin>
65+
<artifactId>maven-surefire-plugin</artifactId>
66+
<configuration>
67+
<!-- add -Dco.paralleluniverse.fibers.writeInstrumentedClasses=QuasarTest to dump classes -->
68+
<!-- add =v for verbose -->
69+
<argLine>-javaagent:@{co.paralleluniverse:quasar-core:jar}</argLine>
70+
</configuration>
71+
</plugin>
72+
</plugins>
73+
</build>
74+
75+
<dependencies>
76+
<!-- dependency on coroutines core -->
77+
<dependency>
78+
<groupId>org.jetbrains.kotlinx</groupId>
79+
<artifactId>kotlinx-coroutines-core</artifactId>
80+
<version>${project.version}</version>
81+
</dependency>
82+
<!-- coroutines test framework dependency -->
83+
<dependency>
84+
<groupId>org.jetbrains.kotlinx</groupId>
85+
<artifactId>kotlinx-coroutines-core</artifactId>
86+
<version>${project.version}</version>
87+
<classifier>tests</classifier>
88+
<scope>test</scope>
89+
</dependency>
90+
<!-- 3rd party dependencies -->
91+
<dependency>
92+
<groupId>co.paralleluniverse</groupId>
93+
<artifactId>quasar-core</artifactId>
94+
<version>0.7.9</version>
95+
</dependency>
96+
</dependencies>
97+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2016-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package kotlinx.coroutines.experimental.quasar
18+
19+
import co.paralleluniverse.fibers.instrument.MethodDatabase
20+
import co.paralleluniverse.fibers.instrument.SuspendableClassifier
21+
22+
/**
23+
* @suppress **Internal implementation**.
24+
*/
25+
class KotlinSuspendableClassifier : SuspendableClassifier {
26+
override fun isSuspendable(
27+
db: MethodDatabase,
28+
sourceName: String?,
29+
sourceDebugInfo: String?,
30+
isInterface: Boolean,
31+
className: String?,
32+
superClassName: String?,
33+
interfaces: Array<out String>,
34+
methodName: String,
35+
methodDesc: String,
36+
methodSignature: String?,
37+
methodExceptions: Array<out String>?
38+
): MethodDatabase.SuspendableType? {
39+
if (methodName == "run" &&
40+
methodDesc.startsWith("()") &&
41+
interfaces.contains("co/paralleluniverse/strands/SuspendableCallable"))
42+
return MethodDatabase.SuspendableType.SUSPENDABLE
43+
return null
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright 2016-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/*
18+
* Copyright 2016-2017 JetBrains s.r.o.
19+
*
20+
* Licensed under the Apache License, Version 2.0 (the "License");
21+
* you may not use this file except in compliance with the License.
22+
* You may obtain a copy of the License at
23+
*
24+
* http://www.apache.org/licenses/LICENSE-2.0
25+
*
26+
* Unless required by applicable law or agreed to in writing, software
27+
* distributed under the License is distributed on an "AS IS" BASIS,
28+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29+
* See the License for the specific language governing permissions and
30+
* limitations under the License.
31+
*/
32+
33+
package kotlinx.coroutines.experimental.quasar
34+
35+
import co.paralleluniverse.fibers.Fiber
36+
import co.paralleluniverse.fibers.FiberAsync
37+
import co.paralleluniverse.fibers.SuspendExecution
38+
import co.paralleluniverse.fibers.Suspendable
39+
import co.paralleluniverse.strands.SuspendableCallable
40+
import kotlinx.coroutines.experimental.asCoroutineDispatcher
41+
import kotlinx.coroutines.experimental.cancelFutureOnCompletion
42+
import kotlinx.coroutines.experimental.suspendCancellableCoroutine
43+
import kotlin.coroutines.experimental.Continuation
44+
import kotlin.coroutines.experimental.CoroutineContext
45+
import kotlin.coroutines.experimental.startCoroutine
46+
47+
/**
48+
* Runs Quasar-instrumented suspendable code from Kotlin coroutine.
49+
*/
50+
suspend fun <T> runSuspendable(callable: SuspendableCallable<T>): T = suspendCancellableCoroutine { cont ->
51+
val fiber = object : Fiber<Unit>() {
52+
@Throws(SuspendExecution::class)
53+
override fun run() {
54+
val result = try { callable.run() }
55+
catch (e: Throwable) {
56+
cont.resumeWithException(e)
57+
return
58+
}
59+
cont.resume(result)
60+
}
61+
}
62+
cont.cancelFutureOnCompletion(fiber)
63+
fiber.start()
64+
}
65+
66+
/**
67+
* Runs Kotlin suspending function from Quasar-instrumented suspendable code.
68+
*/
69+
@Suspendable
70+
fun <T> runFiberBlocking(block: suspend () -> T): T =
71+
CoroutineAsync(block).run()
72+
73+
private class CoroutineAsync<T>(
74+
private val block: suspend () -> T
75+
) : FiberAsync<T, Throwable>(), Continuation<T> {
76+
override val context: CoroutineContext = Fiber.currentFiber().scheduler.executor.asCoroutineDispatcher()
77+
override fun resume(value: T) { asyncCompleted(value) }
78+
override fun resumeWithException(exception: Throwable) { asyncFailed(exception) }
79+
80+
override fun requestAsync() {
81+
block.startCoroutine(completion = this)
82+
}
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
kotlinx.coroutines.experimental.quasar.KotlinSuspendableClassifier
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2016-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package kotlinx.coroutines.experimental.quasar
18+
19+
import co.paralleluniverse.fibers.Fiber
20+
import co.paralleluniverse.fibers.SuspendExecution
21+
import co.paralleluniverse.strands.SuspendableCallable
22+
import co.paralleluniverse.strands.dataflow.Val
23+
import guide.test.ignoreLostThreads
24+
import kotlinx.coroutines.experimental.CompletableDeferred
25+
import kotlinx.coroutines.experimental.TestBase
26+
import kotlinx.coroutines.experimental.launch
27+
import kotlinx.coroutines.experimental.runBlocking
28+
import org.junit.Before
29+
import org.junit.Test
30+
import java.util.concurrent.TimeUnit
31+
32+
class QuasarTest : TestBase() {
33+
@Before
34+
fun setup() {
35+
ignoreLostThreads(
36+
"FiberTimedScheduler-default-fiber-pool",
37+
"ForkJoinPool-default-fiber-pool-worker-",
38+
"Timer-")
39+
}
40+
41+
@Test
42+
fun testRunSuspendable() = runBlocking<Unit> {
43+
expect(1)
44+
val started = CompletableDeferred<Unit>() // Kotlin's event
45+
val x = Val<String>() // Quasar's data flow
46+
launch(coroutineContext) {
47+
started.await() // await Quasar's scheduler
48+
expect(3) // will get scheduled when runSuspendable suspends
49+
x.set("OK")
50+
}
51+
val result = runSuspendable(SuspendableCallable {
52+
expect(2)
53+
started.complete(Unit) // signal that we've started
54+
x.get(10, TimeUnit.SECONDS) // will get suspended
55+
})
56+
finish(4)
57+
check(result == "OK")
58+
}
59+
60+
@Test
61+
fun testRunFiberBlocking() = runBlocking {
62+
expect(1)
63+
val started = CompletableDeferred<Unit>() // Kotlin's event
64+
val result = CompletableDeferred<String>() // result goes here
65+
val fiber = object : Fiber<String>() {
66+
@Throws(SuspendExecution::class)
67+
override fun run(): String {
68+
expect(3)
69+
started.complete(Unit) // signal that fiber is started
70+
// block fiber on suspendable await
71+
val value = runFiberBlocking {
72+
result.await()
73+
}
74+
expect(5)
75+
return value
76+
}
77+
}
78+
fiber.start()
79+
expect(2)
80+
started.await() // wait fiber to start
81+
expect(4)
82+
result.complete("OK") // send Ok to fiber
83+
val answer = runSuspendable(SuspendableCallable {
84+
fiber.get()
85+
})
86+
finish(6)
87+
check(answer == "OK")
88+
}
89+
}

pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
<module>integration/kotlinx-coroutines-jdk8</module>
113113
<module>integration/kotlinx-coroutines-nio</module>
114114
<module>integration/kotlinx-coroutines-guava</module>
115+
<module>integration/kotlinx-coroutines-quasar</module>
115116
</modules>
116117

117118
<dependencies>

site/build.xml

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<fileset dir="../integration/kotlinx-coroutines-jdk8/target/dokka" includes="**/*.md"/>
4545
<fileset dir="../integration/kotlinx-coroutines-nio/target/dokka" includes="**/*.md"/>
4646
<fileset dir="../integration/kotlinx-coroutines-guava/target/dokka" includes="**/*.md"/>
47+
<fileset dir="../integration/kotlinx-coroutines-quasar/target/dokka" includes="**/*.md"/>
4748
</copy>
4849
<antcall target="jekyll"/>
4950
</target>

site/docs/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ Library support for Kotlin coroutines. This reference is a companion to
2121
[kotlinx-coroutines-jdk8](kotlinx-coroutines-jdk8) | Integration with JDK8 `CompletableFuture` (Android API level 24)
2222
[kotlinx-coroutines-nio](kotlinx-coroutines-nio) | Integration with asynchronous IO on JDK7+ (Android O Preview)
2323
[kotlinx-coroutines-guava](kotlinx-coroutines-guava) | Integration with Guava [ListenableFuture](https://github.com/google/guava/wiki/ListenableFutureExplained)
24+
[kotlinx-coroutines-quasar](kotlinx-coroutines-quasar) | Integration with [Quasar](http://docs.paralleluniverse.co/quasar/)

0 commit comments

Comments
 (0)