remove SkThread, using std::thread instead
Change-Id: I871dd5eea4496e87c206b46d9eae81cb521b11ce Reviewed-on: https://skia-review.googlesource.com/65103 Reviewed-by: Hal Canary <halcanary@google.com> Commit-Queue: Mike Klein <mtklein@chromium.org>
This commit is contained in:
parent
cc309eb9b1
commit
03141d25cf
2
BUILD.gn
2
BUILD.gn
@ -798,8 +798,6 @@ component("skia") {
|
||||
} else {
|
||||
sources += [ "src/ports/SkFontMgr_win_dw_factory.cpp" ]
|
||||
}
|
||||
sources -=
|
||||
[ get_path_info("src/utils/SkThreadUtils_pthread.cpp", "abspath") ]
|
||||
libs += [
|
||||
"FontSub.lib",
|
||||
"Ole32.lib",
|
||||
|
@ -45,13 +45,13 @@
|
||||
#include "SkString.h"
|
||||
#include "SkSurface.h"
|
||||
#include "SkTaskGroup.h"
|
||||
#include "SkThreadUtils.h"
|
||||
#include "SkTraceEvent.h"
|
||||
#include "Stats.h"
|
||||
#include "ThermalManager.h"
|
||||
#include "ios_utils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <thread>
|
||||
|
||||
extern bool gSkForceRasterPipelineBlitter;
|
||||
|
||||
@ -1109,21 +1109,18 @@ private:
|
||||
// Some runs (mostly, Valgrind) are so slow that the bot framework thinks we've hung.
|
||||
// This prints something every once in a while so that it knows we're still working.
|
||||
static void start_keepalive() {
|
||||
struct Loop {
|
||||
static void forever(void*) {
|
||||
for (;;) {
|
||||
static const int kSec = 1200;
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
Sleep(kSec * 1000);
|
||||
#else
|
||||
sleep(kSec);
|
||||
#endif
|
||||
SkDebugf("\nBenchmarks still running...\n");
|
||||
}
|
||||
static std::thread* intentionallyLeaked = new std::thread([]{
|
||||
for (;;) {
|
||||
static const int kSec = 1200;
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
Sleep(kSec * 1000);
|
||||
#else
|
||||
sleep(kSec);
|
||||
#endif
|
||||
SkDebugf("\nBenchmarks still running...\n");
|
||||
}
|
||||
};
|
||||
static SkThread* intentionallyLeaked = new SkThread(Loop::forever);
|
||||
intentionallyLeaked->start();
|
||||
});
|
||||
(void)intentionallyLeaked;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "SkSpinlock.h"
|
||||
#include "SkTHash.h"
|
||||
#include "SkTaskGroup.h"
|
||||
#include "SkThreadUtils.h"
|
||||
#include "Test.h"
|
||||
#include "Timer.h"
|
||||
#include "ios_utils.h"
|
||||
|
@ -62,11 +62,8 @@ skia_utils_sources = [
|
||||
"$_src/utils/SkShadowTessellator.h",
|
||||
"$_src/utils/SkShadowUtils.cpp",
|
||||
"$_src/utils/SkTextBox.cpp",
|
||||
"$_src/utils/SkThreadUtils.h",
|
||||
"$_src/utils/SkThreadUtils_pthread.cpp",
|
||||
"$_src/utils/SkThreadUtils_pthread.h",
|
||||
"$_src/utils/SkThreadUtils_win.cpp",
|
||||
"$_src/utils/SkThreadUtils_win.h",
|
||||
"$_src/utils/SkWhitelistTypefaces.cpp",
|
||||
|
||||
#mac
|
||||
|
@ -225,7 +225,6 @@ BASE_SRCS_ALL = struct(
|
||||
"src/ports/**/*",
|
||||
"src/utils/android/**/*",
|
||||
"src/utils/mac/**/*",
|
||||
"src/utils/SkThreadUtils_win.cpp", # Windows-only. Move to ports?
|
||||
"src/utils/win/**/*",
|
||||
"src/views/sdl/*",
|
||||
"src/views/win/*",
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include "SkSemaphore.h"
|
||||
#include "SkSpinlock.h"
|
||||
#include "SkTArray.h"
|
||||
#include "SkThreadUtils.h"
|
||||
#include <deque>
|
||||
#include <thread>
|
||||
|
||||
#if defined(SK_BUILD_FOR_WIN32)
|
||||
#include <windows.h>
|
||||
@ -65,8 +65,7 @@ class SkThreadPool final : public SkExecutor {
|
||||
public:
|
||||
explicit SkThreadPool(int threads) {
|
||||
for (int i = 0; i < threads; i++) {
|
||||
fThreads.emplace_back(new SkThread(&Loop, this));
|
||||
fThreads.back()->start();
|
||||
fThreads.emplace_back(&Loop, this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +76,7 @@ public:
|
||||
}
|
||||
// Wait for each thread to shut down.
|
||||
for (int i = 0; i < fThreads.count(); i++) {
|
||||
fThreads[i]->join();
|
||||
fThreads[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,10 +125,10 @@ private:
|
||||
// Both SkMutex and SkSpinlock can work here.
|
||||
using Lock = SkMutex;
|
||||
|
||||
SkTArray<std::unique_ptr<SkThread>> fThreads;
|
||||
WorkList fWork;
|
||||
Lock fWorkLock;
|
||||
SkSemaphore fWorkAvailable;
|
||||
SkTArray<std::thread> fThreads;
|
||||
WorkList fWork;
|
||||
Lock fWorkLock;
|
||||
SkSemaphore fWorkAvailable;
|
||||
};
|
||||
|
||||
std::unique_ptr<SkExecutor> SkExecutor::MakeFIFOThreadPool(int threads) {
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkThreadUtils_DEFINED
|
||||
#define SkThreadUtils_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
class SkThread : SkNoncopyable {
|
||||
public:
|
||||
typedef void (*entryPointProc)(void*);
|
||||
|
||||
SkThread(entryPointProc entryPoint, void* data = nullptr);
|
||||
|
||||
/**
|
||||
* Non-virtual, do not subclass.
|
||||
*/
|
||||
~SkThread();
|
||||
|
||||
/**
|
||||
* Starts the thread. Returns false if the thread could not be started.
|
||||
*/
|
||||
bool start();
|
||||
|
||||
/**
|
||||
* Waits for the thread to finish.
|
||||
* If the thread has not started, returns immediately.
|
||||
*/
|
||||
void join();
|
||||
|
||||
private:
|
||||
void* fData;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,117 +1,11 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
* Copyright 2017 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_pthread.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
PThreadEvent::PThreadEvent() : fConditionFlag(false) {
|
||||
pthread_cond_init(&fCondition, nullptr);
|
||||
pthread_mutex_init(&fConditionMutex, nullptr);
|
||||
}
|
||||
PThreadEvent::~PThreadEvent() {
|
||||
pthread_mutex_destroy(&fConditionMutex);
|
||||
pthread_cond_destroy(&fCondition);
|
||||
}
|
||||
void PThreadEvent::trigger() {
|
||||
pthread_mutex_lock(&fConditionMutex);
|
||||
fConditionFlag = true;
|
||||
pthread_cond_signal(&fCondition);
|
||||
pthread_mutex_unlock(&fConditionMutex);
|
||||
}
|
||||
void PThreadEvent::wait() {
|
||||
pthread_mutex_lock(&fConditionMutex);
|
||||
while (!fConditionFlag) {
|
||||
pthread_cond_wait(&fCondition, &fConditionMutex);
|
||||
}
|
||||
pthread_mutex_unlock(&fConditionMutex);
|
||||
}
|
||||
bool PThreadEvent::isTriggered() {
|
||||
bool currentFlag;
|
||||
pthread_mutex_lock(&fConditionMutex);
|
||||
currentFlag = fConditionFlag;
|
||||
pthread_mutex_unlock(&fConditionMutex);
|
||||
return currentFlag;
|
||||
}
|
||||
|
||||
SkThread_PThreadData::SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data)
|
||||
: fPThread()
|
||||
, fValidPThread(false)
|
||||
, fParam(data)
|
||||
, fEntryPoint(entryPoint)
|
||||
{
|
||||
pthread_attr_init(&fAttr);
|
||||
pthread_attr_setdetachstate(&fAttr, PTHREAD_CREATE_JOINABLE);
|
||||
}
|
||||
|
||||
SkThread_PThreadData::~SkThread_PThreadData() {
|
||||
pthread_attr_destroy(&fAttr);
|
||||
}
|
||||
|
||||
static void* thread_start(void* arg) {
|
||||
SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(arg);
|
||||
// Wait for start signal
|
||||
pthreadData->fStarted.wait();
|
||||
|
||||
// Call entry point only if thread was not canceled before starting.
|
||||
if (!pthreadData->fCanceled.isTriggered()) {
|
||||
pthreadData->fEntryPoint(pthreadData->fParam);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkThread::SkThread(entryPointProc entryPoint, void* data) {
|
||||
SkThread_PThreadData* pthreadData = new SkThread_PThreadData(entryPoint, data);
|
||||
fData = pthreadData;
|
||||
|
||||
int ret = pthread_create(&(pthreadData->fPThread),
|
||||
&(pthreadData->fAttr),
|
||||
thread_start,
|
||||
pthreadData);
|
||||
|
||||
pthreadData->fValidPThread = (0 == ret);
|
||||
}
|
||||
|
||||
SkThread::~SkThread() {
|
||||
if (fData != nullptr) {
|
||||
SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
|
||||
// If created thread but start was never called, kill the thread.
|
||||
if (pthreadData->fValidPThread && !pthreadData->fStarted.isTriggered()) {
|
||||
pthreadData->fCanceled.trigger();
|
||||
if (this->start()) {
|
||||
this->join();
|
||||
}
|
||||
}
|
||||
delete pthreadData;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkThread::start() {
|
||||
SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
|
||||
if (!pthreadData->fValidPThread) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pthreadData->fStarted.isTriggered()) {
|
||||
return false;
|
||||
}
|
||||
pthreadData->fStarted.trigger();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkThread::join() {
|
||||
SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData);
|
||||
if (!pthreadData->fValidPThread || !pthreadData->fStarted.isTriggered()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_join(pthreadData->fPThread, nullptr);
|
||||
}
|
||||
// Nothing to see here.
|
||||
//
|
||||
// We just need to keep this file around until we do the song and dance
|
||||
// to stop explicitly removing it from Chromium's GN build.
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkThreadUtils_PThreadData_DEFINED
|
||||
#define SkThreadUtils_PThreadData_DEFINED
|
||||
|
||||
#include "SkThreadUtils.h"
|
||||
#include <pthread.h>
|
||||
|
||||
class PThreadEvent : SkNoncopyable {
|
||||
public:
|
||||
PThreadEvent();
|
||||
~PThreadEvent();
|
||||
void trigger();
|
||||
void wait();
|
||||
bool isTriggered();
|
||||
|
||||
private:
|
||||
pthread_cond_t fCondition;
|
||||
pthread_mutex_t fConditionMutex;
|
||||
bool fConditionFlag;
|
||||
};
|
||||
|
||||
class SkThread_PThreadData : SkNoncopyable {
|
||||
public:
|
||||
SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data);
|
||||
~SkThread_PThreadData();
|
||||
pthread_t fPThread;
|
||||
bool fValidPThread;
|
||||
PThreadEvent fStarted;
|
||||
PThreadEvent fCanceled;
|
||||
|
||||
pthread_attr_t fAttr;
|
||||
|
||||
void* fParam;
|
||||
SkThread::entryPointProc fEntryPoint;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,101 +1,11 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
* Copyright 2017 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"
|
||||
#if defined(SK_BUILD_FOR_WIN32)
|
||||
|
||||
#include "SkThreadUtils.h"
|
||||
#include "SkThreadUtils_win.h"
|
||||
|
||||
SkThread_WinData::SkThread_WinData(SkThread::entryPointProc entryPoint, void* data)
|
||||
: fHandle(nullptr)
|
||||
, fParam(data)
|
||||
, fThreadId(0)
|
||||
, fEntryPoint(entryPoint)
|
||||
, fStarted(false)
|
||||
{
|
||||
fCancelEvent = CreateEvent(
|
||||
nullptr, // default security attributes
|
||||
false, //auto reset
|
||||
false, //not signaled
|
||||
nullptr); //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 (nullptr == winData->fCancelEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
winData->fHandle = CreateThread(
|
||||
nullptr, // default security attributes
|
||||
0, // use default stack size
|
||||
thread_start, // thread function name (proxy)
|
||||
winData, // argument to thread function (proxy args)
|
||||
CREATE_SUSPENDED, // we used to set processor affinity, which needed this
|
||||
&winData->fThreadId); // returns the thread identifier
|
||||
}
|
||||
|
||||
SkThread::~SkThread() {
|
||||
if (fData != nullptr) {
|
||||
SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData);
|
||||
// If created thread but start was never called, kill the thread.
|
||||
if (winData->fHandle != nullptr && !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 (nullptr == 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 (nullptr == winData->fHandle || !winData->fStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
WaitForSingleObject(winData->fHandle, INFINITE);
|
||||
}
|
||||
|
||||
#endif//defined(SK_BUILD_FOR_WIN32)
|
||||
// Nothing to see here.
|
||||
//
|
||||
// We just need to keep this file around until we do the song and dance
|
||||
// to stop explicitly removing it from Chromium's GN build.
|
||||
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkThreadUtils_WinData_DEFINED
|
||||
#define SkThreadUtils_WinData_DEFINED
|
||||
|
||||
#include "SkLeanWindows.h"
|
||||
#include "SkThreadUtils.h"
|
||||
|
||||
class SkThread_WinData : SkNoncopyable {
|
||||
public:
|
||||
SkThread_WinData(SkThread::entryPointProc entryPoint, void* data);
|
||||
~SkThread_WinData();
|
||||
HANDLE fHandle;
|
||||
HANDLE fCancelEvent;
|
||||
|
||||
LPVOID fParam;
|
||||
DWORD fThreadId;
|
||||
SkThread::entryPointProc fEntryPoint;
|
||||
bool fStarted;
|
||||
};
|
||||
|
||||
#endif
|
@ -6,10 +6,10 @@
|
||||
*/
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkThreadUtils.h"
|
||||
#include "SkTypes.h"
|
||||
#include "SkWeakRefCnt.h"
|
||||
#include "Test.h"
|
||||
#include <thread>
|
||||
|
||||
static void bounce_ref(void* data) {
|
||||
SkRefCnt* ref = static_cast<SkRefCnt*>(data);
|
||||
@ -22,11 +22,8 @@ static void bounce_ref(void* data) {
|
||||
static void test_refCnt(skiatest::Reporter* reporter) {
|
||||
SkRefCnt* ref = new SkRefCnt();
|
||||
|
||||
SkThread thing1(bounce_ref, ref);
|
||||
SkThread thing2(bounce_ref, ref);
|
||||
|
||||
SkAssertResult(thing1.start());
|
||||
SkAssertResult(thing2.start());
|
||||
std::thread thing1(bounce_ref, ref);
|
||||
std::thread thing2(bounce_ref, ref);
|
||||
|
||||
thing1.join();
|
||||
thing2.join();
|
||||
@ -55,15 +52,10 @@ static void bounce_weak_weak_ref(void* data) {
|
||||
static void test_weakRefCnt(skiatest::Reporter* reporter) {
|
||||
SkWeakRefCnt* ref = new SkWeakRefCnt();
|
||||
|
||||
SkThread thing1(bounce_ref, ref);
|
||||
SkThread thing2(bounce_ref, ref);
|
||||
SkThread thing3(bounce_weak_ref, ref);
|
||||
SkThread thing4(bounce_weak_weak_ref, ref);
|
||||
|
||||
SkAssertResult(thing1.start());
|
||||
SkAssertResult(thing2.start());
|
||||
SkAssertResult(thing3.start());
|
||||
SkAssertResult(thing4.start());
|
||||
std::thread thing1(bounce_ref, ref);
|
||||
std::thread thing2(bounce_ref, ref);
|
||||
std::thread thing3(bounce_weak_ref, ref);
|
||||
std::thread thing4(bounce_weak_weak_ref, ref);
|
||||
|
||||
thing1.join();
|
||||
thing2.join();
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "SkString.h"
|
||||
#include "SkThreadUtils.h"
|
||||
#include "Test.h"
|
||||
#include <thread>
|
||||
|
||||
// Windows vsnprintf doesn't 0-terminate safely), but is so far
|
||||
// encapsulated in SkString that we can't test it directly.
|
||||
@ -291,23 +291,16 @@ DEF_TEST(String_SkStrSplit_All, r) {
|
||||
|
||||
// https://bugs.chromium.org/p/skia/issues/detail?id=7107
|
||||
DEF_TEST(String_Threaded, r) {
|
||||
SkString gString("foo");
|
||||
SkThread::entryPointProc readString = [](void* context) -> void {
|
||||
SkString gStringCopy = *reinterpret_cast<SkString*>(context);
|
||||
bool equals_string = gStringCopy.equals("test");
|
||||
(void)equals_string;
|
||||
};
|
||||
SkThread threads[] = {
|
||||
{readString, &gString},
|
||||
{readString, &gString},
|
||||
{readString, &gString},
|
||||
{readString, &gString},
|
||||
{readString, &gString},
|
||||
};
|
||||
for (SkThread& thread : threads) {
|
||||
thread.start();
|
||||
SkString str("foo");
|
||||
|
||||
std::thread threads[5];
|
||||
for (auto& thread : threads) {
|
||||
thread = std::thread([&] {
|
||||
SkString copy = str;
|
||||
(void)copy.equals("test");
|
||||
});
|
||||
}
|
||||
for (SkThread& thread : threads) {
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,14 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkAtomics.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkTLS.h"
|
||||
#include "SkThreadUtils.h"
|
||||
#include "Test.h"
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
static void thread_main(void*) {
|
||||
static void thread_main() {
|
||||
SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
|
||||
|
||||
const char text[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
@ -31,41 +31,26 @@ static void thread_main(void*) {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_threads(SkThread::entryPointProc proc) {
|
||||
SkThread* threads[8];
|
||||
int N = SK_ARRAY_COUNT(threads);
|
||||
int i;
|
||||
template <typename Fn>
|
||||
static void test_threads(Fn fn) {
|
||||
std::thread threads[8];
|
||||
|
||||
for (i = 0; i < N; ++i) {
|
||||
threads[i] = new SkThread(proc);
|
||||
for (auto& thread : threads) {
|
||||
thread = std::thread(fn);
|
||||
}
|
||||
|
||||
for (i = 0; i < N; ++i) {
|
||||
threads[i]->start();
|
||||
}
|
||||
|
||||
for (i = 0; i < N; ++i) {
|
||||
threads[i]->join();
|
||||
}
|
||||
|
||||
for (i = 0; i < N; ++i) {
|
||||
delete threads[i];
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t gCounter;
|
||||
static std::atomic<int> gCounter{0};
|
||||
|
||||
static void* FakeCreateTLS() {
|
||||
sk_atomic_inc(&gCounter);
|
||||
static void* fake_create_TLS() {
|
||||
gCounter++;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void FakeDeleteTLS(void*) {
|
||||
sk_atomic_dec(&gCounter);
|
||||
}
|
||||
|
||||
static void testTLSDestructor(void*) {
|
||||
SkTLS::Get(FakeCreateTLS, FakeDeleteTLS);
|
||||
static void fake_delete_TLS(void*) {
|
||||
gCounter--;
|
||||
}
|
||||
|
||||
DEF_TEST(TLS, reporter) {
|
||||
@ -76,6 +61,8 @@ DEF_TEST(TLS, reporter) {
|
||||
|
||||
// Test to ensure that at thread destruction, TLS destructors
|
||||
// have been called.
|
||||
test_threads(&testTLSDestructor);
|
||||
REPORTER_ASSERT(reporter, 0 == gCounter);
|
||||
test_threads([] {
|
||||
SkTLS::Get(fake_create_TLS, fake_delete_TLS);
|
||||
});
|
||||
REPORTER_ASSERT(reporter, 0 == gCounter.load());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user