summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
commit8dd16259287f58f9273002717ec4d27e97127719 (patch)
tree3863e62a53829a84037444beab3abd4ed9dfc7d0 /ipc/ipdl
parentReleasing progress-linux version 126.0.1-1~progress7.99u1. (diff)
downloadfirefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz
firefox-8dd16259287f58f9273002717ec4d27e97127719.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ipc/ipdl')
-rw-r--r--ipc/ipdl/Makefile.in2
-rw-r--r--ipc/ipdl/ipdl.py585
-rw-r--r--ipc/ipdl/ipdl/__init__.py2
-rw-r--r--ipc/ipdl/ipdl/lower.py179
-rw-r--r--ipc/ipdl/test/gtest/PTestDestroyNested.ipdl18
-rw-r--r--ipc/ipdl/test/gtest/PTestDestroyNestedSub.ipdl19
-rw-r--r--ipc/ipdl/test/gtest/TestDestroyNested.cpp123
-rw-r--r--ipc/ipdl/test/gtest/moz.build3
8 files changed, 548 insertions, 383 deletions
diff --git a/ipc/ipdl/Makefile.in b/ipc/ipdl/Makefile.in
index 6ebff9cba0..4847569a56 100644
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -19,6 +19,7 @@ ipdl_py_deps := \
# NB: the IPDL compiler manages .ipdl-->.h/.cpp dependencies itself,
# which is why we don't have explicit .h/.cpp targets here
ipdl.track: $(ALL_IPDLSRCS) $(ALL_IPDLSRCS_FILE) $(srcdir)/sync-messages.ini $(srcdir)/message-metadata.ini $(ipdl_py_deps)
+ $(call BUILDSTATUS,START_Ipdl ipdl.py)
$(PYTHON3) $(srcdir)/ipdl.py \
--sync-msg-list=$(srcdir)/sync-messages.ini \
--msg-metadata=$(srcdir)/message-metadata.ini \
@@ -27,6 +28,7 @@ ipdl.track: $(ALL_IPDLSRCS) $(ALL_IPDLSRCS_FILE) $(srcdir)/sync-messages.ini $(s
$(IPDLDIRS:%=-I%) \
--file-list $(ALL_IPDLSRCS_FILE)
touch $@
+ $(call BUILDSTATUS,END_Ipdl ipdl.py)
export:: ipdl.track
endif
diff --git a/ipc/ipdl/ipdl.py b/ipc/ipdl/ipdl.py
index 8e5dd5db3d..5c4b7a8344 100644
--- a/ipc/ipdl/ipdl.py
+++ b/ipc/ipdl/ipdl.py
@@ -6,214 +6,291 @@ import os
import sys
from configparser import RawConfigParser
from io import StringIO
+from multiprocessing import Manager
import ipdl
from ipdl.ast import SYNC
-def log(minv, fmt, *args):
- if _verbosity >= minv:
- print(fmt % args)
-
-
-# process command line
-
-
-op = optparse.OptionParser(usage="ipdl.py [options] IPDLfiles...")
-op.add_option(
- "-I",
- "--include",
- dest="includedirs",
- default=[],
- action="append",
- help="Additional directory to search for included protocol specifications",
-)
-op.add_option(
- "-s",
- "--sync-msg-list",
- dest="syncMsgList",
- default="sync-messages.ini",
- help="Config file listing allowed sync messages",
-)
-op.add_option(
- "-m",
- "--msg-metadata",
- dest="msgMetadata",
- default="message-metadata.ini",
- help="Predicted message sizes for reducing serialization malloc overhead.",
-)
-op.add_option(
- "-v",
- "--verbose",
- dest="verbosity",
- default=1,
- action="count",
- help="Verbose logging (specify -vv or -vvv for very verbose logging)",
-)
-op.add_option(
- "-q",
- "--quiet",
- dest="verbosity",
- action="store_const",
- const=0,
- help="Suppress logging output",
-)
-op.add_option(
- "-d",
- "--outheaders-dir",
- dest="headersdir",
- default=".",
- help="""Directory into which C++ headers will be generated.
-A protocol Foo in the namespace bar will cause the headers
- dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
-to be generated""",
-)
-op.add_option(
- "-o",
- "--outcpp-dir",
- dest="cppdir",
- default=".",
- help="""Directory into which C++ sources will be generated
-A protocol Foo in the namespace bar will cause the sources
- cppdir/FooParent.cpp, cppdir/FooChild.cpp
-to be generated""",
-)
-op.add_option(
- "-F",
- "--file-list",
- dest="file_list_file",
- default=None,
- help="""A file containing IPDL files to parse. This will be
-merged with files provided on the commandline.""",
-)
-
-options, cmdline_files = op.parse_args()
-_verbosity = options.verbosity
-syncMsgList = options.syncMsgList
-msgMetadata = options.msgMetadata
-headersdir = options.headersdir
-cppdir = options.cppdir
-includedirs = [os.path.abspath(incdir) for incdir in options.includedirs]
-
-files = []
-
-if options.file_list_file is not None:
- with open(options.file_list_file) as f:
- files.extend(f.read().splitlines())
-
-files.extend(cmdline_files)
-
-if not len(files):
- op.error("No IPDL files specified")
-
-ipcmessagestartpath = os.path.join(headersdir, "IPCMessageStart.h")
-ipc_msgtype_name_path = os.path.join(cppdir, "IPCMessageTypeName.cpp")
-
-log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
-log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
-
-allmessages = {}
-allsyncmessages = []
-allmessageprognames = []
-allprotocols = []
-
-
-def normalizedFilename(f):
- if f == "-":
- return "<stdin>"
- return f
-
-
-log(2, "Reading sync message list")
-parser = RawConfigParser()
-parser.read_file(open(options.syncMsgList))
-syncMsgList = parser.sections()
-
-for section in syncMsgList:
- if not parser.get(section, "description"):
- print("Error: Sync message %s lacks a description" % section, file=sys.stderr)
- sys.exit(1)
-
-# Read message metadata. Right now we only have 'segment_capacity'
-# for the standard segment size used for serialization.
-log(2, "Reading message metadata...")
-msgMetadataConfig = RawConfigParser()
-msgMetadataConfig.read_file(open(options.msgMetadata))
-
-segmentCapacityDict = {}
-for msgName in msgMetadataConfig.sections():
- if msgMetadataConfig.has_option(msgName, "segment_capacity"):
- capacity = msgMetadataConfig.get(msgName, "segment_capacity")
- segmentCapacityDict[msgName] = capacity
-
-# First pass: parse and type-check all protocols
-for f in files:
- log(2, os.path.basename(f))
- filename = normalizedFilename(f)
- if f == "-":
- fd = sys.stdin
- else:
- fd = open(f)
-
- specstring = fd.read()
- fd.close()
-
- ast = ipdl.parse(specstring, filename, includedirs=includedirs)
- if ast is None:
- print("Specification could not be parsed.", file=sys.stderr)
- sys.exit(1)
+class WorkerPool:
+ per_process_context = None
+
+ def __init__(
+ self,
+ manager,
+ files,
+ asts,
+ headersdir,
+ cppdir,
+ segmentCapacityDict,
+ allmessages,
+ allprotocols,
+ allmessageprognames,
+ allsyncmessages,
+ *,
+ processes=None
+ ):
+ if processes is None:
+ processes = os.cpu_count() or 1
+ processes = min(processes, 8)
+ self.n = len(files)
+ self.asts = asts
+ self.pool = manager.Pool(
+ initializer=WorkerPool._init_worker,
+ initargs=(
+ files,
+ asts,
+ headersdir,
+ cppdir,
+ segmentCapacityDict,
+ allmessages,
+ allprotocols,
+ allmessageprognames,
+ allsyncmessages,
+ ),
+ processes=processes,
+ )
- log(2, "checking types")
- if not ipdl.typecheck(ast):
- print("Specification is not well typed.", file=sys.stderr)
+ def run(self):
+ self.pool.map(WorkerPool._run_worker, range(self.n))
+
+ @staticmethod
+ def _init_worker(*state):
+ WorkerPool.per_process_context = state
+
+ @staticmethod
+ def _run_worker(index):
+ (
+ files,
+ asts,
+ headersdir,
+ cppdir,
+ segmentCapacityDict,
+ allmessages,
+ allprotocols,
+ allmessageprognames,
+ allsyncmessages,
+ ) = WorkerPool.per_process_context
+ ast = asts[index]
+ ipdl.gencxx(files[index], ast, headersdir, cppdir, segmentCapacityDict)
+
+ if ast.protocol:
+ allmessages[ast.protocol.name] = ipdl.genmsgenum(ast)
+ allprotocols.append(ast.protocol.name)
+
+ # e.g. PContent::RequestMemoryReport (not prefixed or suffixed.)
+ for md in ast.protocol.messageDecls:
+ allmessageprognames.append("%s::%s" % (md.namespace, md.decl.progname))
+
+ if md.sendSemantics is SYNC:
+ allsyncmessages.append(
+ "%s__%s" % (ast.protocol.name, md.prettyMsgName())
+ )
+
+
+def main():
+ def log(minv, fmt, *args):
+ if _verbosity >= minv:
+ print(fmt % args)
+
+ # process command line
+
+ op = optparse.OptionParser(usage="ipdl.py [options] IPDLfiles...")
+ op.add_option(
+ "-I",
+ "--include",
+ dest="includedirs",
+ default=[],
+ action="append",
+ help="Additional directory to search for included protocol specifications",
+ )
+ op.add_option(
+ "-s",
+ "--sync-msg-list",
+ dest="syncMsgList",
+ default="sync-messages.ini",
+ help="Config file listing allowed sync messages",
+ )
+ op.add_option(
+ "-m",
+ "--msg-metadata",
+ dest="msgMetadata",
+ default="message-metadata.ini",
+ help="Predicted message sizes for reducing serialization malloc overhead.",
+ )
+ op.add_option(
+ "-v",
+ "--verbose",
+ dest="verbosity",
+ default=1,
+ action="count",
+ help="Verbose logging (specify -vv or -vvv for very verbose logging)",
+ )
+ op.add_option(
+ "-q",
+ "--quiet",
+ dest="verbosity",
+ action="store_const",
+ const=0,
+ help="Suppress logging output",
+ )
+ op.add_option(
+ "-d",
+ "--outheaders-dir",
+ dest="headersdir",
+ default=".",
+ help="""Directory into which C++ headers will be generated.
+ A protocol Foo in the namespace bar will cause the headers
+ dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
+ to be generated""",
+ )
+ op.add_option(
+ "-o",
+ "--outcpp-dir",
+ dest="cppdir",
+ default=".",
+ help="""Directory into which C++ sources will be generated
+ A protocol Foo in the namespace bar will cause the sources
+ cppdir/FooParent.cpp, cppdir/FooChild.cpp
+ to be generated""",
+ )
+ op.add_option(
+ "-F",
+ "--file-list",
+ dest="file_list_file",
+ default=None,
+ help="""A file containing IPDL files to parse. This will be
+ merged with files provided on the commandline.""",
+ )
+
+ options, cmdline_files = op.parse_args()
+ _verbosity = options.verbosity
+ syncMsgList = options.syncMsgList
+ headersdir = options.headersdir
+ cppdir = options.cppdir
+ includedirs = [os.path.abspath(incdir) for incdir in options.includedirs]
+
+ files = []
+
+ if options.file_list_file is not None:
+ with open(options.file_list_file) as f:
+ files.extend(f.read().splitlines())
+
+ files.extend(cmdline_files)
+
+ if not len(files):
+ op.error("No IPDL files specified")
+
+ ipcmessagestartpath = os.path.join(headersdir, "IPCMessageStart.h")
+ ipc_msgtype_name_path = os.path.join(cppdir, "IPCMessageTypeName.cpp")
+
+ log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
+ log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
+
+ def normalizedFilename(f):
+ if f == "-":
+ return "<stdin>"
+ return f
+
+ log(2, "Reading sync message list")
+ parser = RawConfigParser()
+ parser.read_file(open(options.syncMsgList))
+ syncMsgList = parser.sections()
+
+ for section in syncMsgList:
+ if not parser.get(section, "description"):
+ print(
+ "Error: Sync message %s lacks a description" % section, file=sys.stderr
+ )
+ sys.exit(1)
+
+ # Read message metadata. Right now we only have 'segment_capacity'
+ # for the standard segment size used for serialization.
+ log(2, "Reading message metadata...")
+ msgMetadataConfig = RawConfigParser()
+ msgMetadataConfig.read_file(open(options.msgMetadata))
+
+ manager = Manager()
+ segmentCapacityDict = manager.dict()
+ allmessages = manager.dict()
+ allsyncmessages = manager.list()
+ allmessageprognames = manager.list()
+ allprotocols = manager.list()
+
+ for msgName in msgMetadataConfig.sections():
+ if msgMetadataConfig.has_option(msgName, "segment_capacity"):
+ capacity = msgMetadataConfig.get(msgName, "segment_capacity")
+ segmentCapacityDict[msgName] = capacity
+
+ # First pass: parse and type-check all protocols
+ asts = []
+ for f in files:
+ log(2, os.path.basename(f))
+ filename = normalizedFilename(f)
+ if f == "-":
+ fd = sys.stdin
+ else:
+ fd = open(f)
+
+ specstring = fd.read()
+ fd.close()
+
+ ast = ipdl.parse(specstring, filename, includedirs=includedirs)
+ if ast is None:
+ print("Specification could not be parsed.", file=sys.stderr)
+ sys.exit(1)
+
+ log(2, "checking types")
+ if not ipdl.typecheck(ast):
+ print("Specification is not well typed.", file=sys.stderr)
+ sys.exit(1)
+
+ if not ipdl.checkSyncMessage(ast, syncMsgList):
+ print(
+ "Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s"
+ % options.syncMsgList,
+ file=sys.stderr,
+ ) # NOQA: E501
+ sys.exit(1)
+
+ asts.append(ast)
+
+ if not ipdl.checkFixedSyncMessages(parser):
+ # Errors have alraedy been printed to stderr, just exit
sys.exit(1)
- if not ipdl.checkSyncMessage(ast, syncMsgList):
+ # Second pass: generate code
+ pool = WorkerPool(
+ manager,
+ files,
+ asts,
+ headersdir,
+ cppdir,
+ segmentCapacityDict,
+ allmessages,
+ allprotocols,
+ allmessageprognames,
+ allsyncmessages,
+ )
+ pool.run()
+
+ allprotocols.sort()
+ allsyncmessages.sort()
+
+ # Check if we have undefined message names in segmentCapacityDict.
+ # This is a fool-proof of the 'message-metadata.ini' file.
+ undefinedMessages = set(segmentCapacityDict.keys()) - set(allmessageprognames)
+ if len(undefinedMessages) > 0:
print(
- "Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s"
- % options.syncMsgList,
- file=sys.stderr,
- ) # NOQA: E501
+ "Error: Undefined message names in message-metadata.ini:", file=sys.stderr
+ )
+ print(undefinedMessages, file=sys.stderr)
sys.exit(1)
-if not ipdl.checkFixedSyncMessages(parser):
- # Errors have alraedy been printed to stderr, just exit
- sys.exit(1)
-
-# Second pass: generate code
-for f in files:
- # Read from parser cache
- filename = normalizedFilename(f)
- ast = ipdl.parse(None, filename, includedirs=includedirs)
- ipdl.gencxx(filename, ast, headersdir, cppdir, segmentCapacityDict)
-
- if ast.protocol:
- allmessages[ast.protocol.name] = ipdl.genmsgenum(ast)
- allprotocols.append(ast.protocol.name)
-
- # e.g. PContent::RequestMemoryReport (not prefixed or suffixed.)
- for md in ast.protocol.messageDecls:
- allmessageprognames.append("%s::%s" % (md.namespace, md.decl.progname))
-
- if md.sendSemantics is SYNC:
- allsyncmessages.append(
- "%s__%s" % (ast.protocol.name, md.prettyMsgName())
- )
-
-allprotocols.sort()
+ ipcmsgstart = StringIO()
-# Check if we have undefined message names in segmentCapacityDict.
-# This is a fool-proof of the 'message-metadata.ini' file.
-undefinedMessages = set(segmentCapacityDict.keys()) - set(allmessageprognames)
-if len(undefinedMessages) > 0:
- print("Error: Undefined message names in message-metadata.ini:", file=sys.stderr)
- print(undefinedMessages, file=sys.stderr)
- sys.exit(1)
-
-ipcmsgstart = StringIO()
-
-print(
- """
+ print(
+ """
// CODE GENERATED by ipdl.py. Do not edit.
#ifndef IPCMessageStart_h
@@ -221,14 +298,14 @@ print(
enum IPCMessageStart {
""",
- file=ipcmsgstart,
-)
+ file=ipcmsgstart,
+ )
-for name in allprotocols:
- print(" %sMsgStart," % name, file=ipcmsgstart)
+ for name in allprotocols:
+ print(" %sMsgStart," % name, file=ipcmsgstart)
-print(
- """
+ print(
+ """
LastMsgIndex
};
@@ -236,12 +313,12 @@ static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
#endif // ifndef IPCMessageStart_h
""",
- file=ipcmsgstart,
-)
+ file=ipcmsgstart,
+ )
-ipc_msgtype_name = StringIO()
-print(
- """
+ ipc_msgtype_name = StringIO()
+ print(
+ """
// CODE GENERATED by ipdl.py. Do not edit.
#include <cstdint>
@@ -253,19 +330,19 @@ using std::uint32_t;
namespace {
enum IPCMessages {
-""",
- file=ipc_msgtype_name,
-)
-
-for protocol in sorted(allmessages.keys()):
- for msg, num in allmessages[protocol].idnums:
- if num:
- print(" %s = %s," % (msg, num), file=ipc_msgtype_name)
- elif not msg.endswith("End"):
- print(" %s__%s," % (protocol, msg), file=ipc_msgtype_name)
-
-print(
- """
+ """,
+ file=ipc_msgtype_name,
+ )
+
+ for protocol in sorted(allmessages.keys()):
+ for msg, num in allmessages[protocol].idnums:
+ if num:
+ print(" %s = %s," % (msg, num), file=ipc_msgtype_name)
+ elif not msg.endswith("End"):
+ print(" %s__%s," % (protocol, msg), file=ipc_msgtype_name)
+
+ print(
+ """
};
} // anonymous namespace
@@ -276,14 +353,14 @@ bool IPCMessageTypeIsSync(uint32_t aMessageType)
{
switch (aMessageType) {
""",
- file=ipc_msgtype_name,
-)
+ file=ipc_msgtype_name,
+ )
-for msg in allsyncmessages:
- print(" case %s:" % msg, file=ipc_msgtype_name)
+ for msg in allsyncmessages:
+ print(" case %s:" % msg, file=ipc_msgtype_name)
-print(
- """ return true;
+ print(
+ """ return true;
default:
return false;
}
@@ -292,24 +369,24 @@ print(
const char* StringFromIPCMessageType(uint32_t aMessageType)
{
switch (aMessageType) {
-""",
- file=ipc_msgtype_name,
-)
-
-for protocol in sorted(allmessages.keys()):
- for msg, num in allmessages[protocol].idnums:
- if num or msg.endswith("End"):
- continue
- print(
- """
+ """,
+ file=ipc_msgtype_name,
+ )
+
+ for protocol in sorted(allmessages.keys()):
+ for msg, num in allmessages[protocol].idnums:
+ if num or msg.endswith("End"):
+ continue
+ print(
+ """
case %s__%s:
return "%s::%s";"""
- % (protocol, msg, protocol, msg),
- file=ipc_msgtype_name,
- )
+ % (protocol, msg, protocol, msg),
+ file=ipc_msgtype_name,
+ )
-print(
- """
+ print(
+ """
case DATA_PIPE_CLOSED_MESSAGE_TYPE:
return "DATA_PIPE_CLOSED_MESSAGE";
case DATA_PIPE_BYTES_CONSUMED_MESSAGE_TYPE:
@@ -353,15 +430,15 @@ namespace ipc {
const char* ProtocolIdToName(IPCMessageStart aId) {
switch (aId) {
""",
- file=ipc_msgtype_name,
-)
+ file=ipc_msgtype_name,
+ )
-for name in allprotocols:
- print(" case %sMsgStart:" % name, file=ipc_msgtype_name)
- print(' return "%s";' % name, file=ipc_msgtype_name)
+ for name in allprotocols:
+ print(" case %sMsgStart:" % name, file=ipc_msgtype_name)
+ print(' return "%s";' % name, file=ipc_msgtype_name)
-print(
- """
+ print(
+ """
default:
return "<unknown protocol id>";
}
@@ -370,8 +447,12 @@ print(
} // namespace ipc
} // namespace mozilla
""",
- file=ipc_msgtype_name,
-)
+ file=ipc_msgtype_name,
+ )
+
+ ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
+ ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)
+
-ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
-ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)
+if __name__ == "__main__":
+ main()
diff --git a/ipc/ipdl/ipdl/__init__.py b/ipc/ipdl/ipdl/__init__.py
index c042c16444..466a771c4e 100644
--- a/ipc/ipdl/ipdl/__init__.py
+++ b/ipc/ipdl/ipdl/__init__.py
@@ -85,7 +85,7 @@ def genmsgenum(ast):
def writeifmodified(contents, file):
contents = contents.encode("utf-8")
dir = os.path.dirname(file)
- os.path.exists(dir) or os.makedirs(dir)
+ os.makedirs(dir, exist_ok=True)
oldcontents = None
if os.path.exists(file):
diff --git a/ipc/ipdl/ipdl/lower.py b/ipc/ipdl/ipdl/lower.py
index 291e1c698f..0e8b5e8dad 100644
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -474,10 +474,6 @@ def errfnSentinel(rvalue=ExprLiteral.FALSE):
return inner
-def _destroyMethod():
- return ExprVar("ActorDestroy")
-
-
def errfnUnreachable(msg):
return [_logicError(msg)]
@@ -3943,57 +3939,8 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
self.cls.addstmts([meth, refmeth, Whitespace.NL])
- # AllManagedActors(Array& inout) const
- arrvar = ExprVar("arr__")
- managedmeth = MethodDefn(
- MethodDecl(
- "AllManagedActors",
- params=[
- Decl(
- _cxxArrayType(_refptr(_cxxLifecycleProxyType()), ref=True),
- arrvar.name,
- )
- ],
- methodspec=MethodSpec.OVERRIDE,
- const=True,
- )
- )
-
- # Count the number of managed actors, and allocate space in the output array.
- managedmeth.addcode(
- """
- uint32_t total = 0;
- """
- )
- for managed in ptype.manages:
- managedmeth.addcode(
- """
- total += ${container}.Count();
- """,
- container=p.managedVar(managed, self.side),
- )
- managedmeth.addcode(
- """
- arr__.SetCapacity(total);
-
- """
- )
-
- for managed in ptype.manages:
- managedmeth.addcode(
- """
- for (auto* key : ${container}) {
- arr__.AppendElement(key->GetLifecycleProxy());
- }
-
- """,
- container=p.managedVar(managed, self.side),
- )
-
- self.cls.addstmts([managedmeth, Whitespace.NL])
-
# AllManagedActorsCount() const
- managedmeth = MethodDefn(
+ managedcount = MethodDefn(
MethodDecl(
"AllManagedActorsCount",
ret=Type.UINT32,
@@ -4003,26 +3950,26 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
)
# Count the number of managed actors.
- managedmeth.addcode(
+ managedcount.addcode(
"""
uint32_t total = 0;
"""
)
for managed in ptype.manages:
- managedmeth.addcode(
+ managedcount.addcode(
"""
total += ${container}.Count();
""",
container=p.managedVar(managed, self.side),
)
- managedmeth.addcode(
+ managedcount.addcode(
"""
return total;
"""
)
- self.cls.addstmts([managedmeth, Whitespace.NL])
+ self.cls.addstmts([managedcount, Whitespace.NL])
# OpenPEndpoint(...)/BindPEndpoint(...)
for managed in ptype.manages:
@@ -4188,66 +4135,50 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
]
)
- clearsubtreevar = ExprVar("ClearSubtree")
+ # DoomSubtree()
+ doomsubtree = MethodDefn(
+ MethodDecl("DoomSubtree", methodspec=MethodSpec.OVERRIDE)
+ )
- if ptype.isToplevel():
- # OnChannelClose()
- onclose = MethodDefn(
- MethodDecl("OnChannelClose", methodspec=MethodSpec.OVERRIDE)
- )
- onclose.addcode(
+ for managed in ptype.manages:
+ doomsubtree.addcode(
"""
- DestroySubtree(NormalShutdown);
- ClearSubtree();
- DeallocShmems();
- if (GetLifecycleProxy()) {
- GetLifecycleProxy()->Release();
+ for (auto* key : ${container}) {
+ key->DoomSubtree();
}
- """
+ """,
+ container=p.managedVar(managed, self.side),
)
- self.cls.addstmts([onclose, Whitespace.NL])
- # OnChannelError()
- onerror = MethodDefn(
- MethodDecl("OnChannelError", methodspec=MethodSpec.OVERRIDE)
- )
- onerror.addcode(
- """
- DestroySubtree(AbnormalShutdown);
- ClearSubtree();
- DeallocShmems();
- if (GetLifecycleProxy()) {
- GetLifecycleProxy()->Release();
- }
- """
- )
- self.cls.addstmts([onerror, Whitespace.NL])
+ doomsubtree.addcode("SetDoomed();\n")
- # private methods
- self.cls.addstmt(Label.PRIVATE)
+ self.cls.addstmts([doomsubtree, Whitespace.NL])
+
+ # IProtocol* PeekManagedActor() override
+ peekmanagedactor = MethodDefn(
+ MethodDecl(
+ "PeekManagedActor",
+ methodspec=MethodSpec.OVERRIDE,
+ ret=Type("IProtocol", ptr=True),
+ )
+ )
- # ClearSubtree()
- clearsubtree = MethodDefn(MethodDecl(clearsubtreevar.name))
for managed in ptype.manages:
- clearsubtree.addcode(
+ peekmanagedactor.addcode(
"""
- for (auto* key : ${container}) {
- key->ClearSubtree();
- }
- for (auto* key : ${container}) {
- // Recursively releasing ${container} kids.
- auto* proxy = key->GetLifecycleProxy();
- NS_IF_RELEASE(proxy);
+ if (IProtocol* actor = ${container}.Peek()) {
+ return actor;
}
- ${container}.Clear();
-
""",
container=p.managedVar(managed, self.side),
)
- # don't release our own IPC reference: either the manager will do it,
- # or we're toplevel
- self.cls.addstmts([clearsubtree, Whitespace.NL])
+ peekmanagedactor.addcode("return nullptr;\n")
+
+ self.cls.addstmts([peekmanagedactor, Whitespace.NL])
+
+ # private methods
+ self.cls.addstmt(Label.PRIVATE)
if not ptype.isToplevel():
self.cls.addstmts(
@@ -4382,16 +4313,9 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
)
case = ExprCode(
"""
- {
- ${manageecxxtype} actor = static_cast<${manageecxxtype}>(aListener);
-
- const bool removed = ${container}.EnsureRemoved(actor);
- MOZ_RELEASE_ASSERT(removed, "actor not managed by this!");
+ ${container}.EnsureRemoved(static_cast<${manageecxxtype}>(aListener));
+ return;
- auto* proxy = actor->GetLifecycleProxy();
- NS_IF_RELEASE(proxy);
- return;
- }
""",
manageecxxtype=manageecxxtype,
container=p.managedVar(manageeipdltype, self.side),
@@ -4708,14 +4632,18 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return [
StmtCode(
"""
- if (!${actor}) {
- NS_WARNING("Cannot bind null ${actorname} actor");
- return ${errfn};
- }
+ if (!${actor}) {
+ NS_WARNING("Cannot bind null ${actorname} actor");
+ return ${errfn};
+ }
- ${actor}->SetManagerAndRegister($,{setManagerArgs});
- ${container}.Insert(${actor});
- """,
+ if (${actor}->SetManagerAndRegister($,{setManagerArgs})) {
+ ${container}.Insert(${actor});
+ } else {
+ NS_WARNING("Failed to bind ${actorname} actor");
+ return ${errfn};
+ }
+ """,
actor=actordecl.var(),
actorname=actorproto.name() + self.side.capitalize(),
errfn=errfn,
@@ -4766,22 +4694,13 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return method, (lbl, case)
def destroyActor(self, md, actorexpr, why=_DestroyReason.Deletion):
- if md and md.decl.type.isCtor():
- destroyedType = md.decl.type.constructedType()
- else:
- destroyedType = self.protocol.decl.type
-
return [
StmtCode(
"""
- IProtocol* mgr = ${actor}->Manager();
- ${actor}->DestroySubtree(${why});
- ${actor}->ClearSubtree();
- mgr->RemoveManagee(${protoId}, ${actor});
+ ${actor}->ActorDisconnected(${why});
""",
actor=actorexpr,
why=why,
- protoId=_protocolId(destroyedType),
)
]
diff --git a/ipc/ipdl/test/gtest/PTestDestroyNested.ipdl b/ipc/ipdl/test/gtest/PTestDestroyNested.ipdl
new file mode 100644
index 0000000000..1d58f1cf0c
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestDestroyNested.ipdl
@@ -0,0 +1,18 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PTestDestroyNestedSub;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+async protocol PTestDestroyNested {
+ manages PTestDestroyNestedSub;
+child:
+ async PTestDestroyNestedSub();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/PTestDestroyNestedSub.ipdl b/ipc/ipdl/test/gtest/PTestDestroyNestedSub.ipdl
new file mode 100644
index 0000000000..033c49261d
--- /dev/null
+++ b/ipc/ipdl/test/gtest/PTestDestroyNestedSub.ipdl
@@ -0,0 +1,19 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PTestDestroyNested;
+
+namespace mozilla {
+namespace _ipdltest {
+
+[ChildProc=any, ChildImpl=virtual, ParentImpl=virtual]
+async protocol PTestDestroyNestedSub {
+ manager PTestDestroyNested;
+child:
+
+ async __delete__();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
diff --git a/ipc/ipdl/test/gtest/TestDestroyNested.cpp b/ipc/ipdl/test/gtest/TestDestroyNested.cpp
new file mode 100644
index 0000000000..a348357b51
--- /dev/null
+++ b/ipc/ipdl/test/gtest/TestDestroyNested.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Test an actor being destroyed during another ActorDestroy.
+ */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/_ipdltest/IPDLUnitTest.h"
+#include "mozilla/_ipdltest/PTestDestroyNestedChild.h"
+#include "mozilla/_ipdltest/PTestDestroyNestedParent.h"
+#include "mozilla/_ipdltest/PTestDestroyNestedSubChild.h"
+#include "mozilla/_ipdltest/PTestDestroyNestedSubParent.h"
+
+#include "mozilla/SpinEventLoopUntil.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla::_ipdltest {
+
+class TestDestroyNestedSubParent : public PTestDestroyNestedSubParent {
+ NS_INLINE_DECL_REFCOUNTING(TestDestroyNestedSubParent, override)
+
+ void ActorDestroy(ActorDestroyReason aReason) override;
+
+ bool mActorDestroyCalled = false;
+ bool mCloseManager = false;
+
+ nsrefcnt GetRefCnt() const { return mRefCnt; }
+
+ private:
+ ~TestDestroyNestedSubParent() = default;
+};
+
+class TestDestroyNestedSubChild : public PTestDestroyNestedSubChild {
+ NS_INLINE_DECL_REFCOUNTING(TestDestroyNestedSubChild, override)
+ private:
+ ~TestDestroyNestedSubChild() = default;
+};
+
+class TestDestroyNestedParent : public PTestDestroyNestedParent {
+ NS_INLINE_DECL_REFCOUNTING(TestDestroyNestedParent, override)
+
+ void ActorDestroy(ActorDestroyReason aReason) override;
+
+ bool mActorDestroyCalled = false;
+
+ private:
+ ~TestDestroyNestedParent() = default;
+};
+
+class TestDestroyNestedChild : public PTestDestroyNestedChild {
+ NS_INLINE_DECL_REFCOUNTING(TestDestroyNestedChild, override)
+
+ already_AddRefed<PTestDestroyNestedSubChild> AllocPTestDestroyNestedSubChild()
+ override {
+ return MakeAndAddRef<TestDestroyNestedSubChild>();
+ }
+
+ private:
+ ~TestDestroyNestedChild() = default;
+};
+
+void TestDestroyNestedSubParent::ActorDestroy(ActorDestroyReason aReason) {
+ // Destroy our manager from within ActorDestroy() and assert that we don't
+ // re-enter.
+ EXPECT_FALSE(mActorDestroyCalled) << "re-entered ActorDestroy()";
+ mActorDestroyCalled = true;
+
+ if (mCloseManager) {
+ EXPECT_FALSE(
+ static_cast<TestDestroyNestedParent*>(Manager())->mActorDestroyCalled)
+ << "manager already destroyed";
+ Manager()->Close();
+ EXPECT_TRUE(
+ static_cast<TestDestroyNestedParent*>(Manager())->mActorDestroyCalled)
+ << "manager successfully destroyed";
+ }
+
+ // Make sure we also process any pending events, because we might be spinning
+ // a nested event loop within `ActorDestroy`.
+ NS_ProcessPendingEvents(nullptr);
+}
+
+void TestDestroyNestedParent::ActorDestroy(ActorDestroyReason aReason) {
+ // Destroy our manager from within ActorDestroy() and assert that we don't
+ // re-enter.
+ EXPECT_FALSE(mActorDestroyCalled) << "re-entered ActorDestroy()";
+ mActorDestroyCalled = true;
+}
+
+IPDL_TEST(TestDestroyNested) {
+ auto p = MakeRefPtr<TestDestroyNestedSubParent>();
+ p->mCloseManager = true;
+ auto* rv1 = mActor->SendPTestDestroyNestedSubConstructor(p);
+ ASSERT_EQ(p, rv1) << "can't allocate Sub";
+
+ bool rv2 = PTestDestroyNestedSubParent::Send__delete__(p);
+ ASSERT_TRUE(rv2)
+ << "Send__delete__ failed";
+
+ ASSERT_TRUE(mActor->mActorDestroyCalled)
+ << "Parent not destroyed";
+ ASSERT_TRUE(p->mActorDestroyCalled)
+ << "Sub not destroyed";
+
+ ASSERT_EQ(p->GetRefCnt(), 1u) << "Outstanding references to Sub remain";
+
+ // Try to allocate a new actor under the already-destroyed manager, and ensure
+ // that it is destroyed as expected.
+ auto p2 = MakeRefPtr<TestDestroyNestedSubParent>();
+ auto* rv3 = mActor->SendPTestDestroyNestedSubConstructor(p2);
+ ASSERT_EQ(rv3, nullptr) << "construction succeeded unexpectedly";
+
+ ASSERT_TRUE(p2->mActorDestroyCalled)
+ << "Sub not destroyed";
+}
+
+} // namespace mozilla::_ipdltest
diff --git a/ipc/ipdl/test/gtest/moz.build b/ipc/ipdl/test/gtest/moz.build
index 86fa2eca9e..5b60532026 100644
--- a/ipc/ipdl/test/gtest/moz.build
+++ b/ipc/ipdl/test/gtest/moz.build
@@ -22,6 +22,7 @@ SOURCES += [
"TestCrossProcessSemaphore.cpp",
"TestDataStructures.cpp",
"TestDescendant.cpp",
+ "TestDestroyNested.cpp",
"TestEndpointOpens.cpp",
"TestHangs.cpp",
"TestInduceConnectionError.cpp",
@@ -49,6 +50,8 @@ IPDL_SOURCES += [
"PTestDescendant.ipdl",
"PTestDescendantSub.ipdl",
"PTestDescendantSubsub.ipdl",
+ "PTestDestroyNested.ipdl",
+ "PTestDestroyNestedSub.ipdl",
"PTestEndpointOpens.ipdl",
"PTestEndpointOpensOpened.ipdl",
"PTestHangs.ipdl",