You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
3.8 KiB
165 lines
3.8 KiB
// Copyright (c) 2012 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.
|
|
|
|
#include "base/logging.h"
|
|
#include "base/threading/simple_thread.h"
|
|
#include "base/threading/thread_local.h"
|
|
#include "base/synchronization/waitable_event.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace base {
|
|
|
|
namespace {
|
|
|
|
class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
|
|
public:
|
|
typedef base::ThreadLocalPointer<char> TLPType;
|
|
|
|
ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
|
|
: tlp_(tlp),
|
|
done_(done) {
|
|
}
|
|
~ThreadLocalTesterBase() override = default;
|
|
|
|
protected:
|
|
TLPType* tlp_;
|
|
base::WaitableEvent* done_;
|
|
};
|
|
|
|
class SetThreadLocal : public ThreadLocalTesterBase {
|
|
public:
|
|
SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
|
|
: ThreadLocalTesterBase(tlp, done), val_(nullptr) {}
|
|
~SetThreadLocal() override = default;
|
|
|
|
void set_value(char* val) { val_ = val; }
|
|
|
|
void Run() override {
|
|
DCHECK(!done_->IsSignaled());
|
|
tlp_->Set(val_);
|
|
done_->Signal();
|
|
}
|
|
|
|
private:
|
|
char* val_;
|
|
};
|
|
|
|
class GetThreadLocal : public ThreadLocalTesterBase {
|
|
public:
|
|
GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
|
|
: ThreadLocalTesterBase(tlp, done), ptr_(nullptr) {}
|
|
~GetThreadLocal() override = default;
|
|
|
|
void set_ptr(char** ptr) { ptr_ = ptr; }
|
|
|
|
void Run() override {
|
|
DCHECK(!done_->IsSignaled());
|
|
*ptr_ = tlp_->Get();
|
|
done_->Signal();
|
|
}
|
|
|
|
private:
|
|
char** ptr_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
// In this test, we start 2 threads which will access a ThreadLocalPointer. We
|
|
// make sure the default is NULL, and the pointers are unique to the threads.
|
|
TEST(ThreadLocalTest, Pointer) {
|
|
base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1);
|
|
base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1);
|
|
tp1.Start();
|
|
tp2.Start();
|
|
|
|
base::ThreadLocalPointer<char> tlp;
|
|
|
|
static char* const kBogusPointer = reinterpret_cast<char*>(0x1234);
|
|
|
|
char* tls_val;
|
|
base::WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
|
|
WaitableEvent::InitialState::NOT_SIGNALED);
|
|
|
|
GetThreadLocal getter(&tlp, &done);
|
|
getter.set_ptr(&tls_val);
|
|
|
|
// Check that both threads defaulted to NULL.
|
|
tls_val = kBogusPointer;
|
|
done.Reset();
|
|
tp1.AddWork(&getter);
|
|
done.Wait();
|
|
EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
|
|
|
|
tls_val = kBogusPointer;
|
|
done.Reset();
|
|
tp2.AddWork(&getter);
|
|
done.Wait();
|
|
EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
|
|
|
|
SetThreadLocal setter(&tlp, &done);
|
|
setter.set_value(kBogusPointer);
|
|
|
|
// Have thread 1 set their pointer value to kBogusPointer.
|
|
done.Reset();
|
|
tp1.AddWork(&setter);
|
|
done.Wait();
|
|
|
|
tls_val = nullptr;
|
|
done.Reset();
|
|
tp1.AddWork(&getter);
|
|
done.Wait();
|
|
EXPECT_EQ(kBogusPointer, tls_val);
|
|
|
|
// Make sure thread 2 is still NULL
|
|
tls_val = kBogusPointer;
|
|
done.Reset();
|
|
tp2.AddWork(&getter);
|
|
done.Wait();
|
|
EXPECT_EQ(static_cast<char*>(nullptr), tls_val);
|
|
|
|
// Set thread 2 to kBogusPointer + 1.
|
|
setter.set_value(kBogusPointer + 1);
|
|
|
|
done.Reset();
|
|
tp2.AddWork(&setter);
|
|
done.Wait();
|
|
|
|
tls_val = nullptr;
|
|
done.Reset();
|
|
tp2.AddWork(&getter);
|
|
done.Wait();
|
|
EXPECT_EQ(kBogusPointer + 1, tls_val);
|
|
|
|
// Make sure thread 1 is still kBogusPointer.
|
|
tls_val = nullptr;
|
|
done.Reset();
|
|
tp1.AddWork(&getter);
|
|
done.Wait();
|
|
EXPECT_EQ(kBogusPointer, tls_val);
|
|
|
|
tp1.JoinAll();
|
|
tp2.JoinAll();
|
|
}
|
|
|
|
TEST(ThreadLocalTest, Boolean) {
|
|
{
|
|
base::ThreadLocalBoolean tlb;
|
|
EXPECT_FALSE(tlb.Get());
|
|
|
|
tlb.Set(false);
|
|
EXPECT_FALSE(tlb.Get());
|
|
|
|
tlb.Set(true);
|
|
EXPECT_TRUE(tlb.Get());
|
|
}
|
|
|
|
// Our slot should have been freed, we're all reset.
|
|
{
|
|
base::ThreadLocalBoolean tlb;
|
|
EXPECT_FALSE(tlb.Get());
|
|
}
|
|
}
|
|
|
|
} // namespace base
|