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:
Erik Boasson 2018-07-18 16:21:49 +02:00
parent 20d8ef6f0d
commit bfb5874373
12 changed files with 102 additions and 199 deletions

View file

@ -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(

View file

@ -15,4 +15,8 @@
void os_osInit(void);
void os_osExit(void);
#endif
/* implemented by the platform-specific code */
void os_osPlatformInit (void);
void os_osPlatformExit (void);
#endif

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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. */

View file

@ -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