Merge pull request #646 from Kotlin/version-0.30.1

Version 0.30.1
diff --git a/CHANGES.md b/CHANGES.md
index 8557b2e..823e73e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,13 @@
 # Change log for kotlinx.coroutines
 
+## Version 0.30.1
+ Maintenance release:
+ * Added `Dispatchers.Main` to common dispatchers, which can be used from Android, Swing and JavaFx projects if a corresponding integration library is added to dependencies. 
+ * With `Dispatchers.Main` improvement tooling bug in Android Studio #626 is mitigated, so Android users now can safely start the migration to the latest `kotlinx.coroutines` version.
+ * Fixed bug with thread unsafety of shutdown sequence in `EventLoop`.
+ * Experimental coroutine dispatcher now has `close` contract similar to Java `Executor`, so it can be safely instantiated and closed multiple times (affects only unit tests).
+ * Atomicfu version is updated with fixes in JS transformer (see #609)
+
 ## Version 0.30.0
 
 * **[Major]** Further improvements in exception handling — no failure exception is lost. 
diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md
index 405632d..0d83d4f 100644
--- a/COMPATIBILITY.md
+++ b/COMPATIBILITY.md
@@ -18,8 +18,8 @@
 Version `1.0.0` (starting with its release candidate build) will have all its deprecated declarations removed and `kotlinx.coroutines.experimental` package will be renamed to `kotlinx.coroutines` without functional changes.
 In order to migrate `kotlinx.coroutines` to `1.0.0`, follow these steps:
 
-1. Update `kotlinx.coroutines` to `0.30.0` version.
+1. Update `kotlinx.coroutines` to `0.30.1` version.
 2. Inspect compiler warnings about deprecated API and migrate it to a proposed alternative. Most of deprecated API has a corresponding   replacement which can be applied from IDEA with quickfix.
-3. Update Kotlin version to `1.3.0` or to the latest `1.3.0-rc` and `kotlinx.coroutines` to version `0.30.0-eap13`. Then just get rid of `experimental` suffix in all imports.
+3. Update Kotlin version to `1.3.0` or to the latest `1.3.0-rc` and `kotlinx.coroutines` to version `0.30.1-eap13`. Then just get rid of `experimental` suffix in all imports.
 4. Update `kotlinx.coroutines` to version `1.0.0` or to the corresponding release candidate of it).
  
