@@ -1306,7 +1306,8 @@ struct ThreadData
1306
1306
class TlsStorage
1307
1307
{
1308
1308
public:
1309
- TlsStorage ()
1309
+ TlsStorage () :
1310
+ tlsSlotsSize (0 )
1310
1311
{
1311
1312
tlsSlots.reserve (32 );
1312
1313
threads.reserve (32 );
@@ -1351,9 +1352,10 @@ class TlsStorage
1351
1352
size_t reserveSlot ()
1352
1353
{
1353
1354
AutoLock guard (mtxGlobalAccess);
1355
+ CV_Assert (tlsSlotsSize == tlsSlots.size ());
1354
1356
1355
1357
// Find unused slots
1356
- for (size_t slot = 0 ; slot < tlsSlots. size () ; slot++)
1358
+ for (size_t slot = 0 ; slot < tlsSlotsSize ; slot++)
1357
1359
{
1358
1360
if (!tlsSlots[slot])
1359
1361
{
@@ -1363,15 +1365,16 @@ class TlsStorage
1363
1365
}
1364
1366
1365
1367
// Create new slot
1366
- tlsSlots.push_back (1 );
1367
- return (tlsSlots. size ()- 1 ) ;
1368
+ tlsSlots.push_back (1 ); tlsSlotsSize++;
1369
+ return tlsSlotsSize - 1 ;
1368
1370
}
1369
1371
1370
1372
// Release TLS storage index and pass associated data to caller
1371
1373
void releaseSlot (size_t slotIdx, std::vector<void *> &dataVec, bool keepSlot = false )
1372
1374
{
1373
1375
AutoLock guard (mtxGlobalAccess);
1374
- CV_Assert (tlsSlots.size () > slotIdx);
1376
+ CV_Assert (tlsSlotsSize == tlsSlots.size ());
1377
+ CV_Assert (tlsSlotsSize > slotIdx);
1375
1378
1376
1379
for (size_t i = 0 ; i < threads.size (); i++)
1377
1380
{
@@ -1393,7 +1396,9 @@ class TlsStorage
1393
1396
// Get data by TLS storage index
1394
1397
void * getData (size_t slotIdx) const
1395
1398
{
1396
- CV_Assert (tlsSlots.size () > slotIdx);
1399
+ #ifndef CV_THREAD_SANITIZER
1400
+ CV_Assert (tlsSlotsSize > slotIdx);
1401
+ #endif
1397
1402
1398
1403
ThreadData* threadData = (ThreadData*)tls.GetData ();
1399
1404
if (threadData && threadData->slots .size () > slotIdx)
@@ -1406,7 +1411,8 @@ class TlsStorage
1406
1411
void gather (size_t slotIdx, std::vector<void *> &dataVec)
1407
1412
{
1408
1413
AutoLock guard (mtxGlobalAccess);
1409
- CV_Assert (tlsSlots.size () > slotIdx);
1414
+ CV_Assert (tlsSlotsSize == tlsSlots.size ());
1415
+ CV_Assert (tlsSlotsSize > slotIdx);
1410
1416
1411
1417
for (size_t i = 0 ; i < threads.size (); i++)
1412
1418
{
@@ -1422,7 +1428,9 @@ class TlsStorage
1422
1428
// Set data to storage index
1423
1429
void setData (size_t slotIdx, void * pData)
1424
1430
{
1425
- CV_Assert (tlsSlots.size () > slotIdx && pData != NULL );
1431
+ #ifndef CV_THREAD_SANITIZER
1432
+ CV_Assert (tlsSlotsSize > slotIdx);
1433
+ #endif
1426
1434
1427
1435
ThreadData* threadData = (ThreadData*)tls.GetData ();
1428
1436
if (!threadData)
@@ -1438,9 +1446,8 @@ class TlsStorage
1438
1446
1439
1447
if (slotIdx >= threadData->slots .size ())
1440
1448
{
1441
- AutoLock guard (mtxGlobalAccess);
1442
- while (slotIdx >= threadData->slots .size ())
1443
- threadData->slots .push_back (NULL );
1449
+ AutoLock guard (mtxGlobalAccess); // keep synchronization with gather() calls
1450
+ threadData->slots .resize (slotIdx + 1 , NULL );
1444
1451
}
1445
1452
threadData->slots [slotIdx] = pData;
1446
1453
}
@@ -1449,6 +1456,8 @@ class TlsStorage
1449
1456
TlsAbstraction tls; // TLS abstraction layer instance
1450
1457
1451
1458
Mutex mtxGlobalAccess; // Shared objects operation guard
1459
+ size_t tlsSlotsSize; // equal to tlsSlots.size() in synchronized sections
1460
+ // without synchronization this counter doesn't desrease - it is used for slotIdx sanity checks
1452
1461
std::vector<int > tlsSlots; // TLS keys state
1453
1462
std::vector<ThreadData*> threads; // Array for all allocated data. Thread data pointers are placed here to allow data cleanup
1454
1463
};
0 commit comments