exit.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. exit.c
  9. Abstract:
  10. This module implements functionality associated with the ending of a
  11. program.
  12. Author:
  13. Evan Green 11-Mar-2013
  14. Environment:
  15. User Mode C Library
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "libcp.h"
  21. #include <assert.h>
  22. #include <errno.h>
  23. #include <signal.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. //
  29. // ---------------------------------------------------------------- Definitions
  30. //
  31. #define ABORT_RAISE_FAILURE_STATUS 127
  32. //
  33. // Define the number of atexit handlers per block.
  34. //
  35. #define AT_EXIT_BLOCK_SIZE 32
  36. //
  37. // ------------------------------------------------------ Data Type Definitions
  38. //
  39. typedef
  40. void
  41. (*PCXA_AT_EXIT_ROUTINE) (
  42. void *Parameter
  43. );
  44. /*++
  45. Routine Description:
  46. This routine is the prototype for a routine registered to be called via
  47. the __cxa_atexit routine.
  48. Arguments:
  49. Parameter - Supplies the parameter supplied on registration.
  50. Return Value:
  51. None.
  52. --*/
  53. /*++
  54. Structure Description:
  55. This structure defines a registered exit handler.
  56. Members:
  57. AtExitRoutine - Stores the pointer to the exit routine handler. This is
  58. NULL if the slot is free.
  59. Argument - Stores the argument to pass to the cxa_atexit handler.
  60. SharedObject - Stores a pointer to the shared object the cxa_atexit handler
  61. is for.
  62. --*/
  63. typedef struct _AT_EXIT_HANDLER {
  64. PCXA_AT_EXIT_ROUTINE AtExitRoutine;
  65. PVOID Argument;
  66. PVOID SharedObject;
  67. } AT_EXIT_HANDLER, *PAT_EXIT_HANDLER;
  68. /*++
  69. Structure Description:
  70. This structure defines a block of functions to call when the process
  71. exits normally.
  72. Members:
  73. ListEntry - Stores the list entry for the block. For the global at exit
  74. block, this is the head of the list of child blocks. For the child
  75. blocks, this is the list entry storing sibling blocks.
  76. Handlers - Stores the array of atexit handlers.
  77. --*/
  78. typedef struct _AT_EXIT_BLOCK {
  79. LIST_ENTRY ListEntry;
  80. AT_EXIT_HANDLER Handlers[AT_EXIT_BLOCK_SIZE];
  81. } AT_EXIT_BLOCK, *PAT_EXIT_BLOCK;
  82. //
  83. // ----------------------------------------------- Internal Function Prototypes
  84. //
  85. INT
  86. ClpRegisterExitHandler (
  87. PVOID Routine,
  88. PVOID Argument,
  89. PVOID SharedObject
  90. );
  91. VOID
  92. ClpCallExitHandlers (
  93. PVOID SharedObject
  94. );
  95. VOID
  96. ClpAcquireAtExitLock (
  97. VOID
  98. );
  99. VOID
  100. ClpReleaseAtExitLock (
  101. VOID
  102. );
  103. //
  104. // -------------------------------------------------------------------- Globals
  105. //
  106. ULONG ClAtExitLock;
  107. //
  108. // Store the first block of atexit registration routines, which don't require
  109. // dynamic allocation. In this block, the list entry is the head of the list.
  110. //
  111. AT_EXIT_BLOCK ClAtExitBlock;
  112. //
  113. // Store a boolean indicating if atexit has been called to know whether to
  114. // restart calling the exit handlers.
  115. //
  116. BOOL ClAtExitCalled = FALSE;
  117. //
  118. // ------------------------------------------------------------------ Functions
  119. //
  120. LIBC_API
  121. __NO_RETURN
  122. void
  123. abort (
  124. void
  125. )
  126. /*++
  127. Routine Description:
  128. This routine causes abnormal process termination to occur, unless the
  129. signal SIGABRT is being caught and the signal handler does not return. The
  130. abort function shall override ignoring or blocking of the SIGABRT signal.
  131. Arguments:
  132. None.
  133. Return Value:
  134. This routine does not return.
  135. --*/
  136. {
  137. sigset_t Mask;
  138. ClpFlushAllStreams(TRUE, NULL);
  139. sigemptyset(&Mask);
  140. sigaddset(&Mask, SIGABRT);
  141. sigprocmask(SIG_UNBLOCK, &Mask, NULL);
  142. while (TRUE) {
  143. if (raise(SIGABRT) != 0) {
  144. _exit(ABORT_RAISE_FAILURE_STATUS);
  145. }
  146. }
  147. }
  148. LIBC_API
  149. __NO_RETURN
  150. void
  151. exit (
  152. int Status
  153. )
  154. /*++
  155. Routine Description:
  156. This routine terminates the current process, calling any routines registered
  157. to run upon exiting.
  158. Arguments:
  159. Status - Supplies a status code to return to the parent program.
  160. Return Value:
  161. None. This routine does not return.
  162. --*/
  163. {
  164. ClpCallExitHandlers(NULL);
  165. ClpFlushAllStreams(FALSE, NULL);
  166. _Exit(Status);
  167. }
  168. LIBC_API
  169. __NO_RETURN
  170. void
  171. _exit (
  172. int Status
  173. )
  174. /*++
  175. Routine Description:
  176. This routine terminates the current process. It does not call any routines
  177. registered to run upon exit.
  178. Arguments:
  179. Status - Supplies a status code to return to the parent program.
  180. Return Value:
  181. None. This routine does not return.
  182. --*/
  183. {
  184. _Exit(Status);
  185. }
  186. LIBC_API
  187. __NO_RETURN
  188. void
  189. _Exit (
  190. int Status
  191. )
  192. /*++
  193. Routine Description:
  194. This routine terminates the current process. It does not call any routines
  195. registered to run upon exit.
  196. Arguments:
  197. Status - Supplies a status code to return to the parent program.
  198. Return Value:
  199. None. This routine does not return.
  200. --*/
  201. {
  202. OsExitProcess(Status);
  203. //
  204. // Execution should never get here.
  205. //
  206. while (TRUE) {
  207. raise(SIGABRT);
  208. }
  209. }
  210. LIBC_API
  211. int
  212. __cxa_atexit (
  213. void (*DestructorFunction)(void *),
  214. void *Argument,
  215. void *SharedObject
  216. )
  217. /*++
  218. Routine Description:
  219. This routine is called to register a global static destructor function.
  220. Arguments:
  221. DestructorFunction - Supplies a pointer to the function to call.
  222. Argument - Supplies an argument to pass the function when it is called.
  223. SharedObject - Supplies a pointer to the shared object this destructor is
  224. associated with.
  225. Return Value:
  226. 0 on success.
  227. Non-zero on failure.
  228. --*/
  229. {
  230. INT Result;
  231. Result = ClpRegisterExitHandler(DestructorFunction,
  232. Argument,
  233. SharedObject);
  234. return Result;
  235. }
  236. LIBC_API
  237. void
  238. __cxa_finalize (
  239. void *SharedObject
  240. )
  241. /*++
  242. Routine Description:
  243. This routine is called when a shared object unloads. It calls the static
  244. destructors.
  245. Arguments:
  246. SharedObject - Supplies a pointer to the shared object being destroyed, or
  247. 0 if all destructors should be called.
  248. Return Value:
  249. None.
  250. --*/
  251. {
  252. ClpCallExitHandlers(SharedObject);
  253. return;
  254. }
  255. //
  256. // --------------------------------------------------------- Internal Functions
  257. //
  258. INT
  259. ClpRegisterExitHandler (
  260. PVOID Routine,
  261. PVOID Argument,
  262. PVOID SharedObject
  263. )
  264. /*++
  265. Routine Description:
  266. This routine registers a function to be called when the process exits
  267. normally via a call to exit or a return from main. Calls to exec clear
  268. the list of registered exit functions. This routine may allocate memory.
  269. Functions are called in the reverse order in which they were registered.
  270. Arguments:
  271. Routine - Supplies a pointer to the routine to call, which is either of
  272. type PAT_EXIT_ROUTINE or PCXA_AT_EXIT_ROUTINE.
  273. Argument - Supplies the argument to pass to cxa_atexit routines.
  274. SharedObject - Supplies the shared object this routine is attached to for
  275. cxa_atexit handlers.
  276. Return Value:
  277. 0 on success.
  278. Non-zero on failure.
  279. --*/
  280. {
  281. PAT_EXIT_BLOCK Block;
  282. PAT_EXIT_HANDLER Handler;
  283. ULONG Index;
  284. INT Status;
  285. if (Routine == NULL) {
  286. return EINVAL;
  287. }
  288. ClpAcquireAtExitLock();
  289. ClAtExitCalled = TRUE;
  290. //
  291. // Initialize the list head if not yet done.
  292. //
  293. if (ClAtExitBlock.ListEntry.Next == NULL) {
  294. INITIALIZE_LIST_HEAD(&(ClAtExitBlock.ListEntry));
  295. }
  296. //
  297. // Look in the last block for a free slot.
  298. //
  299. Status = ENOMEM;
  300. Block = LIST_VALUE(ClAtExitBlock.ListEntry.Previous,
  301. AT_EXIT_BLOCK,
  302. ListEntry);
  303. for (Index = 0; Index < AT_EXIT_BLOCK_SIZE; Index += 1) {
  304. Handler = &(Block->Handlers[Index]);
  305. if (Handler->AtExitRoutine == NULL) {
  306. Handler->AtExitRoutine = Routine;
  307. Handler->Argument = Argument;
  308. Handler->SharedObject = SharedObject;
  309. Status = 0;
  310. goto RegisterExitHandlerEnd;
  311. }
  312. }
  313. //
  314. // Create a new block.
  315. //
  316. Block = malloc(sizeof(AT_EXIT_BLOCK));
  317. if (Block == NULL) {
  318. Status = ENOMEM;
  319. goto RegisterExitHandlerEnd;
  320. }
  321. memset(Block, 0, sizeof(AT_EXIT_BLOCK));
  322. INSERT_BEFORE(&(Block->ListEntry), &(ClAtExitBlock.ListEntry));
  323. Handler->AtExitRoutine = Routine;
  324. Handler->Argument = Argument;
  325. Handler->SharedObject = SharedObject;
  326. Status = 0;
  327. RegisterExitHandlerEnd:
  328. ClpReleaseAtExitLock();
  329. return Status;
  330. }
  331. VOID
  332. ClpCallExitHandlers (
  333. PVOID SharedObject
  334. )
  335. /*++
  336. Routine Description:
  337. This routine calls the exit handlers, either all of them or only for a
  338. particular shared object.
  339. Arguments:
  340. SharedObject - Supplies an optional pointer to the shared object being
  341. unloaded. If NULL, then all at exit handlers are called.
  342. Return Value:
  343. None. This routine does not return.
  344. --*/
  345. {
  346. PCXA_AT_EXIT_ROUTINE AtExitRoutine;
  347. PAT_EXIT_BLOCK Block;
  348. PLIST_ENTRY CurrentEntry;
  349. PAT_EXIT_HANDLER Handler;
  350. LONG Index;
  351. //
  352. // If the list entry is not initialized, no one has ever called into the
  353. // exit handler registration routine.
  354. //
  355. if (ClAtExitBlock.ListEntry.Next == NULL) {
  356. return;
  357. }
  358. do {
  359. ClAtExitCalled = FALSE;
  360. //
  361. // Handle the blocks in the reverse order.
  362. //
  363. CurrentEntry = ClAtExitBlock.ListEntry.Previous;
  364. while (TRUE) {
  365. Block = LIST_VALUE(CurrentEntry, AT_EXIT_BLOCK, ListEntry);
  366. for (Index = AT_EXIT_BLOCK_SIZE - 1; Index >= 0; Index -= 1) {
  367. Handler = &(Block->Handlers[Index]);
  368. if (Handler->AtExitRoutine == NULL) {
  369. continue;
  370. }
  371. //
  372. // If only calling handlers for a specific shared object being
  373. // unloaded, skip all handlers that aren't registers in the
  374. // shared object.
  375. //
  376. if (SharedObject != NULL) {
  377. if (Handler->SharedObject != SharedObject) {
  378. continue;
  379. }
  380. }
  381. //
  382. // Atomic exchange in the free value so that only one fella
  383. // gets to call the exit handler. Handler slots don't get
  384. // get reused so don't worry about that.
  385. //
  386. AtExitRoutine = (PVOID)RtlAtomicExchange(
  387. (PUINTN)&(Handler->AtExitRoutine),
  388. (UINTN)NULL);
  389. if (AtExitRoutine == NULL) {
  390. continue;
  391. }
  392. AtExitRoutine(Handler->Argument);
  393. //
  394. // If the handler called atexit, start over.
  395. //
  396. if (ClAtExitCalled != FALSE) {
  397. break;
  398. }
  399. }
  400. if (ClAtExitCalled != FALSE) {
  401. break;
  402. }
  403. if (Block == &ClAtExitBlock) {
  404. break;
  405. }
  406. CurrentEntry = CurrentEntry->Previous;
  407. }
  408. } while (ClAtExitCalled != FALSE);
  409. if (SharedObject != NULL) {
  410. ClpUnregisterAtfork(SharedObject);
  411. }
  412. return;
  413. }
  414. VOID
  415. ClpAcquireAtExitLock (
  416. VOID
  417. )
  418. /*++
  419. Routine Description:
  420. This routine acquires the global lock protecting the structures storing the
  421. functions to be called upon exit.
  422. Arguments:
  423. None.
  424. Return Value:
  425. None.
  426. --*/
  427. {
  428. ULONG OriginalValue;
  429. //
  430. // Loop trying to acquire the lock and also checking to see if the process
  431. // has already started exiting.
  432. //
  433. while (TRUE) {
  434. OriginalValue = RtlAtomicCompareExchange32(&ClAtExitLock, 1, 0);
  435. if (OriginalValue == 0) {
  436. break;
  437. }
  438. }
  439. return;
  440. }
  441. VOID
  442. ClpReleaseAtExitLock (
  443. VOID
  444. )
  445. /*++
  446. Routine Description:
  447. This routine releases the global lock protecting the structures storing the
  448. functions to be called upon exit.
  449. Arguments:
  450. None.
  451. Return Value:
  452. None.
  453. --*/
  454. {
  455. ULONG PreviousValue;
  456. PreviousValue = RtlAtomicExchange32(&ClAtExitLock, 0);
  457. assert(PreviousValue == 1);
  458. return;
  459. }