Bug 1368031 - Do not send reply if actor is dead r=billm
authorKan-Ru Chen <kanru@kanru.info>
Thu, 25 May 2017 15:34:33 -0400
changeset 361790 4507e6e48d484390f59047e6d9ecfba6662457c7
parent 361789 9d8e1c9e19e009ec64bbae332a78b87c5acd7150
child 361791 9a39e2222a478bb59bfbc1ee0d6d41adca1e392c
push id31943
push userryanvm@gmail.com
push dateThu, 01 Jun 2017 15:54:45 +0000
treeherdermozilla-central@62005e6aecdf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1368031
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1368031 - Do not send reply if actor is dead r=billm Actors with async returns methods will automatically implement WeakPtr so we can check in the resolving function whether it's safe to send messages. MozReview-Commit-ID: IyDwIYSShlS
ipc/ipdl/ipdl/lower.py
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -2570,53 +2570,72 @@ class _GenerateProtocolActorCode(ipdl.as
         # FIXME: all actors impl Iface for now
         if ptype.isManager() or 1:
             self.hdrfile.addthing(CppDirective('include', '"base/id_map.h"'))
 
         self.hdrfile.addthings([
             CppDirective('include', '"'+ p.channelHeaderFile() +'"'),
             Whitespace.NL ])
 
+        hasAsyncReturns = False
+        for md in p.messageDecls:
+            if self.receivesMessage(md) and md.hasAsyncReturns():
+                hasAsyncReturns = True
+                break
+
         inherits = []
         if ptype.isToplevel():
             inherits.append(Inherit(p.openedProtocolInterfaceType(),
                                     viz='public'))
         else:
             inherits.append(Inherit(p.managerInterfaceType(), viz='public'))
 
+        if hasAsyncReturns:
+            inherits.append(Inherit(Type('SupportsWeakPtr', T=ExprVar(self.clsname)),
+                                    viz='public'))
+            self.hdrfile.addthing(CppDirective('include', '"mozilla/WeakPtr.h"'))
+
         if ptype.isToplevel() and self.side is 'parent':
             self.hdrfile.addthings([
                     _makeForwardDeclForQClass('nsIFile', []),
                     Whitespace.NL
                     ])
 
         self.cls = Class(
             self.clsname,
             inherits=inherits,
             abstract=True)
 
+        if hasAsyncReturns:
+            self.cls.addstmts([
+                Label.PUBLIC,
+                Whitespace('', indent=1),
+                ExprCall(ExprVar('MOZ_DECLARE_WEAKREFERENCE_TYPENAME'),
+                         [ ExprVar(self.clsname) ]),
+                Whitespace.NL
+            ])
+
+        self.cls.addstmt(Label.PRIVATE)
         friends = _FindFriends().findFriends(ptype)
         if ptype.isManaged():
             friends.update(ptype.managers)
 
         # |friend| managed actors so that they can call our Dealloc*()
         friends.update(ptype.manages)
 
         # don't friend ourself if we're a self-managed protocol
         friends.discard(ptype)
 
         for friend in friends:
             self.actorForwardDecls.extend([
                 _makeForwardDeclForActor(friend, self.prettyside),
                 Whitespace.NL
             ])
-            self.cls.addstmts([
-                FriendClassDecl(_actorName(friend.fullname(),
-                                           self.prettyside)),
-                Whitespace.NL ])
+            self.cls.addstmt(FriendClassDecl(_actorName(friend.fullname(),
+                                                        self.prettyside)))
 
         self.cls.addstmt(Label.PROTECTED)
         for typedef in p.cxxTypedefs():
             self.cls.addstmt(typedef)
         for typedef in self.includedActorTypedefs:
             self.cls.addstmt(typedef)
 
         self.cls.addstmt(Whitespace.NL)
@@ -4248,42 +4267,54 @@ class _GenerateProtocolActorCode(ipdl.as
             resolvedecl = Decl(_tuple([p.bareType(self.side) for p in md.returns],
                                       const=1, ref=1),
                                'aParam')
             destructexpr = ExprCall(ExprVar('Tie'),
                                     args=[ p.var() for p in md.returns ])
         else:
             resolvedecl = Decl(md.returns[0].bareType(self.side), 'aParam')
             destructexpr = md.returns[0].var()
-        promisethen = ExprLambda([ExprVar.THIS, routingId, seqno],
+        selfvar = ExprVar('self__')
+        ifactorisdead = StmtIf(ExprNot(selfvar))
+        ifactorisdead.addifstmts([_printWarningMessage("Not resolving promise because actor is dead."),
+                                  StmtReturn()])
+        ifactorisdestroyed = StmtIf(ExprBinary(self.protocol.stateVar(), '==',
+                                               self.protocol.deadState()))
+        ifactorisdestroyed.addifstmts([_printWarningMessage("Not resolving promise because actor is destroyed."),
+                                  StmtReturn()])
+        returnifactorisdead = [ ifactorisdead,
+                                ifactorisdestroyed ]
+        promisethen = ExprLambda([ExprVar.THIS, selfvar, routingId, seqno],
                                  [resolvedecl])
-        promisethen.addstmts([ StmtDecl(Decl(Type.BOOL, resolve.name),
+        promisethen.addstmts(returnifactorisdead
+                             + [ StmtDecl(Decl(Type.BOOL, resolve.name),
                                         init=ExprLiteral.TRUE) ]
                              + [ StmtDecl(Decl(p.bareType(self.side), p.var().name))
                                for p in md.returns ]
                              + [ StmtExpr(ExprAssn(destructexpr, ExprVar('aParam'))),
                                  StmtDecl(Decl(Type('IPC::Message', ptr=1), self.replyvar.name),
                                           init=ExprCall(ExprVar(md.pqReplyCtorFunc()),
                                                         args=[ routingId ])) ]
                              + [ self.checkedWrite(None, resolve, self.replyvar,
                                                    sentinelKey=resolve.name) ]
                              + [ self.checkedWrite(r.ipdltype, r.var(), self.replyvar,
                                                    sentinelKey=r.name)
                                  for r in md.returns ])
         promisethen.addstmts(sendmsg)
-        promiserej = ExprLambda([ExprVar.THIS, routingId, seqno],
+        promiserej = ExprLambda([ExprVar.THIS, selfvar, routingId, seqno],
                                 [Decl(_PromiseRejectReason.Type(), reason.name)])
 
         # If-statement for silently cancelling the promise due to ActorDestroyed.
         returnifactordestroyed = StmtIf(ExprBinary(reason, '==',
                                                    _PromiseRejectReason.ActorDestroyed))
         returnifactordestroyed.addifstmts([_printWarningMessage("Reject due to ActorDestroyed"),
                                            StmtReturn()])
 
-        promiserej.addstmts([ returnifactordestroyed,
+        promiserej.addstmts(returnifactorisdead +
+                            [ returnifactordestroyed,
                               StmtExpr(ExprCall(ExprVar('MOZ_ASSERT'),
                                                 args=[ ExprBinary(reason, '==',
                                                                   _PromiseRejectReason.HandlerRejected) ])),
                               StmtExpr(ExprAssn(reason, _PromiseRejectReason.HandlerRejected)),
                               StmtDecl(Decl(Type.BOOL, resolve.name),
                                        init=ExprLiteral.FALSE),
                               StmtDecl(Decl(Type('IPC::Message', ptr=1), self.replyvar.name),
                                           init=ExprCall(ExprVar(md.pqReplyCtorFunc()),
@@ -4292,16 +4323,19 @@ class _GenerateProtocolActorCode(ipdl.as
                                                   sentinelKey=resolve.name),
                               self.checkedWrite(None, reason, self.replyvar,
                                                 sentinelKey=reason.name) ])
         promiserej.addstmts(sendmsg)
 
         makepromise = [ Whitespace.NL,
                         StmtDecl(Decl(Type.INT32, seqno.name),
                                  init=ExprCall(ExprSelect(self.msgvar, '.', 'seqno'))),
+                        StmtDecl(Decl(Type('WeakPtr', T=ExprVar(self.clsname)),
+                                      selfvar.name),
+                                 init=ExprVar.THIS),
                         StmtDecl(Decl(_refptr(promise), 'promise'),
                                  init=ExprNew(promise, args=[ExprVar('__func__')])),
                         StmtExpr(ExprCall(
                             ExprSelect(ExprVar('promise'), '->', 'Then'),
                             args=[ ExprCall(ExprVar('AbstractThread::GetCurrent')),
                                    ExprVar('__func__'),
                                    promisethen,
                                    promiserej ])) ]