Merge branch 'master' into develop
diff --git a/kotlinx-coroutines-core/common/src/CancellableContinuation.kt b/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
index 139ef04..492e367 100644
--- a/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
+++ b/kotlinx-coroutines-core/common/src/CancellableContinuation.kt
@@ -11,9 +11,9 @@
 // --------------- cancellable continuations ---------------
 
 /**
- * Cancellable continuation. It is _completed_ when it is resumed or cancelled.
- * When [cancel] function is explicitly invoked, this continuation immediately resumes with [CancellationException] or
- * with the specified cancel cause.
+ * Cancellable continuation. It is _completed_ when resumed or cancelled.
+ * When the [cancel] function is explicitly invoked, this continuation immediately resumes with a [CancellationException] or
+ * the specified cancel cause.
  *
  * Cancellable continuation has three states (as subset of [Job] states):
  *
@@ -28,10 +28,10 @@
  *
  * A [cancelled][isCancelled] continuation implies that it is [completed][isCompleted].
  *
- * Invocation of [resume] or [resumeWithException] in _resumed_ state produces [IllegalStateException].
+ * Invocation of [resume] or [resumeWithException] in _resumed_ state produces an [IllegalStateException].
  * Invocation of [resume] in _cancelled_ state is ignored (it is a trivial race between resume from the continuation owner and
- * outer job cancellation and cancellation wins).
- * Invocation of [resumeWithException] in _cancelled_ state triggers exception handling of passed exception.
+ * outer job's cancellation, and the cancellation wins).
+ * Invocation of [resumeWithException] in _cancelled_ state triggers exception handling of the passed exception.
  *
  * ```
  *    +-----------+   resume    +---------+
@@ -53,8 +53,8 @@
     public val isActive: Boolean
 
     /**
-     * Returns `true` when this continuation has completed for any reason. A continuation
-     * that was cancelled is also considered complete.
+     * Returns `true` when this continuation has completed for any reason. A cancelled continuation
+     * is also considered complete.
      */
     public val isCompleted: Boolean
 
@@ -66,11 +66,11 @@
     public val isCancelled: Boolean
 
     /**
-     * Tries to resume this continuation with a given value and returns non-null object token if it was successful,
-     * or `null` otherwise (it was already resumed or cancelled). When non-null object was returned,
+     * Tries to resume this continuation with the specified [value] and returns a non-null object token if successful,
+     * or `null` otherwise (it was already resumed or cancelled). When a non-null object is returned,
      * [completeResume] must be invoked with it.
      *
-     * When [idempotent] is not `null`, this function performs _idempotent_ operation, so that
+     * When [idempotent] is not `null`, this function performs an _idempotent_ operation, so that
      * further invocations with the same non-null reference produce the same result.
      *
      * @suppress **This is unstable API and it is subject to change.**
@@ -79,8 +79,8 @@
     public fun tryResume(value: T, idempotent: Any? = null): Any?
 
     /**
-     * Tries to resume this continuation with a given exception and returns non-null object token if it was successful,
-     * or `null` otherwise (it was already resumed or cancelled). When non-null object was returned,
+     * Tries to resume this continuation with the specified [exception] and returns a non-null object token if successful,
+     * or `null` otherwise (it was already resumed or cancelled). When a non-null object is returned,
      * [completeResume] must be invoked with it.
      *
      * @suppress **This is unstable API and it is subject to change.**
@@ -112,34 +112,34 @@
     public fun initCancellability()
 
     /**
-     * Cancels this continuation with an optional cancellation [cause]. The result is `true` if this continuation was
-     * cancelled as a result of this invocation and `false` otherwise.
+     * Cancels this continuation with an optional cancellation `cause`. The result is `true` if this continuation was
+     * cancelled as a result of this invocation, and `false` otherwise.
      */
     public fun cancel(cause: Throwable? = null): Boolean
 
     /**
-     * Registers handler that is **synchronously** invoked once on cancellation (both regular and exceptional) of this continuation.
-     * When the continuation is already cancelled, then the handler is immediately invoked
-     * with cancellation exception. Otherwise, the handler will be invoked once on cancellation if this
+     * Registers a [handler] to be **synchronously** invoked on cancellation (regular or exceptional) of this continuation.
+     * When the continuation is already cancelled, the handler will be immediately invoked
+     * with the cancellation exception. Otherwise, the handler will be invoked as soon as this
      * continuation is cancelled.
      *
-     * Installed [handler] should not throw any exceptions.
-     * If it does, they will get caught, wrapped into [CompletionHandlerException] and
-     * processed as uncaught exception in the context of the current coroutine
+     * The installed [handler] should not throw any exceptions.
+     * If it does, they will get caught, wrapped into a [CompletionHandlerException] and
+     * processed as an uncaught exception in the context of the current coroutine
      * (see [CoroutineExceptionHandler]).
      *
-     * At most one [handler] can be installed on one continuation.
+     * At most one [handler] can be installed on a continuation.
      *
      * **Note**: Implementation of `CompletionHandler` must be fast, non-blocking, and thread-safe.
-     * This handler can be invoked concurrently with the surrounding code.
-     * There is no guarantee on the execution context in which the [handler] is invoked.
+     * This `handler` can be invoked concurrently with the surrounding code.
+     * There is no guarantee on the execution context in which the `handler` will be invoked.
      */
     public fun invokeOnCancellation(handler: CompletionHandler)
 
     /**
-     * Resumes this continuation with a given [value] in the invoker thread without going though
-     * [dispatch][CoroutineDispatcher.dispatch] function of the [CoroutineDispatcher] in the [context].
-     * This function is designed to be used only by the [CoroutineDispatcher] implementations themselves.
+     * Resumes this continuation with the specified [value] in the invoker thread without going through
+     * the [dispatch][CoroutineDispatcher.dispatch] function of the [CoroutineDispatcher] in the [context].
+     * This function is designed to only be used by [CoroutineDispatcher] implementations.
      * **It should not be used in general code**.
      *
      * **Note: This function is experimental.** Its signature general code may be changed in the future.
@@ -148,9 +148,9 @@
     public fun CoroutineDispatcher.resumeUndispatched(value: T)
 
     /**
-     * Resumes this continuation with a given [exception] in the invoker thread without going though
-     * [dispatch][CoroutineDispatcher.dispatch] function of the [CoroutineDispatcher] in the [context].
-     * This function is designed to be used only by the [CoroutineDispatcher] implementations themselves.
+     * Resumes this continuation with the specified [exception] in the invoker thread without going through
+     * the [dispatch][CoroutineDispatcher.dispatch] function of the [CoroutineDispatcher] in the [context].
+     * This function is designed to only be used by [CoroutineDispatcher] implementations.
      * **It should not be used in general code**.
      *
      * **Note: This function is experimental.** Its signature general code may be changed in the future.
@@ -159,19 +159,19 @@
     public fun CoroutineDispatcher.resumeUndispatchedWithException(exception: Throwable)
 
     /**
-     * Resumes this continuation with a given [value] and calls the specified [onCancellation]
-     * handler when resumed too late (when continuation was already cancelled) or when resumed
-     * successfully (before cancellation), but coroutine's job was cancelled before it had a
-     * chance to run in its dispatcher, so that suspended function threw an exception
+     * Resumes this continuation with the specified `value` and calls the specified `onCancellation`
+     * handler when either resumed too late (when continuation was already cancelled) or, although resumed
+     * successfully (before cancellation), the coroutine's job was cancelled before it had a
+     * chance to run in its dispatcher, so that the suspended function threw an exception
      * instead of returning this value.
      *
-     * Installed [onCancellation] handler should not throw any exceptions.
-     * If it does, they will get caught, wrapped into [CompletionHandlerException] and
-     * processed as uncaught exception in the context of the current coroutine
+     * The installed [onCancellation] handler should not throw any exceptions.
+     * If it does, they will get caught, wrapped into a [CompletionHandlerException] and
+     * processed as an uncaught exception in the context of the current coroutine
      * (see [CoroutineExceptionHandler]).
      *
-     * This function shall be used when resuming with a resource that must be closed by the
-     * code that had called the corresponding suspending function, e.g.:
+     * This function shall be used when resuming with a resource that must be closed by
+     * code that called the corresponding suspending function, e.g.:
      *
      * ```
      * continuation.resume(resource) {
@@ -179,17 +179,17 @@
      * }
      * ```
      *
-     * **Note**: Implementation of [onCancellation] handler must be fast, non-blocking, and thread-safe.
-     * This handler can be invoked concurrently with the surrounding code.
-     * There is no guarantee on the execution context in which the [onCancellation] handler is invoked.
+     * **Note**: The [onCancellation] handler must be fast, non-blocking, and thread-safe.
+     * It can be invoked concurrently with the surrounding code.
+     * There is no guarantee on the execution context of its invocation.
      */
     @ExperimentalCoroutinesApi // since 1.2.0, tentatively graduates in 1.3.0
     public fun resume(value: T, onCancellation: (cause: Throwable) -> Unit)
 }
 
 /**
- * Suspends coroutine similar to [suspendCoroutine], but provide an implementation of [CancellableContinuation] to
- * the [block]. This function throws [CancellationException] if the coroutine is cancelled or completed while suspended.
+ * Suspends the coroutine like [suspendCoroutine], but providing a [CancellableContinuation] to
+ * the [block]. This function throws a [CancellationException] if the coroutine is cancelled or completed while suspended.
  */
 public suspend inline fun <T> suspendCancellableCoroutine(
     crossinline block: (CancellableContinuation<T>) -> Unit
@@ -204,9 +204,9 @@
     }
 
 /**
- * Suspends coroutine similar to [suspendCancellableCoroutine], but with *atomic cancellation*.
+ * Suspends the coroutine like [suspendCancellableCoroutine], but with *atomic cancellation*.
  *
- * When suspended function throws [CancellationException] it means that the continuation was not resumed.
+ * When the suspended function throws a [CancellationException], it means that the continuation was not resumed.
  * As a side-effect of atomic cancellation, a thread-bound coroutine (to some UI thread, for example) may
  * continue to execute even after it was cancelled from the same thread in the case when the continuation
  * was already resumed and was posted for execution to the thread's queue.
@@ -238,15 +238,15 @@
     suspendAtomicCancellableCoroutine(block)
 
 /**
- * Removes a given node on cancellation.
+ * Removes the specified [node] on cancellation.
  */
 internal fun CancellableContinuation<*>.removeOnCancellation(node: LockFreeLinkedListNode) =
     invokeOnCancellation(handler = RemoveOnCancel(node).asHandler)
 
 /**
- * Disposes a specified [handle] when this continuation is cancelled.
+ * Disposes the specified [handle] when this continuation is cancelled.
  *
- * This is a shortcut for the following code with slightly more efficient implementation (one fewer object created).
+ * This is a shortcut for the following code with slightly more efficient implementation (one fewer object created):
  * ```
  * invokeOnCancellation { handle.dispose() }
  * ```
diff --git a/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt b/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
index 785e8a7..a8b5686 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineContext.common.kt
@@ -7,7 +7,7 @@
 import kotlin.coroutines.*
 
 /**
- * Creates context for the new coroutine. It installs [Dispatchers.Default] when no other dispatcher nor
+ * Creates a context for the new coroutine. It installs [Dispatchers.Default] when no other dispatcher or
  * [ContinuationInterceptor] is specified, and adds optional support for debugging facilities (when turned on).
  */
 public expect fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext
diff --git a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
index 19308c2..df7a2da 100644
--- a/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
+++ b/kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt
@@ -7,36 +7,36 @@
 import kotlin.coroutines.*
 
 /**
- * Base class that shall be extended by all coroutine dispatcher implementations.
+ * Base class to be extended by all coroutine dispatcher implementations.
  *
  * The following standard implementations are provided by `kotlinx.coroutines` as properties on
- * [Dispatchers] objects:
+ * the [Dispatchers] object:
  *
- * * [Dispatchers.Default] -- is used by all standard builder if no dispatcher nor any other [ContinuationInterceptor]
+ * * [Dispatchers.Default] &mdash; is used by all standard builders if no dispatcher or any other [ContinuationInterceptor]
  *   is specified in their context. It uses a common pool of shared background threads.
  *   This is an appropriate choice for compute-intensive coroutines that consume CPU resources.
- * * [Dispatchers.IO] -- uses a shared pool of on-demand created threads and is designed for offloading of IO-intensive _blocking_
+ * * [Dispatchers.IO] &mdash; uses a shared pool of on-demand created threads and is designed for offloading of IO-intensive _blocking_
  *   operations (like file I/O and blocking socket I/O).
- * * [Dispatchers.Unconfined] -- starts coroutine execution in the current call-frame until the first suspension.
- *   On first  suspension the coroutine builder function returns.
- *   The coroutine resumes in whatever thread that is used by the
+ * * [Dispatchers.Unconfined] &mdash; starts coroutine execution in the current call-frame until the first suspension,
+ *   whereupon the coroutine builder function returns.
+ *   The coroutine will later resume in whatever thread used by the
  *   corresponding suspending function, without confining it to any specific thread or pool.
- *   **Unconfined dispatcher should not be normally used in code**.
+ *   **The `Unconfined` dispatcher should not normally be used in code**.
  * * Private thread pools can be created with [newSingleThreadContext] and [newFixedThreadPoolContext].
- * * An arbitrary [Executor][java.util.concurrent.Executor] can be converted to dispatcher with [asCoroutineDispatcher] extension function.
+ * * An arbitrary [Executor][java.util.concurrent.Executor] can be converted to a dispatcher with the [asCoroutineDispatcher] extension function.
  *
  * This class ensures that debugging facilities in [newCoroutineContext] function work properly.
  */
 public abstract class CoroutineDispatcher :
     AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
     /**
-     * Returns `true` if execution shall be dispatched onto another thread.
-     * The default behaviour for most dispatchers is to return `true`.
+     * Returns `true` if the execution shall be dispatched onto another thread.
+     * The default behavior for most dispatchers is to return `true`.
      *
      * This method should never be used from general code, it is used only by `kotlinx.coroutines`
-     * internals and its contract with the rest of API is an implementation detail.
+     * internals and its contract with the rest of the API is an implementation detail.
      *
-     * UI dispatchers _should not_ override `isDispatchNeeded`, but leave a default implementation that
+     * UI dispatchers _should not_ override `isDispatchNeeded`, but leave the default implementation that
      * returns `true`. To understand the rationale beyond this recommendation, consider the following code:
      *
      * ```kotlin
@@ -46,24 +46,24 @@
      * ```
      *
      * When you invoke `asyncUpdateUI` in some background thread, it immediately continues to the next
-     * line, while UI update happens asynchronously in the UI thread. However, if you invoke
-     * it in the UI thread itself, it updates UI _synchronously_ if your `isDispatchNeeded` is
+     * line, while the UI update happens asynchronously in the UI thread. However, if you invoke
+     * it in the UI thread itself, it will update the UI _synchronously_ if your `isDispatchNeeded` is
      * overridden with a thread check. Checking if we are already in the UI thread seems more
      * efficient (and it might indeed save a few CPU cycles), but this subtle and context-sensitive
      * difference in behavior makes the resulting async code harder to debug.
      *
-     * Basically, the choice here is between "JS-style" asynchronous approach (async actions
-     * are always postponed to be executed later in the even dispatch thread) and "C#-style" approach
+     * Basically, the choice here is between the "JS-style" asynchronous approach (async actions
+     * are always postponed to be executed later in the event dispatch thread) and "C#-style" approach
      * (async actions are executed in the invoker thread until the first suspension point).
-     * While, C# approach seems to be more efficient, it ends up with recommendations like
-     * "use `yield` if you need to ....". This is error-prone. JS-style approach is more consistent
+     * While the C# approach seems to be more efficient, it ends up with recommendations like
+     * "use `yield` if you need to ....". This is error-prone. The JS-style approach is more consistent
      * and does not require programmers to think about whether they need to yield or not.
      *
      * However, coroutine builders like [launch][CoroutineScope.launch] and [async][CoroutineScope.async] accept an optional [CoroutineStart]
-     * parameter that allows one to optionally choose C#-style [CoroutineStart.UNDISPATCHED] behaviour
+     * parameter that allows one to optionally choose the C#-style [CoroutineStart.UNDISPATCHED] behavior
      * whenever it is needed for efficiency.
      *
-     * This method should be generally exception-safe, an exception thrown from this method
+     * This method should generally be exception-safe. An exception thrown from this method
      * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state.
      *
      * **Note: This is an experimental api.** Execution semantics of coroutines may change in the future when this function returns `false`.
@@ -74,18 +74,18 @@
     /**
      * Dispatches execution of a runnable [block] onto another thread in the given [context].
      *
-     * This method should be generally exception-safe, an exception thrown from this method
+     * This method should generally be exception-safe. An exception thrown from this method
      * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state.
      */
     public abstract fun dispatch(context: CoroutineContext, block: Runnable)
 
     /**
-     * Dispatches execution of a runnable [block] onto another thread in the given [context]
-     * with a hint for dispatcher that current dispatch is triggered by [yield] call, so execution of this
+     * Dispatches execution of a runnable `block` onto another thread in the given `context`
+     * with a hint for the dispatcher that the current dispatch is triggered by a [yield] call, so that the execution of this
      * continuation may be delayed in favor of already dispatched coroutines.
      *
-     * **Implementation note** though yield marker may be passed as a part of [context], this
-     * is a separate method for performance reasons
+     * **Implementation note:** Though the `yield` marker may be passed as a part of [context], this
+     * is a separate method for performance reasons.
      *
      * @suppress **This an internal API and should not be used from general code.**
      */
@@ -93,9 +93,9 @@
     public open fun dispatchYield(context: CoroutineContext, block: Runnable) = dispatch(context, block)
 
     /**
-     * Returns continuation that wraps the original [continuation], thus intercepting all resumptions.
+     * Returns a continuation that wraps the provided [continuation], thus intercepting all resumptions.
      *
-     * This method should be generally exception-safe, an exception thrown from this method
+     * This method should generally be exception-safe. An exception thrown from this method
      * may leave the coroutines that use this dispatcher in the inconsistent and hard to debug state.
      */
     public final override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
@@ -104,13 +104,13 @@
     /**
      * @suppress **Error**: Operator '+' on two CoroutineDispatcher objects is meaningless.
      * CoroutineDispatcher is a coroutine context element and `+` is a set-sum operator for coroutine contexts.
-     * The dispatcher to the right of `+` just replaces the dispatcher the left of `+`.
+     * The dispatcher to the right of `+` just replaces the dispatcher to the left.
      */
     @Suppress("DeprecatedCallableAddReplaceWith")
     @Deprecated(
         message = "Operator '+' on two CoroutineDispatcher objects is meaningless. " +
             "CoroutineDispatcher is a coroutine context element and `+` is a set-sum operator for coroutine contexts. " +
-            "The dispatcher to the right of `+` just replaces the dispatcher the left of `+`.",
+            "The dispatcher to the right of `+` just replaces the dispatcher to the left.",
         level = DeprecationLevel.ERROR
     )
     public operator fun plus(other: CoroutineDispatcher) = other
diff --git a/kotlinx-coroutines-core/common/src/Yield.kt b/kotlinx-coroutines-core/common/src/Yield.kt
index 78ab27f..2272352 100644
--- a/kotlinx-coroutines-core/common/src/Yield.kt
+++ b/kotlinx-coroutines-core/common/src/Yield.kt
@@ -8,12 +8,12 @@
 import kotlin.coroutines.intrinsics.*
 
 /**
- * Yields a thread (or thread pool) of the current coroutine dispatcher to other coroutines to run.
- * If the coroutine dispatcher does not have its own thread pool (like [Dispatchers.Unconfined]) then this
- * function does nothing, but checks if the coroutine [Job] was completed.
+ * Yields the thread (or thread pool) of the current coroutine dispatcher to other coroutines to run.
+ * If the coroutine dispatcher does not have its own thread pool (like [Dispatchers.Unconfined]), this
+ * function does nothing but check if the coroutine's [Job] was completed.
  * This suspending function is cancellable.
  * If the [Job] of the current coroutine is cancelled or completed when this suspending function is invoked or while
- * this function is waiting for dispatching, it resumes with [CancellationException].
+ * this function is waiting for dispatch, it resumes with a [CancellationException].
  */
 public suspend fun yield(): Unit = suspendCoroutineUninterceptedOrReturn sc@ { uCont ->
     val context = uCont.context
diff --git a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
index 7b8f96b..a3be3ba 100644
--- a/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/AbstractChannel.kt
@@ -160,14 +160,24 @@
         val result = offerInternal(element)
         return when {
             result === OFFER_SUCCESS -> true
-            // We should check for closed token on offer as well, otherwise offer won't be linearizable
-            // in the face of concurrent close()
-            result === OFFER_FAILED -> throw closedForSend?.sendException?.let { recoverStackTrace(it) } ?: return false
-            result is Closed<*> -> throw recoverStackTrace(result.sendException)
+            result === OFFER_FAILED -> {
+                // We should check for closed token on offer as well, otherwise offer won't be linearizable
+                // in the face of concurrent close()
+                // See https://github.com/Kotlin/kotlinx.coroutines/issues/359
+                throw recoverStackTrace(helpCloseAndGetSendException(closedForSend ?: return false))
+            }
+            result is Closed<*> -> throw recoverStackTrace(helpCloseAndGetSendException(result))
             else -> error("offerInternal returned $result")
         }
     }
 
