ha(H2): ниты повторного ревью — pump без параллельных читателей, pending-рефкаунт, точная ошибка свойств

- session.py: новый лог-памп не поднимается, пока предыдущий не завершился
  (stopping/is_alive), параллельное чтение кольца исключено
- __init__: счётчик pending закрывает окно гонки setup/unload последней
  записи; warning при не-словарном fglair: в YAML
- trial: properties_missing — отдельная ошибка формы/abort (en/ru/strings)
- ConfigEntryNotReady: «порт 0» больше не показывается
- тесты: контраст одинакового явного порта, неблокирующий unload (тикер loop)
- план H5: публикация pyfglair именно на PyPI (manylinux x86_64/aarch64)
This commit is contained in:
2026-09-29 12:29:35 +03:00
parent da01c607a6
commit 29f62b639c
9 changed files with 109 additions and 26 deletions
+20 -7
View File
@@ -66,6 +66,7 @@ class _LogPump(threading.Thread):
def __init__(self) -> None:
super().__init__(name="pyfglair-log", daemon=True)
self._stop = threading.Event()
self.stopping = False
def run(self) -> None:
out = ffi.new("fgl_log_event_t[]", 8)
@@ -95,6 +96,7 @@ class _LogPump(threading.Thread):
_LOGGER.exception("log handler failed")
def stop(self) -> None:
self.stopping = True
self._stop.set()
self.join(timeout=2.0)
@@ -102,19 +104,30 @@ class _LogPump(threading.Thread):
def set_log_handler(handler: Optional[LogHandler]) -> None:
"""Глобальный приёмник логов ядра (0=debug..3=error).
``None`` останавливает pump-поток (если он запущен).
``None`` останавливает pump-поток (если он запущен). Новый pump не
поднимается, пока предыдущий не завершился: параллельные читатели одного
кольца недопустимы.
"""
global _GLOBAL_LOG, _LOG_PUMP
with _LOG_PUMP_LOCK:
_GLOBAL_LOG = handler
if handler is None:
pump, _LOG_PUMP = _LOG_PUMP, None
if pump is not None:
pump.stop()
if _LOG_PUMP is not None:
_LOG_PUMP.stop()
return
if _LOG_PUMP is None:
_LOG_PUMP = _LogPump()
_LOG_PUMP.start()
pump = _LOG_PUMP
if pump is not None and pump.is_alive():
if not pump.stopping:
return # уже работает и не остановлен
pump.join(timeout=2.0)
if pump.is_alive():
_LOGGER.warning(
"лог-памп не завершился; новый не запускаю (обработчик "
"логов блокируется?)"
)
return
_LOG_PUMP = _LogPump()
_LOG_PUMP.start()
def set_log_level(level: int) -> None: