This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
"""Host-only ownership model for hybrid BigApp/JIT mapping composition."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
MAX_EXECUTABLE_SEGMENTS = 8
|
||||
MAX_EVENTS = 256
|
||||
MAX_TICKS = 256
|
||||
|
||||
CREATE_CHILD = "CREATE_CHILD"
|
||||
RESERVE_REGION = "RESERVE_REGION"
|
||||
CREATE_MIRROR = "CREATE_MIRROR"
|
||||
CREATE_JIT_MASTER = "CREATE_JIT_MASTER"
|
||||
MAP_EXECUTABLE = "MAP_EXECUTABLE"
|
||||
CREATE_JIT_ALIAS = "CREATE_JIT_ALIAS"
|
||||
MAP_HOST_ALIAS = "MAP_HOST_ALIAS"
|
||||
MAP_REMOTE_ALIAS = "MAP_REMOTE_ALIAS"
|
||||
COPY_ALIAS = "COPY_ALIAS"
|
||||
UNMAP_REMOTE_ALIAS = "UNMAP_REMOTE_ALIAS"
|
||||
UNMAP_HOST_ALIAS = "UNMAP_HOST_ALIAS"
|
||||
CLOSE_JIT_ALIAS = "CLOSE_JIT_ALIAS"
|
||||
CLOSE_JIT_MASTER = "CLOSE_JIT_MASTER"
|
||||
FINALIZE_IMAGE = "FINALIZE_IMAGE"
|
||||
RELEASE_MIRROR = "RELEASE_MIRROR"
|
||||
UNMAP_REGION = "UNMAP_REGION"
|
||||
KILL_AND_REAP_CHILD = "KILL_AND_REAP_CHILD"
|
||||
OK = "OK"
|
||||
ERROR = "ERROR"
|
||||
|
||||
INDEXED = {
|
||||
CREATE_JIT_MASTER, MAP_EXECUTABLE, CREATE_JIT_ALIAS, MAP_HOST_ALIAS,
|
||||
MAP_REMOTE_ALIAS, COPY_ALIAS, UNMAP_REMOTE_ALIAS, UNMAP_HOST_ALIAS,
|
||||
CLOSE_JIT_ALIAS, CLOSE_JIT_MASTER,
|
||||
}
|
||||
OPERATIONS = INDEXED | {
|
||||
CREATE_CHILD, RESERVE_REGION, CREATE_MIRROR, FINALIZE_IMAGE,
|
||||
RELEASE_MIRROR, UNMAP_REGION, KILL_AND_REAP_CHILD,
|
||||
}
|
||||
|
||||
|
||||
class CompositionError(RuntimeError):
|
||||
"""The synthetic ownership transaction cannot close safely."""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CompositionPlan:
|
||||
executable_segments: int
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not isinstance(self.executable_segments, int) \
|
||||
or isinstance(self.executable_segments, bool) \
|
||||
or not 1 <= self.executable_segments <= MAX_EXECUTABLE_SEGMENTS:
|
||||
raise CompositionError("executable segment count is invalid")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FakeEvent:
|
||||
operation: str
|
||||
result: str
|
||||
segment: int = -1
|
||||
ticks: int = 1
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.operation not in OPERATIONS or self.result not in {OK, ERROR}:
|
||||
raise CompositionError("event operation/result is invalid")
|
||||
if (self.operation in INDEXED) != (self.segment >= 0):
|
||||
raise CompositionError("event segment binding is invalid")
|
||||
if not isinstance(self.segment, int) or isinstance(self.segment, bool):
|
||||
raise CompositionError("event segment is invalid")
|
||||
if not isinstance(self.ticks, int) or isinstance(self.ticks, bool) \
|
||||
or not 1 <= self.ticks <= MAX_TICKS:
|
||||
raise CompositionError("event ticks are invalid")
|
||||
|
||||
|
||||
class FakeFacade:
|
||||
"""Exact fake script with no process, mapping, clock or device access."""
|
||||
|
||||
def __init__(self, events: tuple[FakeEvent, ...]) -> None:
|
||||
if not isinstance(events, tuple) or not 1 <= len(events) <= MAX_EVENTS \
|
||||
or any(type(event) is not FakeEvent for event in events):
|
||||
raise CompositionError("fake composition script is invalid")
|
||||
self._events = list(events)
|
||||
self.ticks = 0
|
||||
|
||||
def invoke(self, operation: str, segment: int = -1,
|
||||
cleanup: bool = False) -> str:
|
||||
if not self._events:
|
||||
raise CompositionError("fake composition script is exhausted")
|
||||
event = self._events.pop(0)
|
||||
if event.operation != operation or event.segment != segment:
|
||||
raise CompositionError("fake composition ordering differs")
|
||||
if not cleanup and self.ticks + event.ticks > MAX_TICKS:
|
||||
raise CompositionError("composition deadline precedes operation")
|
||||
self.ticks += event.ticks
|
||||
return event.result
|
||||
|
||||
@property
|
||||
def remaining(self) -> int:
|
||||
return len(self._events)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CompositionOutcome:
|
||||
classification: str
|
||||
success: bool
|
||||
child_alive: bool
|
||||
image_retained: bool
|
||||
resources_open: int
|
||||
fail_closed_termination: bool
|
||||
target_action_performed: bool = False
|
||||
firmware_behavior_proven: bool = False
|
||||
|
||||
|
||||
def _require(facade: FakeFacade, operation: str, segment: int = -1) -> None:
|
||||
if facade.invoke(operation, segment) != OK:
|
||||
raise CompositionError(f"{operation} failed")
|
||||
|
||||
|
||||
def run_composition(plan: CompositionPlan, facade: FakeFacade) -> CompositionOutcome:
|
||||
"""Compose synthetic resources; cleanup failure requires child termination."""
|
||||
if type(plan) is not CompositionPlan or type(facade) is not FakeFacade:
|
||||
raise CompositionError("composition boundary is invalid")
|
||||
child = region = mirror = committed = False
|
||||
masters: set[int] = set()
|
||||
aliases: set[int] = set()
|
||||
host_aliases: set[int] = set()
|
||||
remote_aliases: set[int] = set()
|
||||
primary_failed = cleanup_failed = terminated = False
|
||||
|
||||
try:
|
||||
_require(facade, CREATE_CHILD)
|
||||
child = True
|
||||
_require(facade, RESERVE_REGION)
|
||||
region = True
|
||||
_require(facade, CREATE_MIRROR)
|
||||
mirror = True
|
||||
for segment in range(plan.executable_segments):
|
||||
_require(facade, CREATE_JIT_MASTER, segment)
|
||||
masters.add(segment)
|
||||
_require(facade, MAP_EXECUTABLE, segment)
|
||||
_require(facade, CREATE_JIT_ALIAS, segment)
|
||||
aliases.add(segment)
|
||||
_require(facade, MAP_HOST_ALIAS, segment)
|
||||
host_aliases.add(segment)
|
||||
_require(facade, MAP_REMOTE_ALIAS, segment)
|
||||
remote_aliases.add(segment)
|
||||
_require(facade, COPY_ALIAS, segment)
|
||||
_require(facade, UNMAP_REMOTE_ALIAS, segment)
|
||||
remote_aliases.remove(segment)
|
||||
_require(facade, UNMAP_HOST_ALIAS, segment)
|
||||
host_aliases.remove(segment)
|
||||
_require(facade, CLOSE_JIT_ALIAS, segment)
|
||||
aliases.remove(segment)
|
||||
_require(facade, CLOSE_JIT_MASTER, segment)
|
||||
masters.remove(segment)
|
||||
_require(facade, FINALIZE_IMAGE)
|
||||
_require(facade, RELEASE_MIRROR)
|
||||
mirror = False
|
||||
committed = True
|
||||
except Exception:
|
||||
primary_failed = True
|
||||
|
||||
if primary_failed:
|
||||
for resources, operation in (
|
||||
(remote_aliases, UNMAP_REMOTE_ALIAS),
|
||||
(host_aliases, UNMAP_HOST_ALIAS),
|
||||
(aliases, CLOSE_JIT_ALIAS),
|
||||
(masters, CLOSE_JIT_MASTER),
|
||||
):
|
||||
for segment in sorted(resources, reverse=True):
|
||||
if facade.invoke(operation, segment, cleanup=True) != OK:
|
||||
cleanup_failed = True
|
||||
else:
|
||||
resources.remove(segment)
|
||||
if mirror:
|
||||
if facade.invoke(RELEASE_MIRROR, cleanup=True) != OK:
|
||||
cleanup_failed = True
|
||||
else:
|
||||
mirror = False
|
||||
if region:
|
||||
if facade.invoke(UNMAP_REGION, cleanup=True) != OK:
|
||||
cleanup_failed = True
|
||||
else:
|
||||
region = False
|
||||
if child:
|
||||
if facade.invoke(KILL_AND_REAP_CHILD, cleanup=True) != OK:
|
||||
raise CompositionError("fail-closed child termination failed")
|
||||
child = False
|
||||
terminated = True
|
||||
masters.clear()
|
||||
aliases.clear()
|
||||
host_aliases.clear()
|
||||
remote_aliases.clear()
|
||||
mirror = region = False
|
||||
|
||||
if facade.remaining:
|
||||
raise CompositionError("fake composition script has unused operations")
|
||||
open_count = (int(mirror) + int(region) + len(masters) + len(aliases) +
|
||||
len(host_aliases) + len(remote_aliases))
|
||||
if primary_failed:
|
||||
if child or open_count:
|
||||
raise CompositionError("failed composition retained ownership")
|
||||
classification = ("OFFLINE_FAIL_CLOSED_AFTER_CLEANUP_FAILURE" if cleanup_failed
|
||||
else "OFFLINE_COMPOSITION_ROLLED_BACK")
|
||||
return CompositionOutcome(classification, False, False, False, 0,
|
||||
terminated)
|
||||
if not committed or not child or not region or mirror or open_count != 1:
|
||||
raise CompositionError("successful composition invariants failed")
|
||||
return CompositionOutcome("OFFLINE_HYBRID_COMPOSITION_COMPLETE", True,
|
||||
True, True, 0, False)
|
||||
Reference in New Issue
Block a user