blob: 8ac8d54a8b50144cf1513541d5620bd49b58563d [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +03001/*
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
Roman Elizarov3754f952017-01-18 20:47:54 +030017package kotlinx.coroutines.experimental
18
Roman Elizarovea4a51b2017-01-31 12:01:25 +030019import kotlin.coroutines.experimental.Continuation
20import kotlin.coroutines.experimental.CoroutineContext
Roman Elizarov3754f952017-01-18 20:47:54 +030021
Roman Elizarov53a0a402017-01-19 20:21:57 +030022/**
Roman Elizarovd528e3e2017-01-23 15:40:05 +030023 * Receiver interface for generic coroutine builders, so that the code inside coroutine has a convenient access
24 * to its [context] and cancellation status via [isActive].
25 */
26public interface CoroutineScope {
27 /**
28 * Returns `true` when this coroutine is still active (was not cancelled).
29 */
30 public val isActive: Boolean
31
32 /**
33 * Returns the context of this coroutine.
34 */
35 public val context: CoroutineContext
36}
37
38/**
Roman Elizarov53a0a402017-01-19 20:21:57 +030039 * Abstract class to simplify writing of coroutine completion objects that
40 * implements [Continuation] and [Job] interfaces.
41 * It stores the result of continuation in the state of the job.
42 */
Roman Elizarov3754f952017-01-18 20:47:54 +030043@Suppress("LeakingThis")
Roman Elizarov55888f22017-01-26 11:48:37 +030044internal abstract class AbstractCoroutine<in T>(context: CoroutineContext) : JobSupport(), Continuation<T>, CoroutineScope {
Roman Elizarov41c5c8b2017-01-25 13:37:15 +030045 override val context: CoroutineContext = context + this // merges this job into this context
Roman Elizarov3754f952017-01-18 20:47:54 +030046
Roman Elizarov53a0a402017-01-19 20:21:57 +030047 final override fun resume(value: T) {
Roman Elizarov3754f952017-01-18 20:47:54 +030048 while (true) { // lock-free loop on state
49 val state = getState() // atomic read
50 when (state) {
51 is Active -> if (updateState(state, value)) return
52 is Cancelled -> return // ignore resumes on cancelled continuation
53 else -> throw IllegalStateException("Already resumed, but got value $value")
54 }
55 }
56 }
57
Roman Elizarov53a0a402017-01-19 20:21:57 +030058 final override fun resumeWithException(exception: Throwable) {
Roman Elizarov3754f952017-01-18 20:47:54 +030059 while (true) { // lock-free loop on state
60 val state = getState() // atomic read
61 when (state) {
Roman Elizarovb7c46de2017-02-08 12:35:24 +030062 is Active -> if (updateState(state, CompletedExceptionally(exception))) return
Roman Elizarov3754f952017-01-18 20:47:54 +030063 is Cancelled -> {
64 // ignore resumes on cancelled continuation, but handle exception if a different one is here
65 if (exception != state.exception) handleCoroutineException(context, exception)
66 return
67 }
68 else -> throw IllegalStateException("Already resumed, but got exception $exception", exception)
69 }
70 }
71 }
Roman Elizarovc5814542017-01-19 10:19:06 +030072
Roman Elizarov53a0a402017-01-19 20:21:57 +030073 final override fun handleCompletionException(closeException: Throwable) {
74 handleCoroutineException(context, closeException)
Roman Elizarovc5814542017-01-19 10:19:06 +030075 }
Roman Elizarov3754f952017-01-18 20:47:54 +030076}