Commit 040e7f92 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

bind-gen: Support multiprocessing of Python on Windows, etc.

Supports Python's multiprocessing on platforms that do not
support 'fork'.

Bug: 839389
Change-Id: I2dbe28686c3d73badcbf6e07e403079a981f6b00
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2153166Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#759952}
parent 3161914e
......@@ -33,11 +33,9 @@ def _setup_sys_path():
_setup_sys_path()
from . import style_format
from .dictionary import generate_dictionaries
from .enumeration import generate_enumerations
from .interface import generate_interfaces
from .path_manager import PathManager
from .union import generate_unions
......@@ -49,9 +47,9 @@ def init(root_src_dir, root_gen_dir, component_reldirs):
"//out/Default/gen" in GN.
component_reldirs: Pairs of component and output directory.
"""
style_format.init(root_src_dir)
PathManager.init(
from . import package_initializer
package_initializer.init(
root_src_dir=root_src_dir,
root_gen_dir=root_gen_dir,
component_reldirs=component_reldirs)
......@@ -44,6 +44,7 @@ from .codegen_utils import make_forward_declarations
from .codegen_utils import make_header_include_directives
from .codegen_utils import write_code_node_to_file
from .mako_renderer import MakoRenderer
from .package_initializer import package_initializer
from .path_manager import PathManager
......@@ -6426,6 +6427,12 @@ def generate_init_idl_interfaces(web_idl_database):
write_code_node_to_file(source_node, path_manager.gen_path_to(source_path))
def run_multiprocessing_task(args):
interface, package_initializer = args
package_initializer.init()
generate_interface(interface)
def generate_interfaces(web_idl_database):
# More processes do not mean better performance. The default size was
# chosen heuristically.
......@@ -6437,7 +6444,9 @@ def generate_interfaces(web_idl_database):
# Prior to Python3, Pool.map doesn't support user interrupts (e.g. Ctrl-C),
# although Pool.map_async(...).get(...) does.
timeout_in_sec = 3600 # Just enough long time
pool.map_async(generate_interface,
web_idl_database.interfaces).get(timeout_in_sec)
pool.map_async(
run_multiprocessing_task,
map(lambda interface: (interface, package_initializer()),
web_idl_database.interfaces)).get(timeout_in_sec)
generate_init_idl_interfaces(web_idl_database)
# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from . import style_format
from .path_manager import PathManager
def init(**kwargs):
"""
Initializes this package. See PackageInitializer.__init__ for details
about the arguments.
"""
the_instance = PackageInitializer(**kwargs)
the_instance.init()
assert the_instance is PackageInitializer.the_instance()
def package_initializer():
"""
Returns the instance of PackageInitializer that actually initialized this
package.
"""
the_instance = PackageInitializer.the_instance()
assert the_instance
return the_instance
class PackageInitializer(object):
"""
PackageInitializer is designed to support 'multiprocessing' package so that
users can initialize this package in another process with the same
settings.
When the 'start method' of 'multiprocessing' package is 'spawn', the global
environment (e.g. module variables, class variables, etc.) will not be
inherited. See also https://docs.python.org/3/library/multiprocessing.html
PackageInitializer helps reproduce the same runtime environment of this
process in other processes. PackageInitializer.init() initializes this
package in the same way as it was originally initialized iff the current
process' runtime environment has not yet been initialized. In other words,
PackageInitializer.init() works with any start method of multiprocessing
package.
"""
# The instance of PackageInitializer that actually initialized this
# package.
_the_instance = None
@classmethod
def the_instance(cls):
return cls._the_instance
def __init__(self, root_src_dir, root_gen_dir, component_reldirs):
"""
Args:
root_src_dir: Project's root directory, which corresponds to "//"
in GN.
root_gen_dir: Root directory of generated files, which corresponds
to "//out/Default/gen" in GN.
component_reldirs: Pairs of component and output directory.
"""
self._root_src_dir = root_src_dir
self._root_gen_dir = root_gen_dir
self._component_reldirs = component_reldirs
def init(self):
if PackageInitializer._the_instance:
return
PackageInitializer._the_instance = self
self._init()
def _init(self):
style_format.init(self._root_src_dir)
PathManager.init(
root_src_dir=self._root_src_dir,
root_gen_dir=self._root_gen_dir,
component_reldirs=self._component_reldirs)
......@@ -42,6 +42,7 @@ bind_gen/enumeration.py
bind_gen/interface.py
bind_gen/mako_renderer.py
bind_gen/name_style.py
bind_gen/package_initializer.py
bind_gen/path_manager.py
bind_gen/style_format.py
bind_gen/union.py
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment