164 lines
4.4 KiB
C
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);
|
|
}
|