@@ -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