mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
985adb750c
The NodeController and NodeChannel types act as the backbone connecting the existing IPC logic and driving the ports routing code. Individual NodeChannel objects wrap and respond to messages from IPC::Channel, and the NodeController orchestrates all messaging for a process. The design of these types are inspired by the types with the same names from Mojo but have been simplified and streamlined to only support features used by Gecko. Support for attaching ports or handles to messages hasn't been added yet, but can be added in follow-up patches. Differential Revision: https://phabricator.services.mozilla.com/D112775
335 lines
8.3 KiB
Python
335 lines
8.3 KiB
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/.
|
|
from __future__ import print_function
|
|
|
|
from io import StringIO
|
|
import optparse
|
|
import os
|
|
import sys
|
|
from configparser import RawConfigParser
|
|
|
|
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(
|
|
"-s",
|
|
"--sync-msg-list",
|
|
dest="syncMsgList",
|
|
default="sync-messages.ini",
|
|
help="Config file listing allowed sync messages",
|
|
)
|
|
op.add_option(
|
|
"-m",
|
|
"--msg-metadata",
|
|
dest="msgMetadata",
|
|
default="message-metadata.ini",
|
|
help="Predicted message sizes for reducing serialization malloc overhead.",
|
|
)
|
|
op.add_option(
|
|
"-v",
|
|
"--verbose",
|
|
dest="verbosity",
|
|
default=1,
|
|
action="count",
|
|
help="Verbose logging (specify -vv or -vvv for very verbose logging)",
|
|
)
|
|
op.add_option(
|
|
"-q",
|
|
"--quiet",
|
|
dest="verbosity",
|
|
action="store_const",
|
|
const=0,
|
|
help="Suppress logging output",
|
|
)
|
|
op.add_option(
|
|
"-d",
|
|
"--outheaders-dir",
|
|
dest="headersdir",
|
|
default=".",
|
|
help="""Directory into which C++ headers will be generated.
|
|
A protocol Foo in the namespace bar will cause the headers
|
|
dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
|
|
to be generated""",
|
|
)
|
|
op.add_option(
|
|
"-o",
|
|
"--outcpp-dir",
|
|
dest="cppdir",
|
|
default=".",
|
|
help="""Directory into which C++ sources will be generated
|
|
A protocol Foo in the namespace bar will cause the sources
|
|
cppdir/FooParent.cpp, cppdir/FooChild.cpp
|
|
to be generated""",
|
|
)
|
|
|
|
options, files = op.parse_args()
|
|
_verbosity = options.verbosity
|
|
syncMsgList = options.syncMsgList
|
|
msgMetadata = options.msgMetadata
|
|
headersdir = options.headersdir
|
|
cppdir = options.cppdir
|
|
includedirs = [os.path.abspath(incdir) for incdir in options.includedirs]
|
|
|
|
if not len(files):
|
|
op.error("No IPDL files specified")
|
|
|
|
ipcmessagestartpath = os.path.join(headersdir, "IPCMessageStart.h")
|
|
ipc_msgtype_name_path = os.path.join(cppdir, "IPCMessageTypeName.cpp")
|
|
|
|
log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
|
|
log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
|
|
|
|
allmessages = {}
|
|
allmessageprognames = []
|
|
allprotocols = []
|
|
|
|
|
|
def normalizedFilename(f):
|
|
if f == "-":
|
|
return "<stdin>"
|
|
return f
|
|
|
|
|
|
log(2, "Reading sync message list")
|
|
parser = RawConfigParser()
|
|
parser.read_file(open(options.syncMsgList))
|
|
syncMsgList = parser.sections()
|
|
|
|
for section in syncMsgList:
|
|
if not parser.get(section, "description"):
|
|
print("Error: Sync message %s lacks a description" % section, file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Read message metadata. Right now we only have 'segment_capacity'
|
|
# for the standard segment size used for serialization.
|
|
log(2, "Reading message metadata...")
|
|
msgMetadataConfig = RawConfigParser()
|
|
msgMetadataConfig.read_file(open(options.msgMetadata))
|
|
|
|
segmentCapacityDict = {}
|
|
for msgName in msgMetadataConfig.sections():
|
|
if msgMetadataConfig.has_option(msgName, "segment_capacity"):
|
|
capacity = msgMetadataConfig.get(msgName, "segment_capacity")
|
|
segmentCapacityDict[msgName] = capacity
|
|
|
|
# First pass: parse and type-check all protocols
|
|
for f in files:
|
|
log(2, os.path.basename(f))
|
|
filename = normalizedFilename(f)
|
|
if f == "-":
|
|
fd = sys.stdin
|
|
else:
|
|
fd = open(f)
|
|
|
|
specstring = fd.read()
|
|
fd.close()
|
|
|
|
ast = ipdl.parse(specstring, filename, includedirs=includedirs)
|
|
if ast is None:
|
|
print("Specification could not be parsed.", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
log(2, "checking types")
|
|
if not ipdl.typecheck(ast):
|
|
print("Specification is not well typed.", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
if not ipdl.checkSyncMessage(ast, syncMsgList):
|
|
print(
|
|
"Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s"
|
|
% options.syncMsgList,
|
|
file=sys.stderr,
|
|
) # NOQA: E501
|
|
sys.exit(1)
|
|
|
|
if not ipdl.checkFixedSyncMessages(parser):
|
|
# Errors have alraedy been printed to stderr, just exit
|
|
sys.exit(1)
|
|
|
|
# Second pass: generate code
|
|
for f in files:
|
|
# Read from parser cache
|
|
filename = normalizedFilename(f)
|
|
ast = ipdl.parse(None, filename, includedirs=includedirs)
|
|
ipdl.gencxx(filename, ast, headersdir, cppdir, segmentCapacityDict)
|
|
|
|
if ast.protocol:
|
|
allmessages[ast.protocol.name] = ipdl.genmsgenum(ast)
|
|
allprotocols.append(ast.protocol.name)
|
|
# e.g. PContent::RequestMemoryReport (not prefixed or suffixed.)
|
|
for md in ast.protocol.messageDecls:
|
|
allmessageprognames.append("%s::%s" % (md.namespace, md.decl.progname))
|
|
|
|
allprotocols.sort()
|
|
|
|
# Check if we have undefined message names in segmentCapacityDict.
|
|
# This is a fool-proof of the 'message-metadata.ini' file.
|
|
undefinedMessages = set(segmentCapacityDict.keys()) - set(allmessageprognames)
|
|
if len(undefinedMessages) > 0:
|
|
print("Error: Undefined message names in message-metadata.ini:", file=sys.stderr)
|
|
print(undefinedMessages, file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
ipcmsgstart = StringIO()
|
|
|
|
print(
|
|
"""
|
|
// CODE GENERATED by ipdl.py. Do not edit.
|
|
|
|
#ifndef IPCMessageStart_h
|
|
#define IPCMessageStart_h
|
|
|
|
enum IPCMessageStart {
|
|
""",
|
|
file=ipcmsgstart,
|
|
)
|
|
|
|
for name in allprotocols:
|
|
print(" %sMsgStart," % name, file=ipcmsgstart)
|
|
|
|
print(
|
|
"""
|
|
LastMsgIndex
|
|
};
|
|
|
|
static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
|
|
|
|
#endif // ifndef IPCMessageStart_h
|
|
""",
|
|
file=ipcmsgstart,
|
|
)
|
|
|
|
ipc_msgtype_name = StringIO()
|
|
print(
|
|
"""
|
|
// CODE GENERATED by ipdl.py. Do not edit.
|
|
#include <cstdint>
|
|
|
|
#include "mozilla/ipc/ProtocolUtils.h"
|
|
#include "IPCMessageStart.h"
|
|
|
|
using std::uint32_t;
|
|
|
|
namespace {
|
|
|
|
enum IPCMessages {
|
|
""",
|
|
file=ipc_msgtype_name,
|
|
)
|
|
|
|
for protocol in sorted(allmessages.keys()):
|
|
for (msg, num) in allmessages[protocol].idnums:
|
|
if num:
|
|
print(" %s = %s," % (msg, num), file=ipc_msgtype_name)
|
|
elif not msg.endswith("End"):
|
|
print(" %s__%s," % (protocol, msg), file=ipc_msgtype_name)
|
|
|
|
print(
|
|
"""
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
namespace IPC {
|
|
|
|
const char* StringFromIPCMessageType(uint32_t aMessageType)
|
|
{
|
|
switch (aMessageType) {
|
|
""",
|
|
file=ipc_msgtype_name,
|
|
)
|
|
|
|
for protocol in sorted(allmessages.keys()):
|
|
for (msg, num) in allmessages[protocol].idnums:
|
|
if num or msg.endswith("End"):
|
|
continue
|
|
print(
|
|
"""
|
|
case %s__%s:
|
|
return "%s::%s";"""
|
|
% (protocol, msg, protocol, msg),
|
|
file=ipc_msgtype_name,
|
|
)
|
|
|
|
print(
|
|
"""
|
|
case ACCEPT_INVITE_MESSAGE_TYPE:
|
|
return "ACCEPT_INVITE_MESSAGE";
|
|
case REQUEST_INTRODUCTION_MESSAGE_TYPE:
|
|
return "REQUEST_INTRODUCTION_MESSAGE";
|
|
case INTRODUCE_MESSAGE_TYPE:
|
|
return "INTRODUCE_MESSAGE";
|
|
case BROADCAST_MESSAGE_TYPE:
|
|
return "BROADCAST_MESSAGE";
|
|
case EVENT_MESSAGE_TYPE:
|
|
return "EVENT_MESSAGE";
|
|
case IMPENDING_SHUTDOWN_MESSAGE_TYPE:
|
|
return "IMPENDING_SHUTDOWN";
|
|
case BUILD_IDS_MATCH_MESSAGE_TYPE:
|
|
return "BUILD_IDS_MATCH_MESSAGE";
|
|
case BUILD_ID_MESSAGE_TYPE:
|
|
return "BUILD_ID_MESSAGE";
|
|
case CHANNEL_OPENED_MESSAGE_TYPE:
|
|
return "CHANNEL_OPENED_MESSAGE";
|
|
case SHMEM_DESTROYED_MESSAGE_TYPE:
|
|
return "SHMEM_DESTROYED_MESSAGE";
|
|
case SHMEM_CREATED_MESSAGE_TYPE:
|
|
return "SHMEM_CREATED_MESSAGE";
|
|
case GOODBYE_MESSAGE_TYPE:
|
|
return "GOODBYE_MESSAGE";
|
|
case CANCEL_MESSAGE_TYPE:
|
|
return "CANCEL_MESSAGE";
|
|
default:
|
|
return "<unknown IPC msg name>";
|
|
}
|
|
}
|
|
|
|
} // namespace IPC
|
|
|
|
namespace mozilla {
|
|
namespace ipc {
|
|
|
|
const char* ProtocolIdToName(IPCMessageStart aId) {
|
|
switch (aId) {
|
|
""",
|
|
file=ipc_msgtype_name,
|
|
)
|
|
|
|
for name in allprotocols:
|
|
print(" case %sMsgStart:" % name, file=ipc_msgtype_name)
|
|
print(' return "%s";' % name, file=ipc_msgtype_name)
|
|
|
|
print(
|
|
"""
|
|
default:
|
|
return "<unknown protocol id>";
|
|
}
|
|
}
|
|
|
|
} // namespace ipc
|
|
} // namespace mozilla
|
|
""",
|
|
file=ipc_msgtype_name,
|
|
)
|
|
|
|
ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
|
|
ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)
|