Merge pull request #19985 from fpetrogalli:disable_threads

* [build][option] Introduce `OPENCV_DISABLE_THREAD_SUPPORT` option.

The option forces the library to build without thread support.

* update handling of OPENCV_DISABLE_THREAD_SUPPORT

- reduce amount of #if conditions

* [to squash] cmake: apply mode vars in toolchains too

Co-authored-by: Alexander Alekhin <alexander.a.alekhin@gmail.com>
pull/20400/head
Francesco Petrogalli 4 years ago committed by GitHub
parent 59ae0e0013
commit b928ebdd53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      3rdparty/libwebp/CMakeLists.txt
  2. 15
      CMakeLists.txt
  3. 11
      cmake/OpenCVCompilerOptions.cmake
  4. 6
      cmake/OpenCVUtils.cmake
  5. 18
      cmake/vars/EnableModeVars.cmake
  6. 28
      cmake/vars/OPENCV_DISABLE_THREAD_SUPPORT.cmake
  7. 4
      modules/core/CMakeLists.txt
  8. 20
      modules/core/include/opencv2/core/utility.hpp
  9. 166
      modules/core/src/async.cpp
  10. 10
      modules/core/src/parallel.cpp
  11. 112
      modules/core/src/system.cpp
  12. 37
      modules/core/src/umatrix.cpp
  13. 4
      modules/core/src/utils/logtagmanager.hpp
  14. 5
      modules/core/test/test_async.cpp
  15. 5
      modules/core/test/test_utils.cpp
  16. 6
      modules/ts/CMakeLists.txt

@ -32,7 +32,9 @@ endif()
# Define the library target:
# ----------------------------------------------------------------------------------
add_definitions(-DWEBP_USE_THREAD)
if(NOT OPENCV_DISABLE_THREAD_SUPPORT)
add_definitions(-DWEBP_USE_THREAD)
endif()
add_library(${WEBP_LIBRARY} STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL} ${lib_srcs} ${lib_hdrs})
if(ANDROID)

@ -512,6 +512,7 @@ OCV_OPTION(OPENCV_GENERATE_SETUPVARS "Generate setup_vars* scripts" ON IF (NOT
OCV_OPTION(ENABLE_CONFIG_VERIFICATION "Fail build if actual configuration doesn't match requested (WITH_XXX != HAVE_XXX)" OFF)
OCV_OPTION(OPENCV_ENABLE_MEMALIGN "Enable posix_memalign or memalign usage" ON)
OCV_OPTION(OPENCV_DISABLE_FILESYSTEM_SUPPORT "Disable filesystem support" OFF)
OCV_OPTION(OPENCV_DISABLE_THREAD_SUPPORT "Build the library without multi-threaded code." OFF)
OCV_OPTION(ENABLE_PYLINT "Add target with Pylint checks" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
OCV_OPTION(ENABLE_FLAKE8 "Add target with Python flake8 checker" (BUILD_DOCS OR BUILD_EXAMPLES) IF (NOT CMAKE_CROSSCOMPILING AND NOT APPLE_FRAMEWORK) )
@ -666,6 +667,11 @@ if(UNIX)
set(HAVE_PTHREAD 1)
endif()
# Ensure that libpthread is not listed as one of the libraries to pass to the linker.
if (OPENCV_DISABLE_THREAD_SUPPORT)
list(REMOVE_ITEM OPENCV_LINKER_LIBS pthread)
endif()
if(OPENCV_ENABLE_MEMALIGN)
CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)
CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H)
@ -1459,6 +1465,15 @@ ocv_build_features_string(parallel_status EXCLUSIVE
ELSE "none")
status("")
status(" Parallel framework:" "${parallel_status}")
if (OPENCV_DISABLE_THREAD_SUPPORT)
status("" "Multi thread code explicitly disabled with OPENCV_DISABLE_THREAD_SUPPORT.")
if(HAVE_PTHREADS_PF OR HAVE_HPX OR HAVE_OPENMP OR HAVE_GCD OR HAVE_CONCURRENCY)
message(FATAL_ERROR "Not all parallel frameworks have been disabled (using ${parallel_status}).")
endif()
if(HAVE_PTHREAD)
message(FATAL_ERROR "Thread execution might be in use in some component.")
endif()
endif()
if(CV_TRACE OR OPENCV_TRACE)
ocv_build_features_string(trace_status EXCLUSIVE

@ -178,14 +178,17 @@ if(CV_GCC OR CV_CLANG)
add_extra_compiler_option(-Wno-long-long)
endif()
# We need pthread's
if((UNIX
# We need pthread's, unless we have explicitly disabled multi-thread execution.
if(NOT OPENCV_DISABLE_THREAD_SUPPORT
AND (
(UNIX
AND NOT ANDROID
AND NOT (APPLE AND CV_CLANG)
AND NOT EMSCRIPTEN
)
OR (EMSCRIPTEN AND WITH_PTHREADS_PF) # https://github.com/opencv/opencv/issues/20285
)
OR (EMSCRIPTEN AND WITH_PTHREADS_PF) # https://github.com/opencv/opencv/issues/20285
)
) # TODO
add_extra_compiler_option(-pthread)
endif()

@ -1973,3 +1973,9 @@ if(NOT BUILD_SHARED_LIBS AND (CMAKE_VERSION VERSION_LESS "3.14.0"))
else()
ocv_update(OPENCV_3RDPARTY_EXCLUDE_FROM_ALL "EXCLUDE_FROM_ALL")
endif()
#
# Include configuration override settings
#
include(cmake/vars/EnableModeVars.cmake)

@ -0,0 +1,18 @@
set(__OCV_MODE_VARS_DIR "${CMAKE_CURRENT_LIST_DIR}")
macro(ocv_change_mode_var)
set(__var "${ARGV0}")
set(__mode "${ARGV1}")
set(__value "${ARGV2}")
if(__mode STREQUAL "MODIFIED_ACCESS" AND __value)
if(NOT __applied_mode_${__var})
include("${__OCV_MODE_VARS_DIR}/${__var}.cmake")
set(__applied_mode_${__var} 1)
else()
#message("Mode is already applied: ${__var}")
endif()
endif()
endmacro()
variable_watch(OPENCV_DISABLE_THREAD_SUPPORT ocv_change_mode_var)
set(OPENCV_DISABLE_THREAD_SUPPORT "${OPENCV_DISABLE_THREAD_SUPPORT}")

@ -0,0 +1,28 @@
# Force removal of code conditionally compiled with `#if
# HAVE_PTHREAD`.
ocv_update(HAVE_PTHREAD 0)
# There components are disabled because they require
# multi-threaded execution.
ocv_update(WITH_PROTOBUF OFF)
ocv_update(WITH_GSTREAMER OFF)
ocv_update(WITH_IPP OFF)
ocv_update(WITH_ITT OFF)
ocv_update(WITH_OPENCL OFF)
ocv_update(WITH_VA OFF)
ocv_update(WITH_VA_INTEL OFF)
# Disable bindings
ocv_update(BUILD_opencv_python2 OFF)
ocv_update(BUILD_opencv_python3 OFF)
ocv_update(BUILD_JAVA OFF)
ocv_update(BUILD_opencv_java OFF)
# These modules require `#include
# <[thread|mutex|condition_variable|future]>` and linkage into
# `libpthread` to work.
ocv_update(BUILD_opencv_objdetect OFF)
ocv_update(BUILD_opencv_gapi OFF)
ocv_update(BUILD_opencv_dnn OFF)
set(OPJ_USE_THREAD "OFF" CACHE INTERNAL "")

@ -153,6 +153,10 @@ if(OPENCV_CORE_EXCLUDE_C_API)
ocv_target_compile_definitions(${the_module} PRIVATE "OPENCV_EXCLUDE_C_API=1")
endif()
if(OPENCV_DISABLE_THREAD_SUPPORT)
ocv_target_compile_definitions(${the_module} PUBLIC "OPENCV_DISABLE_THREAD_SUPPORT=1")
endif()
if(HAVE_HPX)
ocv_target_link_libraries(${the_module} LINK_PRIVATE "${HPX_LIBRARIES}")
endif()

@ -714,9 +714,27 @@ void Mat::forEach_impl(const Functor& operation) {
/////////////////////////// Synchronization Primitives ///////////////////////////////
#if !defined(_M_CEE)
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
typedef std::recursive_mutex Mutex;
typedef std::lock_guard<cv::Mutex> AutoLock;
#endif
#else // OPENCV_DISABLE_THREAD_SUPPORT
// Custom (failing) implementation of `std::recursive_mutex`.
struct Mutex {
void lock(){
CV_Error(cv::Error::StsNotImplemented,
"cv::Mutex is disabled by OPENCV_DISABLE_THREAD_SUPPORT=ON");
}
void unlock(){
CV_Error(cv::Error::StsNotImplemented,
"cv::Mutex is disabled by OPENCV_DISABLE_THREAD_SUPPORT=ON");
}
};
// Stub for cv::AutoLock when threads are disabled.
struct AutoLock {
AutoLock(Mutex &) { }
};
#endif // OPENCV_DISABLE_THREAD_SUPPORT
#endif // !defined(_M_CEE)
/** @brief Designed for command line parsing

@ -14,6 +14,7 @@
#define CV_LOG_STRIP_LEVEL CV_LOG_LEVEL_DEBUG + 1
#include <opencv2/core/utils/logger.hpp>
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#ifdef CV_CXX11
#include <mutex>
@ -236,6 +237,171 @@ struct AsyncArray::Impl
}
};
} // namespace
#else // OPENCV_DISABLE_THREAD_SUPPORT
namespace cv {
// no threading
struct AsyncArray::Impl
{
int refcount;
void addrefFuture() CV_NOEXCEPT { refcount_future++; refcount++; }
void releaseFuture() CV_NOEXCEPT { refcount_future--; if (0 == --refcount) delete this; }
int refcount_future;
void addrefPromise() CV_NOEXCEPT { refcount_promise++; refcount++; } \
void releasePromise() CV_NOEXCEPT { refcount_promise--; if (0 == --refcount) delete this; }
int refcount_promise;
mutable bool has_result; // Mat, UMat or exception
mutable cv::Ptr<Mat> result_mat;
mutable cv::Ptr<UMat> result_umat;
bool has_exception;
#if CV__EXCEPTION_PTR
std::exception_ptr exception;
#endif
cv::Exception cv_exception;
mutable bool result_is_fetched;
bool future_is_returned;
Impl()
: refcount(1), refcount_future(0), refcount_promise(1)
, has_result(false)
, has_exception(false)
, result_is_fetched(false)
, future_is_returned(false)
{
// nothing
}
~Impl()
{
if (has_result && !result_is_fetched)
{
CV_LOG_INFO(NULL, "Asynchronous result has not been fetched");
}
}
bool get(OutputArray dst, int64 timeoutNs) const
{
CV_Assert(!result_is_fetched);
if (!has_result)
{
CV_UNUSED(timeoutNs);
CV_Error(Error::StsError, "Result is not produced (unable to wait for result in OPENCV_DISABLE_THREAD_SUPPORT mode)");
}
if (!result_mat.empty())
{
dst.move(*result_mat.get());
result_mat.release();
result_is_fetched = true;
return true;
}
if (!result_umat.empty())
{
dst.move(*result_umat.get());
result_umat.release();
result_is_fetched = true;
return true;
}
#if CV__EXCEPTION_PTR
if (has_exception && exception)
{
result_is_fetched = true;
std::rethrow_exception(exception);
}
#endif
if (has_exception)
{
result_is_fetched = true;
throw cv_exception;
}
CV_Error(Error::StsInternal, "AsyncArray: invalid state of 'has_result = true'");
return false;
}
bool valid() const CV_NOEXCEPT
{
if (result_is_fetched)
return false;
if (refcount_promise == 0 && !has_result)
return false;
return true;
}
bool wait_for(int64 timeoutNs) const
{
CV_Assert(valid());
if (has_result)
return has_result;
if (timeoutNs == 0)
return has_result;
CV_Error(Error::StsError, "Unable to wait in OPENCV_DISABLE_THREAD_SUPPORT mode");
}
AsyncArray getArrayResult()
{
CV_Assert(refcount_future == 0);
AsyncArray result;
addrefFuture();
result.p = this;
future_is_returned = true;
return result;
}
void setValue(InputArray value)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
int k = value.kind();
if (k == _InputArray::UMAT)
{
result_umat = makePtr<UMat>();
value.copyTo(*result_umat.get());
}
else
{
result_mat = makePtr<Mat>();
value.copyTo(*result_mat.get());
}
has_result = true;
}
#if CV__EXCEPTION_PTR
void setException(std::exception_ptr e)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
has_exception = true;
exception = e;
has_result = true;
}
#endif
void setException(const cv::Exception e)
{
if (future_is_returned && refcount_future == 0)
CV_Error(Error::StsError, "Associated AsyncArray has been destroyed");
CV_Assert(!has_result);
has_exception = true;
cv_exception = e;
has_result = true;
}
};
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
namespace cv {
AsyncArray::AsyncArray() CV_NOEXCEPT
: p(NULL)

@ -72,7 +72,7 @@
#endif
#endif
#if defined CV_CXX11
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include <thread>
#endif
@ -884,6 +884,7 @@ T minNonZero(const T& val_1, const T& val_2)
return (val_1 != 0) ? val_1 : val_2;
}
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
static
int getNumberOfCPUs_()
{
@ -986,6 +987,13 @@ int getNumberOfCPUs()
return nCPUs; // cached value
}
#else // OPENCV_DISABLE_THREAD_SUPPORT
int getNumberOfCPUs()
{
return 1;
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
const char* currentParallelFramework()
{
std::shared_ptr<ParallelForAPI>& api = getCurrentParallelForAPI();

@ -216,7 +216,9 @@ std::wstring GetTempFileNameWinRT(std::wstring prefix)
#endif
#else
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include <pthread.h>
#endif
#include <sys/time.h>
#include <time.h>
@ -1366,6 +1368,8 @@ bool __termination = false;
namespace details {
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#ifdef _WIN32
#ifdef _MSC_VER
#pragma warning(disable:4505) // unreferenced local function has been removed
@ -1778,14 +1782,122 @@ static void WINAPI opencv_fls_destructor(void* pData)
#endif // CV_USE_FLS
#endif // _WIN32
#else // OPENCV_DISABLE_THREAD_SUPPORT
// no threading (OPENCV_DISABLE_THREAD_SUPPORT=ON)
class TlsStorage
{
public:
TlsStorage()
{
slots.reserve(32);
}
~TlsStorage()
{
for (size_t slotIdx = 0; slotIdx < slots.size(); slotIdx++)
{
SlotInfo& s = slots[slotIdx];
TLSDataContainer* container = s.container;
if (container && s.data)
{
container->deleteDataInstance(s.data); // Can't use from SlotInfo destructor
s.data = nullptr;
}
}
}
// Reserve TLS storage index
size_t reserveSlot(TLSDataContainer* container)
{
size_t slotsSize = slots.size();
for (size_t slot = 0; slot < slotsSize; slot++)
{
SlotInfo& s = slots[slot];
if (s.container == NULL)
{
CV_Assert(!s.data);
s.container = container;
return slot;
}
}
// create new slot
slots.push_back(SlotInfo(container));
return slotsSize;
}
// Release TLS storage index and pass associated data to caller
void releaseSlot(size_t slotIdx, std::vector<void*> &dataVec, bool keepSlot = false)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
void* data = s.data;
if (data)
{
dataVec.push_back(data);
s.data = nullptr;
}
if (!keepSlot)
{
s.container = NULL; // mark slot as free (see reserveSlot() implementation)
}
}
// Get data by TLS storage index
void* getData(size_t slotIdx) const
{
CV_Assert(slotIdx < slots.size());
const SlotInfo& s = slots[slotIdx];
return s.data;
}
// Gather data from threads by TLS storage index
void gather(size_t slotIdx, std::vector<void*> &dataVec)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
void* data = s.data;
if (data)
dataVec.push_back(data);
return;
}
// Set data to storage index
void setData(size_t slotIdx, void* pData)
{
CV_Assert(slotIdx < slots.size());
SlotInfo& s = slots[slotIdx];
s.data = pData;
}
private:
struct SlotInfo
{
SlotInfo(TLSDataContainer* _container) : container(_container), data(nullptr) {}
TLSDataContainer* container; // attached container (to dispose data)
void* data;
};
std::vector<struct SlotInfo> slots;
};
static TlsStorage& getTlsStorage()
{
static TlsStorage g_storage; // no threading
return g_storage;
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
} // namespace details
using namespace details;
void releaseTlsStorageThread()
{
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
if (!g_isTlsStorageInitialized)
return; // nothing to release, so prefer to avoid creation of new global structures
getTlsStorage().releaseThread();
#endif
}
TLSDataContainer::TLSDataContainer()

@ -56,10 +56,6 @@ void setSize(UMat& m, int _dims, const int* _sz, const size_t* _steps,
void updateContinuityFlag(UMat& m);
void finalizeHdr(UMat& m);
// it should be a prime number for the best hash function
enum { UMAT_NLOCKS = 31 };
static Mutex umatLocks[UMAT_NLOCKS];
UMatData::UMatData(const MatAllocator* allocator)
{
prevAllocator = currAllocator = allocator;
@ -131,6 +127,12 @@ UMatData::~UMatData()
}
}
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
// it should be a prime number for the best hash function
enum { UMAT_NLOCKS = 31 };
static Mutex umatLocks[UMAT_NLOCKS];
static size_t getUMatDataLockIndex(const UMatData* u)
{
size_t idx = ((size_t)(void*)u) % UMAT_NLOCKS;
@ -228,6 +230,33 @@ UMatDataAutoLock::~UMatDataAutoLock()
getUMatDataAutoLocker().release(u1, u2);
}
#else
void UMatData::lock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
void UMatData::unlock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::UMatDataAutoLock(UMatData* u) : u1(u), u2(NULL)
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::UMatDataAutoLock(UMatData* u1_, UMatData* u2_) : u1(u1_), u2(u2_)
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
UMatDataAutoLock::~UMatDataAutoLock()
{
// nothing in OPENCV_DISABLE_THREAD_SUPPORT mode
}
#endif // OPENCV_DISABLE_THREAD_SUPPORT
//////////////////////////////// UMat ////////////////////////////////
UMat::UMat(UMatUsageFlags _usageFlags) CV_NOEXCEPT

@ -37,8 +37,8 @@ private:
// also, extensible functions (accepting user-provided callback) are not allowed
// to call LogTagManger (to prevent iterator invalidation), which needs enforced
// with a non-recursive mutex.
using MutexType = std::mutex;
using LockType = std::lock_guard<MutexType>;
using MutexType = cv::Mutex;
using LockType = cv::AutoLock;
enum class MatchingScope
{

@ -7,7 +7,7 @@
#include <opencv2/core/bindings_utils.hpp>
#ifdef CV_CXX11
#if defined(CV_CXX11) && !defined(OPENCV_DISABLE_THREAD_SUPPORT)
#include <thread>
#include <chrono>
#endif
@ -85,7 +85,8 @@ TEST(Core_Async, LikePythonTest)
}
#ifdef CV_CXX11
#if defined(CV_CXX11) && !defined(OPENCV_DISABLE_THREAD_SUPPORT)
TEST(Core_Async, AsyncThread_Simple)
{
Mat m(3, 3, CV_32FC1, Scalar::all(5.0f));

@ -8,9 +8,12 @@
#include "opencv2/core/utils/logger.hpp"
#include "opencv2/core/utils/buffer_area.private.hpp"
#include "test_utils_tls.impl.hpp"
#include "opencv2/core/utils/filesystem.private.hpp"
#ifndef OPENCV_DISABLE_THREAD_SUPPORT
#include "test_utils_tls.impl.hpp"
#endif
namespace opencv_test { namespace {
static const char * const keys =

@ -41,3 +41,9 @@ endif()
if(NOT OPENCV_TESTS_CONFIG_STR STREQUAL "${__content}")
file(WRITE "${OPENCV_TESTS_CONFIG_FILE}" "${OPENCV_TESTS_CONFIG_STR}")
endif()
if(OPENCV_DISABLE_THREAD_SUPPORT)
# This is required to disable threads in the ts module, as
# described in `ts_gtest.h`.
ocv_target_compile_definitions(${the_module} PUBLIC GTEST_HAS_PTHREAD=0)
endif()

Loading…
Cancel
Save