Skip to content

Commit 738c625

Browse files
committed
Add timeout to OWN_GIL context shutdown
Prevents hanging forever if Python thread is stuck. Uses 30 second timeout with platform-specific implementation: - Linux: pthread_timedjoin_np() with deadline - macOS/other: poll thread_running flag On timeout, logs warning and detaches thread instead of blocking.
1 parent 581743f commit 738c625

1 file changed

Lines changed: 31 additions & 2 deletions

File tree

c_src/py_nif.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4115,8 +4115,12 @@ static int owngil_context_init(py_context_t *ctx) {
41154115
/**
41164116
* @brief Shutdown OWN_GIL context and clean up resources
41174117
*
4118+
* Uses a timeout to avoid hanging forever if the Python thread is stuck.
4119+
*
41184120
* @param ctx Context to shutdown
41194121
*/
4122+
#define OWNGIL_SHUTDOWN_TIMEOUT_SECS 30
4123+
41204124
static void owngil_context_shutdown(py_context_t *ctx) {
41214125
if (!ctx->uses_own_gil) {
41224126
return;
@@ -4130,8 +4134,33 @@ static void owngil_context_shutdown(py_context_t *ctx) {
41304134
pthread_cond_signal(&ctx->request_ready);
41314135
pthread_mutex_unlock(&ctx->request_mutex);
41324136

4133-
/* Wait for thread to exit */
4134-
pthread_join(ctx->own_gil_thread, NULL);
4137+
/* Wait for thread to exit with timeout */
4138+
#if defined(__linux__)
4139+
struct timespec deadline;
4140+
clock_gettime(CLOCK_REALTIME, &deadline);
4141+
deadline.tv_sec += OWNGIL_SHUTDOWN_TIMEOUT_SECS;
4142+
int rc = pthread_timedjoin_np(ctx->own_gil_thread, NULL, &deadline);
4143+
if (rc == ETIMEDOUT) {
4144+
fprintf(stderr, "OWN_GIL shutdown timeout after %d seconds, detaching thread\n",
4145+
OWNGIL_SHUTDOWN_TIMEOUT_SECS);
4146+
pthread_detach(ctx->own_gil_thread);
4147+
}
4148+
#else
4149+
/* macOS/other: poll thread_running flag with timeout */
4150+
int wait_ms = 0;
4151+
while (atomic_load(&ctx->thread_running) &&
4152+
wait_ms < OWNGIL_SHUTDOWN_TIMEOUT_SECS * 1000) {
4153+
usleep(100000); /* 100ms */
4154+
wait_ms += 100;
4155+
}
4156+
if (atomic_load(&ctx->thread_running)) {
4157+
fprintf(stderr, "OWN_GIL shutdown timeout after %d seconds, detaching thread\n",
4158+
OWNGIL_SHUTDOWN_TIMEOUT_SECS);
4159+
pthread_detach(ctx->own_gil_thread);
4160+
} else {
4161+
pthread_join(ctx->own_gil_thread, NULL);
4162+
}
4163+
#endif
41354164

41364165
/* Clean up resources */
41374166
if (ctx->shared_env != NULL) {

0 commit comments

Comments
 (0)