Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 67 additions & 14 deletions core/src/drivers/plugin_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,14 @@ int plugin_driver_init(plugin_driver_t *driver)
return -1;
}

PyGILState_STATE local_gstate = PyGILState_Ensure();
// Only acquire Python GIL if we have Python plugins and Python is initialized
// Initialize to PyGILState_LOCKED (0) to satisfy compiler warning
PyGILState_STATE local_gstate = PyGILState_LOCKED;
int have_gil = has_python_plugin && Py_IsInitialized();
if (have_gil)
{
local_gstate = PyGILState_Ensure();
}

// #chamdo a função init de cada plugin aqui
for (int i = 0; i < driver->plugin_count; i++)
Expand All @@ -306,7 +313,10 @@ int plugin_driver_init(plugin_driver_t *driver)
fprintf(stderr, "Failed to generate runtime args for plugin: %s\n",
plugin->config.name);

PyGILState_Release(local_gstate);
if (have_gil)
{
PyGILState_Release(local_gstate);
}
return -1;
}
// Call the Python init function with proper capsule
Expand All @@ -322,7 +332,10 @@ int plugin_driver_init(plugin_driver_t *driver)
fprintf(stderr, "Python init function failed for plugin: %s\n",
plugin->config.name);

PyGILState_Release(local_gstate);
if (have_gil)
{
PyGILState_Release(local_gstate);
}
return -1;
}
Py_DECREF(result);
Expand All @@ -338,6 +351,10 @@ int plugin_driver_init(plugin_driver_t *driver)
{
fprintf(stderr, "Failed to generate runtime args for native plugin: %s\n",
plugin->config.name);
if (have_gil)
{
PyGILState_Release(local_gstate);
}
return -1;
}

Expand All @@ -348,6 +365,10 @@ int plugin_driver_init(plugin_driver_t *driver)
fprintf(stderr, "Native init function failed for plugin: %s (returned %d)\n",
plugin->config.name, result);
free_structured_args(args);
if (have_gil)
{
PyGILState_Release(local_gstate);
}
return -1;
}

Expand All @@ -356,7 +377,10 @@ int plugin_driver_init(plugin_driver_t *driver)
}
}

PyGILState_Release(local_gstate);
if (have_gil)
{
PyGILState_Release(local_gstate);
}

return 0;
}
Expand All @@ -375,8 +399,12 @@ int plugin_driver_start(plugin_driver_t *driver)
return 0;
}

gstate = PyGILState_Ensure();
main_tstate = PyEval_SaveThread();
// Only manage Python GIL if we have Python plugins and Python is initialized
if (has_python_plugin && Py_IsInitialized())
{
gstate = PyGILState_Ensure();
main_tstate = PyEval_SaveThread();
}

for (int i = 0; i < driver->plugin_count; i++)
{
Expand Down Expand Up @@ -465,7 +493,13 @@ int plugin_driver_stop(plugin_driver_t *driver)
return 0;
}

PyGILState_STATE local_gstate = PyGILState_Ensure();
// Only acquire Python GIL if we have Python plugins and Python is initialized
PyGILState_STATE local_gstate;
int need_gil = has_python_plugin && Py_IsInitialized();
if (need_gil)
{
local_gstate = PyGILState_Ensure();
}

// Signal all plugins to stop
for (int i = 0; i < driver->plugin_count; i++)
Expand Down Expand Up @@ -508,7 +542,10 @@ int plugin_driver_stop(plugin_driver_t *driver)
// Plugin manager only handles destruction, not stopping
}

PyGILState_Release(local_gstate);
if (need_gil)
{
PyGILState_Release(local_gstate);
}

return 0;
}
Expand All @@ -531,7 +568,7 @@ int plugin_driver_restart(plugin_driver_t *driver)

// Clean up plugins without destroying the driver
// Note: No need for GIL here as stop() already handled Python operations
if (has_python_plugin)
if (has_python_plugin && Py_IsInitialized())
{
gstate = PyGILState_Ensure();
for (int i = 0; i < driver->plugin_count; i++)
Expand Down Expand Up @@ -581,17 +618,27 @@ void plugin_driver_destroy(plugin_driver_t *driver)
if (driver->plugin_count == 0)
{
printf("[PLUGIN]: No plugins to destroy.\n");
pthread_mutex_destroy(&driver->buffer_mutex);
free(driver);
return;
}

PyGILState_STATE local_gstate = PyGILState_Ensure();
// Check if Python is initialized before any Python operations
int python_initialized = has_python_plugin && Py_IsInitialized();
// Initialize to PyGILState_LOCKED (0) to satisfy compiler warning
PyGILState_STATE local_gstate = PyGILState_LOCKED;

if (python_initialized)
{
local_gstate = PyGILState_Ensure();
}

plugin_driver_stop(driver);

for (int i = 0; i < driver->plugin_count; i++)
{
plugin_instance_t *plugin = &driver->plugins[i];
if (plugin->python_plugin)
if (plugin->python_plugin && python_initialized)
{
python_plugin_cleanup(plugin);
}
Expand All @@ -616,9 +663,15 @@ void plugin_driver_destroy(plugin_driver_t *driver)
}
}

PyGILState_Release(local_gstate);
PyEval_RestoreThread(main_tstate);
Py_FinalizeEx();
if (python_initialized)
{
PyGILState_Release(local_gstate);
if (main_tstate != NULL)
{
PyEval_RestoreThread(main_tstate);
}
Py_FinalizeEx();
}

pthread_mutex_destroy(&driver->buffer_mutex);

Expand Down
7 changes: 6 additions & 1 deletion core/src/plc_app/plc_state_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,15 @@ int unload_plc_program(PluginManager *pm)
journal_cleanup();
log_info("Journal buffer cleaned up");

// Stop plugins FIRST (before acquiring mutex) to prevent deadlock
// The S7Comm plugin's RWArea callback acquires buffer_mutex during
// client read operations. If we try to acquire the mutex before
// stopping the plugin, we can deadlock if a client is connected.
plugin_driver_stop(plugin_driver);

// Clear temporary pointers from image tables before unloading
// This ensures clean state for the next program load
plugin_mutex_take(&plugin_driver->buffer_mutex);
plugin_driver_stop(plugin_driver);
image_tables_clear_null_pointers();
plugin_mutex_give(&plugin_driver->buffer_mutex);

Expand Down
Loading