Skip to content

Commit 389b573

Browse files
committed
rtc: fail fast instead of hanging when FFI is used across fork()
The native runtime (tokio worker/IO threads in liblivekit_ffi) does not survive fork() and cannot be rebuilt by re-initializing, so a child that inherited an initialized FfiClient would hang on every request. Guard request() with the owning pid and raise a clear error instead. The atexit dispose handler is likewise skipped in fork children (it needs the runtime and would hang at exit). Also move the drop_handle side effect out of an assert so it is not stripped under python -O.
1 parent 3f92f3c commit 389b573

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

livekit-rtc/livekit/rtc/_ffi_client.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ def disposed(self) -> bool:
8383
def dispose(self) -> None:
8484
if self.handle != INVALID_HANDLE and not self._disposed:
8585
self._disposed = True
86-
assert FfiClient.instance._ffi_lib.livekit_ffi_drop_handle(ctypes.c_uint64(self.handle))
86+
dropped = FfiClient.instance._ffi_lib.livekit_ffi_drop_handle(
87+
ctypes.c_uint64(self.handle)
88+
)
89+
assert dropped
8790

8891
def __repr__(self) -> str:
8992
return f"FfiHandle({self.handle})"
@@ -218,6 +221,7 @@ def instance(cls) -> "FfiClient":
218221
return cls._instance
219222

220223
def __init__(self) -> None:
224+
self._pid = os.getpid()
221225
self._lock = threading.RLock()
222226
self._queue = FfiQueue[proto_ffi.FfiEvent]()
223227

@@ -253,16 +257,25 @@ def __init__(self) -> None:
253257
)
254258

255259
ffi_lib = self._ffi_lib
260+
init_pid = self._pid
256261

257262
@atexit.register
258263
def _dispose_lk_ffi() -> None:
264+
if os.getpid() != init_pid:
265+
return
259266
ffi_lib.livekit_ffi_dispose()
260267

261268
@property
262269
def queue(self) -> FfiQueue[proto_ffi.FfiEvent]:
263270
return self._queue
264271

265272
def request(self, req: proto_ffi.FfiRequest) -> proto_ffi.FfiResponse:
273+
if self._pid != os.getpid():
274+
raise RuntimeError(
275+
"livekit.rtc was used in a parent process before fork(); the native "
276+
"runtime cannot be used across fork(). Do not create or connect a Room "
277+
"(or use any livekit.rtc object) before forking child processes."
278+
)
266279
proto_data = req.SerializeToString()
267280
proto_len = len(proto_data)
268281
data = (ctypes.c_ubyte * proto_len)(*proto_data)

0 commit comments

Comments
 (0)