mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1675848 - Part 2: Add "BackgroundTasksSelector" to static component category registration. r=mhentges,nika
For simplicity, this implements just on in `NO_TASKS` (the default) or on in `ALL_TASKS` (opt-in). This disables all category registrations when in background task mode; we'll selectively re-enable things as appropriate. The flag constants were chosen to smoothly extend to a (16-)bit set in the future, should we want to add a `JUST_TASKS("task", "other-task")` option in the future. This also adds ython tests for gen_static_components.py exercising categories, simply 'cuz it's easiest to see what this adds in such tests. Functional tests will follow in patches that actually implement the new background tasks functionality. Differential Revision: https://phabricator.services.mozilla.com/D96654
This commit is contained in:
parent
dc4f42262e
commit
3d0d39d82c
@ -85,7 +85,11 @@ Class definitions may have the following properties:
|
||||
``categories`` (optional)
|
||||
A dict of category entries to register for this component's contract ID.
|
||||
Each key in the dict is the name of the category. Each value is either a
|
||||
string containing a single entry name, or a list of entry name strings.
|
||||
string containing a single entry, or a list of entries. Each entry is either
|
||||
a string name, or a dictionary of the form ``{'name': 'value', 'backgroundtasks':
|
||||
BackgroundTasksSelector.ALL_TASKS}``. By default, category entries are registered
|
||||
for **no background tasks**: they have
|
||||
``'backgroundtasks': BackgroundTasksSelector.NO_TASKS``.
|
||||
|
||||
``type`` (optional, default=``nsISupports``)
|
||||
The fully-qualified type of the class implementing this component. Defaults
|
||||
|
@ -548,6 +548,8 @@ xpcom:
|
||||
when:
|
||||
files-changed:
|
||||
- 'third_party/python/ply/**'
|
||||
- 'xpcom/components/*.py'
|
||||
- 'xpcom/components/test/**'
|
||||
- 'xpcom/ds/tools/**'
|
||||
- 'xpcom/ds/test/**'
|
||||
- 'xpcom/idl-parser/**'
|
||||
|
@ -72,6 +72,17 @@ struct Module {
|
||||
static constexpr size_t kMaxProcessSelector =
|
||||
size_t(ProcessSelector::ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS);
|
||||
|
||||
/**
|
||||
* This allows category entries to be marked so that they are or are
|
||||
* not loaded when in backgroundtask mode.
|
||||
*/
|
||||
// Note: This must be kept in sync with the selector matching in
|
||||
// StaticComponents.cpp.in.
|
||||
enum BackgroundTasksSelector {
|
||||
NO_TASKS = 0x0,
|
||||
ALL_TASKS = 0xFFFF,
|
||||
};
|
||||
|
||||
/**
|
||||
* The constructor callback is an implementation detail of the default binary
|
||||
* loader and may be null.
|
||||
|
@ -7,6 +7,9 @@
|
||||
#include "StaticComponents.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#ifdef MOZ_BACKGROUNDTASKS
|
||||
# include "mozilla/BackgroundTasks.h"
|
||||
#endif
|
||||
#include "mozilla/PerfectHash.h"
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
@ -256,11 +259,21 @@ void StaticModule::SetServiceInstance(
|
||||
nsCString StaticCategoryEntry::Entry() const {
|
||||
return GetString(mEntry);
|
||||
}
|
||||
|
||||
nsCString StaticCategoryEntry::Value() const {
|
||||
return GetString(mValue);
|
||||
}
|
||||
|
||||
bool StaticCategoryEntry::Active() const {
|
||||
return FastProcessSelectorMatches(mProcessSelector);
|
||||
if (!FastProcessSelectorMatches(mProcessSelector)) {
|
||||
return false;
|
||||
}
|
||||
#ifdef MOZ_BACKGROUNDTASKS
|
||||
if (MOZ_UNLIKELY(BackgroundTasks::IsBackgroundTaskMode())) {
|
||||
return mBackgroundTasksSelector != Module::BackgroundTasksSelector::NO_TASKS;
|
||||
}
|
||||
#endif /* MOZ_BACKGROUNDTASKS */
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString StaticCategory::Name() const {
|
||||
|
@ -187,6 +187,7 @@ struct ContractEntry final {
|
||||
struct StaticCategoryEntry final {
|
||||
StringOffset mEntry;
|
||||
StringOffset mValue;
|
||||
Module::BackgroundTasksSelector mBackgroundTasksSelector;
|
||||
Module::ProcessSelector mProcessSelector;
|
||||
|
||||
nsCString Entry() const;
|
||||
|
@ -15,7 +15,10 @@ NO_CONTRACT_ID = 0xFFFFFFFF
|
||||
|
||||
PHF_SIZE = 512
|
||||
|
||||
ENDIAN = "<" if buildconfig.substs["TARGET_ENDIANNESS"] == "little" else ">"
|
||||
# In tests, we might not have a (complete) buildconfig.
|
||||
ENDIAN = (
|
||||
"<" if buildconfig.substs.get("TARGET_ENDIANNESS", "little") == "little" else ">"
|
||||
)
|
||||
|
||||
|
||||
# Represents a UUID in the format used internally by Gecko, and supports
|
||||
@ -108,6 +111,28 @@ def lower_module_id(module):
|
||||
return "ModuleID::%s" % module.name
|
||||
|
||||
|
||||
# Corresponds to the Module::BackgroundTasksSelector enum in Module.h. The
|
||||
# actual values don't matter, since the code generator emits symbolic constants
|
||||
# for these values, but we use the same values as the enum constants for
|
||||
# clarity.
|
||||
class BackgroundTasksSelector:
|
||||
NO_TASKS = 0x0
|
||||
ALL_TASKS = 0xFFFF
|
||||
|
||||
|
||||
# Maps BackgroundTasksSelector constants to the name of the corresponding
|
||||
# Module::BackgroundTasksSelector enum value.
|
||||
BACKGROUNDTASKS = {
|
||||
BackgroundTasksSelector.ALL_TASKS: "ALL_TASKS",
|
||||
BackgroundTasksSelector.NO_TASKS: "NO_TASKS",
|
||||
}
|
||||
|
||||
|
||||
# Emits the C++ symbolic constant corresponding to a BackgroundTasks constant.
|
||||
def lower_backgroundtasks(backgroundtasks):
|
||||
return "Module::BackgroundTasksSelector::%s" % BACKGROUNDTASKS[backgroundtasks]
|
||||
|
||||
|
||||
# Represents a static string table, indexed by offset. This allows us to
|
||||
# reference strings from static data structures without requiring runtime
|
||||
# relocations.
|
||||
@ -325,7 +350,7 @@ class ModuleEntry(object):
|
||||
processes=lower_processes(self.processes),
|
||||
)
|
||||
|
||||
# Generates the C++ code for a JSServiceEntry represengin this module.
|
||||
# Generates the C++ code for a JSServiceEntry representing this module.
|
||||
def lower_js_service(self):
|
||||
return """
|
||||
{{
|
||||
@ -495,7 +520,11 @@ def gen_categories(substs, categories):
|
||||
|
||||
count = 0
|
||||
for category, entries in sorted(categories.items()):
|
||||
entries.sort()
|
||||
|
||||
def k(entry):
|
||||
return tuple(entry[0]["name"]) + entry[1:]
|
||||
|
||||
entries.sort(key=k)
|
||||
|
||||
cats.append(
|
||||
" { %s,\n"
|
||||
@ -505,13 +534,20 @@ def gen_categories(substs, categories):
|
||||
|
||||
ents.append(" /* %s */\n" % pretty_string(category))
|
||||
for entry, value, processes in entries:
|
||||
name = entry["name"]
|
||||
backgroundtasks = entry.get(
|
||||
"backgroundtasks", BackgroundTasksSelector.NO_TASKS
|
||||
)
|
||||
|
||||
ents.append(
|
||||
" { %s,\n"
|
||||
" %s,\n"
|
||||
" %s,\n"
|
||||
" %s },\n"
|
||||
% (
|
||||
strings.entry_to_cxx(entry),
|
||||
strings.entry_to_cxx(name),
|
||||
strings.entry_to_cxx(value),
|
||||
lower_backgroundtasks(backgroundtasks),
|
||||
lower_processes(processes),
|
||||
)
|
||||
)
|
||||
@ -626,10 +662,34 @@ def gen_includes(substs, all_headers):
|
||||
substs["relative_includes"] = "\n".join(relative_includes) + "\n"
|
||||
|
||||
|
||||
def to_list(val):
|
||||
def to_category_list(val):
|
||||
# Entries can be bare strings (like `"m-browser"`), lists of bare strings,
|
||||
# or dictionaries (like `{"name": "m-browser", "backgroundtasks":
|
||||
# BackgroundTasksSelector.ALL_TASKS}`), somewhat recursively.
|
||||
|
||||
def ensure_dict(v):
|
||||
# Turn `v` into `{"name": v}` if it's not already a dict.
|
||||
if isinstance(v, dict):
|
||||
return v
|
||||
return {"name": v}
|
||||
|
||||
if isinstance(val, (list, tuple)):
|
||||
return val
|
||||
return (val,)
|
||||
return tuple(ensure_dict(v) for v in val)
|
||||
|
||||
if isinstance(val, dict):
|
||||
# Explode `{"name": ["x", "y"], "backgroundtasks": ...}` into
|
||||
# `[{"name": "x", "backgroundtasks": ...}, {"name": "y", "backgroundtasks": ...}]`.
|
||||
names = val.pop("name")
|
||||
|
||||
vals = []
|
||||
for entry in to_category_list(names):
|
||||
d = dict(val)
|
||||
d["name"] = entry["name"]
|
||||
vals.append(d)
|
||||
|
||||
return tuple(vals)
|
||||
|
||||
return (ensure_dict(val),)
|
||||
|
||||
|
||||
def gen_substs(manifests):
|
||||
@ -682,7 +742,7 @@ def gen_substs(manifests):
|
||||
contract_map[contract_id] = entry
|
||||
|
||||
for category, entries in mod.categories.items():
|
||||
for entry in to_list(entries):
|
||||
for entry in to_category_list(entries):
|
||||
categories[category].append((entry, mod.contract_id, mod.processes))
|
||||
|
||||
if mod.type and not mod.headers:
|
||||
@ -794,8 +854,10 @@ def read_manifest(filename):
|
||||
"buildconfig": buildconfig,
|
||||
"defined": defined,
|
||||
"ProcessSelector": ProcessSelector,
|
||||
"BackgroundTasksSelector": BackgroundTasksSelector,
|
||||
}
|
||||
exec(open(filename).read(), glbl)
|
||||
code = compile(open(filename).read(), filename, "exec")
|
||||
exec(code, glbl)
|
||||
return glbl
|
||||
|
||||
|
||||
|
@ -82,3 +82,7 @@ if CONFIG["MOZ_BACKGROUNDTASKS"]:
|
||||
DEFINES["MOZ_BACKGROUNDTASKS"] = True
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
PYTHON_UNITTEST_MANIFESTS += [
|
||||
"test/python.ini",
|
||||
]
|
||||
|
4
xpcom/components/test/python.ini
Normal file
4
xpcom/components/test/python.ini
Normal file
@ -0,0 +1,4 @@
|
||||
[DEFAULT]
|
||||
subsuite = xpcom
|
||||
|
||||
[test_gen_static_components.py]
|
137
xpcom/components/test/test_gen_static_components.py
Normal file
137
xpcom/components/test/test_gen_static_components.py
Normal file
@ -0,0 +1,137 @@
|
||||
# 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 mozunit
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
|
||||
import gen_static_components
|
||||
from gen_static_components import BackgroundTasksSelector
|
||||
|
||||
|
||||
class TestGenStaticComponents(unittest.TestCase):
|
||||
def test_string(self):
|
||||
# A string: we default to NO_TASKS.
|
||||
clas = {
|
||||
"cid": "{a8566880-0bc7-4822-adb9-748c9af5cce7}",
|
||||
"contract_ids": ["@mozilla.org/dummy-class;1"],
|
||||
"jsm": "resource:///modules/DummyClass.jsm",
|
||||
"js_name": "dummyClass",
|
||||
"constructor": "DummyClassImpl",
|
||||
"categories": {
|
||||
"dummy1": ["m-dummy1", "m-dummy2"],
|
||||
},
|
||||
}
|
||||
|
||||
substs = gen_static_components.gen_substs([{"Classes": [clas]}])
|
||||
|
||||
self.assertEqual(substs["category_count"], 1)
|
||||
self.assertEqual(
|
||||
[s.strip() for s in substs["categories"].splitlines()],
|
||||
[
|
||||
'{ { 0x0 } /* "dummy1" */,',
|
||||
"0, 2 },",
|
||||
],
|
||||
)
|
||||
self.assertEqual(
|
||||
[s.strip() for s in substs["category_entries"].splitlines()],
|
||||
[
|
||||
'/* "dummy1" */',
|
||||
'{ { 0x7 } /* "m-dummy1" */,',
|
||||
'{ 0x10 } /* "@mozilla.org/dummy-class;1" */,',
|
||||
"Module::BackgroundTasksSelector::NO_TASKS,",
|
||||
"Module::ProcessSelector::ANY_PROCESS },",
|
||||
'{ { 0x2b } /* "m-dummy2" */,',
|
||||
'{ 0x10 } /* "@mozilla.org/dummy-class;1" */,',
|
||||
"Module::BackgroundTasksSelector::NO_TASKS,",
|
||||
"Module::ProcessSelector::ANY_PROCESS },",
|
||||
],
|
||||
)
|
||||
|
||||
def test_dict(self):
|
||||
# A dict, but no backgroundtasks selector: we default to NO_TASKS.
|
||||
clas = {
|
||||
"cid": "{a8566880-0bc7-4822-adb9-748c9af5cce7}",
|
||||
"contract_ids": ["@mozilla.org/dummy-class;1"],
|
||||
"jsm": "resource:///modules/DummyClass.jsm",
|
||||
"js_name": "dummyClass",
|
||||
"constructor": "DummyClassImpl",
|
||||
"categories": {
|
||||
"dummy1": {
|
||||
"name": ["m-dummy1", "m-dummy2"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
substs = gen_static_components.gen_substs([{"Classes": [clas]}])
|
||||
|
||||
self.assertEqual(substs["category_count"], 1)
|
||||
self.assertEqual(
|
||||
[s.strip() for s in substs["categories"].splitlines()],
|
||||
[
|
||||
'{ { 0x0 } /* "dummy1" */,',
|
||||
"0, 2 },",
|
||||
],
|
||||
)
|
||||
self.assertEqual(
|
||||
[s.strip() for s in substs["category_entries"].splitlines()],
|
||||
[
|
||||
'/* "dummy1" */',
|
||||
'{ { 0x7 } /* "m-dummy1" */,',
|
||||
'{ 0x10 } /* "@mozilla.org/dummy-class;1" */,',
|
||||
"Module::BackgroundTasksSelector::NO_TASKS,",
|
||||
"Module::ProcessSelector::ANY_PROCESS },",
|
||||
'{ { 0x2b } /* "m-dummy2" */,',
|
||||
'{ 0x10 } /* "@mozilla.org/dummy-class;1" */,',
|
||||
"Module::BackgroundTasksSelector::NO_TASKS,",
|
||||
"Module::ProcessSelector::ANY_PROCESS },",
|
||||
],
|
||||
)
|
||||
|
||||
def test_dict_with_selector(self):
|
||||
# A dict with a selector.
|
||||
clas = {
|
||||
"cid": "{a8566880-0bc7-4822-adb9-748c9af5cce7}",
|
||||
"contract_ids": ["@mozilla.org/dummy-class;1"],
|
||||
"jsm": "resource:///modules/DummyClass.jsm",
|
||||
"js_name": "dummyClass",
|
||||
"constructor": "DummyClassImpl",
|
||||
"categories": {
|
||||
"dummy1": {
|
||||
"name": ["m-dummy1", "m-dummy2"],
|
||||
"backgroundtasks": BackgroundTasksSelector.ALL_TASKS,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
substs = gen_static_components.gen_substs([{"Classes": [clas]}])
|
||||
|
||||
self.assertEqual(substs["category_count"], 1)
|
||||
self.assertEqual(
|
||||
[s.strip() for s in substs["categories"].splitlines()],
|
||||
[
|
||||
'{ { 0x0 } /* "dummy1" */,',
|
||||
"0, 2 },",
|
||||
],
|
||||
)
|
||||
self.assertEqual(
|
||||
[s.strip() for s in substs["category_entries"].splitlines()],
|
||||
[
|
||||
'/* "dummy1" */',
|
||||
'{ { 0x7 } /* "m-dummy1" */,',
|
||||
'{ 0x10 } /* "@mozilla.org/dummy-class;1" */,',
|
||||
"Module::BackgroundTasksSelector::ALL_TASKS,",
|
||||
"Module::ProcessSelector::ANY_PROCESS },",
|
||||
'{ { 0x2b } /* "m-dummy2" */,',
|
||||
'{ 0x10 } /* "@mozilla.org/dummy-class;1" */,',
|
||||
"Module::BackgroundTasksSelector::ALL_TASKS,",
|
||||
"Module::ProcessSelector::ANY_PROCESS },",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mozunit.main()
|
Loading…
Reference in New Issue
Block a user