mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-01 04:47:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
27
ipc/ipdl/Makefile.in
Normal file
27
ipc/ipdl/Makefile.in
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# 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/.
|
||||
|
||||
GARBAGE_DIRS += _ipdlheaders
|
||||
GARBAGE += ipdl_lextab.py ipdl_yacctab.py $(wildcard *.pyc $(srcdir)/ipdl/*.pyc $(srcdir)/ipdl/cxx/*.pyc)
|
||||
|
||||
ifdef COMPILE_ENVIRONMENT
|
||||
|
||||
# This file is generated by the moz.build backend.
|
||||
include ipdlsrcs.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
||||
# NB: the IPDL compiler manages .ipdl-->.h/.cpp dependencies itself,
|
||||
# which is why we don't have explicit .h/.cpp targets here
|
||||
export:: $(ALL_IPDLSRCS)
|
||||
$(PYTHON) $(topsrcdir)/config/pythonpath.py \
|
||||
$(PLY_INCLUDE) \
|
||||
$(srcdir)/ipdl.py \
|
||||
--outheaders-dir=_ipdlheaders \
|
||||
--outcpp-dir=. \
|
||||
$(IPDLDIRS:%=-I%) \
|
||||
$^
|
||||
endif
|
||||
|
||||
232
ipc/ipdl/ipdl.py
Normal file
232
ipc/ipdl/ipdl.py
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
# 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/.
|
||||
|
||||
import optparse, os, re, sys
|
||||
from cStringIO import StringIO
|
||||
from mozbuild.pythonutil import iter_modules_in_path
|
||||
import mozpack.path as mozpath
|
||||
import itertools
|
||||
|
||||
import ipdl
|
||||
|
||||
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('-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""")
|
||||
|
||||
|
||||
options, files = op.parse_args()
|
||||
_verbosity = options.verbosity
|
||||
headersdir = options.headersdir
|
||||
cppdir = options.cppdir
|
||||
includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ]
|
||||
|
||||
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')
|
||||
|
||||
# Compiling the IPDL files can take a long time, even on a fast machine.
|
||||
# Check to see whether we need to do any work.
|
||||
latestipdlmod = max(os.stat(f).st_mtime
|
||||
for f in itertools.chain(files,
|
||||
iter_modules_in_path(mozpath.dirname(__file__))))
|
||||
|
||||
def outputModTime(f):
|
||||
# A non-existant file is newer than everything.
|
||||
if not os.path.exists(f):
|
||||
return 0
|
||||
return os.stat(f).st_mtime
|
||||
|
||||
# Because the IPDL headers are placed into directories reflecting their
|
||||
# namespace, collect a list here so we can easily map output names without
|
||||
# parsing the actual IPDL files themselves.
|
||||
headersmap = {}
|
||||
for (path, dirs, headers) in os.walk(headersdir):
|
||||
for h in headers:
|
||||
base = os.path.basename(h)
|
||||
if base in headersmap:
|
||||
root, ext = os.path.splitext(base)
|
||||
print >>sys.stderr, 'A protocol named', root, 'exists in multiple namespaces'
|
||||
sys.exit(1)
|
||||
headersmap[base] = os.path.join(path, h)
|
||||
|
||||
def outputfiles(f):
|
||||
base = os.path.basename(f)
|
||||
root, ext = os.path.splitext(base)
|
||||
|
||||
suffixes = ['']
|
||||
if ext == '.ipdl':
|
||||
suffixes += ['Child', 'Parent']
|
||||
|
||||
for suffix in suffixes:
|
||||
yield os.path.join(cppdir, "%s%s.cpp" % (root, suffix))
|
||||
header = "%s%s.h" % (root, suffix)
|
||||
# If the header already exists on disk, use that. Otherwise,
|
||||
# just claim that the header is found in headersdir.
|
||||
if header in headersmap:
|
||||
yield headersmap[header]
|
||||
else:
|
||||
yield os.path.join(headersdir, header)
|
||||
|
||||
def alloutputfiles():
|
||||
for f in files:
|
||||
for s in outputfiles(f):
|
||||
yield s
|
||||
yield ipcmessagestartpath
|
||||
|
||||
earliestoutputmod = min(outputModTime(f) for f in alloutputfiles())
|
||||
|
||||
if latestipdlmod < earliestoutputmod:
|
||||
sys.exit(0)
|
||||
|
||||
log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
|
||||
log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
|
||||
|
||||
allmessages = {}
|
||||
allprotocols = []
|
||||
|
||||
def normalizedFilename(f):
|
||||
if f == '-':
|
||||
return '<stdin>'
|
||||
return f
|
||||
|
||||
# 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 >>sys.stderr, 'Specification could not be parsed.'
|
||||
sys.exit(1)
|
||||
|
||||
log(2, 'checking types')
|
||||
if not ipdl.typecheck(ast):
|
||||
print >>sys.stderr, 'Specification is not well typed.'
|
||||
sys.exit(1)
|
||||
|
||||
if _verbosity > 2:
|
||||
log(3, ' pretty printed code:')
|
||||
ipdl.genipdl(ast, codedir)
|
||||
|
||||
# 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)
|
||||
|
||||
if ast.protocol:
|
||||
allmessages[ast.protocol.name] = ipdl.genmsgenum(ast)
|
||||
allprotocols.append('%sMsgStart' % ast.protocol.name)
|
||||
|
||||
allprotocols.sort()
|
||||
|
||||
ipcmsgstart = StringIO()
|
||||
|
||||
print >>ipcmsgstart, """
|
||||
// CODE GENERATED by ipdl.py. Do not edit.
|
||||
|
||||
#ifndef IPCMessageStart_h
|
||||
#define IPCMessageStart_h
|
||||
|
||||
enum IPCMessageStart {
|
||||
"""
|
||||
|
||||
for name in allprotocols:
|
||||
print >>ipcmsgstart, " %s," % name
|
||||
print >>ipcmsgstart, " %sChild," % name
|
||||
|
||||
print >>ipcmsgstart, """
|
||||
LastMsgIndex
|
||||
};
|
||||
|
||||
static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
|
||||
|
||||
#endif // ifndef IPCMessageStart_h
|
||||
"""
|
||||
|
||||
ipc_msgtype_name = StringIO()
|
||||
print >>ipc_msgtype_name, """
|
||||
// CODE GENERATED by ipdl.py. Do not edit.
|
||||
#include <cstdint>
|
||||
|
||||
#include "IPCMessageStart.h"
|
||||
|
||||
using std::uint32_t;
|
||||
|
||||
namespace {
|
||||
|
||||
enum IPCMessages {
|
||||
"""
|
||||
|
||||
for protocol in sorted(allmessages.keys()):
|
||||
for (msg, num) in allmessages[protocol].idnums:
|
||||
if num:
|
||||
print >>ipc_msgtype_name, " %s = %s," % (msg, num)
|
||||
elif not msg.endswith('End'):
|
||||
print >>ipc_msgtype_name, " %s__%s," % (protocol, msg)
|
||||
|
||||
print >>ipc_msgtype_name, """
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
const char* StringFromIPCMessageType(uint32_t aMessageType)
|
||||
{
|
||||
switch (aMessageType) {
|
||||
"""
|
||||
|
||||
for protocol in sorted(allmessages.keys()):
|
||||
for (msg, num) in allmessages[protocol].idnums:
|
||||
if num or msg.endswith('End'):
|
||||
continue
|
||||
print >>ipc_msgtype_name, """
|
||||
case %s__%s:
|
||||
return "%s::%s";""" % (protocol, msg, protocol, msg)
|
||||
|
||||
print >>ipc_msgtype_name, """
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
"""
|
||||
|
||||
ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
|
||||
ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)
|
||||
77
ipc/ipdl/ipdl/__init__.py
Normal file
77
ipc/ipdl/ipdl/__init__.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# 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/.
|
||||
|
||||
__all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified' ]
|
||||
|
||||
import os, sys
|
||||
from cStringIO import StringIO
|
||||
|
||||
from ipdl.cgen import IPDLCodeGen
|
||||
from ipdl.lower import LowerToCxx, msgenums
|
||||
from ipdl.parser import Parser
|
||||
from ipdl.type import TypeCheck
|
||||
|
||||
from ipdl.cxx.cgen import CxxCodeGen
|
||||
|
||||
|
||||
def parse(specstring, filename='/stdin', includedirs=[ ], errout=sys.stderr):
|
||||
'''Return an IPDL AST if parsing was successful. Print errors to |errout|
|
||||
if it is not.'''
|
||||
# The file type and name are later enforced by the type checker.
|
||||
# This is just a hint to the parser.
|
||||
prefix, ext = os.path.splitext(filename)
|
||||
name = os.path.basename(prefix)
|
||||
if ext == '.ipdlh':
|
||||
type = 'header'
|
||||
else:
|
||||
type = 'protocol'
|
||||
return Parser(type, name).parse(specstring, os.path.abspath(filename), includedirs, errout)
|
||||
|
||||
|
||||
def typecheck(ast, errout=sys.stderr):
|
||||
'''Return True iff |ast| is well typed. Print errors to |errout| if
|
||||
it is not.'''
|
||||
return TypeCheck().check(ast, errout)
|
||||
|
||||
|
||||
def gencxx(ipdlfilename, ast, outheadersdir, outcppdir):
|
||||
headers, cpps = LowerToCxx().lower(ast)
|
||||
|
||||
def resolveHeader(hdr):
|
||||
return [
|
||||
hdr,
|
||||
os.path.join(
|
||||
outheadersdir,
|
||||
*([ns.name for ns in ast.namespaces] + [hdr.name]))
|
||||
]
|
||||
def resolveCpp(cpp):
|
||||
return [ cpp, os.path.join(outcppdir, cpp.name) ]
|
||||
|
||||
for ast, filename in ([ resolveHeader(hdr) for hdr in headers ]
|
||||
+ [ resolveCpp(cpp) for cpp in cpps ]):
|
||||
tempfile = StringIO()
|
||||
CxxCodeGen(tempfile).cgen(ast)
|
||||
writeifmodified(tempfile.getvalue(), filename)
|
||||
|
||||
|
||||
def genipdl(ast, outdir):
|
||||
return IPDLCodeGen().cgen(ast)
|
||||
|
||||
|
||||
def genmsgenum(ast):
|
||||
return msgenums(ast.protocol, pretty=True)
|
||||
|
||||
def writeifmodified(contents, file):
|
||||
dir = os.path.dirname(file)
|
||||
os.path.exists(dir) or os.makedirs(dir)
|
||||
|
||||
oldcontents = None
|
||||
if os.path.exists(file):
|
||||
fd = open(file, 'rb')
|
||||
oldcontents = fd.read()
|
||||
fd.close()
|
||||
if oldcontents != contents:
|
||||
fd = open(file, 'wb')
|
||||
fd.write(contents)
|
||||
fd.close()
|
||||
454
ipc/ipdl/ipdl/ast.py
Normal file
454
ipc/ipdl/ipdl/ast.py
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
# 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/.
|
||||
|
||||
import sys
|
||||
|
||||
NOT_NESTED = 1
|
||||
INSIDE_SYNC_NESTED = 2
|
||||
INSIDE_CPOW_NESTED = 3
|
||||
|
||||
NORMAL_PRIORITY = 1
|
||||
HIGH_PRIORITY = 2
|
||||
|
||||
class Visitor:
|
||||
def defaultVisit(self, node):
|
||||
raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
|
||||
node.__class__.__name__)
|
||||
|
||||
def visitTranslationUnit(self, tu):
|
||||
for cxxInc in tu.cxxIncludes:
|
||||
cxxInc.accept(self)
|
||||
for inc in tu.includes:
|
||||
inc.accept(self)
|
||||
for su in tu.structsAndUnions:
|
||||
su.accept(self)
|
||||
for using in tu.builtinUsing:
|
||||
using.accept(self)
|
||||
for using in tu.using:
|
||||
using.accept(self)
|
||||
if tu.protocol:
|
||||
tu.protocol.accept(self)
|
||||
|
||||
|
||||
def visitCxxInclude(self, inc):
|
||||
pass
|
||||
|
||||
def visitInclude(self, inc):
|
||||
# Note: we don't visit the child AST here, because that needs delicate
|
||||
# and pass-specific handling
|
||||
pass
|
||||
|
||||
def visitStructDecl(self, struct):
|
||||
for f in struct.fields:
|
||||
f.accept(self)
|
||||
|
||||
def visitStructField(self, field):
|
||||
field.typespec.accept(self)
|
||||
|
||||
def visitUnionDecl(self, union):
|
||||
for t in union.components:
|
||||
t.accept(self)
|
||||
|
||||
def visitUsingStmt(self, using):
|
||||
pass
|
||||
|
||||
def visitProtocol(self, p):
|
||||
for namespace in p.namespaces:
|
||||
namespace.accept(self)
|
||||
for spawns in p.spawnsStmts:
|
||||
spawns.accept(self)
|
||||
for bridges in p.bridgesStmts:
|
||||
bridges.accept(self)
|
||||
for opens in p.opensStmts:
|
||||
opens.accept(self)
|
||||
for mgr in p.managers:
|
||||
mgr.accept(self)
|
||||
for managed in p.managesStmts:
|
||||
managed.accept(self)
|
||||
for msgDecl in p.messageDecls:
|
||||
msgDecl.accept(self)
|
||||
for transitionStmt in p.transitionStmts:
|
||||
transitionStmt.accept(self)
|
||||
|
||||
def visitNamespace(self, ns):
|
||||
pass
|
||||
|
||||
def visitSpawnsStmt(self, spawns):
|
||||
pass
|
||||
|
||||
def visitBridgesStmt(self, bridges):
|
||||
pass
|
||||
|
||||
def visitOpensStmt(self, opens):
|
||||
pass
|
||||
|
||||
def visitManager(self, mgr):
|
||||
pass
|
||||
|
||||
def visitManagesStmt(self, mgs):
|
||||
pass
|
||||
|
||||
def visitMessageDecl(self, md):
|
||||
for inParam in md.inParams:
|
||||
inParam.accept(self)
|
||||
for outParam in md.outParams:
|
||||
outParam.accept(self)
|
||||
|
||||
def visitTransitionStmt(self, ts):
|
||||
ts.state.accept(self)
|
||||
for trans in ts.transitions:
|
||||
trans.accept(self)
|
||||
|
||||
def visitTransition(self, t):
|
||||
for toState in t.toStates:
|
||||
toState.accept(self)
|
||||
|
||||
def visitState(self, s):
|
||||
pass
|
||||
|
||||
def visitParam(self, decl):
|
||||
pass
|
||||
|
||||
def visitTypeSpec(self, ts):
|
||||
pass
|
||||
|
||||
def visitDecl(self, d):
|
||||
pass
|
||||
|
||||
class Loc:
|
||||
def __init__(self, filename='<??>', lineno=0):
|
||||
assert filename
|
||||
self.filename = filename
|
||||
self.lineno = lineno
|
||||
def __repr__(self):
|
||||
return '%r:%r'% (self.filename, self.lineno)
|
||||
def __str__(self):
|
||||
return '%s:%s'% (self.filename, self.lineno)
|
||||
|
||||
Loc.NONE = Loc(filename='<??>', lineno=0)
|
||||
|
||||
class _struct:
|
||||
pass
|
||||
|
||||
class Node:
|
||||
def __init__(self, loc=Loc.NONE):
|
||||
self.loc = loc
|
||||
|
||||
def accept(self, visitor):
|
||||
visit = getattr(visitor, 'visit'+ self.__class__.__name__, None)
|
||||
if visit is None:
|
||||
return getattr(visitor, 'defaultVisit')(self)
|
||||
return visit(self)
|
||||
|
||||
def addAttrs(self, attrsName):
|
||||
if not hasattr(self, attrsName):
|
||||
setattr(self, attrsName, _struct())
|
||||
|
||||
|
||||
class NamespacedNode(Node):
|
||||
def __init__(self, loc=Loc.NONE, name=None):
|
||||
Node.__init__(self, loc)
|
||||
self.name = name
|
||||
self.namespaces = [ ]
|
||||
|
||||
def addOuterNamespace(self, namespace):
|
||||
self.namespaces.insert(0, namespace)
|
||||
|
||||
def qname(self):
|
||||
return QualifiedId(self.loc, self.name,
|
||||
[ ns.name for ns in self.namespaces ])
|
||||
|
||||
class TranslationUnit(NamespacedNode):
|
||||
def __init__(self, type, name):
|
||||
NamespacedNode.__init__(self, name=name)
|
||||
self.filetype = type
|
||||
self.filename = None
|
||||
self.cxxIncludes = [ ]
|
||||
self.includes = [ ]
|
||||
self.builtinUsing = [ ]
|
||||
self.using = [ ]
|
||||
self.structsAndUnions = [ ]
|
||||
self.protocol = None
|
||||
|
||||
def addCxxInclude(self, cxxInclude): self.cxxIncludes.append(cxxInclude)
|
||||
def addInclude(self, inc): self.includes.append(inc)
|
||||
def addStructDecl(self, struct): self.structsAndUnions.append(struct)
|
||||
def addUnionDecl(self, union): self.structsAndUnions.append(union)
|
||||
def addUsingStmt(self, using): self.using.append(using)
|
||||
|
||||
def setProtocol(self, protocol): self.protocol = protocol
|
||||
|
||||
class CxxInclude(Node):
|
||||
def __init__(self, loc, cxxFile):
|
||||
Node.__init__(self, loc)
|
||||
self.file = cxxFile
|
||||
|
||||
class Include(Node):
|
||||
def __init__(self, loc, type, name):
|
||||
Node.__init__(self, loc)
|
||||
suffix = 'ipdl'
|
||||
if type == 'header':
|
||||
suffix += 'h'
|
||||
self.file = "%s.%s" % (name, suffix)
|
||||
|
||||
class UsingStmt(Node):
|
||||
def __init__(self, loc, cxxTypeSpec, cxxHeader=None, kind=None):
|
||||
Node.__init__(self, loc)
|
||||
assert not isinstance(cxxTypeSpec, str)
|
||||
assert cxxHeader is None or isinstance(cxxHeader, str);
|
||||
assert kind is None or kind == 'class' or kind == 'struct'
|
||||
self.type = cxxTypeSpec
|
||||
self.header = cxxHeader
|
||||
self.kind = kind
|
||||
def canBeForwardDeclared(self):
|
||||
return self.isClass() or self.isStruct()
|
||||
def isClass(self):
|
||||
return self.kind == 'class'
|
||||
def isStruct(self):
|
||||
return self.kind == 'struct'
|
||||
|
||||
# "singletons"
|
||||
class PrettyPrinted:
|
||||
@classmethod
|
||||
def __hash__(cls): return hash(cls.pretty)
|
||||
@classmethod
|
||||
def __str__(cls): return cls.pretty
|
||||
|
||||
class ASYNC(PrettyPrinted):
|
||||
pretty = 'async'
|
||||
class INTR(PrettyPrinted):
|
||||
pretty = 'intr'
|
||||
class SYNC(PrettyPrinted):
|
||||
pretty = 'sync'
|
||||
|
||||
class INOUT(PrettyPrinted):
|
||||
pretty = 'inout'
|
||||
class IN(PrettyPrinted):
|
||||
pretty = 'in'
|
||||
class OUT(PrettyPrinted):
|
||||
pretty = 'out'
|
||||
|
||||
|
||||
class Namespace(Node):
|
||||
def __init__(self, loc, namespace):
|
||||
Node.__init__(self, loc)
|
||||
self.name = namespace
|
||||
|
||||
class Protocol(NamespacedNode):
|
||||
def __init__(self, loc):
|
||||
NamespacedNode.__init__(self, loc)
|
||||
self.sendSemantics = ASYNC
|
||||
self.nested = NOT_NESTED
|
||||
self.spawnsStmts = [ ]
|
||||
self.bridgesStmts = [ ]
|
||||
self.opensStmts = [ ]
|
||||
self.managers = [ ]
|
||||
self.managesStmts = [ ]
|
||||
self.messageDecls = [ ]
|
||||
self.transitionStmts = [ ]
|
||||
self.startStates = [ ]
|
||||
|
||||
class StructField(Node):
|
||||
def __init__(self, loc, type, name):
|
||||
Node.__init__(self, loc)
|
||||
self.typespec = type
|
||||
self.name = name
|
||||
|
||||
class StructDecl(NamespacedNode):
|
||||
def __init__(self, loc, name, fields):
|
||||
NamespacedNode.__init__(self, loc, name)
|
||||
self.fields = fields
|
||||
|
||||
class UnionDecl(NamespacedNode):
|
||||
def __init__(self, loc, name, components):
|
||||
NamespacedNode.__init__(self, loc, name)
|
||||
self.components = components
|
||||
|
||||
class SpawnsStmt(Node):
|
||||
def __init__(self, loc, side, proto, spawnedAs):
|
||||
Node.__init__(self, loc)
|
||||
self.side = side
|
||||
self.proto = proto
|
||||
self.spawnedAs = spawnedAs
|
||||
|
||||
class BridgesStmt(Node):
|
||||
def __init__(self, loc, parentSide, childSide):
|
||||
Node.__init__(self, loc)
|
||||
self.parentSide = parentSide
|
||||
self.childSide = childSide
|
||||
|
||||
class OpensStmt(Node):
|
||||
def __init__(self, loc, side, proto):
|
||||
Node.__init__(self, loc)
|
||||
self.side = side
|
||||
self.proto = proto
|
||||
|
||||
class Manager(Node):
|
||||
def __init__(self, loc, managerName):
|
||||
Node.__init__(self, loc)
|
||||
self.name = managerName
|
||||
|
||||
class ManagesStmt(Node):
|
||||
def __init__(self, loc, managedName):
|
||||
Node.__init__(self, loc)
|
||||
self.name = managedName
|
||||
|
||||
class MessageDecl(Node):
|
||||
def __init__(self, loc):
|
||||
Node.__init__(self, loc)
|
||||
self.name = None
|
||||
self.sendSemantics = ASYNC
|
||||
self.nested = NOT_NESTED
|
||||
self.prio = NORMAL_PRIORITY
|
||||
self.direction = None
|
||||
self.inParams = [ ]
|
||||
self.outParams = [ ]
|
||||
self.compress = ''
|
||||
self.verify = ''
|
||||
|
||||
def addInParams(self, inParamsList):
|
||||
self.inParams += inParamsList
|
||||
|
||||
def addOutParams(self, outParamsList):
|
||||
self.outParams += outParamsList
|
||||
|
||||
def addModifiers(self, modifiers):
|
||||
for modifier in modifiers:
|
||||
if modifier.startswith('compress'):
|
||||
self.compress = modifier
|
||||
elif modifier == 'verify':
|
||||
self.verify = modifier
|
||||
elif modifier != '':
|
||||
raise Exception, "Unexpected message modifier `%s'"% modifier
|
||||
|
||||
class Transition(Node):
|
||||
def __init__(self, loc, trigger, msg, toStates):
|
||||
Node.__init__(self, loc)
|
||||
self.trigger = trigger
|
||||
self.msg = msg
|
||||
self.toStates = toStates
|
||||
|
||||
def __cmp__(self, o):
|
||||
c = cmp(self.msg, o.msg)
|
||||
if c: return c
|
||||
c = cmp(self.trigger, o.trigger)
|
||||
if c: return c
|
||||
|
||||
def __hash__(self): return hash(str(self))
|
||||
def __str__(self): return '%s %s'% (self.trigger, self.msg)
|
||||
|
||||
@staticmethod
|
||||
def nameToTrigger(name):
|
||||
return { 'send': SEND, 'recv': RECV, 'call': CALL, 'answer': ANSWER }[name]
|
||||
|
||||
Transition.NULL = Transition(Loc.NONE, None, None, [ ])
|
||||
|
||||
class TransitionStmt(Node):
|
||||
def __init__(self, loc, state, transitions):
|
||||
Node.__init__(self, loc)
|
||||
self.state = state
|
||||
self.transitions = transitions
|
||||
|
||||
@staticmethod
|
||||
def makeNullStmt(state):
|
||||
return TransitionStmt(Loc.NONE, state, [ Transition.NULL ])
|
||||
|
||||
class SEND:
|
||||
pretty = 'send'
|
||||
@classmethod
|
||||
def __hash__(cls): return hash(cls.pretty)
|
||||
@classmethod
|
||||
def direction(cls): return OUT
|
||||
class RECV:
|
||||
pretty = 'recv'
|
||||
@classmethod
|
||||
def __hash__(cls): return hash(cls.pretty)
|
||||
@classmethod
|
||||
def direction(cls): return IN
|
||||
class CALL:
|
||||
pretty = 'call'
|
||||
@classmethod
|
||||
def __hash__(cls): return hash(cls.pretty)
|
||||
@classmethod
|
||||
def direction(cls): return OUT
|
||||
class ANSWER:
|
||||
pretty = 'answer'
|
||||
@classmethod
|
||||
def __hash__(cls): return hash(cls.pretty)
|
||||
@classmethod
|
||||
def direction(cls): return IN
|
||||
|
||||
class State(Node):
|
||||
def __init__(self, loc, name, start=False):
|
||||
Node.__init__(self, loc)
|
||||
self.name = name
|
||||
self.start = start
|
||||
def __eq__(self, o):
|
||||
return (isinstance(o, State)
|
||||
and o.name == self.name
|
||||
and o.start == self.start)
|
||||
def __hash__(self):
|
||||
return hash(repr(self))
|
||||
def __ne__(self, o):
|
||||
return not (self == o)
|
||||
def __repr__(self): return '<State %r start=%r>'% (self.name, self.start)
|
||||
def __str__(self): return '<State %s start=%s>'% (self.name, self.start)
|
||||
|
||||
State.ANY = State(Loc.NONE, '[any]', start=True)
|
||||
State.DEAD = State(Loc.NONE, '[dead]', start=False)
|
||||
State.DYING = State(Loc.NONE, '[dying]', start=False)
|
||||
|
||||
class Param(Node):
|
||||
def __init__(self, loc, typespec, name):
|
||||
Node.__init__(self, loc)
|
||||
self.name = name
|
||||
self.typespec = typespec
|
||||
|
||||
class TypeSpec(Node):
|
||||
def __init__(self, loc, spec, state=None, array=0, nullable=0,
|
||||
myChmod=None, otherChmod=None):
|
||||
Node.__init__(self, loc)
|
||||
self.spec = spec # QualifiedId
|
||||
self.state = state # None or State
|
||||
self.array = array # bool
|
||||
self.nullable = nullable # bool
|
||||
self.myChmod = myChmod # None or string
|
||||
self.otherChmod = otherChmod # None or string
|
||||
|
||||
def basename(self):
|
||||
return self.spec.baseid
|
||||
|
||||
def isActor(self):
|
||||
return self.state is not None
|
||||
|
||||
def __str__(self): return str(self.spec)
|
||||
|
||||
class QualifiedId: # FIXME inherit from node?
|
||||
def __init__(self, loc, baseid, quals=[ ]):
|
||||
assert isinstance(baseid, str)
|
||||
for qual in quals: assert isinstance(qual, str)
|
||||
|
||||
self.loc = loc
|
||||
self.baseid = baseid
|
||||
self.quals = quals
|
||||
|
||||
def qualify(self, id):
|
||||
self.quals.append(self.baseid)
|
||||
self.baseid = id
|
||||
|
||||
def __str__(self):
|
||||
if 0 == len(self.quals):
|
||||
return self.baseid
|
||||
return '::'.join(self.quals) +'::'+ self.baseid
|
||||
|
||||
# added by type checking passes
|
||||
class Decl(Node):
|
||||
def __init__(self, loc):
|
||||
Node.__init__(self, loc)
|
||||
self.progname = None # what the programmer typed, if relevant
|
||||
self.shortname = None # shortest way to refer to this decl
|
||||
self.fullname = None # full way to refer to this decl
|
||||
self.loc = loc
|
||||
self.type = None
|
||||
self.scope = None
|
||||
59
ipc/ipdl/ipdl/builtin.py
Normal file
59
ipc/ipdl/ipdl/builtin.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# 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/.
|
||||
|
||||
# WARNING: the syntax of the builtin types is not checked, so please
|
||||
# don't add something syntactically invalid. It will not be fun to
|
||||
# track down the bug.
|
||||
|
||||
Types = (
|
||||
# C types
|
||||
'bool',
|
||||
'char',
|
||||
'short',
|
||||
'int',
|
||||
'long',
|
||||
'float',
|
||||
'double',
|
||||
|
||||
# stdint types
|
||||
'int8_t',
|
||||
'uint8_t',
|
||||
'int16_t',
|
||||
'uint16_t',
|
||||
'int32_t',
|
||||
'uint32_t',
|
||||
'int64_t',
|
||||
'uint64_t',
|
||||
'intptr_t',
|
||||
'uintptr_t',
|
||||
|
||||
# stddef types
|
||||
'size_t',
|
||||
'ssize_t',
|
||||
|
||||
# Mozilla types: "less" standard things we know how serialize/deserialize
|
||||
'nsresult',
|
||||
'nsString',
|
||||
'nsCString',
|
||||
'mozilla::ipc::Shmem',
|
||||
'mozilla::ipc::FileDescriptor'
|
||||
)
|
||||
|
||||
|
||||
HeaderIncludes = (
|
||||
'mozilla/Attributes.h',
|
||||
'IPCMessageStart.h',
|
||||
'ipc/IPCMessageUtils.h',
|
||||
'mozilla/RefPtr.h',
|
||||
'nsStringGlue.h',
|
||||
'nsTArray.h',
|
||||
'mozilla/ipc/ProtocolUtils.h',
|
||||
'nsTHashtable.h',
|
||||
'mozilla/OperatorNewExtensions.h',
|
||||
)
|
||||
|
||||
CppIncludes = (
|
||||
'nsIFile.h',
|
||||
'GeckoProfiler.h',
|
||||
)
|
||||
101
ipc/ipdl/ipdl/cgen.py
Normal file
101
ipc/ipdl/ipdl/cgen.py
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# 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/.
|
||||
|
||||
import os, sys
|
||||
|
||||
from ipdl.ast import Visitor
|
||||
from ipdl.ast import IN, OUT, INOUT, ASYNC, SYNC, INTR
|
||||
|
||||
class CodePrinter:
|
||||
def __init__(self, outf=sys.stdout, indentCols=4):
|
||||
self.outf = outf
|
||||
self.col = 0
|
||||
self.indentCols = indentCols
|
||||
|
||||
def write(self, str):
|
||||
self.outf.write(str)
|
||||
|
||||
def printdent(self, str=''):
|
||||
self.write((' '* self.col) + str)
|
||||
|
||||
def println(self, str=''):
|
||||
self.write(str +'\n')
|
||||
|
||||
def printdentln(self, str):
|
||||
self.write((' '* self.col) + str +'\n')
|
||||
|
||||
def indent(self): self.col += self.indentCols
|
||||
def dedent(self): self.col -= self.indentCols
|
||||
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
class IPDLCodeGen(CodePrinter, Visitor):
|
||||
'''Spits back out equivalent IPDL to the code that generated this.
|
||||
Also known as pretty-printing.'''
|
||||
|
||||
def __init__(self, outf=sys.stdout, indentCols=4, printed=set()):
|
||||
CodePrinter.__init__(self, outf, indentCols)
|
||||
self.printed = printed
|
||||
|
||||
def visitTranslationUnit(self, tu):
|
||||
self.printed.add(tu.filename)
|
||||
self.println('//\n// Automatically generated by ipdlc\n//')
|
||||
CodeGen.visitTranslationUnit(self, tu)
|
||||
|
||||
def visitCxxInclude(self, inc):
|
||||
self.println('include "'+ inc.file +'";')
|
||||
|
||||
def visitProtocolInclude(self, inc):
|
||||
self.println('include protocol "'+ inc.file +'";')
|
||||
if inc.tu.filename not in self.printed:
|
||||
self.println('/* Included file:')
|
||||
IPDLCodeGen(outf=self.outf, indentCols=self.indentCols,
|
||||
printed=self.printed).visitTranslationUnit(inc.tu)
|
||||
|
||||
self.println('*/')
|
||||
|
||||
def visitProtocol(self, p):
|
||||
self.println()
|
||||
for namespace in p.namespaces: namespace.accept(self)
|
||||
|
||||
self.println('%s protocol %s\n{'% (p.sendSemantics[0], p.name))
|
||||
self.indent()
|
||||
|
||||
for mgs in p.managesStmts:
|
||||
mgs.accept(self)
|
||||
if len(p.managesStmts): self.println()
|
||||
|
||||
for msgDecl in p.messageDecls: msgDecl.accept(self)
|
||||
self.println()
|
||||
|
||||
for transStmt in p.transitionStmts: transStmt.accept(self)
|
||||
|
||||
self.dedent()
|
||||
self.println('}')
|
||||
self.write('}\n'* len(p.namespaces))
|
||||
|
||||
def visitManagerStmt(self, mgr):
|
||||
self.printdentln('manager '+ mgr.name +';')
|
||||
|
||||
def visitManagesStmt(self, mgs):
|
||||
self.printdentln('manages '+ mgs.name +';')
|
||||
|
||||
def visitMessageDecl(self, msg):
|
||||
self.printdent('%s %s %s('% (msg.sendSemantics[0], msg.direction[0], msg.name))
|
||||
for i, inp in enumerate(msg.inParams):
|
||||
inp.accept(self)
|
||||
if i != (len(msg.inParams) - 1): self.write(', ')
|
||||
self.write(')')
|
||||
if 0 == len(msg.outParams):
|
||||
self.println(';')
|
||||
return
|
||||
|
||||
self.println()
|
||||
self.indent()
|
||||
self.printdent('returns (')
|
||||
for i, outp in enumerate(msg.outParams):
|
||||
outp.accept(self)
|
||||
if i != (len(msg.outParams) - 1): self.write(', ')
|
||||
self.println(');')
|
||||
self.dedent()
|
||||
6
ipc/ipdl/ipdl/cxx/__init__.py
Normal file
6
ipc/ipdl/ipdl/cxx/__init__.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# 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/.
|
||||
|
||||
import ipdl.cxx.ast
|
||||
import ipdl.cxx.cgen
|
||||
809
ipc/ipdl/ipdl/cxx/ast.py
Normal file
809
ipc/ipdl/ipdl/cxx/ast.py
Normal file
|
|
@ -0,0 +1,809 @@
|
|||
# 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/.
|
||||
|
||||
import copy, sys
|
||||
|
||||
class Visitor:
|
||||
def defaultVisit(self, node):
|
||||
raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
|
||||
node.__class__.__name__)
|
||||
|
||||
def visitWhitespace(self, ws):
|
||||
pass
|
||||
|
||||
def visitFile(self, f):
|
||||
for thing in f.stuff:
|
||||
thing.accept(self)
|
||||
|
||||
def visitCppDirective(self, ppd):
|
||||
pass
|
||||
|
||||
def visitBlock(self, block):
|
||||
for stmt in block.stmts:
|
||||
stmt.accept(self)
|
||||
|
||||
def visitNamespace(self, ns):
|
||||
self.visitBlock(ns)
|
||||
|
||||
def visitType(self, type):
|
||||
pass
|
||||
|
||||
def visitTypeArray(self, ta):
|
||||
ta.basetype.accept(self)
|
||||
ta.nmemb.accept(self)
|
||||
|
||||
def visitTypeEnum(self, enum):
|
||||
pass
|
||||
|
||||
def visitTypeUnion(self, union):
|
||||
for t, name in union.components:
|
||||
t.accept(self)
|
||||
|
||||
def visitTypedef(self, tdef):
|
||||
tdef.fromtype.accept(self)
|
||||
|
||||
def visitUsing(self, us):
|
||||
us.type.accept(self)
|
||||
|
||||
def visitForwardDecl(self, fd):
|
||||
pass
|
||||
|
||||
def visitDecl(self, decl):
|
||||
decl.type.accept(self)
|
||||
|
||||
def visitParam(self, param):
|
||||
self.visitDecl(param)
|
||||
if param.default is not None:
|
||||
param.default.accept(self)
|
||||
|
||||
def visitClass(self, cls):
|
||||
for inherit in cls.inherits:
|
||||
inherit.accept(self)
|
||||
self.visitBlock(cls)
|
||||
|
||||
def visitInherit(self, inh):
|
||||
pass
|
||||
|
||||
def visitFriendClassDecl(self, fcd):
|
||||
pass
|
||||
|
||||
def visitMethodDecl(self, meth):
|
||||
for param in meth.params:
|
||||
param.accept(self)
|
||||
if meth.ret is not None:
|
||||
meth.ret.accept(self)
|
||||
if meth.typeop is not None:
|
||||
meth.typeop.accept(self)
|
||||
if meth.T is not None:
|
||||
meth.T.accept(self)
|
||||
|
||||
def visitMethodDefn(self, meth):
|
||||
meth.decl.accept(self)
|
||||
self.visitBlock(meth)
|
||||
|
||||
def visitFunctionDecl(self, fun):
|
||||
self.visitMethodDecl(fun)
|
||||
|
||||
def visitFunctionDefn(self, fd):
|
||||
self.visitMethodDefn(fd)
|
||||
|
||||
def visitConstructorDecl(self, ctor):
|
||||
self.visitMethodDecl(ctor)
|
||||
|
||||
def visitConstructorDefn(self, cd):
|
||||
cd.decl.accept(self)
|
||||
for init in cd.memberinits:
|
||||
init.accept(self)
|
||||
self.visitBlock(cd)
|
||||
|
||||
def visitDestructorDecl(self, dtor):
|
||||
self.visitMethodDecl(dtor)
|
||||
|
||||
def visitDestructorDefn(self, dd):
|
||||
dd.decl.accept(self)
|
||||
self.visitBlock(dd)
|
||||
|
||||
def visitExprLiteral(self, l):
|
||||
pass
|
||||
|
||||
def visitExprVar(self, v):
|
||||
pass
|
||||
|
||||
def visitExprPrefixUnop(self, e):
|
||||
e.expr.accept(self)
|
||||
|
||||
def visitExprBinary(self, e):
|
||||
e.left.accept(self)
|
||||
e.right.accept(self)
|
||||
|
||||
def visitExprConditional(self, c):
|
||||
c.cond.accept(self)
|
||||
c.ife.accept(self)
|
||||
c.elsee.accept(self)
|
||||
|
||||
def visitExprAddrOf(self, eao):
|
||||
self.visitExprPrefixUnop(eao)
|
||||
|
||||
def visitExprDeref(self, ed):
|
||||
self.visitExprPrefixUnop(ed)
|
||||
|
||||
def visitExprNot(self, en):
|
||||
self.visitExprPrefixUnop(en)
|
||||
|
||||
def visitExprCast(self, ec):
|
||||
ec.expr.accept(self)
|
||||
|
||||
def visitExprIndex(self, ei):
|
||||
ei.arr.accept(self)
|
||||
ei.idx.accept(self)
|
||||
|
||||
def visitExprSelect(self, es):
|
||||
es.obj.accept(self)
|
||||
|
||||
def visitExprAssn(self, ea):
|
||||
ea.lhs.accept(self)
|
||||
ea.rhs.accept(self)
|
||||
|
||||
def visitExprCall(self, ec):
|
||||
ec.func.accept(self)
|
||||
for arg in ec.args:
|
||||
arg.accept(self)
|
||||
|
||||
def visitExprNew(self, en):
|
||||
en.ctype.accept(self)
|
||||
if en.newargs is not None:
|
||||
for arg in en.newargs:
|
||||
arg.accept(self)
|
||||
if en.args is not None:
|
||||
for arg in en.args:
|
||||
arg.accept(self)
|
||||
|
||||
def visitExprDelete(self, ed):
|
||||
ed.obj.accept(self)
|
||||
|
||||
def visitExprMemberInit(self, minit):
|
||||
self.visitExprCall(minit)
|
||||
|
||||
def visitExprSizeof(self, es):
|
||||
self.visitExprCall(es)
|
||||
|
||||
def visitStmtBlock(self, sb):
|
||||
self.visitBlock(sb)
|
||||
|
||||
def visitStmtDecl(self, sd):
|
||||
sd.decl.accept(self)
|
||||
if sd.init is not None:
|
||||
sd.init.accept(self)
|
||||
|
||||
def visitLabel(self, label):
|
||||
pass
|
||||
|
||||
def visitCaseLabel(self, case):
|
||||
pass
|
||||
|
||||
def visitDefaultLabel(self, dl):
|
||||
pass
|
||||
|
||||
def visitStmtIf(self, si):
|
||||
si.cond.accept(self)
|
||||
si.ifb.accept(self)
|
||||
if si.elseb is not None:
|
||||
si.elseb.accept(self)
|
||||
|
||||
def visitStmtFor(self, sf):
|
||||
if sf.init is not None:
|
||||
sf.init.accept(self)
|
||||
if sf.cond is not None:
|
||||
sf.cond.accept(self)
|
||||
if sf.update is not None:
|
||||
sf.update.accept(self)
|
||||
|
||||
def visitStmtSwitch(self, ss):
|
||||
ss.expr.accept(self)
|
||||
self.visitBlock(ss)
|
||||
|
||||
def visitStmtBreak(self, sb):
|
||||
pass
|
||||
|
||||
def visitStmtExpr(self, se):
|
||||
se.expr.accept(self)
|
||||
|
||||
def visitStmtReturn(self, sr):
|
||||
if sr.expr is not None:
|
||||
sr.expr.accept(self)
|
||||
|
||||
##------------------------------
|
||||
class Node:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def accept(self, visitor):
|
||||
visit = getattr(visitor, 'visit'+ self.__class__.__name__, None)
|
||||
if visit is None:
|
||||
return getattr(visitor, 'defaultVisit')(self)
|
||||
return visit(self)
|
||||
|
||||
class Whitespace(Node):
|
||||
# yes, this is silly. but we need to stick comments in the
|
||||
# generated code without resorting to more serious hacks
|
||||
def __init__(self, ws, indent=0):
|
||||
Node.__init__(self)
|
||||
self.ws = ws
|
||||
self.indent = indent
|
||||
Whitespace.NL = Whitespace('\n')
|
||||
|
||||
class File(Node):
|
||||
def __init__(self, filename):
|
||||
Node.__init__(self)
|
||||
self.name = filename
|
||||
# array of stuff in the file --- stmts and preprocessor thingies
|
||||
self.stuff = [ ]
|
||||
|
||||
def addthing(self, thing):
|
||||
assert thing is not None
|
||||
assert not isinstance(thing, list)
|
||||
self.stuff.append(thing)
|
||||
|
||||
def addthings(self, things):
|
||||
for t in things: self.addthing(t)
|
||||
|
||||
# "look like" a Block so code doesn't have to care whether they're
|
||||
# in global scope or not
|
||||
def addstmt(self, stmt):
|
||||
assert stmt is not None
|
||||
assert not isinstance(stmt, list)
|
||||
self.stuff.append(stmt)
|
||||
|
||||
def addstmts(self, stmts):
|
||||
for s in stmts: self.addstmt(s)
|
||||
|
||||
class CppDirective(Node):
|
||||
'''represents |#[directive] [rest]|, where |rest| is any string'''
|
||||
def __init__(self, directive, rest=None):
|
||||
Node.__init__(self)
|
||||
self.directive = directive
|
||||
self.rest = rest
|
||||
|
||||
class Block(Node):
|
||||
def __init__(self):
|
||||
Node.__init__(self)
|
||||
self.stmts = [ ]
|
||||
|
||||
def addstmt(self, stmt):
|
||||
assert stmt is not None
|
||||
assert not isinstance(stmt, tuple)
|
||||
self.stmts.append(stmt)
|
||||
|
||||
def addstmts(self, stmts):
|
||||
for s in stmts: self.addstmt(s)
|
||||
|
||||
##------------------------------
|
||||
# type and decl thingies
|
||||
class Namespace(Block):
|
||||
def __init__(self, name):
|
||||
assert isinstance(name, str)
|
||||
|
||||
Block.__init__(self)
|
||||
self.name = name
|
||||
|
||||
class Type(Node):
|
||||
def __init__(self, name, const=0,
|
||||
ptr=0, ptrconst=0, ptrptr=0, ptrconstptr=0,
|
||||
ref=0,
|
||||
hasimplicitcopyctor=True,
|
||||
T=None):
|
||||
"""
|
||||
To avoid getting fancy with recursive types, we limit the kinds
|
||||
of pointer types that can be be constructed.
|
||||
|
||||
ptr => T*
|
||||
ptrconst => T* const
|
||||
ptrptr => T**
|
||||
ptrconstptr => T* const*
|
||||
|
||||
Any type, naked or pointer, can be const (const T) or ref (T&).
|
||||
"""
|
||||
assert isinstance(name, str)
|
||||
assert not isinstance(const, str)
|
||||
assert not isinstance(T, str)
|
||||
|
||||
Node.__init__(self)
|
||||
self.name = name
|
||||
self.const = const
|
||||
self.ptr = ptr
|
||||
self.ptrconst = ptrconst
|
||||
self.ptrptr = ptrptr
|
||||
self.ptrconstptr = ptrconstptr
|
||||
self.ref = ref
|
||||
self.hasimplicitcopyctor = hasimplicitcopyctor
|
||||
self.T = T
|
||||
# XXX could get serious here with recursive types, but shouldn't
|
||||
# need that for this codegen
|
||||
def __deepcopy__(self, memo):
|
||||
return Type(self.name,
|
||||
const=self.const,
|
||||
ptr=self.ptr, ptrconst=self.ptrconst,
|
||||
ptrptr=self.ptrptr, ptrconstptr=self.ptrconstptr,
|
||||
ref=self.ref,
|
||||
T=copy.deepcopy(self.T, memo))
|
||||
Type.BOOL = Type('bool')
|
||||
Type.INT = Type('int')
|
||||
Type.INT32 = Type('int32_t')
|
||||
Type.INTPTR = Type('intptr_t')
|
||||
Type.NSRESULT = Type('nsresult')
|
||||
Type.UINT32 = Type('uint32_t')
|
||||
Type.UINT32PTR = Type('uint32_t', ptr=1)
|
||||
Type.SIZE = Type('size_t')
|
||||
Type.VOID = Type('void')
|
||||
Type.VOIDPTR = Type('void', ptr=1)
|
||||
Type.AUTO = Type('auto')
|
||||
|
||||
class TypeArray(Node):
|
||||
def __init__(self, basetype, nmemb):
|
||||
'''the type |basetype DECLNAME[nmemb]|. |nmemb| is an Expr'''
|
||||
self.basetype = basetype
|
||||
self.nmemb = nmemb
|
||||
def __deepcopy__(self, memo):
|
||||
return TypeArray(deepcopy(self.basetype, memo), nmemb)
|
||||
|
||||
class TypeEnum(Node):
|
||||
def __init__(self, name=None):
|
||||
'''name can be None'''
|
||||
Node.__init__(self)
|
||||
self.name = name
|
||||
self.idnums = [ ] # pairs of ('Foo', [num]) or ('Foo', None)
|
||||
|
||||
def addId(self, id, num=None):
|
||||
self.idnums.append((id, num))
|
||||
|
||||
class TypeUnion(Node):
|
||||
def __init__(self, name=None):
|
||||
Node.__init__(self)
|
||||
self.name = name
|
||||
self.components = [ ] # [ Decl ]
|
||||
|
||||
def addComponent(self, type, name):
|
||||
self.components.append(Decl(type, name))
|
||||
|
||||
class Typedef(Node):
|
||||
def __init__(self, fromtype, totypename, templateargs=[]):
|
||||
assert isinstance(totypename, str)
|
||||
|
||||
Node.__init__(self)
|
||||
self.fromtype = fromtype
|
||||
self.totypename = totypename
|
||||
self.templateargs = templateargs
|
||||
|
||||
def __cmp__(self, o):
|
||||
return cmp(self.totypename, o.totypename)
|
||||
def __eq__(self, o):
|
||||
return (self.__class__ == o.__class__
|
||||
and 0 == cmp(self, o))
|
||||
def __hash__(self):
|
||||
return hash(self.totypename)
|
||||
|
||||
class Using(Node):
|
||||
def __init__(self, type):
|
||||
Node.__init__(self)
|
||||
self.type = type
|
||||
|
||||
class ForwardDecl(Node):
|
||||
def __init__(self, pqname, cls=0, struct=0):
|
||||
assert (not cls and struct) or (cls and not struct)
|
||||
|
||||
self.pqname = pqname
|
||||
self.cls = cls
|
||||
self.struct = struct
|
||||
|
||||
class Decl(Node):
|
||||
'''represents |Foo bar|, e.g. in a function signature'''
|
||||
def __init__(self, type, name):
|
||||
assert type is not None
|
||||
assert not isinstance(type, str)
|
||||
assert isinstance(name, str)
|
||||
|
||||
Node.__init__(self)
|
||||
self.type = type
|
||||
self.name = name
|
||||
def __deepcopy__(self, memo):
|
||||
return Decl(copy.deepcopy(self.type, memo), self.name)
|
||||
|
||||
class Param(Decl):
|
||||
def __init__(self, type, name, default=None):
|
||||
Decl.__init__(self, type, name)
|
||||
self.default = default
|
||||
def __deepcopy__(self, memo):
|
||||
return Param(copy.deepcopy(self.type, memo), self.name,
|
||||
copy.deepcopy(self.default, memo))
|
||||
|
||||
##------------------------------
|
||||
# class stuff
|
||||
class Class(Block):
|
||||
def __init__(self, name, inherits=[ ],
|
||||
interface=0, abstract=0, final=0,
|
||||
specializes=None, struct=0):
|
||||
assert not (interface and abstract)
|
||||
assert not (abstract and final)
|
||||
assert not (interface and final)
|
||||
assert not (inherits and specializes)
|
||||
|
||||
Block.__init__(self)
|
||||
self.name = name
|
||||
self.inherits = inherits # [ Type ]
|
||||
self.interface = interface # bool
|
||||
self.abstract = abstract # bool
|
||||
self.final = final # bool
|
||||
self.specializes = specializes # Type or None
|
||||
self.struct = struct # bool
|
||||
|
||||
class Inherit(Node):
|
||||
def __init__(self, type, viz='public'):
|
||||
assert isinstance(viz, str)
|
||||
Node.__init__(self)
|
||||
self.type = type
|
||||
self.viz = viz
|
||||
|
||||
class FriendClassDecl(Node):
|
||||
def __init__(self, friend):
|
||||
Node.__init__(self)
|
||||
self.friend = friend
|
||||
|
||||
class MethodDecl(Node):
|
||||
def __init__(self, name, params=[ ], ret=Type('void'),
|
||||
virtual=0, const=0, pure=0, static=0, warn_unused=0,
|
||||
inline=0, force_inline=0, never_inline=0,
|
||||
typeop=None,
|
||||
T=None):
|
||||
assert not (virtual and static)
|
||||
assert not pure or virtual # pure => virtual
|
||||
assert not (static and typeop)
|
||||
assert not (name and typeop)
|
||||
assert name is None or isinstance(name, str)
|
||||
assert not isinstance(ret, list)
|
||||
for decl in params: assert not isinstance(decl, str)
|
||||
assert not isinstance(T, int)
|
||||
assert not (inline and never_inline)
|
||||
assert not (force_inline and never_inline)
|
||||
|
||||
if typeop is not None:
|
||||
ret = None
|
||||
|
||||
Node.__init__(self)
|
||||
self.name = name
|
||||
self.params = params # [ Param ]
|
||||
self.ret = ret # Type or None
|
||||
self.virtual = virtual # bool
|
||||
self.const = const # bool
|
||||
self.pure = pure # bool
|
||||
self.static = static # bool
|
||||
self.warn_unused = warn_unused # bool
|
||||
self.force_inline = (force_inline or T) # bool
|
||||
self.inline = inline # bool
|
||||
self.never_inline = never_inline # bool
|
||||
self.typeop = typeop # Type or None
|
||||
self.T = T # Type or None
|
||||
self.only_for_definition = False
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return MethodDecl(
|
||||
self.name,
|
||||
params=copy.deepcopy(self.params, memo),
|
||||
ret=copy.deepcopy(self.ret, memo),
|
||||
virtual=self.virtual,
|
||||
const=self.const,
|
||||
pure=self.pure,
|
||||
static=self.static,
|
||||
warn_unused=self.warn_unused,
|
||||
inline=self.inline,
|
||||
force_inline=self.force_inline,
|
||||
never_inline=self.never_inline,
|
||||
typeop=copy.deepcopy(self.typeop, memo),
|
||||
T=copy.deepcopy(self.T, memo))
|
||||
|
||||
class MethodDefn(Block):
|
||||
def __init__(self, decl):
|
||||
Block.__init__(self)
|
||||
self.decl = decl
|
||||
|
||||
class FunctionDecl(MethodDecl):
|
||||
def __init__(self, name, params=[ ], ret=Type('void'),
|
||||
static=0, warn_unused=0,
|
||||
inline=0, force_inline=0,
|
||||
T=None):
|
||||
MethodDecl.__init__(self, name, params=params, ret=ret,
|
||||
static=static, warn_unused=warn_unused,
|
||||
inline=inline, force_inline=force_inline,
|
||||
T=T)
|
||||
|
||||
class FunctionDefn(MethodDefn):
|
||||
def __init__(self, decl):
|
||||
MethodDefn.__init__(self, decl)
|
||||
|
||||
class ConstructorDecl(MethodDecl):
|
||||
def __init__(self, name, params=[ ], explicit=0, force_inline=0):
|
||||
MethodDecl.__init__(self, name, params=params, ret=None,
|
||||
force_inline=force_inline)
|
||||
self.explicit = explicit
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return ConstructorDecl(self.name,
|
||||
copy.deepcopy(self.params, memo),
|
||||
self.explicit)
|
||||
|
||||
class ConstructorDefn(MethodDefn):
|
||||
def __init__(self, decl, memberinits=[ ]):
|
||||
MethodDefn.__init__(self, decl)
|
||||
self.memberinits = memberinits
|
||||
|
||||
class DestructorDecl(MethodDecl):
|
||||
def __init__(self, name, virtual=0, force_inline=0, inline=0):
|
||||
MethodDecl.__init__(self, name, params=[ ], ret=None,
|
||||
virtual=virtual,
|
||||
force_inline=force_inline, inline=inline)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return DestructorDecl(self.name,
|
||||
virtual=self.virtual,
|
||||
force_inline=self.force_inline,
|
||||
inline=self.inline)
|
||||
|
||||
|
||||
class DestructorDefn(MethodDefn):
|
||||
def __init__(self, decl): MethodDefn.__init__(self, decl)
|
||||
|
||||
##------------------------------
|
||||
# expressions
|
||||
class ExprVar(Node):
|
||||
def __init__(self, name):
|
||||
assert isinstance(name, str)
|
||||
|
||||
Node.__init__(self)
|
||||
self.name = name
|
||||
ExprVar.THIS = ExprVar('this')
|
||||
|
||||
class ExprLiteral(Node):
|
||||
def __init__(self, value, type):
|
||||
'''|type| is a Python format specifier; 'd' for example'''
|
||||
Node.__init__(self)
|
||||
self.value = value
|
||||
self.type = type
|
||||
|
||||
@staticmethod
|
||||
def Int(i): return ExprLiteral(i, 'd')
|
||||
|
||||
@staticmethod
|
||||
def String(s): return ExprLiteral('"'+ s +'"', 's')
|
||||
|
||||
@staticmethod
|
||||
def WString(s): return ExprLiteral('L"'+ s +'"', 's')
|
||||
|
||||
def __str__(self):
|
||||
return ('%'+ self.type)% (self.value)
|
||||
ExprLiteral.ZERO = ExprLiteral.Int(0)
|
||||
ExprLiteral.ONE = ExprLiteral.Int(1)
|
||||
ExprLiteral.NULL = ExprVar('nullptr')
|
||||
ExprLiteral.TRUE = ExprVar('true')
|
||||
ExprLiteral.FALSE = ExprVar('false')
|
||||
|
||||
class ExprPrefixUnop(Node):
|
||||
def __init__(self, expr, op):
|
||||
assert not isinstance(expr, tuple)
|
||||
self.expr = expr
|
||||
self.op = op
|
||||
|
||||
class ExprNot(ExprPrefixUnop):
|
||||
def __init__(self, expr):
|
||||
ExprPrefixUnop.__init__(self, expr, '!')
|
||||
|
||||
class ExprAddrOf(ExprPrefixUnop):
|
||||
def __init__(self, expr):
|
||||
ExprPrefixUnop.__init__(self, expr, '&')
|
||||
|
||||
class ExprDeref(ExprPrefixUnop):
|
||||
def __init__(self, expr):
|
||||
ExprPrefixUnop.__init__(self, expr, '*')
|
||||
|
||||
class ExprCast(Node):
|
||||
def __init__(self, expr, type,
|
||||
dynamic=0, static=0, reinterpret=0, const=0, C=0):
|
||||
assert 1 == reduce(lambda a, x: a+x, [ dynamic, static, reinterpret, const, C ])
|
||||
|
||||
Node.__init__(self)
|
||||
self.expr = expr
|
||||
self.type = type
|
||||
self.dynamic = dynamic
|
||||
self.static = static
|
||||
self.reinterpret = reinterpret
|
||||
self.const = const
|
||||
self.C = C
|
||||
|
||||
class ExprBinary(Node):
|
||||
def __init__(self, left, op, right):
|
||||
Node.__init__(self)
|
||||
self.left = left
|
||||
self.op = op
|
||||
self.right = right
|
||||
|
||||
class ExprConditional(Node):
|
||||
def __init__(self, cond, ife, elsee):
|
||||
Node.__init__(self)
|
||||
self.cond = cond
|
||||
self.ife = ife
|
||||
self.elsee = elsee
|
||||
|
||||
class ExprIndex(Node):
|
||||
def __init__(self, arr, idx):
|
||||
Node.__init__(self)
|
||||
self.arr = arr
|
||||
self.idx = idx
|
||||
|
||||
class ExprSelect(Node):
|
||||
def __init__(self, obj, op, field):
|
||||
assert obj and op and field
|
||||
assert not isinstance(obj, str)
|
||||
assert isinstance(field, str)
|
||||
|
||||
Node.__init__(self)
|
||||
self.obj = obj
|
||||
self.op = op
|
||||
self.field = field
|
||||
|
||||
class ExprAssn(Node):
|
||||
def __init__(self, lhs, rhs, op='='):
|
||||
Node.__init__(self)
|
||||
self.lhs = lhs
|
||||
self.op = op
|
||||
self.rhs = rhs
|
||||
|
||||
class ExprCall(Node):
|
||||
def __init__(self, func, args=[ ]):
|
||||
assert hasattr(func, 'accept')
|
||||
assert isinstance(args, list)
|
||||
for arg in args: assert arg and not isinstance(arg, str)
|
||||
|
||||
Node.__init__(self)
|
||||
self.func = func
|
||||
self.args = args
|
||||
|
||||
class ExprMove(ExprCall):
|
||||
def __init__(self, arg):
|
||||
ExprCall.__init__(self, ExprVar("mozilla::Move"), args=[arg])
|
||||
|
||||
class ExprNew(Node):
|
||||
# XXX taking some poetic license ...
|
||||
def __init__(self, ctype, args=[ ], newargs=None):
|
||||
assert not (ctype.const or ctype.ref)
|
||||
|
||||
Node.__init__(self)
|
||||
self.ctype = ctype
|
||||
self.args = args
|
||||
self.newargs = newargs
|
||||
|
||||
class ExprDelete(Node):
|
||||
def __init__(self, obj):
|
||||
Node.__init__(self)
|
||||
self.obj = obj
|
||||
|
||||
class ExprMemberInit(ExprCall):
|
||||
def __init__(self, member, args=[ ]):
|
||||
ExprCall.__init__(self, member, args)
|
||||
|
||||
class ExprSizeof(ExprCall):
|
||||
def __init__(self, t):
|
||||
ExprCall.__init__(self, ExprVar('sizeof'), [ t ])
|
||||
|
||||
##------------------------------
|
||||
# statements etc.
|
||||
class StmtBlock(Block):
|
||||
def __init__(self, stmts=[ ]):
|
||||
Block.__init__(self)
|
||||
self.addstmts(stmts)
|
||||
|
||||
class StmtDecl(Node):
|
||||
def __init__(self, decl, init=None, initargs=None):
|
||||
assert not (init and initargs)
|
||||
assert not isinstance(init, str) # easy to confuse with Decl
|
||||
assert not isinstance(init, list)
|
||||
assert not isinstance(decl, tuple)
|
||||
|
||||
Node.__init__(self)
|
||||
self.decl = decl
|
||||
self.init = init
|
||||
self.initargs = initargs
|
||||
|
||||
class Label(Node):
|
||||
def __init__(self, name):
|
||||
Node.__init__(self)
|
||||
self.name = name
|
||||
Label.PUBLIC = Label('public')
|
||||
Label.PROTECTED = Label('protected')
|
||||
Label.PRIVATE = Label('private')
|
||||
|
||||
class CaseLabel(Node):
|
||||
def __init__(self, name):
|
||||
Node.__init__(self)
|
||||
self.name = name
|
||||
|
||||
class DefaultLabel(Node):
|
||||
def __init__(self):
|
||||
Node.__init__(self)
|
||||
|
||||
class StmtIf(Node):
|
||||
def __init__(self, cond):
|
||||
Node.__init__(self)
|
||||
self.cond = cond
|
||||
self.ifb = Block()
|
||||
self.elseb = None
|
||||
|
||||
def addifstmt(self, stmt):
|
||||
self.ifb.addstmt(stmt)
|
||||
|
||||
def addifstmts(self, stmts):
|
||||
self.ifb.addstmts(stmts)
|
||||
|
||||
def addelsestmt(self, stmt):
|
||||
if self.elseb is None: self.elseb = Block()
|
||||
self.elseb.addstmt(stmt)
|
||||
|
||||
def addelsestmts(self, stmts):
|
||||
if self.elseb is None: self.elseb = Block()
|
||||
self.elseb.addstmts(stmts)
|
||||
|
||||
class StmtFor(Block):
|
||||
def __init__(self, init=None, cond=None, update=None):
|
||||
Block.__init__(self)
|
||||
self.init = init
|
||||
self.cond = cond
|
||||
self.update = update
|
||||
|
||||
class StmtRangedFor(Block):
|
||||
def __init__(self, var, iteree):
|
||||
assert isinstance(var, ExprVar)
|
||||
assert iteree
|
||||
|
||||
Block.__init__(self)
|
||||
self.var = var
|
||||
self.iteree = iteree
|
||||
|
||||
class StmtSwitch(Block):
|
||||
def __init__(self, expr):
|
||||
Block.__init__(self)
|
||||
self.expr = expr
|
||||
self.nr_cases = 0
|
||||
|
||||
def addcase(self, case, block):
|
||||
'''NOTE: |case| is not checked for uniqueness'''
|
||||
assert not isinstance(case, str)
|
||||
assert (isinstance(block, StmtBreak)
|
||||
or isinstance(block, StmtReturn)
|
||||
or isinstance(block, StmtSwitch)
|
||||
or (hasattr(block, 'stmts')
|
||||
and (isinstance(block.stmts[-1], StmtBreak)
|
||||
or isinstance(block.stmts[-1], StmtReturn))))
|
||||
self.addstmt(case)
|
||||
self.addstmt(block)
|
||||
self.nr_cases += 1
|
||||
|
||||
def addfallthrough(self, case):
|
||||
self.addstmt(case)
|
||||
self.nr_cases += 1
|
||||
|
||||
class StmtBreak(Node):
|
||||
def __init__(self):
|
||||
Node.__init__(self)
|
||||
|
||||
class StmtExpr(Node):
|
||||
def __init__(self, expr):
|
||||
assert expr is not None
|
||||
|
||||
Node.__init__(self)
|
||||
self.expr = expr
|
||||
|
||||
class StmtReturn(Node):
|
||||
def __init__(self, expr=None):
|
||||
Node.__init__(self)
|
||||
self.expr = expr
|
||||
|
||||
StmtReturn.TRUE = StmtReturn(ExprLiteral.TRUE)
|
||||
StmtReturn.FALSE = StmtReturn(ExprLiteral.FALSE)
|
||||
520
ipc/ipdl/ipdl/cxx/cgen.py
Normal file
520
ipc/ipdl/ipdl/cxx/cgen.py
Normal file
|
|
@ -0,0 +1,520 @@
|
|||
# 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/.
|
||||
|
||||
import sys
|
||||
|
||||
from ipdl.cgen import CodePrinter
|
||||
from ipdl.cxx.ast import TypeArray, Visitor
|
||||
|
||||
class CxxCodeGen(CodePrinter, Visitor):
|
||||
def __init__(self, outf=sys.stdout, indentCols=4):
|
||||
CodePrinter.__init__(self, outf, indentCols)
|
||||
|
||||
def cgen(self, cxxfile):
|
||||
cxxfile.accept(self)
|
||||
|
||||
def visitWhitespace(self, ws):
|
||||
if ws.indent:
|
||||
self.printdent('')
|
||||
self.write(ws.ws)
|
||||
|
||||
def visitCppDirective(self, cd):
|
||||
if cd.rest:
|
||||
self.println('#%s %s'% (cd.directive, cd.rest))
|
||||
else:
|
||||
self.println('#%s'% (cd.directive))
|
||||
|
||||
def visitNamespace(self, ns):
|
||||
self.println('namespace '+ ns.name +' {')
|
||||
self.visitBlock(ns)
|
||||
self.println('} // namespace '+ ns.name)
|
||||
|
||||
def visitType(self, t):
|
||||
if t.const:
|
||||
self.write('const ')
|
||||
|
||||
self.write(t.name)
|
||||
|
||||
if t.T is not None:
|
||||
self.write('<')
|
||||
t.T.accept(self)
|
||||
self.write('>')
|
||||
|
||||
ts = ''
|
||||
if t.ptr: ts += '*'
|
||||
elif t.ptrconst: ts += '* const'
|
||||
elif t.ptrptr: ts += '**'
|
||||
elif t.ptrconstptr: ts += '* const*'
|
||||
|
||||
ts += '&' * t.ref
|
||||
|
||||
self.write(ts)
|
||||
|
||||
def visitTypeEnum(self, te):
|
||||
self.write('enum')
|
||||
if te.name:
|
||||
self.write(' '+ te.name)
|
||||
self.println(' {')
|
||||
|
||||
self.indent()
|
||||
nids = len(te.idnums)
|
||||
for i, (id, num) in enumerate(te.idnums):
|
||||
self.printdent(id)
|
||||
if num:
|
||||
self.write(' = '+ str(num))
|
||||
if i != (nids-1):
|
||||
self.write(',')
|
||||
self.println()
|
||||
self.dedent()
|
||||
self.printdent('}')
|
||||
|
||||
def visitTypeUnion(self, u):
|
||||
self.write('union')
|
||||
if u.name:
|
||||
self.write(' '+ u.name)
|
||||
self.println(' {')
|
||||
|
||||
self.indent()
|
||||
for decl in u.components:
|
||||
self.printdent()
|
||||
decl.accept(self)
|
||||
self.println(';')
|
||||
self.dedent()
|
||||
|
||||
self.printdent('}')
|
||||
|
||||
|
||||
def visitTypedef(self, td):
|
||||
if td.templateargs:
|
||||
formals = ', '.join([ 'class ' + T for T in td.templateargs ])
|
||||
args = ', '.join(td.templateargs)
|
||||
self.printdent('template<' + formals + '> using ' + td.totypename + ' = ')
|
||||
td.fromtype.accept(self)
|
||||
self.println('<' + args + '>;')
|
||||
else:
|
||||
self.printdent('typedef ')
|
||||
td.fromtype.accept(self)
|
||||
self.println(' '+ td.totypename +';')
|
||||
|
||||
def visitUsing(self, us):
|
||||
self.printdent('using ')
|
||||
us.type.accept(self)
|
||||
self.println(';')
|
||||
|
||||
def visitForwardDecl(self, fd):
|
||||
if fd.cls: self.printdent('class ')
|
||||
elif fd.struct: self.printdent('struct ')
|
||||
self.write(str(fd.pqname))
|
||||
self.println(';')
|
||||
|
||||
def visitDecl(self, d):
|
||||
# C-syntax arrays make code generation much more annoying
|
||||
if isinstance(d.type, TypeArray):
|
||||
d.type.basetype.accept(self)
|
||||
else:
|
||||
d.type.accept(self)
|
||||
|
||||
if d.name:
|
||||
self.write(' '+ d.name)
|
||||
|
||||
if isinstance(d.type, TypeArray):
|
||||
self.write('[')
|
||||
d.type.nmemb.accept(self)
|
||||
self.write(']')
|
||||
|
||||
def visitParam(self, p):
|
||||
self.visitDecl(p)
|
||||
if p.default is not None:
|
||||
self.write(' = ')
|
||||
p.default.accept(self)
|
||||
|
||||
def visitClass(self, c):
|
||||
if c.specializes is not None:
|
||||
self.printdentln('template<>')
|
||||
|
||||
if c.struct:
|
||||
self.printdent('struct')
|
||||
else:
|
||||
self.printdent('class')
|
||||
self.write(' '+ c.name)
|
||||
if c.final:
|
||||
self.write(' final')
|
||||
|
||||
if c.specializes is not None:
|
||||
self.write(' <')
|
||||
c.specializes.accept(self)
|
||||
self.write('>')
|
||||
|
||||
ninh = len(c.inherits)
|
||||
if 0 < ninh:
|
||||
self.println(' :')
|
||||
self.indent()
|
||||
for i, inherit in enumerate(c.inherits):
|
||||
self.printdent()
|
||||
inherit.accept(self)
|
||||
if i != (ninh - 1):
|
||||
self.println(',')
|
||||
self.dedent()
|
||||
self.println()
|
||||
|
||||
self.printdentln('{')
|
||||
self.indent()
|
||||
|
||||
self.visitBlock(c)
|
||||
|
||||
self.dedent()
|
||||
self.printdentln('};')
|
||||
|
||||
def visitInherit(self, inh):
|
||||
self.write(inh.viz +' ')
|
||||
inh.type.accept(self)
|
||||
|
||||
def visitFriendClassDecl(self, fcd):
|
||||
self.printdentln('friend class '+ fcd.friend +';')
|
||||
|
||||
|
||||
def visitMethodDecl(self, md):
|
||||
assert not (md.static and md.virtual)
|
||||
|
||||
if md.T:
|
||||
self.write('template<')
|
||||
self.write('typename ')
|
||||
md.T.accept(self)
|
||||
self.println('>')
|
||||
self.printdent()
|
||||
|
||||
if md.warn_unused:
|
||||
self.write('MOZ_MUST_USE ')
|
||||
if md.inline:
|
||||
self.write('inline ')
|
||||
if md.never_inline:
|
||||
self.write('MOZ_NEVER_INLINE ')
|
||||
if md.static:
|
||||
self.write('static ')
|
||||
if md.virtual:
|
||||
self.write('virtual ')
|
||||
if md.ret:
|
||||
if md.only_for_definition:
|
||||
self.write('auto ')
|
||||
else:
|
||||
md.ret.accept(self)
|
||||
self.println()
|
||||
self.printdent()
|
||||
if md.typeop is not None:
|
||||
self.write('operator ')
|
||||
md.typeop.accept(self)
|
||||
else:
|
||||
self.write(md.name)
|
||||
|
||||
self.write('(')
|
||||
self.writeDeclList(md.params)
|
||||
self.write(')')
|
||||
|
||||
if md.const:
|
||||
self.write(' const')
|
||||
if md.ret and md.only_for_definition:
|
||||
self.write(' -> ')
|
||||
md.ret.accept(self)
|
||||
if md.pure:
|
||||
self.write(' = 0')
|
||||
|
||||
|
||||
def visitMethodDefn(self, md):
|
||||
if md.decl.pure:
|
||||
return
|
||||
|
||||
self.printdent()
|
||||
md.decl.accept(self)
|
||||
self.println()
|
||||
|
||||
self.printdentln('{')
|
||||
self.indent()
|
||||
self.visitBlock(md)
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
|
||||
def visitConstructorDecl(self, cd):
|
||||
if cd.explicit:
|
||||
self.write('explicit ')
|
||||
else:
|
||||
self.write('MOZ_IMPLICIT ')
|
||||
self.visitMethodDecl(cd)
|
||||
|
||||
def visitConstructorDefn(self, cd):
|
||||
self.printdent()
|
||||
cd.decl.accept(self)
|
||||
if len(cd.memberinits):
|
||||
self.println(' :')
|
||||
self.indent()
|
||||
ninits = len(cd.memberinits)
|
||||
for i, init in enumerate(cd.memberinits):
|
||||
self.printdent()
|
||||
init.accept(self)
|
||||
if i != (ninits-1):
|
||||
self.println(',')
|
||||
self.dedent()
|
||||
self.println()
|
||||
|
||||
self.printdentln('{')
|
||||
self.indent()
|
||||
|
||||
self.visitBlock(cd)
|
||||
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
|
||||
def visitDestructorDecl(self, dd):
|
||||
if dd.inline:
|
||||
self.write('inline ')
|
||||
if dd.virtual:
|
||||
self.write('virtual ')
|
||||
|
||||
# hack alert
|
||||
parts = dd.name.split('::')
|
||||
parts[-1] = '~'+ parts[-1]
|
||||
|
||||
self.write('::'.join(parts) +'()')
|
||||
|
||||
def visitDestructorDefn(self, dd):
|
||||
self.printdent()
|
||||
dd.decl.accept(self)
|
||||
self.println()
|
||||
|
||||
self.printdentln('{')
|
||||
self.indent()
|
||||
|
||||
self.visitBlock(dd)
|
||||
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
|
||||
def visitExprLiteral(self, el):
|
||||
self.write(str(el))
|
||||
|
||||
def visitExprVar(self, ev):
|
||||
self.write(ev.name)
|
||||
|
||||
def visitExprPrefixUnop(self, e):
|
||||
self.write('(')
|
||||
self.write(e.op)
|
||||
self.write('(')
|
||||
e.expr.accept(self)
|
||||
self.write(')')
|
||||
self.write(')')
|
||||
|
||||
def visitExprCast(self, c):
|
||||
pfx, sfx = '', ''
|
||||
if c.dynamic: pfx, sfx = 'dynamic_cast<', '>'
|
||||
elif c.static: pfx, sfx = 'static_cast<', '>'
|
||||
elif c.reinterpret: pfx, sfx = 'reinterpret_cast<', '>'
|
||||
elif c.const: pfx, sfx = 'const_cast<', '>'
|
||||
elif c.C: pfx, sfx = '(', ')'
|
||||
self.write(pfx)
|
||||
c.type.accept(self)
|
||||
self.write(sfx +'(')
|
||||
c.expr.accept(self)
|
||||
self.write(')')
|
||||
|
||||
def visitExprBinary(self, e):
|
||||
self.write('(')
|
||||
e.left.accept(self)
|
||||
self.write(') '+ e.op +' (')
|
||||
e.right.accept(self)
|
||||
self.write(')')
|
||||
|
||||
def visitExprConditional(self, c):
|
||||
self.write('(')
|
||||
c.cond.accept(self)
|
||||
self.write(' ? ')
|
||||
c.ife.accept(self)
|
||||
self.write(' : ')
|
||||
c.elsee.accept(self)
|
||||
self.write(')')
|
||||
|
||||
def visitExprIndex(self, ei):
|
||||
ei.arr.accept(self)
|
||||
self.write('[')
|
||||
ei.idx.accept(self)
|
||||
self.write(']')
|
||||
|
||||
def visitExprSelect(self, es):
|
||||
self.write('(')
|
||||
es.obj.accept(self)
|
||||
self.write(')')
|
||||
self.write(es.op + es.field)
|
||||
|
||||
def visitExprAssn(self, ea):
|
||||
ea.lhs.accept(self)
|
||||
self.write(' '+ ea.op +' ')
|
||||
ea.rhs.accept(self)
|
||||
|
||||
def visitExprCall(self, ec):
|
||||
ec.func.accept(self)
|
||||
self.write('(')
|
||||
self.writeExprList(ec.args)
|
||||
self.write(')')
|
||||
|
||||
def visitExprMove(self, em):
|
||||
self.visitExprCall(em)
|
||||
|
||||
def visitExprNew(self, en):
|
||||
self.write('new ')
|
||||
if en.newargs is not None:
|
||||
self.write('(')
|
||||
self.writeExprList(en.newargs)
|
||||
self.write(') ')
|
||||
en.ctype.accept(self)
|
||||
if en.args is not None:
|
||||
self.write('(')
|
||||
self.writeExprList(en.args)
|
||||
self.write(')')
|
||||
|
||||
def visitExprDelete(self, ed):
|
||||
self.write('delete ')
|
||||
ed.obj.accept(self)
|
||||
|
||||
|
||||
def visitStmtBlock(self, b):
|
||||
self.printdentln('{')
|
||||
self.indent()
|
||||
self.visitBlock(b)
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
def visitLabel(self, label):
|
||||
self.dedent() # better not be at global scope ...
|
||||
self.printdentln(label.name +':')
|
||||
self.indent()
|
||||
|
||||
def visitCaseLabel(self, cl):
|
||||
self.dedent()
|
||||
self.printdentln('case '+ cl.name +':')
|
||||
self.indent()
|
||||
|
||||
def visitDefaultLabel(self, dl):
|
||||
self.dedent()
|
||||
self.printdentln('default:')
|
||||
self.indent()
|
||||
|
||||
|
||||
def visitStmtIf(self, si):
|
||||
self.printdent('if (')
|
||||
si.cond.accept(self)
|
||||
self.println(') {')
|
||||
self.indent()
|
||||
si.ifb.accept(self)
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
if si.elseb is not None:
|
||||
self.printdentln('else {')
|
||||
self.indent()
|
||||
si.elseb.accept(self)
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
|
||||
def visitStmtFor(self, sf):
|
||||
self.printdent('for (')
|
||||
if sf.init is not None:
|
||||
sf.init.accept(self)
|
||||
self.write('; ')
|
||||
if sf.cond is not None:
|
||||
sf.cond.accept(self)
|
||||
self.write('; ')
|
||||
if sf.update is not None:
|
||||
sf.update.accept(self)
|
||||
self.println(') {')
|
||||
|
||||
self.indent()
|
||||
self.visitBlock(sf)
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
|
||||
def visitStmtRangedFor(self, rf):
|
||||
self.printdent('for (auto& ')
|
||||
rf.var.accept(self)
|
||||
self.write(' : ')
|
||||
rf.iteree.accept(self)
|
||||
self.println(') {')
|
||||
|
||||
self.indent()
|
||||
self.visitBlock(rf)
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
|
||||
def visitStmtSwitch(self, sw):
|
||||
self.printdent('switch (')
|
||||
sw.expr.accept(self)
|
||||
self.println(') {')
|
||||
self.indent()
|
||||
self.visitBlock(sw)
|
||||
self.dedent()
|
||||
self.printdentln('}')
|
||||
|
||||
def visitStmtBreak(self, sb):
|
||||
self.printdentln('break;')
|
||||
|
||||
|
||||
def visitStmtDecl(self, sd):
|
||||
self.printdent()
|
||||
sd.decl.accept(self)
|
||||
if sd.initargs is not None:
|
||||
self.write('(')
|
||||
self.writeDeclList(sd.initargs)
|
||||
self.write(')')
|
||||
if sd.init is not None:
|
||||
self.write(' = ')
|
||||
sd.init.accept(self)
|
||||
self.println(';')
|
||||
|
||||
|
||||
def visitStmtExpr(self, se):
|
||||
self.printdent()
|
||||
se.expr.accept(self)
|
||||
self.println(';')
|
||||
|
||||
|
||||
def visitStmtReturn(self, sr):
|
||||
self.printdent('return')
|
||||
if sr.expr:
|
||||
self.write (' ')
|
||||
sr.expr.accept(self)
|
||||
self.println(';')
|
||||
|
||||
|
||||
def writeDeclList(self, decls):
|
||||
# FIXME/cjones: try to do nice formatting of these guys
|
||||
|
||||
ndecls = len(decls)
|
||||
if 0 == ndecls:
|
||||
return
|
||||
elif 1 == ndecls:
|
||||
decls[0].accept(self)
|
||||
return
|
||||
|
||||
self.indent()
|
||||
self.indent()
|
||||
for i, decl in enumerate(decls):
|
||||
self.println()
|
||||
self.printdent()
|
||||
decl.accept(self)
|
||||
if i != (ndecls-1):
|
||||
self.write(',')
|
||||
self.dedent()
|
||||
self.dedent()
|
||||
|
||||
def writeExprList(self, exprs):
|
||||
# FIXME/cjones: try to do nice formatting and share code with
|
||||
# writeDeclList()
|
||||
nexprs = len(exprs)
|
||||
for i, expr in enumerate(exprs):
|
||||
expr.accept(self)
|
||||
if i != (nexprs-1):
|
||||
self.write(', ')
|
||||
4822
ipc/ipdl/ipdl/lower.py
Normal file
4822
ipc/ipdl/ipdl/lower.py
Normal file
File diff suppressed because it is too large
Load diff
807
ipc/ipdl/ipdl/parser.py
Normal file
807
ipc/ipdl/ipdl/parser.py
Normal file
|
|
@ -0,0 +1,807 @@
|
|||
# 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/.
|
||||
|
||||
import os, sys
|
||||
from ply import lex, yacc
|
||||
|
||||
from ipdl.ast import *
|
||||
|
||||
def _getcallerpath():
|
||||
'''Return the absolute path of the file containing the code that
|
||||
**CALLED** this function.'''
|
||||
return os.path.abspath(sys._getframe(1).f_code.co_filename)
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
|
||||
class ParseError(Exception):
|
||||
def __init__(self, loc, fmt, *args):
|
||||
self.loc = loc
|
||||
self.error = ('%s%s: error: %s'% (
|
||||
Parser.includeStackString(), loc, fmt)) % args
|
||||
def __str__(self):
|
||||
return self.error
|
||||
|
||||
def _safeLinenoValue(t):
|
||||
lineno, value = 0, '???'
|
||||
if hasattr(t, 'lineno'): lineno = t.lineno
|
||||
if hasattr(t, 'value'): value = t.value
|
||||
return lineno, value
|
||||
|
||||
def _error(loc, fmt, *args):
|
||||
raise ParseError(loc, fmt, *args)
|
||||
|
||||
class Parser:
|
||||
# when we reach an |include [protocol] foo;| statement, we need to
|
||||
# save the current parser state and create a new one. this "stack" is
|
||||
# where that state is saved
|
||||
#
|
||||
# there is one Parser per file
|
||||
current = None
|
||||
parseStack = [ ]
|
||||
parsed = { }
|
||||
|
||||
def __init__(self, type, name, debug=0):
|
||||
assert type and name
|
||||
self.type = type
|
||||
self.debug = debug
|
||||
self.filename = None
|
||||
self.includedirs = None
|
||||
self.loc = None # not always up to date
|
||||
self.lexer = None
|
||||
self.parser = None
|
||||
self.tu = TranslationUnit(type, name)
|
||||
self.direction = None
|
||||
self.errout = None
|
||||
|
||||
def parse(self, input, filename, includedirs, errout):
|
||||
assert os.path.isabs(filename)
|
||||
|
||||
if filename in Parser.parsed:
|
||||
return Parser.parsed[filename].tu
|
||||
|
||||
self.lexer = lex.lex(debug=self.debug,
|
||||
optimize=not self.debug,
|
||||
lextab="ipdl_lextab")
|
||||
self.parser = yacc.yacc(debug=self.debug,
|
||||
optimize=not self.debug,
|
||||
tabmodule="ipdl_yacctab")
|
||||
self.filename = filename
|
||||
self.includedirs = includedirs
|
||||
self.tu.filename = filename
|
||||
self.errout = errout
|
||||
|
||||
Parser.parsed[filename] = self
|
||||
Parser.parseStack.append(Parser.current)
|
||||
Parser.current = self
|
||||
|
||||
try:
|
||||
ast = self.parser.parse(input=input, lexer=self.lexer,
|
||||
debug=self.debug)
|
||||
except ParseError, p:
|
||||
print >>errout, p
|
||||
return None
|
||||
|
||||
Parser.current = Parser.parseStack.pop()
|
||||
return ast
|
||||
|
||||
def resolveIncludePath(self, filepath):
|
||||
'''Return the absolute path from which the possibly partial
|
||||
|filepath| should be read, or |None| if |filepath| cannot be located.'''
|
||||
for incdir in self.includedirs +[ '' ]:
|
||||
realpath = os.path.join(incdir, filepath)
|
||||
if os.path.isfile(realpath):
|
||||
return os.path.abspath(realpath)
|
||||
return None
|
||||
|
||||
# returns a GCC-style string representation of the include stack.
|
||||
# e.g.,
|
||||
# in file included from 'foo.ipdl', line 120:
|
||||
# in file included from 'bar.ipd', line 12:
|
||||
# which can be printed above a proper error message or warning
|
||||
@staticmethod
|
||||
def includeStackString():
|
||||
s = ''
|
||||
for parse in Parser.parseStack[1:]:
|
||||
s += " in file included from `%s', line %d:\n"% (
|
||||
parse.loc.filename, parse.loc.lineno)
|
||||
return s
|
||||
|
||||
def locFromTok(p, num):
|
||||
return Loc(Parser.current.filename, p.lineno(num))
|
||||
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
|
||||
reserved = set((
|
||||
'answer',
|
||||
'as',
|
||||
'async',
|
||||
'both',
|
||||
'bridges',
|
||||
'call',
|
||||
'child',
|
||||
'class',
|
||||
'compress',
|
||||
'compressall',
|
||||
'__delete__',
|
||||
'delete', # reserve 'delete' to prevent its use
|
||||
'from',
|
||||
'goto',
|
||||
'include',
|
||||
'intr',
|
||||
'manager',
|
||||
'manages',
|
||||
'namespace',
|
||||
'nested',
|
||||
'nullable',
|
||||
'opens',
|
||||
'or',
|
||||
'parent',
|
||||
'prio',
|
||||
'protocol',
|
||||
'recv',
|
||||
'returns',
|
||||
'send',
|
||||
'spawns',
|
||||
'start',
|
||||
'state',
|
||||
'struct',
|
||||
'sync',
|
||||
'union',
|
||||
'upto',
|
||||
'using',
|
||||
'verify'))
|
||||
tokens = [
|
||||
'COLONCOLON', 'ID', 'STRING',
|
||||
] + [ r.upper() for r in reserved ]
|
||||
|
||||
t_COLONCOLON = '::'
|
||||
|
||||
literals = '(){}[]<>;:,~'
|
||||
t_ignore = ' \f\t\v'
|
||||
|
||||
def t_linecomment(t):
|
||||
r'//[^\n]*'
|
||||
|
||||
def t_multilinecomment(t):
|
||||
r'/\*(\n|.)*?\*/'
|
||||
t.lexer.lineno += t.value.count('\n')
|
||||
|
||||
def t_NL(t):
|
||||
r'(?:\r\n|\n|\n)+'
|
||||
t.lexer.lineno += len(t.value)
|
||||
|
||||
def t_ID(t):
|
||||
r'[a-zA-Z_][a-zA-Z0-9_]*'
|
||||
if t.value in reserved:
|
||||
t.type = t.value.upper()
|
||||
return t
|
||||
|
||||
def t_STRING(t):
|
||||
r'"[^"\n]*"'
|
||||
t.value = t.value[1:-1]
|
||||
return t
|
||||
|
||||
def t_error(t):
|
||||
_error(Loc(Parser.current.filename, t.lineno),
|
||||
'lexically invalid characters `%s', t.value)
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
|
||||
def p_TranslationUnit(p):
|
||||
"""TranslationUnit : Preamble NamespacedStuff"""
|
||||
tu = Parser.current.tu
|
||||
tu.loc = Loc(tu.filename)
|
||||
for stmt in p[1]:
|
||||
if isinstance(stmt, CxxInclude):
|
||||
tu.addCxxInclude(stmt)
|
||||
elif isinstance(stmt, Include):
|
||||
tu.addInclude(stmt)
|
||||
elif isinstance(stmt, UsingStmt):
|
||||
tu.addUsingStmt(stmt)
|
||||
else:
|
||||
assert 0
|
||||
|
||||
for thing in p[2]:
|
||||
if isinstance(thing, StructDecl):
|
||||
tu.addStructDecl(thing)
|
||||
elif isinstance(thing, UnionDecl):
|
||||
tu.addUnionDecl(thing)
|
||||
elif isinstance(thing, Protocol):
|
||||
if tu.protocol is not None:
|
||||
_error(thing.loc, "only one protocol definition per file")
|
||||
tu.protocol = thing
|
||||
else:
|
||||
assert(0)
|
||||
|
||||
# The "canonical" namespace of the tu, what it's considered to be
|
||||
# in for the purposes of C++: |#include "foo/bar/TU.h"|
|
||||
if tu.protocol:
|
||||
assert tu.filetype == 'protocol'
|
||||
tu.namespaces = tu.protocol.namespaces
|
||||
tu.name = tu.protocol.name
|
||||
else:
|
||||
assert tu.filetype == 'header'
|
||||
# There's not really a canonical "thing" in headers. So
|
||||
# somewhat arbitrarily use the namespace of the last
|
||||
# interesting thing that was declared.
|
||||
for thing in reversed(tu.structsAndUnions):
|
||||
tu.namespaces = thing.namespaces
|
||||
break
|
||||
|
||||
p[0] = tu
|
||||
|
||||
##--------------------
|
||||
## Preamble
|
||||
def p_Preamble(p):
|
||||
"""Preamble : Preamble PreambleStmt ';'
|
||||
|"""
|
||||
if 1 == len(p):
|
||||
p[0] = [ ]
|
||||
else:
|
||||
p[1].append(p[2])
|
||||
p[0] = p[1]
|
||||
|
||||
def p_PreambleStmt(p):
|
||||
"""PreambleStmt : CxxIncludeStmt
|
||||
| IncludeStmt
|
||||
| UsingStmt"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_CxxIncludeStmt(p):
|
||||
"""CxxIncludeStmt : INCLUDE STRING"""
|
||||
p[0] = CxxInclude(locFromTok(p, 1), p[2])
|
||||
|
||||
def p_IncludeStmt(p):
|
||||
"""IncludeStmt : INCLUDE PROTOCOL ID
|
||||
| INCLUDE ID"""
|
||||
loc = locFromTok(p, 1)
|
||||
|
||||
Parser.current.loc = loc
|
||||
if 4 == len(p):
|
||||
id = p[3]
|
||||
type = 'protocol'
|
||||
else:
|
||||
id = p[2]
|
||||
type = 'header'
|
||||
inc = Include(loc, type, id)
|
||||
|
||||
path = Parser.current.resolveIncludePath(inc.file)
|
||||
if path is None:
|
||||
raise ParseError(loc, "can't locate include file `%s'"% (
|
||||
inc.file))
|
||||
|
||||
inc.tu = Parser(type, id).parse(open(path).read(), path, Parser.current.includedirs, Parser.current.errout)
|
||||
p[0] = inc
|
||||
|
||||
def p_UsingStmt(p):
|
||||
"""UsingStmt : USING CxxType FROM STRING
|
||||
| USING CLASS CxxType FROM STRING
|
||||
| USING STRUCT CxxType FROM STRING"""
|
||||
if 6 == len(p):
|
||||
header = p[5]
|
||||
elif 5 == len(p):
|
||||
header = p[4]
|
||||
else:
|
||||
header = None
|
||||
if 6 == len(p):
|
||||
kind = p[2]
|
||||
else:
|
||||
kind = None
|
||||
if 6 == len(p):
|
||||
cxxtype = p[3]
|
||||
else:
|
||||
cxxtype = p[2]
|
||||
p[0] = UsingStmt(locFromTok(p, 1), cxxtype, header, kind)
|
||||
|
||||
##--------------------
|
||||
## Namespaced stuff
|
||||
def p_NamespacedStuff(p):
|
||||
"""NamespacedStuff : NamespacedStuff NamespaceThing
|
||||
| NamespaceThing"""
|
||||
if 2 == len(p):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[1].extend(p[2])
|
||||
p[0] = p[1]
|
||||
|
||||
def p_NamespaceThing(p):
|
||||
"""NamespaceThing : NAMESPACE ID '{' NamespacedStuff '}'
|
||||
| StructDecl
|
||||
| UnionDecl
|
||||
| ProtocolDefn"""
|
||||
if 2 == len(p):
|
||||
p[0] = [ p[1] ]
|
||||
else:
|
||||
for thing in p[4]:
|
||||
thing.addOuterNamespace(Namespace(locFromTok(p, 1), p[2]))
|
||||
p[0] = p[4]
|
||||
|
||||
def p_StructDecl(p):
|
||||
"""StructDecl : STRUCT ID '{' StructFields '}' ';'
|
||||
| STRUCT ID '{' '}' ';'"""
|
||||
if 7 == len(p):
|
||||
p[0] = StructDecl(locFromTok(p, 1), p[2], p[4])
|
||||
else:
|
||||
p[0] = StructDecl(locFromTok(p, 1), p[2], [ ])
|
||||
|
||||
def p_StructFields(p):
|
||||
"""StructFields : StructFields StructField ';'
|
||||
| StructField ';'"""
|
||||
if 3 == len(p):
|
||||
p[0] = [ p[1] ]
|
||||
else:
|
||||
p[1].append(p[2])
|
||||
p[0] = p[1]
|
||||
|
||||
def p_StructField(p):
|
||||
"""StructField : Type ID"""
|
||||
p[0] = StructField(locFromTok(p, 1), p[1], p[2])
|
||||
|
||||
def p_UnionDecl(p):
|
||||
"""UnionDecl : UNION ID '{' ComponentTypes '}' ';'"""
|
||||
p[0] = UnionDecl(locFromTok(p, 1), p[2], p[4])
|
||||
|
||||
def p_ComponentTypes(p):
|
||||
"""ComponentTypes : ComponentTypes Type ';'
|
||||
| Type ';'"""
|
||||
if 3 == len(p):
|
||||
p[0] = [ p[1] ]
|
||||
else:
|
||||
p[1].append(p[2])
|
||||
p[0] = p[1]
|
||||
|
||||
def p_ProtocolDefn(p):
|
||||
"""ProtocolDefn : OptionalProtocolSendSemanticsQual PROTOCOL ID '{' ProtocolBody '}' ';'"""
|
||||
protocol = p[5]
|
||||
protocol.loc = locFromTok(p, 2)
|
||||
protocol.name = p[3]
|
||||
protocol.nestedRange = p[1][0]
|
||||
protocol.sendSemantics = p[1][1]
|
||||
p[0] = protocol
|
||||
|
||||
if Parser.current.type == 'header':
|
||||
_error(protocol.loc, 'can\'t define a protocol in a header. Do it in a protocol spec instead.')
|
||||
|
||||
|
||||
def p_ProtocolBody(p):
|
||||
"""ProtocolBody : SpawnsStmtsOpt"""
|
||||
p[0] = p[1]
|
||||
|
||||
##--------------------
|
||||
## spawns/bridges/opens stmts
|
||||
|
||||
def p_SpawnsStmtsOpt(p):
|
||||
"""SpawnsStmtsOpt : SpawnsStmt SpawnsStmtsOpt
|
||||
| BridgesStmtsOpt"""
|
||||
if 2 == len(p):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[2].spawnsStmts.insert(0, p[1])
|
||||
p[0] = p[2]
|
||||
|
||||
def p_SpawnsStmt(p):
|
||||
"""SpawnsStmt : PARENT SPAWNS ID AsOpt ';'
|
||||
| CHILD SPAWNS ID AsOpt ';'"""
|
||||
p[0] = SpawnsStmt(locFromTok(p, 1), p[1], p[3], p[4])
|
||||
|
||||
def p_AsOpt(p):
|
||||
"""AsOpt : AS PARENT
|
||||
| AS CHILD
|
||||
| """
|
||||
if 3 == len(p):
|
||||
p[0] = p[2]
|
||||
else:
|
||||
p[0] = 'child'
|
||||
|
||||
def p_BridgesStmtsOpt(p):
|
||||
"""BridgesStmtsOpt : BridgesStmt BridgesStmtsOpt
|
||||
| OpensStmtsOpt"""
|
||||
if 2 == len(p):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[2].bridgesStmts.insert(0, p[1])
|
||||
p[0] = p[2]
|
||||
|
||||
def p_BridgesStmt(p):
|
||||
"""BridgesStmt : BRIDGES ID ',' ID ';'"""
|
||||
p[0] = BridgesStmt(locFromTok(p, 1), p[2], p[4])
|
||||
|
||||
def p_OpensStmtsOpt(p):
|
||||
"""OpensStmtsOpt : OpensStmt OpensStmtsOpt
|
||||
| ManagersStmtOpt"""
|
||||
if 2 == len(p):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[2].opensStmts.insert(0, p[1])
|
||||
p[0] = p[2]
|
||||
|
||||
def p_OpensStmt(p):
|
||||
"""OpensStmt : PARENT OPENS ID ';'
|
||||
| CHILD OPENS ID ';'"""
|
||||
p[0] = OpensStmt(locFromTok(p, 1), p[1], p[3])
|
||||
|
||||
##--------------------
|
||||
## manager/manages stmts
|
||||
|
||||
def p_ManagersStmtOpt(p):
|
||||
"""ManagersStmtOpt : ManagersStmt ManagesStmtsOpt
|
||||
| ManagesStmtsOpt"""
|
||||
if 2 == len(p):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[2].managers = p[1]
|
||||
p[0] = p[2]
|
||||
|
||||
def p_ManagersStmt(p):
|
||||
"""ManagersStmt : MANAGER ManagerList ';'"""
|
||||
if 1 == len(p):
|
||||
p[0] = [ ]
|
||||
else:
|
||||
p[0] = p[2]
|
||||
|
||||
def p_ManagerList(p):
|
||||
"""ManagerList : ID
|
||||
| ManagerList OR ID"""
|
||||
if 2 == len(p):
|
||||
p[0] = [ Manager(locFromTok(p, 1), p[1]) ]
|
||||
else:
|
||||
p[1].append(Manager(locFromTok(p, 3), p[3]))
|
||||
p[0] = p[1]
|
||||
|
||||
def p_ManagesStmtsOpt(p):
|
||||
"""ManagesStmtsOpt : ManagesStmt ManagesStmtsOpt
|
||||
| MessageDeclsOpt"""
|
||||
if 2 == len(p):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[2].managesStmts.insert(0, p[1])
|
||||
p[0] = p[2]
|
||||
|
||||
def p_ManagesStmt(p):
|
||||
"""ManagesStmt : MANAGES ID ';'"""
|
||||
p[0] = ManagesStmt(locFromTok(p, 1), p[2])
|
||||
|
||||
|
||||
##--------------------
|
||||
## Message decls
|
||||
|
||||
def p_MessageDeclsOpt(p):
|
||||
"""MessageDeclsOpt : MessageDeclThing MessageDeclsOpt
|
||||
| TransitionStmtsOpt"""
|
||||
if 2 == len(p):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[2].messageDecls.insert(0, p[1])
|
||||
p[0] = p[2]
|
||||
|
||||
def p_MessageDeclThing(p):
|
||||
"""MessageDeclThing : MessageDirectionLabel ':' MessageDecl ';'
|
||||
| MessageDecl ';'"""
|
||||
if 3 == len(p):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[0] = p[3]
|
||||
|
||||
def p_MessageDirectionLabel(p):
|
||||
"""MessageDirectionLabel : PARENT
|
||||
| CHILD
|
||||
| BOTH"""
|
||||
if p[1] == 'parent':
|
||||
Parser.current.direction = IN
|
||||
elif p[1] == 'child':
|
||||
Parser.current.direction = OUT
|
||||
elif p[1] == 'both':
|
||||
Parser.current.direction = INOUT
|
||||
else:
|
||||
assert 0
|
||||
|
||||
def p_MessageDecl(p):
|
||||
"""MessageDecl : SendSemanticsQual MessageBody"""
|
||||
msg = p[2]
|
||||
msg.nested = p[1][0]
|
||||
msg.prio = p[1][1]
|
||||
msg.sendSemantics = p[1][2]
|
||||
|
||||
if Parser.current.direction is None:
|
||||
_error(msg.loc, 'missing message direction')
|
||||
msg.direction = Parser.current.direction
|
||||
|
||||
p[0] = msg
|
||||
|
||||
def p_MessageBody(p):
|
||||
"""MessageBody : MessageId MessageInParams MessageOutParams OptionalMessageModifiers"""
|
||||
# FIXME/cjones: need better loc info: use one of the quals
|
||||
loc, name = p[1]
|
||||
msg = MessageDecl(loc)
|
||||
msg.name = name
|
||||
msg.addInParams(p[2])
|
||||
msg.addOutParams(p[3])
|
||||
msg.addModifiers(p[4])
|
||||
|
||||
p[0] = msg
|
||||
|
||||
def p_MessageId(p):
|
||||
"""MessageId : ID
|
||||
| __DELETE__
|
||||
| DELETE
|
||||
| '~' ID"""
|
||||
loc = locFromTok(p, 1)
|
||||
if 3 == len(p):
|
||||
_error(loc, "sorry, `%s()' destructor syntax is a relic from a bygone era. Declare `__delete__()' in the `%s' protocol instead", p[1]+p[2], p[2])
|
||||
elif 'delete' == p[1]:
|
||||
_error(loc, "`delete' is a reserved identifier")
|
||||
p[0] = [ loc, p[1] ]
|
||||
|
||||
def p_MessageInParams(p):
|
||||
"""MessageInParams : '(' ParamList ')'"""
|
||||
p[0] = p[2]
|
||||
|
||||
def p_MessageOutParams(p):
|
||||
"""MessageOutParams : RETURNS '(' ParamList ')'
|
||||
| """
|
||||
if 1 == len(p):
|
||||
p[0] = [ ]
|
||||
else:
|
||||
p[0] = p[3]
|
||||
|
||||
def p_OptionalMessageModifiers(p):
|
||||
"""OptionalMessageModifiers : OptionalMessageModifiers MessageModifier
|
||||
| MessageModifier
|
||||
| """
|
||||
if 1 == len(p):
|
||||
p[0] = [ ]
|
||||
elif 2 == len(p):
|
||||
p[0] = [ p[1] ]
|
||||
else:
|
||||
p[1].append(p[2])
|
||||
p[0] = p[1]
|
||||
|
||||
def p_MessageModifier(p):
|
||||
""" MessageModifier : MessageVerify
|
||||
| MessageCompress """
|
||||
p[0] = p[1]
|
||||
|
||||
def p_MessageVerify(p):
|
||||
"""MessageVerify : VERIFY"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_MessageCompress(p):
|
||||
"""MessageCompress : COMPRESS
|
||||
| COMPRESSALL"""
|
||||
p[0] = p[1]
|
||||
|
||||
##--------------------
|
||||
## State machine
|
||||
|
||||
def p_TransitionStmtsOpt(p):
|
||||
"""TransitionStmtsOpt : TransitionStmt TransitionStmtsOpt
|
||||
|"""
|
||||
if 1 == len(p):
|
||||
# we fill in |loc| in the Protocol rule
|
||||
p[0] = Protocol(None)
|
||||
else:
|
||||
p[2].transitionStmts.insert(0, p[1])
|
||||
p[0] = p[2]
|
||||
|
||||
def p_TransitionStmt(p):
|
||||
"""TransitionStmt : OptionalStart STATE State ':' Transitions"""
|
||||
p[3].start = p[1]
|
||||
p[0] = TransitionStmt(locFromTok(p, 2), p[3], p[5])
|
||||
|
||||
def p_OptionalStart(p):
|
||||
"""OptionalStart : START
|
||||
| """
|
||||
p[0] = (len(p) == 2) # True iff 'start' specified
|
||||
|
||||
def p_Transitions(p):
|
||||
"""Transitions : Transitions Transition
|
||||
| Transition"""
|
||||
if 3 == len(p):
|
||||
p[1].append(p[2])
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[0] = [ p[1] ]
|
||||
|
||||
def p_Transition(p):
|
||||
"""Transition : Trigger ID GOTO StateList ';'
|
||||
| Trigger __DELETE__ ';'
|
||||
| Trigger DELETE ';'"""
|
||||
if 'delete' == p[2]:
|
||||
_error(locFromTok(p, 1), "`delete' is a reserved identifier")
|
||||
|
||||
loc, trigger = p[1]
|
||||
if 6 == len(p):
|
||||
nextstates = p[4]
|
||||
else:
|
||||
nextstates = [ State.DEAD ]
|
||||
p[0] = Transition(loc, trigger, p[2], nextstates)
|
||||
|
||||
def p_Trigger(p):
|
||||
"""Trigger : SEND
|
||||
| RECV
|
||||
| CALL
|
||||
| ANSWER"""
|
||||
p[0] = [ locFromTok(p, 1), Transition.nameToTrigger(p[1]) ]
|
||||
|
||||
def p_StateList(p):
|
||||
"""StateList : StateList OR State
|
||||
| State"""
|
||||
if 2 == len(p):
|
||||
p[0] = [ p[1] ]
|
||||
else:
|
||||
p[1].append(p[3])
|
||||
p[0] = p[1]
|
||||
|
||||
def p_State(p):
|
||||
"""State : ID"""
|
||||
p[0] = State(locFromTok(p, 1), p[1])
|
||||
|
||||
##--------------------
|
||||
## Minor stuff
|
||||
def p_Nested(p):
|
||||
"""Nested : ID"""
|
||||
kinds = {'not': 1,
|
||||
'inside_sync': 2,
|
||||
'inside_cpow': 3}
|
||||
if p[1] not in kinds:
|
||||
_error(locFromTok(p, 1), "Expected not, inside_sync, or inside_cpow for nested()")
|
||||
|
||||
p[0] = { 'nested': kinds[p[1]] }
|
||||
|
||||
def p_Priority(p):
|
||||
"""Priority : ID"""
|
||||
kinds = {'normal': 1,
|
||||
'high': 2}
|
||||
if p[1] not in kinds:
|
||||
_error(locFromTok(p, 1), "Expected normal or high for prio()")
|
||||
|
||||
p[0] = { 'prio': kinds[p[1]] }
|
||||
|
||||
def p_SendQualifier(p):
|
||||
"""SendQualifier : NESTED '(' Nested ')'
|
||||
| PRIO '(' Priority ')'"""
|
||||
p[0] = p[3]
|
||||
|
||||
def p_SendQualifierList(p):
|
||||
"""SendQualifierList : SendQualifier SendQualifierList
|
||||
| """
|
||||
if len(p) > 1:
|
||||
p[0] = p[1]
|
||||
p[0].update(p[2])
|
||||
else:
|
||||
p[0] = {}
|
||||
|
||||
def p_SendSemanticsQual(p):
|
||||
"""SendSemanticsQual : SendQualifierList ASYNC
|
||||
| SendQualifierList SYNC
|
||||
| INTR"""
|
||||
quals = {}
|
||||
if len(p) == 3:
|
||||
quals = p[1]
|
||||
mtype = p[2]
|
||||
else:
|
||||
mtype = 'intr'
|
||||
|
||||
if mtype == 'async': mtype = ASYNC
|
||||
elif mtype == 'sync': mtype = SYNC
|
||||
elif mtype == 'intr': mtype = INTR
|
||||
else: assert 0
|
||||
|
||||
p[0] = [ quals.get('nested', NOT_NESTED), quals.get('prio', NORMAL_PRIORITY), mtype ]
|
||||
|
||||
def p_OptionalProtocolSendSemanticsQual(p):
|
||||
"""OptionalProtocolSendSemanticsQual : ProtocolSendSemanticsQual
|
||||
| """
|
||||
if 2 == len(p): p[0] = p[1]
|
||||
else: p[0] = [ (NOT_NESTED, NOT_NESTED), ASYNC ]
|
||||
|
||||
def p_ProtocolSendSemanticsQual(p):
|
||||
"""ProtocolSendSemanticsQual : ASYNC
|
||||
| SYNC
|
||||
| NESTED '(' UPTO Nested ')' ASYNC
|
||||
| NESTED '(' UPTO Nested ')' SYNC
|
||||
| INTR"""
|
||||
if p[1] == 'nested':
|
||||
mtype = p[6]
|
||||
nested = (NOT_NESTED, p[4])
|
||||
else:
|
||||
mtype = p[1]
|
||||
nested = (NOT_NESTED, NOT_NESTED)
|
||||
|
||||
if mtype == 'async': mtype = ASYNC
|
||||
elif mtype == 'sync': mtype = SYNC
|
||||
elif mtype == 'intr': mtype = INTR
|
||||
else: assert 0
|
||||
|
||||
p[0] = [ nested, mtype ]
|
||||
|
||||
def p_ParamList(p):
|
||||
"""ParamList : ParamList ',' Param
|
||||
| Param
|
||||
| """
|
||||
if 1 == len(p):
|
||||
p[0] = [ ]
|
||||
elif 2 == len(p):
|
||||
p[0] = [ p[1] ]
|
||||
else:
|
||||
p[1].append(p[3])
|
||||
p[0] = p[1]
|
||||
|
||||
def p_Param(p):
|
||||
"""Param : Type ID"""
|
||||
p[0] = Param(locFromTok(p, 1), p[1], p[2])
|
||||
|
||||
def p_Type(p):
|
||||
"""Type : MaybeNullable BasicType"""
|
||||
# only actor types are nullable; we check this in the type checker
|
||||
p[2].nullable = p[1]
|
||||
p[0] = p[2]
|
||||
|
||||
def p_BasicType(p):
|
||||
"""BasicType : ScalarType
|
||||
| ScalarType '[' ']'"""
|
||||
if 4 == len(p):
|
||||
p[1].array = 1
|
||||
p[0] = p[1]
|
||||
|
||||
def p_ScalarType(p):
|
||||
"""ScalarType : ActorType
|
||||
| CxxID""" # ID == CxxType; we forbid qnames here,
|
||||
# in favor of the |using| declaration
|
||||
if isinstance(p[1], TypeSpec):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
loc, id = p[1]
|
||||
p[0] = TypeSpec(loc, QualifiedId(loc, id))
|
||||
|
||||
def p_ActorType(p):
|
||||
"""ActorType : ID ':' State"""
|
||||
loc = locFromTok(p, 1)
|
||||
p[0] = TypeSpec(loc, QualifiedId(loc, p[1]), state=p[3])
|
||||
|
||||
def p_MaybeNullable(p):
|
||||
"""MaybeNullable : NULLABLE
|
||||
| """
|
||||
p[0] = (2 == len(p))
|
||||
|
||||
##--------------------
|
||||
## C++ stuff
|
||||
def p_CxxType(p):
|
||||
"""CxxType : QualifiedID
|
||||
| CxxID"""
|
||||
if isinstance(p[1], QualifiedId):
|
||||
p[0] = TypeSpec(p[1].loc, p[1])
|
||||
else:
|
||||
loc, id = p[1]
|
||||
p[0] = TypeSpec(loc, QualifiedId(loc, id))
|
||||
|
||||
def p_QualifiedID(p):
|
||||
"""QualifiedID : QualifiedID COLONCOLON CxxID
|
||||
| CxxID COLONCOLON CxxID"""
|
||||
if isinstance(p[1], QualifiedId):
|
||||
loc, id = p[3]
|
||||
p[1].qualify(id)
|
||||
p[0] = p[1]
|
||||
else:
|
||||
loc1, id1 = p[1]
|
||||
_, id2 = p[3]
|
||||
p[0] = QualifiedId(loc1, id2, [ id1 ])
|
||||
|
||||
def p_CxxID(p):
|
||||
"""CxxID : ID
|
||||
| CxxTemplateInst"""
|
||||
if isinstance(p[1], tuple):
|
||||
p[0] = p[1]
|
||||
else:
|
||||
p[0] = (locFromTok(p, 1), str(p[1]))
|
||||
|
||||
def p_CxxTemplateInst(p):
|
||||
"""CxxTemplateInst : ID '<' ID '>'"""
|
||||
p[0] = (locFromTok(p, 1), str(p[1]) +'<'+ str(p[3]) +'>')
|
||||
|
||||
def p_error(t):
|
||||
lineno, value = _safeLinenoValue(t)
|
||||
_error(Loc(Parser.current.filename, lineno),
|
||||
"bad syntax near `%s'", value)
|
||||
2200
ipc/ipdl/ipdl/type.py
Normal file
2200
ipc/ipdl/ipdl/type.py
Normal file
File diff suppressed because it is too large
Load diff
19
ipc/ipdl/moz.build
Normal file
19
ipc/ipdl/moz.build
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
if CONFIG['MOZ_IPDL_TESTS']:
|
||||
DIRS += ['test']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Generated by ipdl.py
|
||||
SOURCES += ['!IPCMessageTypeName.cpp']
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
# We #include some things in the dom/plugins/ directory that rely on
|
||||
# toolkit libraries.
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
13
ipc/ipdl/msgtype-components
Normal file
13
ipc/ipdl/msgtype-components
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/python
|
||||
# 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/.
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
msgid = int(sys.argv[1])
|
||||
protocol = (msgid >> 16)
|
||||
msg = (msgid - (protocol << 16))
|
||||
|
||||
print 'protocol', protocol, 'message', msg
|
||||
10
ipc/ipdl/test/README.txt
Normal file
10
ipc/ipdl/test/README.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
There are two major categories of tests, segregated into different
|
||||
top-level directories under test/.
|
||||
|
||||
The first category (ipdl/) is IPDL-compiler tests. These tests check
|
||||
that the IPDL compiler is successfully compiling correct
|
||||
specifications, and successfully rejecting erroneous specifications.
|
||||
|
||||
The second category (cxx/) is C++ tests of IPDL semantics. These
|
||||
tests check that async/sync/rpc semantics are implemented correctly,
|
||||
ctors/dtors behave as they should, etc.
|
||||
32
ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp
Normal file
32
ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* 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 "mozilla/ipc/IOThreadChild.h"
|
||||
|
||||
#include "IPDLUnitTestProcessChild.h"
|
||||
#include "IPDLUnitTests.h"
|
||||
|
||||
#include "nsRegion.h"
|
||||
|
||||
using mozilla::ipc::IOThreadChild;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
bool
|
||||
IPDLUnitTestProcessChild::Init()
|
||||
{
|
||||
IPDLUnitTestChildInit(IOThreadChild::channel(),
|
||||
ParentPid(),
|
||||
IOThreadChild::message_loop());
|
||||
|
||||
if (NS_FAILED(nsRegion::InitStatic()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
32
ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h
Normal file
32
ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h
|
||||
#define mozilla__ipdltest_IPDLUnitTestThreadChild_h 1
|
||||
|
||||
#include "mozilla/ipc/ProcessChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild
|
||||
{
|
||||
typedef mozilla::ipc::ProcessChild ProcessChild;
|
||||
|
||||
public:
|
||||
explicit IPDLUnitTestProcessChild(ProcessId aParentPid) :
|
||||
ProcessChild(aParentPid)
|
||||
{ }
|
||||
|
||||
~IPDLUnitTestProcessChild()
|
||||
{ }
|
||||
|
||||
virtual bool Init();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h
|
||||
23
ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp
Normal file
23
ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* 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 "IPDLUnitTestSubprocess.h"
|
||||
|
||||
using mozilla::ipc::GeckoChildProcessHost;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
IPDLUnitTestSubprocess::IPDLUnitTestSubprocess() :
|
||||
GeckoChildProcessHost(GeckoProcessType_IPDLUnitTest)
|
||||
{
|
||||
}
|
||||
|
||||
IPDLUnitTestSubprocess::~IPDLUnitTestSubprocess()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
37
ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h
Normal file
37
ipc/ipdl/test/cxx/IPDLUnitTestSubprocess.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h
|
||||
#define mozilla__ipdltest_IPDLUnitTestTestSubprocess_h 1
|
||||
|
||||
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class IPDLUnitTestSubprocess : public mozilla::ipc::GeckoChildProcessHost
|
||||
{
|
||||
public:
|
||||
IPDLUnitTestSubprocess();
|
||||
~IPDLUnitTestSubprocess();
|
||||
|
||||
/**
|
||||
* Asynchronously launch the plugin process.
|
||||
*/
|
||||
// Could override parent Launch, but don't need to here
|
||||
//bool Launch();
|
||||
|
||||
private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(IPDLUnitTestSubprocess);
|
||||
};
|
||||
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h
|
||||
44
ipc/ipdl/test/cxx/IPDLUnitTestTypes.h
Normal file
44
ipc/ipdl/test/cxx/IPDLUnitTestTypes.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla__ipdltest_IPDLUnitTestTypes_h
|
||||
#define mozilla__ipdltest_IPDLUnitTestTypes_h
|
||||
|
||||
#include "mozilla/ipc/ProtocolUtils.h" // ActorDestroyReason
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
struct DirtyRect
|
||||
{
|
||||
int x; int y; int w; int h;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
template<>
|
||||
struct ParamTraits<mozilla::_ipdltest::DirtyRect>
|
||||
{
|
||||
typedef mozilla::_ipdltest::DirtyRect paramType;
|
||||
static void Write(Message* aMsg, const paramType& aParam) {
|
||||
WriteParam(aMsg, aParam.x);
|
||||
WriteParam(aMsg, aParam.y);
|
||||
WriteParam(aMsg, aParam.w);
|
||||
WriteParam(aMsg, aParam.h);
|
||||
}
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
return (ReadParam(aMsg, aIter, &aResult->x) &&
|
||||
ReadParam(aMsg, aIter, &aResult->y) &&
|
||||
ReadParam(aMsg, aIter, &aResult->w) &&
|
||||
ReadParam(aMsg, aIter, &aResult->h));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // ifndef mozilla__ipdltest_IPDLUnitTestTypes_h
|
||||
27
ipc/ipdl/test/cxx/IPDLUnitTestUtils.h
Normal file
27
ipc/ipdl/test/cxx/IPDLUnitTestUtils.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
#ifndef mozilla__ipdltest_IPDLUnitTestUtils
|
||||
#define mozilla__ipdltest_IPDLUnitTestUtils 1
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
struct Bad {};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
struct ParamTraits<mozilla::_ipdltest::Bad>
|
||||
{
|
||||
typedef mozilla::_ipdltest::Bad paramType;
|
||||
|
||||
// Defined in TestActorPunning.cpp.
|
||||
static void Write(Message* aMsg, const paramType& aParam);
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla__ipdltest_IPDLUnitTestUtils
|
||||
93
ipc/ipdl/test/cxx/IPDLUnitTests.h
Normal file
93
ipc/ipdl/test/cxx/IPDLUnitTests.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla__ipdltest_IPDLUnitTests_h
|
||||
#define mozilla__ipdltest_IPDLUnitTests_h 1
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "base/process.h"
|
||||
#include "chrome/common/ipc_channel.h"
|
||||
|
||||
#include "nsIAppShell.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsServiceManagerUtils.h" // do_GetService()
|
||||
#include "nsWidgetsCID.h" // NS_APPSHELL_CID
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
|
||||
#define MOZ_IPDL_TESTFAIL_LABEL "TEST-UNEXPECTED-FAIL"
|
||||
#define MOZ_IPDL_TESTPASS_LABEL "TEST-PASS"
|
||||
#define MOZ_IPDL_TESTINFO_LABEL "TEST-INFO"
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// both processes
|
||||
const char* IPDLUnitTestName();
|
||||
|
||||
// NB: these are named like the similar functions in
|
||||
// xpcom/test/TestHarness.h. The names should nominally be kept in
|
||||
// sync.
|
||||
|
||||
inline void fail(const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL " | %s | ", IPDLUnitTestName());
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fputc('\n', stderr);
|
||||
|
||||
NS_RUNTIMEABORT("failed test");
|
||||
}
|
||||
|
||||
inline void passed(const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
printf(MOZ_IPDL_TESTPASS_LABEL " | %s | ", IPDLUnitTestName());
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// parent process only
|
||||
|
||||
class IPDLUnitTestSubprocess;
|
||||
|
||||
extern void* gParentActor;
|
||||
extern IPDLUnitTestSubprocess* gSubprocess;
|
||||
|
||||
void IPDLUnitTestMain(void* aData);
|
||||
|
||||
void QuitParent();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// child process only
|
||||
|
||||
extern void* gChildActor;
|
||||
|
||||
void IPDLUnitTestChildInit(IPC::Channel* transport,
|
||||
base::ProcessId parentPid,
|
||||
MessageLoop* worker);
|
||||
|
||||
void QuitChild();
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // ifndef mozilla__ipdltest_IPDLUnitTests_h
|
||||
390
ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp
Normal file
390
ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
//
|
||||
// Autogenerated from Python template. Hands off.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "IPDLUnitTests.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/task.h"
|
||||
#include "base/thread.h"
|
||||
|
||||
#include "nsRegion.h"
|
||||
|
||||
#include "IPDLUnitTestSubprocess.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${INCLUDES}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
using namespace std;
|
||||
|
||||
using base::Thread;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
void* gParentActor;
|
||||
IPDLUnitTestSubprocess* gSubprocess;
|
||||
|
||||
void* gChildActor;
|
||||
|
||||
// Note: in threaded mode, this will be non-null (for both parent and
|
||||
// child, since they share one set of globals).
|
||||
Thread* gChildThread;
|
||||
MessageLoop *gParentMessageLoop;
|
||||
bool gParentDone;
|
||||
bool gChildDone;
|
||||
|
||||
void
|
||||
DeleteChildActor();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// data/functions accessed by both parent and child processes
|
||||
|
||||
char* gIPDLUnitTestName = nullptr;
|
||||
|
||||
const char*
|
||||
IPDLUnitTestName()
|
||||
{
|
||||
if (!gIPDLUnitTestName) {
|
||||
#if defined(OS_WIN)
|
||||
vector<wstring> args =
|
||||
CommandLine::ForCurrentProcess()->GetLooseValues();
|
||||
gIPDLUnitTestName = ::strdup(WideToUTF8(args[0]).c_str());
|
||||
#elif defined(OS_POSIX)
|
||||
vector<string> argv = CommandLine::ForCurrentProcess()->argv();
|
||||
gIPDLUnitTestName = ::moz_xstrdup(argv[1].c_str());
|
||||
#else
|
||||
# error Sorry
|
||||
#endif
|
||||
}
|
||||
return gIPDLUnitTestName;
|
||||
}
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
enum IPDLUnitTestType {
|
||||
NoneTest = 0,
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${ENUM_VALUES}
|
||||
|
||||
LastTest = ${LAST_ENUM}
|
||||
//-----------------------------------------------------------------------------
|
||||
};
|
||||
|
||||
|
||||
IPDLUnitTestType
|
||||
IPDLUnitTestFromString(const char* const aString)
|
||||
{
|
||||
if (!aString)
|
||||
return static_cast<IPDLUnitTestType>(0);
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${STRING_TO_ENUMS}
|
||||
//-----------------------------------------------------------------------------
|
||||
else
|
||||
return static_cast<IPDLUnitTestType>(0);
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
IPDLUnitTestToString(IPDLUnitTestType aTest)
|
||||
{
|
||||
switch (aTest) {
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${ENUM_TO_STRINGS}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IPDLUnitTestType
|
||||
IPDLUnitTest()
|
||||
{
|
||||
return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName());
|
||||
}
|
||||
|
||||
|
||||
} // namespace <anon>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// parent process only
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
void
|
||||
DeferredParentShutdown();
|
||||
|
||||
void
|
||||
IPDLUnitTestThreadMain(char *testString);
|
||||
|
||||
void
|
||||
IPDLUnitTestMain(void* aData)
|
||||
{
|
||||
char* testString = reinterpret_cast<char*>(aData);
|
||||
|
||||
// Check if we are to run the test using threads instead:
|
||||
const char *prefix = "thread:";
|
||||
const int prefixLen = strlen(prefix);
|
||||
if (!strncmp(testString, prefix, prefixLen)) {
|
||||
IPDLUnitTestThreadMain(testString + prefixLen);
|
||||
return;
|
||||
}
|
||||
|
||||
IPDLUnitTestType test = IPDLUnitTestFromString(testString);
|
||||
if (!test) {
|
||||
// use this instead of |fail()| because we don't know what the test is
|
||||
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
|
||||
"<--->", testString);
|
||||
NS_RUNTIMEABORT("can't continue");
|
||||
}
|
||||
gIPDLUnitTestName = testString;
|
||||
|
||||
// Check whether this test is enabled for processes:
|
||||
switch (test) {
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${PARENT_ENABLED_CASES_PROC}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
default:
|
||||
fail("not reached");
|
||||
return; // unreached
|
||||
}
|
||||
|
||||
printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
|
||||
|
||||
std::vector<std::string> testCaseArgs;
|
||||
testCaseArgs.push_back(testString);
|
||||
|
||||
gSubprocess = new IPDLUnitTestSubprocess();
|
||||
if (!gSubprocess->SyncLaunch(testCaseArgs))
|
||||
fail("problem launching subprocess");
|
||||
|
||||
IPC::Channel* transport = gSubprocess->GetChannel();
|
||||
if (!transport)
|
||||
fail("no transport");
|
||||
|
||||
base::ProcessId child = base::GetProcId(gSubprocess->GetChildProcessHandle());
|
||||
|
||||
switch (test) {
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${PARENT_MAIN_CASES_PROC}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
default:
|
||||
fail("not reached");
|
||||
return; // unreached
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPDLUnitTestThreadMain(char *testString)
|
||||
{
|
||||
IPDLUnitTestType test = IPDLUnitTestFromString(testString);
|
||||
if (!test) {
|
||||
// use this instead of |fail()| because we don't know what the test is
|
||||
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
|
||||
"<--->", testString);
|
||||
NS_RUNTIMEABORT("can't continue");
|
||||
}
|
||||
gIPDLUnitTestName = testString;
|
||||
|
||||
// Check whether this test is enabled for threads:
|
||||
switch (test) {
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${PARENT_ENABLED_CASES_THREAD}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
default:
|
||||
fail("not reached");
|
||||
return; // unreached
|
||||
}
|
||||
|
||||
printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
|
||||
|
||||
std::vector<std::string> testCaseArgs;
|
||||
testCaseArgs.push_back(testString);
|
||||
|
||||
gChildThread = new Thread("ParentThread");
|
||||
if (!gChildThread->Start())
|
||||
fail("starting parent thread");
|
||||
|
||||
gParentMessageLoop = MessageLoop::current();
|
||||
MessageLoop *childMessageLoop = gChildThread->message_loop();
|
||||
|
||||
switch (test) {
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${PARENT_MAIN_CASES_THREAD}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
default:
|
||||
fail("not reached");
|
||||
return; // unreached
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeleteParentActor()
|
||||
{
|
||||
if (!gParentActor)
|
||||
return;
|
||||
|
||||
switch (IPDLUnitTest()) {
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${PARENT_DELETE_CASES}
|
||||
//-----------------------------------------------------------------------------
|
||||
default: ::mozilla::_ipdltest::fail("???");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QuitXPCOM()
|
||||
{
|
||||
DeleteParentActor();
|
||||
|
||||
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
|
||||
appShell->Exit();
|
||||
}
|
||||
|
||||
void
|
||||
DeleteSubprocess(MessageLoop* uiLoop)
|
||||
{
|
||||
// pong to QuitXPCOM
|
||||
delete gSubprocess;
|
||||
uiLoop->PostTask(NewRunnableFunction(QuitXPCOM));
|
||||
}
|
||||
|
||||
void
|
||||
DeferredParentShutdown()
|
||||
{
|
||||
// ping to DeleteSubprocess
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
NewRunnableFunction(DeleteSubprocess, MessageLoop::current()));
|
||||
}
|
||||
|
||||
void
|
||||
TryThreadedShutdown()
|
||||
{
|
||||
// Stop if either:
|
||||
// - the child has not finished,
|
||||
// - the parent has not finished,
|
||||
// - or this code has already executed.
|
||||
// Remember: this TryThreadedShutdown() task is enqueued
|
||||
// by both parent and child (though always on parent's msg loop).
|
||||
if (!gChildDone || !gParentDone || !gChildThread)
|
||||
return;
|
||||
|
||||
delete gChildThread;
|
||||
gChildThread = 0;
|
||||
DeferredParentShutdown();
|
||||
}
|
||||
|
||||
void
|
||||
ChildCompleted()
|
||||
{
|
||||
// Executes on the parent message loop once child has completed.
|
||||
gChildDone = true;
|
||||
TryThreadedShutdown();
|
||||
}
|
||||
|
||||
void
|
||||
QuitParent()
|
||||
{
|
||||
if (gChildThread) {
|
||||
gParentDone = true;
|
||||
MessageLoop::current()->PostTask(
|
||||
NewRunnableFunction(TryThreadedShutdown));
|
||||
} else {
|
||||
// defer "real" shutdown to avoid *Channel::Close() racing with the
|
||||
// deletion of the subprocess
|
||||
MessageLoop::current()->PostTask(
|
||||
NewRunnableFunction(DeferredParentShutdown));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ChildDie()
|
||||
{
|
||||
DeleteChildActor();
|
||||
XRE_ShutdownChildProcess();
|
||||
}
|
||||
|
||||
void
|
||||
QuitChild()
|
||||
{
|
||||
if (gChildThread) { // Threaded-mode test
|
||||
gParentMessageLoop->PostTask(
|
||||
NewRunnableFunction(ChildCompleted));
|
||||
} else { // Process-mode test
|
||||
MessageLoop::current()->PostTask(
|
||||
NewRunnableFunction(ChildDie));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// child process only
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
void
|
||||
DeleteChildActor()
|
||||
{
|
||||
if (!gChildActor)
|
||||
return;
|
||||
|
||||
switch (IPDLUnitTest()) {
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${CHILD_DELETE_CASES}
|
||||
//-----------------------------------------------------------------------------
|
||||
default: ::mozilla::_ipdltest::fail("???");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IPDLUnitTestChildInit(IPC::Channel* transport,
|
||||
base::ProcessId parentPid,
|
||||
MessageLoop* worker)
|
||||
{
|
||||
switch (IPDLUnitTest()) {
|
||||
//-----------------------------------------------------------------------------
|
||||
//===== TEMPLATED =====
|
||||
${CHILD_INIT_CASES}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
default:
|
||||
fail("not reached");
|
||||
return; // unreached
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
46
ipc/ipdl/test/cxx/Makefile.in
Normal file
46
ipc/ipdl/test/cxx/Makefile.in
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# 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/.
|
||||
|
||||
IPDLTESTSRCS = $(filter Test%,$(CPPSRCS))
|
||||
IPDLTESTS = $(IPDLTESTSRCS:.cpp=)
|
||||
|
||||
EXTRA_PROTOCOLS = \
|
||||
TestBridgeSub \
|
||||
TestEndpointBridgeSub \
|
||||
$(NULL)
|
||||
|
||||
IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS)))
|
||||
|
||||
TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp
|
||||
GENTESTER := $(srcdir)/genIPDLUnitTests.py
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
||||
IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX)
|
||||
|
||||
IPDLUnitTests.cpp : Makefile.in moz.build $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
|
||||
$(PYTHON) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@
|
||||
|
||||
check-proc::
|
||||
@$(EXIT_ON_ERROR) \
|
||||
for test in $(IPDLTESTS); do \
|
||||
$(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) $$test ; \
|
||||
done
|
||||
|
||||
check-thread::
|
||||
@$(EXIT_ON_ERROR) \
|
||||
for test in $(IPDLTESTS); do \
|
||||
$(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) thread:$$test ; \
|
||||
done
|
||||
|
||||
check:: check-proc check-thread
|
||||
|
||||
check-valgrind::
|
||||
@$(EXIT_ON_ERROR) \
|
||||
for test in $(IPDLTESTS); do \
|
||||
$(RUN_TEST_PROGRAM) -g -d \
|
||||
valgrind -a '--leak-check=full --trace-children=yes -q' \
|
||||
$(IPDLUNITTEST_BIN) $$test ; \
|
||||
done
|
||||
39
ipc/ipdl/test/cxx/PTestActorPunning.ipdl
Normal file
39
ipc/ipdl/test/cxx/PTestActorPunning.ipdl
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
include protocol PTestActorPunningPunned;
|
||||
include protocol PTestActorPunningSub;
|
||||
include "mozilla/_ipdltest/IPDLUnitTestUtils.h";
|
||||
|
||||
using struct mozilla::_ipdltest::Bad from "mozilla/_ipdltest/IPDLUnitTestUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestActorPunning {
|
||||
manages PTestActorPunningPunned;
|
||||
manages PTestActorPunningSub;
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
async PTestActorPunningPunned();
|
||||
async PTestActorPunningSub();
|
||||
async Pun(PTestActorPunningSub a, Bad bad);
|
||||
async __delete__();
|
||||
|
||||
|
||||
state PING:
|
||||
send Start goto CONSTRUCTING;
|
||||
|
||||
state CONSTRUCTING:
|
||||
recv PTestActorPunningPunned goto CONSTRUCTING;
|
||||
recv PTestActorPunningSub goto CONSTRUCTING;
|
||||
recv Pun goto DEAD;
|
||||
// We never make it past this transition, --> error.
|
||||
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
15
ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl
Normal file
15
ipc/ipdl/test/cxx/PTestActorPunningPunned.ipdl
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
include protocol PTestActorPunning;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestActorPunningPunned {
|
||||
manager PTestActorPunning;
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltes
|
||||
16
ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl
Normal file
16
ipc/ipdl/test/cxx/PTestActorPunningSub.ipdl
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
include protocol PTestActorPunning;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestActorPunningSub {
|
||||
manager PTestActorPunning;
|
||||
|
||||
child:
|
||||
async Bad();
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltes
|
||||
18
ipc/ipdl/test/cxx/PTestBadActor.ipdl
Normal file
18
ipc/ipdl/test/cxx/PTestBadActor.ipdl
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
include protocol PTestBadActorSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
// Test that a parent sending a reentrant __delete__ message
|
||||
// is not killed if a child's message races with the reply.
|
||||
|
||||
intr protocol PTestBadActor {
|
||||
manages PTestBadActorSub;
|
||||
|
||||
child:
|
||||
async PTestBadActorSub();
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
17
ipc/ipdl/test/cxx/PTestBadActorSub.ipdl
Normal file
17
ipc/ipdl/test/cxx/PTestBadActorSub.ipdl
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
include protocol PTestBadActor;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestBadActorSub {
|
||||
manager PTestBadActor;
|
||||
|
||||
child:
|
||||
intr __delete__();
|
||||
|
||||
parent:
|
||||
async Ping();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
26
ipc/ipdl/test/cxx/PTestBridgeMain.ipdl
Normal file
26
ipc/ipdl/test/cxx/PTestBridgeMain.ipdl
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
include protocol PTestBridgeMainSub;
|
||||
include protocol PTestBridgeSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestBridgeMain {
|
||||
child spawns PTestBridgeSub;
|
||||
child opens PTestBridgeMainSub;
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send Start goto DEAD;
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
33
ipc/ipdl/test/cxx/PTestBridgeMainSub.ipdl
Normal file
33
ipc/ipdl/test/cxx/PTestBridgeMainSub.ipdl
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
include protocol PTestBridgeMain;
|
||||
include protocol PTestBridgeSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
// (Bridge protocols can have different semantics than the endpoints
|
||||
// they bridge)
|
||||
intr protocol PTestBridgeMainSub {
|
||||
bridges PTestBridgeMain, PTestBridgeSub;
|
||||
|
||||
child:
|
||||
async Hi();
|
||||
intr HiRpc();
|
||||
|
||||
parent:
|
||||
async Hello();
|
||||
sync HelloSync();
|
||||
intr HelloRpc();
|
||||
async __delete__();
|
||||
|
||||
state START: recv Hello goto HI;
|
||||
state HI: send Hi goto HELLO_SYNC;
|
||||
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
|
||||
state HELLO_RPC: answer HelloRpc goto HI_RPC;
|
||||
state HI_RPC: call HiRpc goto DEAD;
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
25
ipc/ipdl/test/cxx/PTestBridgeSub.ipdl
Normal file
25
ipc/ipdl/test/cxx/PTestBridgeSub.ipdl
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
include protocol PTestBridgeMainSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestBridgeSub {
|
||||
child:
|
||||
async Ping();
|
||||
|
||||
parent:
|
||||
async BridgeEm();
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send Ping goto BRIDGEEM;
|
||||
state BRIDGEEM:
|
||||
recv BridgeEm goto DEAD;
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
36
ipc/ipdl/test/cxx/PTestCancel.ipdl
Normal file
36
ipc/ipdl/test/cxx/PTestCancel.ipdl
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
nested(upto inside_sync) sync protocol PTestCancel
|
||||
{
|
||||
// Test1
|
||||
child:
|
||||
nested(inside_sync) sync Test1_1();
|
||||
parent:
|
||||
async Done1();
|
||||
|
||||
// Test2
|
||||
child:
|
||||
async Start2();
|
||||
nested(inside_sync) sync Test2_2();
|
||||
parent:
|
||||
sync Test2_1();
|
||||
|
||||
// Test3
|
||||
child:
|
||||
nested(inside_sync) sync Test3_1();
|
||||
parent:
|
||||
async Start3();
|
||||
nested(inside_sync) sync Test3_2();
|
||||
|
||||
parent:
|
||||
async Done();
|
||||
|
||||
child:
|
||||
nested(inside_sync) sync CheckChild() returns (uint32_t reply);
|
||||
parent:
|
||||
nested(inside_sync) sync CheckParent() returns (uint32_t reply);
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
22
ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl
Normal file
22
ipc/ipdl/test/cxx/PTestCrashCleanup.ipdl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// See bug 538586: if the top-level protocol's actor is deleted before
|
||||
// the "connection error" notification comes in from the IO thread,
|
||||
// IPDL teardown never occurs, even if Channel::Close() is called
|
||||
// after the error.
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
// NB: needs to be RPC so that the parent blocks on the child's crash.
|
||||
intr protocol PTestCrashCleanup {
|
||||
child:
|
||||
intr DIEDIEDIE();
|
||||
async __delete__();
|
||||
|
||||
state ALIVE:
|
||||
call DIEDIEDIE goto CRASH;
|
||||
state CRASH:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
132
ipc/ipdl/test/cxx/PTestDataStructures.ipdl
Normal file
132
ipc/ipdl/test/cxx/PTestDataStructures.ipdl
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
include protocol PTestDataStructuresSub;
|
||||
include PTestDataStructuresCommon;
|
||||
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
sync protocol PTestDataStructures {
|
||||
manages PTestDataStructuresSub;
|
||||
|
||||
child:
|
||||
async PTestDataStructuresSub(int i);
|
||||
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
|
||||
sync Test1(int[] i1)
|
||||
returns (int[] o1);
|
||||
|
||||
sync Test2(PTestDataStructuresSub[] i1)
|
||||
returns (PTestDataStructuresSub[] o1);
|
||||
|
||||
sync Test3(IntDouble i1,
|
||||
IntDouble i2)
|
||||
returns (IntDouble o1,
|
||||
IntDouble o2);
|
||||
|
||||
sync Test4(IntDouble[] i1)
|
||||
returns (IntDouble[] o1);
|
||||
|
||||
sync Test5(IntDoubleArrays i1,
|
||||
IntDoubleArrays i2,
|
||||
IntDoubleArrays i3)
|
||||
returns (IntDoubleArrays o1,
|
||||
IntDoubleArrays o2,
|
||||
IntDoubleArrays o3);
|
||||
|
||||
sync Test6(IntDoubleArrays[] i1)
|
||||
returns (IntDoubleArrays[] o1);
|
||||
|
||||
sync Test7_0(ActorWrapper a1)
|
||||
returns (ActorWrapper o1);
|
||||
|
||||
sync Test7(Actors i1,
|
||||
Actors i2,
|
||||
Actors i3)
|
||||
returns (Actors o1,
|
||||
Actors o2,
|
||||
Actors o3);
|
||||
|
||||
sync Test8(Actors[] i1)
|
||||
returns (Actors[] o1);
|
||||
|
||||
sync Test9(Unions i1,
|
||||
Unions i2,
|
||||
Unions i3,
|
||||
Unions i4)
|
||||
returns (Unions o1,
|
||||
Unions o2,
|
||||
Unions o3,
|
||||
Unions o4);
|
||||
|
||||
sync Test10(Unions[] i1)
|
||||
returns (Unions[] o1);
|
||||
|
||||
sync Test11(SIntDouble i)
|
||||
returns (SIntDouble o);
|
||||
|
||||
sync Test12(SIntDoubleArrays i)
|
||||
returns (SIntDoubleArrays o);
|
||||
|
||||
sync Test13(SActors i)
|
||||
returns (SActors o);
|
||||
|
||||
sync Test14(Structs i)
|
||||
returns (Structs o);
|
||||
|
||||
sync Test15(WithStructs i1,
|
||||
WithStructs i2,
|
||||
WithStructs i3,
|
||||
WithStructs i4,
|
||||
WithStructs i5)
|
||||
returns (WithStructs o1,
|
||||
WithStructs o2,
|
||||
WithStructs o3,
|
||||
WithStructs o4,
|
||||
WithStructs o5);
|
||||
|
||||
sync Test16(WithUnions i)
|
||||
returns (WithUnions o);
|
||||
|
||||
sync Test17(Op[] ops);
|
||||
|
||||
// test that the ParamTraits<nsTArray>::Read() workaround for
|
||||
// nsTArray's incorrect memmove() semantics works properly
|
||||
// (nsIntRegion isn't memmove()able)
|
||||
sync Test18(nsIntRegion[] ops);
|
||||
|
||||
sync Dummy(ShmemUnion su) returns (ShmemUnion rsu);
|
||||
|
||||
state CONSTRUCTING:
|
||||
send PTestDataStructuresSub goto CONSTRUCTING;
|
||||
send Start goto TEST1;
|
||||
state TEST1: recv Test1 goto TEST2;
|
||||
state TEST2: recv Test2 goto TEST3;
|
||||
state TEST3: recv Test3 goto TEST4;
|
||||
state TEST4: recv Test4 goto TEST5;
|
||||
state TEST5: recv Test5 goto TEST6;
|
||||
state TEST6: recv Test6 goto TEST7;
|
||||
state TEST7: recv Test7 goto TEST8;
|
||||
state TEST8: recv Test8 goto TEST9;
|
||||
state TEST9: recv Test9 goto TEST10;
|
||||
state TEST10: recv Test10 goto TEST11;
|
||||
state TEST11: recv Test11 goto TEST12;
|
||||
state TEST12: recv Test12 goto TEST13;
|
||||
state TEST13: recv Test13 goto TEST14;
|
||||
state TEST14: recv Test14 goto TEST15;
|
||||
state TEST15: recv Test15 goto TEST16;
|
||||
state TEST16: recv Test16 goto TEST17;
|
||||
state TEST17: recv Test17 goto TEST18;
|
||||
state TEST18: recv Test18 goto DEAD;
|
||||
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
107
ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh
Normal file
107
ipc/ipdl/test/cxx/PTestDataStructuresCommon.ipdlh
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
include protocol PTestDataStructuresSub;
|
||||
|
||||
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
|
||||
using nsIntRegion from "nsRegion.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace _foo {
|
||||
|
||||
union IntDouble {
|
||||
int;
|
||||
double;
|
||||
};
|
||||
|
||||
struct SIntDouble {
|
||||
int i;
|
||||
double d;
|
||||
};
|
||||
|
||||
union IntDoubleArrays {
|
||||
int;
|
||||
int[];
|
||||
double[];
|
||||
};
|
||||
|
||||
struct SIntDoubleArrays {
|
||||
int i;
|
||||
int[] ai;
|
||||
double[] ad;
|
||||
};
|
||||
|
||||
struct ActorWrapper {
|
||||
PTestDataStructuresSub actor;
|
||||
};
|
||||
|
||||
union Actors {
|
||||
int;
|
||||
int[];
|
||||
PTestDataStructuresSub[];
|
||||
};
|
||||
|
||||
struct SActors {
|
||||
int i;
|
||||
int[] ai;
|
||||
PTestDataStructuresSub[] ap;
|
||||
};
|
||||
|
||||
union Unions {
|
||||
int;
|
||||
int[];
|
||||
PTestDataStructuresSub[];
|
||||
Actors[];
|
||||
};
|
||||
|
||||
struct Structs {
|
||||
int i;
|
||||
int[] ai;
|
||||
PTestDataStructuresSub[] ap;
|
||||
SActors[] aa;
|
||||
};
|
||||
|
||||
union WithStructs {
|
||||
int;
|
||||
int[];
|
||||
PTestDataStructuresSub[];
|
||||
SActors[];
|
||||
Structs[];
|
||||
};
|
||||
|
||||
struct WithUnions {
|
||||
int i;
|
||||
int[] ai;
|
||||
PTestDataStructuresSub[] ap;
|
||||
Actors[] aa;
|
||||
Unions[] au;
|
||||
};
|
||||
|
||||
struct CommonAttrs { bool dummy; };
|
||||
struct FooAttrs { int dummy; };
|
||||
struct BarAttrs { float dummy; };
|
||||
union SpecificAttrs {
|
||||
FooAttrs;
|
||||
BarAttrs;
|
||||
};
|
||||
struct Attrs {
|
||||
CommonAttrs common;
|
||||
SpecificAttrs specific;
|
||||
};
|
||||
struct SetAttrs {
|
||||
PTestDataStructuresSub x;
|
||||
Attrs attrs;
|
||||
};
|
||||
union Op { null_t; SetAttrs; };
|
||||
|
||||
struct ShmemStruct {
|
||||
int i;
|
||||
Shmem mem;
|
||||
};
|
||||
|
||||
union ShmemUnion {
|
||||
int;
|
||||
Shmem;
|
||||
};
|
||||
|
||||
struct Empty { };
|
||||
|
||||
} // namespace _foo
|
||||
} // namespace mozilla
|
||||
15
ipc/ipdl/test/cxx/PTestDataStructuresSub.ipdl
Normal file
15
ipc/ipdl/test/cxx/PTestDataStructuresSub.ipdl
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
include PTestDataStructuresCommon;
|
||||
include protocol PTestDataStructures;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
sync protocol PTestDataStructuresSub {
|
||||
manager PTestDataStructures;
|
||||
|
||||
parent:
|
||||
sync __delete__();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
21
ipc/ipdl/test/cxx/PTestDemon.ipdl
Normal file
21
ipc/ipdl/test/cxx/PTestDemon.ipdl
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
nested(upto inside_cpow) sync protocol PTestDemon
|
||||
{
|
||||
child:
|
||||
async Start();
|
||||
|
||||
both:
|
||||
async AsyncMessage(int n);
|
||||
nested(inside_sync) sync HiPrioSyncMessage();
|
||||
|
||||
parent:
|
||||
sync SyncMessage(int n);
|
||||
|
||||
nested(inside_cpow) async UrgentAsyncMessage(int n);
|
||||
nested(inside_cpow) sync UrgentSyncMessage(int n);
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
31
ipc/ipdl/test/cxx/PTestDesc.ipdl
Normal file
31
ipc/ipdl/test/cxx/PTestDesc.ipdl
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
include protocol PTestDescSub;
|
||||
include protocol PTestDescSubsub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestDesc {
|
||||
manages PTestDescSub;
|
||||
child:
|
||||
intr PTestDescSub(nullable PTestDescSubsub dummy);
|
||||
|
||||
async Test(PTestDescSubsub a);
|
||||
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
async Ok(PTestDescSubsub a);
|
||||
|
||||
|
||||
state CONSTRUCT:
|
||||
call PTestDescSub goto TEST;
|
||||
state TEST:
|
||||
send Test goto ACK;
|
||||
state ACK:
|
||||
recv Ok goto DEAD;
|
||||
state DEAD:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
18
ipc/ipdl/test/cxx/PTestDescSub.ipdl
Normal file
18
ipc/ipdl/test/cxx/PTestDescSub.ipdl
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
include protocol PTestDesc;
|
||||
include protocol PTestDescSubsub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestDescSub {
|
||||
manager PTestDesc;
|
||||
manages PTestDescSubsub;
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
||||
intr PTestDescSubsub();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
15
ipc/ipdl/test/cxx/PTestDescSubsub.ipdl
Normal file
15
ipc/ipdl/test/cxx/PTestDescSubsub.ipdl
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
include protocol PTestDescSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestDescSubsub {
|
||||
manager PTestDescSub;
|
||||
|
||||
child:
|
||||
intr __delete__();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
23
ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl
Normal file
23
ipc/ipdl/test/cxx/PTestEndpointBridgeMain.ipdl
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
|
||||
include protocol PTestEndpointBridgeMainSub;
|
||||
include protocol PTestEndpointBridgeSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestEndpointBridgeMain {
|
||||
child spawns PTestEndpointBridgeSub;
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
async Bridged(Endpoint<PTestEndpointBridgeMainSubParent> endpoint);
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
25
ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl
Normal file
25
ipc/ipdl/test/cxx/PTestEndpointBridgeMainSub.ipdl
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
|
||||
include protocol PTestEndpointBridgeMain;
|
||||
include protocol PTestEndpointBridgeSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
// (Bridge protocols can have different semantics than the endpoints
|
||||
// they bridge)
|
||||
intr protocol PTestEndpointBridgeMainSub {
|
||||
child:
|
||||
async Hi();
|
||||
intr HiRpc();
|
||||
|
||||
parent:
|
||||
async Hello();
|
||||
sync HelloSync();
|
||||
intr HelloRpc();
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
22
ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl
Normal file
22
ipc/ipdl/test/cxx/PTestEndpointBridgeSub.ipdl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
|
||||
include protocol PTestEndpointBridgeMainSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestEndpointBridgeSub {
|
||||
child:
|
||||
async Ping();
|
||||
|
||||
async Bridged(Endpoint<PTestEndpointBridgeMainSubChild> endpoint);
|
||||
|
||||
parent:
|
||||
async BridgeEm();
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
19
ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl
Normal file
19
ipc/ipdl/test/cxx/PTestEndpointOpens.ipdl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
include protocol PTestEndpointOpensOpened;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestEndpointOpens {
|
||||
child:
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
async StartSubprotocol(Endpoint<PTestEndpointOpensOpenedParent> endpoint);
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
30
ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl
Normal file
30
ipc/ipdl/test/cxx/PTestEndpointOpensOpened.ipdl
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
namespace mozilla {
|
||||
namespace _ipdltest2 {
|
||||
|
||||
// (Opens protocols can have different semantics than the endpoints
|
||||
// that opened them)
|
||||
intr protocol PTestEndpointOpensOpened {
|
||||
child:
|
||||
async Hi();
|
||||
intr HiRpc();
|
||||
|
||||
parent:
|
||||
async Hello();
|
||||
sync HelloSync();
|
||||
intr HelloRpc();
|
||||
async __delete__();
|
||||
|
||||
state START: recv Hello goto HI;
|
||||
state HI: send Hi goto HELLO_SYNC;
|
||||
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
|
||||
state HELLO_RPC: answer HelloRpc goto HI_RPC;
|
||||
state HI_RPC: call HiRpc goto DEAD;
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest2
|
||||
19
ipc/ipdl/test/cxx/PTestFailedCtor.ipdl
Normal file
19
ipc/ipdl/test/cxx/PTestFailedCtor.ipdl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
include protocol PTestFailedCtorSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestFailedCtor {
|
||||
manages PTestFailedCtorSub;
|
||||
child:
|
||||
intr PTestFailedCtorSub();
|
||||
async __delete__();
|
||||
|
||||
state CONSTRUCT:
|
||||
call PTestFailedCtorSub goto DEAD;
|
||||
state DEAD:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
18
ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl
Normal file
18
ipc/ipdl/test/cxx/PTestFailedCtorSub.ipdl
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
include protocol PTestFailedCtor;
|
||||
include protocol PTestFailedCtorSubsub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestFailedCtorSub {
|
||||
manager PTestFailedCtor;
|
||||
manages PTestFailedCtorSubsub;
|
||||
|
||||
parent:
|
||||
async PTestFailedCtorSubsub();
|
||||
sync Sync();
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
15
ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl
Normal file
15
ipc/ipdl/test/cxx/PTestFailedCtorSubsub.ipdl
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
include protocol PTestFailedCtorSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestFailedCtorSubsub {
|
||||
manager PTestFailedCtorSub;
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
14
ipc/ipdl/test/cxx/PTestHandle.ipdl
Normal file
14
ipc/ipdl/test/cxx/PTestHandle.ipdl
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
include protocol PTestJSON;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestHandle {
|
||||
manager PTestJSON;
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
40
ipc/ipdl/test/cxx/PTestHangs.ipdl
Normal file
40
ipc/ipdl/test/cxx/PTestHangs.ipdl
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestHangs {
|
||||
both:
|
||||
intr StackFrame();
|
||||
|
||||
parent:
|
||||
async Nonce();
|
||||
|
||||
child:
|
||||
async Start();
|
||||
intr Hang();
|
||||
async __delete__();
|
||||
|
||||
|
||||
state START:
|
||||
send Start goto RACE;
|
||||
|
||||
state RACE:
|
||||
recv Nonce goto RACE1;
|
||||
call StackFrame goto RACE2;
|
||||
state RACE1:
|
||||
call StackFrame goto FRAME2;
|
||||
state RACE2:
|
||||
recv Nonce goto FRAME2;
|
||||
|
||||
// So as to test unwinding the RPC stack
|
||||
state FRAME2: answer StackFrame goto FRAME3;
|
||||
state FRAME3: call StackFrame goto FRAME4;
|
||||
state FRAME4: answer StackFrame goto HANG;
|
||||
state HANG: call Hang goto DEATH;
|
||||
|
||||
state DEATH:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
18
ipc/ipdl/test/cxx/PTestHighestPrio.ipdl
Normal file
18
ipc/ipdl/test/cxx/PTestHighestPrio.ipdl
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
nested(upto inside_cpow) sync protocol PTestHighestPrio
|
||||
{
|
||||
parent:
|
||||
nested(inside_cpow) async Msg1();
|
||||
nested(inside_sync) sync Msg2();
|
||||
nested(inside_cpow) async Msg3();
|
||||
nested(inside_cpow) sync Msg4();
|
||||
|
||||
child:
|
||||
async Start();
|
||||
nested(inside_sync) sync StartInner();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
15
ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh
Normal file
15
ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
include protocol PTestIndirectProtocolParamSecond;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
struct IndirectParamStruct {
|
||||
PTestIndirectProtocolParamSecond actor;
|
||||
};
|
||||
|
||||
union IndirectParamUnion {
|
||||
IndirectParamStruct;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
19
ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl
Normal file
19
ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
include protocol PTestIndirectProtocolParamManage;
|
||||
// FIXME/bug 792908 protocol PTestIndirectProtocolParamSecond is
|
||||
// already included in PTestIndirectProtocolParam.ipdlh
|
||||
include protocol PTestIndirectProtocolParamSecond;
|
||||
include PTestIndirectProtocolParam;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
sync protocol PTestIndirectProtocolParamFirst {
|
||||
manager PTestIndirectProtocolParamManage;
|
||||
parent:
|
||||
sync Test(IndirectParamUnion actor);
|
||||
both:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
17
ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl
Normal file
17
ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
include protocol PTestIndirectProtocolParamFirst;
|
||||
include protocol PTestIndirectProtocolParamSecond;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
sync protocol PTestIndirectProtocolParamManage {
|
||||
manages PTestIndirectProtocolParamFirst;
|
||||
manages PTestIndirectProtocolParamSecond;
|
||||
both:
|
||||
async PTestIndirectProtocolParamFirst();
|
||||
async PTestIndirectProtocolParamSecond();
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
13
ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl
Normal file
13
ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
include protocol PTestIndirectProtocolParamManage;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
sync protocol PTestIndirectProtocolParamSecond {
|
||||
manager PTestIndirectProtocolParamManage;
|
||||
both:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
11
ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl
Normal file
11
ipc/ipdl/test/cxx/PTestInterruptErrorCleanup.ipdl
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestInterruptErrorCleanup {
|
||||
child:
|
||||
intr Error();
|
||||
intr __delete__();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
82
ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl
Normal file
82
ipc/ipdl/test/cxx/PTestInterruptRaces.ipdl
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestInterruptRaces {
|
||||
both:
|
||||
intr Race() returns (bool hasReply);
|
||||
intr StackFrame() returns ();
|
||||
intr StackFrame3() returns ();
|
||||
|
||||
parent:
|
||||
sync StartRace();
|
||||
intr Parent();
|
||||
sync GetAnsweredParent() returns (bool answeredParent);
|
||||
|
||||
child:
|
||||
async Start();
|
||||
async Wakeup();
|
||||
async Wakeup3();
|
||||
intr Child();
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send Start goto TEST1;
|
||||
|
||||
// First test: race while no other messages are on the Interrupt stack
|
||||
state TEST1:
|
||||
recv StartRace goto RACE1;
|
||||
state RACE1:
|
||||
call Race goto DUMMY1_1;
|
||||
answer Race goto DUMMY1_2;
|
||||
state DUMMY1_1:
|
||||
answer Race goto TEST2;
|
||||
state DUMMY1_2:
|
||||
call Race goto TEST2;
|
||||
|
||||
// Second test: race while other messages are on the Interrupt stack
|
||||
state TEST2:
|
||||
call StackFrame goto MORESTACK;
|
||||
state MORESTACK:
|
||||
answer StackFrame goto STARTRACE;
|
||||
state STARTRACE:
|
||||
send Wakeup goto RACE2;
|
||||
state RACE2:
|
||||
call Race goto DUMMY2_1;
|
||||
answer Race goto DUMMY2_2;
|
||||
state DUMMY2_1:
|
||||
answer Race goto TEST3;
|
||||
state DUMMY2_2:
|
||||
call Race goto TEST3;
|
||||
|
||||
// Third test: resolve race using custom policy
|
||||
state TEST3:
|
||||
call StackFrame3 goto MORESTACK3;
|
||||
state MORESTACK3:
|
||||
answer StackFrame3 goto STARTRACE3;
|
||||
state STARTRACE3:
|
||||
send Wakeup3 goto RACE3;
|
||||
state RACE3:
|
||||
call Child goto DUMMY3_1;
|
||||
answer Parent goto DUMMY3_2;
|
||||
state DUMMY3_1:
|
||||
// the parent receives this from the child in this state
|
||||
recv GetAnsweredParent goto CHECK;
|
||||
// this transition is never taken (if the custom race resolution
|
||||
// works correctly)
|
||||
answer Parent goto CHECK;
|
||||
state DUMMY3_2:
|
||||
call Child goto CHECK;
|
||||
state CHECK:
|
||||
// the child sends this from this state
|
||||
recv GetAnsweredParent goto DYING;
|
||||
// because of deferred processing, the parent receives the child's
|
||||
// message here
|
||||
answer Parent goto DYING;
|
||||
|
||||
|
||||
state DYING:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
34
ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl
Normal file
34
ipc/ipdl/test/cxx/PTestInterruptShutdownRace.ipdl
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestInterruptShutdownRace {
|
||||
parent:
|
||||
sync StartDeath();
|
||||
async Orphan();
|
||||
|
||||
child:
|
||||
async Start();
|
||||
intr Exit();
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send Start goto START_DEATH;
|
||||
|
||||
state START_DEATH:
|
||||
recv StartDeath goto EXITING;
|
||||
|
||||
state EXITING:
|
||||
recv Orphan goto QUITTING1;
|
||||
call Exit goto QUITTING2;
|
||||
|
||||
state QUITTING1:
|
||||
call Exit goto DEAD;
|
||||
state QUITTING2:
|
||||
recv Orphan goto DEAD;
|
||||
|
||||
state DEAD:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
54
ipc/ipdl/test/cxx/PTestJSON.ipdl
Normal file
54
ipc/ipdl/test/cxx/PTestJSON.ipdl
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
include protocol PTestHandle;
|
||||
|
||||
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
union Key {
|
||||
// int;
|
||||
// double;
|
||||
nsString;
|
||||
};
|
||||
|
||||
struct KeyValue {
|
||||
Key key;
|
||||
JSONVariant value;
|
||||
};
|
||||
|
||||
union JSONVariant {
|
||||
void_t;
|
||||
null_t;
|
||||
bool;
|
||||
int;
|
||||
double;
|
||||
nsString;
|
||||
PTestHandle;
|
||||
KeyValue[];
|
||||
JSONVariant[];
|
||||
};
|
||||
|
||||
sync protocol PTestJSON {
|
||||
manages PTestHandle;
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
async PTestHandle();
|
||||
sync Test(JSONVariant i)
|
||||
returns (JSONVariant o);
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send Start goto TEST;
|
||||
|
||||
state TEST:
|
||||
recv PTestHandle goto TEST;
|
||||
recv Test goto TEST;
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
75
ipc/ipdl/test/cxx/PTestLatency.ipdl
Normal file
75
ipc/ipdl/test/cxx/PTestLatency.ipdl
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
intr protocol PTestLatency {
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
async Ping();
|
||||
async Ping5();
|
||||
intr Rpc();
|
||||
async Spam();
|
||||
intr Synchro();
|
||||
async CompressedSpam(uint32_t seqno) compress;
|
||||
intr Synchro2() returns (uint32_t lastSeqno,
|
||||
uint32_t numMessagesDispatched);
|
||||
|
||||
parent:
|
||||
async Pong();
|
||||
async Pong5();
|
||||
|
||||
state START:
|
||||
// if the timing resolution is too low, abort the test
|
||||
send __delete__;
|
||||
// otherwise, kick off the ping/pong trials
|
||||
send Ping goto PONG;
|
||||
|
||||
// Trial 1: single ping/pong latency
|
||||
state PING:
|
||||
send Ping goto PONG;
|
||||
send Ping5 goto PING4;
|
||||
|
||||
state PONG:
|
||||
recv Pong goto PING;
|
||||
|
||||
// Trial 2: "overlapped" ping/pong latency
|
||||
state PING5:
|
||||
send Ping5 goto PING4;
|
||||
call Rpc goto RPC;
|
||||
|
||||
state PING4: send Ping5 goto PING3;
|
||||
state PING3: send Ping5 goto PING2;
|
||||
state PING2: send Ping5 goto PING1;
|
||||
state PING1: send Ping5 goto PONG1;
|
||||
|
||||
state PONG1: recv Pong5 goto PONG2;
|
||||
state PONG2: recv Pong5 goto PONG3;
|
||||
state PONG3: recv Pong5 goto PONG4;
|
||||
state PONG4: recv Pong5 goto PONG5;
|
||||
state PONG5: recv Pong5 goto PING5;
|
||||
|
||||
// Trial 3: lotsa RPC
|
||||
state RPC:
|
||||
call Rpc goto RPC;
|
||||
send Spam goto SPAM;
|
||||
|
||||
// Trial 4: lots of sequential asyn messages, which tests pipelining
|
||||
state SPAM:
|
||||
send Spam goto SPAM;
|
||||
call Synchro goto COMPRESSED_SPAM;
|
||||
|
||||
// Trial 5: lots of async spam, but compressed to cut down on
|
||||
// dispatch overhead
|
||||
state COMPRESSED_SPAM: // compressed spam, mmm
|
||||
send CompressedSpam goto COMPRESSED_SPAM;
|
||||
call Synchro2 goto DONE;
|
||||
|
||||
state DONE:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
19
ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl
Normal file
19
ipc/ipdl/test/cxx/PTestManyChildAllocs.ipdl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
include protocol PTestManyChildAllocsSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestManyChildAllocs {
|
||||
manages PTestManyChildAllocsSub;
|
||||
|
||||
child:
|
||||
async Go(); // start allocating
|
||||
|
||||
parent:
|
||||
async Done();
|
||||
|
||||
async PTestManyChildAllocsSub();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
19
ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl
Normal file
19
ipc/ipdl/test/cxx/PTestManyChildAllocsSub.ipdl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
include protocol PTestManyChildAllocs;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestManyChildAllocsSub {
|
||||
manager PTestManyChildAllocs;
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
async Hello();
|
||||
|
||||
// empty
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
34
ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl
Normal file
34
ipc/ipdl/test/cxx/PTestMultiMgrs.ipdl
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
include protocol PTestMultiMgrsLeft;
|
||||
include protocol PTestMultiMgrsRight;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestMultiMgrs {
|
||||
manages PTestMultiMgrsLeft;
|
||||
manages PTestMultiMgrsRight;
|
||||
|
||||
parent:
|
||||
async OK();
|
||||
|
||||
child:
|
||||
async PTestMultiMgrsLeft();
|
||||
async PTestMultiMgrsRight();
|
||||
async Check();
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send PTestMultiMgrsLeft goto CONSTRUCT_RIGHT;
|
||||
state CONSTRUCT_RIGHT:
|
||||
send PTestMultiMgrsRight goto CHILD_CHECK;
|
||||
state CHILD_CHECK:
|
||||
send Check goto CHILD_ACK;
|
||||
state CHILD_ACK:
|
||||
recv OK goto DONE;
|
||||
|
||||
state DONE:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
18
ipc/ipdl/test/cxx/PTestMultiMgrsBottom.ipdl
Normal file
18
ipc/ipdl/test/cxx/PTestMultiMgrsBottom.ipdl
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
include protocol PTestMultiMgrsLeft;
|
||||
include protocol PTestMultiMgrsRight;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestMultiMgrsBottom {
|
||||
manager PTestMultiMgrsLeft or PTestMultiMgrsRight;
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
||||
state DOA:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
24
ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl
Normal file
24
ipc/ipdl/test/cxx/PTestMultiMgrsLeft.ipdl
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
include protocol PTestMultiMgrs;
|
||||
include protocol PTestMultiMgrsBottom;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestMultiMgrsLeft {
|
||||
manager PTestMultiMgrs;
|
||||
|
||||
manages PTestMultiMgrsBottom;
|
||||
|
||||
child:
|
||||
async PTestMultiMgrsBottom();
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send PTestMultiMgrsBottom goto DONE;
|
||||
|
||||
state DONE:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
24
ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl
Normal file
24
ipc/ipdl/test/cxx/PTestMultiMgrsRight.ipdl
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
include protocol PTestMultiMgrs;
|
||||
include protocol PTestMultiMgrsBottom;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestMultiMgrsRight {
|
||||
manager PTestMultiMgrs;
|
||||
|
||||
manages PTestMultiMgrsBottom;
|
||||
|
||||
child:
|
||||
async PTestMultiMgrsBottom();
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send PTestMultiMgrsBottom goto DONE;
|
||||
|
||||
state DONE:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
34
ipc/ipdl/test/cxx/PTestNestedLoops.ipdl
Normal file
34
ipc/ipdl/test/cxx/PTestNestedLoops.ipdl
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
intr protocol PTestNestedLoops {
|
||||
|
||||
child:
|
||||
async Start();
|
||||
intr R();
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
async Nonce();
|
||||
|
||||
|
||||
state START:
|
||||
send Start goto RACE;
|
||||
|
||||
state RACE:
|
||||
recv Nonce goto RACE1;
|
||||
call R goto RACE2;
|
||||
state RACE1:
|
||||
call R goto DEAD;
|
||||
state RACE2:
|
||||
recv Nonce goto DEAD;
|
||||
|
||||
state DEAD:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
25
ipc/ipdl/test/cxx/PTestOpens.ipdl
Normal file
25
ipc/ipdl/test/cxx/PTestOpens.ipdl
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
include protocol PTestOpensOpened;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestOpens {
|
||||
// This channel is opened and parked on a non-main thread
|
||||
child opens PTestOpensOpened;
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
|
||||
state START:
|
||||
send Start goto DEAD;
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
28
ipc/ipdl/test/cxx/PTestOpensOpened.ipdl
Normal file
28
ipc/ipdl/test/cxx/PTestOpensOpened.ipdl
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest2 {
|
||||
|
||||
// (Opens protocols can have different semantics than the endpoints
|
||||
// that opened them)
|
||||
intr protocol PTestOpensOpened {
|
||||
child:
|
||||
async Hi();
|
||||
intr HiRpc();
|
||||
|
||||
parent:
|
||||
async Hello();
|
||||
sync HelloSync();
|
||||
intr HelloRpc();
|
||||
async __delete__();
|
||||
|
||||
state START: recv Hello goto HI;
|
||||
state HI: send Hi goto HELLO_SYNC;
|
||||
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
|
||||
state HELLO_RPC: answer HelloRpc goto HI_RPC;
|
||||
state HI_RPC: call HiRpc goto DEAD;
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest2
|
||||
14
ipc/ipdl/test/cxx/PTestPriority.ipdl
Normal file
14
ipc/ipdl/test/cxx/PTestPriority.ipdl
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
sync protocol PTestPriority {
|
||||
parent:
|
||||
prio(high) async Msg1();
|
||||
prio(high) sync Msg2();
|
||||
|
||||
child:
|
||||
prio(high) async Msg3();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
21
ipc/ipdl/test/cxx/PTestRPC.ipdl
Normal file
21
ipc/ipdl/test/cxx/PTestRPC.ipdl
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
nested(upto inside_sync) sync protocol PTestRPC
|
||||
{
|
||||
parent:
|
||||
nested(inside_sync) sync Test1_Start() returns (uint32_t result);
|
||||
nested(inside_sync) sync Test1_InnerEvent() returns (uint32_t result);
|
||||
async Test2_Start();
|
||||
nested(inside_sync) sync Test2_OutOfOrder();
|
||||
|
||||
child:
|
||||
async Start();
|
||||
nested(inside_sync) sync Test1_InnerQuery() returns (uint32_t result);
|
||||
nested(inside_sync) sync Test1_NoReenter() returns (uint32_t result);
|
||||
nested(inside_sync) sync Test2_FirstUrgent();
|
||||
nested(inside_sync) sync Test2_SecondUrgent();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
20
ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl
Normal file
20
ipc/ipdl/test/cxx/PTestRaceDeadlock.ipdl
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestRaceDeadlock {
|
||||
both:
|
||||
async StartRace();
|
||||
|
||||
parent:
|
||||
intr Lose();
|
||||
|
||||
child:
|
||||
intr Win();
|
||||
intr Rpc();
|
||||
async __delete__();
|
||||
|
||||
/* Tests that race resolution does not cause deadlocks */
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
45
ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl
Normal file
45
ipc/ipdl/test/cxx/PTestRaceDeferral.ipdl
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestRaceDeferral {
|
||||
parent:
|
||||
intr Lose();
|
||||
|
||||
child:
|
||||
async StartRace();
|
||||
intr Win();
|
||||
intr Rpc();
|
||||
async __delete__();
|
||||
|
||||
// Test that messages deferred due to race resolution are
|
||||
// re-considered when the winner makes later RPCs
|
||||
|
||||
// IPDL's type system can't express this protocol because the race
|
||||
// resolution causes state to diverge for multiple steps, so we'll
|
||||
// leave it "stateless"
|
||||
/*
|
||||
state START:
|
||||
send StartRace goto DEFER;
|
||||
state DEFER:
|
||||
call Win goto PARENT;
|
||||
answer Lose goto CHILD;
|
||||
|
||||
state PARENT:
|
||||
// 'Lose' is received here but deferred
|
||||
call Rpc goto PARENT_LOSE;
|
||||
state PARENT_LOSE:
|
||||
// Calling 'Rpc' undefers 'Lose', and it wins the "race" with 'Rpc'
|
||||
answer Lose goto DONE;
|
||||
|
||||
state CHILD:
|
||||
call Win goto CHILD_RPC;
|
||||
state CHILD_RPC:
|
||||
call Rpc goto DONE;
|
||||
|
||||
state DONE:
|
||||
send __delete__;
|
||||
*/
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
41
ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl
Normal file
41
ipc/ipdl/test/cxx/PTestRacyInterruptReplies.ipdl
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestRacyInterruptReplies {
|
||||
child:
|
||||
intr R_() returns (int replyNum);
|
||||
async _A();
|
||||
async ChildTest();
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
intr _R() returns (int replyNum);
|
||||
async A_();
|
||||
|
||||
state PARENT_START:
|
||||
call R_ goto PARENT_S1;
|
||||
|
||||
state PARENT_S1:
|
||||
recv A_ goto PARENT_S2;
|
||||
|
||||
state PARENT_S2:
|
||||
call R_ goto CHILD_TEST;
|
||||
|
||||
state CHILD_TEST:
|
||||
send ChildTest goto CHILD_START;
|
||||
|
||||
state CHILD_START:
|
||||
answer _R goto CHILD_S1;
|
||||
|
||||
state CHILD_S1:
|
||||
send _A goto CHILD_S2;
|
||||
|
||||
state CHILD_S2:
|
||||
answer _R goto DYING;
|
||||
|
||||
state DYING:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
21
ipc/ipdl/test/cxx/PTestRacyReentry.ipdl
Normal file
21
ipc/ipdl/test/cxx/PTestRacyReentry.ipdl
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
intr protocol PTestRacyReentry {
|
||||
|
||||
parent:
|
||||
intr E();
|
||||
async __delete__();
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
async N();
|
||||
intr H();
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
28
ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl
Normal file
28
ipc/ipdl/test/cxx/PTestRacyUndefer.ipdl
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
intr protocol PTestRacyUndefer {
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
async AwakenSpam();
|
||||
async AwakenRaceWinTwice();
|
||||
|
||||
intr Race();
|
||||
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
|
||||
intr Spam();
|
||||
intr RaceWinTwice();
|
||||
|
||||
async Done();
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
28
ipc/ipdl/test/cxx/PTestSanity.ipdl
Normal file
28
ipc/ipdl/test/cxx/PTestSanity.ipdl
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestSanity {
|
||||
|
||||
child:
|
||||
async Ping(int zero, float zeroPtFive, int8_t dummy);
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
async Pong(int one, float zeroPtTwoFive, uint8_t dummy);
|
||||
|
||||
|
||||
state PING:
|
||||
send Ping goto PONG;
|
||||
|
||||
state PONG:
|
||||
recv Pong goto DEAD;
|
||||
|
||||
state DEAD:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
22
ipc/ipdl/test/cxx/PTestSelfManage.ipdl
Normal file
22
ipc/ipdl/test/cxx/PTestSelfManage.ipdl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
include protocol PTestSelfManageRoot;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestSelfManage {
|
||||
manager PTestSelfManageRoot or PTestSelfManage;
|
||||
manages PTestSelfManage;
|
||||
|
||||
child:
|
||||
async PTestSelfManage();
|
||||
async __delete__();
|
||||
|
||||
state LIVE:
|
||||
send PTestSelfManage goto LIVE;
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
23
ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl
Normal file
23
ipc/ipdl/test/cxx/PTestSelfManageRoot.ipdl
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
include protocol PTestSelfManage;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestSelfManageRoot {
|
||||
manages PTestSelfManage;
|
||||
|
||||
child:
|
||||
async PTestSelfManage();
|
||||
async __delete__();
|
||||
|
||||
state LIVE:
|
||||
send PTestSelfManage goto DEAD;
|
||||
|
||||
state DEAD:
|
||||
send __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
22
ipc/ipdl/test/cxx/PTestShmem.ipdl
Normal file
22
ipc/ipdl/test/cxx/PTestShmem.ipdl
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
protocol PTestShmem {
|
||||
child:
|
||||
async Give(Shmem mem, Shmem unsafe, size_t expectedSize);
|
||||
|
||||
parent:
|
||||
async Take(Shmem mem, Shmem unsafe, size_t expectedSize);
|
||||
async __delete__();
|
||||
|
||||
|
||||
state GIVING:
|
||||
send Give goto TAKING;
|
||||
|
||||
state TAKING:
|
||||
recv Take goto TAKING;
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
37
ipc/ipdl/test/cxx/PTestShutdown.ipdl
Normal file
37
ipc/ipdl/test/cxx/PTestShutdown.ipdl
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
include protocol PTestShutdownSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestShutdown {
|
||||
manages PTestShutdownSub;
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
// NB: we test deletion and crashing only, not shutdown, because
|
||||
// crashing is the same code path as shutdown, and other IPDL unit
|
||||
// tests check shutdown semantics
|
||||
async PTestShutdownSub(bool expectCrash);
|
||||
|
||||
// Used to synchronize between parent and child, to avoid races
|
||||
// around flushing socket write queues
|
||||
sync Sync();
|
||||
|
||||
async __delete__();
|
||||
|
||||
|
||||
state START:
|
||||
send Start goto TESTING;
|
||||
|
||||
state TESTING:
|
||||
recv PTestShutdownSub goto TESTING;
|
||||
recv Sync goto DYING;
|
||||
|
||||
state DYING:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
30
ipc/ipdl/test/cxx/PTestShutdownSub.ipdl
Normal file
30
ipc/ipdl/test/cxx/PTestShutdownSub.ipdl
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
include protocol PTestShutdown;
|
||||
include protocol PTestShutdownSubsub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestShutdownSub {
|
||||
manager PTestShutdown;
|
||||
manages PTestShutdownSubsub;
|
||||
|
||||
both:
|
||||
intr StackFrame();
|
||||
|
||||
parent:
|
||||
async PTestShutdownSubsub(bool expectParentDeleted);
|
||||
sync __delete__();
|
||||
|
||||
state CREATING:
|
||||
recv PTestShutdownSubsub goto CREATING;
|
||||
answer StackFrame goto DUMMYFRAME;
|
||||
|
||||
state DUMMYFRAME:
|
||||
call StackFrame goto DEAD;
|
||||
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
17
ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl
Normal file
17
ipc/ipdl/test/cxx/PTestShutdownSubsub.ipdl
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
include protocol PTestShutdownSub;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
sync protocol PTestShutdownSubsub {
|
||||
manager PTestShutdownSub;
|
||||
|
||||
parent:
|
||||
sync __delete__();
|
||||
|
||||
state LIVE:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
56
ipc/ipdl/test/cxx/PTestStackHooks.ipdl
Normal file
56
ipc/ipdl/test/cxx/PTestStackHooks.ipdl
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
intr protocol PTestStackHooks {
|
||||
child:
|
||||
async Start();
|
||||
|
||||
// These tests are more fruitful running child->parent, because
|
||||
// children can send |sync| messages
|
||||
parent:
|
||||
async Async();
|
||||
sync Sync();
|
||||
intr Rpc();
|
||||
|
||||
both:
|
||||
intr StackFrame();
|
||||
|
||||
parent:
|
||||
async __delete__();
|
||||
|
||||
|
||||
state START:
|
||||
send Start goto TEST1;
|
||||
|
||||
state TEST1:
|
||||
recv Async goto TEST2;
|
||||
|
||||
state TEST2:
|
||||
recv Sync goto TEST3;
|
||||
|
||||
state TEST3:
|
||||
answer Rpc goto TEST4;
|
||||
|
||||
state TEST4:
|
||||
answer StackFrame goto TEST4_2;
|
||||
state TEST4_2:
|
||||
call StackFrame goto TEST4_3;
|
||||
state TEST4_3:
|
||||
recv Async goto TEST5;
|
||||
|
||||
state TEST5:
|
||||
answer StackFrame goto TEST5_2;
|
||||
state TEST5_2:
|
||||
call StackFrame goto TEST5_3;
|
||||
state TEST5_3:
|
||||
recv Sync goto DEAD;
|
||||
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
28
ipc/ipdl/test/cxx/PTestSyncError.ipdl
Normal file
28
ipc/ipdl/test/cxx/PTestSyncError.ipdl
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
sync protocol PTestSyncError {
|
||||
|
||||
child:
|
||||
async Start();
|
||||
|
||||
parent:
|
||||
sync Error();
|
||||
async __delete__();
|
||||
|
||||
|
||||
state START:
|
||||
send Start goto SYNC_ERROR;
|
||||
|
||||
state SYNC_ERROR:
|
||||
recv Error goto DEAD;
|
||||
|
||||
state DEAD:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
15
ipc/ipdl/test/cxx/PTestSyncHang.ipdl
Normal file
15
ipc/ipdl/test/cxx/PTestSyncHang.ipdl
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
protocol PTestSyncHang {
|
||||
|
||||
child:
|
||||
async __delete__();
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
41
ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl
Normal file
41
ipc/ipdl/test/cxx/PTestSyncWakeup.ipdl
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
intr protocol PTestSyncWakeup {
|
||||
both:
|
||||
intr StackFrame();
|
||||
|
||||
child:
|
||||
async Start();
|
||||
async Note1();
|
||||
async Note2();
|
||||
|
||||
parent:
|
||||
sync Sync1();
|
||||
sync Sync2();
|
||||
async __delete__();
|
||||
|
||||
|
||||
state START:
|
||||
send Start goto TEST1;
|
||||
|
||||
state TEST1:
|
||||
recv Sync1 goto TEST1_P2;
|
||||
state TEST1_P2:
|
||||
send Note1 goto TEST2;
|
||||
|
||||
state TEST2:
|
||||
answer StackFrame goto TEST2_P2;
|
||||
state TEST2_P2:
|
||||
call StackFrame goto TEST2_P3;
|
||||
state TEST2_P3:
|
||||
recv Sync2 goto TEST2_P4;
|
||||
state TEST2_P4:
|
||||
send Note2 goto DONE;
|
||||
|
||||
state DONE:
|
||||
recv __delete__;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
19
ipc/ipdl/test/cxx/PTestUrgency.ipdl
Normal file
19
ipc/ipdl/test/cxx/PTestUrgency.ipdl
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
nested(upto inside_cpow) sync protocol PTestUrgency
|
||||
{
|
||||
parent:
|
||||
nested(inside_sync) sync Test1() returns (uint32_t result);
|
||||
async Test2();
|
||||
sync Test3() returns (uint32_t result);
|
||||
sync FinalTest_Begin();
|
||||
|
||||
child:
|
||||
async Start();
|
||||
nested(inside_sync) sync Reply1() returns (uint32_t result);
|
||||
nested(inside_sync) sync Reply2() returns (uint32_t result);
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
28
ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl
Normal file
28
ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
nested(upto inside_cpow) sync protocol PTestUrgentHangs
|
||||
{
|
||||
parent:
|
||||
nested(inside_sync) sync Test1_2();
|
||||
|
||||
nested(inside_sync) sync TestInner();
|
||||
nested(inside_cpow) sync TestInnerUrgent();
|
||||
|
||||
child:
|
||||
nested(inside_sync) sync Test1_1();
|
||||
nested(inside_sync) sync Test1_3();
|
||||
|
||||
nested(inside_sync) sync Test2();
|
||||
|
||||
nested(inside_sync) sync Test3();
|
||||
|
||||
async Test4();
|
||||
nested(inside_sync) sync Test4_1();
|
||||
|
||||
async Test5();
|
||||
nested(inside_sync) sync Test5_1();
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
61
ipc/ipdl/test/cxx/README.txt
Normal file
61
ipc/ipdl/test/cxx/README.txt
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
To add a new IPDL C++ unit test, you need to create (at least) the
|
||||
following files (for a test "TestFoo"):
|
||||
|
||||
- PTestFoo.ipdl, specifying the top-level protocol used for the test
|
||||
|
||||
- TestFoo.h, declaring the top-level parent/child actors used for
|
||||
the test
|
||||
|
||||
- TestFoo.cpp, defining the top-level actors
|
||||
|
||||
- (make sure all are in the namespace mozilla::_ipdltest)
|
||||
|
||||
Next
|
||||
|
||||
- add PTestFoo.ipdl to ipdl.mk
|
||||
|
||||
- append TestFoo to the variable IPDLTESTS in Makefile.in
|
||||
|
||||
You must define three methods in your |TestFooParent| class:
|
||||
|
||||
- static methods |bool RunTestInProcesses()| and
|
||||
|bool RunTestInThreads()|. These methods control whether
|
||||
to execute the test using actors in separate processes and
|
||||
threads respectively. Generally, both should return true.
|
||||
|
||||
- an instance method |void Main()|. The test harness wil first
|
||||
initialize the processes or threads, create and open both actors,
|
||||
and then kick off the test using |Main()|. Make sure you define
|
||||
it.
|
||||
|
||||
If your test passes its criteria, please call
|
||||
|MOZ_IPDL_TESTPASS("msg")| and "exit gracefully".
|
||||
|
||||
If your tests fails, please call |MOZ_IPDL_TESTFAIL("msg")| and "exit
|
||||
ungracefully", preferably by abort()ing.
|
||||
|
||||
|
||||
If all goes well, running
|
||||
|
||||
make -C $OBJDIR/ipc/ipdl/test/cxx
|
||||
|
||||
will update the file IPDLUnitTests.cpp (the test launcher), and your
|
||||
new code will be built automatically.
|
||||
|
||||
|
||||
You can launch your new test by invoking one of
|
||||
|
||||
make -C $OBJDIR/ipc/ipdl/test/cxx check-proc (test process-based tests)
|
||||
make -C $OBJDIR/ipc/ipdl/test/cxx check-threads (test thread-based tests)
|
||||
make -C $OBJDIR/ipc/ipdl/test/cxx check (tests both)
|
||||
|
||||
If you want to launch only your test, run
|
||||
|
||||
cd $OBJDIR/dist/bin
|
||||
./run-mozilla.sh ./ipdlunittest TestFoo (test in two processes, if appl.)
|
||||
./run-mozilla.sh ./ipdlunittest thread:TestFoo (test in two threads, if appl.)
|
||||
|
||||
|
||||
For a bare-bones example of adding a test, take a look at
|
||||
PTestSanity.ipdl, TestSanity.h, TestSanity.cpp, and how "TestSanity"
|
||||
is included in ipdl.mk and Makefile.in.
|
||||
128
ipc/ipdl/test/cxx/TestActorPunning.cpp
Normal file
128
ipc/ipdl/test/cxx/TestActorPunning.cpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#include "TestActorPunning.h"
|
||||
|
||||
#include "IPDLUnitTests.h" // fail etc.
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// parent
|
||||
|
||||
void
|
||||
TestActorPunningParent::Main()
|
||||
{
|
||||
if (!SendStart())
|
||||
fail("sending Start");
|
||||
}
|
||||
|
||||
bool
|
||||
TestActorPunningParent::RecvPun(PTestActorPunningSubParent* a, const Bad& bad)
|
||||
{
|
||||
if (a->SendBad())
|
||||
fail("bad!");
|
||||
fail("shouldn't have received this message in the first place");
|
||||
return true;
|
||||
}
|
||||
|
||||
PTestActorPunningPunnedParent*
|
||||
TestActorPunningParent::AllocPTestActorPunningPunnedParent()
|
||||
{
|
||||
return new TestActorPunningPunnedParent();
|
||||
}
|
||||
|
||||
bool
|
||||
TestActorPunningParent::DeallocPTestActorPunningPunnedParent(PTestActorPunningPunnedParent* a)
|
||||
{
|
||||
delete a;
|
||||
return true;
|
||||
}
|
||||
|
||||
PTestActorPunningSubParent*
|
||||
TestActorPunningParent::AllocPTestActorPunningSubParent()
|
||||
{
|
||||
return new TestActorPunningSubParent();
|
||||
}
|
||||
|
||||
bool
|
||||
TestActorPunningParent::DeallocPTestActorPunningSubParent(PTestActorPunningSubParent* a)
|
||||
{
|
||||
delete a;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// child
|
||||
|
||||
PTestActorPunningPunnedChild*
|
||||
TestActorPunningChild::AllocPTestActorPunningPunnedChild()
|
||||
{
|
||||
return new TestActorPunningPunnedChild();
|
||||
}
|
||||
|
||||
bool
|
||||
TestActorPunningChild::DeallocPTestActorPunningPunnedChild(PTestActorPunningPunnedChild*)
|
||||
{
|
||||
fail("should have died by now");
|
||||
return true;
|
||||
}
|
||||
|
||||
PTestActorPunningSubChild*
|
||||
TestActorPunningChild::AllocPTestActorPunningSubChild()
|
||||
{
|
||||
return new TestActorPunningSubChild();
|
||||
}
|
||||
|
||||
bool
|
||||
TestActorPunningChild::DeallocPTestActorPunningSubChild(PTestActorPunningSubChild*)
|
||||
{
|
||||
fail("should have died by now");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestActorPunningChild::RecvStart()
|
||||
{
|
||||
SendPTestActorPunningSubConstructor();
|
||||
SendPTestActorPunningPunnedConstructor();
|
||||
PTestActorPunningSubChild* a = SendPTestActorPunningSubConstructor();
|
||||
// We can't assert whether this succeeds or fails, due to race
|
||||
// conditions.
|
||||
SendPun(a, Bad());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestActorPunningSubChild::RecvBad()
|
||||
{
|
||||
fail("things are going really badly right now");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
using namespace mozilla::_ipdltest;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
/*static*/ void
|
||||
ParamTraits<Bad>::Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
// Skip past the sentinel for the actor as well as the actor.
|
||||
int32_t* ptr = aMsg->GetInt32PtrForTest(2 * sizeof(int32_t));
|
||||
ActorHandle* ah = reinterpret_cast<ActorHandle*>(ptr);
|
||||
if (ah->mId != -3)
|
||||
fail("guessed wrong offset (value is %d, should be -3)", ah->mId);
|
||||
ah->mId = -2;
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
ParamTraits<Bad>::Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
110
ipc/ipdl/test/cxx/TestActorPunning.h
Normal file
110
ipc/ipdl/test/cxx/TestActorPunning.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
#ifndef mozilla__ipdltest_TestActorPunning_h
|
||||
#define mozilla__ipdltest_TestActorPunning_h 1
|
||||
|
||||
#include "mozilla/_ipdltest/IPDLUnitTests.h"
|
||||
|
||||
#include "mozilla/_ipdltest/PTestActorPunningParent.h"
|
||||
#include "mozilla/_ipdltest/PTestActorPunningPunnedParent.h"
|
||||
#include "mozilla/_ipdltest/PTestActorPunningSubParent.h"
|
||||
#include "mozilla/_ipdltest/PTestActorPunningChild.h"
|
||||
#include "mozilla/_ipdltest/PTestActorPunningPunnedChild.h"
|
||||
#include "mozilla/_ipdltest/PTestActorPunningSubChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
class TestActorPunningParent :
|
||||
public PTestActorPunningParent
|
||||
{
|
||||
public:
|
||||
static bool RunTestInProcesses() { return true; }
|
||||
static bool RunTestInThreads() { return false; }
|
||||
|
||||
void Main();
|
||||
|
||||
protected:
|
||||
PTestActorPunningPunnedParent* AllocPTestActorPunningPunnedParent() override;
|
||||
bool DeallocPTestActorPunningPunnedParent(PTestActorPunningPunnedParent* a) override;
|
||||
|
||||
PTestActorPunningSubParent* AllocPTestActorPunningSubParent() override;
|
||||
bool DeallocPTestActorPunningSubParent(PTestActorPunningSubParent* a) override;
|
||||
|
||||
virtual bool RecvPun(PTestActorPunningSubParent* a, const Bad& bad) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override
|
||||
{
|
||||
if (NormalShutdown == why)
|
||||
fail("should have died from error!");
|
||||
passed("ok");
|
||||
QuitParent();
|
||||
}
|
||||
};
|
||||
|
||||
class TestActorPunningPunnedParent :
|
||||
public PTestActorPunningPunnedParent
|
||||
{
|
||||
public:
|
||||
TestActorPunningPunnedParent() {}
|
||||
virtual ~TestActorPunningPunnedParent() {}
|
||||
protected:
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override {}
|
||||
};
|
||||
|
||||
class TestActorPunningSubParent :
|
||||
public PTestActorPunningSubParent
|
||||
{
|
||||
public:
|
||||
TestActorPunningSubParent() {}
|
||||
virtual ~TestActorPunningSubParent() {}
|
||||
protected:
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override {}
|
||||
};
|
||||
|
||||
|
||||
class TestActorPunningChild :
|
||||
public PTestActorPunningChild
|
||||
{
|
||||
public:
|
||||
TestActorPunningChild() {}
|
||||
virtual ~TestActorPunningChild() {}
|
||||
|
||||
protected:
|
||||
PTestActorPunningPunnedChild* AllocPTestActorPunningPunnedChild() override;
|
||||
bool DeallocPTestActorPunningPunnedChild(PTestActorPunningPunnedChild* a) override;
|
||||
|
||||
PTestActorPunningSubChild* AllocPTestActorPunningSubChild() override;
|
||||
bool DeallocPTestActorPunningSubChild(PTestActorPunningSubChild* a) override;
|
||||
|
||||
virtual bool RecvStart() override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override
|
||||
{
|
||||
fail("should have been killed off!");
|
||||
}
|
||||
};
|
||||
|
||||
class TestActorPunningPunnedChild :
|
||||
public PTestActorPunningPunnedChild
|
||||
{
|
||||
public:
|
||||
TestActorPunningPunnedChild() {}
|
||||
virtual ~TestActorPunningPunnedChild() {}
|
||||
};
|
||||
|
||||
class TestActorPunningSubChild :
|
||||
public PTestActorPunningSubChild
|
||||
{
|
||||
public:
|
||||
TestActorPunningSubChild() {}
|
||||
virtual ~TestActorPunningSubChild() {}
|
||||
|
||||
virtual bool RecvBad() override;
|
||||
};
|
||||
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // ifndef mozilla__ipdltest_TestActorPunning_h
|
||||
51
ipc/ipdl/test/cxx/TestBadActor.cpp
Normal file
51
ipc/ipdl/test/cxx/TestBadActor.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include "TestBadActor.h"
|
||||
#include "IPDLUnitTests.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
void
|
||||
TestBadActorParent::Main()
|
||||
{
|
||||
// This test is designed to test a race condition where the child sends us
|
||||
// a message on an actor that we've already destroyed. The child process
|
||||
// should die, and the parent process should not abort.
|
||||
|
||||
PTestBadActorSubParent* child = SendPTestBadActorSubConstructor();
|
||||
if (!child)
|
||||
fail("Sending constructor");
|
||||
|
||||
Unused << child->Call__delete__(child);
|
||||
}
|
||||
|
||||
PTestBadActorSubParent*
|
||||
TestBadActorParent::AllocPTestBadActorSubParent()
|
||||
{
|
||||
return new TestBadActorSubParent();
|
||||
}
|
||||
|
||||
bool
|
||||
TestBadActorSubParent::RecvPing()
|
||||
{
|
||||
fail("Shouldn't have received ping.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PTestBadActorSubChild*
|
||||
TestBadActorChild::AllocPTestBadActorSubChild()
|
||||
{
|
||||
return new TestBadActorSubChild();
|
||||
}
|
||||
|
||||
bool
|
||||
TestBadActorChild::RecvPTestBadActorSubConstructor(PTestBadActorSubChild* actor)
|
||||
{
|
||||
if (!actor->SendPing()) {
|
||||
fail("Couldn't send ping to an actor which supposedly isn't dead yet.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
91
ipc/ipdl/test/cxx/TestBadActor.h
Normal file
91
ipc/ipdl/test/cxx/TestBadActor.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#ifndef mozilla__ipdltest_TestBadActor_h
|
||||
#define mozilla__ipdltest_TestBadActor_h
|
||||
|
||||
#include "mozilla/_ipdltest/IPDLUnitTests.h"
|
||||
|
||||
#include "mozilla/_ipdltest/PTestBadActorParent.h"
|
||||
#include "mozilla/_ipdltest/PTestBadActorChild.h"
|
||||
|
||||
#include "mozilla/_ipdltest/PTestBadActorSubParent.h"
|
||||
#include "mozilla/_ipdltest/PTestBadActorSubChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
class TestBadActorParent
|
||||
: public PTestBadActorParent
|
||||
{
|
||||
public:
|
||||
TestBadActorParent() { }
|
||||
virtual ~TestBadActorParent() { }
|
||||
|
||||
static bool RunTestInProcesses() { return true; }
|
||||
static bool RunTestInThreads() { return false; }
|
||||
|
||||
void Main();
|
||||
|
||||
protected:
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override
|
||||
{
|
||||
if (AbnormalShutdown != why)
|
||||
fail("unexpected destruction");
|
||||
passed("ok");
|
||||
QuitParent();
|
||||
}
|
||||
|
||||
virtual PTestBadActorSubParent*
|
||||
AllocPTestBadActorSubParent();
|
||||
|
||||
virtual bool
|
||||
DeallocPTestBadActorSubParent(PTestBadActorSubParent* actor) {
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class TestBadActorSubParent
|
||||
: public PTestBadActorSubParent
|
||||
{
|
||||
public:
|
||||
TestBadActorSubParent() { }
|
||||
virtual ~TestBadActorSubParent() { }
|
||||
|
||||
protected:
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override {}
|
||||
virtual bool RecvPing();
|
||||
};
|
||||
|
||||
class TestBadActorChild
|
||||
: public PTestBadActorChild
|
||||
{
|
||||
public:
|
||||
TestBadActorChild() { }
|
||||
virtual ~TestBadActorChild() { }
|
||||
|
||||
protected:
|
||||
virtual PTestBadActorSubChild*
|
||||
AllocPTestBadActorSubChild();
|
||||
|
||||
virtual bool
|
||||
DeallocPTestBadActorSubChild(PTestBadActorSubChild* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvPTestBadActorSubConstructor(PTestBadActorSubChild* actor);
|
||||
};
|
||||
|
||||
class TestBadActorSubChild
|
||||
: public PTestBadActorSubChild
|
||||
{
|
||||
public:
|
||||
TestBadActorSubChild() { }
|
||||
virtual ~TestBadActorSubChild() { }
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla__ipdltest_TestBadActor_h
|
||||
227
ipc/ipdl/test/cxx/TestBridgeMain.cpp
Normal file
227
ipc/ipdl/test/cxx/TestBridgeMain.cpp
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
#include "TestBridgeMain.h"
|
||||
|
||||
#include "base/task.h"
|
||||
#include "IPDLUnitTests.h" // fail etc.
|
||||
#include "IPDLUnitTestSubprocess.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// main process
|
||||
void
|
||||
TestBridgeMainParent::Main()
|
||||
{
|
||||
if (!SendStart())
|
||||
fail("sending Start");
|
||||
}
|
||||
|
||||
PTestBridgeMainSubParent*
|
||||
TestBridgeMainParent::AllocPTestBridgeMainSubParent(Transport* transport,
|
||||
ProcessId otherPid)
|
||||
{
|
||||
nsAutoPtr<TestBridgeMainSubParent> a(new TestBridgeMainSubParent(transport));
|
||||
if (!a->Open(transport, otherPid, XRE_GetIOMessageLoop(), ipc::ParentSide)) {
|
||||
return nullptr;
|
||||
}
|
||||
return a.forget();
|
||||
}
|
||||
|
||||
void
|
||||
TestBridgeMainParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (NormalShutdown != why)
|
||||
fail("unexpected destruction!");
|
||||
passed("ok");
|
||||
QuitParent();
|
||||
}
|
||||
|
||||
bool
|
||||
TestBridgeMainSubParent::RecvHello()
|
||||
{
|
||||
return SendHi();
|
||||
}
|
||||
|
||||
bool
|
||||
TestBridgeMainSubParent::RecvHelloSync()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestBridgeMainSubParent::AnswerHelloRpc()
|
||||
{
|
||||
return CallHiRpc();
|
||||
}
|
||||
|
||||
void
|
||||
TestBridgeMainSubParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (NormalShutdown != why)
|
||||
fail("unexpected destruction!");
|
||||
|
||||
// ActorDestroy() is just a callback from IPDL-generated code,
|
||||
// which needs the top-level actor (this) to stay alive a little
|
||||
// longer so other things can be cleaned up.
|
||||
MessageLoop::current()->PostTask(
|
||||
do_AddRef(new DeleteTask<TestBridgeMainSubParent>(this)));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// sub process --- child of main
|
||||
TestBridgeMainChild* gBridgeMainChild;
|
||||
|
||||
TestBridgeMainChild::TestBridgeMainChild()
|
||||
: mSubprocess(nullptr)
|
||||
{
|
||||
gBridgeMainChild = this;
|
||||
}
|
||||
|
||||
bool
|
||||
TestBridgeMainChild::RecvStart()
|
||||
{
|
||||
vector<string> subsubArgs;
|
||||
subsubArgs.push_back("TestBridgeSub");
|
||||
|
||||
mSubprocess = new IPDLUnitTestSubprocess();
|
||||
if (!mSubprocess->SyncLaunch(subsubArgs))
|
||||
fail("problem launching subprocess");
|
||||
|
||||
IPC::Channel* transport = mSubprocess->GetChannel();
|
||||
if (!transport)
|
||||
fail("no transport");
|
||||
|
||||
TestBridgeSubParent* bsp = new TestBridgeSubParent();
|
||||
bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle()));
|
||||
|
||||
bsp->Main();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TestBridgeMainChild::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (NormalShutdown != why)
|
||||
fail("unexpected destruction!");
|
||||
// NB: this is kosher because QuitChild() joins with the IO thread
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
do_AddRef(new DeleteTask<IPDLUnitTestSubprocess>(mSubprocess)));
|
||||
QuitChild();
|
||||
}
|
||||
|
||||
void
|
||||
TestBridgeSubParent::Main()
|
||||
{
|
||||
if (!SendPing())
|
||||
fail("sending Ping");
|
||||
}
|
||||
|
||||
bool
|
||||
TestBridgeSubParent::RecvBridgeEm()
|
||||
{
|
||||
if (NS_FAILED(PTestBridgeMainSub::Bridge(gBridgeMainChild, this)))
|
||||
fail("bridging Main and Sub");
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TestBridgeSubParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (NormalShutdown != why)
|
||||
fail("unexpected destruction!");
|
||||
gBridgeMainChild->Close();
|
||||
|
||||
// ActorDestroy() is just a callback from IPDL-generated code,
|
||||
// which needs the top-level actor (this) to stay alive a little
|
||||
// longer so other things can be cleaned up.
|
||||
MessageLoop::current()->PostTask(
|
||||
do_AddRef(new DeleteTask<TestBridgeSubParent>(this)));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// subsub process --- child of sub
|
||||
|
||||
static TestBridgeSubChild* gBridgeSubChild;
|
||||
|
||||
TestBridgeSubChild::TestBridgeSubChild()
|
||||
{
|
||||
gBridgeSubChild = this;
|
||||
}
|
||||
|
||||
bool
|
||||
TestBridgeSubChild::RecvPing()
|
||||
{
|
||||
if (!SendBridgeEm())
|
||||
fail("sending BridgeEm");
|
||||
return true;
|
||||
}
|
||||
|
||||
PTestBridgeMainSubChild*
|
||||
TestBridgeSubChild::AllocPTestBridgeMainSubChild(Transport* transport,
|
||||
ProcessId otherPid)
|
||||
{
|
||||
nsAutoPtr<TestBridgeMainSubChild> a(new TestBridgeMainSubChild(transport));
|
||||
if (!a->Open(transport, otherPid, XRE_GetIOMessageLoop(), ipc::ChildSide)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!a->SendHello())
|
||||
fail("sending Hello");
|
||||
|
||||
return a.forget();
|
||||
}
|
||||
|
||||
void
|
||||
TestBridgeSubChild::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (NormalShutdown != why)
|
||||
fail("unexpected destruction!");
|
||||
QuitChild();
|
||||
}
|
||||
|
||||
bool
|
||||
TestBridgeMainSubChild::RecvHi()
|
||||
{
|
||||
if (!SendHelloSync())
|
||||
fail("sending HelloSync");
|
||||
if (!CallHelloRpc())
|
||||
fail("calling HelloRpc");
|
||||
if (!mGotHi)
|
||||
fail("didn't answer HiRpc");
|
||||
|
||||
// Need to close the channel without message-processing frames on
|
||||
// the C++ stack
|
||||
MessageLoop::current()->PostTask(
|
||||
NewNonOwningRunnableMethod(this, &TestBridgeMainSubChild::Close));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestBridgeMainSubChild::AnswerHiRpc()
|
||||
{
|
||||
mGotHi = true; // d00d
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TestBridgeMainSubChild::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (NormalShutdown != why)
|
||||
fail("unexpected destruction!");
|
||||
|
||||
gBridgeSubChild->Close();
|
||||
|
||||
// ActorDestroy() is just a callback from IPDL-generated code,
|
||||
// which needs the top-level actor (this) to stay alive a little
|
||||
// longer so other things can be cleaned up.
|
||||
MessageLoop::current()->PostTask(
|
||||
do_AddRef(new DeleteTask<TestBridgeMainSubChild>(this)));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
} // namespace _ipdltest
|
||||
149
ipc/ipdl/test/cxx/TestBridgeMain.h
Normal file
149
ipc/ipdl/test/cxx/TestBridgeMain.h
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#ifndef mozilla__ipdltest_TestBridgeMain_h
|
||||
#define mozilla__ipdltest_TestBridgeMain_h 1
|
||||
|
||||
#include "mozilla/_ipdltest/IPDLUnitTests.h"
|
||||
|
||||
#include "mozilla/_ipdltest/PTestBridgeMainParent.h"
|
||||
#include "mozilla/_ipdltest/PTestBridgeMainChild.h"
|
||||
|
||||
#include "mozilla/_ipdltest/PTestBridgeSubParent.h"
|
||||
#include "mozilla/_ipdltest/PTestBridgeSubChild.h"
|
||||
|
||||
#include "mozilla/_ipdltest/PTestBridgeMainSubParent.h"
|
||||
#include "mozilla/_ipdltest/PTestBridgeMainSubChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "Main" process
|
||||
//
|
||||
class TestBridgeMainParent :
|
||||
public PTestBridgeMainParent
|
||||
{
|
||||
public:
|
||||
TestBridgeMainParent() {}
|
||||
virtual ~TestBridgeMainParent() {}
|
||||
|
||||
static bool RunTestInProcesses() { return true; }
|
||||
static bool RunTestInThreads() { return false; }
|
||||
|
||||
void Main();
|
||||
|
||||
protected:
|
||||
virtual PTestBridgeMainSubParent*
|
||||
AllocPTestBridgeMainSubParent(Transport* transport,
|
||||
ProcessId otherProcess) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
};
|
||||
|
||||
class TestBridgeMainSubParent :
|
||||
public PTestBridgeMainSubParent
|
||||
{
|
||||
public:
|
||||
explicit TestBridgeMainSubParent(Transport* aTransport)
|
||||
: mTransport(aTransport)
|
||||
{}
|
||||
virtual ~TestBridgeMainSubParent() {}
|
||||
|
||||
protected:
|
||||
virtual bool RecvHello() override;
|
||||
virtual bool RecvHelloSync() override;
|
||||
virtual bool AnswerHelloRpc() override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
Transport* mTransport;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "Sub" process --- child of "main"
|
||||
//
|
||||
class TestBridgeSubParent;
|
||||
|
||||
class TestBridgeMainChild :
|
||||
public PTestBridgeMainChild
|
||||
{
|
||||
public:
|
||||
TestBridgeMainChild();
|
||||
virtual ~TestBridgeMainChild() {}
|
||||
|
||||
protected:
|
||||
virtual bool RecvStart() override;
|
||||
|
||||
virtual PTestBridgeMainSubChild*
|
||||
AllocPTestBridgeMainSubChild(Transport* transport,
|
||||
ProcessId otherProcess) override
|
||||
{
|
||||
// This shouldn't be called. It's just a byproduct of testing that
|
||||
// the right code is generated for a bridged protocol that's also
|
||||
// opened, but we only test bridging here.
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
IPDLUnitTestSubprocess* mSubprocess;
|
||||
};
|
||||
|
||||
class TestBridgeSubParent :
|
||||
public PTestBridgeSubParent
|
||||
{
|
||||
public:
|
||||
TestBridgeSubParent() {}
|
||||
virtual ~TestBridgeSubParent() {}
|
||||
|
||||
void Main();
|
||||
|
||||
protected:
|
||||
virtual bool RecvBridgeEm() override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "Subsub" process --- child of "sub"
|
||||
//
|
||||
class TestBridgeSubChild :
|
||||
public PTestBridgeSubChild
|
||||
{
|
||||
public:
|
||||
TestBridgeSubChild();
|
||||
virtual ~TestBridgeSubChild() {}
|
||||
|
||||
protected:
|
||||
virtual bool RecvPing() override;
|
||||
|
||||
virtual PTestBridgeMainSubChild*
|
||||
AllocPTestBridgeMainSubChild(Transport* transport,
|
||||
ProcessId otherProcess) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
};
|
||||
|
||||
class TestBridgeMainSubChild :
|
||||
public PTestBridgeMainSubChild
|
||||
{
|
||||
public:
|
||||
explicit TestBridgeMainSubChild(Transport* aTransport)
|
||||
: mGotHi(false)
|
||||
, mTransport(aTransport)
|
||||
{}
|
||||
virtual ~TestBridgeMainSubChild() {}
|
||||
|
||||
protected:
|
||||
virtual bool RecvHi() override;
|
||||
virtual bool AnswerHiRpc() override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
bool mGotHi;
|
||||
Transport* mTransport;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // ifndef mozilla__ipdltest_TestBridgeMain_h
|
||||
168
ipc/ipdl/test/cxx/TestCancel.cpp
Normal file
168
ipc/ipdl/test/cxx/TestCancel.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
#include "TestCancel.h"
|
||||
|
||||
#include "IPDLUnitTests.h" // fail etc.
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// parent
|
||||
|
||||
TestCancelParent::TestCancelParent()
|
||||
{
|
||||
MOZ_COUNT_CTOR(TestCancelParent);
|
||||
}
|
||||
|
||||
TestCancelParent::~TestCancelParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TestCancelParent);
|
||||
}
|
||||
|
||||
void
|
||||
TestCancelParent::Main()
|
||||
{
|
||||
if (SendTest1_1())
|
||||
fail("sending Test1_1");
|
||||
|
||||
uint32_t value = 0;
|
||||
if (!SendCheckChild(&value))
|
||||
fail("Test1 CheckChild");
|
||||
|
||||
if (value != 12)
|
||||
fail("Test1 CheckChild reply");
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelParent::RecvDone1()
|
||||
{
|
||||
if (!SendStart2())
|
||||
fail("sending Start2");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelParent::RecvTest2_1()
|
||||
{
|
||||
if (SendTest2_2())
|
||||
fail("sending Test2_2");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelParent::RecvStart3()
|
||||
{
|
||||
if (SendTest3_1())
|
||||
fail("sending Test3_1");
|
||||
|
||||
uint32_t value = 0;
|
||||
if (!SendCheckChild(&value))
|
||||
fail("Test1 CheckChild");
|
||||
|
||||
if (value != 12)
|
||||
fail("Test1 CheckChild reply");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelParent::RecvTest3_2()
|
||||
{
|
||||
GetIPCChannel()->CancelCurrentTransaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelParent::RecvDone()
|
||||
{
|
||||
MessageLoop::current()->PostTask(
|
||||
NewNonOwningRunnableMethod(this, &TestCancelParent::Close));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelParent::RecvCheckParent(uint32_t *reply)
|
||||
{
|
||||
*reply = 12;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// child
|
||||
|
||||
bool
|
||||
TestCancelChild::RecvTest1_1()
|
||||
{
|
||||
GetIPCChannel()->CancelCurrentTransaction();
|
||||
|
||||
uint32_t value = 0;
|
||||
if (!SendCheckParent(&value))
|
||||
fail("Test1 CheckParent");
|
||||
|
||||
if (value != 12)
|
||||
fail("Test1 CheckParent reply");
|
||||
|
||||
if (!SendDone1())
|
||||
fail("Test1 CheckParent");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelChild::RecvStart2()
|
||||
{
|
||||
if (!SendTest2_1())
|
||||
fail("sending Test2_1");
|
||||
|
||||
if (!SendStart3())
|
||||
fail("sending Start3");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelChild::RecvTest2_2()
|
||||
{
|
||||
GetIPCChannel()->CancelCurrentTransaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelChild::RecvTest3_1()
|
||||
{
|
||||
if (SendTest3_2())
|
||||
fail("sending Test3_2");
|
||||
|
||||
uint32_t value = 0;
|
||||
if (!SendCheckParent(&value))
|
||||
fail("Test1 CheckParent");
|
||||
|
||||
if (value != 12)
|
||||
fail("Test1 CheckParent reply");
|
||||
|
||||
if (!SendDone())
|
||||
fail("sending Done");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TestCancelChild::RecvCheckChild(uint32_t *reply)
|
||||
{
|
||||
*reply = 12;
|
||||
return true;
|
||||
}
|
||||
|
||||
TestCancelChild::TestCancelChild()
|
||||
{
|
||||
MOZ_COUNT_CTOR(TestCancelChild);
|
||||
}
|
||||
|
||||
TestCancelChild::~TestCancelChild()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TestCancelChild);
|
||||
}
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
66
ipc/ipdl/test/cxx/TestCancel.h
Normal file
66
ipc/ipdl/test/cxx/TestCancel.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef mozilla__ipdltest_TestCancel_h
|
||||
#define mozilla__ipdltest_TestCancel_h 1
|
||||
|
||||
#include "mozilla/_ipdltest/IPDLUnitTests.h"
|
||||
|
||||
#include "mozilla/_ipdltest/PTestCancelParent.h"
|
||||
#include "mozilla/_ipdltest/PTestCancelChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
|
||||
class TestCancelParent :
|
||||
public PTestCancelParent
|
||||
{
|
||||
public:
|
||||
TestCancelParent();
|
||||
virtual ~TestCancelParent();
|
||||
|
||||
static bool RunTestInProcesses() { return true; }
|
||||
static bool RunTestInThreads() { return false; }
|
||||
|
||||
void Main();
|
||||
|
||||
virtual bool RecvDone1() override;
|
||||
virtual bool RecvTest2_1() override;
|
||||
virtual bool RecvStart3() override;
|
||||
virtual bool RecvTest3_2() override;
|
||||
virtual bool RecvDone() override;
|
||||
|
||||
virtual bool RecvCheckParent(uint32_t *reply) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override
|
||||
{
|
||||
passed("ok");
|
||||
QuitParent();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TestCancelChild :
|
||||
public PTestCancelChild
|
||||
{
|
||||
public:
|
||||
TestCancelChild();
|
||||
virtual ~TestCancelChild();
|
||||
|
||||
virtual bool RecvTest1_1() override;
|
||||
virtual bool RecvStart2() override;
|
||||
virtual bool RecvTest2_2() override;
|
||||
virtual bool RecvTest3_1() override;
|
||||
|
||||
virtual bool RecvCheckChild(uint32_t *reply) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override
|
||||
{
|
||||
QuitChild();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
#endif // ifndef mozilla__ipdltest_TestCancel_h
|
||||
116
ipc/ipdl/test/cxx/TestCrashCleanup.cpp
Normal file
116
ipc/ipdl/test/cxx/TestCrashCleanup.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "TestCrashCleanup.h"
|
||||
|
||||
#include "base/task.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
#include "IPDLUnitTests.h" // fail etc.
|
||||
#include "IPDLUnitTestSubprocess.h"
|
||||
|
||||
using mozilla::CondVar;
|
||||
using mozilla::Mutex;
|
||||
using mozilla::MutexAutoLock;
|
||||
|
||||
namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// parent
|
||||
|
||||
namespace {
|
||||
|
||||
// NB: this test does its own shutdown, rather than going through
|
||||
// QuitParent(), because it's testing degenerate edge cases
|
||||
|
||||
void DeleteSubprocess(Mutex* mutex, CondVar* cvar)
|
||||
{
|
||||
MutexAutoLock lock(*mutex);
|
||||
|
||||
delete gSubprocess;
|
||||
gSubprocess = nullptr;
|
||||
|
||||
cvar->Notify();
|
||||
}
|
||||
|
||||
void DeleteTheWorld()
|
||||
{
|
||||
delete static_cast<TestCrashCleanupParent*>(gParentActor);
|
||||
gParentActor = nullptr;
|
||||
|
||||
// needs to be synchronous to avoid affecting event ordering on
|
||||
// the main thread
|
||||
Mutex mutex("TestCrashCleanup.DeleteTheWorld.mutex");
|
||||
CondVar cvar(mutex, "TestCrashCleanup.DeleteTheWorld.cvar");
|
||||
|
||||
MutexAutoLock lock(mutex);
|
||||
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
NewRunnableFunction(DeleteSubprocess, &mutex, &cvar));
|
||||
|
||||
cvar.Wait();
|
||||
}
|
||||
|
||||
void Done()
|
||||
{
|
||||
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
|
||||
appShell->Exit();
|
||||
|
||||
passed(__FILE__);
|
||||
}
|
||||
|
||||
} // namespace <anon>
|
||||
|
||||
TestCrashCleanupParent::TestCrashCleanupParent() : mCleanedUp(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TestCrashCleanupParent);
|
||||
}
|
||||
|
||||
TestCrashCleanupParent::~TestCrashCleanupParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TestCrashCleanupParent);
|
||||
|
||||
if (!mCleanedUp)
|
||||
fail("should have been ActorDestroy()d!");
|
||||
}
|
||||
|
||||
void
|
||||
TestCrashCleanupParent::Main()
|
||||
{
|
||||
// NB: has to be enqueued before IO thread's error notification
|
||||
MessageLoop::current()->PostTask(
|
||||
NewRunnableFunction(DeleteTheWorld));
|
||||
|
||||
if (CallDIEDIEDIE())
|
||||
fail("expected an error!");
|
||||
|
||||
Close();
|
||||
|
||||
MessageLoop::current()->PostTask(NewRunnableFunction(Done));
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// child
|
||||
|
||||
TestCrashCleanupChild::TestCrashCleanupChild()
|
||||
{
|
||||
MOZ_COUNT_CTOR(TestCrashCleanupChild);
|
||||
}
|
||||
|
||||
TestCrashCleanupChild::~TestCrashCleanupChild()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TestCrashCleanupChild);
|
||||
}
|
||||
|
||||
bool
|
||||
TestCrashCleanupChild::AnswerDIEDIEDIE()
|
||||
{
|
||||
_exit(0);
|
||||
NS_RUNTIMEABORT("unreached");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace _ipdltest
|
||||
} // namespace mozilla
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue