Skip to content

Commit 19102a1

Browse files
authored
Merge pull request #994 from Yo-DDV/fix/launcher-lock-pidfd-compat
Fix launcher lock on Python without pidfd APIs
2 parents 7a12c74 + 7cc47e5 commit 19102a1

4 files changed

Lines changed: 56 additions & 48 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
3535

3636
### Fixed
3737

38+
- Launcher startup no longer requires Python's pidfd wrappers for normal
39+
launcher lock acquire and release. Pidfd remains reserved for the
40+
identity-verified stale Electron termination path.
3841
- Approval notifications now preserve the upstream Approve, Approve for
3942
session, and Decline actions on Linux. A small freedesktop notification
4043
bridge forwards the action and close signals that Electron's Linux

launcher/start.sh.template

Lines changed: 10 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3894,9 +3894,6 @@ parent_pid = int(sys.argv[1])
38943894
lock_path, wait_text, status_path = sys.argv[2:]
38953895
wait_seconds = int(wait_text)
38963896

3897-
if not hasattr(os, "pidfd_open") or not hasattr(signal, "pidfd_send_signal"):
3898-
sys.exit(1)
3899-
39003897
libc_name = ctypes.util.find_library("c") or "libc.so.6"
39013898
try:
39023899
libc = ctypes.CDLL(libc_name, use_errno=True)
@@ -3999,49 +3996,16 @@ launcher_lock_helper_is_active() {
39993996
}
40003997

40013998
stop_launcher_lock_helper() {
4002-
python3 - \
4003-
"$LAUNCHER_LOCK_HELPER_PID" \
4004-
"$LAUNCHER_LOCK_HELPER_START_TIME" \
4005-
"${BASHPID:-$$}" <<'PY'
4006-
import os
4007-
import select
4008-
import signal
4009-
import sys
4010-
4011-
pid = int(sys.argv[1])
4012-
expected_start_time = sys.argv[2]
4013-
expected_parent = int(sys.argv[3])
3999+
local actual_start_time
4000+
local cmdline
40144001

4015-
if not hasattr(os, "pidfd_open") or not hasattr(signal, "pidfd_send_signal"):
4016-
sys.exit(1)
4017-
try:
4018-
pidfd = os.pidfd_open(pid, 0)
4019-
with open(f"/proc/{pid}/stat", "r", encoding="utf-8") as handle:
4020-
fields = handle.read().rsplit(") ", 1)[1].split()
4021-
if fields[19] != expected_start_time or int(fields[1]) != expected_parent:
4022-
os.close(pidfd)
4023-
sys.exit(1)
4024-
poller = select.poll()
4025-
poller.register(pidfd, select.POLLIN)
4026-
exited = False
4027-
for requested_signal, wait_ms in (
4028-
(signal.SIGUSR1, 500),
4029-
(signal.SIGTERM, 500),
4030-
(signal.SIGKILL, 500),
4031-
):
4032-
try:
4033-
signal.pidfd_send_signal(pidfd, requested_signal)
4034-
except ProcessLookupError:
4035-
exited = True
4036-
break
4037-
if poller.poll(wait_ms):
4038-
exited = True
4039-
break
4040-
os.close(pidfd)
4041-
sys.exit(0 if exited else 1)
4042-
except (OSError, IndexError, ValueError):
4043-
sys.exit(1)
4044-
PY
4002+
[[ "$LAUNCHER_LOCK_HELPER_PID" =~ ^[0-9]+$ ]] || return 1
4003+
actual_start_time="$(pid_start_time "$LAUNCHER_LOCK_HELPER_PID" 2>/dev/null || true)"
4004+
[ -n "$actual_start_time" ] && [ "$actual_start_time" = "$LAUNCHER_LOCK_HELPER_START_TIME" ] || return 1
4005+
pid_parent_matches "$LAUNCHER_LOCK_HELPER_PID" "${BASHPID:-$$}" || return 1
4006+
cmdline="$(pid_cmdline "$LAUNCHER_LOCK_HELPER_PID")"
4007+
[[ "$cmdline" == *" $APP_STATE_DIR/launcher.lock "*" $LAUNCHER_LOCK_STATUS_PATH"* ]] || return 1
4008+
kill -TERM "$LAUNCHER_LOCK_HELPER_PID" 2>/dev/null || ! kill -0 "$LAUNCHER_LOCK_HELPER_PID" 2>/dev/null
40454009
}
40464010

