Skip to content

Commit 581743f

Browse files
committed
Fix executor deadlock during shutdown
Check executor_enqueue() return value at all 8 call sites. When runtime is shutting down, return {error, runtime_shutting_down} instead of blocking forever on executor_wait(). Affected NIFs: worker_call, worker_eval, worker_exec, worker_next, import_module, get_attr, memory_stats, gc.
1 parent ba5633c commit 581743f

1 file changed

Lines changed: 32 additions & 8 deletions

File tree

c_src/py_nif.c

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,7 +1503,10 @@ static ERL_NIF_TERM nif_worker_call(ErlNifEnv *env, int argc, const ERL_NIF_TERM
15031503
}
15041504

15051505
/* Submit to executor and wait */
1506-
executor_enqueue(&req);
1506+
if (executor_enqueue(&req) != 0) {
1507+
request_cleanup(&req);
1508+
return make_error(env, "runtime_shutting_down");
1509+
}
15071510
executor_wait(&req);
15081511

15091512
ERL_NIF_TERM result = req.result;
@@ -1535,7 +1538,10 @@ static ERL_NIF_TERM nif_worker_eval(ErlNifEnv *env, int argc, const ERL_NIF_TERM
15351538
enif_get_ulong(env, argv[3], &req.timeout_ms);
15361539
}
15371540

1538-
executor_enqueue(&req);
1541+
if (executor_enqueue(&req) != 0) {
1542+
request_cleanup(&req);
1543+
return make_error(env, "runtime_shutting_down");
1544+
}
15391545
executor_wait(&req);
15401546

15411547
ERL_NIF_TERM result = req.result;
@@ -1562,7 +1568,10 @@ static ERL_NIF_TERM nif_worker_exec(ErlNifEnv *env, int argc, const ERL_NIF_TERM
15621568
return make_error(env, "invalid_code");
15631569
}
15641570

1565-
executor_enqueue(&req);
1571+
if (executor_enqueue(&req) != 0) {
1572+
request_cleanup(&req);
1573+
return make_error(env, "runtime_shutting_down");
1574+
}
15661575
executor_wait(&req);
15671576

15681577
ERL_NIF_TERM result = req.result;
@@ -1589,7 +1598,10 @@ static ERL_NIF_TERM nif_worker_next(ErlNifEnv *env, int argc, const ERL_NIF_TERM
15891598
req.env = env;
15901599
req.gen_wrapper = gen_wrapper;
15911600

1592-
executor_enqueue(&req);
1601+
if (executor_enqueue(&req) != 0) {
1602+
request_cleanup(&req);
1603+
return make_error(env, "runtime_shutting_down");
1604+
}
15931605
executor_wait(&req);
15941606

15951607
ERL_NIF_TERM result = req.result;
@@ -1616,7 +1628,10 @@ static ERL_NIF_TERM nif_import_module(ErlNifEnv *env, int argc, const ERL_NIF_TE
16161628
return make_error(env, "invalid_module");
16171629
}
16181630

1619-
executor_enqueue(&req);
1631+
if (executor_enqueue(&req) != 0) {
1632+
request_cleanup(&req);
1633+
return make_error(env, "runtime_shutting_down");
1634+
}
16201635
executor_wait(&req);
16211636

16221637
ERL_NIF_TERM result = req.result;
@@ -1648,7 +1663,10 @@ static ERL_NIF_TERM nif_get_attr(ErlNifEnv *env, int argc, const ERL_NIF_TERM ar
16481663
return make_error(env, "invalid_attr");
16491664
}
16501665

1651-
executor_enqueue(&req);
1666+
if (executor_enqueue(&req) != 0) {
1667+
request_cleanup(&req);
1668+
return make_error(env, "runtime_shutting_down");
1669+
}
16521670
executor_wait(&req);
16531671

16541672
ERL_NIF_TERM result = req.result;
@@ -1686,7 +1704,10 @@ static ERL_NIF_TERM nif_memory_stats(ErlNifEnv *env, int argc, const ERL_NIF_TER
16861704
req.type = PY_REQ_MEMORY_STATS;
16871705
req.env = env;
16881706

1689-
executor_enqueue(&req);
1707+
if (executor_enqueue(&req) != 0) {
1708+
request_cleanup(&req);
1709+
return make_error(env, "runtime_shutting_down");
1710+
}
16901711
executor_wait(&req);
16911712

16921713
ERL_NIF_TERM result = req.result;
@@ -1763,7 +1784,10 @@ static ERL_NIF_TERM nif_gc(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
17631784
enif_get_int(env, argv[0], &req.gc_generation);
17641785
}
17651786

1766-
executor_enqueue(&req);
1787+
if (executor_enqueue(&req) != 0) {
1788+
request_cleanup(&req);
1789+
return make_error(env, "runtime_shutting_down");
1790+
}
17671791
executor_wait(&req);
17681792

17691793
ERL_NIF_TERM result = req.result;

0 commit comments

Comments
 (0)