Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions src/madengine/scripts/common/post_scripts/dynolog_stop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ if [ ! -f "$DYNOLOG_START_FILE" ]; then
exit 0
fi

# Both processes are started in the background by the pre-script, so once it exits
# they are reparented to PID 1, which in a container is the model command rather
# than an init that reaps children. A terminated process therefore lingers as a
# zombie and `kill -0` keeps succeeding, so the process state has to be checked as
# well, or every stop would burn the full grace period below.
is_running() {
local pid=$1
kill -0 "$pid" 2>/dev/null || return 1
if [ -r "/proc/$pid/stat" ]; then
# State is the field after the command name, which itself may contain
# spaces and is always parenthesised.
local state
state=$(sed 's/.*) //' "/proc/$pid/stat" 2>/dev/null | cut -d' ' -f1)
[ "$state" = "Z" ] && return 1
fi
return 0
}

stop_pid() {
local name=$1
local pid_file=$2
Expand All @@ -31,14 +49,14 @@ stop_pid() {
fi
local pid
pid=$(cat "$pid_file")
if kill -0 "$pid" 2>/dev/null; then
if is_running "$pid"; then
kill -TERM "$pid" 2>/dev/null || true
local waited=0
while kill -0 "$pid" 2>/dev/null && [ $waited -lt 20 ]; do
while is_running "$pid" && [ $waited -lt 20 ]; do
sleep 0.5
waited=$((waited + 1))
done
if kill -0 "$pid" 2>/dev/null; then
if is_running "$pid"; then
echo "⚠️ $name did not stop gracefully, force killing..."
kill -9 "$pid" 2>/dev/null || true
fi
Expand Down
19 changes: 12 additions & 7 deletions src/madengine/scripts/common/tools/tracelens_analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ def _build_command(python: str, script_name: str, args: Sequence[str]) -> List[s

Prefers the installed console script (clearer logs, honours the package's
own entry-point wiring) and falls back to importing the module's ``main``.
The fallback exits with ``main()``'s return value, the same way the console
scripts pip generates do, so a report failure is not silently swallowed.
"""
bindir = os.path.dirname(os.path.abspath(python))
candidate = os.path.join(bindir, script_name)
Expand All @@ -216,7 +218,12 @@ def _build_command(python: str, script_name: str, args: Sequence[str]) -> List[s
if on_path:
return [on_path, *args]
module = _ENTRY_POINTS[script_name]
return [python, "-c", f"from {module} import main; main()", *args]
return [
python,
"-c",
f"import sys; from {module} import main; sys.exit(main())",
*args,
]


def _run(command: Sequence[str], cwd: Optional[str] = None) -> Tuple[int, str]:
Expand Down Expand Up @@ -461,9 +468,9 @@ def analyze(
code, output = _run(_build_command(interpreter, tool, args))
results.append(
{
"trace_file": os.path.relpath(trace, root)
if os.path.exists(trace)
else trace,
"trace_file": (
os.path.relpath(trace, root) if os.path.exists(trace) else trace
),
"kind": kind,
"tracelens_tool": tool,
"status": "SUCCESS" if code == 0 else "FAILURE",
Expand Down Expand Up @@ -605,9 +612,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
)
failed = summary["status"] != "SUCCESS"
elif args.discover_only:
traces, unsupported = discover_traces(
args.root, exclude_dirs=[args.output_dir]
)
traces, unsupported = discover_traces(args.root, exclude_dirs=[args.output_dir])
for kind, paths in sorted(traces.items()):
for path in paths:
print(f"{kind}\t{path}")
Expand Down
Loading