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
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
/* 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