Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
887d8d09
Commit
887d8d09
authored
Aug 19, 2015
by
Alexander Alekhin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #5177 from lupustr3:pvlasov/tls_fixes
parents
76da19d5
a33d98c1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
230 additions
and
177 deletions
+230
-177
cvdef.h
modules/core/include/opencv2/core/cvdef.h
+2
-0
utility.hpp
modules/core/include/opencv2/core/utility.hpp
+21
-9
system.cpp
modules/core/src/system.cpp
+207
-168
No files found.
modules/core/include/opencv2/core/cvdef.h
View file @
887d8d09
...
...
@@ -58,6 +58,8 @@
#include "opencv2/hal/defs.h"
#define OPENCV_ABI_COMPATIBILITY 300
#ifdef __OPENCV_BUILD
# define DISABLE_OPENCV_24_COMPATIBILITY
#endif
...
...
modules/core/include/opencv2/core/utility.hpp
View file @
887d8d09
...
...
@@ -513,30 +513,42 @@ private:
AutoLock
&
operator
=
(
const
AutoLock
&
);
};
// TLS interface
class
CV_EXPORTS
TLSDataContainer
{
private
:
int
key_
;
protected
:
TLSDataContainer
();
virtual
~
TLSDataContainer
();
#if OPENCV_ABI_COMPATIBILITY > 300
void
*
getData
()
const
;
void
release
();
private
:
#else
void
release
();
public
:
void
*
getData
()
const
;
#endif
virtual
void
*
createDataInstance
()
const
=
0
;
virtual
void
deleteDataInstance
(
void
*
d
ata
)
const
=
0
;
virtual
void
deleteDataInstance
(
void
*
pD
ata
)
const
=
0
;
void
*
getData
()
const
;
int
key_
;
};
// Main TLS data class
template
<
typename
T
>
class
TLSData
:
protected
TLSDataContainer
{
public
:
inline
TLSData
()
{}
inline
~
TLSData
()
{}
inline
T
*
get
()
const
{
return
(
T
*
)
getData
();
}
inline
TLSData
()
{}
inline
~
TLSData
()
{
release
();
}
// Release key and delete associated data
inline
T
*
get
()
const
{
return
(
T
*
)
getData
();
}
// Get data assosiated with key
private
:
virtual
void
*
createDataInstance
()
const
{
return
new
T
;
}
virtual
void
deleteDataInstance
(
void
*
data
)
const
{
delete
(
T
*
)
data
;
}
virtual
void
*
createDataInstance
()
const
{
return
new
T
;}
// Wrapper to allocate data by template
virtual
void
deleteDataInstance
(
void
*
pData
)
const
{
delete
(
T
*
)
pData
;}
// Wrapper to release data by template
};
/** @brief Designed for command line parsing
...
...
modules/core/src/system.cpp
View file @
887d8d09
...
...
@@ -936,241 +936,280 @@ bool Mutex::trylock() { return impl->trylock(); }
//////////////////////////////// thread-local storage ////////////////////////////////
class
TLSStorage
#ifdef WIN32
#ifdef _MSC_VER
#pragma warning(disable:4505) // unreferenced local function has been removed
#endif
#ifndef TLS_OUT_OF_INDEXES
#define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
#endif
#endif
// TLS platform abstraction layer
class
TlsAbstraction
{
std
::
vector
<
void
*>
tlsData_
;
public
:
TLSStorage
()
{
tlsData_
.
reserve
(
16
);
}
~
TLSStorage
();
inline
void
*
getData
(
int
key
)
const
{
CV_DbgAssert
(
key
>=
0
);
return
(
key
<
(
int
)
tlsData_
.
size
())
?
tlsData_
[
key
]
:
NULL
;
}
inline
void
setData
(
int
key
,
void
*
data
)
{
CV_DbgAssert
(
key
>=
0
);
if
(
key
>=
(
int
)
tlsData_
.
size
())
{
tlsData_
.
resize
(
key
+
1
,
NULL
);
}
tlsData_
[
key
]
=
data
;
}
inline
static
TLSStorage
*
get
();
};
TlsAbstraction
();
~
TlsAbstraction
();
void
*
GetData
()
const
;
void
SetData
(
void
*
pData
);
private
:
#ifdef WIN32
#if
def _MSC_VER
#pragma warning(disable:4505) // unreferenced local function has been removed
#if
ndef WINRT
DWORD
tlsKey
;
#endif
#else // WIN32
pthread_key_t
tlsKey
;
#endif
};
#ifdef WIN32
#ifdef WINRT
// using C++11 thread attribute for local thread data
static
__declspec
(
thread
)
TLSStorage
*
g_tlsdata
=
NULL
;
static
__declspec
(
thread
)
void
*
tlsData
=
NULL
;
// using C++11 thread attribute for local thread data
TlsAbstraction
::
TlsAbstraction
()
{}
TlsAbstraction
::~
TlsAbstraction
()
{}
void
*
TlsAbstraction
::
GetData
()
const
{
return
tlsData
;
}
void
TlsAbstraction
::
SetData
(
void
*
pData
)
{
tlsData
=
pData
;
}
#else //WINRT
TlsAbstraction
::
TlsAbstraction
()
{
tlsKey
=
TlsAlloc
();
CV_Assert
(
tlsKey
!=
TLS_OUT_OF_INDEXES
);
}
TlsAbstraction
::~
TlsAbstraction
()
{
TlsFree
(
tlsKey
);
}
void
*
TlsAbstraction
::
GetData
()
const
{
return
TlsGetValue
(
tlsKey
);
}
void
TlsAbstraction
::
SetData
(
void
*
pData
)
{
CV_Assert
(
TlsSetValue
(
tlsKey
,
pData
)
==
TRUE
);
}
#endif
#else // WIN32
TlsAbstraction
::
TlsAbstraction
()
{
CV_Assert
(
pthread_key_create
(
&
tlsKey
,
NULL
)
==
0
);
}
TlsAbstraction
::~
TlsAbstraction
()
{
CV_Assert
(
pthread_key_delete
(
tlsKey
)
==
0
);
}
void
*
TlsAbstraction
::
GetData
()
const
{
return
pthread_getspecific
(
tlsKey
);
}
void
TlsAbstraction
::
SetData
(
void
*
pData
)
{
CV_Assert
(
pthread_setspecific
(
tlsKey
,
pData
)
==
0
);
}
#endif
static
void
deleteThreadData
()
// Per-thread data structure
struct
ThreadData
{
ThreadData
()
{
if
(
g_tlsdata
)
{
delete
g_tlsdata
;
g_tlsdata
=
NULL
;
}
idx
=
0
;
slots
.
reserve
(
32
);
}
inline
TLSStorage
*
TLSStorage
::
get
()
{
if
(
!
g_tlsdata
)
{
g_tlsdata
=
new
TLSStorage
;
}
return
g_tlsdata
;
}
#else
#ifdef WINCE
# define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
#endif
static
DWORD
tlsKey
=
TLS_OUT_OF_INDEXES
;
std
::
vector
<
void
*>
slots
;
// Data array for a thread
size_t
idx
;
// Thread index in TLS storage. This is not OS thread ID!
};
static
void
deleteThreadData
()
// Main TLS storage class
class
TlsStorage
{
public
:
TlsStorage
()
{
if
(
tlsKey
!=
TLS_OUT_OF_INDEXES
)
{
delete
(
TLSStorage
*
)
TlsGetValue
(
tlsKey
);
TlsSetValue
(
tlsKey
,
NULL
);
}
tlsSlots
=
0
;
threads
.
reserve
(
32
);
}
inline
TLSStorage
*
TLSStorage
::
get
()
~
TlsStorage
()
{
if
(
tlsKey
==
TLS_OUT_OF_INDEXES
)
for
(
size_t
i
=
0
;
i
<
threads
.
size
();
i
++
)
{
tlsKey
=
TlsAlloc
();
CV_Assert
(
tlsKey
!=
TLS_OUT_OF_INDEXES
);
}
TLSStorage
*
d
=
(
TLSStorage
*
)
TlsGetValue
(
tlsKey
);
if
(
!
d
)
{
d
=
new
TLSStorage
;
TlsSetValue
(
tlsKey
,
d
);
if
(
threads
[
i
])
{
/* Current architecture doesn't allow proper global objects relase, so this check can cause crashes
// Check if all slots were properly cleared
for(size_t j = 0; j < threads[i]->slots.size(); j++)
{
CV_Assert(threads[i]->slots[j] == 0);
}
*/
delete
threads
[
i
];
}
}
return
d
;
threads
.
clear
()
;
}
#endif //WINRT
#if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE
#ifdef WINRT
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
#endif
extern
"C"
BOOL
WINAPI
DllMain
(
HINSTANCE
,
DWORD
fdwReason
,
LPVOID
lpReserved
)
{
if
(
fdwReason
==
DLL_THREAD_DETACH
||
fdwReason
==
DLL_PROCESS_DETACH
)
void
releaseThread
()
{
if
(
lpReserved
!=
NULL
)
// called after ExitProcess() call
AutoLock
guard
(
mtxGlobalAccess
);
ThreadData
*
pTD
=
(
ThreadData
*
)
tls
.
GetData
();
for
(
size_t
i
=
0
;
i
<
threads
.
size
();
i
++
)
{
cv
::
__termination
=
true
;
}
else
{
// Not allowed to free resources if lpReserved is non-null
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583.aspx
cv
::
deleteThreadAllocData
();
cv
::
deleteThreadData
();
if
(
pTD
==
threads
[
i
])
{
threads
[
i
]
=
0
;
break
;
}
}
tls
.
SetData
(
0
);
delete
pTD
;
}
return
TRUE
;
}
#endif
#else
static
pthread_key_t
tlsKey
=
0
;
static
pthread_once_t
tlsKeyOnce
=
PTHREAD_ONCE_INIT
;
static
void
deleteTLSStorage
(
void
*
data
)
// Reserve TLS storage index
size_t
reserveSlot
()
{
delete
(
TLSStorage
*
)
data
;
AutoLock
guard
(
mtxGlobalAccess
);
tlsSlots
++
;
return
(
tlsSlots
-
1
);
}
static
void
makeKey
()
// Release TLS storage index and pass assosiated data to caller
void
releaseSlot
(
size_t
slotIdx
,
std
::
vector
<
void
*>
&
dataVec
)
{
int
errcode
=
pthread_key_create
(
&
tlsKey
,
deleteTLSStorage
);
CV_Assert
(
errcode
==
0
);
}
AutoLock
guard
(
mtxGlobalAccess
);
CV_Assert
(
tlsSlots
>
slotIdx
);
inline
TLSStorage
*
TLSStorage
::
get
()
{
pthread_once
(
&
tlsKeyOnce
,
makeKey
);
TLSStorage
*
d
=
(
TLSStorage
*
)
pthread_getspecific
(
tlsKey
);
if
(
!
d
)
for
(
size_t
i
=
0
;
i
<
threads
.
size
();
i
++
)
{
d
=
new
TLSStorage
;
pthread_setspecific
(
tlsKey
,
d
);
if
(
threads
[
i
]
->
slots
[
slotIdx
])
{
dataVec
.
push_back
(
threads
[
i
]
->
slots
[
slotIdx
]);
threads
[
i
]
->
slots
[
slotIdx
]
=
0
;
}
}
return
d
;
// If we removing last element, decriment slots size to save space
if
(
tlsSlots
-
1
==
slotIdx
)
tlsSlots
--
;
}
#endif
class
TLSContainerStorage
{
cv
::
Mutex
mutex_
;
std
::
vector
<
TLSDataContainer
*>
tlsContainers_
;
public
:
TLSContainerStorage
()
{
}
~
TLSContainerStorage
()
// Get data by TLS storage index
void
*
getData
(
size_t
slotIdx
)
const
{
for
(
size_t
i
=
0
;
i
<
tlsContainers_
.
size
();
i
++
)
{
CV_DbgAssert
(
tlsContainers_
[
i
]
==
NULL
);
// not all keys released
tlsContainers_
[
i
]
=
NULL
;
}
}
CV_Assert
(
tlsSlots
>
slotIdx
);
int
allocateKey
(
TLSDataContainer
*
pContainer
)
{
cv
::
AutoLock
lock
(
mutex_
);
tlsContainers_
.
push_back
(
pContainer
);
return
(
int
)
tlsContainers_
.
size
()
-
1
;
}
void
releaseKey
(
int
id
,
TLSDataContainer
*
pContainer
)
{
cv
::
AutoLock
lock
(
mutex_
);
CV_Assert
(
tlsContainers_
[
id
]
==
pContainer
);
tlsContainers_
[
id
]
=
NULL
;
// currently, we don't go into thread's TLSData and release data for this key
ThreadData
*
threadData
=
(
ThreadData
*
)
tls
.
GetData
();
if
(
threadData
&&
threadData
->
slots
.
size
()
>
slotIdx
)
return
threadData
->
slots
[
slotIdx
];
return
NULL
;
}
void
destroyData
(
int
key
,
void
*
data
)
// Set data to storage index
void
setData
(
size_t
slotIdx
,
void
*
pData
)
{
cv
::
AutoLock
lock
(
mutex_
);
TLSDataContainer
*
k
=
tlsContainers_
[
key
];
if
(
!
k
)
return
;
try
{
k
->
deleteDataInstance
(
data
);
}
catch
(...)
CV_Assert
(
pData
!=
NULL
);
ThreadData
*
threadData
=
(
ThreadData
*
)
tls
.
GetData
();
if
(
!
threadData
)
{
CV_DbgAssert
(
k
==
NULL
);
// Debug this!
threadData
=
new
ThreadData
;
tls
.
SetData
((
void
*
)
threadData
);
{
AutoLock
guard
(
mtxGlobalAccess
);
threadData
->
idx
=
threads
.
size
();
threads
.
push_back
(
threadData
);
}
}
if
(
slotIdx
>=
threadData
->
slots
.
size
())
threadData
->
slots
.
resize
(
slotIdx
+
1
);
threadData
->
slots
[
slotIdx
]
=
pData
;
}
private
:
TlsAbstraction
tls
;
// TLS abstraction layer instance
Mutex
mtxGlobalAccess
;
// Shared objects operation guard
size_t
tlsSlots
;
// TLS storage counter
std
::
vector
<
ThreadData
*>
threads
;
// Array for all allocated data. Thread data pointers are placed here to allow data cleanup
};
// This is a wrapper function that will ensure 'tlsContainerStorage' is constructed on first use.
// For more information: http://www.parashift.com/c++-faq/static-init-order-on-first-use.html
static
TLSContainerStorage
&
getTLSContainerStorage
()
// Create global TLS storage object
static
TlsStorage
&
getTlsStorage
()
{
CV_SINGLETON_LAZY_INIT_REF
(
T
LSContainerStorage
,
new
TLSContainer
Storage
())
CV_SINGLETON_LAZY_INIT_REF
(
T
lsStorage
,
new
Tls
Storage
())
}
TLSDataContainer
::
TLSDataContainer
()
:
key_
(
-
1
)
{
key_
=
getTLSContainerStorage
().
allocateKey
(
this
);
key_
=
(
int
)
getTlsStorage
().
reserveSlot
();
// Reserve key from TLS storage
}
TLSDataContainer
::~
TLSDataContainer
()
{
getTLSContainerStorage
().
releaseKey
(
key_
,
this
);
key_
=
-
1
;
CV_Assert
(
key_
==
-
1
);
// Key must be released in child object
}
void
*
TLSDataContainer
::
getData
()
const
void
TLSDataContainer
::
release
()
{
CV_Assert
(
key_
>=
0
);
TLSStorage
*
tlsData
=
TLSStorage
::
get
();
void
*
data
=
tlsData
->
getData
(
key_
);
if
(
!
data
)
{
data
=
this
->
createDataInstance
();
CV_DbgAssert
(
data
!=
NULL
);
tlsData
->
setData
(
key_
,
data
);
}
return
data
;
std
::
vector
<
void
*>
data
;
data
.
reserve
(
32
);
getTlsStorage
().
releaseSlot
(
key_
,
data
);
// Release key and get stored data for proper destruction
for
(
size_t
i
=
0
;
i
<
data
.
size
();
i
++
)
// Delete all assosiated data
deleteDataInstance
(
data
[
i
]);
key_
=
-
1
;
}
TLSStorage
::~
TLSStorage
()
void
*
TLSDataContainer
::
getData
()
const
{
for
(
int
i
=
0
;
i
<
(
int
)
tlsData_
.
size
();
i
++
)
void
*
pData
=
getTlsStorage
().
getData
(
key_
);
// Check if data was already allocated
if
(
!
pData
)
{
void
*&
data
=
tlsData_
[
i
];
if
(
data
)
{
getTLSContainerStorage
().
destroyData
(
i
,
data
);
data
=
NULL
;
}
// Create new data instance and save it to TLS storage
pData
=
createDataInstance
();
getTlsStorage
().
setData
(
key_
,
pData
);
}
tlsData_
.
clear
()
;
return
pData
;
}
TLSData
<
CoreTLSData
>&
getCoreTlsData
()
{
CV_SINGLETON_LAZY_INIT_REF
(
TLSData
<
CoreTLSData
>
,
new
TLSData
<
CoreTLSData
>
())
}
#if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE
#ifdef WINRT
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
#endif
extern
"C"
BOOL
WINAPI
DllMain
(
HINSTANCE
,
DWORD
fdwReason
,
LPVOID
lpReserved
)
{
if
(
fdwReason
==
DLL_THREAD_DETACH
||
fdwReason
==
DLL_PROCESS_DETACH
)
{
if
(
lpReserved
!=
NULL
)
// called after ExitProcess() call
{
cv
::
__termination
=
true
;
}
else
{
// Not allowed to free resources if lpReserved is non-null
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583.aspx
cv
::
deleteThreadAllocData
();
cv
::
getTlsStorage
().
releaseThread
();
}
}
return
TRUE
;
}
#endif
#ifdef CV_COLLECT_IMPL_DATA
ImplCollector
&
getImplData
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment