Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: MacOS

on:
push:
branches:
- master
- develop
pull_request:
branches:
- master
- develop

env:
CTEST_OUTPUT_ON_FAILURE: 1
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm_modules

jobs:
build:
runs-on: macos-latest

steps:
- uses: actions/checkout@v2

- uses: actions/cache@v2
with:
path: "**/cpm_modules"
key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }}

- name: Install boost libs
shell: bash
run: |
brew install boost

- name: configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug

- name: build
run: cmake --build build -j4

- name: test
run: |
cd build
ctest --build-config Debug --timeout 60
44 changes: 44 additions & 0 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: Ubuntu

on:
push:
branches:
- master
- develop
pull_request:
branches:
- master
- develop

env:
CTEST_OUTPUT_ON_FAILURE: 1
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm_modules

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- uses: actions/cache@v2
with:
path: "**/cpm_modules"
key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }}

- name: Install boost libs
shell: bash
run: |
sudo apt-get install libboost1.71-all-dev

- name: configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug

- name: build
run: cmake --build build -j4

- name: test
run: |
cd build
ctest --build-config Debug --timeout 60
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ if(USE_BOOST OR BUILD_TESTING)
# ----------------------------------------------------------------------
# additional tests from me (CK)
# ----------------------------------------------------------------------
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# add_compile_options(-fsanitize=memory -fsanitize-memory-use-after-dtor)
endif()

add_executable(test_mutexattr test_mutexattr.c)
set_target_properties(test_mutexattr PROPERTIES CXX_STANDARD 99)
target_link_libraries(test_mutexattr Threads::Threads)
Expand Down
3 changes: 2 additions & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ CHECKS?='-*,cppcoreguidelines-*,cppcoreguidelines-pro-*,-cppcoreguidelines-avoid
CHECKS?='-*,portability-*,readability-*'
CHECKS?='-*,misc-*,boost-*,cert-*,misc-unused-parameters'

#FIXME! ThreadSanitizer?=0
#TBD: ThreadSanitizer?=0
ifeq ($(BUILD_TYPE),Coverage)
ThreadSanitizer:=0
else
Expand All @@ -44,6 +44,7 @@ ifeq (${ThreadSanitizer},1)
export CMAKE_INSTALL_PREFIX
CMAKE_STAGING_PREFIX?=/tmp/staging/$(PROJECT_NAME)$(CMAKE_INSTALL_PREFIX)
CMAKE_PREFIX_PATH?="$(CMAKE_STAGING_PREFIX);$(CMAKE_INSTALL_PREFIX);/usr/local/opt/boost;/usr/local/opt/openssl;/usr"
export MSAN_OPTIONS=poison_in_dtor=1
endif


Expand Down
60 changes: 30 additions & 30 deletions posix/threadpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,45 +89,45 @@ Synchronized::Synchronized()

Synchronized::~Synchronized()
{
int error = 0;
int errors = 0;

notify_all(); // NOTE: just in case an other thread is waiting for the
// signal! CK
int error =
pthread_mutex_unlock(&monitor); // in case the thread own the lock! CK
if (error) {
++errors;
}

#ifdef NO_FAST_MUTEXES
do {
// first try to get the lock
error = pthread_mutex_destroy(&monitor);
if (error) {
// wait for other threads ...
error = pthread_mutex_trylock(&monitor);
if (!error) {
(void)pthread_mutex_unlock(&monitor);
// if another thread waits for signal with mutex, let's wait.
if (EBUSY == error) {
++errors;
// another thread owns the mutex,

# if defined(_POSIX_TIMEOUTS) && _POSIX_TIMEOUTS > 0
if (lock(10)) // NOTE: but not forever! CK
# else
error = pthread_mutex_trylock(&monitor);
if (!error)
if (lock(100)) { // NOTE: but not forever! CK
pthread_mutex_unlock(&monitor);
}
# endif
{
(void)pthread_mutex_unlock(&monitor);
error = pthread_mutex_destroy(&monitor);
if (error) {

int retries = 0;
do {
error = pthread_mutex_trylock(&monitor);
if (!error) {
pthread_mutex_unlock(&monitor);
error = pthread_mutex_destroy(&monitor);
} else {
++errors;
Thread::sleep(errors * 2);
sleep(errors * 2); // NOTE: prevent busy loops! CK
}
}
} else {
// in case this thread hold the lock:
error = pthread_mutex_unlock(&monitor);
if (error != EPERM) {
break;
}
notify_all();
++errors;
Thread::sleep(errors * 2);
} while (EBUSY == error
&& (retries++ < AGENTPP_SYNCHRONIZED_UNLOCK_RETRIES));
}
if (errors > AGENTPP_SYNCHRONIZED_UNLOCK_RETRIES) {
break;
}
} while (EBUSY == error);
}
#else
error = pthread_mutex_destroy(&monitor);
#endif
Expand Down Expand Up @@ -307,7 +307,7 @@ bool Synchronized::lock(unsigned long timeout)
# else
struct timeval tv = {};
gettimeofday(&tv, 0);
ts.tv_sec = tv.tv_sec + (time_t)timeout / 1000;
ts.tv_sec = tv.tv_sec + (time_t)timeout / 1000;
long millis = tv.tv_usec / 1000 + (timeout % 1000);
if (millis >= 1000) {
ts.tv_sec += 1;
Expand Down
10 changes: 7 additions & 3 deletions threads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,10 @@ Synchronized::Synchronized()

Synchronized::~Synchronized()
{
int errors = 0;
int result = pthread_cond_destroy(&cond);
if (result) {
++errors;
LOG_BEGIN(loggerModuleName, ERROR_LOG | 2);
LOG("Synchronized cond_destroy failed with (result)(ptr)");
LOG(result);
Expand All @@ -178,12 +180,12 @@ Synchronized::~Synchronized()
// wait for other threads ...
if (EBUSY == pthread_mutex_trylock(&monitor)) {
// another thread owns the mutex,
if (lock(123)) // NOTE: let's wait, but not forever! CK
if (lock()) // FIXME: let's wait, but not forever! CK
{
int retries = 0;
do {
pthread_mutex_unlock(&monitor);
sleep(13);
sleep(13); // NOTE: prevent busy loops! CK
result = pthread_mutex_destroy(&monitor);
} while (EBUSY == result
&& (retries++ < AGENTPP_SYNCHRONIZED_UNLOCK_RETRIES));
Expand All @@ -192,13 +194,15 @@ Synchronized::~Synchronized()
}
#endif

isLocked = false;
if (result) {
++errors;
LOG_BEGIN(loggerModuleName, ERROR_LOG | 2);
LOG("Synchronized mutex_destroy failed with (result)(ptr)");
LOG(result);
LOG((unsigned long)this);
LOG_END;
} else {
// NO: ThreadSanitizer: prevent data race! CK isLocked = false;
}
}

Expand Down
63 changes: 44 additions & 19 deletions threads_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,37 +618,49 @@ BOOST_AUTO_TEST_CASE(SyncDeadlock_test)
BOOST_TEST(sync.unlock());
}

#ifndef _WIN32
void handler(int signum)
BOOST_AUTO_TEST_CASE(SyncDeleteLocked_test)
{
switch (signum) {
case SIGALRM:
signal(signum, SIG_DFL);
break;
default: // ignored
break;
try {
Synchronized sync;
BOOST_TEST(sync.lock());
} catch (std::exception& e) {
BOOST_TEST_MESSAGE(BOOST_CURRENT_FUNCTION);
BOOST_TEST_MESSAGE(e.what());
}
}
#endif

BOOST_AUTO_TEST_CASE(SyncDeleteLocked_test)
boost::atomic<bool> stop { false };
void lock_task(Synchronized* m)
{
#ifndef _WIN32
signal(SIGALRM, &handler);
ualarm(1000, 0); // us
#endif
Lock l(*m);
stop = false;

while (!stop) {
Thread::sleep(123); // NOTE: do somet work ...
m->wait();
}

Thread::sleep(
BOOST_THREAD_TEST_TIME_MS); // do some cleanup task ... with lock!
}

BOOST_AUTO_TEST_CASE(SyncDeleteWaiting_test)
{
Stopwatch sw;
try {

auto sync = boost::make_shared<Synchronized>();
BOOST_TEST(sync->lock());

#ifndef __WIN32
sync->wait(1234); // for signal with timout
#endif
boost::thread t(lock_task, sync.get());
t.detach();

Thread::sleep(BOOST_THREAD_TEST_TIME_MS);
BOOST_TEST_MESSAGE(BOOST_CURRENT_FUNCTION << sw.elapsed());
{
BOOST_TEST(sync->lock());
stop = true; // NOTE: without notify! CK
BOOST_TEST(sync->unlock());
}
sync.reset(); // NOTE: this delete the Synchronized obj! CK
} catch (std::exception& e) {
BOOST_TEST_MESSAGE(BOOST_CURRENT_FUNCTION);
BOOST_TEST_MESSAGE(e.what());
Expand Down Expand Up @@ -784,6 +796,19 @@ BOOST_AUTO_TEST_CASE(ThreadLivetime_test)
BOOST_TEST_MESSAGE(BOOST_CURRENT_FUNCTION << sw.elapsed());
}

#ifndef _WIN32
void handler(int signum)
{
switch (signum) {
case SIGALRM:
signal(signum, SIG_DFL);
break;
default: // ignored
break;
}
}
#endif

BOOST_AUTO_TEST_CASE(ThreadNanoSleep_test)
{
#ifndef _WIN32
Expand Down