Add bench and test for SkRefCnt.
http://codereview.appspot.com/6195071/
This also adds a cross platform SkThread for testing purposes.
git-svn-id: http://skia.googlecode.com/svn/trunk@3921 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/utils/SkThreadUtils_win.cpp b/src/utils/SkThreadUtils_win.cpp
new file mode 100644
index 0000000..208ffde
--- /dev/null
+++ b/src/utils/SkThreadUtils_win.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+
+#include "SkThreadUtils.h"
+#include "SkThreadUtils_win.h"
+
+SkThread_WinData::SkThread_WinData(SkThread::entryPointProc entryPoint, void* data)
+ : fHandle(NULL)
+ , fParam(data)
+ , fThreadId(0)
+ , fEntryPoint(entryPoint)
+ , fStarted(false)
+{
+ fCancelEvent = CreateEvent(
+ NULL, // default security attributes
+ false, //auto reset
+ false, //not signaled
+ NULL); //no name
+}
+
+SkThread_WinData::~SkThread_WinData() {
+ CloseHandle(fCancelEvent);
+}
+
+static DWORD WINAPI thread_start(LPVOID data) {
+ SkThread_WinData* winData = static_cast<SkThread_WinData*>(data);
+
+ //See if this thread was canceled before starting.
+ if (WaitForSingleObject(winData->fCancelEvent, 0) == WAIT_OBJECT_0) {
+ return 0;
+ }
+
+ winData->fEntryPoint(winData->fParam);
+ return 0;
+}
+
+SkThread::SkThread(entryPointProc entryPoint, void* data) {
+ SkThread_WinData* winData = new SkThread_WinData(entryPoint, data);
+ fData = winData;
+
+ if (NULL == winData->fCancelEvent) {
+ return;
+ }
+
+ winData->fHandle = CreateThread(
+ NULL, // default security attributes
+ 0, // use default stack size
+ thread_start, // thread function name (proxy)
+ winData, // argument to thread function (proxy args)
+ CREATE_SUSPENDED, // create suspended so affinity can be set
+ &winData->fThreadId); // returns the thread identifier
+}
+
+SkThread::~SkThread() {
+ if (fData != NULL) {
+ SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
+ // If created thread but start was never called, kill the thread.
+ if (winData->fHandle != NULL && !winData->fStarted) {
+ if (SetEvent(winData->fCancelEvent) != 0) {
+ if (this->start()) {
+ this->join();
+ }
+ } else {
+ //kill with prejudice
+ TerminateThread(winData->fHandle, -1);
+ }
+ }
+ delete winData;
+ }
+}
+
+bool SkThread::start() {
+ SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
+ if (NULL == winData->fHandle) {
+ return false;
+ }
+
+ if (winData->fStarted) {
+ return false;
+ }
+ winData->fStarted = -1 != ResumeThread(winData->fHandle);
+ return winData->fStarted;
+}
+
+void SkThread::join() {
+ SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
+ if (NULL == winData->fHandle || !winData->fStarted) {
+ return;
+ }
+
+ WaitForSingleObject(winData->fHandle, INFINITE);
+}
+
+static unsigned int num_bits_set(DWORD_PTR mask) {
+ unsigned int count;
+ for (count = 0; mask; ++count) {
+ mask &= mask - 1;
+ }
+ return count;
+}
+
+static unsigned int nth_set_bit(unsigned int n, DWORD_PTR mask) {
+ n %= num_bits_set(mask);
+ for (unsigned int setBitsSeen = 0, currentBit = 0; true; ++currentBit) {
+ if (mask & (1 << currentBit)) {
+ ++setBitsSeen;
+ if (setBitsSeen > n) {
+ return currentBit;
+ }
+ }
+ }
+}
+
+bool SkThread::setProcessorAffinity(unsigned int processor) {
+ SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
+ if (NULL == winData->fHandle) {
+ return false;
+ }
+
+ DWORD_PTR processAffinityMask;
+ DWORD_PTR systemAffinityMask;
+ if (0 == GetProcessAffinityMask(GetCurrentProcess(),
+ &processAffinityMask,
+ &systemAffinityMask)) {
+ return false;
+ }
+
+ DWORD_PTR threadAffinityMask = 1 << nth_set_bit(processor, processAffinityMask);
+ return 0 != SetThreadAffinityMask(winData->fHandle, threadAffinityMask);
+}