Manually load CONDITION_VARIABLE methods on Windows, checking for failure (XP).

Tested by running DM on XP.  Before this patch, it fails at startup (even just out/Debug/dm --help).  Now it asserts for other reasons later on in user code, which is just fine by me.

The net effect is that SkTaskGroups will always be synchronous on XP.  That's not ideal, but a step up from crashing.

CQ_EXTRA_TRYBOTS=client.skia:Test-Win7-ShuttleA-HD2000-x86-Release-Trybot,Test-Win7-ShuttleA-HD2000-x86_64-Release-Trybot

BUG=skia:

Review URL: https://codereview.chromium.org/700683002
This commit is contained in:
mtklein 2014-11-03 17:25:54 -08:00 committed by Commit bot
parent 7c11aadd82
commit db8d0e5bb0
3 changed files with 51 additions and 16 deletions

View File

@ -165,7 +165,7 @@ ThreadPool* ThreadPool::gGlobal = NULL;
SkTaskGroup::Enabler::Enabler(int threads) { SkTaskGroup::Enabler::Enabler(int threads) {
SkASSERT(ThreadPool::gGlobal == NULL); SkASSERT(ThreadPool::gGlobal == NULL);
if (threads != 0) { if (threads != 0 && SkCondVar::Supported()) {
ThreadPool::gGlobal = SkNEW_ARGS(ThreadPool, (threads)); ThreadPool::gGlobal = SkNEW_ARGS(ThreadPool, (threads));
} }
} }

View File

@ -7,13 +7,47 @@
#include "SkCondVar.h" #include "SkCondVar.h"
#if defined(SK_BUILD_FOR_WIN32)
static void (WINAPI *initialize_condition_variable)(PCONDITION_VARIABLE);
static BOOL (WINAPI *sleep_condition_variable)(PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD);
static void (WINAPI *wake_condition_variable)(PCONDITION_VARIABLE);
static void (WINAPI *wake_all_condition_variable)(PCONDITION_VARIABLE);
template <typename T>
static void set_fn_ptr(T* ptr, FARPROC fn) { *ptr = reinterpret_cast<T>(fn); }
#endif
bool SkCondVar::Supported() {
#ifdef SK_USE_POSIX_THREADS
return true;
#elif defined(SK_BUILD_FOR_WIN32)
// If we're >= Vista we'll find these functions. Otherwise (XP) SkCondVar is not supported.
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
set_fn_ptr(&initialize_condition_variable,
GetProcAddress(kernel32, "InitializeConditionVariable"));
set_fn_ptr(&sleep_condition_variable,
GetProcAddress(kernel32, "SleepConditionVariableCS"));
set_fn_ptr(&wake_condition_variable,
GetProcAddress(kernel32, "WakeConditionVariable"));
set_fn_ptr(&wake_all_condition_variable,
GetProcAddress(kernel32, "WakeAllConditionVariable"));
return initialize_condition_variable
&& sleep_condition_variable
&& wake_condition_variable
&& wake_all_condition_variable;
#else
return false;
#endif
}
SkCondVar::SkCondVar() { SkCondVar::SkCondVar() {
#ifdef SK_USE_POSIX_THREADS #ifdef SK_USE_POSIX_THREADS
pthread_mutex_init(&fMutex, NULL /* default mutex attr */); pthread_mutex_init(&fMutex, NULL /* default mutex attr */);
pthread_cond_init(&fCond, NULL /* default cond attr */); pthread_cond_init(&fCond, NULL /* default cond attr */);
#elif defined(SK_BUILD_FOR_WIN32) #elif defined(SK_BUILD_FOR_WIN32)
InitializeCriticalSection(&fCriticalSection); InitializeCriticalSection(&fCriticalSection);
InitializeConditionVariable(&fCondition); SkASSERT(initialize_condition_variable);
initialize_condition_variable(&fCondition);
#endif #endif
} }
@ -47,7 +81,8 @@ void SkCondVar::wait() {
#ifdef SK_USE_POSIX_THREADS #ifdef SK_USE_POSIX_THREADS
pthread_cond_wait(&fCond, &fMutex); pthread_cond_wait(&fCond, &fMutex);
#elif defined(SK_BUILD_FOR_WIN32) #elif defined(SK_BUILD_FOR_WIN32)
SleepConditionVariableCS(&fCondition, &fCriticalSection, INFINITE); SkASSERT(sleep_condition_variable);
sleep_condition_variable(&fCondition, &fCriticalSection, INFINITE);
#endif #endif
} }
@ -55,7 +90,8 @@ void SkCondVar::signal() {
#ifdef SK_USE_POSIX_THREADS #ifdef SK_USE_POSIX_THREADS
pthread_cond_signal(&fCond); pthread_cond_signal(&fCond);
#elif defined(SK_BUILD_FOR_WIN32) #elif defined(SK_BUILD_FOR_WIN32)
WakeConditionVariable(&fCondition); SkASSERT(wake_condition_variable);
wake_condition_variable(&fCondition);
#endif #endif
} }
@ -63,6 +99,7 @@ void SkCondVar::broadcast() {
#ifdef SK_USE_POSIX_THREADS #ifdef SK_USE_POSIX_THREADS
pthread_cond_broadcast(&fCond); pthread_cond_broadcast(&fCond);
#elif defined(SK_BUILD_FOR_WIN32) #elif defined(SK_BUILD_FOR_WIN32)
WakeAllConditionVariable(&fCondition); SkASSERT(wake_all_condition_variable);
wake_all_condition_variable(&fCondition);
#endif #endif
} }

View File

@ -8,9 +8,6 @@
#ifndef SkCondVar_DEFINED #ifndef SkCondVar_DEFINED
#define SkCondVar_DEFINED #define SkCondVar_DEFINED
/**
* Import any thread model setting from configuration files.
*/
#include "SkTypes.h" #include "SkTypes.h"
#ifdef SK_USE_POSIX_THREADS #ifdef SK_USE_POSIX_THREADS
@ -18,21 +15,22 @@
#elif defined(SK_BUILD_FOR_WIN32) #elif defined(SK_BUILD_FOR_WIN32)
#include <windows.h> #include <windows.h>
#else #else
/** #error "SkCondVar requires pthreads or Windows."
* Warn if the implementation of this class is empty, i.e. thread safety is not working.
*/
#warning "Thread safety class SkCondVar has no implementation!"
#endif #endif
/** /**
* Condition variable for blocking access to shared data from other threads and * Condition variable for blocking access to shared data from other threads and
* controlling which threads are awake. * controlling which threads are awake.
* *
* Currently only supported on platforms with posix threads and Windows Vista and * Currently only supported on platforms with posix threads and Windows Vista and above.
* above.
*/ */
class SkCondVar { class SkCondVar {
public: public:
/** Returns true if it makes sense to create and use SkCondVars.
* You _MUST_ call this method and it must return true before creating any SkCondVars.
*/
static bool Supported();
SkCondVar(); SkCondVar();
~SkCondVar(); ~SkCondVar();