40474011
release_launcher_lock() {
@@ -4051,7 +4015,7 @@ release_launcher_lock() {
40514015
if stop_launcher_lock_helper; then
40524016
wait "$LAUNCHER_LOCK_HELPER_PID" 2>/dev/null || true
40534017
else
4054-
echo "WARN: launcher lock helper did not exit after bounded pidfd signals" >&2
4018+
echo "WARN: launcher lock helper did not exit after a verified release signal" >&2
40554019
fi
40564020
fi
40574021
LAUNCHER_LOCK_HELPER_PID=""

tests/launcher_warm_start_recovery.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,21 @@ mkdir -p \
9797
"$HOME_DIR" \
9898
"$RUNTIME_DIR/codex-desktop"
9999

100+
if [ "${CODEX_TEST_DISABLE_PIDFD:-0}" = "1" ]; then
101+
mkdir -p "$TMP_DIR/python-site"
102+
cat > "$TMP_DIR/python-site/sitecustomize.py" <<'PY'
103+
import os
104+
import signal
105+
106+
for module, attribute in (
107+
(os, "pidfd_open"),
108+
(signal, "pidfd_send_signal"),
109+
):
110+
if hasattr(module, attribute):
111+
delattr(module, attribute)
112+
PY
113+
fi
114+
100115
if [ "${CODEX_TEST_DISABLE_WARM_START:-0}" = "1" ]; then
101116
printf '%s\n' '{"codex-linux-warm-start-enabled":false}' \
102117
> "$HOME_DIR/.config/codex-desktop/settings.json"
@@ -181,6 +196,9 @@ COMMON_ENV=(
181196
"CODEX_WEBVIEW_PORT=$PORT"
182197
"CODEX_TEST_HOOK_PID_FILE=$TMP_DIR/hook.pid"
183198
)
199+
if [ "${CODEX_TEST_DISABLE_PIDFD:-0}" = "1" ]; then
200+
COMMON_ENV+=("PYTHONPATH=$TMP_DIR/python-site")
201+
fi
184202

185203
"${COMMON_ENV[@]}" "$APP_DIR/start.sh" > "$FIRST_LOG" 2>&1 &
186204
LAUNCHER_PID=$!
@@ -213,9 +231,23 @@ if [ "${CODEX_TEST_KILL_DURING_PRELAUNCH:-0}" = "1" ]; then
213231
fi
214232

215233
wait_for "first Electron" pid_file_is_live
234+
wait_for "first launcher lock release" grep -q "electron_spawned" "$APP_LOG"
216235
wait_for "first packaged webview" webview_is_ready
217236
FIRST_ELECTRON_PID="$(read_live_app_pid)"
218237

238+
if [ "${CODEX_TEST_NORMAL_LOCK_ONLY:-0}" = "1" ]; then
239+
flock -n "$STATE_DIR/launcher.lock" true \
240+
|| fail "launcher lock should be released after app.pid publication"
241+
if grep -q "launcher lock helper did not exit" "$FIRST_LOG"; then
242+
fail "normal launcher lock release should not require pidfd escalation"
243+
fi
244+
kill "$FIRST_ELECTRON_PID"
245+
wait "$LAUNCHER_PID"
246+
LAUNCHER_PID=""
247+
printf '%s\n' "launcher normal lock test passed (pidfd disabled=${CODEX_TEST_DISABLE_PIDFD:-0})"
248+
exit 0
249+
fi
250+
219251
kill -KILL "$LAUNCHER_PID"
220252
wait "$LAUNCHER_PID" 2>/dev/null || true
221253
LAUNCHER_PID=""

tests/scripts_smoke.sh

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5580,8 +5580,13 @@ if "reap_orphaned_runtime_processes" in source or "pid_is_orphaned_runtime_proce
55805580
raise SystemExit("lock timeout must not kill processes belonging to the active serialized cold start")
55815581
if "LAUNCHER_LOCK_HELD=1" not in source or "stop_launcher_lock_helper" not in source:
55825582
raise SystemExit("launcher must explicitly release and reap its dedicated lock helper")
5583-
if "signal.SIGUSR1, 500" not in source or "signal.SIGTERM, 500" not in source or "signal.SIGKILL, 500" not in source:
5584-
raise SystemExit("launcher lock helper shutdown must use bounded identity-bound pidfd escalation")
5583+
stop_helper_body = source.split("stop_launcher_lock_helper() {", 1)[1].split("release_launcher_lock() {", 1)[0]
5584+
if "pidfd_open" in stop_helper_body or "pidfd_send_signal" in stop_helper_body:
5585+
raise SystemExit("normal launcher lock release must not require pidfd")
5586+
if 'kill -TERM "$LAUNCHER_LOCK_HELPER_PID"' not in stop_helper_body:
5587+
raise SystemExit("launcher lock helper must release through a verified child signal")
5588+
if 'read().strip() == "release"' in source or '"release\\n"' in source:
5589+
raise SystemExit("launcher lock release must not add a status-file control protocol")
55855590
if "launcher_lock_helper_is_active" not in source or "require_active_launcher_lock" not in launch_body:
55865591
raise SystemExit("launcher must fail closed if the identity-bound lock helper exits before Electron")
55875592
if "LAUNCHER_LOCK_CONTROL_PATH" in source or "mkfifo" in source:
@@ -10001,6 +10006,10 @@ test_launcher_warm_start_recovery() {
1000110006
bash "$REPO_DIR/tests/launcher_warm_start_recovery.sh"
1000210007
CODEX_TEST_DISABLE_WARM_START=1 bash "$REPO_DIR/tests/launcher_warm_start_recovery.sh"
1000310008
CODEX_TEST_KILL_DURING_PRELAUNCH=1 bash "$REPO_DIR/tests/launcher_warm_start_recovery.sh"
10009+
CODEX_TEST_DISABLE_PIDFD=1 CODEX_TEST_NORMAL_LOCK_ONLY=1 \
10010+
bash "$REPO_DIR/tests/launcher_warm_start_recovery.sh"
10011+
CODEX_TEST_DISABLE_PIDFD=1 CODEX_TEST_KILL_DURING_PRELAUNCH=1 \
10012+
bash "$REPO_DIR/tests/launcher_warm_start_recovery.sh"
1000410013
}
1000510014

1000610015
test_notification_actions_bridge_accepts_prebuilt_binary() {

0 commit comments

Comments
 (0)