Skip to content

Commit d62834b

Browse files
kboyarinovaleksei-fedotovvossmjp
authored
Fix the allocator for Flow Graph critical tasks creating (#1596)
Co-authored-by: Aleksei Fedotov <[email protected]> Co-authored-by: Mike Voss <[email protected]>
1 parent acd1e73 commit d62834b

File tree

3 files changed

+31
-4
lines changed

3 files changed

+31
-4
lines changed

include/oneapi/tbb/detail/_flow_graph_impl.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2005-2024 Intel Corporation
2+
Copyright (c) 2005-2025 Intel Corporation
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -526,7 +526,10 @@ inline graph_task* prioritize_task(graph& g, graph_task& gt) {
526526
//! priority queue, and a new critical task is created to take and execute a work item with
527527
//! the highest known priority. The reference counting responsibility is transferred to
528528
//! the new task.
529-
d1::task* critical_task = gt.my_allocator.new_object<priority_task_selector>(g.my_priority_queue, gt.my_allocator);
529+
// A newly created small_object_allocator should be used to allocate the priority_task_selector
530+
// instead of the allocator, associated with gt since gt can be allocated by another thread
531+
d1::small_object_allocator allocator;
532+
d1::task* critical_task = allocator.new_object<priority_task_selector>(g.my_priority_queue, allocator);
530533
__TBB_ASSERT( critical_task, "bad_alloc?" );
531534
g.my_priority_queue.push(&gt);
532535
using tbb::detail::d1::submit;

src/tbb/small_object_pool.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2020-2021 Intel Corporation
2+
Copyright (c) 2020-2025 Intel Corporation
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -45,6 +45,8 @@ void* __TBB_EXPORTED_FUNC allocate(d1::small_object_pool*& allocator, std::size_
4545

4646
void* small_object_pool_impl::allocate_impl(d1::small_object_pool*& allocator, std::size_t number_of_bytes)
4747
{
48+
__TBB_ASSERT(allocator == nullptr || allocator == this,
49+
"An attempt was made to allocate using another thread's small memory pool");
4850
small_object* obj{nullptr};
4951

5052
if (number_of_bytes <= small_object_size) {

test/tbb/test_function_node.cpp

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2005-2024 Intel Corporation
2+
Copyright (c) 2005-2025 Intel Corporation
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -806,3 +806,25 @@ TEST_CASE("test function_node try_put_and_wait") {
806806
test_try_put_and_wait();
807807
}
808808
#endif
809+
810+
// It was an issue when the critical task wrapper was allocated using the small object pool
811+
// of the task being wrapped. Since the original task creates under the aggregator, there is no
812+
// guarantee that the thread that requested the task creating is the same as actually created the task
813+
// Mismatch between memory pool caused internal assertion failure while deallocating the task
814+
//! \brief \ref regression
815+
TEST_CASE("test critical tasks memory pool correctness") {
816+
using node_type = tbb::flow::function_node<int, tbb::flow::continue_msg>;
817+
constexpr int num_iterations = 10000;
818+
int num_calls = 0;
819+
auto node_body = [&](int) { ++num_calls; };
820+
821+
tbb::flow::graph g;
822+
node_type node(g, tbb::flow::serial, node_body, tbb::flow::node_priority_t{1});
823+
824+
for (int i = 0; i < num_iterations; ++i) {
825+
node.try_put(i);
826+
}
827+
828+
g.wait_for_all();
829+
REQUIRE_MESSAGE(num_calls == num_iterations, "Incorrect number of body executions");
830+
}

0 commit comments

Comments
 (0)