This is an automated email from the git hooks/post-receive script.
Git pushed a commit to branch master
in repository ffmpeg.
The following commit(s) were added to refs/heads/master by this push:
new b52c71e438 avfilter/dnn: fix async teardown race condition in all
backends
b52c71e438 is described below
commit b52c71e43813952650a74c57b2f31bd0166600ba
Author: Raja-89 <[email protected]>
AuthorDate: Thu Jul 23 23:22:32 2026 +0530
Commit: guoyejun <[email protected]>
CommitDate: Sat Jul 25 15:08:07 2026 +0000
avfilter/dnn: fix async teardown race condition in all backends
When the filter graph is torn down early (e.g. at EOF with -frames:v),
the main thread calls dnn_free_model and destroys the request queue
while async inference threads may still be running. When a detached
thread finishes and tries to push its result back to the destroyed
queue, it triggers a segmentation fault.
Add ff_dnn_wait_requests() to dnn_backend_common which blocks
until all allocated request items (ctx->nireq) have been safely
returned to the request_queue. Call it from dnn_free_model in the
torch, tensorflow, openvino, and onnx backends before destroying the queue.
---
libavfilter/dnn/dnn_backend_common.c | 9 +++++++++
libavfilter/dnn/dnn_backend_common.h | 11 +++++++++++
libavfilter/dnn/dnn_backend_onnx.c | 1 +
libavfilter/dnn/dnn_backend_openvino.c | 1 +
libavfilter/dnn/dnn_backend_tf.c | 1 +
libavfilter/dnn/dnn_backend_torch.cpp | 1 +
6 files changed, 24 insertions(+)
diff --git a/libavfilter/dnn/dnn_backend_common.c
b/libavfilter/dnn/dnn_backend_common.c
index e45eefd14d..4d6752ae33 100644
--- a/libavfilter/dnn/dnn_backend_common.c
+++ b/libavfilter/dnn/dnn_backend_common.c
@@ -22,6 +22,7 @@
*/
#include "libavutil/mem.h"
+#include "libavutil/time.h"
#include "dnn_backend_common.h"
#define DNN_ASYNC_SUCCESS (void *)0
@@ -102,6 +103,14 @@ int ff_dnn_async_module_cleanup(DNNAsyncExecModule
*async_module)
return 0;
}
+void ff_dnn_wait_requests(SafeQueue *request_queue, int nireq)
+{
+ if (!request_queue)
+ return;
+ while (ff_safe_queue_size(request_queue) < nireq)
+ av_usleep(10000);
+}
+
int ff_dnn_start_inference_async(void *ctx, DNNAsyncExecModule *async_module)
{
int ret;
diff --git a/libavfilter/dnn/dnn_backend_common.h
b/libavfilter/dnn/dnn_backend_common.h
index 9f5d37b3e0..f0b8b47397 100644
--- a/libavfilter/dnn/dnn_backend_common.h
+++ b/libavfilter/dnn/dnn_backend_common.h
@@ -25,6 +25,7 @@
#define AVFILTER_DNN_DNN_BACKEND_COMMON_H
#include "queue.h"
+#include "safe_queue.h"
#include "../dnn_interface.h"
#include "libavutil/thread.h"
@@ -112,6 +113,16 @@ int ff_dnn_fill_task(TaskItem *task, DNNExecBaseParams
*exec_params, void *backe
*/
int ff_dnn_async_module_cleanup(DNNAsyncExecModule *async_module);
+/**
+ * Wait for all inference requests to complete before teardown.
+ * This blocks the calling thread until all request items have been
+ * returned to the request_queue by the async inference threads.
+ *
+ * @param request_queue pointer to the SafeQueue holding request items
+ * @param nireq total number of allocated request items
+ */
+void ff_dnn_wait_requests(SafeQueue *request_queue, int nireq);
+
/**
* Start asynchronous inference routine for the TensorFlow
* model on a detached thread. It calls the completion callback
diff --git a/libavfilter/dnn/dnn_backend_onnx.c
b/libavfilter/dnn/dnn_backend_onnx.c
index 0ff0ffb285..6c75d6eb24 100644
--- a/libavfilter/dnn/dnn_backend_onnx.c
+++ b/libavfilter/dnn/dnn_backend_onnx.c
@@ -152,6 +152,7 @@ static void dnn_free_model_onnx(DNNModel **model)
onnx_model = (ONNXModel *)(*model);
+ ff_dnn_wait_requests(onnx_model->request_queue, onnx_model->ctx->nireq);
while (ff_safe_queue_size(onnx_model->request_queue) != 0) {
ONNXRequestItem *item = (ONNXRequestItem
*)ff_safe_queue_pop_front(onnx_model->request_queue);
destroy_request_item(&item);
diff --git a/libavfilter/dnn/dnn_backend_openvino.c
b/libavfilter/dnn/dnn_backend_openvino.c
index a3dfa401ff..8df1f346ab 100644
--- a/libavfilter/dnn/dnn_backend_openvino.c
+++ b/libavfilter/dnn/dnn_backend_openvino.c
@@ -516,6 +516,7 @@ static void dnn_free_model_ov(DNNModel **model)
return;
ov_model = (OVModel *)(*model);
+ ff_dnn_wait_requests(ov_model->request_queue, ov_model->ctx->nireq);
while (ff_safe_queue_size(ov_model->request_queue) != 0) {
OVRequestItem *item = ff_safe_queue_pop_front(ov_model->request_queue);
if (item && item->infer_request) {
diff --git a/libavfilter/dnn/dnn_backend_tf.c b/libavfilter/dnn/dnn_backend_tf.c
index 48372bea38..07129bcdb6 100644
--- a/libavfilter/dnn/dnn_backend_tf.c
+++ b/libavfilter/dnn/dnn_backend_tf.c
@@ -486,6 +486,7 @@ static void dnn_free_model_tf(DNNModel **model)
return;
tf_model = (TFModel *)(*model);
+ ff_dnn_wait_requests(tf_model->request_queue, tf_model->ctx->nireq);
while (ff_safe_queue_size(tf_model->request_queue) != 0) {
TFRequestItem *item = ff_safe_queue_pop_front(tf_model->request_queue);
destroy_request_item(&item);
diff --git a/libavfilter/dnn/dnn_backend_torch.cpp
b/libavfilter/dnn/dnn_backend_torch.cpp
index 9ba6d61377..b28d31cc5c 100644
--- a/libavfilter/dnn/dnn_backend_torch.cpp
+++ b/libavfilter/dnn/dnn_backend_torch.cpp
@@ -123,6 +123,7 @@ static void dnn_free_model_th(DNNModel **model)
th_model = (THModel *)(*model);
if (th_model->request_queue) {
+ ff_dnn_wait_requests(th_model->request_queue, th_model->ctx->nireq);
while (ff_safe_queue_size(th_model->request_queue) != 0) {
THRequestItem *item = (THRequestItem
*)ff_safe_queue_pop_front(th_model->request_queue);
destroy_request_item(&item);
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]