Chromium Code Reviews| Index: base/win/dllmain.cc |
| =================================================================== |
| --- base/win/dllmain.cc (revision 0) |
| +++ base/win/dllmain.cc (revision 0) |
| @@ -0,0 +1,101 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +// Windows doesn't support pthread_key_create's destr_function, and in fact |
| +// it's a bit tricky to get code to run when a thread exits. This is |
| +// cargo-cult magic from http://www.codeproject.com/threads/tls.asp. |
| +// We are trying to be compatible with both a LoadLibrary style invocation, as |
| +// well as static linking. This code only needs to be included if we use |
| +// LoadLibrary, but it hooks into the "standard" set of TLS callbacks that are |
| +// provided for static linking. |
| + |
| +// Force a reference to _tls_used to make the linker create the TLS directory |
| +// if it's not already there (that is, even if __declspec(thread) is not used). |
| +// To make sure we really traverse the whole list, we put down two elements, and |
| +// then check that we called both functions when we scanned the list. |
| +// Force a reference to p_thread_callback_dllmain_first_entry and |
| +// p_thread_callback_dllmain_first_entry to prevent whole program optimization |
| +// from discarding the variables. |
| + |
| +#include <windows.h> |
| + |
| +#include "base/logging.h" |
| + |
| +// Indicate if another service is scanning the callbacks. |
| +static bool linker_notifications_are_active = false; |
| + |
| +// This will be our mostly no-op callback that we'll list (twice). We won't |
| +// deliberately call it, and if it is called, that means we don't need to do any |
| +// of the scanning anymore. We expect such a call to arrive via a |
| +// THREAD_ATTACH message, long before we'd have to perform our THREAD_DETACH |
| +// callback scans. |
| +static void NTAPI on_callback(HINSTANCE h, DWORD dwReason, PVOID pv); |
|
cpu_(ooo_6.6-7.5)
2011/12/06 19:15:50
use same notation as thread_local_storage_win.cc
jar (doing other things)
2011/12/06 19:56:26
Done.
|
| + |
| +#ifdef _WIN64 |
| + |
| +#pragma comment(linker, "/INCLUDE:_tls_used") |
| +#pragma comment(linker, "/INCLUDE:p_thread_callback_dllmain_first_entry") |
| +#pragma comment(linker, "/INCLUDE:p_thread_callback_dllmain_later_entry") |
| + |
| +#else // _WIN64 |
| + |
| +#pragma comment(linker, "/INCLUDE:__tls_used") |
| +#pragma comment(linker, "/INCLUDE:_p_thread_callback_dllmain_first_entry") |
| +#pragma comment(linker, "/INCLUDE:_p_thread_callback_dllmain_later_entry") |
| + |
| +#endif // _WIN64 |
| + |
| +// extern "C" suppresses C++ name mangling so we know the symbol names for the |
| +// linker /INCLUDE:symbol pragmas above. |
| +extern "C" { |
| +typedef void (NTAPI *CallbackPointer)(HINSTANCE h, DWORD dwReason, PVOID pv); |
| +// This tells the linker to run these functions. |
| +#pragma data_seg(push, old_seg) |
| +// Use earliest possible name in the .CRT$XL? list of segments. |
| +#pragma data_seg(".CRT$XLA") |
| +CallbackPointer p_thread_callback_dllmain_first_entry = on_callback; |
|
cpu_(ooo_6.6-7.5)
2011/12/06 19:15:50
this must be const in x64
jar (doing other things)
2011/12/06 19:56:26
Done.
|
| +// The latest possible name in the .CRT$XL? (other than *Z, which has a NULL). |
| +#pragma data_seg(".CRT$XLY") |
| +CallbackPointer p_thread_callback_dllmain_later_entry = on_callback; |
|
cpu_(ooo_6.6-7.5)
2011/12/06 19:15:50
use thread_local_storage_win.cc notation like PIMA
jar (doing other things)
2011/12/06 19:56:26
Done.
|
| +#pragma data_seg(pop, old_seg) |
| +} // extern "C" |
| + |
| + |
| +// Make DllMain call the listed callbacks. This way any third parties that are |
| +// linked in will also be called. |
| +BOOL WINAPI DllMain(HINSTANCE h, DWORD reason, PVOID pv) { |
| + if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) |
| + return true; // We won't service THREAD_ATTACH calls. |
| + |
| + if (linker_notifications_are_active) |
| + return true; // Some other service is doing this work. |
| + |
| + // Use our first entry as a starting point, but don't call it. |
| + CallbackPointer* it = &p_thread_callback_dllmain_first_entry; |
| + while(*++it) { |
| + if (*it == p_thread_callback_dllmain_later_entry) |
| + continue; // Don't bother to call our own callbacks. |
| + (*it)(h, reason, pv); |
| + } |
| + // Guarantee that we did a full list, and didn't get "stuck" on some NULL |
| + // ahead of time. The fear is that there migtht be another null in ".CRT$XLA" |
| + // the way there is guaranteed to be a NULL in ".CRT$XLZ" |
| + // We use a CHECK to ensure that the release bulid, no matter how created, is |
| + // compliant with this arrangement. |
| + CHECK_GT(*it, p_thread_callback_dllmain_later_entry); |
| + return true; |
| +} |
| + |
| +static void NTAPI on_callback(HINSTANCE h, DWORD dwReason, PVOID pv) { |
| + // Do nothing. We were just a place holder in the list used to test that we |
| + // call all items. |
| + // If we are called, it means that some other system is scanning the callbacks |
| + // and we don't need to do so in DllMain(). |
| + linker_notifications_are_active = true; |
| + // Note: If some other routine some how plays this same game... we could both |
| + // decide not to do the scanning <sigh>, but this trick should suppress |
| + // duplicate calls on Vista, where the runtime takes care of the callbacks, |
| + // and allow us to do the callbacks on XP, where we are currently devoid of |
| + // callbacks (due to an explicit LoadLibrary call). |
| +} |