+    private fun helpCloseAndGetSendException(closed: Closed<*>): Throwable {
+        // To ensure linearizablity we must ALWAYS help close the channel when we observe that it was closed
+        // See https://github.com/Kotlin/kotlinx.coroutines/issues/1419
+        helpClose(closed)
+        return closed.sendException
+    }
+
     private suspend fun sendSuspend(element: E): Unit = suspendAtomicCancellableCoroutine sc@ { cont ->
         loop@ while (true) {
             if (full) {
@@ -179,8 +189,7 @@
                         return@sc
                     }
                     enqueueResult is Closed<*> -> {
-                        helpClose(enqueueResult)
-                        cont.resumeWithException(enqueueResult.sendException)
+                        cont.helpCloseAndResumeWithSendException(enqueueResult)
                         return@sc
                     }
                     enqueueResult === ENQUEUE_FAILED -> {} // try to offer instead
@@ -197,8 +206,7 @@
                 }
                 offerResult === OFFER_FAILED -> continue@loop
                 offerResult is Closed<*> -> {
-                    helpClose(offerResult)
-                    cont.resumeWithException(offerResult.sendException)
+                    cont.helpCloseAndResumeWithSendException(offerResult)
                     return@sc
                 }
                 else -> error("offerInternal returned $offerResult")
@@ -206,6 +214,11 @@
         }
     }
 
+    private fun Continuation<*>.helpCloseAndResumeWithSendException(closed: Closed<*>) {
+        helpClose(closed)
+        resumeWithException(closed.sendException)
+    }
+
     /**
      * Result is:
      * * null -- successfully enqueued
@@ -230,23 +243,17 @@
 
     public override fun close(cause: Throwable?): Boolean {
         val closed = Closed<E>(cause)
-
         /*
          * Try to commit close by adding a close token to the end of the queue.
          * Successful -> we're now responsible for closing receivers
          * Not successful -> help closing pending receivers to maintain invariant
          * "if (!close()) next send will throw"
          */
-        val closeAdded = queue.addLastIfPrev(closed, { it !is Closed<*> })
-        if (!closeAdded) {
-            val actualClosed = queue.prevNode as Closed<*>
-            helpClose(actualClosed)
-            return false
-        }
-
-        helpClose(closed)
-        invokeOnCloseHandler(cause)
-        return true
+        val closeAdded = queue.addLastIfPrev(closed) { it !is Closed<*> }
+        val actuallyClosed = if (closeAdded) closed else queue.prevNode as Closed<*>
+        helpClose(actuallyClosed)
+        if (closeAdded) invokeOnCloseHandler(cause)
+        return closeAdded // true if we have closed
     }
 
     private fun invokeOnCloseHandler(cause: Throwable?) {
@@ -370,10 +377,7 @@
                         select.disposeOnSelect(node)
                         return
                     }
-                    enqueueResult is Closed<*> -> {
-                        helpClose(enqueueResult)
-                        throw recoverStackTrace(enqueueResult.sendException)
-                    }
+                    enqueueResult is Closed<*> -> throw recoverStackTrace(helpCloseAndGetSendException(enqueueResult))
                     enqueueResult === ENQUEUE_FAILED -> {} // try to offer
                     enqueueResult is Receive<*> -> {} // try to offer
                     else -> error("enqueueSend returned $enqueueResult ")
@@ -388,10 +392,7 @@
                     block.startCoroutineUnintercepted(receiver = this, completion = select.completion)
                     return
                 }
-                offerResult is Closed<*> -> {
-                    helpClose(offerResult)
-                    throw recoverStackTrace(offerResult.sendException)
-                }
+                offerResult is Closed<*> -> throw recoverStackTrace(helpCloseAndGetSendException(offerResult))
                 else -> error("offerSelectInternal returned $offerResult")
             }
         }
@@ -432,7 +433,7 @@
 
     private class SendSelect<E, R>(
         override val pollResult: Any?,
-        @JvmField val channel: SendChannel<E>,
+        @JvmField val channel: AbstractSendChannel<E>,
         @JvmField val select: SelectInstance<R>,
         @JvmField val block: suspend (SendChannel<E>) -> R
     ) : Send(), DisposableHandle {
diff --git a/kotlinx-coroutines-core/common/src/channels/Channel.kt b/kotlinx-coroutines-core/common/src/channels/Channel.kt
index f13a15c..07e05f0 100644
--- a/kotlinx-coroutines-core/common/src/channels/Channel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Channel.kt
@@ -22,8 +22,8 @@
  */
 public interface SendChannel<in E> {
     /**
-     * Returns `true` if this channel was closed by invocation of [close] and thus
-     * the [send] and [offer] attempts throws exception.
+     * Returns `true` if this channel was closed by an invocation of [close]. This means that
+     * calling [send] or [offer] will result in an exception.
      *
      * **Note: This is an experimental api.** This property may change its semantics and/or name in the future.
      */
@@ -31,8 +31,8 @@
     public val isClosedForSend: Boolean
 
     /**
-     * Returns `true` if the channel is full (out of capacity) and the [send] attempt will suspend.
-     * This function returns `false` for [isClosedForSend] channel.
+     * Returns `true` if the channel is full (out of capacity), which means that an attempt to [send] will suspend.
+     * This function returns `false`  if the channel [is closed for `send`][isClosedForSend].
      *
      * @suppress **Will be removed in next releases, no replacement.**
      */
@@ -41,74 +41,76 @@
     public val isFull: Boolean
 
     /**
-     * Adds [element] into to this channel, suspending the caller while the buffer of this channel is full
-     * or if it does not exist, or throws exception if the channel [isClosedForSend] (see [close] for details).
+     * Sends the specified [element] to this channel, suspending the caller while the buffer of this channel is full
+     * or if it does not exist, or throws an exception if the channel [is closed for `send`][isClosedForSend] (see [close] for details).
      *
-     * Note that closing a channel _after_ this function had suspended does not cause this suspended send invocation
+     * Note that closing a channel _after_ this function has suspended does not cause this suspended [send] invocation
      * to abort, because closing a channel is conceptually like sending a special "close token" over this channel.
-     * All elements that are sent over the channel are delivered in first-in first-out order. The element that
-     * is being sent will get delivered to receivers before a close token.
+     * All elements sent over the channel are delivered in first-in first-out order. The sent element
+     * will be delivered to receivers before the close token.
      *
      * This suspending function is cancellable. If the [Job] of the current coroutine is cancelled or completed while this
-     * function is suspended, this function immediately resumes with [CancellationException].
+     * function is suspended, this function immediately resumes with a [CancellationException].
      *
-     * *Cancellation of suspended send is atomic* -- when this function
-     * throws [CancellationException] it means that the [element] was not sent to this channel.
+     * *Cancellation of suspended `send` is atomic*: when this function
+     * throws a [CancellationException], it means that the [element] was not sent to this channel.
      * As a side-effect of atomic cancellation, a thread-bound coroutine (to some UI thread, for example) may
-     * continue to execute even after it was cancelled from the same thread in the case when this send operation
+     * continue to execute even after it was cancelled from the same thread in the case when this `send` operation
      * was already resumed and the continuation was posted for execution to the thread's queue.
      *
      * Note that this function does not check for cancellation when it is not suspended.
      * Use [yield] or [CoroutineScope.isActive] to periodically check for cancellation in tight loops if needed.
      *
-     * This function can be used in [select] invocation with [onSend] clause.
+     * This function can be used in [select] invocations with the [onSend] clause.
      * Use [offer] to try sending to this channel without waiting.
      */
     public suspend fun send(element: E)
 
     /**
-     * Clause for [select] expression of [send] suspending function that selects when the element that is specified
-     * as parameter is sent to the channel. When the clause is selected the reference to this channel
+     * Clause for the [select] expression of the [send] suspending function that selects when the element that is specified
+     * as the parameter is sent to the channel. When the clause is selected, the reference to this channel
      * is passed into the corresponding block.
      *
-     * The [select] invocation fails with exception if the channel [isClosedForSend] (see [close] for details).
+     * The [select] invocation fails with an exception if the channel [is closed for `send`][isClosedForSend] (see [close] for details).
      */
     public val onSend: SelectClause2<E, SendChannel<E>>
 
     /**
-     * Adds [element] into this queue if it is possible to do so immediately without violating capacity restrictions
-     * and returns `true`. Otherwise, it returns `false` immediately
-     * or throws exception if the channel [isClosedForSend] (see [close] for details).
+     * Immediately adds the specified [element] to this channel, if this doesn't violate its capacity restrictions,
+     * and returns `true`. Otherwise, just returns `false`. This is a synchronous variant of [send] which backs off
+     * in situations when `send` suspends.
+     *
+     * Throws an exception if the channel [is closed for `send`][isClosedForSend] (see [close] for details).
      */
     public fun offer(element: E): Boolean
 
     /**
      * Closes this channel.
-     * This is an idempotent operation -- subsequent invocations of this function have no effect and return `false`.
+     * This is an idempotent operation &mdash; subsequent invocations of this function have no effect and return `false`.
      * Conceptually, its sends a special "close token" over this channel.
      *
-     * Immediately after invocation of this function
+     * Immediately after invocation of this function,
      * [isClosedForSend] starts returning `true`. However, [isClosedForReceive][ReceiveChannel.isClosedForReceive]
      * on the side of [ReceiveChannel] starts returning `true` only after all previously sent elements
      * are received.
      *
-     * A channel that was closed without a [cause] throws [ClosedSendChannelException] on attempts to send
-     * and [ClosedReceiveChannelException] on attempts to receive.
+     * A channel that was closed without a [cause] throws a [ClosedSendChannelException] on attempts to [send] or [offer]
+     * and [ClosedReceiveChannelException] on attempts to [receive][ReceiveChannel.receive].
      * A channel that was closed with non-null [cause] is called a _failed_ channel. Attempts to send or
      * receive on a failed channel throw the specified [cause] exception.
      */
     public fun close(cause: Throwable? = null): Boolean
 
     /**
-     * Registers handler which is synchronously invoked once the channel is [closed][close]
-     * or receiving side of this channel is [cancelled][ReceiveChannel.cancel].
-     * Only one handler can be attached to the channel during channel's lifetime.
-     * Handler is invoked when [isClosedForSend] starts to return `true`.
-     * If channel is already closed, handler is invoked immediately.
+     * Registers a [handler] which is synchronously invoked once the channel is [closed][close]
+     * or the receiving side of this channel is [cancelled][ReceiveChannel.cancel].
+     * Only one handler can be attached to a channel during its lifetime.
+     * The `handler` is invoked when [isClosedForSend] starts to return `true`.
+     * If the channel is closed already, the handler is invoked immediately.
      *
      * The meaning of `cause` that is passed to the handler:
-     * * `null` if channel was closed or cancelled without corresponding argument
-     * * close or cancel cause otherwise.
+     * * `null` if the channel was closed or cancelled without the corresponding argument
+     * * the cause of `close` or `cancel` otherwise.
      *
      * Example of usage (exception handling is omitted):
      * ```
@@ -128,7 +130,7 @@
      *
      * **Note: This is an experimental api.** This function may change its semantics, parameters or return type in the future.
      *
-     * @throws UnsupportedOperationException if underlying channel doesn't support [invokeOnClose].
+     * @throws UnsupportedOperationException if the underlying channel doesn't support [invokeOnClose].
      * Implementation note: currently, [invokeOnClose] is unsupported only by Rx-like integrations
      *
      * @throws IllegalStateException if another handler was already registered
@@ -143,9 +145,9 @@
 public interface ReceiveChannel<out E> {
     /**
      * Returns `true` if this channel was closed by invocation of [close][SendChannel.close] on the [SendChannel]
-     * side and all previously sent items were already received, so that the [receive] attempt
-     * throws [ClosedReceiveChannelException]. If the channel was closed because of the exception, it
-     * is considered closed, too, but it is called a _failed_ channel. All suspending attempts to receive
+     * side and all previously sent items were already received. This means that calling [receive]
+     * will result in a [ClosedReceiveChannelException]. If the channel was closed because of an exception, it
+     * is considered closed, too, but is called a _failed_ channel. All suspending attempts to receive
      * an element from a failed channel throw the original [close][SendChannel.close] cause exception.
      *
      * **Note: This is an experimental api.** This property may change its semantics and/or name in the future.
@@ -154,61 +156,61 @@
     public val isClosedForReceive: Boolean
 
     /**
-     * Returns `true` if the channel is empty (contains no elements) and the [receive] attempt will suspend.
-     * This function returns `false` for [isClosedForReceive] channel.
+     * Returns `true` if the channel is empty (contains no elements), which means that an attempt to [receive] will suspend.
+     * This function returns `false` if the channel [is closed for `receive`][isClosedForReceive].
      */
     @ExperimentalCoroutinesApi
     public val isEmpty: Boolean
 
     /**
-     * Retrieves and removes the element from this channel suspending the caller while this channel is empty,
-     * or throws [ClosedReceiveChannelException] if the channel [isClosedForReceive].
-     * If the channel was closed because of the exception, it is called a _failed_ channel and this function
-     * throws the original [close][SendChannel.close] cause exception.
+     * Retrieves and removes an element from this channel if it's not empty, or suspends the caller while the channel is empty,
+     * or throws a [ClosedReceiveChannelException] if the channel [is closed for `receive`][isClosedForReceive].
+     * If the channel was closed because of an exception, it is called a _failed_ channel and this function
+     * will throw the original [close][SendChannel.close] cause exception.
      *
      * This suspending function is cancellable. If the [Job] of the current coroutine is cancelled or completed while this
-     * function is suspended, this function immediately resumes with [CancellationException].
+     * function is suspended, this function immediately resumes with a [CancellationException].
      *
-     * *Cancellation of suspended receive is atomic* -- when this function
-     * throws [CancellationException] it means that the element was not retrieved from this channel.
+     * *Cancellation of suspended `receive` is atomic*: when this function
+     * throws a [CancellationException], it means that the element was not retrieved from this channel.
      * As a side-effect of atomic cancellation, a thread-bound coroutine (to some UI thread, for example) may
-     * continue to execute even after it was cancelled from the same thread in the case when this receive operation
+     * continue to execute even after it was cancelled from the same thread in the case when this `receive` operation
      * was already resumed and the continuation was posted for execution to the thread's queue.
      *
      * Note that this function does not check for cancellation when it is not suspended.
      * Use [yield] or [CoroutineScope.isActive] to periodically check for cancellation in tight loops if needed.
      *
-     * This function can be used in [select] invocation with [onReceive] clause.
+     * This function can be used in [select] invocations with the [onReceive] clause.
      * Use [poll] to try receiving from this channel without waiting.
      */
     public suspend fun receive(): E
 
     /**
-     * Clause for [select] expression of [receive] suspending function that selects with the element that
-     * is received from the channel.
-     * The [select] invocation fails with exception if the channel
-     * [isClosedForReceive] (see [close][SendChannel.close] for details).
+     * Clause for the [select] expression of the [receive] suspending function that selects with the element
+     * received from the channel.
+     * The [select] invocation fails with an exception if the channel
+     * [is closed for `receive`][isClosedForReceive] (see [close][SendChannel.close] for details).
      */
     public val onReceive: SelectClause1<E>
 
     /**
-     * Retrieves and removes the element from this channel suspending the caller while this channel is empty,
-     * or returns `null` if the channel is [closed][isClosedForReceive] without cause
+     * Retrieves and removes an element from this channel if it's not empty, or suspends the caller while the channel is empty,
+     * or returns `null` if the channel is [closed for `receive`][isClosedForReceive] without cause,
      * or throws the original [close][SendChannel.close] cause exception if the channel has _failed_.
      *
      * This suspending function is cancellable. If the [Job] of the current coroutine is cancelled or completed while this
-     * function is suspended, this function immediately resumes with [CancellationException].
+     * function is suspended, this function immediately resumes with a [CancellationException].
      *
-     * *Cancellation of suspended receive is atomic* -- when this function
-     * throws [CancellationException] it means that the element was not retrieved from this channel.
+     * *Cancellation of suspended `receive` is atomic*: when this function
+     * throws a [CancellationException], it means that the element was not retrieved from this channel.
      * As a side-effect of atomic cancellation, a thread-bound coroutine (to some UI thread, for example) may
-     * continue to execute even after it was cancelled from the same thread in the case when this receive operation
+     * continue to execute even after it was cancelled from the same thread in the case when this `receive` operation
      * was already resumed and the continuation was posted for execution to the thread's queue.
      *
      * Note that this function does not check for cancellation when it is not suspended.
      * Use [yield] or [CoroutineScope.isActive] to periodically check for cancellation in tight loops if needed.
      *
-     * This function can be used in [select] invocation with [onReceiveOrNull] clause.
+     * This function can be used in [select] invocations with the [onReceiveOrNull] clause.
      * Use [poll] to try receiving from this channel without waiting.
      *
      * @suppress **Deprecated**: in favor of receiveOrClosed and receiveOrNull extension.
@@ -224,9 +226,9 @@
     public suspend fun receiveOrNull(): E?
 
     /**
-     * Clause for [select] expression of [receiveOrNull] suspending function that selects with the element that
-     * is received from the channel or selects with `null` if the channel
-     * [isClosedForReceive] without cause. The [select] invocation fails with
+     * Clause for the [select] expression of the [receiveOrNull] suspending function that selects with the element
+     * received from the channel or `null` if the channel is
+     * [closed for `receive`][isClosedForReceive] without a cause. The [select] invocation fails with
      * the original [close][SendChannel.close] cause exception if the channel has _failed_.
      *
      * @suppress **Deprecated**: in favor of onReceiveOrClosed and onReceiveOrNull extension.
@@ -242,23 +244,23 @@
     public val onReceiveOrNull: SelectClause1<E?>
 
     /**
-     * Retrieves and removes the element from this channel suspending the caller while this channel [isEmpty].
-     * This method returns [ValueOrClosed] with a value if element was successfully retrieved from the channel
-     * or [ValueOrClosed] with close cause if channel was closed.
+     * Retrieves and removes an element from this channel if it's not empty, or suspends the caller while this channel is empty.
+     * This method returns [ValueOrClosed] with the value of an element successfully retrieved from the channel
+     * or the close cause if the channel was closed.
      *
      * This suspending function is cancellable. If the [Job] of the current coroutine is cancelled or completed while this
-     * function is suspended, this function immediately resumes with [CancellationException].
+     * function is suspended, this function immediately resumes with a [CancellationException].
      *
-     * *Cancellation of suspended receive is atomic* -- when this function
-     * throws [CancellationException] it means that the element was not retrieved from this channel.
+     * *Cancellation of suspended `receive` is atomic*: when this function
+     * throws a [CancellationException], it means that the element was not retrieved from this channel.
      * As a side-effect of atomic cancellation, a thread-bound coroutine (to some UI thread, for example) may
      * continue to execute even after it was cancelled from the same thread in the case when this receive operation
      * was already resumed and the continuation was posted for execution to the thread's queue.
      *
-     * Note, that this function does not check for cancellation when it is not suspended.
+     * Note that this function does not check for cancellation when it is not suspended.
      * Use [yield] or [CoroutineScope.isActive] to periodically check for cancellation in tight loops if needed.
      *
-     * This function can be used in [select] invocation with [onReceiveOrClosed] clause.
+     * This function can be used in [select] invocations with the [onReceiveOrClosed] clause.
      * Use [poll] to try receiving from this channel without waiting.
      *
      * @suppress *This is an internal API, do not use*: Inline classes ABI is not stable yet and
@@ -268,9 +270,9 @@
     public suspend fun receiveOrClosed(): ValueOrClosed<E>
 
     /**
-     * Clause for [select] expression of [receiveOrClosed] suspending function that selects with the [ValueOrClosed] with a value
-     * that is received from the channel or selects with [ValueOrClosed] with a close cause if the channel
-     * [isClosedForReceive].
+     * Clause for the [select] expression of the [receiveOrClosed] suspending function that selects with the [ValueOrClosed] with a value
+     * that is received from the channel or with a close cause if the channel
+     * [is closed for `receive`][isClosedForReceive].
      *
      * @suppress *This is an internal API, do not use*: Inline classes ABI is not stable yet and
      *            [KT-27524](https://youtrack.jetbrains.com/issue/KT-27524) needs to be fixed.
@@ -279,15 +281,15 @@
     public val onReceiveOrClosed: SelectClause1<ValueOrClosed<E>>
 
     /**
-     * Retrieves and removes the element from this channel, or returns `null` if this channel is empty
-     * or is [isClosedForReceive] without cause.
+     * Retrieves and removes an element from this channel if its not empty, or returns `null` if the channel is empty
+     * or is [is closed for `receive`][isClosedForReceive] without a cause.
      * It throws the original [close][SendChannel.close] cause exception if the channel has _failed_.
      */
     public fun poll(): E?
 
     /**
-     * Returns new iterator to receive elements from this channels using `for` loop.
-     * Iteration completes normally when the channel is [isClosedForReceive] without cause and
+     * Returns a new iterator to receive elements from this channel using a `for` loop.
+     * Iteration completes normally when the channel [is closed for `receive`][isClosedForReceive] without a cause and
      * throws the original [close][SendChannel.close] cause exception if the channel has _failed_.
      */
     public operator fun iterator(): ChannelIterator<E>
@@ -297,14 +299,14 @@
      * This function closes the channel and removes all buffered sent elements from it.
      *
      * A cause can be used to specify an error message or to provide other details on
-     * a cancellation reason for debugging purposes.
+     * the cancellation reason for debugging purposes.
      * If the cause is not specified, then an instance of [CancellationException] with a
      * default message is created to [close][SendChannel.close] the channel.
      *
      * Immediately after invocation of this function [isClosedForReceive] and
      * [isClosedForSend][SendChannel.isClosedForSend]
-     * on the side of [SendChannel] start returning `true`. All attempts to send to this channel
-     * or receive from this channel will throw [CancellationException].
+     * on the side of [SendChannel] start returning `true`. Any attempt to send to or receive from this channel
+     * will lead to a [CancellationException].
      */
     public fun cancel(cause: CancellationException? = null)
 
@@ -322,8 +324,8 @@
 }
 
 /**
- * A discriminated union of [ReceiveChannel.receiveOrClosed] result,
- * that encapsulates either successfully received element of type [T] from the channel or a close cause.
+ * A discriminated union of [ReceiveChannel.receiveOrClosed] result
+ * that encapsulates either an element of type [T] successfully received from the channel or a close cause.
  *
  * :todo: Do not make it public before resolving todos in the code of this class.
  *
@@ -335,36 +337,36 @@
 public inline class ValueOrClosed<out T>
 internal constructor(private val holder: Any?) {
     /**
-     * Returns `true` if this instance represents received element.
+     * Returns `true` if this instance represents a received element.
      * In this case [isClosed] returns `false`.
      * todo: it is commented for now, because it is not used
      */
     //public val isValue: Boolean get() = holder !is Closed
 
     /**
-     * Returns `true` if this instance represents close cause.
+     * Returns `true` if this instance represents a close cause.
      * In this case [isValue] returns `false`.
      */
     public val isClosed: Boolean get() = holder is Closed
 
     /**
-     * Returns received value if this instance represents received value or throws [IllegalStateException] otherwise.
+     * Returns the received value if this instance represents a received value, or throws an [IllegalStateException] otherwise.
      *
-     * :todo: Decide if it is needed how it shall be named with relation to [valueOrThrow]:
+     * :todo: Decide, if it is needed, how it shall be named with relation to [valueOrThrow]:
      *
-     * So we have the following methods on ValueOrClosed: `value`, `valueOrNull`, `valueOrThrow`.
-     * On the other hand, the channel has the following receive variants:
+     * So we have the following methods on `ValueOrClosed`: `value`, `valueOrNull`, `valueOrThrow`.
+     * On the other hand, the channel has the following `receive` variants:
      *  * `receive` which corresponds to `receiveOrClosed().valueOrThrow`... huh?
      *  * `receiveOrNull` which corresponds to `receiveOrClosed().valueOrNull`
      *  * `receiveOrClosed`
-     * For the sake of consider dropping this version of `value` and rename [valueOrThrow] to simply `value`.
+     * For the sake of simplicity consider dropping this version of `value` and rename [valueOrThrow] to simply `value`.
      */
     @Suppress("UNCHECKED_CAST")
     public val value: T
         get() = if (holder is Closed) error(DEFAULT_CLOSE_MESSAGE) else holder as T
 
     /**
-     * Returns received value if this element represents received value or `null` otherwise.
+     * Returns the received value if this element represents a received value, or `null` otherwise.
      * :todo: Decide if it shall be made into extension that is available only for non-null T.
      * Note: it might become inconsistent with kotlin.Result
      */
@@ -373,9 +375,9 @@
         get() = if (holder is Closed) null else holder as T
 
     /**
-     * :todo: Decide if it is needed how it shall be named with relation to [value].
-     * Note, that valueOrThrow rethrows the cause adding no meaningful information about the callsite,
-     * so if one is sure that ValueOrClosed is always value, this very property should be used.
+     * :todo: Decide, if it is needed, how it shall be named with relation to [value].
+     * Note that `valueOrThrow` rethrows the cause adding no meaningful information about the call site,
+     * so if one is sure that `ValueOrClosed` always holds a value, this very property should be used.
      * Otherwise, it could be very hard to locate the source of the exception.
      * todo: it is commented for now, because it is not used
      */
@@ -384,8 +386,8 @@
     //    get() = if (holder is Closed) throw holder.exception else holder as T
 
     /**
-     * Returns close cause of the channel if this instance represents close cause or throws
-     * [IllegalStateException] otherwise.
+     * Returns the close cause of the channel if this instance represents a close cause, or throws
+     * an [IllegalStateException] otherwise.
      */
     @Suppress("UNCHECKED_CAST")
     public val closeCause: Throwable? get() =
@@ -429,17 +431,17 @@
 public interface ChannelIterator<out E> {
     /**
      * Returns `true` if the channel has more elements, suspending the caller while this channel is empty,
-     * or returns `false` if the channel [isClosedForReceive][ReceiveChannel.isClosedForReceive] without cause.
+     * or returns `false` if the channel [is closed for `receive`][ReceiveChannel.isClosedForReceive] without a cause.
      * It throws the original [close][SendChannel.close] cause exception if the channel has _failed_.
      *
-     * This function retrieves and removes the element from this channel for the subsequent invocation
+     * This function retrieves and removes an element from this channel for the subsequent invocation
      * of [next].
      *
      * This suspending function is cancellable. If the [Job] of the current coroutine is cancelled or completed while this
-     * function is suspended, this function immediately resumes with [CancellationException].
+     * function is suspended, this function immediately resumes with a [CancellationException].
      *
-     * *Cancellation of suspended receive is atomic* -- when this function
-     * throws [CancellationException] it means that the element was not retrieved from this channel.
+     * *Cancellation of suspended `receive` is atomic*: when this function
+     * throws a [CancellationException], it means that the element was not retrieved from this channel.
      * As a side-effect of atomic cancellation, a thread-bound coroutine (to some UI thread, for example) may
      * continue to execute even after it was cancelled from the same thread in the case when this receive operation
      * was already resumed and the continuation was posted for execution to the thread's queue.
@@ -463,9 +465,9 @@
     }
 
     /**
-     * Retrieves the element from the current iterator previously removed from the channel by preceding call to [hasNext] or
-     * throws [IllegalStateException] if [hasNext] was not invoked.
-     * [next] should only be used in pair with [hasNext]:
+     * Retrieves the element removed from the channel by a preceding call to [hasNext], or
+     * throws an [IllegalStateException] if [hasNext] was not invoked.
+     * This method should only be used in pair with [hasNext]:
      * ```
      * while (iterator.hasNext()) {
      *     val element = iterator.next()
@@ -473,64 +475,64 @@
      * }
      * ```
      *
-     * This method throws [ClosedReceiveChannelException] if the channel [isClosedForReceive][ReceiveChannel.isClosedForReceive] without cause.
+     * This method throws a [ClosedReceiveChannelException] if the channel [is closed for `receive`][ReceiveChannel.isClosedForReceive] without a cause.
      * It throws the original [close][SendChannel.close] cause exception if the channel has _failed_.
      */
     public operator fun next(): E
 }
 
 /**
- * Channel is a non-blocking primitive for communication between sender using [SendChannel] and receiver using [ReceiveChannel].
- * Conceptually, a channel is similar to [BlockingQueue][java.util.concurrent.BlockingQueue],
- * but it has suspending operations instead of blocking ones and it can be closed.
+ * Channel is a non-blocking primitive for communication between a sender (via [SendChannel]) and a receiver (via [ReceiveChannel]).
+ * Conceptually, a channel is similar to Java's [BlockingQueue][java.util.concurrent.BlockingQueue],
+ * but it has suspending operations instead of blocking ones and can be [closed][SendChannel.close].
  *
- * `Channel(capacity)` factory function is used to create channels of different kind depending on
- * the value of `capacity` integer:
+ * The `Channel(capacity)` factory function is used to create channels of different kinds depending on
+ * the value of the `capacity` integer:
  *
- * * When `capacity` is 0 -- it creates `RendezvousChannel`.
- *   This channel does not have any buffer at all. An element is transferred from sender
- *   to receiver only when [send] and [receive] invocations meet in time (rendezvous), so [send] suspends
- *   until another coroutine invokes [receive] and [receive] suspends until another coroutine invokes [send].
+ * * When `capacity` is 0 &mdash; it creates a `RendezvousChannel`.
+ *   This channel does not have any buffer at all. An element is transferred from the sender
+ *   to the receiver only when [send] and [receive] invocations meet in time (rendezvous), so [send] suspends
+ *   until another coroutine invokes [receive], and [receive] suspends until another coroutine invokes [send].
  *
- * * When `capacity` is [Channel.UNLIMITED] -- it creates `LinkedListChannel`.
- *   This is a channel with linked-list buffer of a unlimited capacity (limited only by available memory).
- *   Sender to this channel never suspends and [offer] always returns `true`.
+ * * When `capacity` is [Channel.UNLIMITED] &mdash; it creates a `LinkedListChannel`.
+ *   This channel has a linked-list buffer of unlimited capacity (limited only by available memory).
+ *   [Sending][send] to this channel never suspends, and [offer] always returns `true`.
  *
- * * When `capacity` is [Channel.CONFLATED] -- it creates `ConflatedChannel`.
+ * * When `capacity` is [Channel.CONFLATED] &mdash; it creates a `ConflatedChannel`.
  *   This channel buffers at most one element and conflates all subsequent `send` and `offer` invocations,
- *   so that the receiver always gets the most recently sent element.
- *   Back-to-send sent elements are _conflated_ -- only the the most recently sent element is received,
+ *   so that the receiver always gets the last element sent.
+ *   Back-to-send sent elements are _conflated_ &mdash; only the last sent element is received,
  *   while previously sent elements **are lost**.
- *   Sender to this channel never suspends and [offer] always returns `true`.
+ *   [Sending][send] to this channel never suspends, and [offer] always returns `true`.
  *
- * * When `capacity` is positive, but less than [UNLIMITED] -- it creates array-based channel with given capacity.
+ * * When `capacity` is positive but less than [UNLIMITED] &mdash; it creates an array-based channel with the specified capacity.
  *   This channel has an array buffer of a fixed `capacity`.
- *   Sender suspends only when buffer is full and receiver suspends only when buffer is empty.
+ *   [Sending][send] suspends only when the buffer is full, and [receiving][receive] suspends only when the buffer is empty.
  */
 public interface Channel<E> : SendChannel<E>, ReceiveChannel<E> {
     /**
-     * Constants for channel factory function `Channel()`.
+     * Constants for the channel factory function `Channel()`.
      */
     public companion object Factory {
         /**
-         * Requests channel with unlimited capacity buffer in `Channel(...)` factory function
+         * Requests a channel with an unlimited capacity buffer in the `Channel(...)` factory function
          */
         public const val UNLIMITED = Int.MAX_VALUE
 
         /**
-         * Requests rendezvous channel in `Channel(...)` factory function -- the `RendezvousChannel` gets created.
+         * Requests a rendezvous channel in the `Channel(...)` factory function &mdash; a `RendezvousChannel` gets created.
          */
         public const val RENDEZVOUS = 0
 
         /**
-         * Requests conflated channel in `Channel(...)` factory function -- the `ConflatedChannel` gets created.
+         * Requests a conflated channel in the `Channel(...)` factory function &mdash; a `ConflatedChannel` gets created.
          */
         public const val CONFLATED = -1
 
         /**
-         * Requests buffered channel with a default buffer capacity in `Channel(...)` factory function --
-         * the `ArrayChannel` gets created with a default capacity.
-         * This capacity is equal to 64 by default and can be overridden by setting
+         * Requests a buffered channel with the default buffer capacity in the `Channel(...)` factory function &mdash;
+         * an `ArrayChannel` gets created with the default capacity.
+         * The default capacity is 64 and can be overridden by setting
          * [DEFAULT_BUFFER_PROPERTY_NAME] on JVM.
          */
         public const val BUFFERED = -2
@@ -567,18 +569,18 @@
     }
 
 /**
- * Indicates attempt to [send][SendChannel.send] on [isClosedForSend][SendChannel.isClosedForSend] channel
+ * Indicates an attempt to [send][SendChannel.send] to a [isClosedForSend][SendChannel.isClosedForSend] channel
  * that was closed without a cause. A _failed_ channel rethrows the original [close][SendChannel.close] cause
  * exception on send attempts.
  *
- * This exception is a subclass of [IllegalStateException] because, conceptually, sender is responsible
- * for closing the channel and not be trying to send anything after the channel was close. Attempts to
- * send into the closed channel indicate logical error in the sender's code.
+ * This exception is a subclass of [IllegalStateException], because, conceptually, it is the sender's responsibility
+ * to close the channel and not try to send anything thereafter. Attempts to
+ * send to a closed channel indicate a logical error in the sender's code.
  */
 public class ClosedSendChannelException(message: String?) : IllegalStateException(message)
 
 /**
- * Indicates attempt to [receive][ReceiveChannel.receive] on [isClosedForReceive][ReceiveChannel.isClosedForReceive]
+ * Indicates an attempt to [receive][ReceiveChannel.receive] from a [isClosedForReceive][ReceiveChannel.isClosedForReceive]
  * channel that was closed without a cause. A _failed_ channel rethrows the original [close][SendChannel.close] cause
  * exception on receive attempts.
  *
diff --git a/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt b/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
index 3afc86c..2a73930 100644
--- a/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
+++ b/kotlinx-coroutines-core/common/src/channels/LinkedListChannel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.channels
@@ -29,8 +29,7 @@
             when {
                 result === OFFER_SUCCESS -> return OFFER_SUCCESS
                 result === OFFER_FAILED -> { // try to buffer
-                    val sendResult = sendBuffered(element)
-                    when (sendResult) {
+                    when (val sendResult = sendBuffered(element)) {
                         null -> return OFFER_SUCCESS
                         is Closed<*> -> return sendResult
                     }
diff --git a/kotlinx-coroutines-core/common/src/channels/Produce.kt b/kotlinx-coroutines-core/common/src/channels/Produce.kt
index a579d7a..59ebf52 100644
--- a/kotlinx-coroutines-core/common/src/channels/Produce.kt
+++ b/kotlinx-coroutines-core/common/src/channels/Produce.kt
@@ -8,19 +8,19 @@
 import kotlin.coroutines.*
 
 /**
- * Scope for [produce][CoroutineScope.produce] coroutine builder.
+ * Scope for the [produce][CoroutineScope.produce] coroutine builder.
  *
- * **Note: This is an experimental api.** Behaviour of producers that work as children in a parent scope with respect
+ * **Note: This is an experimental api.** Behavior of producers that work as children in a parent scope with respect
  *        to cancellation and error handling may change in the future.
  */
 @ExperimentalCoroutinesApi
 public interface ProducerScope<in E> : CoroutineScope, SendChannel<E> {
     /**
-     * A reference to the channel that this coroutine [sends][send] elements to.
+     * A reference to the channel this coroutine [sends][send] elements to.
      * It is provided for convenience, so that the code in the coroutine can refer
-     * to the channel as `channel` as apposed to `this`.
+     * to the channel as `channel` as opposed to `this`.
      * All the [SendChannel] functions on this interface delegate to
-     * the channel instance returned by this function.
+     * the channel instance returned by this property.
      */
     val channel: SendChannel<E>
 }
@@ -29,9 +29,9 @@
  * Suspends the current coroutine until the channel is either [closed][SendChannel.close] or [cancelled][ReceiveChannel.cancel]
  * and invokes the given [block] before resuming the coroutine.
  *
- * Note that when producer channel is cancelled this function resumes with cancellation exception,
- * so putting the code after calling this function would not lead to its execution in case of cancellation.
- * That is why this code takes a lambda parameter.
+ * Note that when the producer channel is cancelled, this function resumes with a cancellation exception.
+ * Therefore, in case of cancellation, no code after the call to this function will be executed.
+ * That's why this function takes a lambda parameter.
  *
  * Example of usage:
  * ```
@@ -43,7 +43,7 @@
  */
 @ExperimentalCoroutinesApi
 public suspend fun ProducerScope<*>.awaitClose(block: () -> Unit = {}) {
-    check(kotlin.coroutines.coroutineContext[Job] === this) { "awaitClose() can be invoke only from the producer context" }
+    check(kotlin.coroutines.coroutineContext[Job] === this) { "awaitClose() can only be invoked from the producer context" }
     try {
         suspendCancellableCoroutine<Unit> { cont ->
             invokeOnClose {
@@ -56,28 +56,28 @@
 }
 
 /**
- * Launches new coroutine to produce a stream of values by sending them to a channel
+ * Launches a new coroutine to produce a stream of values by sending them to a channel
  * and returns a reference to the coroutine as a [ReceiveChannel]. This resulting
  * object can be used to [receive][ReceiveChannel.receive] elements produced by this coroutine.
  *
- * The scope of the coroutine contains [ProducerScope] interface, which implements
- * both [CoroutineScope] and [SendChannel], so that coroutine can invoke
+ * The scope of the coroutine contains the [ProducerScope] interface, which implements
+ * both [CoroutineScope] and [SendChannel], so that the coroutine can invoke
  * [send][SendChannel.send] directly. The channel is [closed][SendChannel.close]
  * when the coroutine completes.
  * The running coroutine is cancelled when its receive channel is [cancelled][ReceiveChannel.cancel].
  *
- * Coroutine context is inherited from a [CoroutineScope], additional context elements can be specified with [context] argument.
- * If the context does not have any dispatcher nor any other [ContinuationInterceptor], then [Dispatchers.Default] is used.
- * The parent job is inherited from a [CoroutineScope] as well, but it can also be overridden
- * with corresponding [coroutineContext] element.
+ * The coroutine context is inherited from this [CoroutineScope]. Additional context elements can be specified with the [context] argument.
+ * If the context does not have any dispatcher or other [ContinuationInterceptor], then [Dispatchers.Default] is used.
+ * The parent job is inherited from the [CoroutineScope] as well, but it can also be overridden
+ * with a corresponding [coroutineContext] element.
  *
- * Uncaught exceptions in this coroutine close the channel with this exception as a cause and
- * the resulting channel becomes _failed_, so that any attempt to receive from such a channel throws exception.
+ * Any uncaught exception in this coroutine will close the channel with this exception as the cause and
+ * the resulting channel will become _failed_, so that any attempt to receive from it thereafter will throw an exception.
  *
  * The kind of the resulting channel depends on the specified [capacity] parameter.
- * See [Channel] interface documentation for details.
+ * See the [Channel] interface documentation for details.
  *
- * See [newCoroutineContext] for a description of debugging facilities that are available for newly created coroutine.
+ * See [newCoroutineContext] for a description of debugging facilities available for newly created coroutines.
  *
  * **Note: This is an experimental api.** Behaviour of producers that work as children in a parent scope with respect
  *        to cancellation and error handling may change in the future.
@@ -100,9 +100,9 @@
 }
 
 /**
- * This an internal API and should not be used from general code.**
- * onCompletion parameter will be redesigned.
- * If you have to use `onCompletion` operator, please report to https://github.com/Kotlin/kotlinx.coroutines/issues/.
+ * **This is an internal API and should not be used from general code.**
+ * The `onCompletion` parameter will be redesigned.
+ * If you have to use the `onCompletion` operator, please report to https://github.com/Kotlin/kotlinx.coroutines/issues/.
  * As a temporary solution, [invokeOnCompletion][Job.invokeOnCompletion] can be used instead:
  * ```
  * fun <E> ReceiveChannel<E>.myOperator(): ReceiveChannel<E> = GlobalScope.produce(Dispatchers.Unconfined) {
diff --git a/kotlinx-coroutines-core/common/src/flow/Builders.kt b/kotlinx-coroutines-core/common/src/flow/Builders.kt
index 2b03e33..4b9fa6b 100644
--- a/kotlinx-coroutines-core/common/src/flow/Builders.kt
+++ b/kotlinx-coroutines-core/common/src/flow/Builders.kt
@@ -20,17 +20,18 @@
  *
  * Example of usage:
  * ```
- * fun fibonacci(): Flow<Long> = flow {
- *     emit(1L)
- *     var f1 = 1L
- *     var f2 = 1L
- *     repeat(100) {
- *         var tmp = f1
- *         f1 = f2
- *         f2 += tmp
- *         emit(f1)
+ * fun fibonacci(): Flow<BigInteger> = flow {
+ *     var x = BigInteger.ZERO
+ *     var y = BigInteger.ONE
+ *     while (true) {
+ *         emit(x)
+ *         x = y.also {
+ *             y += x
+ *         }
  *     }
  * }
+ *
+ * fibonacci().take(100).collect { println(it) }
  * ```
  *
  * `emit` should happen strictly in the dispatchers of the [block] in order to preserve the flow context.
@@ -85,7 +86,7 @@
 }
 
 /**
- * Creates a flow that produces values from the given iterable.
+ * Creates a flow that produces values from the given iterator.
  */
 public fun <T> Iterator<T>.asFlow(): Flow<T> = flow {
     forEach { value ->
@@ -103,7 +104,12 @@
 }
 
 /**
- * Creates a flow that produces values from the given array of elements.
+ * Creates a flow that produces values from the specified `vararg`-arguments.
+ *
+ * Example of usage:
+ * ```
+ * flowOf(1, 2, 3)
+ * ```
  */
 public fun <T> flowOf(vararg elements: T): Flow<T> = flow {
     for (element in elements) {
@@ -112,12 +118,12 @@
 }
 
 /**
- * Creates flow that produces a given [value].
+ * Creates flow that produces the given [value].
  */
 public fun <T> flowOf(value: T): Flow<T> = flow {
     /*
      * Implementation note: this is just an "optimized" overload of flowOf(vararg)
-     * which significantly reduce the footprint of widespread single-value flows.
+     * which significantly reduces the footprint of widespread single-value flows.
      */
     emit(value)
 }
@@ -141,7 +147,7 @@
 }
 
 /**
- * Creates flow that produces values from the given array.
+ * Creates a flow that produces values from the array.
  */
 public fun IntArray.asFlow(): Flow<Int> = flow {
     forEach { value ->
@@ -150,7 +156,7 @@
 }
 
 /**
- * Creates flow that produces values from the given array.
+ * Creates a flow that produces values from the array.
  */
 public fun LongArray.asFlow(): Flow<Long> = flow {
     forEach { value ->
@@ -159,7 +165,7 @@
 }
 
 /**
- * Creates flow that produces values from the given range.
+ * Creates a flow that produces values from the range.
  */
 public fun IntRange.asFlow(): Flow<Int> = flow {
     forEach { value ->
@@ -168,7 +174,7 @@
 }
 
 /**
- * Creates flow that produces values from the given range.
+ * Creates a flow that produces values from the range.
  */
 public fun LongRange.asFlow(): Flow<Long> = flow {
     forEach { value ->
@@ -197,20 +203,20 @@
 
 /**
  * Creates an instance of the cold [Flow] with elements that are sent to a [SendChannel]
- * that is provided to the builder's [block] of code via [ProducerScope]. It allows elements to be
- * produced by the code that is running in a different context or running concurrently.
- * The resulting flow is _cold_, which means that [block] is called on each call of a terminal operator
- * on the resulting flow.
+ * provided to the builder's [block] of code via [ProducerScope]. It allows elements to be
+ * produced by code that is running in a different context or concurrently.
+ * The resulting flow is _cold_, which means that [block] is called every time a terminal operator
+ * is applied to the resulting flow.
  *
  * This builder ensures thread-safety and context preservation, thus the provided [ProducerScope] can be used
  * concurrently from different contexts.
- * The resulting flow completes as soon as the code in the [block] and all its children complete.
+ * The resulting flow completes as soon as the code in the [block] and all its children completes.
  * Use [awaitClose] as the last statement to keep it running.
- * For more detailed example please refer to [callbackFlow] documentation.
+ * A more detailed example is provided in the documentation of [callbackFlow].
  *
- * A channel with [default][Channel.BUFFERED] buffer size is used. Use [buffer] operator on the
- * resulting flow to specify a value other than default and to control what happens when data is produced faster
- * than it is consumed, that is to control backpressure behavior.
+ * A channel with the [default][Channel.BUFFERED] buffer size is used. Use the [buffer] operator on the
+ * resulting flow to specify a user-defined value and to control what happens when data is produced faster
+ * than consumed, i.e. to control the back-pressure behavior.
  *
  * Adjacent applications of [channelFlow], [flowOn], [buffer], [produceIn], and [broadcastIn] are
  * always fused so that only one properly configured channel is used for execution.
@@ -245,22 +251,22 @@
 
 /**
  * Creates an instance of the cold [Flow] with elements that are sent to a [SendChannel]
- * that is provided to the builder's [block] of code via [ProducerScope]. It allows elements to be
- * produced by the code that is running in a different context or running concurrently.
+ * provided to the builder's [block] of code via [ProducerScope]. It allows elements to be
+ * produced by code that is running in a different context or concurrently.
  *
- * The resulting flow is _cold_, which means that [block] is called on each call of a terminal operator
- * on the resulting flow.
+ * The resulting flow is _cold_, which means that [block] is called every time a terminal operator
+ * is applied to the resulting flow.
  *
  * This builder ensures thread-safety and context preservation, thus the provided [ProducerScope] can be used
- * from any context, e.g. from the callback-based API.
- * The resulting flow completes as soon as the code in the [block] and all its children complete.
+ * from any context, e.g. from a callback-based API.
+ * The resulting flow completes as soon as the code in the [block] and all its children completes.
  * Use [awaitClose] as the last statement to keep it running.
- * [awaitClose] argument is called when either flow consumer cancels flow collection
- * or when callback-based API invokes [SendChannel.close] manually.
+ * The [awaitClose] argument is called either when a flow consumer cancels the flow collection
+ * or when a callback-based API invokes [SendChannel.close] manually.
  *
- * A channel with [default][Channel.BUFFERED] buffer size is used. Use [buffer] operator on the
- * resulting flow to specify a value other than default and to control what happens when data is produced faster
- * than it is consumed, that is to control backpressure behavior.
+ * A channel with the [default][Channel.BUFFERED] buffer size is used. Use the [buffer] operator on the
+ * resulting flow to specify a user-defined value and to control what happens when data is produced faster
+ * than consumed, i.e. to control the back-pressure behavior.
  *
  * Adjacent applications of [callbackFlow], [flowOn], [buffer], [produceIn], and [broadcastIn] are
  * always fused so that only one properly configured channel is used for execution.
diff --git a/kotlinx-coroutines-core/jvm/test/channels/ChannelLFStressTest.kt b/kotlinx-coroutines-core/jvm/test/channels/ChannelLFStressTest.kt
index 67bd68a..75e34e5 100644
--- a/kotlinx-coroutines-core/jvm/test/channels/ChannelLFStressTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/channels/ChannelLFStressTest.kt
@@ -50,9 +50,12 @@
     }
 
     private fun performLockFreedomTest() {
-        env.onCompletion { channel.close() }
-        repeat(2) { env.testThread { sender() } }
-        repeat(2) { env.testThread { receiver() } }
+        env.onCompletion {
+            // We must cancel the channel to abort both senders & receivers
+            channel.cancel(TestCompleted())
+        }
+        repeat(2) { env.testThread("sender-$it") { sender() } }
+        repeat(2) { env.testThread("receiver-$it") { receiver() } }
         env.performTest(nSeconds) {
             println("Sent: $sendIndex, Received: $receiveCount, dups: $duplicateCount")
         }
@@ -70,7 +73,7 @@
         val value = sendIndex.getAndIncrement()
         try {
             channel.send(value)
-        } catch (e: ClosedSendChannelException) {
+        } catch (e: TestCompleted) {
             check(env.isCompleted) // expected when test was completed
             markReceived(value) // fake received (actually failed to send)
         }
@@ -79,7 +82,7 @@
     private suspend fun receiver() {
         val value = try {
             channel.receive()
-        } catch (e: ClosedReceiveChannelException) {
+        } catch (e: TestCompleted) {
             check(env.isCompleted) // expected when test was completed
             return
         }
@@ -107,4 +110,6 @@
         val bits = receivedBits.get(index)
         return bits and mask != 0L
     }
+
+    private class TestCompleted : CancellationException()
 }
diff --git a/kotlinx-coroutines-core/jvm/test/linearizability/ChannelCloseLCStressTest.kt b/kotlinx-coroutines-core/jvm/test/linearizability/ChannelCloseLCStressTest.kt
new file mode 100644
index 0000000..5bdc284
--- /dev/null
+++ b/kotlinx-coroutines-core/jvm/test/linearizability/ChannelCloseLCStressTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+@file:Suppress("unused")
+
+package kotlinx.coroutines.linearizability
+
+import com.devexperts.dxlab.lincheck.*
+import com.devexperts.dxlab.lincheck.annotations.*
+import com.devexperts.dxlab.lincheck.paramgen.*
+import com.devexperts.dxlab.lincheck.strategy.stress.*
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.*
+import org.junit.*
+import java.io.*
+
+/**
+ * This is stress test that is fine-tuned to catch the problem
+ * [#1419](https://github.com/Kotlin/kotlinx.coroutines/issues/1419)
+ */
+@Param(name = "value", gen = IntGen::class, conf = "2:2")
+@OpGroupConfig.OpGroupConfigs(
+    OpGroupConfig(name = "send", nonParallel = true),
+    OpGroupConfig(name = "receive", nonParallel = true),
+    OpGroupConfig(name = "close", nonParallel = true)
+)
+class ChannelCloseLCStressTest : TestBase() {
+
+    private companion object {
+        // Emulating ctor argument for lincheck
+        var capacity = 0
+    }
+
+    private val lt = LinTesting()
+    private var channel: Channel<Int> = Channel(capacity)
+
+    @Operation(runOnce = true, group = "send")
+    fun send1(@Param(name = "value") value: Int) = lt.run("send1") { channel.send(value) }
+
+    @Operation(runOnce = true, group = "send")
+    fun send2(@Param(name = "value") value: Int) = lt.run("send2") { channel.send(value) }
+
+    @Operation(runOnce = true, group = "receive")
+    fun receive1() = lt.run("receive1") { channel.receive() }
+
+    @Operation(runOnce = true, group = "receive")
+    fun receive2() = lt.run("receive2") { channel.receive() }
+
+    @Operation(runOnce = true, group = "close")
+    fun close1() = lt.run("close1") { channel.close(IOException("close1")) }
+
+    @Operation(runOnce = true, group = "close")
+    fun close2() = lt.run("close2") { channel.close(IOException("close2")) }
+
+    @Test
+    fun testRendezvousChannelLinearizability() {
+        runTest(0)
+    }
+
+    @Test
+    fun testArrayChannelLinearizability() {
+        for (i in listOf(1, 2, 16)) {
+            runTest(i)
+        }
+    }
+
+    @Test
+    fun testConflatedChannelLinearizability() = runTest(Channel.CONFLATED)
+
+    @Test
+    fun testUnlimitedChannelLinearizability() = runTest(Channel.UNLIMITED)
+
+    private fun runTest(capacity: Int) {
+        ChannelCloseLCStressTest.capacity = capacity
+        val options = StressOptions()
+            .iterations(1) // only one iteration -- test scenario is fixed
+            .invocationsPerIteration(10_000 * stressTestMultiplierSqrt)
+            .threads(3)
+            .verifier(LinVerifier::class.java)
+        LinChecker.check(ChannelCloseLCStressTest::class.java, options)
+    }
+}
diff --git a/kotlinx-coroutines-debug/test/CoroutinesDumpTest.kt b/kotlinx-coroutines-debug/test/CoroutinesDumpTest.kt
index ec72701..fa73534 100644
--- a/kotlinx-coroutines-debug/test/CoroutinesDumpTest.kt
+++ b/kotlinx-coroutines-debug/test/CoroutinesDumpTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
 package kotlinx.coroutines.debug
@@ -11,6 +11,7 @@
 
 class CoroutinesDumpTest : DebugTestBase() {
     private val monitor = Any()
+    private var coroutineStarted = false // guarded by monitor
 
     @Test
     fun testSuspendedCoroutine() = synchronized(monitor) {
@@ -130,7 +131,7 @@
 
     private suspend fun nestedActiveMethod(shouldSuspend: Boolean) {
         if (shouldSuspend) yield()
-        notifyTest()
+        notifyCoroutineStarted()
         while (coroutineContext[Job]!!.isActive) {
             Thread.sleep(100)
         }
@@ -143,17 +144,18 @@
 
     private suspend fun sleepingNestedMethod() {
         yield()
-        notifyTest()
+        notifyCoroutineStarted()
         delay(Long.MAX_VALUE)
     }
 
     private fun awaitCoroutineStarted() {
-        (monitor as Object).wait()
+        while (!coroutineStarted) (monitor as Object).wait()
     }
 
-    private fun notifyTest() {
+    private fun notifyCoroutineStarted() {
         synchronized(monitor) {
-            (monitor as Object).notify()
+            coroutineStarted = true
+            (monitor as Object).notifyAll()
         }
     }
 }
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/build.gradle b/ui/kotlinx-coroutines-android/animation-app/app/build.gradle
index b5919be..7fd9c8a 100644
--- a/ui/kotlinx-coroutines-android/animation-app/app/build.gradle
+++ b/ui/kotlinx-coroutines-android/animation-app/app/build.gradle
@@ -1,35 +1,33 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
 apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
 apply plugin: 'kotlin-android-extensions'
 
 android {
-    compileSdkVersion 27
+    compileSdkVersion 29
     defaultConfig {
         applicationId "org.jetbrains.kotlinx.animation"
         minSdkVersion 14
-        targetSdkVersion 27
+        targetSdkVersion 29
         versionCode 1
         versionName "1.0"
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-    }
-    buildTypes {
-        release {
-            minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
-        }
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
 }
 
 dependencies {
-    implementation 'com.android.support:appcompat-v7:27.1.1'
-    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
-    implementation 'com.android.support:design:27.1.1'
-    implementation 'android.arch.lifecycle:extensions:1.1.1'
+    implementation 'androidx.appcompat:appcompat:1.0.2'
+    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+    implementation 'com.google.android.material:material:1.0.0'
+    implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
 
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
     implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
 
     testImplementation 'junit:junit:4.12'
-    androidTestImplementation 'com.android.support.test:runner:1.0.1'
-    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+    androidTestImplementation 'androidx.test:runner:1.2.0'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
 }
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/proguard-rules.pro b/ui/kotlinx-coroutines-android/animation-app/app/proguard-rules.pro
deleted file mode 100644
index aea920a..0000000
--- a/ui/kotlinx-coroutines-android/animation-app/app/proguard-rules.pro
+++ /dev/null
@@ -1,8 +0,0 @@
--keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
--keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
--keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {}
--keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {}
-
--keepclassmembernames class kotlinx.** {
-    volatile <fields>;
-}
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/Animation.kt b/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/Animation.kt
index dd4aafb..88e0bae 100644
--- a/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/Animation.kt
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/Animation.kt
@@ -1,9 +1,13 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
 package org.jetbrains.kotlinx.animation
 
-import android.arch.lifecycle.LifecycleOwner
-import android.arch.lifecycle.MutableLiveData
-import android.arch.lifecycle.Observer
-import android.arch.lifecycle.ViewModel
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModel
 import android.content.Context
 import android.graphics.Canvas
 import android.graphics.Color
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/MainActivity.kt b/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/MainActivity.kt
index 87a857c..756db9b 100644
--- a/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/MainActivity.kt
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/java/org/jetbrains/kotlinx/animation/MainActivity.kt
@@ -1,8 +1,12 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
 package org.jetbrains.kotlinx.animation
 
-import android.arch.lifecycle.ViewModelProviders
+import androidx.lifecycle.ViewModelProviders
 import android.os.Bundle
-import android.support.v7.app.AppCompatActivity
+import androidx.appcompat.app.AppCompatActivity
 import kotlinx.android.synthetic.main.activity_main.*
 import kotlinx.android.synthetic.main.content_main.*
 
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/activity_main.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/activity_main.xml
index cfc022f..ad11f2a 100644
--- a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/activity_main.xml
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/activity_main.xml
@@ -1,28 +1,32 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!--
+  ~ Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+  -->
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     tools:context="org.jetbrains.kotlinx.animation.MainActivity">
 
-    <android.support.design.widget.AppBarLayout
+    <com.google.android.material.appbar.AppBarLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:theme="@style/AppTheme.AppBarOverlay">
 
-        <android.support.v7.widget.Toolbar
+        <androidx.appcompat.widget.Toolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="?attr/actionBarSize"
             android:background="?attr/colorPrimary"
             app:popupTheme="@style/AppTheme.PopupOverlay" />
 
-    </android.support.design.widget.AppBarLayout>
+    </com.google.android.material.appbar.AppBarLayout>
 
     <include layout="@layout/content_main" />
 
-    <android.support.design.widget.FloatingActionButton
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
         android:id="@+id/addButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -31,7 +35,7 @@
         app:backgroundTint="@color/colorPrimary"
         app:srcCompat="@android:drawable/ic_input_add" />
 
-    <android.support.design.widget.FloatingActionButton
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
         android:id="@+id/removeButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -40,4 +44,4 @@
         app:backgroundTint="@color/colorPrimary"
         app:srcCompat="@android:drawable/ic_delete" />
 
-</android.support.design.widget.CoordinatorLayout>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/content_main.xml b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/content_main.xml
index 02058bd..30665fe 100644
--- a/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/content_main.xml
+++ b/ui/kotlinx-coroutines-android/animation-app/app/src/main/res/layout/content_main.xml
@@ -1,5 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!--
+  ~ Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
@@ -17,4 +21,4 @@
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-</android.support.constraint.ConstraintLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/ui/kotlinx-coroutines-android/animation-app/build.gradle b/ui/kotlinx-coroutines-android/animation-app/build.gradle
index f512a87..d198b1a 100644
--- a/ui/kotlinx-coroutines-android/animation-app/build.gradle
+++ b/ui/kotlinx-coroutines-android/animation-app/build.gradle
@@ -1,3 +1,7 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 
 buildscript {
@@ -6,7 +10,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.4.1'
+        classpath 'com.android.tools.build:gradle:3.5.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 
         // NOTE: Do not place your application dependencies here; they belong
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradle.properties b/ui/kotlinx-coroutines-android/animation-app/gradle.properties
index 8e119d7..19a1481 100644
--- a/ui/kotlinx-coroutines-android/animation-app/gradle.properties
+++ b/ui/kotlinx-coroutines-android/animation-app/gradle.properties
@@ -1,3 +1,7 @@
+#
+# Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
 # Project-wide Gradle settings.
 
 # IDE (e.g. Android Studio) users:
@@ -16,8 +20,9 @@
 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 # org.gradle.parallel=true
 
-kotlin.coroutines=enable
-
 kotlin_version=1.3.50
 coroutines_version=1.3.1
 
+android.useAndroidX=true
+android.enableJetifier=true
+
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties b/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties
index caf54fa..ab5d60b 100644
--- a/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/kotlinx-coroutines-android/animation-app/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,9 @@
+#
+# Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
diff --git a/ui/kotlinx-coroutines-android/example-app/app/build.gradle b/ui/kotlinx-coroutines-android/example-app/app/build.gradle
index 98257d3..f970baa 100644
--- a/ui/kotlinx-coroutines-android/example-app/app/build.gradle
+++ b/ui/kotlinx-coroutines-android/example-app/app/build.gradle
@@ -1,34 +1,32 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
 apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
 apply plugin: 'kotlin-android-extensions'
 
 android {
-    compileSdkVersion 27
+    compileSdkVersion 29
     defaultConfig {
         applicationId "com.example.app"
         minSdkVersion 14
-        targetSdkVersion 27
+        targetSdkVersion 29
         versionCode 1
         versionName "1.0"
-        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
-    }
-    buildTypes {
-        release {
-            minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
-        }
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
 }
 
 dependencies {
-    implementation 'com.android.support:appcompat-v7:27.1.1'
-    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
-    implementation 'com.android.support:design:27.1.1'
+    implementation 'androidx.appcompat:appcompat:1.0.2'
+    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+    implementation 'com.google.android.material:material:1.0.0'
 
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
     implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
 
     testImplementation 'junit:junit:4.12'
-    androidTestImplementation 'com.android.support.test:runner:1.0.1'
-    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+    androidTestImplementation 'androidx.test:runner:1.2.0'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
 }
diff --git a/ui/kotlinx-coroutines-android/example-app/app/proguard-rules.pro b/ui/kotlinx-coroutines-android/example-app/app/proguard-rules.pro
deleted file mode 100644
index aea920a..0000000
--- a/ui/kotlinx-coroutines-android/example-app/app/proguard-rules.pro
+++ /dev/null
@@ -1,8 +0,0 @@
--keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
--keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
--keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {}
--keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {}
-
--keepclassmembernames class kotlinx.** {
-    volatile <fields>;
-}
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt b/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt
index fc1cdbf..47bd16c 100644
--- a/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/java/com/example/app/MainActivity.kt
@@ -1,8 +1,12 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
 package com.example.app
 
 import android.os.Bundle
-import android.support.design.widget.FloatingActionButton
-import android.support.v7.app.AppCompatActivity
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import androidx.appcompat.app.AppCompatActivity
 import android.view.Menu
 import android.view.MenuItem
 import android.widget.TextView
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml
index 13d3225..b98ce43 100644
--- a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/activity_main.xml
@@ -1,28 +1,32 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!--
+  ~ Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+  -->
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     tools:context="com.example.app.MainActivity">
 
-    <android.support.design.widget.AppBarLayout
+    <com.google.android.material.appbar.AppBarLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:theme="@style/AppTheme.AppBarOverlay">
 
-        <android.support.v7.widget.Toolbar
+        <androidx.appcompat.widget.Toolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="?attr/actionBarSize"
             android:background="?attr/colorPrimary"
             app:popupTheme="@style/AppTheme.PopupOverlay" />
 
-    </android.support.design.widget.AppBarLayout>
+    </com.google.android.material.appbar.AppBarLayout>
 
     <include layout="@layout/content_main" />
 
-    <android.support.design.widget.FloatingActionButton
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
         android:id="@+id/fab"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -30,4 +34,4 @@
         android:layout_margin="@dimen/fab_margin"
         app:srcCompat="@android:drawable/ic_dialog_email" />
 
-</android.support.design.widget.CoordinatorLayout>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml
index 110dc67..6eb08c0 100644
--- a/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml
+++ b/ui/kotlinx-coroutines-android/example-app/app/src/main/res/layout/content_main.xml
@@ -1,5 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
-<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!--
+  ~ Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
@@ -18,4 +22,4 @@
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
-</android.support.constraint.ConstraintLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/ui/kotlinx-coroutines-android/example-app/build.gradle b/ui/kotlinx-coroutines-android/example-app/build.gradle
index f512a87..d198b1a 100644
--- a/ui/kotlinx-coroutines-android/example-app/build.gradle
+++ b/ui/kotlinx-coroutines-android/example-app/build.gradle
@@ -1,3 +1,7 @@
+/*
+ * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 
 buildscript {
@@ -6,7 +10,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.4.1'
+        classpath 'com.android.tools.build:gradle:3.5.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 
         // NOTE: Do not place your application dependencies here; they belong
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle.properties b/ui/kotlinx-coroutines-android/example-app/gradle.properties
index 8e119d7..19a1481 100644
--- a/ui/kotlinx-coroutines-android/example-app/gradle.properties
+++ b/ui/kotlinx-coroutines-android/example-app/gradle.properties
@@ -1,3 +1,7 @@
+#
+# Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
 # Project-wide Gradle settings.
 
 # IDE (e.g. Android Studio) users:
@@ -16,8 +20,9 @@
 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 # org.gradle.parallel=true
 
-kotlin.coroutines=enable
-
 kotlin_version=1.3.50
 coroutines_version=1.3.1
 
+android.useAndroidX=true
+android.enableJetifier=true
+
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
index caf54fa..ab5d60b 100644
--- a/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/kotlinx-coroutines-android/example-app/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,9 @@
+#
+# Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+#
+
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip