Files
epics-base/modules/libcom/src/misc/epicsExit.c
Andrew Johnson 3c99391d93 Added SPDX License ID to all EPICS-original source files
In some cases the license-identification header was missing,
so I added that as well. Replaced the remaining headers that
specifically identified "Versions 3.13.7 and higher".

Makefiles and the build system were deliberately excluded.
2020-08-03 11:53:01 -05:00

213 lines
5.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.
* SPDX-License-Identifier: EPICS
* EPICS BASE is 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 <stdio.h>
#include <errno.h>
#include <string.h>
#include "ellLib.h"
#include "errlog.h"
#include "epicsThread.h"
#include "epicsMutex.h"
#include "cantProceed.h"
#include "epicsExit.h"
void epicsMutexCleanup(void);
typedef struct exitNode {
ELLNODE node;
epicsExitFunc func;
void *arg;
char name[1];
}exitNode;
typedef struct exitPvt {
ELLLIST list;
} exitPvt;
int atExitDebug = 0;
static epicsThreadOnceId exitPvtOnce = EPICS_THREAD_ONCE_INIT;
static epicsThreadOnceId exitLaterOnce = EPICS_THREAD_ONCE_INIT;
static exitPvt * pExitPvtPerProcess = 0;
static epicsMutexId exitPvtLock = 0;
static epicsThreadPrivateId exitPvtPerThread = 0;
static int exitLaterStatus;
static void destroyExitPvt(exitPvt * pep)
{
ellFree ( &pep->list );
free ( pep );
}
static exitPvt * createExitPvt(void)
{
exitPvt * pep = calloc ( 1, sizeof ( * pep ) );
if ( pep ) {
ellInit ( &pep->list );
}
return pep;
}
static void exitPvtOnceFunc(void *pParm)
{
exitPvtPerThread = epicsThreadPrivateCreate ();
assert ( exitPvtPerThread );
exitPvtLock = epicsMutexMustCreate ();
}
static void epicsExitInit(void)
{
epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
}
static void epicsExitCallAtExitsPvt(exitPvt *pep)
{
exitNode *pexitNode;
while ( ( pexitNode = (exitNode *) ellLast ( & pep->list ) ) ) {
if (atExitDebug && pexitNode->name[0])
fprintf(stderr, "atExit %s(%p)\n", pexitNode->name, pexitNode->arg);
else if(atExitDebug)
fprintf(stderr, "atExit %p(%p)\n", pexitNode->func, pexitNode->arg);
pexitNode->func ( pexitNode->arg );
ellDelete ( & pep->list, & pexitNode->node );
free ( pexitNode );
}
}
LIBCOM_API void epicsExitCallAtExits(void)
{
exitPvt * pep = 0;
epicsExitInit ();
epicsMutexMustLock ( exitPvtLock );
if ( pExitPvtPerProcess ) {
pep = pExitPvtPerProcess;
pExitPvtPerProcess = 0;
}
epicsMutexUnlock ( exitPvtLock );
if ( pep ) {
epicsExitCallAtExitsPvt ( pep );
destroyExitPvt ( pep );
}
/* Handle specially to avoid circular reference */
epicsMutexCleanup();
}
LIBCOM_API void epicsExitCallAtThreadExits(void)
{
exitPvt * pep;
epicsExitInit ();
pep = epicsThreadPrivateGet ( exitPvtPerThread );
if ( pep ) {
epicsExitCallAtExitsPvt ( pep );
destroyExitPvt ( pep );
epicsThreadPrivateSet ( exitPvtPerThread, 0 );
}
}
static int epicsAtExitPvt(exitPvt *pep, epicsExitFunc func, void *arg, const char *name)
{
int status = -1;
exitNode * pExitNode = calloc ( 1, sizeof( *pExitNode ) + (name?strlen(name):0) );
if ( pExitNode ) {
pExitNode->func = func;
pExitNode->arg = arg;
if(name)
strcpy(pExitNode->name, name);
ellAdd ( & pep->list, & pExitNode->node );
status = 0;
}
return status;
}
LIBCOM_API int epicsAtThreadExit(epicsExitFunc func, void *arg)
{
exitPvt * pep;
epicsExitInit ();
pep = epicsThreadPrivateGet ( exitPvtPerThread );
if ( ! pep ) {
pep = createExitPvt ();
if ( ! pep ) {
return -1;
}
epicsThreadPrivateSet ( exitPvtPerThread, pep );
}
return epicsAtExitPvt ( pep, func, arg, NULL );
}
LIBCOM_API int epicsAtExit3(epicsExitFunc func, void *arg, const char* name)
{
int status = -1;
epicsExitInit ();
epicsMutexMustLock ( exitPvtLock );
if ( !pExitPvtPerProcess ) {
pExitPvtPerProcess = createExitPvt ();
}
if ( pExitPvtPerProcess ) {
status = epicsAtExitPvt ( pExitPvtPerProcess, func, arg, name );
}
epicsMutexUnlock ( exitPvtLock );
return status;
}
LIBCOM_API void epicsExit(int status)
{
epicsExitCallAtExits();
epicsThreadSleep(0.1);
exit(status);
}
static void exitNow(void *junk)
{
epicsExit(exitLaterStatus);
}
static void exitLaterOnceFunc(void *raw)
{
int *status = raw;
exitLaterStatus = *status;
epicsThreadMustCreate("exitLater",
epicsThreadPriorityLow,
epicsThreadGetStackSize(epicsThreadStackSmall),
&exitNow, NULL);
}
LIBCOM_API void epicsExitLater(int status)
{
epicsThreadOnce(&exitLaterOnce, &exitLaterOnceFunc, &status);
}
#include "epicsExport.h"
epicsExportAddress(int,atExitDebug);