Skip to content

Commit f37945e

Browse files
committed
fix(dispatcher): restore daemon fast-path for Linux without C dispatcher
On Linux systems where the C dispatcher binary is unavailable (no gcc, read-only bin/, etc.), the Python dispatcher was silently bypassing the daemon on every invocation and falling through to a cold os.execv(), inflating wall time ~3x (~70ms → ~200ms). Root causes: - is_correct check hardcoded "Lib/site-packages" (Windows layout) so it always failed on Linux, triggering a stale config rewrite every call - Rewrite block wrote the same wrong path back, making it self-perpetuating - Linux daemon connect used hardcoded flat sock path instead of reading daemon_connection.txt (which the daemon uses to publish its hash-subdir socket path) - Clean daemon disconnect fell through to os.execv instead of sys.exit(0) Also: uninstall with no version spec now correctly bypasses daemon in dispatcher.c so the interactive version picker TUI works; setup.py compile error output improved; worker stdin reply timeout 5s → 120s.
1 parent e029623 commit f37945e

5 files changed

Lines changed: 46 additions & 11 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ version = "3.3.4"
1010
authors = [
1111
{ name = "1minds3t", email = "1minds3t@proton.me" },
1212
]
13-
description = "Runtime Hypervisor. Run infinite Python package & interpreter versions concurrently in one environment in milliseconds."
13+
description = "Python Runtime Hypervisor. Run infinite Python package & interpreter versions concurrently in one environment in milliseconds."
1414
readme = "README.md"
1515
requires-python = ">=3.7, <3.16"
1616

setup.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def _install_dispatcher_binary(install_dir=None):
103103
gcc = shutil.which("gcc")
104104
if gcc:
105105
compiler = gcc
106-
compiler_args = ["-O2", "-o", "{out}", "{src}", "-ldl"]
106+
compiler_args = ["-O2", "-o", "{out}", "{src}"]
107107
if sys.platform == "darwin":
108108
archflags = os.environ.get("ARCHFLAGS", "")
109109
if archflags:
@@ -133,7 +133,9 @@ def _install_dispatcher_binary(install_dir=None):
133133
try:
134134
result = subprocess.run(cmd, capture_output=True, text=True, env=compile_env)
135135
if result.returncode != 0:
136-
print(f" [dispatcher] Compilation failed: {result.stderr[:200]}")
136+
print(f" [dispatcher] Compilation failed (retcode={result.returncode})")
137+
print(f" [dispatcher] cmd: {' '.join(cmd)}")
138+
print(f" [dispatcher] stderr:\n{result.stderr.strip()}")
137139
return
138140

139141
import time
@@ -154,10 +156,9 @@ def _install_dispatcher_binary(install_dir=None):
154156
if replaced:
155157
binary_out.unlink(missing_ok=True)
156158
print(f" [dispatcher] ✅ Fast C dispatcher installed over: {replaced}")
157-
print(f" [dispatcher] binary source : {binary_out}")
158-
for name in replaced:
159-
target = Path(install_dir) / (name + _exe)
160-
print(f" [dispatcher] → {target}")
159+
for name in replaced:
160+
target = Path(install_dir) / (name + _exe)
161+
print(f" [dispatcher] → {target}")
161162
else:
162163
print(f" [dispatcher] Bundling compiled C dispatcher into the wheel.")
163164
print(f" [dispatcher] binary at : {binary_out.resolve()}")

src/omnipkg/common_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ def _read():
766766

767767
t = threading.Thread(target=_read, daemon=True)
768768
t.start()
769-
t.join(5.0)
769+
t.join(120.0)
770770
if t.is_alive():
771771
raise TimeoutError("no stdin reply within 5s")
772772
if exc[0]:

src/omnipkg/dispatcher.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2200,7 +2200,18 @@ int main(int argc, char **argv) {
22002200
}
22012201
}
22022202
}
2203-
is_interactive_command = ((is_info && !info_python) || is_config || is_logs_follow);
2203+
/* "uninstall <pkg>" with no version spec needs interactive version picker */
2204+
int is_uninstall_interactive = 0;
2205+
if (argc >= 3 && strcmp(argv[1], "uninstall") == 0) {
2206+
is_uninstall_interactive = 1;
2207+
for (int _i = 2; _i < argc; _i++) {
2208+
if (strchr(argv[_i], '=') || strchr(argv[_i], '>') || strchr(argv[_i], '<')) {
2209+
is_uninstall_interactive = 0; /* version spec present — daemon is fine */
2210+
break;
2211+
}
2212+
}
2213+
}
2214+
is_interactive_command = ((is_info && !info_python) || is_config || is_logs_follow || is_uninstall_interactive);
22042215
}
22052216
if (!is_swap_python && !is_interactive_command) {
22062217
try_daemon_cli(target_python, argc, argv, version_injected, forced_version);

src/omnipkg/dispatcher.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,20 @@ def main():
273273
else:
274274
raise ValueError()
275275
else:
276+
# Read daemon_connection.txt to get the actual socket path (daemon
277+
# may use a hash subdir e.g. /tmp/omnipkg/4db29431/omnipkg_daemon.sock).
278+
# Fall back to the flat path if the file is absent.
279+
conn_file = os.path.join(tempfile.gettempdir(), "omnipkg", "daemon_connection.txt")
280+
if os.path.exists(conn_file):
281+
try:
282+
with open(conn_file, "r") as f:
283+
conn_str = f.read().strip()
284+
if conn_str.startswith("unix://"):
285+
sock_path = conn_str[7:]
286+
elif conn_str and not conn_str.startswith("tcp://"):
287+
sock_path = conn_str # bare path
288+
except Exception:
289+
pass
276290
if os.path.exists(sock_path):
277291
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
278292
sock.connect(sock_path)
@@ -315,6 +329,7 @@ def main():
315329
elif msg.get("status") == "ERROR":
316330
sys.stderr.write(msg.get("error", "") + "\n")
317331
sys.exit(msg.get("exit_code", 1))
332+
sys.exit(0) # daemon closed connection cleanly — do NOT fall through to execv
318333
except Exception:
319334
pass
320335

@@ -1047,7 +1062,12 @@ def determine_target_python() -> Path:
10471062
current_exe = Path(sys.executable).resolve()
10481063

10491064
# Strong check: both executable AND site_packages_path must match native
1050-
expected_site = str(find_absolute_venv_root() / "Lib" / "site-packages")
1065+
_vr_check = find_absolute_venv_root()
1066+
if sys.platform == "win32":
1067+
expected_site = str(_vr_check / "Lib" / "site-packages")
1068+
else:
1069+
_py_mm_check = f"{sys.version_info.major}.{sys.version_info.minor}"
1070+
expected_site = str(_vr_check / "lib" / f"python{_py_mm_check}" / "site-packages")
10511071
actual_site = config.get("site_packages_path", "")
10521072

10531073
is_correct = (config_python == current_exe) and (actual_site == expected_site)
@@ -1067,7 +1087,10 @@ def determine_target_python() -> Path:
10671087
root_config = venv_root / ".omnipkg_config.json"
10681088

10691089
native_version = f"{sys.version_info.major}.{sys.version_info.minor}"
1070-
site_packages = str(venv_root / "Lib" / "site-packages")
1090+
if sys.platform == "win32":
1091+
site_packages = str(venv_root / "Lib" / "site-packages")
1092+
else:
1093+
site_packages = str(venv_root / "lib" / f"python{native_version}" / "site-packages")
10711094

10721095
config["python_executable"] = str(current_exe.resolve())
10731096
config["python_version"] = native_version

0 commit comments

Comments
 (0)