[boost.thread] Static Library support for Windows

In the attached file you will find a proposal for how the problem of static linkage can be solved for Windows. The files can be dircetly inserted into the boost library framework. They almost do not touch existing implementation and also provide for a backup solution (overrideable) in case some unforeseeable things are happening. The solution has been worked out for MS compilers so far. However the principle should be portable to borland compiler as well. I would like to encourage someone with knowledge in this field to attempt this. Roland ***************************************************************************** ** ** ** WARNING: This email contains an attachment of a very suspicious type. ** ** You are urged NOT to open this attachment unless you are absolutely ** ** sure it is legitmate. Opening this attachment may cause irreparable ** ** damage to your computer and your files. If you have any questions ** ** about the validity of this message, PLEASE SEEK HELP BEFORE OPENING IT. ** ** ** ** This warning was added by the IU Computer Science Dept. mail scanner. ** *****************************************************************************

I've looked at this, and if I haven't missed anything the pe_tls.cpp file is essentially the same as what you posted yesterday; the changes are in config.hpp and jamfile. Is this correct? Mike

On Thu, 5 Aug 2004 11:41:13 -0400 Michael Glassford <glassfordm@hotmail.com> wrote:
I've looked at this, and if I haven't missed anything the pe_tls.cpp file is essentially the same as what you posted yesterday; the changes are in config.hpp and jamfile. Is this correct?
When my memory is correct, this is true. In either case I took it from my latest source I tested with. BTW.: while everything seems nice so far I just tried to use the thing with MFC. It turns out that the process / thread init / term need even some more tweeking. While every destructor is getting called properly the debug version of MFC still thinks it has discovered a memory leak. Since this will be able to make a potential user nervous, I am looking to a way to get rid of these messages (by finding the correct calling order). Also at the moment there is a problem with the new operator overloading of the MFC library NAFXCWD and LIBCMTD. I will also try to fix this as soon as possible. However a simple work around exists: In the linker settings one simply needs to explicitely specify the NAFXCWD.LIB library to get things correct. Roland

On Thu, 5 Aug 2004 18:10:10 +0200 (W. Europe Daylight Time) Roland <roland.schwarz@chello.at> wrote:
BTW.: while everything seems nice so far I just tried to use the thing with MFC. It turns out that the process / thread init / term need even some more tweeking. While every destructor is getting called properly the debug version of MFC still thinks it has discovered a memory leak. Since this will be able to make a potential user nervous, I am looking to a way to get rid of these messages (by finding the correct calling order).
I am not anymore sure the leak has to do with the calling order. At least I tracked the leak down to somewhere near: // Intentional memory "leak" // This is the only way to ensure the mutex in the global data // structure is available when cleanup handlers are run, since the // execution order of cleanup handlers is unspecified on any platform // with regards to C++ destructor ordering rules. However I do not yet understand fully what is going on. What will I need to expect beeing leaking? I am not sure if there are additional leaks from elsewhere. Also, isn't the atexit well specified with respect to the global dtors? Is this MS specific or is this in the standard? Could you please help me? Roland

On Thu, 5 Aug 2004 18:10:10 +0200 (W. Europe Daylight Time) Roland <roland.schwarz@chello.at> wrote:
BTW.: while everything seems nice so far I just tried to use the
MFC. It turns out that the process / thread init / term need even some more tweeking. While every destructor is getting called properly the debug version of MFC still thinks it has discovered a memory leak. Since this will be able to make a potential user nervous, I am looking to a way to get rid of these messages (by finding the correct calling order).
I am not anymore sure the leak has to do with the calling order. At least I tracked the leak down to somewhere near: // Intentional memory "leak" // This is the only way to ensure the mutex in the global data // structure is available when cleanup handlers are run, since
"Roland" <roland.schwarz@chello.at> wrote in message news:20040805162509.ILOD9307.viefep19-int.chello.at@speedsnail... thing with the
// execution order of cleanup handlers is unspecified on any
platform
// with regards to C++ destructor ordering rules. However I do not yet understand fully what is going on. What will I
need to
expect beeing leaking?
I am not sure if there are additional leaks from elsewhere. Also, isn't the atexit well specified with respect to the global
What's being intentionally leaked? 1) The tls slot used by tss (not the same as the one used by threadmon) is never released. 2) The tss_data_t struct allocated at the beginning of the init_tss_data() function is also being leaked. dtors? The cleanup handlers being referred to in the comment are tls cleanup handlers. It has nothing to do with atexit: 1) The Windows cleanup handlers, when called by DllMain, (probably) still have the same problem that they used to have tls_callback: they can be called after constructors. I haven't gotten around to fixing this yet. 2) IIUC, with the pthreads cleanup handlers, it is literally unspecified whether they run before or after C++ destructors because pthreads is a C-based standard. 3) I'm not sure how the MPThreads cleanup handlers work, but judging by the comment it is also unspecified whether they run before or after C++ destructors.
Is this MS specific or is this in the standard?
Could you please help me?
Hope that helps. Mike

