All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.paralleluniverse.kotlin.Actor.kt Maven / Gradle / Ivy

There is a newer version: 0.8.0
Show newest version
/*
 * Quasar: lightweight threads and actors for the JVM.
 * Copyright (c) 2015, Parallel Universe Software Co. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 3.0
 * as published by the Free Software Foundation.
 */
package co.paralleluniverse.kotlin

import co.paralleluniverse.actors.KotlinActorSupport
import java.util.concurrent.TimeUnit
import co.paralleluniverse.actors.LifecycleMessage
import co.paralleluniverse.actors.Actor as JActor
import java.util.concurrent.TimeoutException
import co.paralleluniverse.fibers.Suspendable
import co.paralleluniverse.actors.ActorRef
import co.paralleluniverse.fibers.Fiber
import co.paralleluniverse.strands.SuspendableCallable
import co.paralleluniverse.strands.queues.QueueIterator

/**
 * Ported from {@link co.paralleluniverse.actors.SelectiveReceiveHelper}
 *
 * @author circlespainter
 */
public abstract class Actor : KotlinActorSupport() {
    public companion object {
        object DeferException : Exception()
        public object Timeout
    }

    protected var currentMessage: Any? = null

    /**
     * Higher-order selective receive
     */
    inline protected fun receive(proc: (Any) -> Any?) {
        receive(-1, null, proc)
    }

    /**
     * Let the actor handle lifecycle messages
     */
    override protected fun handleLifecycleMessage(lcm: LifecycleMessage): Any? {
        return lcm
    }

    /**
     * Higher-order selective receive
     */
    inline protected fun receive(timeout: Long, unit: TimeUnit?, proc: (Any) -> Any?) {
        assert(JActor.currentActor() == null || JActor.currentActor() == this)

        val mailbox = mailbox()

        checkThrownIn1()
        mailbox.maybeSetCurrentStrandAsOwner()

        val start = if (timeout > 0) System.nanoTime() else 0
        var now: Long
        var left = if (unit != null) unit.toNanos(timeout) else 0
        val deadline = start + left

        monitorResetSkippedMessages()
        var i: Int = 0
        val it: QueueIterator = mailboxQueue().iterator()
        while (true) {
            if (flightRecorder != null)
                record(1, "KotlinActor", "receive", "%s waiting for a message. %s", this, if (timeout > 0) "millis left: " + TimeUnit.MILLISECONDS.convert(left, TimeUnit.NANOSECONDS) else "")

            mailbox.lock()

            if (it.hasNext()) {
                val m = it.next()
                mailbox.unlock()
                if (m == currentMessage) {
                    it.remove()
                    continue
                }

                record(1, "KotlinActor", "receive", "Received %s <- %s", this, m)
                monitorAddMessage()
                if (m is LifecycleMessage) {
                    it.remove()
                    handleLifecycleMessage(m)
                } else {
                    currentMessage = m
                    try {
                        val res = proc(m)

                        if (res != null) {
                            checkAndRemove(it, m)
                            return
                        } else // Discard
                            checkAndRemove(it, m)

                    } catch (d: DeferException) {
                        // Leave it there and go on to the next one
                        record(1, "KotlinActor", "receive", "%s skipped %s", this, m)
                        monitorSkippedMessage()
                    } catch (e: Exception) {
                        checkAndRemove(it, m)
                        throw e
                    } finally {
                        currentMessage = null
                    }
                }
            } else {
                try {
                    if (unit == null)
                        mailbox.await(i)
                    else if (timeout > 0) {
                        mailbox.await(i, left, TimeUnit.NANOSECONDS)

                        now = System.nanoTime()
                        left = deadline - now
                        if (left <= 0) {
                            record(1, "KotlinActor", "receive", "%s timed out.", this)
                            proc(Timeout)
                        }
                    }
                } finally {
                    mailbox.unlock()
                }
            }
        }
    }

    protected fun checkAndRemove(it: QueueIterator, m: Any) {
        if (it.value() == m) // Checking it's still there before removing it because another call to receive from within the processor may have removed it already
            it.remove()
    }

    protected fun defer() {
        throw DeferException;
    }
}

// A couple of top-level utils

public fun spawn(a: JActor<*, *>): ActorRef {
    @suppress("UNCHECKED_CAST")
    Fiber(a as SuspendableCallable).start()
    return a.ref() as ActorRef
}

public fun register(ref: String, v: JActor<*, *>): JActor<*, *> {
    return v.register(ref)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy