2 * Copyright 2004-2010, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Daniel Reinhold, danielre@users.sf.net
7 * Axel Dörfler, axeld@pinc-software.de
8 * Ingo Weinhold, ingo_weinhold@gmx.de
12 #include <SupportDefs.h>
21 #include <util/DoublyLinkedList.h>
22 #include <util/SinglyLinkedList.h>
24 #include <libroot_private.h>
26 #include <runtime_loader.h>
30 extern "C" void _IO_cleanup(void);
31 extern "C" void _thread_do_exit_work(void);
34 struct AtExitInfoBlock
;
36 struct AtExitInfo
: SinglyLinkedListLinkImpl
<AtExitInfo
> {
37 AtExitInfoBlock
* block
;
43 typedef SinglyLinkedList
<AtExitInfo
> AtExitInfoList
;
46 struct AtExitInfoBlock
: DoublyLinkedListLinkImpl
<AtExitInfoBlock
> {
55 return fFirstUnused
== ATEXIT_MAX
&& fFreeList
.IsEmpty();
58 AtExitInfo
* AllocateInfo()
60 // Handle the likely case -- the block is not fully used yet -- first.
61 // Grab the next info from the array.
62 if (fFirstUnused
< ATEXIT_MAX
) {
63 AtExitInfo
* info
= &fInfos
[fFirstUnused
++];
68 // The block was fully used, but there might be infos in the free list.
69 return fFreeList
.RemoveHead();
72 void FreeInfo(AtExitInfo
* info
)
78 AtExitInfo fInfos
[ATEXIT_MAX
];
80 AtExitInfoList fFreeList
;
83 typedef DoublyLinkedList
<AtExitInfoBlock
> AtExitInfoBlockList
;
87 DSOPredicate(void* dsoHandle
)
93 inline bool operator()(const AtExitInfo
* info
) const
95 return info
->dsoHandle
== fDSOHandle
;
103 struct AddressRangePredicate
{
104 AddressRangePredicate(addr_t start
, size_t size
)
107 fEnd(start
+ size
- 1)
111 inline bool operator()(const AtExitInfo
* info
) const
113 addr_t address
= (addr_t
)info
->hook
;
114 return info
->dsoHandle
== NULL
&& address
>= fStart
&& address
<= fEnd
;
115 // Note: We ignore hooks associated with an image (the same one
116 // likely), since those will be called anyway when __cxa_finalize()
117 // is invoked for that image.
126 static AtExitInfoBlock sInitialAtExitInfoBlock
;
127 static AtExitInfoBlockList sAtExitInfoBlocks
;
128 static AtExitInfoList sAtExitInfoStack
;
129 static recursive_lock sAtExitLock
= RECURSIVE_LOCK_INITIALIZER("at exit lock");
135 recursive_lock_lock(&sAtExitLock
);
142 recursive_lock_unlock(&sAtExitLock
);
146 template<typename Predicate
>
148 call_exit_hooks(const Predicate
& predicate
)
152 AtExitInfo
* previousInfo
= NULL
;
153 AtExitInfo
* info
= sAtExitInfoStack
.Head();
154 while (info
!= NULL
) {
155 AtExitInfo
* nextInfo
= sAtExitInfoStack
.GetNext(info
);
157 if (predicate(info
)) {
158 // remove info from stack
159 sAtExitInfoStack
.Remove(previousInfo
, info
);
162 info
->hook(info
->data
);
164 // return the info to the block
165 if (info
->block
->IsEmpty())
166 sAtExitInfoBlocks
.Add(info
->block
);
168 info
->block
->FreeInfo(info
);
175 _exit_stack_unlock();
179 // #pragma mark -- C++ ABI
182 /*! exit() hook registration function (mandated by the C++ ABI).
183 \param hook Hook function to be called.
184 \param data The data to be passed to the hook.
185 \param dsoHandle If non-NULL, the hook is associated with the respective
186 loaded shared object (aka image) -- the hook will be called either on
187 exit() or earlier when the shared object is unloaded. If NULL, the hook
188 is called only on exit().
189 \return \c 0 on success, another value on failure.
192 __cxa_atexit(void (*hook
)(void*), void* data
, void* dsoHandle
)
199 // We need to allocate an info. Get an info block from which to allocate.
200 AtExitInfoBlock
* block
= sAtExitInfoBlocks
.Head();
202 // might be the first call -- check the initial block
203 if (!sInitialAtExitInfoBlock
.IsEmpty()) {
204 block
= &sInitialAtExitInfoBlock
;
206 // no empty block -- let's hope libroot is initialized sufficiently
207 // for the heap to work
208 block
= new(std::nothrow
) AtExitInfoBlock
;
210 _exit_stack_unlock();
215 sAtExitInfoBlocks
.Add(block
);
219 AtExitInfo
* info
= block
->AllocateInfo();
221 // If the block is empty now, remove it from the list.
222 if (block
->IsEmpty())
223 sAtExitInfoBlocks
.Remove(block
);
225 // init and add the info
228 info
->dsoHandle
= dsoHandle
;
230 sAtExitInfoStack
.Add(info
);
232 _exit_stack_unlock();
238 /*! exit() hook calling function (mandated by the C++ ABI).
240 Calls the exit() hooks associated with a certain shared object handle,
241 respectively calls all hooks when a NULL handle is given. All called
244 \param dsoHandle If non-NULL, all hooks associated with that handle are
245 called. If NULL, all hooks are called.
248 __cxa_finalize(void* dsoHandle
)
250 if (dsoHandle
== NULL
) {
254 while (AtExitInfo
* info
= sAtExitInfoStack
.RemoveHead()) {
256 info
->hook(info
->data
);
258 // return the info to the block
259 if (info
->block
->IsEmpty())
260 sAtExitInfoBlocks
.Add(info
->block
);
262 info
->block
->FreeInfo(info
);
265 _exit_stack_unlock();
267 // call all hooks for the respective DSO
268 call_exit_hooks(DSOPredicate(dsoHandle
));
273 // #pragma mark - private API
277 _call_atexit_hooks_for_range(addr_t start
, addr_t size
)
279 call_exit_hooks(AddressRangePredicate(start
, size
));
283 // #pragma mark - public API
289 fprintf(stderr
, "Abort\n");
292 debugger("abort() called");
298 atexit(void (*func
)(void))
300 return __cxa_atexit((void (*)(void*))func
, NULL
, NULL
);
307 // BeOS on exit notification for the main thread
308 _thread_do_exit_work();
310 // unwind the exit stack, calling the registered functions
311 __cxa_finalize(NULL
);
313 // close all open files
316 __gRuntimeLoader
->call_termination_hooks();
318 // exit with status code
319 _kern_exit_team(status
);