On Thu, 5 Aug 2004 12:56:40 -0400 Michael Glassford <glassfordm@hotmail.com> wrote:
Hope that helps.
Yes thank you. Indeed something else seems to be leaking. I will investigate this further. The NAFXCWD.LIB problem turned out to be nonexistent, since I simply made wrong usage of the stdafx.h and precompiled headers. When one specifies everything as intended there is no linkage problem. Thanks, Roland

On Thu, 5 Aug 2004 19:12:35 +0200 (W. Europe Daylight Time) Roland <roland.schwarz@chello.at> wrote:
On Thu, 5 Aug 2004 12:56:40 -0400 Michael Glassford <glassfordm@hotmail.com> wrote:
Hope that helps.
Yes thank you. Indeed something else seems to be leaking. I will investigate this further.
It turned out that in total 7 objects are leaking, but they are all related to the two you mentioned. It seems they are simply dynamically allocated members and the like. At least I can try to do a forced deallocation in my debug environment and see wheter they go away entirely. Roland

On Thu, 5 Aug 2004 12:56:40 -0400 Michael Glassford <glassfordm@hotmail.com> wrote:
The cleanup handlers being referred to in the comment are tls cleanup handlers. It has nothing to do with atexit:
I think I understand this yet. But I was suggesting that when you schedule a call to atexit after all constructors have been run this handler will be called before any of the global destructors are called (of course we are implying that at this time all threads already have exited. Else there is still a problem.) This behaviour seem to be standard. At least I found the following on the net: -3- If a function is registered with atexit (see <cstdlib>, lib.support.start.term <lib-support.html>) then following the call to exit, any objects with static storage duration initialized prior to the registration of that function shall not be destroyed until the registered function is called from the termination process and has completed. For an object with static storage duration constructed after a function is registered with atexit, then following the call to exit, the registered function is not called until the execution of the object's destructor has completed. If atexit is called during the construction of an object, the complete object to which it belongs shall be destroyed before the registered function is called. Roland

Michael Glassford wrote: [...]
2) IIUC, with the pthreads cleanup handlers, it is literally unspecified whether they run before or after C++ destructors because pthreads is a C-based standard.
What "pthreads cleanup handlers"? Do you mean TSD dtors and/or thread cancel/exit cleanup handlers? Thread termination (unwinding of cleanup handlers followed by TSD destruction) and program (aka process) termination (it runs atexit() handlers and C++ destructors for objects with static storage duration, if not abnormal) is fully specified. Or do you mean C++ stuff "on the stack", not static storage duration? regards, alexander.

"Alexander" == Alexander Terekhov <terekhov@web.de> writes:
Alexander> Michael Glassford wrote: Alexander> [...]
2) IIUC, with the pthreads cleanup handlers, it is literally unspecified whether they run before or after C++ destructors because pthreads is a C-based standard.
Alexander> What "pthreads cleanup handlers"? Do you mean TSD dtors and/or Alexander> thread cancel/exit cleanup handlers? Thread termination (unwinding Alexander> of cleanup handlers followed by TSD destruction) and program (aka Alexander> process) termination (it runs atexit() handlers and C++ destructors Alexander> for objects with static storage duration, if not abnormal) is fully Alexander> specified. Or do you mean C++ stuff "on the stack", not static Alexander> storage duration? I guess yes, he meant auto objects. IMHO, one can safely assume C++ destructors will be run before cleanup handlers. ~velco

Momchil Velikov wrote: [...]
Alexander> What "pthreads cleanup handlers"? Do you mean TSD dtors and/or Alexander> thread cancel/exit cleanup handlers? Thread termination (unwinding Alexander> of cleanup handlers followed by TSD destruction) and program (aka Alexander> process) termination (it runs atexit() handlers and C++ destructors Alexander> for objects with static storage duration, if not abnormal) is fully Alexander> specified. Or do you mean C++ stuff "on the stack", not static Alexander> storage duration?
I guess yes, he meant auto objects.
I'm not so sure. So, just in case: oviously, thread termination runs before process termination (on "passive" process exit). But if process is terminated "actively" then no thread cleanup is done at all. http://www.opengroup.org/austin/mailarchives/ag-review/msg01792.html (my DR that was initially rejected) http://www.opengroup.org/austin/mailarchives/ag/msg07029.html (my appeal, part I) http://www.opengroup.org/austin/mailarchives/ag/msg07032.html (my appeal, part II) http://www.opengroup.org/austin/mailarchives/ag/msg07033.html (DRB's friend of the court brief) http://www.opengroup.org/austin/mailarchives/ag/msg07048.html (Preliminary revised verdict) <quote> http://www.opengroup.org/austin/aardvark/latest/ XSH ERN 41 exit OPEN This item had been previously rejected but in the light of comments on the reflector has been revisited. A revised proposal is in the aardvark reports. This is being left open for further feedback. </quote>
IMHO, one can safely assume C++ destructors will be run before cleanup handlers.
They should run "interleaved". There shall be only one stack. http://www.opengroup.org/austin/mailarchives/ag/msg06963.html regards, alexander.

