diff options
author | Ivan Zhakov <ivan@apache.org> | 2019-12-14 10:45:39 +0000 |
---|---|---|
committer | Ivan Zhakov <ivan@apache.org> | 2019-12-14 10:45:39 +0000 |
commit | c90021a5071ba646356fb1509a0cdff7416653b4 (patch) | |
tree | 2e4a61716deed375963fb907e7da61eea5499890 /misc | |
parent | d5f961e6c40af43e0a3e1edf3005a661edb38075 (diff) | |
download | apr-c90021a5071ba646356fb1509a0cdff7416653b4.tar.gz |
win32: Rewrite late linking code (again) without using INIT_ONCE as groundwork
to backport r1866562 and 1859477 to APR 1.6.x and APR 1.7.x. It also slightly
improves performance and reduce lock contention.
* include/arch/win32/apr_arch_misc.h
(apr_winapi_fpt_##fn): Declare as volatile and initialize to (ULONG_PTR) -1.
(apr_winapi_ctrl_##fn, apr_winapi_init_once_##fn): Remove.
(apr_winapi_ld_##fn): Concurrently invoke apr_load_dll_func() if
apr_winapi_fpt_##fn == -1.
* misc/win32/misc.c
(win32_late_dll_t.control): Remove.
(win32_late_dll_t.dll_handle): Declare as volatile.
(late_dll): Initialize dll_handle to INVALID_HANDLE_VALUE (assume that is
invalid module handle).
(apr_load_dll_func): Concurrently load library if dll_handle ==
INVALID_HANDLE_VALUE. Then perform CAS and then free library if other
thread performed initialization before.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1871447 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'misc')
-rw-r--r-- | misc/win32/misc.c | 75 |
1 files changed, 41 insertions, 34 deletions
diff --git a/misc/win32/misc.c b/misc/win32/misc.c index 5136b9336..5631d2c9e 100644 --- a/misc/win32/misc.c +++ b/misc/win32/misc.c @@ -135,63 +135,70 @@ apr_status_t apr_get_oslevel(apr_oslevel_e *level) */ typedef struct win32_late_dll_t { - INIT_ONCE control; const apr_wchar_t *apiset_name; const apr_wchar_t *dll_name; - HMODULE dll_handle; + volatile HMODULE dll_handle; } win32_late_dll_t; static win32_late_dll_t late_dll[DLL_defined] = { - {INIT_ONCE_STATIC_INIT, NULL, L"kernel32", NULL}, - {INIT_ONCE_STATIC_INIT, NULL, L"advapi32", NULL}, - {INIT_ONCE_STATIC_INIT, NULL, L"mswsock", NULL}, - {INIT_ONCE_STATIC_INIT, NULL, L"ws2_32", NULL}, - {INIT_ONCE_STATIC_INIT, NULL, L"shell32", NULL}, - {INIT_ONCE_STATIC_INIT, NULL, L"ntdll.dll", NULL}, - {INIT_ONCE_STATIC_INIT, NULL, L"Iphplapi", NULL}, - {INIT_ONCE_STATIC_INIT, L"api-ms-win-downlevel-shell32-l1-1-0.dll", - L"shell32", NULL} + {NULL, L"kernel32", INVALID_HANDLE_VALUE}, + {NULL, L"advapi32", INVALID_HANDLE_VALUE}, + {NULL, L"mswsock", INVALID_HANDLE_VALUE}, + {NULL, L"ws2_32", INVALID_HANDLE_VALUE}, + {NULL, L"shell32", INVALID_HANDLE_VALUE}, + {NULL, L"ntdll.dll", INVALID_HANDLE_VALUE}, + {NULL, L"Iphplapi", INVALID_HANDLE_VALUE}, + {L"api-ms-win-downlevel-shell32-l1-1-0.dll", L"shell32", INVALID_HANDLE_VALUE} }; -static BOOL WINAPI load_dll_callback(PINIT_ONCE InitOnce, - PVOID Parameter, - PVOID *Context) +FARPROC apr_load_dll_func(apr_dlltoken_e fnLib, char* fnName, int ordinal) { - win32_late_dll_t *dll = Parameter; + win32_late_dll_t *dll = &late_dll[fnLib]; + HMODULE cached_dll_handle; - /* Try api set dll first if defined. */ - if (dll->apiset_name) { - dll->dll_handle = LoadLibraryExW(dll->apiset_name, NULL, - LOAD_LIBRARY_SEARCH_SYSTEM32); - } + /* Pointer sized reads are atomic on Windows. */ + cached_dll_handle = dll->dll_handle; + if (cached_dll_handle == INVALID_HANDLE_VALUE) { + HMODULE dll_handle = NULL; - if (!dll->dll_handle) { - dll->dll_handle = LoadLibraryW(dll->dll_name); - } + /* Try API Set dll first if defined. */ + if (dll->apiset_name) { + dll_handle = LoadLibraryExW(dll->apiset_name, NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32); + } - return TRUE; -} + if (!dll_handle) { + dll_handle = LoadLibraryW(dll->dll_name); + } -FARPROC apr_load_dll_func(apr_dlltoken_e fnLib, char* fnName, int ordinal) -{ - win32_late_dll_t *dll = &late_dll[fnLib]; + cached_dll_handle = InterlockedCompareExchangePointer(&dll->dll_handle, + dll_handle, + INVALID_HANDLE_VALUE); + if (cached_dll_handle == INVALID_HANDLE_VALUE) { + cached_dll_handle = dll_handle; + } + else if (dll_handle) { + /* Other thread won the race: release our library handle. */ + FreeLibrary(dll_handle); + } + } - InitOnceExecuteOnce(&dll->control, load_dll_callback, dll, NULL); - if (!dll->dll_handle) + if (!cached_dll_handle) { return NULL; + } #if defined(_WIN32_WCE) if (ordinal) - return GetProcAddressA(dll->dll_handle, + return GetProcAddressA(cached_dll_handle, (const char *) (apr_ssize_t)ordinal); else - return GetProcAddressA(dll->dll_handle, fnName); + return GetProcAddressA(cached_dll_handle, fnName); #else if (ordinal) - return GetProcAddress(dll->dll_handle, + return GetProcAddress(cached_dll_handle, (const char *) (apr_ssize_t)ordinal); else - return GetProcAddress(dll->dll_handle, fnName); + return GetProcAddress(cached_dll_handle, fnName); #endif } |