Files
epics-base/src/libCom/misc/epicsExit.c
2006-12-07 17:00:20 +00:00

164 lines
4.4 KiB
C

/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*epicsExit.c*/
/*
* Author: Marty Kraimer
* Date: 23AUG2004
* Thread exit revisions: Jeff Hill
* Date: 06Dec2006
*
* Note that epicsExitCallAtThreadExits is currently called directly from the
* thread entry wrapper in OS dependent code. That approach might not work
* correctly if the thread exits indirectly instead of just returning from
* the function specified to epicsThreadCreate. For example the thread might
* exit via the exit() call. There might be OS dependent solutions for that
* weakness.
*
*/
#include <stdlib.h>
#include <errno.h>
#define epicsExportSharedSymbols
#include "ellLib.h"
#include "epicsThread.h"
#include "epicsMutex.h"
#include "cantProceed.h"
#include "epicsExit.h"
typedef void (*epicsExitFunc)(void *arg);
typedef struct exitNode {
ELLNODE node;
epicsExitFunc func;
void *arg;
}exitNode;
typedef struct exitPvt {
ELLLIST list;
} exitPvt;
static epicsThreadOnceId exitPvtOnce = EPICS_THREAD_ONCE_INIT;
static exitPvt * pExitPvtPerProcess = 0;
static epicsMutexId exitPvtLock = 0;
static epicsThreadPrivateId exitPvtPerThread = 0;
static void destroyExitPvt ( exitPvt * pep )
{
ellFree ( &pep->list );
}
static exitPvt * createExitPvt ()
{
exitPvt * pep = calloc ( 1, sizeof ( * pep ) );
if ( pep ) {
ellInit ( &pep->list );
}
return pep;
}
static void exitPvtOnceFunc ( void * pParm )
{
exitPvtPerThread = epicsThreadPrivateCreate ();
assert ( exitPvtPerThread );
pExitPvtPerProcess = createExitPvt ();
assert ( pExitPvtPerProcess );
exitPvtLock = epicsMutexMustCreate ();
}
static void epicsExitCallAtExitsPvt ( exitPvt * pep )
{
exitNode *pexitNode;
while ( ( pexitNode = (exitNode *) ellLast ( & pep->list ) ) ) {
pexitNode->func ( pexitNode->arg );
ellDelete ( & pep->list, & pexitNode->node );
free ( pexitNode );
}
}
epicsShareFunc void epicsShareAPI epicsExitCallAtExits ( void )
{
exitPvt * pep = 0;
epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
epicsMutexMustLock ( exitPvtLock );
if ( pExitPvtPerProcess ) {
pep = pExitPvtPerProcess;
pExitPvtPerProcess = 0;
}
epicsMutexUnlock ( exitPvtLock );
if ( pep ) {
epicsExitCallAtExitsPvt ( pep );
destroyExitPvt ( pep );
}
}
epicsShareFunc void epicsShareAPI epicsExitCallAtThreadExits ( void )
{
exitPvt * pep;
epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
pep = epicsThreadPrivateGet ( exitPvtPerThread );
if ( pep ) {
epicsExitCallAtExitsPvt ( pep );
destroyExitPvt ( pep );
epicsThreadPrivateSet ( exitPvtPerThread, 0 );
}
}
static int epicsAtExitPvt (
exitPvt * pep, epicsExitFunc func, void *arg )
{
int status = -1;
exitNode * pExitNode
= calloc ( 1, sizeof( *pExitNode ) );
if ( pExitNode ) {
pExitNode->func = func;
pExitNode->arg = arg;
ellAdd ( & pep->list, & pExitNode->node );
status = 0;
}
return status;
}
epicsShareFunc int epicsShareAPI epicsAtThreadExit (
epicsExitFunc func, void *arg )
{
exitPvt * pep;
epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
pep = epicsThreadPrivateGet ( exitPvtPerThread );
if ( ! pep ) {
pep = createExitPvt ();
if ( ! pep ) {
return -1;
}
epicsThreadPrivateSet ( exitPvtPerThread, pep );
}
return epicsAtExitPvt ( pep, func, arg );
}
epicsShareFunc int epicsShareAPI epicsAtExit(
epicsExitFunc func, void *arg )
{
int status = -1;
epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
epicsMutexMustLock ( exitPvtLock );
if ( pExitPvtPerProcess ) {
status = epicsAtExitPvt ( pExitPvtPerProcess, func, arg );
}
epicsMutexUnlock ( exitPvtLock );
return status;
}
epicsShareFunc void epicsShareAPI epicsExit(int status)
{
epicsExitCallAtExits();
epicsThreadSleep(1.0);
exit(status);
}