Alexander Terekhov wrote:
Momchil Velikov wrote: [...]
Alexander> What "pthreads cleanup handlers"?
The tss cleanup handler (sorry, probably the wrong name) that you pass as the second parameter to pthread_key_create.
Alexander> Do you mean TSD dtors and/or Alexander> thread cancel/exit cleanup handlers? Thread termination (unwinding Alexander> of cleanup handlers followed by TSD destruction) and program (aka Alexander> process) termination (it runs atexit() handlers and C++ destructors Alexander> for objects with static storage duration, if not abnormal) is fully Alexander> specified. Or do you mean C++ stuff "on the stack", not static Alexander> storage duration?
I meant objects with static storage duration.
I guess yes, he meant auto objects.
I'm not so sure. So, just in case: oviously, thread termination runs before process termination (on "passive" process exit). But if process is terminated "actively" then no thread cleanup is done at all.
[snip references and quote]
IMHO, one can safely assume C++ destructors will be run before cleanup handlers.
[another snip] Most of the quotes apply to thread termination cleanup handlers, not tss cleanup handlers or whatever you call them, but perhaps the same principles apply? If so, the executive summary is that I was wrong, and the order is specified? Mike

Michael Glassford wrote: [...]
Most of the quotes apply to thread termination cleanup handlers, not tss cleanup handlers or whatever you call them,
Official name is thread-specific data destructors or simply destructors.
but perhaps the same principles apply?
Yep.
If so, the executive summary is that I was wrong, and the order is specified?
If you call exit() either explicitly or by means of returning from main() than no cleanup (pthread_cleanup_push()) handlers or TSD destructors are called. Now, http://www.opengroup.org/onlinepubs/009695399/functions/pthread_exit.html says "After all cancellation cleanup handlers have been executed, if the thread has any thread-specific data, appropriate destructor functions shall be called in an unspecified order. ... The process shall exit with an exit status of 0 after the last thread has been terminated. The behavior shall be as if the implementation called exit() with a zero argument at thread termination time." #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <pthread.h> void atexit_func() { printf("atexit_func()\n"); } void tsd_dtor(void * value) { printf("tsd_dtor(%p)\n", value); } void f() { static struct object { ~object() { printf("~object()\n"); } } o; } pthread_key_t key; int main() { int status; f(); status = atexit(&atexit_func); assert(!status); status = pthread_key_create(&key, &tsd_dtor); assert(!status); status = pthread_setspecific(key, &key); assert(!status); pthread_exit(0); } shall print "atexit_func()" after "tsd_dtor" and before "~object()". And you better do NOT mess with threading stuff in atexit handlers and/or C++ destructors of objects with static storage duration. ;-) regards, alexander.

On Fri, 06 Aug 2004 15:04:30 +0200 Alexander Terekhov <terekhov@web.de> wrote:
says "After all cancellation cleanup handlers have been executed, if the thread has any thread-specific data, appropriate destructor functions shall be called in an unspecified order. ... The process shall exit with an exit status of 0 after the last thread has been terminated. The behavior shall be as if the implementation called exit() with a zero argument at thread termination time."
shall print "atexit_func()" after "tsd_dtor" and before "~object()". read shall print "atexit_func()" after "~object()" and before "tsd_dtor".
Shouldn't the line then ? Roland

On Fri, 6 Aug 2004 15:28:48 +0200 (W. Europe Daylight Time) Roland <roland.schwarz@chello.at> wrote:
shall print "atexit_func()" after "tsd_dtor" and before "~object()". read shall print "atexit_func()" after "~object()" and before "tsd_dtor".
Shouldn't the line then ?
Oops! I missed the static on the local struct declaration. I see. Roland.

On Thu, 5 Aug 2004 11:41:13 -0400 Michael Glassford <glassfordm@hotmail.com> wrote:
I've looked at this, and if I haven't missed anything the pe_tls.cpp file is essentially the same as what you posted yesterday; the changes are in config.hpp and jamfile. Is this correct?
When my memory is correct, this is true. In either case I took it from my latest source I tested with.
BTW.: while everything seems nice so far I just tried to use the thing with MFC. It turns out that the process / thread init / term need even some more tweeking. While every destructor is getting called properly the debug version of MFC still thinks it has discovered a memory leak. Since this will be able to make a
"Roland" <roland.schwarz@chello.at> wrote in message news:20040805160547.ICDA9307.viefep19-int.chello.at@speedsnail... potential
user nervous, I am looking to a way to get rid of these messages (by finding the correct calling order).
I'm just throwing this out in case it might help, but you could take a look at the documentation for #pragma init_seg ("lib" in particular). Sorry if it's not applicable, but I don't have the time to go through details in the Boost.Thread code right now. I've used that myself to be able to properly track memory leaks using the _CrtXxx functions without getting warnings for global static objects' leaking. // Johan
participants (5)
-
Alexander Terekhov
-
Johan Nilsson
-
Michael Glassford
-
Momchil Velikov
-
Roland