@@ -3224,43 +3224,6 @@ static void owngil_execute_apply_imports(py_context_t *ctx) {
32243224 ctx -> response_ok = true;
32253225}
32263226
3227- /**
3228- * @brief Execute flush_imports in OWN_GIL context
3229- *
3230- * Clears the per-context module cache optimization layer.
3231- * Does NOT clear sys.modules (that would break Python).
3232- */
3233- static void owngil_execute_flush_imports (py_context_t * ctx ) {
3234- /* Remove specified modules from sys.modules */
3235- PyObject * sys_modules = PyImport_GetModuleDict (); /* Borrowed ref */
3236- if (sys_modules != NULL ) {
3237- ERL_NIF_TERM head , tail = ctx -> request_data ;
3238- while (enif_get_list_cell (ctx -> shared_env , tail , & head , & tail )) {
3239- ErlNifBinary mod_bin ;
3240- if (enif_inspect_binary (ctx -> shared_env , head , & mod_bin )) {
3241- char * mod_name = enif_alloc (mod_bin .size + 1 );
3242- if (mod_name != NULL ) {
3243- memcpy (mod_name , mod_bin .data , mod_bin .size );
3244- mod_name [mod_bin .size ] = '\0' ;
3245- /* Remove module from sys.modules if present */
3246- if (PyDict_GetItemString (sys_modules , mod_name ) != NULL ) {
3247- PyDict_DelItemString (sys_modules , mod_name );
3248- }
3249- enif_free (mod_name );
3250- }
3251- }
3252- }
3253- }
3254-
3255- /* Clear the per-context optimization cache if it exists */
3256- if (ctx -> module_cache != NULL ) {
3257- PyDict_Clear (ctx -> module_cache );
3258- }
3259-
3260- ctx -> response_term = enif_make_atom (ctx -> shared_env , "ok" );
3261- ctx -> response_ok = true;
3262- }
3263-
32643227/**
32653228 * @brief Execute a request based on its type
32663229 */
@@ -3299,9 +3262,6 @@ static void owngil_execute_request(py_context_t *ctx) {
32993262 case CTX_REQ_APPLY_IMPORTS :
33003263 owngil_execute_apply_imports (ctx );
33013264 break ;
3302- case CTX_REQ_FLUSH_IMPORTS :
3303- owngil_execute_flush_imports (ctx );
3304- break ;
33053265 default :
33063266 ctx -> response_term = enif_make_tuple2 (ctx -> shared_env ,
33073267 enif_make_atom (ctx -> shared_env , "error" ),
@@ -3911,50 +3871,6 @@ static ERL_NIF_TERM dispatch_apply_imports_to_owngil(
39113871 return result ;
39123872}
39133873
3914- /**
3915- * @brief Dispatch flush_imports to OWN_GIL worker thread
3916- *
3917- * @param env NIF environment
3918- * @param ctx Context resource
3919- * @param modules_list List of module names to remove from sys.modules
3920- * @return ok
3921- */
3922- static ERL_NIF_TERM dispatch_flush_imports_to_owngil (
3923- ErlNifEnv * env , py_context_t * ctx , ERL_NIF_TERM modules_list
3924- ) {
3925- if (!atomic_load (& ctx -> thread_running )) {
3926- return make_error (env , "thread_not_running" );
3927- }
3928-
3929- pthread_mutex_lock (& ctx -> request_mutex );
3930-
3931- enif_clear_env (ctx -> shared_env );
3932- ctx -> request_type = CTX_REQ_FLUSH_IMPORTS ;
3933- ctx -> request_data = enif_make_copy (ctx -> shared_env , modules_list );
3934-
3935- pthread_cond_signal (& ctx -> request_ready );
3936-
3937- /* Wait for response with timeout */
3938- struct timespec deadline ;
3939- clock_gettime (CLOCK_REALTIME , & deadline );
3940- deadline .tv_sec += OWNGIL_DISPATCH_TIMEOUT_SECS ;
3941-
3942- while (ctx -> request_type != CTX_REQ_NONE ) {
3943- int rc = pthread_cond_timedwait (& ctx -> response_ready , & ctx -> request_mutex , & deadline );
3944- if (rc == ETIMEDOUT ) {
3945- atomic_store (& ctx -> thread_running , false);
3946- pthread_mutex_unlock (& ctx -> request_mutex );
3947- fprintf (stderr , "OWN_GIL flush_imports dispatch timeout: worker thread unresponsive\n" );
3948- return make_error (env , "worker_timeout" );
3949- }
3950- }
3951-
3952- ERL_NIF_TERM result = enif_make_copy (env , ctx -> response_term );
3953- pthread_mutex_unlock (& ctx -> request_mutex );
3954-
3955- return result ;
3956- }
3957-
39583874#endif /* HAVE_SUBINTERPRETERS */
39593875
39603876/**
@@ -4124,7 +4040,6 @@ static ERL_NIF_TERM nif_context_create(ErlNifEnv *env, int argc, const ERL_NIF_T
41244040 ctx -> globals = NULL ;
41254041 ctx -> locals = NULL ;
41264042 ctx -> module_cache = NULL ;
4127- ctx -> cache_generation = 0 ;
41284043
41294044 /* Create callback pipe for blocking callback responses */
41304045 if (pipe (ctx -> callback_pipe ) < 0 ) {
@@ -4237,7 +4152,6 @@ static ERL_NIF_TERM nif_context_create(ErlNifEnv *env, int argc, const ERL_NIF_T
42374152 ctx -> globals = PyDict_New ();
42384153 ctx -> locals = PyDict_New ();
42394154 ctx -> module_cache = PyDict_New ();
4240- ctx -> cache_generation = import_cache_get_generation ();
42414155
42424156 /* Import __builtins__ into globals */
42434157 PyObject * builtins = PyEval_GetBuiltins ();
@@ -4370,25 +4284,6 @@ static ERL_NIF_TERM nif_context_destroy(ErlNifEnv *env, int argc, const ERL_NIF_
43704284 * Helper function - no mutex needed since context is process-owned.
43714285 */
43724286static PyObject * context_get_module (py_context_t * ctx , const char * module_name ) {
4373- /* Check for stale cache (main interpreter contexts only) */
4374- if (ctx -> module_cache != NULL ) {
4375- #ifdef HAVE_SUBINTERPRETERS
4376- /* Pool-backed contexts get fresh interpreters on flush, so only check
4377- * for non-pool contexts (main interpreter or OWN_GIL) */
4378- bool is_main_interp = (ctx -> pool_slot < 0 && !ctx -> uses_own_gil );
4379- #else
4380- bool is_main_interp = true; /* All contexts use main interpreter */
4381- #endif
4382- if (is_main_interp ) {
4383- uint64_t current_gen = import_cache_get_generation ();
4384- if (ctx -> cache_generation != current_gen ) {
4385- /* Cache is stale - clear it and update generation */
4386- PyDict_Clear (ctx -> module_cache );
4387- ctx -> cache_generation = current_gen ;
4388- }
4389- }
4390- }
4391-
43924287 /* Check cache first */
43934288 if (ctx -> module_cache != NULL ) {
43944289 PyObject * cached = PyDict_GetItemString (ctx -> module_cache , module_name );
@@ -5040,97 +4935,6 @@ static ERL_NIF_TERM nif_interp_apply_imports(ErlNifEnv *env, int argc, const ERL
50404935 return ATOM_OK ;
50414936}
50424937
5043- /**
5044- * @brief Flush imports from an interpreter's sys.modules
5045- *
5046- * nif_interp_flush_imports(Ref, Modules) -> ok
5047- *
5048- * Removes specified modules from sys.modules and clears the per-context
5049- * module_cache optimization layer.
5050- *
5051- * @param Ref Context reference
5052- * @param Modules List of binary module names to remove from sys.modules
5053- */
5054- static ERL_NIF_TERM nif_interp_flush_imports (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
5055- (void )argc ;
5056- py_context_t * ctx ;
5057-
5058- if (!runtime_is_running ()) {
5059- return ATOM_OK ; /* Nothing to flush if Python not running */
5060- }
5061-
5062- if (!enif_get_resource (env , argv [0 ], PY_CONTEXT_RESOURCE_TYPE , (void * * )& ctx )) {
5063- return make_error (env , "invalid_context" );
5064- }
5065-
5066- if (ctx -> destroyed ) {
5067- return ATOM_OK ; /* Already destroyed */
5068- }
5069-
5070- #ifdef HAVE_SUBINTERPRETERS
5071- /* OWN_GIL mode: dispatch to the dedicated thread */
5072- if (ctx -> uses_own_gil ) {
5073- return dispatch_flush_imports_to_owngil (env , ctx , argv [1 ]);
5074- }
5075- #endif
5076-
5077- py_context_guard_t guard = py_context_acquire (ctx );
5078- if (!guard .acquired ) {
5079- return ATOM_OK ; /* Can't acquire - just return ok */
5080- }
5081-
5082- /* Remove specified modules from sys.modules */
5083- PyObject * sys_modules = PyImport_GetModuleDict (); /* Borrowed ref */
5084- if (sys_modules != NULL ) {
5085- ERL_NIF_TERM head , tail = argv [1 ];
5086- while (enif_get_list_cell (env , tail , & head , & tail )) {
5087- ErlNifBinary mod_bin ;
5088- if (enif_inspect_binary (env , head , & mod_bin )) {
5089- char * mod_name = binary_to_string (& mod_bin );
5090- if (mod_name != NULL ) {
5091- /* Remove module from sys.modules if present */
5092- if (PyDict_GetItemString (sys_modules , mod_name ) != NULL ) {
5093- PyDict_DelItemString (sys_modules , mod_name );
5094- }
5095- enif_free (mod_name );
5096- }
5097- }
5098- }
5099- }
5100-
5101- /* Clear per-context optimization cache */
5102- if (ctx -> module_cache != NULL ) {
5103- PyDict_Clear (ctx -> module_cache );
5104- }
5105-
5106- py_context_release (& guard );
5107- return ATOM_OK ;
5108- }
5109-
5110- /**
5111- * @brief Flush import generation and mark all pool slots stale
5112- *
5113- * nif_subinterp_pool_flush_generation() -> {ok, NewGeneration}
5114- *
5115- * Increments the global import generation counter and marks all initialized
5116- * pool slots as stale. When a stale slot's usage count drops to 0, the
5117- * subinterpreter is automatically destroyed and the slot becomes available
5118- * for a fresh subinterpreter.
5119- *
5120- * This enables flush_imports to work by replacing subinterpreters rather
5121- * than trying to manipulate sys.modules directly (which can crash C extensions).
5122- */
5123- static ERL_NIF_TERM nif_subinterp_pool_flush_generation (ErlNifEnv * env , int argc , const ERL_NIF_TERM argv []) {
5124- (void )argc ;
5125- (void )argv ;
5126-
5127- /* Use the unconditional version that works with or without subinterpreters.
5128- * This increments the generation counter (used by main interpreter contexts)
5129- * and also marks pool slots stale when subinterpreters are available. */
5130- uint64_t new_gen = import_cache_flush_generation ();
5131- return enif_make_tuple2 (env , ATOM_OK , enif_make_uint64 (env , new_gen ));
5132- }
5133-
51344938/**
51354939 * @brief Execute Python statements using a process-local environment
51364940 *
@@ -7261,8 +7065,6 @@ static ErlNifFunc nif_funcs[] = {
72617065 {"context_call" , 6 , nif_context_call_with_env , ERL_NIF_DIRTY_JOB_CPU_BOUND },
72627066 {"create_local_env" , 1 , nif_create_local_env , 0 },
72637067 {"interp_apply_imports" , 2 , nif_interp_apply_imports , ERL_NIF_DIRTY_JOB_CPU_BOUND },
7264- {"interp_flush_imports" , 2 , nif_interp_flush_imports , ERL_NIF_DIRTY_JOB_CPU_BOUND },
7265- {"subinterp_pool_flush_generation" , 0 , nif_subinterp_pool_flush_generation , 0 },
72667068 {"context_call_method" , 4 , nif_context_call_method , ERL_NIF_DIRTY_JOB_CPU_BOUND },
72677069 {"context_to_term" , 1 , nif_context_to_term , 0 },
72687070 {"context_interp_id" , 1 , nif_context_interp_id , 0 },
0 commit comments