Source code for zephon.debug.semaphore_registry
# Copyright 2025 DatologyAI
# SPDX-License-Identifier: Apache-2.0
"""Debug registry for tracking SafeSemLock instances.
This module provides a registry that tracks semaphore creation and cleanup
for debugging purposes. Enable with ZEPHON_SEMAPHORE_DEBUG=1 environment variable.
The registry is used by:
- SafeSemLock.__init__(): registers semaphores on creation
- SafeSemLock.cleanup(): marks semaphores as cleaned
- dump_semaphore_registry(): prints debug info at shutdown
- debug/semaphore_tracker.py: reads for leak analysis
"""
from __future__ import annotations
import os
import threading
# Debug registry: maps semaphore name -> (source, cleaned_up)
_semaphore_registry: dict[str, tuple[str, bool]] = {}
_registry_lock = threading.Lock()
def _is_semaphore_debug_enabled() -> bool:
"""Check if semaphore debug tracking is enabled via env var."""
return os.environ.get("ZEPHON_SEMAPHORE_DEBUG", "").lower() in ("1", "true", "yes")
def _register_semaphore(name: str, source: str) -> None:
"""Register a semaphore for debug tracking."""
if not _is_semaphore_debug_enabled() or name is None:
return
with _registry_lock:
_semaphore_registry[name] = (source, False)
def _mark_semaphore_cleaned(name: str) -> None:
"""Mark a semaphore as cleaned up."""
if not _is_semaphore_debug_enabled() or name is None:
return
with _registry_lock:
if name in _semaphore_registry:
source, _ = _semaphore_registry[name]
_semaphore_registry[name] = (source, True)
[docs]
def dump_semaphore_registry() -> None:
"""Print debug info about tracked semaphores."""
if not _is_semaphore_debug_enabled():
return
with _registry_lock:
if not _semaphore_registry:
return
print(f"\n=== Semaphore Registry ({len(_semaphore_registry)} total) ===")
not_cleaned = [(n, s) for n, (s, c) in _semaphore_registry.items() if not c]
cleaned = [(n, s) for n, (s, c) in _semaphore_registry.items() if c]
print(f"Cleaned: {len(cleaned)}, Not cleaned: {len(not_cleaned)}")
if not_cleaned:
print("\nNOT CLEANED:")
for name, source in sorted(not_cleaned, key=lambda x: x[1]):
print(f" {name}: {source}")
__all__ = [
"dump_semaphore_registry",
]