\ No newline at end of file
diff --git a/README.md b/README.md
index 17f7b5f..784a55b 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 [![official JetBrains project](http://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
 [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0)
-[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.coroutines/images/download.svg?version=0.30.0) ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/0.30.0)
+[![Download](https://api.bintray.com/packages/kotlin/kotlinx/kotlinx.coroutines/images/download.svg?version=0.30.1) ](https://bintray.com/kotlin/kotlinx/kotlinx.coroutines/0.30.1)
 
 Library support for Kotlin coroutines with [multiplatform](#multiplatform) support.
 This is a companion version for Kotlin 1.2.70 release.
@@ -21,9 +21,12 @@
 * [common](common/README.md) — common coroutines across all backends:
   * `launch` and `async` coroutine builders;
   * `Job` and `Deferred` light-weight future with cancellation support;
+  *` Dispatchers.Main` for UI dispatcher for Android, Swing and JavaFx;
   * `delay` and `yield` top-level suspending functions;
   * `Channel` and `Mutex` communication and synchronization primitives;
   * `produce` and `actor` coroutine builders;
+  * `coroutineScope` and `supervisorScope` scope builders;
+  * `SupervisorJob` for supervision of coroutines hierarchies;
   * `select` expression support and more.
 * [core](core/README.md) — Kotlin/JVM implementation of common coroutines with additional features:
   * `Dispatchers.IO` dispatcher for blocking coroutines.
@@ -39,8 +42,8 @@
 ## Documentation
 
 * Presentations and videos:
-   * [Introduction to Coroutines](https://www.youtube.com/watch?v=_hfBv0a09Jc) (Roman Elizarov at KotlinConf 2017, [slides](https://www.slideshare.net/elizarov/introduction-to-coroutines-kotlinconf-2017))
-   * [Deep dive into Coroutines](https://www.youtube.com/watch?v=YrrUCSi72E8) (Roman Elizarov at KotlinConf 2017, [slides](https://www.slideshare.net/elizarov/deep-dive-into-coroutines-on-jvm-kotlinconf-2017))
+  * [Introduction to Coroutines](https://www.youtube.com/watch?v=_hfBv0a09Jc) (Roman Elizarov at KotlinConf 2017, [slides](https://www.slideshare.net/elizarov/introduction-to-coroutines-kotlinconf-2017))
+  * [Deep dive into Coroutines](https://www.youtube.com/watch?v=YrrUCSi72E8) (Roman Elizarov at KotlinConf 2017, [slides](https://www.slideshare.net/elizarov/deep-dive-into-coroutines-on-jvm-kotlinconf-2017))
 * Guides and manuals: 
   * [Guide to kotlinx.coroutines by example](docs/coroutines-guide.md) (**read it first**)
   * [Guide to UI programming with coroutines](ui/coroutines-guide-ui.md)
@@ -82,7 +85,7 @@
 Add dependencies (you can also add other modules that you need):
 
 ```groovy
-implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.30.0'
+implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.30.1'
 ```
 
 And make sure that you use the latest Kotlin version:
@@ -115,7 +118,7 @@
 module as dependency when using `kotlinx.coroutines` on Android:
 
 ```groovy
-implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.30.0'
+implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.30.1'
 ```
 This gives you access to Android [Dispatchers.Main](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-android/kotlinx.coroutines.experimental.android/kotlinx.coroutines.experimental.-dispatchers/index.html)
 coroutine dispatcher and also makes sure that in case of crashed coroutine with unhandled exception this
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt
index baef165..93aea1c 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt
+++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-android.txt
@@ -4,6 +4,7 @@
 	public final fun awaitFrame (Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
 	public fun dispatch (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Runnable;)V
 	public fun equals (Ljava/lang/Object;)Z
+	public synthetic fun getImmediate ()Lkotlinx/coroutines/experimental/MainCoroutineDispatcher;
 	public fun getImmediate ()Lkotlinx/coroutines/experimental/android/HandlerContext;
 	public synthetic fun getImmediate ()Lkotlinx/coroutines/experimental/android/HandlerDispatcher;
 	public fun hashCode ()I
@@ -18,7 +19,7 @@
 	public static final fun getUI ()Lkotlinx/coroutines/experimental/android/HandlerContext;
 }
 
-public abstract class kotlinx/coroutines/experimental/android/HandlerDispatcher : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay {
+public abstract class kotlinx/coroutines/experimental/android/HandlerDispatcher : kotlinx/coroutines/experimental/MainCoroutineDispatcher, kotlinx/coroutines/experimental/Delay {
 	public synthetic fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
 	public fun delay (JLkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
 	public abstract fun getImmediate ()Lkotlinx/coroutines/experimental/android/HandlerDispatcher;
@@ -32,6 +33,6 @@
 	public static final fun from (Landroid/os/Handler;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher;
 	public static final fun from (Landroid/os/Handler;Ljava/lang/String;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher;
 	public static synthetic fun from$default (Landroid/os/Handler;Ljava/lang/String;ILjava/lang/Object;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher;
-	public static final fun getMain (Lkotlinx/coroutines/experimental/Dispatchers;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher;
+	public static final synthetic fun getMain (Lkotlinx/coroutines/experimental/Dispatchers;)Lkotlinx/coroutines/experimental/android/HandlerDispatcher;
 }
 
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt
index b84c4b6..53b858f 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt
+++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-core.txt
@@ -314,14 +314,15 @@
 }
 
 public final class kotlinx/coroutines/experimental/Dispatchers {
-	public static final field Default Lkotlinx/coroutines/experimental/CoroutineDispatcher;
 	public static final field INSTANCE Lkotlinx/coroutines/experimental/Dispatchers;
-	public static final field Unconfined Lkotlinx/coroutines/experimental/CoroutineDispatcher;
+	public static final fun getDefault ()Lkotlinx/coroutines/experimental/CoroutineDispatcher;
+	public static final fun getIO ()Lkotlinx/coroutines/experimental/CoroutineDispatcher;
+	public static final fun getMain ()Lkotlinx/coroutines/experimental/MainCoroutineDispatcher;
+	public static final fun getUnconfined ()Lkotlinx/coroutines/experimental/CoroutineDispatcher;
 }
 
 public final class kotlinx/coroutines/experimental/DispatchersKt {
 	public static final field IO_PARALLELISM_PROPERTY_NAME Ljava/lang/String;
-	public static final fun getIO (Lkotlinx/coroutines/experimental/Dispatchers;)Lkotlinx/coroutines/experimental/CoroutineDispatcher;
 }
 
 public abstract interface class kotlinx/coroutines/experimental/DisposableHandle {
@@ -468,6 +469,11 @@
 	public static final fun lazyDefer (Lkotlin/coroutines/experimental/CoroutineContext;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/experimental/Deferred;
 }
 
+public abstract class kotlinx/coroutines/experimental/MainCoroutineDispatcher : kotlinx/coroutines/experimental/CoroutineDispatcher {
+	public fun <init> ()V
+	public abstract fun getImmediate ()Lkotlinx/coroutines/experimental/MainCoroutineDispatcher;
+}
+
 public final class kotlinx/coroutines/experimental/NonCancellable : kotlin/coroutines/experimental/AbstractCoroutineContextElement, kotlinx/coroutines/experimental/Job {
 	public static final field INSTANCE Lkotlinx/coroutines/experimental/NonCancellable;
 	public fun attachChild (Lkotlinx/coroutines/experimental/ChildJob;)Lkotlinx/coroutines/experimental/ChildHandle;
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-javafx.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-javafx.txt
index 69c98bb..341f038 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-javafx.txt
+++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-javafx.txt
@@ -1,18 +1,18 @@
 public final class kotlinx/coroutines/experimental/javafx/JavaFx : kotlinx/coroutines/experimental/javafx/JavaFxDispatcher {
 	public static final field INSTANCE Lkotlinx/coroutines/experimental/javafx/JavaFx;
 	public final fun awaitPulse (Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
-	public fun dispatch (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Runnable;)V
-	public fun invokeOnTimeout (JLjava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle;
-	public fun scheduleResumeAfterDelay (JLkotlinx/coroutines/experimental/CancellableContinuation;)V
+	public fun getImmediate ()Lkotlinx/coroutines/experimental/MainCoroutineDispatcher;
 	public fun toString ()Ljava/lang/String;
 }
 
-public abstract class kotlinx/coroutines/experimental/javafx/JavaFxDispatcher : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay {
+public abstract class kotlinx/coroutines/experimental/javafx/JavaFxDispatcher : kotlinx/coroutines/experimental/MainCoroutineDispatcher, kotlinx/coroutines/experimental/Delay {
 	public synthetic fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
 	public fun delay (JLkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
+	public fun dispatch (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Runnable;)V
 	public fun invokeOnTimeout (JLjava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle;
 	public synthetic fun invokeOnTimeout (JLjava/util/concurrent/TimeUnit;Ljava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle;
 	public synthetic fun scheduleResumeAfterDelay (JLjava/util/concurrent/TimeUnit;Lkotlinx/coroutines/experimental/CancellableContinuation;)V
+	public fun scheduleResumeAfterDelay (JLkotlinx/coroutines/experimental/CancellableContinuation;)V
 }
 
 public final class kotlinx/coroutines/experimental/javafx/JavaFxDispatcherKt {
diff --git a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-swing.txt b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-swing.txt
index dcb7f3b..14be922 100644
--- a/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-swing.txt
+++ b/binary-compatibility-validator/reference-public-api/kotlinx-coroutines-swing.txt
@@ -1,17 +1,17 @@
 public final class kotlinx/coroutines/experimental/swing/Swing : kotlinx/coroutines/experimental/swing/SwingDispatcher {
 	public static final field INSTANCE Lkotlinx/coroutines/experimental/swing/Swing;
-	public fun dispatch (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Runnable;)V
-	public fun invokeOnTimeout (JLjava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle;
-	public fun scheduleResumeAfterDelay (JLkotlinx/coroutines/experimental/CancellableContinuation;)V
+	public fun getImmediate ()Lkotlinx/coroutines/experimental/MainCoroutineDispatcher;
 	public fun toString ()Ljava/lang/String;
 }
 
-public abstract class kotlinx/coroutines/experimental/swing/SwingDispatcher : kotlinx/coroutines/experimental/CoroutineDispatcher, kotlinx/coroutines/experimental/Delay {
+public abstract class kotlinx/coroutines/experimental/swing/SwingDispatcher : kotlinx/coroutines/experimental/MainCoroutineDispatcher, kotlinx/coroutines/experimental/Delay {
 	public synthetic fun delay (JLjava/util/concurrent/TimeUnit;Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
 	public fun delay (JLkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;
+	public fun dispatch (Lkotlin/coroutines/experimental/CoroutineContext;Ljava/lang/Runnable;)V
 	public fun invokeOnTimeout (JLjava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle;
 	public synthetic fun invokeOnTimeout (JLjava/util/concurrent/TimeUnit;Ljava/lang/Runnable;)Lkotlinx/coroutines/experimental/DisposableHandle;
 	public synthetic fun scheduleResumeAfterDelay (JLjava/util/concurrent/TimeUnit;Lkotlinx/coroutines/experimental/CancellableContinuation;)V
+	public fun scheduleResumeAfterDelay (JLkotlinx/coroutines/experimental/CancellableContinuation;)V
 }
 
 public final class kotlinx/coroutines/experimental/swing/SwingDispatcherKt {
diff --git a/common/kotlinx-coroutines-core-common/src/AbstractContinuation.kt b/common/kotlinx-coroutines-core-common/src/AbstractContinuation.kt
index 41035eb..1b93207 100644
--- a/common/kotlinx-coroutines-core-common/src/AbstractContinuation.kt
+++ b/common/kotlinx-coroutines-core-common/src/AbstractContinuation.kt
@@ -105,7 +105,7 @@
     /**
      * It is used when parent is cancelled to get the cancellation cause for this continuation.
      */
-    open fun getParentCancellationCause(parent: Job): Throwable =
+    open fun getContinuationCancellationCause(parent: Job): Throwable =
         parent.getCancellationException()
 
     private fun trySuspend(): Boolean {
diff --git a/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt b/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt
index 4e723ed..c3eda77 100644
--- a/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt
+++ b/common/kotlinx-coroutines-core-common/src/Dispatchers.common.kt
@@ -4,13 +4,12 @@
 
 package kotlinx.coroutines.experimental
 
-import kotlinx.coroutines.experimental.internal.*
 import kotlin.coroutines.experimental.*
 
 /**
  * Groups various implementations of [CoroutineDispatcher].
  */
-public object Dispatchers {
+expect object Dispatchers {
     /**
      * The default [CoroutineDispatcher] that is used by all standard builders like
      * [launch][CoroutineScope.launch], [async][CoroutineScope.async], etc
@@ -19,9 +18,27 @@
      * It is backed by a shared pool of threads on JVM. By default, the maximal number of threads used
      * by this dispatcher is equal to the number CPU cores, but is at least two.
      */
-    @JvmField
-    public val Default: CoroutineDispatcher =
-        createDefaultDispatcher()
+    public val Default: CoroutineDispatcher
+
+    /**
+     * A coroutine dispatcher that is confined to the Main thread operating with UI objects.
+     * Usually such dispatcher is single-threaded.
+     *
+     * Access to this property may throw [IllegalStateException] if no main dispatchers are present in the classpath.
+     *
+     * Depending on platform and classpath it can be mapped to different dispatchers:
+     * - On JS and Native it is equivalent of [Default] dispatcher.
+     * - On JVM it either Android main thread dispatcher, JavaFx or Swing EDT dispatcher. It is chosen by
+     *   [`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html).
+     *
+     * In order to work with `Main` dispatcher, following artifact should be added to project runtime dependencies:
+     *  - `kotlinx-coroutines-android` for Android Main thread dispatcher
+     *  - `kotlinx-coroutines-javafx` for JavaFx Application thread dispatcher
+     *  - `kotlinx-coroutines-swing` for Swing EDT dispatcher
+     *
+     * Implementation note: [MainCoroutineDispatcher.immediate] is not supported on Native and JS platforms.
+     */
+    public val Main: MainCoroutineDispatcher
 
     /**
      * A coroutine dispatcher that is not confined to any specific thread.
@@ -39,8 +56,6 @@
      * **Note: This is an experimental api.**
      * Semantics, order of execution, and particular implementation details of this dispatcher may change in the future.
      */
-    @JvmField
     @ExperimentalCoroutinesApi
-    public val Unconfined: CoroutineDispatcher =
-        kotlinx.coroutines.experimental.Unconfined
-}
\ No newline at end of file
+    public val Unconfined: CoroutineDispatcher
+}
diff --git a/common/kotlinx-coroutines-core-common/src/Job.kt b/common/kotlinx-coroutines-core-common/src/Job.kt
index d1b97c5..23d9be9 100644
--- a/common/kotlinx-coroutines-core-common/src/Job.kt
+++ b/common/kotlinx-coroutines-core-common/src/Job.kt
@@ -425,13 +425,30 @@
 internal interface ChildJob : Job {
     /**
      * Parent is cancelling its child by invoking this method.
-     * Child finds the cancellation cause using [getCancellationException] of the [parentJob].
+     * Child finds the cancellation cause using [ParentJob.getChildJobCancellationCause].
      * This method does nothing is the child is already being cancelled.
      *
      * @suppress **This is unstable API and it is subject to change.**
      */
     @InternalCoroutinesApi
-    public fun parentCancelled(parentJob: Job)
+    public fun parentCancelled(parentJob: ParentJob)
+}
+
+/**
+ * A reference that child receives from its parent when it is being cancelled by the parent.
+ *
+ * @suppress **This is unstable API and it is subject to change.**
+ */
+@InternalCoroutinesApi
+internal interface ParentJob : Job {
+    /**
+     * Child job is using this method to learn its cancellation cause when the parent cancels it with [ChildJob.parentCancelled].
+     * This method is invoked only if the child was not already being cancelled.
+     *
+     * @suppress **This is unstable API and it is subject to change.**
+     */
+    @InternalCoroutinesApi
+    public fun getChildJobCancellationCause(): Throwable
 }
 
 /**
diff --git a/common/kotlinx-coroutines-core-common/src/JobSupport.kt b/common/kotlinx-coroutines-core-common/src/JobSupport.kt
index 02ef7b3..4b1ca86 100644
--- a/common/kotlinx-coroutines-core-common/src/JobSupport.kt
+++ b/common/kotlinx-coroutines-core-common/src/JobSupport.kt
@@ -20,7 +20,7 @@
  * @param active when `true` the job is created in _active_ state, when `false` in _new_ state. See [Job] for details.
  * @suppress **This is unstable API and it is subject to change.**
  */
-internal open class JobSupport constructor(active: Boolean) : Job, ChildJob, SelectClause0 {
+internal open class JobSupport constructor(active: Boolean) : Job, ChildJob, ParentJob, SelectClause0 {
     final override val key: CoroutineContext.Key<*> get() = Job
 
     /*
@@ -230,63 +230,23 @@
             if (state.isCancelling) return createJobCancellationException()
             return null
         }
-        /*
-         * This is a place where we step on our API limitation:
-         * We can't distinguish internal JobCancellationException from our parent
-         * from external cancellation, thus we ought to collect all exceptions.
-         * If parent is cancelling, it cancels its children with JCE(rootCause).
-         * When child is building final exception, it can skip JCE(anything) if it knows
-         * that parent handles exceptions, because parent should already have this exception.
-         * If parent does not, then we should unwrap exception, otherwise in the following code
-         * ```
-         * val parent = Job()
-         * launch(parent) {
-         *   try { delay() } finally { throw E2() }
-         * }
-         * parent.cancel(E1)
-         * ```
-         * E1 will be lost.
-         */
-        var rootCause = exceptions[0]
-        if (rootCause is CancellationException) {
-            val cause = unwrap(rootCause)
-            rootCause = if (cause !== null) {
-                cause
-            } else {
-                exceptions.firstOrNull { unwrap(it) != null } ?: return rootCause
-            }
-        }
-        return rootCause
+        // Take either the first real exception (not a cancellation) or just the first exception
+        return exceptions.firstOrNull { it !is CancellationException } ?: exceptions[0]
     }
 
     private fun suppressExceptions(rootCause: Throwable, exceptions: List<Throwable>): Boolean {
         if (exceptions.size <= 1) return false // nothing more to do here
         val seenExceptions = identitySet<Throwable>(exceptions.size)
         var suppressed = false
-        for (i in 1 until exceptions.size) {
-            val unwrapped = unwrap(exceptions[i])
-            if (unwrapped !== null && unwrapped !== rootCause) {
-                if (seenExceptions.add(unwrapped)) {
-                    rootCause.addSuppressedThrowable(unwrapped)
-                    suppressed = true
-                }
+        for (exception in exceptions) {
+            if (exception !== rootCause && exception !is CancellationException && seenExceptions.add(exception)) {
+                rootCause.addSuppressedThrowable(exception)
+                suppressed = true
             }
         }
         return suppressed
     }
 
-    private tailrec fun unwrap(exception: Throwable): Throwable? {
-        if (exception is CancellationException && parentHandlesExceptions) {
-            return null
-        }
-        return if (exception is CancellationException) {
-            val cause = exception.cause
-            if (cause !== null) unwrap(cause) else null
-        } else {
-            exception
-        }
-    }
-
     // fast-path method to finalize normally completed coroutines without children
     private fun tryFinalizeSimpleState(state: Incomplete, update: Any?, mode: Int): Boolean {
         check(state is Empty || state is JobNode<*>) // only simple state without lists where children can concurrently add
@@ -616,7 +576,7 @@
         cancelImpl(cause) && handlesException
 
     // Parent is cancelling child
-    public final override fun parentCancelled(parentJob: Job) {
+    public final override fun parentCancelled(parentJob: ParentJob) {
         cancelImpl(parentJob)
     }
 
@@ -624,7 +584,7 @@
     public open fun childCancelled(cause: Throwable): Boolean =
         cancelImpl(cause) && handlesException
 
-    // cause is Throwable or Job when cancelChild was invoked
+    // cause is Throwable or ParentJob when cancelChild was invoked
     // returns true is exception was handled, false otherwise
     private fun cancelImpl(cause: Any?): Boolean {
         if (onCancelComplete) {
@@ -636,6 +596,7 @@
         return makeCancelling(cause)
     }
 
+    // cause is Throwable or ParentJob when cancelChild was invoked
     private fun cancelMakeCompleting(cause: Any?): Boolean {
         loopOnState { state ->
             if (state !is Incomplete || state is Finishing && state.isCompleting) {
@@ -654,14 +615,35 @@
     private fun createJobCancellationException() =
         JobCancellationException("Job was cancelled", null, this)
 
-    // cause is Throwable or Job when cancelChild was invoked, cause can be null only on cancel
+    override fun getChildJobCancellationCause(): Throwable {
+        // determine root cancellation cause of this job (why is it cancelling its children?)
+        val state = this.state
+        val rootCause = when (state) {
+            is Finishing -> state.rootCause
+            is Incomplete -> error("Cannot be cancelling child in this state: $state")
+            is CompletedExceptionally -> state.cause
+            else -> null // create exception with the below code on normal completion
+        }
+        /*
+         * If this parent job handles exceptions, then wrap cause into JobCancellationException, because we
+         * don't want the child to handle this exception on more time. Otherwise, pass our original rootCause
+         * to the child for cancellation.
+         */
+        return if (rootCause == null || handlesException && rootCause !is CancellationException) {
+            JobCancellationException("Parent job is ${stateString(state)}", rootCause, this)
+        } else {
+            rootCause
+        }
+    }
+
+    // cause is Throwable or ParentJob when cancelChild was invoked
     private fun createCauseException(cause: Any?): Throwable = when(cause) {
         is Throwable? -> cause ?: createJobCancellationException()
-        else -> (cause as Job).getCancellationException()
+        else -> (cause as ParentJob).getChildJobCancellationCause()
     }
 
     // transitions to Cancelling state
-    // cause is Throwable or Job when cancelChild was invoked, cause can be null only on cancel
+    // cause is Throwable or ParentJob when cancelChild was invoked
     private fun makeCancelling(cause: Any?): Boolean {
         var causeExceptionCache: Throwable? = null // lazily init result of createCauseException(cause)
         loopOnState { state ->
@@ -927,10 +909,6 @@
      */
     protected open val handlesException: Boolean get() = true
 
-    // returns true when we know that parent handles exceptions
-    private val parentHandlesExceptions: Boolean get() =
-        (parentHandle as? ChildHandleNode)?.job?.handlesException ?: false
-
     /**
      * This method is invoked **exactly once** when the final exception of the job is determined
      * and before it becomes complete. At the moment of invocation the job and all its children are complete.
@@ -959,27 +937,22 @@
 
     // for nicer debugging
     public override fun toString(): String =
-        "${nameString()}{${stateString()}}@$hexAddress"
+        "${nameString()}{${stateString(state)}}@$hexAddress"
 
     /**
      * @suppress **This is unstable API and it is subject to change.**
      */
     internal open fun nameString(): String = classSimpleName
 
-    private fun stateString(): String {
-        val state = this.state
-        return when (state) {
-            is Finishing -> buildString {
-                when {
-                    state.isCancelling -> append("Cancelling")
-                    else -> append("Active")
-                }
-                if (state.isCompleting) append("Completing")
-            }
-            is Incomplete -> if (state.isActive) "Active" else "New"
-            is CompletedExceptionally -> "Cancelled"
-            else -> "Completed"
+    private fun stateString(state: Any?): String = when (state) {
+        is Finishing -> when {
+            state.isCancelling -> "Cancelling"
+            state.isCompleting -> "Completing"
+            else -> "Active"
         }
+        is Incomplete -> if (state.isActive) "Active" else "New"
+        is CompletedExceptionally -> "Cancelled"
+        else -> "Completed"
     }
 
     // Completing & Cancelling states,
@@ -1068,7 +1041,7 @@
         delegate: Continuation<T>,
         private val job: JobSupport
     ) : CancellableContinuationImpl<T>(delegate, MODE_CANCELLABLE) {
-        override fun getParentCancellationCause(parent: Job): Throwable {
+        override fun getContinuationCancellationCause(parent: Job): Throwable {
             val state = job.state
             /*
              * When the job we are waiting for had already completely completed exceptionally or
@@ -1351,7 +1324,7 @@
     @JvmField val child: AbstractContinuation<*>
 ) : JobCancellingNode<Job>(parent) {
     override fun invoke(cause: Throwable?) {
-        child.cancelImpl(child.getParentCancellationCause(job))
+        child.cancelImpl(child.getContinuationCancellationCause(job))
     }
     override fun toString(): String =
         "ChildContinuation[$child]"
diff --git a/common/kotlinx-coroutines-core-common/src/MainCoroutineDispatcher.kt b/common/kotlinx-coroutines-core-common/src/MainCoroutineDispatcher.kt
new file mode 100644
index 0000000..b0da263
--- /dev/null
+++ b/common/kotlinx-coroutines-core-common/src/MainCoroutineDispatcher.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.experimental
+
+/**
+ * Base class for special [CoroutineDispatcher] which is confined to application "Main" or "UI" thread
+ * and used for any UI-based activities. Instance of `MainDispatcher` can be obtained by [Dispatchers.Main].
+ *
+ * Platform may or may not provide instance of `MainDispatcher`, see documentation to [Dispatchers.Main]
+ */
+public abstract class MainCoroutineDispatcher : CoroutineDispatcher() {
+
+    /**
+     * Returns dispatcher that executes coroutines immediately when it is already in the right context
+     * (e.g. current looper is the same as this handler's looper). See [isDispatchNeeded] documentation on
+     * why this should not be done by default.
+     * Method may throw [UnsupportedOperationException] if immediate dispatching is not supported by current dispatcher,
+     * please refer to specific dispatcher documentation.
+     *
+     * **Note: This is an experimental api.** Semantics of this dispatcher may change in the future.
+     */
+    @ExperimentalCoroutinesApi
+    public abstract val immediate: MainCoroutineDispatcher
+}
diff --git a/common/kotlinx-coroutines-core-common/src/internal/MainDispatcherFactory.kt b/common/kotlinx-coroutines-core-common/src/internal/MainDispatcherFactory.kt
new file mode 100644
index 0000000..6077849
--- /dev/null
+++ b/common/kotlinx-coroutines-core-common/src/internal/MainDispatcherFactory.kt
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.experimental.internal
+
+import kotlinx.coroutines.experimental.*
+
+@InternalCoroutinesApi // Emulating DI for Kotlin object's
+public interface MainDispatcherFactory {
+    val loadPriority: Int // higher priority wins
+
+    fun createDispatcher(): MainCoroutineDispatcher
+}
diff --git a/core/kotlinx-coroutines-core/src/Dispatchers.kt b/core/kotlinx-coroutines-core/src/Dispatchers.kt
index c689b7e..50396a9 100644
--- a/core/kotlinx-coroutines-core/src/Dispatchers.kt
+++ b/core/kotlinx-coroutines-core/src/Dispatchers.kt
@@ -6,7 +6,10 @@
 
 package kotlinx.coroutines.experimental
 
+import kotlinx.coroutines.experimental.internal.*
 import kotlinx.coroutines.experimental.scheduling.*
+import java.util.*
+import kotlin.coroutines.experimental.*
 
 /**
  * Name of the property that defines the maximal number of threads that are used by [Dispatchers.IO] coroutines dispatcher.
@@ -14,16 +17,83 @@
 public const val IO_PARALLELISM_PROPERTY_NAME = "kotlinx.coroutines.io.parallelism"
 
 /**
- * The [CoroutineDispatcher] that is designed for offloading blocking IO tasks to a shared pool of threads.
- *
- * Additional threads in this pool are created and are shutdown on demand.
- * The number of threads used by this dispatcher is limited by the value of
- * "`kotlinx.coroutines.io.parallelism`" ([IO_PARALLELISM_PROPERTY_NAME]) system property.
- * It defaults to the limit of 64 threads or the number of cores (whichever is larger).
- *
- * This dispatcher shares threads with a [Default][Dispatchers.Default] dispatcher, so using
- * `withContext(Dispatchers.IO) { ... }` does not lead to an actual switching to another thread &mdash;
- * typically execution continues in the same thread.
+ * Groups various implementations of [CoroutineDispatcher].
  */
-public val Dispatchers.IO: CoroutineDispatcher
-    get() = DefaultScheduler.IO
+actual object Dispatchers {
+
+    private val mainDispatcher = loadMainDispatcher()
+
+    private fun loadMainDispatcher(): MainCoroutineDispatcher? {
+        return MainDispatcherFactory::class.java.let { clz ->
+            ServiceLoader.load(clz, clz.classLoader).toList()
+        }.maxBy { it.loadPriority }?.createDispatcher()
+    }
+
+    /**
+     * The default [CoroutineDispatcher] that is used by all standard builders like
+     * [launch][CoroutineScope.launch], [async][CoroutineScope.async], etc
+     * if no dispatcher nor any other [ContinuationInterceptor] is specified in their context.
+     *
+     * It is backed by a shared pool of threads on JVM. By default, the maximal number of threads used
+     * by this dispatcher is equal to the number CPU cores, but is at least two.
+     */
+    @JvmStatic
+    public actual val Default: CoroutineDispatcher = createDefaultDispatcher()
+
+    /**
+     * A coroutine dispatcher that is confined to the Main thread operating with UI objects.
+     * Usually such dispatcher is single-threaded.
+     *
+     * Access to this property may throw [IllegalStateException] if no main thread dispatchers are present in the classpath.
+     *
+     * Depending on platform and classpath it can be mapped to different dispatchers:
+     * - On JS and Native it is equivalent of [Default] dispatcher.
+     * - On JVM it either Android main thread dispatcher, JavaFx or Swing EDT dispatcher. It is chosen by
+     *   [`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html).
+     *
+     * In order to work with `Main` dispatcher, following artifact should be added to project runtime dependencies:
+     *  - `kotlinx-coroutines-android` for Android Main thread dispatcher
+     *  - `kotlinx-coroutines-javafx` for JavaFx Application thread dispatcher
+     *  - `kotlinx-coroutines-swing` for Swing EDT dispatcher
+     *
+     * Implementation note: [MainCoroutineDispatcher.immediate] is not supported on Native and JS platforms.
+     */
+    @JvmStatic
+    public actual val Main: MainCoroutineDispatcher get() = mainDispatcher ?: error("Module with Main dispatcher is missing. " +
+            "Add dependency with required Main dispatcher, e.g. 'kotlinx-coroutines-android'")
+
+    /**
+     * A coroutine dispatcher that is not confined to any specific thread.
+     * It executes initial continuation of the coroutine _immediately_ in the current call-frame
+     * and lets the coroutine resume in whatever thread that is used by the corresponding suspending function, without
+     * mandating any specific threading policy.
+     * **Note: use with extreme caution, not for general code**.
+     *
+     * Note, that if you need your coroutine to be confined to a particular thread or a thread-pool after resumption,
+     * but still want to execute it in the current call-frame until its first suspension, then you can use
+     * an optional [CoroutineStart] parameter in coroutine builders like
+     * [launch][CoroutineScope.launch] and [async][CoroutineScope.async] setting it to the
+     * the value of [CoroutineStart.UNDISPATCHED].
+     *
+     * **Note: This is an experimental api.**
+     * Semantics, order of execution, and particular implementation details of this dispatcher may change in the future.
+     */
+    @JvmStatic
+    @ExperimentalCoroutinesApi
+    public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.experimental.Unconfined
+
+    /**
+     * The [CoroutineDispatcher] that is designed for offloading blocking IO tasks to a shared pool of threads.
+     *
+     * Additional threads in this pool are created and are shutdown on demand.
+     * The number of threads used by this dispatcher is limited by the value of
+     * "`kotlinx.coroutines.io.parallelism`" ([IO_PARALLELISM_PROPERTY_NAME]) system property.
+     * It defaults to the limit of 64 threads or the number of cores (whichever is larger).
+     *
+     * This dispatcher shares threads with a [Default][Dispatchers.Default] dispatcher, so using
+     * `withContext(Dispatchers.IO) { ... }` does not lead to an actual switching to another thread &mdash;
+     * typically execution continues in the same thread.
+     */
+    @JvmStatic
+    public val IO: CoroutineDispatcher = DefaultScheduler.IO
+}
diff --git a/core/kotlinx-coroutines-core/src/EventLoop.kt b/core/kotlinx-coroutines-core/src/EventLoop.kt
index bb909d8..45af38c 100644
--- a/core/kotlinx-coroutines-core/src/EventLoop.kt
+++ b/core/kotlinx-coroutines-core/src/EventLoop.kt
@@ -72,9 +72,12 @@
 public fun EventLoop_Deprecated(thread: Thread = Thread.currentThread(), parentJob: Job? = null): CoroutineDispatcher =
     EventLoop(thread, parentJob) as CoroutineDispatcher
 
-internal const val DELAYED = 0
-internal const val REMOVED = 1
-internal const val RESCHEDULED = 2
+private val DISPOSED_TASK = Symbol("REMOVED_TASK")
+
+// results for scheduleImpl
+private const val SCHEDULE_OK = 0
+private const val SCHEDULE_COMPLETED = 1
+private const val SCHEDULE_DISPOSED = 2
 
 private const val MS_TO_NS = 1_000_000L
 private const val MAX_MS = Long.MAX_VALUE / MS_TO_NS
@@ -242,22 +245,23 @@
     }
 
     internal fun schedule(delayedTask: DelayedTask) {
-        if (scheduleImpl(delayedTask)) {
-            if (shouldUnpark(delayedTask)) unpark()
-        } else {
-            DefaultExecutor.schedule(delayedTask)
+        when (scheduleImpl(delayedTask)) {
+            SCHEDULE_OK -> if (shouldUnpark(delayedTask)) unpark()
+            SCHEDULE_COMPLETED -> DefaultExecutor.schedule(delayedTask)
+            SCHEDULE_DISPOSED -> {} // do nothing -- task was already disposed
+            else -> error("unexpected result")
         }
     }
 
     private fun shouldUnpark(task: DelayedTask): Boolean = _delayed.value?.peek() === task
 
-    private fun scheduleImpl(delayedTask: DelayedTask): Boolean {
-        if (isCompleted) return false
+    private fun scheduleImpl(delayedTask: DelayedTask): Int {
+        if (isCompleted) return SCHEDULE_COMPLETED
         val delayed = _delayed.value ?: run {
             _delayed.compareAndSet(null, ThreadSafeHeap())
             _delayed.value!!
         }
-        return delayed.addLastIf(delayedTask) { !isCompleted }
+        return delayedTask.schedule(delayed)
     }
 
     internal fun removeDelayedImpl(delayedTask: DelayedTask) {
@@ -273,6 +277,13 @@
     // This is a "soft" (normal) shutdown
     protected fun rescheduleAllDelayed() {
         while (true) {
+            /*
+             * `removeFirstOrNull` below is the only operation on DelayedTask & ThreadSafeHeap that is not
+             * synchronized on DelayedTask itself. All other operation are synchronized both on
+             * DelayedTask & ThreadSafeHeap instances (in this order). It is still safe, because `dispose`
+             * first removes DelayedTask from the heap (under synchronization) then
+             * assign "_heap = DISPOSED_TASK", so there cannot be ever a race to _heap reference update.
+             */
             val delayedTask = _delayed.value?.removeFirstOrNull() ?: break
             delayedTask.rescheduleOnShutdown()
         }
@@ -281,8 +292,17 @@
     internal abstract inner class DelayedTask(
         timeMillis: Long
     ) : Runnable, Comparable<DelayedTask>, DisposableHandle, ThreadSafeHeapNode {
+        private var _heap: Any? = null // null | ThreadSafeHeap | DISPOSED_TASK
+        
+        override var heap: ThreadSafeHeap<*>?
+            get() = _heap as? ThreadSafeHeap<*>
+            set(value) {
+                require(_heap !== DISPOSED_TASK) // this can never happen, it is always checked before adding/removing
+                _heap = value
+            }
+        
         override var index: Int = -1
-        @JvmField var state = DELAYED // Guarded by by lock on this task for reschedule/dispose purposes
+        
         @JvmField val nanoTime: Long = timeSource.nanoTime() + delayToNanos(timeMillis)
 
         override fun compareTo(other: DelayedTask): Int {
@@ -297,24 +317,21 @@
         fun timeToExecute(now: Long): Boolean = now - nanoTime >= 0L
 
         @Synchronized
-        fun rescheduleOnShutdown() {
-            if (state != DELAYED) return
-            if (_delayed.value!!.remove(this)) {
-                state = RESCHEDULED
-                DefaultExecutor.schedule(this)
-            } else {
-                state = REMOVED
-            }
+        fun schedule(delayed: ThreadSafeHeap<DelayedTask>): Int {
+            if (_heap === DISPOSED_TASK) return SCHEDULE_DISPOSED // don't add -- was already disposed
+            return if (delayed.addLastIf(this) { !isCompleted }) SCHEDULE_OK else SCHEDULE_COMPLETED
         }
 
+        // note: DefaultExecutor.schedule performs `schedule` (above) which does sync & checks for DISPOSED_TASK
+        fun rescheduleOnShutdown() = DefaultExecutor.schedule(this)
+
         @Synchronized
         final override fun dispose() {
-            when (state) {
-                DELAYED -> _delayed.value?.remove(this)
-                RESCHEDULED -> DefaultExecutor.removeDelayedImpl(this)
-                else -> return
-            }
-            state = REMOVED
+            val heap = _heap
+            if (heap === DISPOSED_TASK) return // already disposed
+            @Suppress("UNCHECKED_CAST")
+            (heap as? ThreadSafeHeap<DelayedTask>)?.remove(this) // remove if it is in heap (first)
+            _heap = DISPOSED_TASK // never add again to any heap
         }
 
         override fun toString(): String = "Delayed[nanos=$nanoTime]"
diff --git a/core/kotlinx-coroutines-core/src/internal/LockFreeLinkedList.kt b/core/kotlinx-coroutines-core/src/internal/LockFreeLinkedList.kt
index bbf4226..2cb1d68 100644
--- a/core/kotlinx-coroutines-core/src/internal/LockFreeLinkedList.kt
+++ b/core/kotlinx-coroutines-core/src/internal/LockFreeLinkedList.kt
@@ -5,6 +5,7 @@
 package kotlinx.coroutines.experimental.internal
 
 import kotlinx.atomicfu.*
+import kotlinx.coroutines.experimental.*
 
 private typealias Node = LockFreeLinkedListNode
 
@@ -53,6 +54,7 @@
  * @suppress **This is unstable API and it is subject to change.**
  */
 @Suppress("LeakingThis")
+@InternalCoroutinesApi
 public actual open class LockFreeLinkedListNode {
     private val _next = atomic<Any>(this) // Node | Removed | OpDescriptor
     private val _prev = atomic<Any>(this) // Node | Removed
diff --git a/core/kotlinx-coroutines-core/src/internal/LockFreeMPMCQueue.kt b/core/kotlinx-coroutines-core/src/internal/LockFreeMPMCQueue.kt
index 6ee0b28..738e21b 100644
--- a/core/kotlinx-coroutines-core/src/internal/LockFreeMPMCQueue.kt
+++ b/core/kotlinx-coroutines-core/src/internal/LockFreeMPMCQueue.kt
@@ -9,7 +9,9 @@
 internal open class LockFreeMPMCQueueNode<T> {
     val next = atomic<T?>(null)
 
+    // internal declarations for inline functions
     @PublishedApi internal val nextValue: T? get() = next.value
+    @PublishedApi internal fun nextCas(expect: T?, update: T?) = next.compareAndSet(expect, update)
 }
 
 /*
@@ -23,9 +25,14 @@
         atomic(LockFreeMPMCQueueNode<T>() as T) // sentinel
 
     private val tail = atomic(head.value)
-    internal val headValue: T get() = head.value
 
-    public fun addLast(node: T): Boolean {
+    // internal declarations for inline functions
+    @PublishedApi internal val headValue: T get() = head.value
+    @PublishedApi internal val tailValue: T get() = tail.value
+    @PublishedApi internal fun headCas(curHead: T, update: T) = head.compareAndSet(curHead, update)
+    @PublishedApi internal fun tailCas(curTail: T, update: T) = tail.compareAndSet(curTail, update)
+
+    public fun addLast(node: T) {
         tail.loop { curTail ->
             val curNext = curTail.next.value
             if (curNext != null) {
@@ -34,6 +41,22 @@
             }
             if (curTail.next.compareAndSet(null, node)) {
                 tail.compareAndSet(curTail, node)
+                return
+            }
+        }
+    }
+
+    public inline fun addLastIfPrev(node: T, predicate: (prev: Any) -> Boolean): Boolean {
+        while(true) {
+            val curTail = tailValue
+            val curNext = curTail.nextValue
+            if (curNext != null) {
+                tailCas(curTail, curNext)
+                continue // retry
+            }
+            if (!predicate(curTail)) return false
+            if (curTail.nextCas(null, node)) {
+                tailCas(curTail, node)
                 return true
             }
         }
@@ -48,9 +71,7 @@
         }
     }
 
-    fun headCas(curHead: T, update: T) = head.compareAndSet(curHead, update)
-
-    public inline fun removeFirstOrNullIf(predicate: (T) -> Boolean): T? {
+    public inline fun removeFirstOrNullIf(predicate: (first: T) -> Boolean): T? {
         while (true) {
             val curHead = headValue
             val next = curHead.nextValue ?: return null
diff --git a/core/kotlinx-coroutines-core/src/internal/LockFreeMPSCQueue.kt b/core/kotlinx-coroutines-core/src/internal/LockFreeMPSCQueue.kt
index 6ed1cca..7eff402 100644
--- a/core/kotlinx-coroutines-core/src/internal/LockFreeMPSCQueue.kt
+++ b/core/kotlinx-coroutines-core/src/internal/LockFreeMPSCQueue.kt
@@ -5,6 +5,7 @@
 package kotlinx.coroutines.experimental.internal
 
 import kotlinx.atomicfu.*
+import kotlinx.coroutines.experimental.*
 import java.util.concurrent.atomic.*
 
 private typealias Core<E> = LockFreeMPSCQueueCore<E>
@@ -22,7 +23,8 @@
  *
  * @suppress **This is unstable API and it is subject to change.**
  */
-class LockFreeMPSCQueue<E : Any> {
+@InternalCoroutinesApi
+internal class LockFreeMPSCQueue<E : Any> {
     private val _cur = atomic(Core<E>(Core.INITIAL_CAPACITY))
 
     // Note: it is not atomic w.r.t. remove operation (remove can transiently fail when isEmpty is false)
diff --git a/core/kotlinx-coroutines-core/src/internal/ThreadSafeHeap.kt b/core/kotlinx-coroutines-core/src/internal/ThreadSafeHeap.kt
index 7d78d39..a9583eb 100644
--- a/core/kotlinx-coroutines-core/src/internal/ThreadSafeHeap.kt
+++ b/core/kotlinx-coroutines-core/src/internal/ThreadSafeHeap.kt
@@ -10,7 +10,9 @@
 /**
  * @suppress **This is unstable API and it is subject to change.**
  */
+@InternalCoroutinesApi
 public interface ThreadSafeHeapNode {
+    public var heap: ThreadSafeHeap<*>?
     public var index: Int
 }
 
@@ -19,6 +21,7 @@
  *
  * @suppress **This is unstable API and it is subject to change.**
  */
+@InternalCoroutinesApi
 public class ThreadSafeHeap<T> : SynchronizedObject() where T: ThreadSafeHeapNode, T: Comparable<T> {
     private var a: Array<T?>? = null
 
@@ -44,10 +47,10 @@
             null
         }
 
-    @Synchronized
-    public inline fun removeFirstIf(predicate: (T) -> Boolean): T?  {
+    // @Synchronized // NOTE! NOTE! NOTE! inline fun cannot be @Synchronized
+    public inline fun removeFirstIf(predicate: (T) -> Boolean): T? = synchronized(this) {
         val first = firstImpl() ?: return null
-        return if (predicate(first)) {
+        if (predicate(first)) {
             removeAtImpl(0)
         } else {
             null
@@ -57,21 +60,24 @@
     @Synchronized
     public fun addLast(node: T) = addImpl(node)
 
-    @Synchronized
-    public fun addLastIf(node: T, cond: () -> Boolean): Boolean =
+    // @Synchronized // NOTE! NOTE! NOTE! inline fun cannot be @Synchronized
+    public inline fun addLastIf(node: T, cond: () -> Boolean): Boolean = synchronized(this) {
         if (cond()) {
             addImpl(node)
             true
         } else {
             false
         }
+    }
 
     @Synchronized
     public fun remove(node: T): Boolean {
-        return if (node.index < 0) {
+        return if (node.heap == null) {
             false
         } else {
-            removeAtImpl(node.index)
+            val index = node.index
+            check(index >= 0)
+            removeAtImpl(index)
             true
         }
     }
@@ -95,6 +101,8 @@
             }
         }
         val result = a[size]!!
+        check(result.heap === this)
+        result.heap = null
         result.index = -1
         a[size] = null
         return result
@@ -102,11 +110,8 @@
 
     @PublishedApi
     internal fun addImpl(node: T) {
-        // TODO remove this after #541 when ThreadSafeHeapNode is gone
-        if (node is EventLoopBase.DelayedTask && node.state == REMOVED) {
-            return
-        }
-
+        check(node.heap == null)
+        node.heap = this
         val a = realloc()
         val i = size++
         a[i] = node
diff --git a/core/kotlinx-coroutines-core/src/scheduling/CoroutineScheduler.kt b/core/kotlinx-coroutines-core/src/scheduling/CoroutineScheduler.kt
index 23547ac..d1a72c8 100644
--- a/core/kotlinx-coroutines-core/src/scheduling/CoroutineScheduler.kt
+++ b/core/kotlinx-coroutines-core/src/scheduling/CoroutineScheduler.kt
@@ -301,23 +301,29 @@
         val currentWorker = Thread.currentThread() as? Worker
         // Capture # of created workers that cannot change anymore (mind the synchronized block!)
         val created = synchronized(workers) { createdWorkers }
+        // Shutdown all workers with the only exception of the current thread
         for (i in 1..created) {
             val worker = workers[i]!!
-            if (worker.isAlive && worker !== currentWorker) {
-                LockSupport.unpark(worker)
-                worker.join(timeout)
+            if (worker !== currentWorker) {
+                while (worker.isAlive) {
+                    LockSupport.unpark(worker)
+                    worker.join(timeout)
+                }
+                val state = worker.state
+                check(state === WorkerState.TERMINATED) { "Expected TERMINATED state, but found $state"}
                 worker.localQueue.offloadAllWork(globalQueue)
             }
-
         }
+        // Make sure no more work is added to GlobalQueue from anywhere
+        check(globalQueue.add(CLOSED_TASK)) { "GlobalQueue could not be closed yet" }
         // Finish processing tasks from globalQueue and/or from this worker's local queue
         while (true) {
-            val task = currentWorker?.findTask() ?: globalQueue.removeFirstOrNull() ?: break
+            val task = currentWorker?.findTask() ?: globalQueue.removeFirstIfNotClosed() ?: break
             runSafely(task)
         }
         // Shutdown current thread
         currentWorker?.tryReleaseCpu(WorkerState.TERMINATED)
-        // cleanup state to make sure that tryUnpark tries to create new threads and fails because isTerminated
+        // check & cleanup state
         assert(cpuPermits.availablePermits() == corePoolSize)
         parkedWorkersStack.value = 0L
         controlState.value = 0L
@@ -339,8 +345,12 @@
         when (submitToLocalQueue(task, fair)) {
             ADDED -> return
             NOT_ADDED -> {
-                globalQueue.addLast(task) // offload task to local queue
-                requestCpuWorker() // ask for help
+                // try to offload task to global queue
+                if (!globalQueue.add(task)) {
+                    // Global queue is closed in the last step of close/shutdown -- no more tasks should be accepted
+                    throw RejectedExecutionException("$schedulerName was terminated")
+                }
+                requestCpuWorker()
             }
             else -> requestCpuWorker() // ask for help
         }
@@ -439,7 +449,7 @@
     private fun createNewWorker(): Int {
         synchronized(workers) {
             // Make sure we're not trying to resurrect terminated scheduler
-            if (isTerminated) throw RejectedExecutionException("$schedulerName was terminated")
+            if (isTerminated) return -1
             val state = controlState.value
             val created = createdWorkers(state)
             val blocking = blockingWorkers(state)
@@ -464,6 +474,12 @@
             ?: return NOT_ADDED
         if (worker.scheduler !== this) return NOT_ADDED // different scheduler's worker (!!!)
 
+        /*
+         * This worker could have been already terminated from this thread by close/shutdown and it should not
+         * accept any more tasks into its local queue.
+         */
+        if (worker.state === WorkerState.TERMINATED) return NOT_ADDED
+
         var result = ADDED
         if (task.mode == TaskMode.NON_BLOCKING) {
             /*
@@ -923,9 +939,9 @@
              * once per two core pool size iterations
              */
             val globalFirst = nextInt(2 * corePoolSize) == 0
-            if (globalFirst) globalQueue.removeFirstOrNull()?.let { return it }
+            if (globalFirst) globalQueue.removeFirstIfNotClosed()?.let { return it }
             localQueue.poll()?.let { return it }
-            if (!globalFirst) globalQueue.removeFirstOrNull()?.let { return it }
+            if (!globalFirst) globalQueue.removeFirstIfNotClosed()?.let { return it }
             return trySteal()
         }
 
diff --git a/core/kotlinx-coroutines-core/src/scheduling/Dispatcher.kt b/core/kotlinx-coroutines-core/src/scheduling/Dispatcher.kt
index a21c768..7a718f5 100644
--- a/core/kotlinx-coroutines-core/src/scheduling/Dispatcher.kt
+++ b/core/kotlinx-coroutines-core/src/scheduling/Dispatcher.kt
@@ -26,6 +26,7 @@
  * @suppress **This is unstable API and it is subject to change.**
  */
 // TODO make internal (and rename) after complete integration
+@InternalCoroutinesApi
 open class ExperimentalCoroutineDispatcher(
     private val corePoolSize: Int,
     private val maxPoolSize: Int,
@@ -47,10 +48,18 @@
     private var coroutineScheduler = createScheduler()
 
     override fun dispatch(context: CoroutineContext, block: Runnable): Unit =
-        coroutineScheduler.dispatch(block)
+        try {
+            coroutineScheduler.dispatch(block)
+        } catch (e: RejectedExecutionException) {
+            DefaultExecutor.dispatch(context, block)
+        }
 
     override fun dispatchYield(context: CoroutineContext, block: Runnable): Unit =
-        coroutineScheduler.dispatch(block, fair = true)
+        try {
+            coroutineScheduler.dispatch(block, fair = true)
+        } catch (e: RejectedExecutionException) {
+            DefaultExecutor.dispatchYield(context, block)
+        }
 
     override fun close() = coroutineScheduler.close()
 
@@ -84,7 +93,11 @@
     }
 
     internal fun dispatchWithContext(block: Runnable, context: TaskContext, fair: Boolean): Unit =
-        coroutineScheduler.dispatch(block, context, fair)
+        try {
+            coroutineScheduler.dispatch(block, context, fair)
+        } catch (e: RejectedExecutionException) {
+            DefaultExecutor.execute(block)
+        }
 
     private fun createScheduler() = CoroutineScheduler(corePoolSize, maxPoolSize, idleWorkerKeepAliveNs)
 
diff --git a/core/kotlinx-coroutines-core/src/scheduling/Tasks.kt b/core/kotlinx-coroutines-core/src/scheduling/Tasks.kt
index 545a5bb..bf0b1dc 100644
--- a/core/kotlinx-coroutines-core/src/scheduling/Tasks.kt
+++ b/core/kotlinx-coroutines-core/src/scheduling/Tasks.kt
@@ -101,8 +101,19 @@
         "Task[${block.classSimpleName}@${block.hexAddress}, $submissionTime, $taskContext]"
 }
 
+private val EMPTY_RUNNABLE = Runnable {}
+internal val CLOSED_TASK = Task(EMPTY_RUNNABLE, 0, NonBlockingContext)
+
 // Open for tests
 internal open class GlobalQueue : LockFreeMPMCQueue<Task>() {
+    // Returns false when GlobalQueue was was already closed
+    public fun add(task: Task): Boolean =
+        addLastIfPrev(task) { prev -> prev !== CLOSED_TASK }
+
+    // Returns null when GlobalQueue was was already closed
+    public fun removeFirstIfNotClosed(): Task? =
+        removeFirstOrNullIf { first -> first !== CLOSED_TASK }
+
     // Open for tests
     public open fun removeFirstBlockingModeOrNull(): Task? =
         removeFirstOrNullIf { it.mode == TaskMode.PROBABLY_BLOCKING }
diff --git a/core/kotlinx-coroutines-core/src/scheduling/WorkQueue.kt b/core/kotlinx-coroutines-core/src/scheduling/WorkQueue.kt
index f41b0f7..d097f18 100644
--- a/core/kotlinx-coroutines-core/src/scheduling/WorkQueue.kt
+++ b/core/kotlinx-coroutines-core/src/scheduling/WorkQueue.kt
@@ -140,14 +140,23 @@
     private fun offloadWork(globalQueue: GlobalQueue) {
         repeat((bufferSize / 2).coerceAtLeast(1)) {
             val task = pollExternal() ?: return
-            globalQueue.addLast(task)
+            addToGlobalQueue(globalQueue, task)
         }
     }
 
+    private fun addToGlobalQueue(globalQueue: GlobalQueue, task: Task) {
+        /*
+         * globalQueue is closed as the very last step in the shutdown sequence when all worker threads had
+         * been already shutdown (with the only exception of the last worker thread that might be performing
+         * shutdown procedure itself). As a consistency check we do a [cheap!] check that it is not closed here yet.
+         */
+        check(globalQueue.add(task)) { "GlobalQueue could not be closed yet" }
+    }
+
     internal fun offloadAllWork(globalQueue: GlobalQueue) {
+        lastScheduledTask.getAndSet(null)?.let { addToGlobalQueue(globalQueue, it) }
         while (true) {
-            val task = pollExternal() ?: return
-            globalQueue.addLast(task)
+            addToGlobalQueue(globalQueue, pollExternal() ?: return)
         }
     }
 
diff --git a/core/kotlinx-coroutines-core/src/test_/TestCoroutineContext.kt b/core/kotlinx-coroutines-core/src/test_/TestCoroutineContext.kt
index deb3e1a..70dc0f1 100644
--- a/core/kotlinx-coroutines-core/src/test_/TestCoroutineContext.kt
+++ b/core/kotlinx-coroutines-core/src/test_/TestCoroutineContext.kt
@@ -239,6 +239,7 @@
     private val count: Long = 0,
     @JvmField internal val time: Long = 0
 ) : Comparable<TimedRunnable>, Runnable by run, ThreadSafeHeapNode {
+    override var heap: ThreadSafeHeap<*>? = null
     override var index: Int = 0
 
     override fun run() = run.run()
diff --git a/core/kotlinx-coroutines-core/test/exceptions/WithContextExceptionHandlingTest.kt b/core/kotlinx-coroutines-core/test/exceptions/WithContextExceptionHandlingTest.kt
index 4d54950..5b1efec 100644
--- a/core/kotlinx-coroutines-core/test/exceptions/WithContextExceptionHandlingTest.kt
+++ b/core/kotlinx-coroutines-core/test/exceptions/WithContextExceptionHandlingTest.kt
@@ -13,11 +13,13 @@
 import kotlin.test.*
 
 @RunWith(Parameterized::class)
-class WithContextExceptionHandlingTest(private val withContext: Boolean) : TestBase() {
+class WithContextExceptionHandlingTest(private val mode: Mode) : TestBase() {
+    enum class Mode { WITH_CONTEXT, ASYNC_AWAIT }
+
     companion object {
-        @Parameterized.Parameters(name = "withContext={0}")
+        @Parameterized.Parameters(name = "mode={0}")
         @JvmStatic
-        fun params(): Collection<Array<Any>> = listOf<Array<Any>>(arrayOf(true), arrayOf(false))
+        fun params(): Collection<Array<Any>> = Mode.values().map { arrayOf<Any>(it) }
     }
 
     @Test
@@ -106,16 +108,14 @@
         /*
          * context cancelled with ISE
          * block itself throws CE(IOE)
-         * Result: ISE suppressed IOE
+         * Result: ISE (because cancellation exception is always ignored and not handled)
          */
         val cancellationCause = IllegalStateException()
         val thrown = CancellationException()
         thrown.initCause(IOException())
         runCancellation(cancellationCause, thrown) { e ->
             assertSame(cancellationCause, e)
-            val suppressed = e.suppressed
-            assertEquals(1, suppressed.size)
-            assertTrue(suppressed[0] is IOException)
+            assertTrue(e.suppressed.isEmpty())
         }
     }
 
@@ -161,10 +161,11 @@
 
     @Test
     fun testThrowingCancellationWithCause() = runTest {
+        // Exception are never unwrapped, so if CE(IOE) is thrown then it is the cancellation cause
         val thrown = CancellationException()
         thrown.initCause(IOException())
         runThrowing(thrown) { e ->
-           checkException<IOException>(e)
+           assertSame(thrown, e)
         }
     }
 
@@ -247,12 +248,11 @@
     }
 
     private suspend fun withCtx(context: CoroutineContext, job: Job = Job(), block: suspend CoroutineScope.(Job) -> Nothing) {
-        if (withContext) {
-            withContext(context + job) {
+        when (mode) {
+            Mode.WITH_CONTEXT -> withContext(context + job) {
                 block(job)
             }
-        } else {
-            CoroutineScope(coroutineContext).async(context + job) {
+            Mode.ASYNC_AWAIT -> CoroutineScope(coroutineContext).async(context + job) {
                 block(job)
             }.await()
         }
diff --git a/core/kotlinx-coroutines-core/test/internal/ThreadSafeHeapTest.kt b/core/kotlinx-coroutines-core/test/internal/ThreadSafeHeapTest.kt
index 12a24a5..d8331d5 100644
--- a/core/kotlinx-coroutines-core/test/internal/ThreadSafeHeapTest.kt
+++ b/core/kotlinx-coroutines-core/test/internal/ThreadSafeHeapTest.kt
@@ -10,6 +10,7 @@
 
 class ThreadSafeHeapTest : TestBase() {
     class Node(val value: Int) : ThreadSafeHeapNode, Comparable<Node> {
+        override var heap: ThreadSafeHeap<*>? = null
         override var index = -1
         override fun compareTo(other: Node): Int = value.compareTo(other.value)
         override fun equals(other: Any?): Boolean = other is Node && other.value == value
diff --git a/core/kotlinx-coroutines-core/test/scheduling/CoroutineSchedulerCloseStressTest.kt b/core/kotlinx-coroutines-core/test/scheduling/CoroutineSchedulerCloseStressTest.kt
new file mode 100644
index 0000000..349319d
--- /dev/null
+++ b/core/kotlinx-coroutines-core/test/scheduling/CoroutineSchedulerCloseStressTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.experimental.scheduling
+
+import kotlinx.atomicfu.*
+import kotlinx.coroutines.experimental.*
+import org.junit.Test
+import java.util.*
+import kotlin.test.*
+
+class CoroutineSchedulerCloseStressTest : TestBase() {
+    private val N_REPEAT = 2 * stressTestMultiplier
+    private val MAX_LEVEL = 5
+    private val N_COROS = (1 shl (MAX_LEVEL + 1)) - 1
+    private val N_THREADS = 4
+    private val rnd = Random()
+
+    private lateinit var dispatcher: ExecutorCoroutineDispatcher
+    private var closeIndex = -1
+
+    private val started = atomic(0)
+    private val finished = atomic(0)
+
+    @Test
+    fun testNormalClose() {
+        try {
+            launchCoroutines()
+        } finally {
+            dispatcher.close()
+        }
+    }
+
+    @Test
+    fun testRacingClose() {
+        repeat(N_REPEAT) {
+            closeIndex = rnd.nextInt(N_COROS)
+            launchCoroutines()
+        }
+    }
+
+    private fun launchCoroutines() = runBlocking {
+        dispatcher = ExperimentalCoroutineDispatcher(N_THREADS)
+        started.value = 0
+        finished.value = 0
+        withContext(dispatcher) {
+            launchChild(0, 0)
+        }
+        assertEquals(N_COROS, started.value)
+        assertEquals(N_COROS, finished.value)
+    }
+
+    private fun CoroutineScope.launchChild(index: Int, level: Int): Job = launch(start = CoroutineStart.ATOMIC) {
+        started.incrementAndGet()
+        try {
+            if (index == closeIndex) dispatcher.close()
+            if (level < MAX_LEVEL) {
+                launchChild(2 * index + 1, level + 1)
+                launchChild(2 * index + 2, level + 1)
+            } else {
+                delay(1000)
+            }
+        } finally {
+            finished.incrementAndGet()
+        }
+    }
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index acb537e..848d32b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,12 +1,12 @@
 # Kotlin
-version=0.30.0-SNAPSHOT
+version=0.30.1-SNAPSHOT
 group=org.jetbrains.kotlinx
 kotlin_version=1.2.70
 kotlin_native_version=0.8.2
 
 # Dependencies
 junit_version=4.12
-atomicFU_version=0.11.5
+atomicFU_version=0.11.10
 html_version=0.6.8
 lincheck_version=1.9
 dokka_version=0.9.16-rdev-2-mpp-hacks
diff --git a/js/kotlinx-coroutines-core-js/src/Dispatchers.kt b/js/kotlinx-coroutines-core-js/src/Dispatchers.kt
new file mode 100644
index 0000000..8679199
--- /dev/null
+++ b/js/kotlinx-coroutines-core-js/src/Dispatchers.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.experimental
+
+import kotlin.coroutines.experimental.*
+
+actual object Dispatchers {
+
+    public actual val Default: CoroutineDispatcher = createDefaultDispatcher()
+
+    public actual val Main: MainCoroutineDispatcher = JsMainDispatcher(Default)
+
+    public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.experimental.Unconfined
+}
+
+private class JsMainDispatcher(val delegate: CoroutineDispatcher) : MainCoroutineDispatcher() {
+
+    override val immediate: MainCoroutineDispatcher
+        get() = throw UnsupportedOperationException("Immediate dispatching is not supported on JS")
+
+    override fun dispatch(context: CoroutineContext, block: Runnable) = delegate.dispatch(context, block)
+
+    override fun isDispatchNeeded(context: CoroutineContext): Boolean = delegate.isDispatchNeeded(context)
+
+    override fun dispatchYield(context: CoroutineContext, block: Runnable) = delegate.dispatchYield(context, block)
+
+    override fun toString(): String = delegate.toString()
+}
diff --git a/native/README.md b/native/README.md
index b055e49..e795868 100644
--- a/native/README.md
+++ b/native/README.md
@@ -42,7 +42,7 @@
 }
 
 dependencies {
-    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-native:0.30.0'
+    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-native:0.30.1'
 }
 
 sourceSets {
diff --git a/native/kotlinx-coroutines-core-native/src/Dispatchers.kt b/native/kotlinx-coroutines-core-native/src/Dispatchers.kt
new file mode 100644
index 0000000..759743c
--- /dev/null
+++ b/native/kotlinx-coroutines-core-native/src/Dispatchers.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.experimental
+
+import kotlin.coroutines.experimental.*
+
+
+actual object Dispatchers {
+
+    public actual val Default: CoroutineDispatcher = createDefaultDispatcher()
+
+    public actual val Main: MainCoroutineDispatcher = NativeMainDispatcher(Default)
+
+    public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.experimental.Unconfined
+}
+
+private class NativeMainDispatcher(val delegate: CoroutineDispatcher) : MainCoroutineDispatcher() {
+
+    override val immediate: MainCoroutineDispatcher
+        get() = throw UnsupportedOperationException("Immediate dispatching is not supported on Native")
+
+    override fun dispatch(context: CoroutineContext, block: Runnable) = delegate.dispatch(context, block)
+
+    override fun isDispatchNeeded(context: CoroutineContext): Boolean = delegate.isDispatchNeeded(context)
+
+    override fun dispatchYield(context: CoroutineContext, block: Runnable) = delegate.dispatchYield(context, block)
+
+    override fun toString(): String = delegate.toString()
+}
diff --git a/ui/README.md b/ui/README.md
index db5b92d..0417ff9 100644
--- a/ui/README.md
+++ b/ui/README.md
@@ -1,6 +1,7 @@
 # Coroutines for UI
 
 This directory contains modules for coroutine programming with various single-threaded UI libraries.
+After adding dependency to the UI library, corresponding UI dispatcher will be available via `Dispatchers.Main`.
 Module name below corresponds to the artifact name in Maven/Gradle.
 
 ## Modules
diff --git a/ui/coroutines-guide-ui.md b/ui/coroutines-guide-ui.md
index 4a75762..ed6c165 100644
--- a/ui/coroutines-guide-ui.md
+++ b/ui/coroutines-guide-ui.md
@@ -71,6 +71,10 @@
 * [kotlinx-coroutines-javafx](kotlinx-coroutines-javafx) -- `Dispatchers.JavaFx` context for JavaFX UI applications.
 * [kotlinx-coroutines-swing](kotlinx-coroutines-swing) -- `Dispatchers.Swing` context for Swing UI applications.
 
+Also, UI dispatcher is available via `Dispatchers.Main` from `kotlinx-coroutines-core` and corresponding 
+implementation (Android, JavaFx or Swing) is discovered by [`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html) API.
+For example, if you are writing JavaFx application, you can use either `Dispatchers.Main` or `Dispachers.JavaFx` extension, it will be the same object.
+
 This guide covers all UI libraries simultaneously, because each of these modules consists of just one
 object definition that is a couple of pages long. You can use any of them as an example to write the corresponding
 context object for your favourite UI library, even if it is not included out of the box here.
@@ -161,7 +165,7 @@
 `app/build.gradle` file:
 
 ```groovy
-compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.30.0"
+compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.30.1"
 ```
 
 Coroutines are experimental feature in Kotlin.
diff --git a/ui/kotlinx-coroutines-android/animation-app/gradle.properties b/ui/kotlinx-coroutines-android/animation-app/gradle.properties
index d3701fd..80d2f47 100644
--- a/ui/kotlinx-coroutines-android/animation-app/gradle.properties
+++ b/ui/kotlinx-coroutines-android/animation-app/gradle.properties
@@ -19,5 +19,5 @@
 kotlin.coroutines=enable
 
 kotlin_version=1.2.70
-coroutines_version=0.30.0
+coroutines_version=0.30.1
 
diff --git a/ui/kotlinx-coroutines-android/example-app/gradle.properties b/ui/kotlinx-coroutines-android/example-app/gradle.properties
index d3701fd..80d2f47 100644
--- a/ui/kotlinx-coroutines-android/example-app/gradle.properties
+++ b/ui/kotlinx-coroutines-android/example-app/gradle.properties
@@ -19,5 +19,5 @@
 kotlin.coroutines=enable
 
 kotlin_version=1.2.70
-coroutines_version=0.30.0
+coroutines_version=0.30.1
 
diff --git a/ui/kotlinx-coroutines-android/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory b/ui/kotlinx-coroutines-android/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory
new file mode 100644
index 0000000..b1b6654
--- /dev/null
+++ b/ui/kotlinx-coroutines-android/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory
@@ -0,0 +1 @@
+kotlinx.coroutines.experimental.android.AndroidDispatcherFactory
diff --git a/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt b/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
index 1b2c4b1..dd27bba 100644
--- a/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
+++ b/ui/kotlinx-coroutines-android/src/HandlerDispatcher.kt
@@ -7,24 +7,26 @@
 package kotlinx.coroutines.experimental.android
 
 import android.os.*
-import android.support.annotation.VisibleForTesting
+import android.support.annotation.*
 import android.view.*
 import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.internal.MainDispatcherFactory
 import java.lang.reflect.Constructor
 import kotlin.coroutines.experimental.*
 
 /**
  * Dispatches execution onto Android main thread and provides native [delay][Delay.delay] support.
  */
+@Deprecated(level = DeprecationLevel.HIDDEN, message = "Deprecated in favor of Dispatchers property")
 public val Dispatchers.Main: HandlerDispatcher
-    get() = kotlinx.coroutines.experimental.android.Main
+    get() = MainDispatcher
 
 /**
  * Dispatches execution onto Android [Handler].
  *
  * This class provides type-safety and a point for future extensions.
  */
-public sealed class HandlerDispatcher : CoroutineDispatcher(), Delay {
+public sealed class HandlerDispatcher : MainCoroutineDispatcher(), Delay {
     /**
      * Returns dispatcher that executes coroutines immediately when it is already in the right handler context
      * (current looper is the same as this handler's looper). See [isDispatchNeeded] documentation on
@@ -33,7 +35,15 @@
      * **Note: This is an experimental api.** Semantics of this dispatcher may change in the future.
      */
     @ExperimentalCoroutinesApi
-    public abstract val immediate: HandlerDispatcher
+    public abstract override val immediate: HandlerDispatcher
+}
+
+@Keep
+internal class AndroidDispatcherFactory : MainDispatcherFactory {
+    override fun createDispatcher(): MainCoroutineDispatcher = Main
+
+    override val loadPriority: Int
+        get() = Int.MAX_VALUE
 }
 
 /**
@@ -76,6 +86,8 @@
 @JvmField // this is for a nice Java API, see issue #255
 internal val Main: HandlerDispatcher = HandlerContext(mainHandler, "Main")
 
+private val MainDispatcher: HandlerDispatcher = Main // Alias
+
 /**
  * Implements [CoroutineDispatcher] on top of an arbitrary Android [Handler].
  * @suppress **Deprecated**: Use [HandlerDispatcher].
diff --git a/ui/kotlinx-coroutines-javafx/README.md b/ui/kotlinx-coroutines-javafx/README.md
index 32a8aa2..de763ab 100644
--- a/ui/kotlinx-coroutines-javafx/README.md
+++ b/ui/kotlinx-coroutines-javafx/README.md
@@ -1,10 +1,10 @@
 # Module kotlinx-coroutines-javafx
 
-Provides `Dispatchers.JavaFx` context for JavaFX UI applications.
+Provides `Dispatchers.JavaFx` context and `Dispatchers.Main` implementation for JavaFX UI applications.
 
 Read [Guide to UI programming with coroutines](https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md)
 for tutorial on this module.
 
 # Package kotlinx.coroutines.experimental.javafx
 
-Provides `Dispatchers.JavaFx` context for JavaFX UI applications.
+Provides `Dispatchers.JavaFx` context and `Dispatchers.Main` implementation for JavaFX UI applications.
diff --git a/ui/kotlinx-coroutines-javafx/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory b/ui/kotlinx-coroutines-javafx/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory
new file mode 100644
index 0000000..b590694
--- /dev/null
+++ b/ui/kotlinx-coroutines-javafx/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory
@@ -0,0 +1 @@
+kotlinx.coroutines.experimental.javafx.JavaFxDispatcherFactory
diff --git a/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt b/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt
index cc5ddf0..23c74cb 100644
--- a/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt
+++ b/ui/kotlinx-coroutines-javafx/src/JavaFxDispatcher.kt
@@ -9,12 +9,14 @@
 import javafx.event.*
 import javafx.util.*
 import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.internal.*
 import java.util.concurrent.*
 import kotlin.coroutines.experimental.*
 
 /**
  * Dispatches execution onto JavaFx application thread and provides native [delay] support.
  */
+@Suppress("unused")
 public val Dispatchers.JavaFx: JavaFxDispatcher
     get() = kotlinx.coroutines.experimental.javafx.JavaFx
 
@@ -23,40 +25,10 @@
  *
  * This class provides type-safety and a point for future extensions.
  */
-public sealed class JavaFxDispatcher : CoroutineDispatcher(), Delay
-
-/**
- * Dispatches execution onto JavaFx application thread and provides native [delay] support.
- * @suppress **Deprecated**: Use [Dispatchers.JavaFx].
- */
-@Deprecated(
-    message = "Use Dispatchers.JavaFx",
-    replaceWith = ReplaceWith("Dispatchers.JavaFx",
-        imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.javafx.JavaFx"])
-)
-// todo: it will become an internal implementation object
-object JavaFx : JavaFxDispatcher() {
-    init {
-        // :kludge: to make sure Toolkit is initialized if we use JavaFx dispatcher outside of JavaFx app
-        initPlatform()
-    }
+public sealed class JavaFxDispatcher : MainCoroutineDispatcher(), Delay {
 
     override fun dispatch(context: CoroutineContext, block: Runnable) = Platform.runLater(block)
 
-    /**
-     * Suspends coroutine until next JavaFx pulse and returns time of the pulse on resumption.
-     * If the [Job] of the current coroutine is completed while this suspending function is waiting, this function
-     * immediately resumes with [CancellationException] .
-     *
-     * @suppress **Deprecated**: Use top-level [awaitPulse].
-     */
-    @Deprecated(
-        message = "Use top-level awaitFrame",
-        replaceWith = ReplaceWith("kotlinx.coroutines.experimental.javafx.awaitPulse()")
-    )
-    suspend fun awaitPulse(): Long =
-        kotlinx.coroutines.experimental.javafx.awaitPulse()
-
     override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
         val timeline = schedule(timeMillis, TimeUnit.MILLISECONDS, EventHandler {
             with(continuation) { resumeUndispatched(Unit) }
@@ -77,6 +49,57 @@
 
     private fun schedule(time: Long, unit: TimeUnit, handler: EventHandler<ActionEvent>): Timeline =
         Timeline(KeyFrame(Duration.millis(unit.toMillis(time).toDouble()), handler)).apply { play() }
+}
+
+internal class JavaFxDispatcherFactory : MainDispatcherFactory {
+    override fun createDispatcher(): MainCoroutineDispatcher = JavaFx
+
+    override val loadPriority: Int
+        get() = 1 // Swing has 0
+}
+
+private object ImmediateJavaFxDispatcher : JavaFxDispatcher() {
+    override val immediate: MainCoroutineDispatcher
+        get() = this
+
+    override fun isDispatchNeeded(context: CoroutineContext): Boolean = !Platform.isFxApplicationThread()
+
+    override fun toString() = "JavaFx [immediate]"
+}
+
+/**
+ * Dispatches execution onto JavaFx application thread and provides native [delay] support.
+ * @suppress **Deprecated**: Use [Dispatchers.JavaFx].
+ */
+@Deprecated(
+    message = "Use Dispatchers.JavaFx",
+    replaceWith = ReplaceWith("Dispatchers.JavaFx",
+        imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.javafx.JavaFx"])
+)
+// todo: it will become an internal implementation object
+object JavaFx : JavaFxDispatcher() {
+    init {
+        // :kludge: to make sure Toolkit is initialized if we use JavaFx dispatcher outside of JavaFx app
+        initPlatform()
+    }
+
+    override val immediate: MainCoroutineDispatcher
+        get() = ImmediateJavaFxDispatcher
+
+    /**
+     * Suspends coroutine until next JavaFx pulse and returns time of the pulse on resumption.
+     * If the [Job] of the current coroutine is completed while this suspending function is waiting, this function
+     * immediately resumes with [CancellationException] .
+     *
+     * @suppress **Deprecated**: Use top-level [awaitPulse].
+     */
+    @Deprecated(
+        message = "Use top-level awaitFrame",
+        replaceWith = ReplaceWith("kotlinx.coroutines.experimental.javafx.awaitPulse()")
+    )
+    suspend fun awaitPulse(): Long =
+        kotlinx.coroutines.experimental.javafx.awaitPulse()
+
 
     override fun toString() = "JavaFx"
 }
diff --git a/ui/kotlinx-coroutines-swing/README.md b/ui/kotlinx-coroutines-swing/README.md
index dbd15d7..140da35 100644
--- a/ui/kotlinx-coroutines-swing/README.md
+++ b/ui/kotlinx-coroutines-swing/README.md
@@ -1,10 +1,10 @@
 # Module kotlinx-coroutines-swing
 
-Provides `Dispatchers.Swing` context for Swing UI applications.
+Provides `Dispatchers.Swing` context and `Dispatchers.Main` implementation for Swing UI applications.
 
 Read [Guide to UI programming with coroutines](https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md)
 for tutorial on this module.
 
 # Package kotlinx.coroutines.experimental.swing
 
-Provides `Dispatchers.Swing` context for Swing UI applications.
+Provides `Dispatchers.Swing` context and `Dispatchers.Main` implementation  for Swing UI applications.
diff --git a/ui/kotlinx-coroutines-swing/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory b/ui/kotlinx-coroutines-swing/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory
new file mode 100644
index 0000000..59969a7
--- /dev/null
+++ b/ui/kotlinx-coroutines-swing/resources/META-INF/services/kotlinx.coroutines.experimental.internal.MainDispatcherFactory
@@ -0,0 +1 @@
+kotlinx.coroutines.experimental.swing.SwingDispatcherFactory
diff --git a/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt b/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt
index a78e2ed..71dadb8 100644
--- a/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt
+++ b/ui/kotlinx-coroutines-swing/src/SwingDispatcher.kt
@@ -4,7 +4,9 @@
 
 package kotlinx.coroutines.experimental.swing
 
+import javafx.application.*
 import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.internal.*
 import java.awt.event.*
 import java.util.concurrent.*
 import javax.swing.*
@@ -13,6 +15,7 @@
 /**
  * Dispatches execution onto Swing event dispatching thread and provides native [delay] support.
  */
+@Suppress("unused")
 public val Dispatchers.Swing : SwingDispatcher
     get() = kotlinx.coroutines.experimental.swing.Swing
 
@@ -21,19 +24,7 @@
  *
  * This class provides type-safety and a point for future extensions.
  */
-public sealed class SwingDispatcher : CoroutineDispatcher(), Delay
-
-/**
- * Dispatches execution onto Swing event dispatching thread and provides native [delay] support.
- * @suppress **Deprecated**: Use [Dispatchers.Swing].
- */
-@Deprecated(
-    message = "Use Dispatchers.Swing",
-    replaceWith = ReplaceWith("Dispatchers.Swing",
-        imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.swing.Swing"])
-)
-// todo: it will become an internal implementation object
-object Swing : SwingDispatcher() {
+public sealed class SwingDispatcher : MainCoroutineDispatcher(), Delay {
     override fun dispatch(context: CoroutineContext, block: Runnable) = SwingUtilities.invokeLater(block)
 
     override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
@@ -59,6 +50,37 @@
             isRepeats = false
             start()
         }
+}
+
+internal class SwingDispatcherFactory : MainDispatcherFactory {
+    override val loadPriority: Int
+        get() = 0
+
+    override fun createDispatcher(): MainCoroutineDispatcher = Swing
+}
+
+private object ImmediateSwingDispatcher : SwingDispatcher() {
+    override val immediate: MainCoroutineDispatcher
+        get() = this
+
+    override fun isDispatchNeeded(context: CoroutineContext): Boolean = !SwingUtilities.isEventDispatchThread()
+
+    override fun toString() = "Swing [immediate]"
+}
+
+/**
+ * Dispatches execution onto Swing event dispatching thread and provides native [delay] support.
+ * @suppress **Deprecated**: Use [Dispatchers.Swing].
+ */
+@Deprecated(
+    message = "Use Dispatchers.Swing",
+    replaceWith = ReplaceWith("Dispatchers.Swing",
+        imports = ["kotlinx.coroutines.experimental.Dispatchers", "kotlinx.coroutines.experimental.swing.Swing"])
+)
+// todo: it will become an internal implementation object
+object Swing : SwingDispatcher() {
+    override val immediate: MainCoroutineDispatcher
+        get() = ImmediateSwingDispatcher
 
     override fun toString() = "Swing"
 }