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:
Giacomo Vercesi
2023-06-30 09:52:57 +02:00
parent 406a21360a
commit 0ec2fdd175
6 changed files with 15 additions and 8 deletions
+8
View File
@@ -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:
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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)
+2 -1
View File
@@ -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(
+2 -4
View File
@@ -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
+1 -1
View File
@@ -9,7 +9,7 @@
</div>
<div>
Welcome to revng!<br />
Working directory is {{ manager.workdir }}
Working directory is {{ workdir }}
</div>
<div>