make cleanUp of systemMessages atomic
- extend systemDrain to take the new contents which shall be switched in - make NoMessage placeholder which will signal final closing of the mailbox - put that in when cleaning up, and check it when enqueuing
This commit is contained in:
parent
1821927023
commit
fd1d0ce121
5 changed files with 40 additions and 35 deletions
|
|
@ -169,6 +169,7 @@ private[akka] abstract class Mailbox(val actor: ActorCell, val messageQueue: Mes
|
|||
*/
|
||||
protected final def systemQueueGet: SystemMessage =
|
||||
Unsafe.instance.getObjectVolatile(this, AbstractMailbox.systemMessageOffset).asInstanceOf[SystemMessage]
|
||||
|
||||
protected final def systemQueuePut(_old: SystemMessage, _new: SystemMessage): Boolean =
|
||||
Unsafe.instance.compareAndSwapObject(this, AbstractMailbox.systemMessageOffset, _old, _new)
|
||||
|
||||
|
|
@ -208,14 +209,14 @@ private[akka] abstract class Mailbox(val actor: ActorCell, val messageQueue: Mes
|
|||
}
|
||||
|
||||
final def processAllSystemMessages() {
|
||||
var nextMessage = systemDrain()
|
||||
var nextMessage = systemDrain(null)
|
||||
try {
|
||||
while ((nextMessage ne null) && !isClosed) {
|
||||
if (debug) println(actor.self + " processing system message " + nextMessage + " with " + actor.childrenRefs)
|
||||
actor systemInvoke nextMessage
|
||||
nextMessage = nextMessage.next
|
||||
// don’t ever execute normal message when system message present!
|
||||
if (nextMessage eq null) nextMessage = systemDrain()
|
||||
if (nextMessage eq null) nextMessage = systemDrain(null)
|
||||
}
|
||||
} catch {
|
||||
case NonFatal(e) ⇒
|
||||
|
|
@ -235,15 +236,13 @@ private[akka] abstract class Mailbox(val actor: ActorCell, val messageQueue: Mes
|
|||
protected[dispatch] def cleanUp(): Unit =
|
||||
if (actor ne null) { // actor is null for the deadLetterMailbox
|
||||
val dlm = actor.systemImpl.deadLetterMailbox
|
||||
while (hasSystemMessages) {
|
||||
var message = systemDrain()
|
||||
while (message ne null) {
|
||||
// message must be “virgin” before being able to systemEnqueue again
|
||||
val next = message.next
|
||||
message.next = null
|
||||
dlm.systemEnqueue(actor.self, message)
|
||||
message = next
|
||||
}
|
||||
var message = systemDrain(NoMessage)
|
||||
while (message ne null) {
|
||||
// message must be “virgin” before being able to systemEnqueue again
|
||||
val next = message.next
|
||||
message.next = null
|
||||
dlm.systemEnqueue(actor.self, message)
|
||||
message = next
|
||||
}
|
||||
|
||||
if (messageQueue ne null) // needed for CallingThreadDispatcher, which never calls Mailbox.run()
|
||||
|
|
@ -300,7 +299,7 @@ private[akka] trait SystemMessageQueue {
|
|||
/**
|
||||
* Dequeue all messages from system queue and return them as single-linked list.
|
||||
*/
|
||||
def systemDrain(): SystemMessage
|
||||
def systemDrain(newContents: SystemMessage): SystemMessage
|
||||
|
||||
def hasSystemMessages: Boolean
|
||||
}
|
||||
|
|
@ -315,26 +314,30 @@ private[akka] trait DefaultSystemMessageQueue { self: Mailbox ⇒
|
|||
assert(message.next eq null)
|
||||
if (Mailbox.debug) println(actor.self + " having enqueued " + message)
|
||||
val head = systemQueueGet
|
||||
/*
|
||||
* this write is safely published by the compareAndSet contained within
|
||||
* systemQueuePut; “Intra-Thread Semantics” on page 12 of the JSR133 spec
|
||||
* guarantees that “head” uses the value obtained from systemQueueGet above.
|
||||
* Hence, SystemMessage.next does not need to be volatile.
|
||||
*/
|
||||
message.next = head
|
||||
if (!systemQueuePut(head, message)) {
|
||||
message.next = null
|
||||
systemEnqueue(receiver, message)
|
||||
if (head == NoMessage) actor.system.deadLetterMailbox.systemEnqueue(receiver, message)
|
||||
else {
|
||||
/*
|
||||
* this write is safely published by the compareAndSet contained within
|
||||
* systemQueuePut; “Intra-Thread Semantics” on page 12 of the JSR133 spec
|
||||
* guarantees that “head” uses the value obtained from systemQueueGet above.
|
||||
* Hence, SystemMessage.next does not need to be volatile.
|
||||
*/
|
||||
message.next = head
|
||||
if (!systemQueuePut(head, message)) {
|
||||
message.next = null
|
||||
systemEnqueue(receiver, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@tailrec
|
||||
final def systemDrain(): SystemMessage = {
|
||||
final def systemDrain(newContents: SystemMessage): SystemMessage = {
|
||||
val head = systemQueueGet
|
||||
if (systemQueuePut(head, null)) SystemMessage.reverse(head) else systemDrain()
|
||||
if (systemQueuePut(head, newContents)) SystemMessage.reverse(head) else systemDrain(newContents)
|
||||
}
|
||||
|
||||
def hasSystemMessages: Boolean = systemQueueGet ne null
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue