fix crashes when C++ global destructors call DDS code
- properly count invocations of os_osInit/os_osExit - handle concurrent invocations of those - provide a single mutex for use by dds_init - eliminate use of atexit() - attendant dds_init/dds_fini changes - fix related crash in thread local storage cleanup Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
20d8ef6f0d
commit
bfb5874373
12 changed files with 102 additions and 199 deletions
|
@ -22,16 +22,6 @@ dds_return_t
|
|||
dds__check_domain(
|
||||
_In_ dds_domainid_t domain);
|
||||
|
||||
/**
|
||||
*Description : Initialization function. This operation initializes all the
|
||||
*required resources that are needed for the DDSC API process lifecycle
|
||||
*(like the init mutex and os layer).
|
||||
*A function will be registered that is called at the end of the process
|
||||
*lifecycle and will destroy the resources initialized in this function.
|
||||
**/
|
||||
void
|
||||
dds__startup(void);
|
||||
|
||||
/**
|
||||
*Description : Initialization function, called from main. This operation
|
||||
*initializes all the required DDS resources,
|
||||
|
@ -66,12 +56,6 @@ dds_fini(void);
|
|||
dds_domainid_t dds_domain_default (void);
|
||||
|
||||
|
||||
/**
|
||||
* Description : Mutex used for initialization synchronization.
|
||||
*/
|
||||
extern os_mutex dds__init_mutex;
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -45,36 +45,6 @@ dds_globals dds_global =
|
|||
|
||||
static struct cfgst * dds_cfgst = NULL;
|
||||
|
||||
|
||||
|
||||
|
||||
os_mutex dds__init_mutex;
|
||||
|
||||
static void
|
||||
dds__fini_once(void)
|
||||
{
|
||||
os_mutexDestroy(&dds__init_mutex);
|
||||
os_osExit();
|
||||
}
|
||||
|
||||
static void
|
||||
dds__init_once(void)
|
||||
{
|
||||
os_osInit();
|
||||
os_mutexInit(&dds__init_mutex);
|
||||
os_procAtExit(dds__fini_once);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
dds__startup(void)
|
||||
{
|
||||
static os_once_t dds__init_control = OS_ONCE_T_STATIC_INIT;
|
||||
os_once(&dds__init_control, dds__init_once);
|
||||
}
|
||||
|
||||
|
||||
dds_return_t
|
||||
dds_init(void)
|
||||
{
|
||||
|
@ -83,13 +53,15 @@ dds_init(void)
|
|||
char progname[50];
|
||||
char hostname[64];
|
||||
uint32_t len;
|
||||
os_mutex *init_mutex;
|
||||
|
||||
/* Be sure the DDS lifecycle resources are initialized. */
|
||||
dds__startup();
|
||||
os_osInit();
|
||||
init_mutex = os_getSingletonMutex();
|
||||
|
||||
DDS_REPORT_STACK();
|
||||
|
||||
os_mutexLock(&dds__init_mutex);
|
||||
os_mutexLock(init_mutex);
|
||||
|
||||
dds_global.m_init_count++;
|
||||
if (dds_global.m_init_count > 1)
|
||||
|
@ -181,7 +153,7 @@ dds_init(void)
|
|||
gv.default_plist_pp.present |= PP_ENTITY_NAME;
|
||||
|
||||
skip:
|
||||
os_mutexUnlock(&dds__init_mutex);
|
||||
os_mutexUnlock(init_mutex);
|
||||
DDS_REPORT_FLUSH(false);
|
||||
return DDS_RETCODE_OK;
|
||||
|
||||
|
@ -203,8 +175,9 @@ fail_config:
|
|||
ut_handleserver_fini();
|
||||
fail_handleserver:
|
||||
dds_global.m_init_count--;
|
||||
os_mutexUnlock(&dds__init_mutex);
|
||||
os_mutexUnlock(init_mutex);
|
||||
DDS_REPORT_FLUSH(true);
|
||||
os_osExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -212,7 +185,9 @@ fail_handleserver:
|
|||
|
||||
extern void dds_fini (void)
|
||||
{
|
||||
os_mutexLock(&dds__init_mutex);
|
||||
os_mutex *init_mutex;
|
||||
init_mutex = os_getSingletonMutex();
|
||||
os_mutexLock(init_mutex);
|
||||
assert(dds_global.m_init_count > 0);
|
||||
dds_global.m_init_count--;
|
||||
if (dds_global.m_init_count == 0)
|
||||
|
@ -232,7 +207,8 @@ extern void dds_fini (void)
|
|||
os_mutexDestroy (&dds_global.m_mutex);
|
||||
dds_global.m_default_domain = DDS_DOMAIN_DEFAULT;
|
||||
}
|
||||
os_mutexUnlock(&dds__init_mutex);
|
||||
os_mutexUnlock(init_mutex);
|
||||
os_osExit();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -145,9 +145,6 @@ dds_create_participant(
|
|||
struct thread_state1 * thr;
|
||||
bool asleep;
|
||||
|
||||
/* Be sure the DDS lifecycle resources are initialized. */
|
||||
dds__startup();
|
||||
|
||||
/* Make sure DDS instance is initialized. */
|
||||
ret = dds_init();
|
||||
if (ret != DDS_RETCODE_OK) {
|
||||
|
@ -243,9 +240,11 @@ dds_lookup_participant(
|
|||
_In_ size_t size)
|
||||
{
|
||||
dds_return_t ret = 0;
|
||||
os_mutex *init_mutex;
|
||||
|
||||
/* Be sure the DDS lifecycle resources are initialized. */
|
||||
dds__startup();
|
||||
os_osInit();
|
||||
init_mutex = os_getSingletonMutex();
|
||||
|
||||
DDS_REPORT_STACK();
|
||||
|
||||
|
@ -262,7 +261,7 @@ dds_lookup_participant(
|
|||
participants[0] = 0;
|
||||
}
|
||||
|
||||
os_mutexLock (&dds__init_mutex);
|
||||
os_mutexLock (init_mutex);
|
||||
|
||||
/* Check if dds is intialized. */
|
||||
if (dds_global.m_init_count > 0) {
|
||||
|
@ -281,9 +280,10 @@ dds_lookup_participant(
|
|||
os_mutexUnlock (&dds_global.m_mutex);
|
||||
}
|
||||
|
||||
os_mutexUnlock (&dds__init_mutex);
|
||||
os_mutexUnlock (init_mutex);
|
||||
|
||||
err:
|
||||
DDS_REPORT_FLUSH(ret != DDS_RETCODE_OK);
|
||||
os_osExit();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ cleanup_thread_state(
|
|||
assert(ts->state == THREAD_STATE_ALIVE);
|
||||
assert(vtime_asleep_p(ts->vtime));
|
||||
reset_thread_state(ts);
|
||||
os_reportExit(); /* FIXME: Should not be here! */
|
||||
os_osExit();
|
||||
}
|
||||
|
||||
_Ret_valid_ struct thread_state1 *
|
||||
|
@ -133,6 +133,7 @@ lookup_thread_state(
|
|||
os_mutexLock(&thread_states.lock);
|
||||
ts1 = init_thread_state(tname);
|
||||
if (ts1 != NULL) {
|
||||
os_osInit();
|
||||
ts1->lb = 0;
|
||||
ts1->extTid = tid;
|
||||
ts1->tid = tid;
|
||||
|
|
|
@ -20,7 +20,7 @@ ENDIF()
|
|||
PREPEND(srcs_platform ${platform} os_platform_errno.c os_platform_heap.c os_platform_init.c os_platform_process.c os_platform_socket.c os_platform_stdlib.c os_platform_sync.c os_platform_thread.c os_platform_time.c)
|
||||
|
||||
include (GenerateExportHeader)
|
||||
PREPEND(srcs_os "${CMAKE_CURRENT_SOURCE_DIR}/src" os_atomics.c os_init.c os_process.c os_report.c os_socket.c os_thread.c os_time.c os_errno.c os_iter.c ${srcs_platform})
|
||||
PREPEND(srcs_os "${CMAKE_CURRENT_SOURCE_DIR}/src" os_atomics.c os_init.c os_report.c os_socket.c os_thread.c os_time.c os_errno.c os_iter.c ${srcs_platform})
|
||||
add_library(OSAPI ${srcs_os})
|
||||
|
||||
configure_file(
|
||||
|
|
|
@ -15,4 +15,8 @@
|
|||
void os_osInit(void);
|
||||
void os_osExit(void);
|
||||
|
||||
/* implemented by the platform-specific code */
|
||||
void os_osPlatformInit (void);
|
||||
void os_osPlatformExit (void);
|
||||
|
||||
#endif
|
|
@ -72,22 +72,6 @@ os_procName(
|
|||
_Out_writes_z_(procNameSize) char *procName,
|
||||
_In_ size_t procNameSize);
|
||||
|
||||
|
||||
/** \brief Register an process exit handler
|
||||
*
|
||||
* Register an process exit handler. Multiple handlers may be
|
||||
* registered. The handlers are called in reverse order of
|
||||
* registration.
|
||||
*
|
||||
* Possible Results:
|
||||
* - os_resultSuccess: function registered
|
||||
* - os_resultFail: function could not be registered
|
||||
* - assertion failure: function = NULL
|
||||
*/
|
||||
OSAPI_EXPORT os_result
|
||||
os_procAtExit(
|
||||
_In_ void (*function)(void));
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -360,6 +360,10 @@ extern "C" {
|
|||
_Inout_ os_once_t *control,
|
||||
_In_ os_once_fn init_fn);
|
||||
|
||||
OSAPI_EXPORT os_mutex *
|
||||
os_getSingletonMutex(
|
||||
void);
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -29,3 +29,53 @@ os_versionString(void)
|
|||
{
|
||||
return OSPL_VERSION_STR;
|
||||
}
|
||||
|
||||
#define OSINIT_STATUS_OK 0x80000000u
|
||||
static os_atomic_uint32_t osinit_status = OS_ATOMIC_UINT32_INIT(0);
|
||||
static os_mutex init_mutex;
|
||||
|
||||
void os_osInit (void)
|
||||
{
|
||||
uint32_t v;
|
||||
v = os_atomic_inc32_nv(&osinit_status);
|
||||
retry:
|
||||
if (v > OSINIT_STATUS_OK)
|
||||
return;
|
||||
else if (v == 1) {
|
||||
os_osPlatformInit();
|
||||
os_mutexInit(&init_mutex);
|
||||
os_atomic_or32(&osinit_status, OSINIT_STATUS_OK);
|
||||
} else {
|
||||
while (v > 1 && !(v & OSINIT_STATUS_OK)) {
|
||||
os_nanoSleep((os_time){10000000});
|
||||
v = os_atomic_ld32(&osinit_status);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
void os_osExit (void)
|
||||
{
|
||||
uint32_t v, nv;
|
||||
do {
|
||||
v = os_atomic_ld32(&osinit_status);
|
||||
if (v == (OSINIT_STATUS_OK | 1)) {
|
||||
nv = 1;
|
||||
} else {
|
||||
nv = v - 1;
|
||||
}
|
||||
} while (!os_atomic_cas32(&osinit_status, v, nv));
|
||||
if (nv == 1)
|
||||
{
|
||||
os_mutexDestroy(&init_mutex);
|
||||
os_osPlatformExit();
|
||||
os_atomic_dec32(&osinit_status);
|
||||
}
|
||||
}
|
||||
|
||||
os_mutex *os_getSingletonMutex(void)
|
||||
{
|
||||
return &init_mutex;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
|
||||
* v. 1.0 which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
|
||||
*/
|
||||
#include "os/os.h"
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/** \brief Register an process exit handler
|
||||
*
|
||||
* \b os_procAtExit registers an process exit
|
||||
* handler by calling \b atexit passing the \b function
|
||||
* to be called when the process exits.
|
||||
* The standard POSIX implementation guarantees the
|
||||
* required order of execution of the exit handlers.
|
||||
*/
|
||||
os_result
|
||||
os_procAtExit(
|
||||
_In_ void (*function)(void))
|
||||
{
|
||||
int result;
|
||||
os_result osResult;
|
||||
|
||||
assert (function != NULL);
|
||||
|
||||
result = atexit (function);
|
||||
if(!result)
|
||||
{
|
||||
osResult = os_resultSuccess;
|
||||
} else
|
||||
{
|
||||
osResult = os_resultFail;
|
||||
}
|
||||
return osResult;
|
||||
}
|
|
@ -21,53 +21,28 @@
|
|||
#include <assert.h>
|
||||
#include "os/os.h"
|
||||
|
||||
/** \brief Counter that keeps track of number of times os-layer is initialized */
|
||||
static os_atomic_uint32_t _ospl_osInitCount = OS_ATOMIC_UINT32_INIT(0);
|
||||
|
||||
/** \brief OS layer initialization
|
||||
*
|
||||
* \b os_osInit calls:
|
||||
* - \b os_sharedMemoryInit
|
||||
* - \b os_threadInit
|
||||
*/
|
||||
void os_osInit (void)
|
||||
void os_osPlatformInit (void)
|
||||
{
|
||||
uint32_t initCount;
|
||||
|
||||
initCount = os_atomic_inc32_nv(&_ospl_osInitCount);
|
||||
|
||||
if (initCount == 1) {
|
||||
os_syncModuleInit();
|
||||
os_threadModuleInit();
|
||||
os_processModuleInit();
|
||||
os_reportInit(false);
|
||||
}
|
||||
|
||||
return;
|
||||
os_syncModuleInit();
|
||||
os_threadModuleInit();
|
||||
os_processModuleInit();
|
||||
os_reportInit(false);
|
||||
}
|
||||
|
||||
/** \brief OS layer deinitialization
|
||||
*/
|
||||
void os_osExit (void)
|
||||
void os_osPlatformExit (void)
|
||||
{
|
||||
uint32_t initCount;
|
||||
|
||||
initCount = os_atomic_dec32_nv(&_ospl_osInitCount);
|
||||
|
||||
if (initCount == 0) {
|
||||
os_reportExit();
|
||||
os_processModuleExit();
|
||||
os_threadModuleExit();
|
||||
os_syncModuleExit();
|
||||
} else if ((initCount + 1) < initCount){
|
||||
/* The 0 boundary is passed, so os_osExit is called more often than
|
||||
* os_osInit. Therefore undo decrement as nothing happened and warn. */
|
||||
os_atomic_inc32(&_ospl_osInitCount);
|
||||
OS_WARNING("os_osExit", 1, "OS-layer not initialized");
|
||||
/* Fail in case of DEV, as it is incorrect API usage */
|
||||
assert(0);
|
||||
}
|
||||
return;
|
||||
os_reportExit();
|
||||
os_processModuleExit();
|
||||
os_threadModuleExit();
|
||||
os_syncModuleExit();
|
||||
}
|
||||
|
||||
/* This constructor is invoked when the library is loaded into a process. */
|
||||
|
|
|
@ -21,55 +21,22 @@
|
|||
|
||||
#include "os/os.h"
|
||||
|
||||
/** \brief Counter that keeps track of number of times os-layer is initialized */
|
||||
static os_atomic_uint32_t _ospl_osInitCount = OS_ATOMIC_UINT32_INIT(0);
|
||||
|
||||
/** \brief OS layer initialization
|
||||
*
|
||||
* \b os_osInit calls:
|
||||
* - \b os_sharedMemoryInit
|
||||
* - \b os_threadInit
|
||||
*/
|
||||
void os_osInit (void)
|
||||
void os_osPlatformInit (void)
|
||||
{
|
||||
uint32_t initCount;
|
||||
|
||||
initCount = os_atomic_inc32_nv(&_ospl_osInitCount);
|
||||
|
||||
if (initCount == 1) {
|
||||
os_processModuleInit();
|
||||
os_threadModuleInit();
|
||||
os_timeModuleInit();
|
||||
os_reportInit(false);
|
||||
os_socketModuleInit();
|
||||
}
|
||||
|
||||
return;
|
||||
os_processModuleInit();
|
||||
os_threadModuleInit();
|
||||
os_timeModuleInit();
|
||||
os_reportInit(false);
|
||||
os_socketModuleInit();
|
||||
}
|
||||
|
||||
/** \brief OS layer deinitialization
|
||||
*/
|
||||
void os_osExit (void)
|
||||
void os_osPlatformExit (void)
|
||||
{
|
||||
uint32_t initCount;
|
||||
|
||||
initCount = os_atomic_dec32_nv(&_ospl_osInitCount);
|
||||
|
||||
if (initCount == 0) {
|
||||
os_socketModuleExit();
|
||||
os_reportExit();
|
||||
os_timeModuleExit();
|
||||
os_threadModuleExit();
|
||||
os_processModuleExit();
|
||||
} else if ((initCount + 1) < initCount){
|
||||
/* The 0 boundary is passed, so os_osExit is called more often than
|
||||
* os_osInit. Therefore undo decrement as nothing happened and warn. */
|
||||
os_atomic_inc32(&_ospl_osInitCount);
|
||||
OS_WARNING("os_osExit", 1, "OS-layer not initialized");
|
||||
/* Fail in case of DEV, as it is incorrect API usage */
|
||||
assert(0);
|
||||
}
|
||||
return;
|
||||
os_socketModuleExit();
|
||||
os_reportExit();
|
||||
os_timeModuleExit();
|
||||
os_threadModuleExit();
|
||||
os_processModuleExit();
|
||||
}
|
||||
|
||||
/* We need this on windows to make sure the main thread of MFC applications
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue