Skip to content

Version 1.0.0 #756

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Oct 29, 2018
Merged
7 changes: 7 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change log for kotlinx.coroutines

## Version 1.0.0

* All Kotlin dependencies updated to 1.3 release version.
* Fixed potential memory leak in `HandlerDispatcher.scheduleResumeAfterDelay`, thanks @cbeyls.
* `yield` support for `Unconfined` and immediate dispatchers (#737).
* Various documentation improvements.

## Version 1.0.0-RC1

* Coroutines API is updated to Kotlin 1.3.
Expand Down
2 changes: 1 addition & 1 deletion COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ In order to migrate `kotlinx.coroutines` to `1.0.0`, follow these steps:

1. Update `kotlinx.coroutines` to `0.30.2` version.
2. Inspect compiler warnings about deprecated API and migrate it to a proposed alternative. Most of deprecated API has a corresponding replacement which can be applied from IDEA with quickfix.
3. Update Kotlin version to `1.3.0` or to the latest `1.3.0-rc` and `kotlinx.coroutines` to version `0.30.2-eap13`. Then just get rid of `experimental` suffix in all imports.
3. Update Kotlin version to `1.3.0` and `kotlinx.coroutines` to version `0.30.2-eap13`. Then just get rid of `experimental` suffix in all imports.
4. Update `kotlinx.coroutines` to version `1.0.0` or to the corresponding release candidate of it).

28 changes: 9 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

[![official JetBrains project](http://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0)
[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.coroutines/images/download.svg?version=1.0.0-RC1) ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/1.0.0-RC1)
[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.coroutines/images/download.svg?version=1.0.0) ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/1.0.0)

