@@ -178,6 +178,107 @@ TEST_F(test, BasicPoolByPtrTest) {
178178 ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
179179}
180180
181+ struct tagTest : umf_test::test {
182+ void SetUp () override {
183+ test::SetUp ();
184+ provider = umf_test::wrapProviderUnique (nullProviderCreate ());
185+ pool = umf_test::wrapPoolUnique (
186+ createPoolChecked (umfProxyPoolOps (), provider.get (), nullptr ));
187+ }
188+
189+ umf::provider_unique_handle_t provider;
190+ umf::pool_unique_handle_t pool;
191+ };
192+
193+ TEST_F (tagTest, SetAndGet) {
194+ umf_result_t ret = umfPoolSetTag (pool.get (), (void *)0x99 , nullptr );
195+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
196+
197+ void *tag;
198+ ret = umfPoolGetTag (pool.get (), &tag);
199+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
200+ ASSERT_EQ (tag, (void *)0x99 );
201+
202+ void *oldTag;
203+ ret = umfPoolSetTag (pool.get (), (void *)0x100 , &oldTag);
204+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
205+ ASSERT_EQ (oldTag, (void *)0x99 );
206+ }
207+
208+ TEST_F (tagTest, SetAndGetNull) {
209+ umf_result_t ret = umfPoolSetTag (pool.get (), nullptr , nullptr );
210+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
211+
212+ void *tag;
213+ ret = umfPoolGetTag (pool.get (), &tag);
214+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
215+ ASSERT_EQ (tag, nullptr );
216+ }
217+
218+ TEST_F (tagTest, NoSetAndGet) {
219+ void *tag;
220+ umf_result_t ret = umfPoolGetTag (pool.get (), &tag);
221+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
222+ ASSERT_EQ (tag, nullptr );
223+ }
224+
225+ TEST_F (tagTest, SetAndGetMt) {
226+ static constexpr size_t NUM_THREADS = 8 ;
227+ static constexpr size_t NUM_OPS_PER_THREAD = 16 ;
228+
229+ std::vector<std::thread> threads;
230+
231+ auto encodeTag = [](size_t thread, size_t op) -> void * {
232+ return reinterpret_cast <void *>(thread * NUM_OPS_PER_THREAD + op);
233+ };
234+
235+ auto decodeTag = [](void *tag) -> std::pair<size_t , size_t > {
236+ auto op = reinterpret_cast <size_t >(tag) & (NUM_OPS_PER_THREAD - 1 );
237+ auto thread = reinterpret_cast <size_t >(tag) / NUM_OPS_PER_THREAD;
238+ return {thread, op};
239+ };
240+
241+ for (size_t i = 0 ; i < NUM_THREADS; i++) {
242+ threads.emplace_back ([this , i, encodeTag, decodeTag] {
243+ for (size_t j = 0 ; j < NUM_OPS_PER_THREAD; j++) {
244+ void *oldTag;
245+ umf_result_t ret =
246+ umfPoolSetTag (pool.get (), encodeTag (i, j), &oldTag);
247+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
248+
249+ void *queriedTag;
250+ ret = umfPoolGetTag (pool.get (), &queriedTag);
251+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
252+
253+ auto [t1, op1] = decodeTag (oldTag);
254+ auto [t2, op2] = decodeTag (queriedTag);
255+ // if the tag was set by the same thread, the op part should same or higher
256+ ASSERT_TRUE (t1 != t2 || op2 >= op1);
257+ }
258+ });
259+ }
260+
261+ for (auto &thread : threads) {
262+ thread.join ();
263+ }
264+
265+ void *tag;
266+ auto ret = umfPoolGetTag (pool.get (), &tag);
267+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
268+
269+ auto [t, op] = decodeTag (tag);
270+ ASSERT_TRUE (t < NUM_THREADS);
271+ ASSERT_TRUE (op == NUM_OPS_PER_THREAD - 1 );
272+ }
273+
274+ TEST_F (tagTest, SetAndGetInvalidPtr) {
275+ umf_result_t ret = umfPoolSetTag (pool.get (), nullptr , nullptr );
276+ ASSERT_EQ (ret, UMF_RESULT_SUCCESS);
277+
278+ ret = umfPoolGetTag (pool.get (), nullptr );
279+ ASSERT_EQ (ret, UMF_RESULT_ERROR_INVALID_ARGUMENT);
280+ }
281+
181282INSTANTIATE_TEST_SUITE_P (
182283 mallocPoolTest, umfPoolTest,
183284 ::testing::Values (poolCreateExtParams{&MALLOC_POOL_OPS, nullptr ,
0 commit comments