/*************************************************************************\ * 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 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 #include #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 ); 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 ); 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); }