Library support for Kotlin coroutines with [multiplatform](#multiplatform) support.
This is a companion version for Kotlin `1.3.0-rc-146` release.
This is a companion version for Kotlin `1.3.0` release.

**NOTE**: `0.30.2` was the last release with Kotlin 1.2 and experimental coroutines.
See [COMPATIBILITY.md](COMPATIBILITY.md) for details of migration onto the stable Kotlin 1.3 coroutines.
Expand Down Expand Up @@ -69,35 +69,33 @@ Add dependencies (you can also add other modules that you need):
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-core</artifactId>
<version>1.0.0-RC1</version>
<version>1.0.0</version>
</dependency>
```

And make sure that you use the latest Kotlin version:

```xml
<properties>
<kotlin.version>1.3.0-rc-146</kotlin.version>
<kotlin.version>1.3.0</kotlin.version>
</properties>
```

While Kotlin 1.3 is still in release candidate status, in order to depend on it you should add eap repository: `https://dl.bintray.com/kotlin/kotlin-eap`.

### Gradle

Add dependencies (you can also add other modules that you need):

```groovy
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0-RC1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0'
}
```

And make sure that you use the latest Kotlin version:

```groovy
buildscript {
ext.kotlin_version = '1.3.0-rc-146'
ext.kotlin_version = '1.3.0'
}
```

Expand All @@ -115,27 +113,19 @@ Add dependencies (you can also add other modules that you need):

```groovy
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0-RC1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0")
}
```

And make sure that you use the latest Kotlin version:

```groovy
plugins {
kotlin("jvm") version "1.3.0-rc-146"
kotlin("jvm") version "1.3.0"
}
```

Make sure that you have either `jcenter()` or `mavenCentral()` in the list of repositories.
For Kotlin EAP builds you also may need `kotlin-eap` repository:

```
repository {
jcenter()
maven { url "https://kotlin.bintray.com/kotlin-eap" }
}
```

### Multiplatform

Expand All @@ -151,7 +141,7 @@ Add [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android)
module as dependency when using `kotlinx.coroutines` on Android:

```groovy
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0-RC1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0'
```
This gives you access to Android [Dispatchers.Main](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-android/kotlinx.coroutines.android/kotlinx.coroutines.-dispatchers/index.html)
coroutine dispatcher and also makes sure that in case of crashed coroutine with unhandled exception this
Expand Down
9 changes: 9 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,17 @@ allprojects {
kotlin_version = '1.2-SNAPSHOT'
}

def name = it.name
repositories {
/*
* google should be first in the repository list because some of the play services
* transitive dependencies was removed from jcenter, thus breaking gradle dependency resolution
*/
if (name == "kotlinx-coroutines-play-services") {
google()
}
jcenter()
maven { url "https://kotlin.bintray.com/kotlin-dev" }
maven { url "https://kotlin.bintray.com/kotlin-eap" }
maven { url "https://kotlin.bintray.com/kotlinx" }
}
Expand Down
27 changes: 23 additions & 4 deletions common/kotlinx-coroutines-core-common/src/Dispatched.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,40 @@ internal object UndispatchedEventLoop {
@JvmField
internal val threadLocalEventLoop = CommonThreadLocal { EventLoop() }

inline fun execute(continuation: DispatchedContinuation<*>, contState: Any?, mode: Int, block: () -> Unit) {
/**
* Executes given [block] as part of current event loop, updating related to block [continuation]
* mode and state if continuation is not resumed immediately.
* [doYield] indicates whether current continuation is yielding (to provide fast-path if event-loop is empty).
* Returns `true` if execution of continuation was queued (trampolined) or `false` otherwise.
*/
inline fun execute(continuation: DispatchedContinuation<*>, contState: Any?, mode: Int,
doYield: Boolean = false, block: () -> Unit) : Boolean {
val eventLoop = threadLocalEventLoop.get()
if (eventLoop.isActive) {
// If we are yielding and queue is empty, we can bail out as part of fast path
if (doYield && eventLoop.queue.isEmpty) {
return false
}

continuation._state = contState
continuation.resumeMode = mode
eventLoop.queue.addLast(continuation)
return
return true
}

runEventLoop(eventLoop, block)
return false
}

fun resumeUndispatched(task: DispatchedTask<*>) {
fun resumeUndispatched(task: DispatchedTask<*>): Boolean {
val eventLoop = threadLocalEventLoop.get()
if (eventLoop.isActive) {
eventLoop.queue.addLast(task)
return
return true
}

runEventLoop(eventLoop, { task.resume(task.delegate, MODE_UNDISPATCHED) })
return false
}

inline fun runEventLoop(eventLoop: EventLoop, block: () -> Unit) {
Expand Down Expand Up @@ -227,6 +241,11 @@ internal interface DispatchedTask<in T> : Runnable {
}
}

internal fun DispatchedContinuation<Unit>.yieldUndispatched(): Boolean =
UndispatchedEventLoop.execute(this, Unit, MODE_CANCELLABLE, doYield = true) {
run()
}

internal fun <T> DispatchedTask<T>.dispatch(mode: Int = MODE_CANCELLABLE) {
val delegate = this.delegate
if (mode.isDispatchedMode && delegate is DispatchedContinuation<*> && mode.isCancellableMode == resumeMode.isCancellableMode) {
Expand Down
4 changes: 3 additions & 1 deletion common/kotlinx-coroutines-core-common/src/Yield.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public suspend fun yield(): Unit = suspendCoroutineUninterceptedOrReturn sc@ { u
val context = uCont.context
context.checkCompletion()
val cont = uCont.intercepted() as? DispatchedContinuation<Unit> ?: return@sc Unit
if (!cont.dispatcher.isDispatchNeeded(context)) return@sc Unit
if (!cont.dispatcher.isDispatchNeeded(context)) {
return@sc if (cont.yieldUndispatched()) COROUTINE_SUSPENDED else Unit
}
cont.dispatchYield(Unit)
COROUTINE_SUSPENDED
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,9 @@ public interface ReceiveChannel<out E> {
* **Note: This is an obsolete api.**
* This function will be replaced with `receiveOrClosed: ReceiveResult<E>` and
* extension `suspend fun <E: Any> ReceiveChannel<E>.receiveOrNull(): E?`
* It is obsolete because it does not distinguish closed channel and null elements.
*/
@ExperimentalCoroutinesApi
@ObsoleteCoroutinesApi
@Deprecated(level = DeprecationLevel.WARNING, message = "This method does not distinguish closed channel and null elements")
public suspend fun receiveOrNull(): E?

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ internal class ArrayQueue<T : Any> {
private var elements = arrayOfNulls<Any>(16)
private var head = 0
private var tail = 0
val isEmpty: Boolean get() = head == tail

public fun addLast(element: T) {
elements[tail] = element
Expand Down
43 changes: 42 additions & 1 deletion common/kotlinx-coroutines-core-common/test/UnconfinedTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class UnconfinedTest : TestBase() {
}

@Test
fun enterMultipleTimes() = runTest {
fun testEnterMultipleTimes() = runTest {
launch(Unconfined) {
expect(1)
}
Expand All @@ -70,5 +70,46 @@ class UnconfinedTest : TestBase() {
finish(4)
}

@Test
fun testYield() = runTest {
expect(1)
launch(Dispatchers.Unconfined) {
expect(2)
yield()
launch {
expect(4)
}
expect(3)
yield()
expect(5)
}.join()

finish(6)
}

@Test
fun testCancellationWihYields() = runTest {
expect(1)
GlobalScope.launch(Dispatchers.Unconfined) {
val job = coroutineContext[Job]!!
expect(2)
yield()
GlobalScope.launch(Dispatchers.Unconfined) {
expect(4)
job.cancel()
expect(5)
}
expect(3)

try {
yield()
} finally {
expect(6)
}
}

finish(7)
}

class TestException : Throwable()
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ class UnconfinedConcurrentStressTest : TestBase() {
executor.close()
}

@Test(timeout = 10_000L)
@Test
fun testConcurrent() = runTest {
val iterations = 10_000 * stressTestMultiplier
val iterations = 1_000 * stressTestMultiplier
val startBarrier = CyclicBarrier(threads + 1)
val finishLatch = CountDownLatch(threads)

Expand Down
8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Kotlin
version=1.0.0-RC1-SNAPSHOT
version=1.0.0-SNAPSHOT
group=org.jetbrains.kotlinx
kotlin_version=1.3.0-rc-146
kotlin_native_version=1.3.0-rc-146
kotlin_version=1.3.0
kotlin_native_version=1.3.0-rc-208

# Dependencies
junit_version=4.12
atomicFU_version=0.11.11
atomicFU_version=0.11.12
html_version=0.6.8
lincheck_version=1.9
dokka_version=0.9.16-rdev-2-mpp-hacks
Expand Down
4 changes: 0 additions & 4 deletions integration/kotlinx-coroutines-play-services/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ import java.util.zip.ZipFile

ext.tasks_version = '15.0.1'

repositories {
google()
}

def attr = Attribute.of("artifactType", String.class)
configurations {
aar {
Expand Down
2 changes: 1 addition & 1 deletion native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ repositories {
}

dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.0.0-RC1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.0.0'
}

sourceSets {
Expand Down
2 changes: 1 addition & 1 deletion ui/coroutines-guide-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ Add dependencies on `kotlinx-coroutines-android` module to the `dependencies { .
`app/build.gradle` file:

```groovy
compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0-RC1"
compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0"
```

You can clone [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) project from GitHub onto your
Expand Down
4 changes: 2 additions & 2 deletions ui/kotlinx-coroutines-android/animation-app/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ org.gradle.jvmargs=-Xmx1536m

kotlin.coroutines=enable

kotlin_version=1.3.0-rc-146
coroutines_version=1.0.0-RC1
kotlin_version=1.3.0
coroutines_version=1.0.0

4 changes: 2 additions & 2 deletions ui/kotlinx-coroutines-android/example-app/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ org.gradle.jvmargs=-Xmx1536m

kotlin.coroutines=enable

kotlin_version=1.3.0-rc-146
coroutines_version=1.0.0-RC1
kotlin_version=1.3.0
coroutines_version=1.0.0

6 changes: 4 additions & 2 deletions ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,11 @@ internal class HandlerContext private constructor(
}

override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
handler.postDelayed({
val block = Runnable {
with(continuation) { resumeUndispatched(Unit) }
}, timeMillis.coerceAtMost(MAX_DELAY))
}
handler.postDelayed(block, timeMillis.coerceAtMost(MAX_DELAY))
continuation.invokeOnCancellation { handler.removeCallbacks(block) }
}

override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle {
Expand Down