This is Unofficial EPICS BASE Doxygen Site
epicsExit.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 /*epicsExit.c*/
10 /*
11  * Author: Marty Kraimer
12  * Date: 23AUG2004
13  * Thread exit revisions: Jeff Hill
14  * Date: 06Dec2006
15  *
16  * Note that epicsExitCallAtThreadExits is currently called directly from the
17  * thread entry wrapper in OS dependent code. That approach might not work
18  * correctly if the thread exits indirectly instead of just returning from
19  * the function specified to epicsThreadCreate. For example the thread might
20  * exit via the exit() call. There might be OS dependent solutions for that
21  * weakness.
22  *
23  */
24 
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 
30 #include "ellLib.h"
31 #include "errlog.h"
32 #include "epicsThread.h"
33 #include "epicsMutex.h"
34 #include "cantProceed.h"
35 #include "epicsExit.h"
36 
37 void epicsMutexCleanup(void);
38 
39 typedef struct exitNode {
42  void *arg;
43  char name[1];
44 }exitNode;
45 
46 typedef struct exitPvt {
48 } exitPvt;
49 
50 int atExitDebug = 0;
51 
52 static epicsThreadOnceId exitPvtOnce = EPICS_THREAD_ONCE_INIT;
53 static epicsThreadOnceId exitLaterOnce = EPICS_THREAD_ONCE_INIT;
54 static exitPvt * pExitPvtPerProcess = 0;
55 static epicsMutexId exitPvtLock = 0;
56 static epicsThreadPrivateId exitPvtPerThread = 0;
57 
58 static int exitLaterStatus;
59 
60 static void destroyExitPvt(exitPvt * pep)
61 {
62  ellFree ( &pep->list );
63  free ( pep );
64 }
65 
66 static exitPvt * createExitPvt(void)
67 {
68  exitPvt * pep = calloc ( 1, sizeof ( * pep ) );
69  if ( pep ) {
70  ellInit ( &pep->list );
71  }
72  return pep;
73 }
74 
75 static void exitPvtOnceFunc(void *pParm)
76 {
77  exitPvtPerThread = epicsThreadPrivateCreate ();
78  assert ( exitPvtPerThread );
79  exitPvtLock = epicsMutexMustCreate ();
80 }
81 
82 static void epicsExitInit(void)
83 {
84  epicsThreadOnce ( & exitPvtOnce, exitPvtOnceFunc, 0 );
85 }
86 
87 static void epicsExitCallAtExitsPvt(exitPvt *pep)
88 {
89  exitNode *pexitNode;
90 
91  while ( ( pexitNode = (exitNode *) ellLast ( & pep->list ) ) ) {
92  if (atExitDebug && pexitNode->name[0])
93  fprintf(stderr, "atExit %s(%p)\n", pexitNode->name, pexitNode->arg);
94  else if(atExitDebug)
95  fprintf(stderr, "atExit %p(%p)\n", pexitNode->func, pexitNode->arg);
96  pexitNode->func ( pexitNode->arg );
97  ellDelete ( & pep->list, & pexitNode->node );
98  free ( pexitNode );
99  }
100 }
101 
102 LIBCOM_API void epicsExitCallAtExits(void)
103 {
104  exitPvt * pep = 0;
105 
106  epicsExitInit ();
107  epicsMutexMustLock ( exitPvtLock );
108  if ( pExitPvtPerProcess ) {
109  pep = pExitPvtPerProcess;
110  pExitPvtPerProcess = 0;
111  }
112  epicsMutexUnlock ( exitPvtLock );
113  if ( pep ) {
114  epicsExitCallAtExitsPvt ( pep );
115  destroyExitPvt ( pep );
116  }
117  /* Handle specially to avoid circular reference */
119 }
120 
121 LIBCOM_API void epicsExitCallAtThreadExits(void)
122 {
123  exitPvt * pep;
124 
125  epicsExitInit ();
126  pep = epicsThreadPrivateGet ( exitPvtPerThread );
127  if ( pep ) {
128  epicsExitCallAtExitsPvt ( pep );
129  destroyExitPvt ( pep );
130  epicsThreadPrivateSet ( exitPvtPerThread, 0 );
131  }
132 }
133 
134 static int epicsAtExitPvt(exitPvt *pep, epicsExitFunc func, void *arg, const char *name)
135 {
136  int status = -1;
137  exitNode * pExitNode = calloc ( 1, sizeof( *pExitNode ) + (name?strlen(name):0) );
138 
139  if ( pExitNode ) {
140  pExitNode->func = func;
141  pExitNode->arg = arg;
142  if(name)
143  strcpy(pExitNode->name, name);
144  ellAdd ( & pep->list, & pExitNode->node );
145  status = 0;
146  }
147  return status;
148 }
149 
150 LIBCOM_API int epicsAtThreadExit(epicsExitFunc func, void *arg)
151 {
152  exitPvt * pep;
153 
154  epicsExitInit ();
155  pep = epicsThreadPrivateGet ( exitPvtPerThread );
156  if ( ! pep ) {
157  pep = createExitPvt ();
158  if ( ! pep ) {
159  return -1;
160  }
161  epicsThreadPrivateSet ( exitPvtPerThread, pep );
162  }
163  return epicsAtExitPvt ( pep, func, arg, NULL );
164 }
165 
166 LIBCOM_API int epicsAtExit3(epicsExitFunc func, void *arg, const char* name)
167 {
168  int status = -1;
169 
170  epicsExitInit ();
171  epicsMutexMustLock ( exitPvtLock );
172  if ( !pExitPvtPerProcess ) {
173  pExitPvtPerProcess = createExitPvt ();
174  }
175  if ( pExitPvtPerProcess ) {
176  status = epicsAtExitPvt ( pExitPvtPerProcess, func, arg, name );
177  }
178  epicsMutexUnlock ( exitPvtLock );
179  return status;
180 }
181 
182 LIBCOM_API void epicsExit(int status)
183 {
185  epicsThreadSleep(0.1);
186  exit(status);
187 }
188 
189 static void exitNow(void *junk)
190 {
191  epicsExit(exitLaterStatus);
192 }
193 
194 static void exitLaterOnceFunc(void *raw)
195 {
196  int *status = raw;
197  exitLaterStatus = *status;
198  epicsThreadMustCreate("exitLater",
201  &exitNow, NULL);
202 }
203 
204 LIBCOM_API void epicsExitLater(int status)
205 {
206  epicsThreadOnce(&exitLaterOnce, &exitLaterOnceFunc, &status);
207 }
208 
209 #include "epicsExport.h"
210 
struct exitPvt exitPvt
ELLNODE node
Definition: epicsExit.c:40
epicsThreadId epicsStdCall epicsThreadMustCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
LIBCOM_API int epicsAtThreadExit(epicsExitFunc func, void *arg)
Register a function and an context value to be run by this thread when it returns from its entry rout...
Definition: epicsExit.c:150
pvd::Status status
LIBCOM_API void epicsExitCallAtThreadExits(void)
Internal routine that runs the registered thread exit routines.
Definition: epicsExit.c:121
struct exitNode exitNode
LIBCOM_API void *epicsStdCall epicsThreadPrivateGet(epicsThreadPrivateId)
Definition: osdThread.c:973
int atExitDebug
Definition: epicsExit.c:50
LIBCOM_API void epicsExitLater(int status)
Arrange to call epicsExit() later from a low priority thread.
Definition: epicsExit.c:204
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:179
epicsExportAddress(int, atExitDebug)
#define NULL
Definition: catime.c:38
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
Definition: osdThread.c:466
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
char name[1]
Definition: epicsExit.c:43
#define ellFree(PLIST)
Free up the list.
Definition: ellLib.h:108
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
void * arg
Definition: epicsExit.c:42
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
LIBCOM_API void epicsStdCall epicsThreadPrivateSet(epicsThreadPrivateId, void *)
Definition: osdThread.c:961
void epicsMutexCleanup(void)
Definition: epicsMutex.cpp:176
#define epicsThreadPriorityLow
Definition: epicsThread.h:75
LIBCOM_API void epicsExit(int status)
Calls epicsExitCallAtExits(), then the OS exit() routine.
Definition: epicsExit.c:182
Extended replacement for the Posix exit and atexit routines.
ELLLIST list
Definition: epicsExit.c:47
#define ellLast(PLIST)
Find the last node in list.
Definition: ellLib.h:94
List node type.
Definition: ellLib.h:45
void(* epicsExitFunc)(void *arg)
Pointer to a callback function that is to be called by the epicsExit subsystem.
Definition: epicsExit.h:34
epicsExitFunc func
Definition: epicsExit.c:41
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Definition: osdThread.c:790
LIBCOM_API void epicsExitCallAtExits(void)
Internal routine that runs the registered exit routines.
Definition: epicsExit.c:102
Routines for code that can&#39;t continue or return after an error.
#define stderr
Definition: epicsStdio.h:32
List header type.
Definition: ellLib.h:56
C++ and C descriptions for a thread.
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
LIBCOM_API epicsThreadPrivateId epicsStdCall epicsThreadPrivateCreate(void)
Definition: osdThread.c:934
LIBCOM_API int epicsAtExit3(epicsExitFunc func, void *arg, const char *name)
Register a function and an associated context parameter.
Definition: epicsExit.c:166
Exporting IOC objects.