mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
revng.daemon: prevent shutdown crash
Change the behavior of `revng daemon` to avoid a crash at shutdown caused by `rp_shutdown` not being called due to the pointer of `rp_manager` not being freed.
This commit is contained in:
@@ -16,6 +16,12 @@ from revng.support import AnyPaths, get_root, to_iterable
|
||||
from revng.support.collect import collect_files, collect_libraries, collect_one
|
||||
|
||||
|
||||
# This counter is used to count the pointers released by PipelineC, since
|
||||
# calling rp_shutdown before all pointers are freed leads to a crash
|
||||
# This will count (atomically) the pointers created by PipelineC and decrements
|
||||
# once the pointer is freed by `ffi.gc`. Once the API signals that it will no
|
||||
# longer do anything (by calling `mark_end`) then once the counter reaches 0
|
||||
# the callback can be invoked which will safely call rp_shutdown.
|
||||
class AtomicCounterWithCallback:
|
||||
"""Simple atomic counter, will call callback once mark_end has been called
|
||||
and the counter reaches zero"""
|
||||
@@ -39,6 +45,8 @@ class AtomicCounterWithCallback:
|
||||
def mark_end(self):
|
||||
with self.lock:
|
||||
self.ending = True
|
||||
if self.counter == 0:
|
||||
self.callback()
|
||||
|
||||
|
||||
class ApiWrapper:
|
||||
|
||||
@@ -75,7 +75,7 @@ class AnalysesList(Sequence[Analysis]):
|
||||
return _api.rp_analyses_list_count(self._analyses_list)
|
||||
|
||||
def _get_analysis(self, index: int) -> Analysis:
|
||||
_analysis = _api.rp_manager_get_analysis(self._manager, self._analyses_list, index)
|
||||
_analysis = _api.rp_manager_get_analysis(self._manager._manager, self._analyses_list, index)
|
||||
return Analysis(_analysis)
|
||||
|
||||
@overload
|
||||
|
||||
@@ -427,7 +427,7 @@ class Manager:
|
||||
|
||||
def _analyses_list_get(self, index: int) -> AnalysesList:
|
||||
_analyses_list = _api.rp_manager_get_analyses_list(self._manager, index)
|
||||
return AnalysesList(_analyses_list, self._manager)
|
||||
return AnalysesList(_analyses_list, self)
|
||||
|
||||
def analyses_lists(self) -> Generator[AnalysesList, None, None]:
|
||||
return make_generator(self._analyses_list_count(), self._analyses_list_get)
|
||||
|
||||
@@ -105,7 +105,7 @@ def make_startlette() -> Starlette:
|
||||
}
|
||||
|
||||
routes = [
|
||||
Route("/", generate_demo_page(manager, DEBUG), methods=["GET"]),
|
||||
Route("/", generate_demo_page(manager.workdir, DEBUG), methods=["GET"]),
|
||||
Route("/status", status, methods=["GET"]),
|
||||
Mount(
|
||||
"/graphql",
|
||||
@@ -129,6 +129,7 @@ def make_startlette() -> Starlette:
|
||||
store_result = manager.save()
|
||||
if not store_result:
|
||||
logging.warning("Failed to store manager's containers")
|
||||
manager._manager = None
|
||||
capi_shutdown()
|
||||
|
||||
return Starlette(
|
||||
|
||||
@@ -8,18 +8,16 @@ from starlette.requests import Request
|
||||
from starlette.responses import PlainTextResponse
|
||||
from starlette.templating import Jinja2Templates
|
||||
|
||||
from revng.api import Manager
|
||||
|
||||
module_dir = Path(__file__).parent.resolve()
|
||||
templates = Jinja2Templates(directory=module_dir / "templates")
|
||||
|
||||
|
||||
def generate_demo_page(manager: Manager, debug: bool):
|
||||
def generate_demo_page(workdir: Path, debug: bool):
|
||||
if debug:
|
||||
|
||||
async def dev_demo_page(request: Request):
|
||||
return templates.TemplateResponse(
|
||||
"index.html", {"request": request, "manager": manager}
|
||||
"index.html", {"request": request, "workdir": workdir}
|
||||
)
|
||||
|
||||
return dev_demo_page
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<div>
|
||||
Welcome to revng!<br />
|
||||
Working directory is {{ manager.workdir }}
|
||||
Working directory is {{ workdir }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user