Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e09d9ce3 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I15a59ba0,I8289df7d into main

* changes:
  [kairos] drop init block after initialization
  [kairos] finish outputs before ending transaction
parents ed62dbf6 2e90bf7b
Loading
Loading
Loading
Loading
+16 −9
Original line number Diff line number Diff line
@@ -17,35 +17,42 @@
package com.android.systemui.kairos.internal

import com.android.systemui.kairos.util.Maybe
import kotlinx.coroutines.ExperimentalCoroutinesApi

/** Performs actions once, when the reactive component is first connected to the network. */
internal class Init<out A>(val name: String?, private val block: InitScope.() -> A) {
internal class Init<out A>(val name: String?, initBlock: InitScope.() -> A) {

    private var block: (InitScope.() -> A)? = initBlock

    /**
     * Stores the result after initialization, as well as the id of the [Network] it's been
     * initialized with.
     */
    private val cache = CompletableLazy<Pair<Any, A>>()
    private val cache = CompletableLazy<Initialized<A>>()

    fun connect(evalScope: InitScope): A =
        if (cache.isInitialized()) {
    fun connect(evalScope: InitScope): A {
        val block = block
        if (block == null) {
            // Read from cache
            val (networkId, result) = cache.value
            check(networkId == evalScope.networkId) { "Network mismatch" }
            result
            return result
        } else {
            // Write to cache
            block(evalScope).also { cache.setValue(evalScope.networkId to it) }
            return block(evalScope).also {
                cache.setValue(Initialized(evalScope.networkId, it))
                this.block = null
            }
        }
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    fun getUnsafe(): Maybe<A> =
        if (cache.isInitialized()) {
            Maybe.present(cache.value.second)
            Maybe.present(cache.value.value)
        } else {
            Maybe.absent
        }

    private data class Initialized<A>(val networkId: Any, val value: A)
}

@Suppress("NOTHING_TO_INLINE")
+35 −48
Original line number Diff line number Diff line
@@ -34,8 +34,6 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.isActive
import kotlinx.coroutines.job
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.yield

private val nextNetworkId = AtomicLong()
@@ -78,7 +76,6 @@ internal class Network(
    private val muxMovers = ArrayDeque<MuxDeferredNode<*, *, *>>()
    private val deactivations = ArrayDeque<PushNode<*>>()
    private val outputDeactivations = ArrayDeque<Output<*>>()
    private val transactionMutex = Mutex()
    private val inputScheduleChan = Channel<ScheduledAction<*>>()

    override fun scheduleOutput(output: Output<*>) {
@@ -133,7 +130,6 @@ internal class Network(
                    }
                }
            }
            transactionMutex.withLock {
            val e = epoch
            logDuration(indent = 0, { "Kairos Transaction epoch=$e" }, trace = true) {
                val evalScope =
@@ -148,7 +144,7 @@ internal class Network(
                        }
                    }
                    // Step through the network
                        doTransaction(evalScope)
                    coroutineScope { doTransaction(evalScope, coroutineScope = this) }
                } catch (e: Exception) {
                    // Signal failure
                    while (actions.isNotEmpty()) {
@@ -167,7 +163,6 @@ internal class Network(
            }
        }
    }
    }

    /** Evaluates [block] inside of a new transaction when the network is ready. */
    fun <R> transaction(reason: String, block: EvalScope.() -> R): Deferred<R> =
@@ -189,7 +184,7 @@ internal class Network(
        block().also { deferScopeImpl.drainDeferrals() }

    /** Performs a transactional update of the Kairos network. */
    private fun LogIndent.doTransaction(evalScope: EvalScope) {
    private fun LogIndent.doTransaction(evalScope: EvalScope, coroutineScope: CoroutineScope) {
        // Traverse network, then run outputs
        logDuration({ "traverse network" }, trace = true) {
            do {
@@ -204,7 +199,7 @@ internal class Network(
                }
            )
        }
        coroutineScope.launch { evalLaunchedOutputs() }
        evalLaunchedOutputs(coroutineScope)
        // Update states
        logDuration({ "write states" }, trace = true) {
            runThenDrainDeferrals { evalStateWriters(currentLogIndent, evalScope) }
@@ -237,15 +232,11 @@ internal class Network(
        return true
    }

    private suspend fun evalLaunchedOutputs() {
        // Outputs might enqueue other outputs, so we need two loops
        while (outputsByDispatcher.isNotEmpty()) {
            var launchedAny = false
            coroutineScope {
    private fun evalLaunchedOutputs(coroutineScope: CoroutineScope) {
        if (outputsByDispatcher.isEmpty()) return
        for ((key, outputs) in outputsByDispatcher) {
            if (outputs.isNotEmpty()) {
                        launchedAny = true
                        launch(key) {
                coroutineScope.launch(key) {
                    while (outputs.isNotEmpty()) {
                        val output = outputs.removeFirst()
                        launch { output() }
@@ -253,12 +244,8 @@ internal class Network(
                }
            }
        }
            }
            if (!launchedAny) {
        outputsByDispatcher.clear()
    }
        }
    }

    private fun evalMuxMovers(logIndent: Int, evalScope: EvalScope) {
        while (muxMovers.isNotEmpty()) {