merge(3p/glog): Vendor glog from commit 'afe04691'
This commit is contained in:
commit
6941048b7e
133 changed files with 23455 additions and 0 deletions
611
third_party/glog/src/googletest.h
vendored
Normal file
611
third_party/glog/src/googletest.h
vendored
Normal file
|
|
@ -0,0 +1,611 @@
|
|||
// Copyright (c) 2009, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: Shinichiro Hamaji
|
||||
// (based on googletest: http://code.google.com/p/googletest/)
|
||||
|
||||
#ifdef GOOGLETEST_H__
|
||||
#error You must not include this file twice.
|
||||
#endif
|
||||
#define GOOGLETEST_H__
|
||||
|
||||
#include "utilities.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
extern GOOGLE_GLOG_DLL_DECL void (*g_logging_fail_func)();
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#undef GOOGLE_GLOG_DLL_DECL
|
||||
#define GOOGLE_GLOG_DLL_DECL
|
||||
|
||||
static inline string GetTempDir() {
|
||||
#ifndef OS_WINDOWS
|
||||
return "/tmp";
|
||||
#else
|
||||
char tmp[MAX_PATH];
|
||||
GetTempPathA(MAX_PATH, tmp);
|
||||
return tmp;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS) && defined(_MSC_VER) && !defined(TEST_SRC_DIR)
|
||||
// The test will run in glog/vsproject/<project name>
|
||||
// (e.g., glog/vsproject/logging_unittest).
|
||||
static const char TEST_SRC_DIR[] = "../..";
|
||||
#elif !defined(TEST_SRC_DIR)
|
||||
# warning TEST_SRC_DIR should be defined in config.h
|
||||
static const char TEST_SRC_DIR[] = ".";
|
||||
#endif
|
||||
|
||||
static const uint32_t PTR_TEST_VALUE = 0x12345678;
|
||||
|
||||
DEFINE_string(test_tmpdir, GetTempDir(), "Dir we use for temp files");
|
||||
DEFINE_string(test_srcdir, TEST_SRC_DIR,
|
||||
"Source-dir root, needed to find glog_unittest_flagfile");
|
||||
DEFINE_bool(run_benchmark, false, "If true, run benchmarks");
|
||||
#ifdef NDEBUG
|
||||
DEFINE_int32(benchmark_iters, 100000000, "Number of iterations per benchmark");
|
||||
#else
|
||||
DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIB_GTEST
|
||||
# include <gtest/gtest.h>
|
||||
// Use our ASSERT_DEATH implementation.
|
||||
# undef ASSERT_DEATH
|
||||
# undef ASSERT_DEBUG_DEATH
|
||||
using testing::InitGoogleTest;
|
||||
#else
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
void InitGoogleTest(int*, char**);
|
||||
|
||||
void InitGoogleTest(int*, char**) {}
|
||||
|
||||
// The following is some bare-bones testing infrastructure
|
||||
|
||||
#define EXPECT_TRUE(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "Check failed: %s\n", #cond); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
|
||||
|
||||
#define EXPECT_OP(op, val1, val2) \
|
||||
do { \
|
||||
if (!((val1) op (val2))) { \
|
||||
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
|
||||
#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
|
||||
#define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
|
||||
#define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
|
||||
|
||||
#define EXPECT_NAN(arg) \
|
||||
do { \
|
||||
if (!isnan(arg)) { \
|
||||
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_INF(arg) \
|
||||
do { \
|
||||
if (!isinf(arg)) { \
|
||||
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_DOUBLE_EQ(val1, val2) \
|
||||
do { \
|
||||
if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
|
||||
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_STREQ(val1, val2) \
|
||||
do { \
|
||||
if (strcmp((val1), (val2)) != 0) { \
|
||||
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
vector<void (*)()> g_testlist; // the tests to run
|
||||
|
||||
#define TEST(a, b) \
|
||||
struct Test_##a##_##b { \
|
||||
Test_##a##_##b() { g_testlist.push_back(&Run); } \
|
||||
static void Run() { FlagSaver fs; RunTest(); } \
|
||||
static void RunTest(); \
|
||||
}; \
|
||||
static Test_##a##_##b g_test_##a##_##b; \
|
||||
void Test_##a##_##b::RunTest()
|
||||
|
||||
|
||||
static inline int RUN_ALL_TESTS() {
|
||||
vector<void (*)()>::const_iterator it;
|
||||
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
|
||||
(*it)();
|
||||
}
|
||||
fprintf(stderr, "Passed %d tests\n\nPASS\n", (int)g_testlist.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif // ! HAVE_LIB_GTEST
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
static bool g_called_abort;
|
||||
static jmp_buf g_jmp_buf;
|
||||
static inline void CalledAbort() {
|
||||
g_called_abort = true;
|
||||
longjmp(g_jmp_buf, 1);
|
||||
}
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
// TODO(hamaji): Death test somehow doesn't work in Windows.
|
||||
#define ASSERT_DEATH(fn, msg)
|
||||
#else
|
||||
#define ASSERT_DEATH(fn, msg) \
|
||||
do { \
|
||||
g_called_abort = false; \
|
||||
/* in logging.cc */ \
|
||||
void (*original_logging_fail_func)() = g_logging_fail_func; \
|
||||
g_logging_fail_func = &CalledAbort; \
|
||||
if (!setjmp(g_jmp_buf)) fn; \
|
||||
/* set back to their default */ \
|
||||
g_logging_fail_func = original_logging_fail_func; \
|
||||
if (!g_called_abort) { \
|
||||
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ASSERT_DEBUG_DEATH(fn, msg)
|
||||
#else
|
||||
#define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
|
||||
#endif // NDEBUG
|
||||
|
||||
// Benchmark tools.
|
||||
|
||||
#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n);
|
||||
|
||||
map<string, void (*)(int)> g_benchlist; // the benchmarks to run
|
||||
|
||||
class BenchmarkRegisterer {
|
||||
public:
|
||||
BenchmarkRegisterer(const char* name, void (*function)(int iters)) {
|
||||
EXPECT_TRUE(g_benchlist.insert(std::make_pair(name, function)).second);
|
||||
}
|
||||
};
|
||||
|
||||
static inline void RunSpecifiedBenchmarks() {
|
||||
if (!FLAGS_run_benchmark) {
|
||||
return;
|
||||
}
|
||||
|
||||
int iter_cnt = FLAGS_benchmark_iters;
|
||||
puts("Benchmark\tTime(ns)\tIterations");
|
||||
for (map<string, void (*)(int)>::const_iterator iter = g_benchlist.begin();
|
||||
iter != g_benchlist.end();
|
||||
++iter) {
|
||||
clock_t start = clock();
|
||||
iter->second(iter_cnt);
|
||||
double elapsed_ns =
|
||||
((double)clock() - start) / CLOCKS_PER_SEC * 1000*1000*1000;
|
||||
printf("%s\t%8.2lf\t%10d\n",
|
||||
iter->first.c_str(), elapsed_ns / iter_cnt, iter_cnt);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Golden file functions
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
class CapturedStream {
|
||||
public:
|
||||
CapturedStream(int fd, const string & filename) :
|
||||
fd_(fd),
|
||||
uncaptured_fd_(-1),
|
||||
filename_(filename) {
|
||||
Capture();
|
||||
}
|
||||
|
||||
~CapturedStream() {
|
||||
if (uncaptured_fd_ != -1) {
|
||||
CHECK(close(uncaptured_fd_) != -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Start redirecting output to a file
|
||||
void Capture() {
|
||||
// Keep original stream for later
|
||||
CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
|
||||
uncaptured_fd_ = dup(fd_);
|
||||
CHECK(uncaptured_fd_ != -1);
|
||||
|
||||
// Open file to save stream to
|
||||
int cap_fd = open(filename_.c_str(),
|
||||
O_CREAT | O_TRUNC | O_WRONLY,
|
||||
S_IRUSR | S_IWUSR);
|
||||
CHECK(cap_fd != -1);
|
||||
|
||||
// Send stdout/stderr to this file
|
||||
fflush(NULL);
|
||||
CHECK(dup2(cap_fd, fd_) != -1);
|
||||
CHECK(close(cap_fd) != -1);
|
||||
}
|
||||
|
||||
// Remove output redirection
|
||||
void StopCapture() {
|
||||
// Restore original stream
|
||||
if (uncaptured_fd_ != -1) {
|
||||
fflush(NULL);
|
||||
CHECK(dup2(uncaptured_fd_, fd_) != -1);
|
||||
}
|
||||
}
|
||||
|
||||
const string & filename() const { return filename_; }
|
||||
|
||||
private:
|
||||
int fd_; // file descriptor being captured
|
||||
int uncaptured_fd_; // where the stream was originally being sent to
|
||||
string filename_; // file where stream is being saved
|
||||
};
|
||||
static CapturedStream * s_captured_streams[STDERR_FILENO+1];
|
||||
// Redirect a file descriptor to a file.
|
||||
// fd - Should be STDOUT_FILENO or STDERR_FILENO
|
||||
// filename - File where output should be stored
|
||||
static inline void CaptureTestOutput(int fd, const string & filename) {
|
||||
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
|
||||
CHECK(s_captured_streams[fd] == NULL);
|
||||
s_captured_streams[fd] = new CapturedStream(fd, filename);
|
||||
}
|
||||
static inline void CaptureTestStderr() {
|
||||
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
|
||||
}
|
||||
// Return the size (in bytes) of a file
|
||||
static inline size_t GetFileSize(FILE * file) {
|
||||
fseek(file, 0, SEEK_END);
|
||||
return static_cast<size_t>(ftell(file));
|
||||
}
|
||||
// Read the entire content of a file as a string
|
||||
static inline string ReadEntireFile(FILE * file) {
|
||||
const size_t file_size = GetFileSize(file);
|
||||
char * const buffer = new char[file_size];
|
||||
|
||||
size_t bytes_last_read = 0; // # of bytes read in the last fread()
|
||||
size_t bytes_read = 0; // # of bytes read so far
|
||||
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
// Keep reading the file until we cannot read further or the
|
||||
// pre-determined file size is reached.
|
||||
do {
|
||||
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
|
||||
bytes_read += bytes_last_read;
|
||||
} while (bytes_last_read > 0 && bytes_read < file_size);
|
||||
|
||||
const string content = string(buffer, buffer+bytes_read);
|
||||
delete[] buffer;
|
||||
|
||||
return content;
|
||||
}
|
||||
// Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
|
||||
// fd is STDERR_FILENO) as a string
|
||||
static inline string GetCapturedTestOutput(int fd) {
|
||||
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
|
||||
CapturedStream * const cap = s_captured_streams[fd];
|
||||
CHECK(cap)
|
||||
<< ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
|
||||
|
||||
// Make sure everything is flushed.
|
||||
cap->StopCapture();
|
||||
|
||||
// Read the captured file.
|
||||
FILE * const file = fopen(cap->filename().c_str(), "r");
|
||||
const string content = ReadEntireFile(file);
|
||||
fclose(file);
|
||||
|
||||
delete cap;
|
||||
s_captured_streams[fd] = NULL;
|
||||
|
||||
return content;
|
||||
}
|
||||
// Get the captured stderr of a test as a string.
|
||||
static inline string GetCapturedTestStderr() {
|
||||
return GetCapturedTestOutput(STDERR_FILENO);
|
||||
}
|
||||
|
||||
// Check if the string is [IWEF](\d{8}|YEARDATE)
|
||||
static inline bool IsLoggingPrefix(const string& s) {
|
||||
if (s.size() != 9) return false;
|
||||
if (!strchr("IWEF", s[0])) return false;
|
||||
for (int i = 1; i <= 8; ++i) {
|
||||
if (!isdigit(s[i]) && s[i] != "YEARDATE"[i-1]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert log output into normalized form.
|
||||
//
|
||||
// Example:
|
||||
// I20200102 030405 logging_unittest.cc:345] RAW: vlog -1
|
||||
// => IYEARDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
|
||||
static inline string MungeLine(const string& line) {
|
||||
std::istringstream iss(line);
|
||||
string before, logcode_date, time, thread_lineinfo;
|
||||
iss >> logcode_date;
|
||||
while (!IsLoggingPrefix(logcode_date)) {
|
||||
before += " " + logcode_date;
|
||||
if (!(iss >> logcode_date)) {
|
||||
// We cannot find the header of log output.
|
||||
return before;
|
||||
}
|
||||
}
|
||||
if (!before.empty()) before += " ";
|
||||
iss >> time;
|
||||
iss >> thread_lineinfo;
|
||||
CHECK(!thread_lineinfo.empty());
|
||||
if (thread_lineinfo[thread_lineinfo.size() - 1] != ']') {
|
||||
// We found thread ID.
|
||||
string tmp;
|
||||
iss >> tmp;
|
||||
CHECK(!tmp.empty());
|
||||
CHECK_EQ(']', tmp[tmp.size() - 1]);
|
||||
thread_lineinfo = "THREADID " + tmp;
|
||||
}
|
||||
size_t index = thread_lineinfo.find(':');
|
||||
CHECK_NE(string::npos, index);
|
||||
thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]";
|
||||
string rest;
|
||||
std::getline(iss, rest);
|
||||
return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
|
||||
MungeLine(rest));
|
||||
}
|
||||
|
||||
static inline void StringReplace(string* str,
|
||||
const string& oldsub,
|
||||
const string& newsub) {
|
||||
size_t pos = str->find(oldsub);
|
||||
if (pos != string::npos) {
|
||||
str->replace(pos, oldsub.size(), newsub.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static inline string Munge(const string& filename) {
|
||||
FILE* fp = fopen(filename.c_str(), "rb");
|
||||
CHECK(fp != NULL) << filename << ": couldn't open";
|
||||
char buf[4096];
|
||||
string result;
|
||||
while (fgets(buf, 4095, fp)) {
|
||||
string line = MungeLine(buf);
|
||||
char null_str[256];
|
||||
char ptr_str[256];
|
||||
sprintf(null_str, "%p", static_cast<void*>(NULL));
|
||||
sprintf(ptr_str, "%p", reinterpret_cast<void*>(PTR_TEST_VALUE));
|
||||
|
||||
StringReplace(&line, "__NULLP__", null_str);
|
||||
StringReplace(&line, "__PTRTEST__", ptr_str);
|
||||
|
||||
StringReplace(&line, "__SUCCESS__", StrError(0));
|
||||
StringReplace(&line, "__ENOENT__", StrError(ENOENT));
|
||||
StringReplace(&line, "__EINTR__", StrError(EINTR));
|
||||
StringReplace(&line, "__ENXIO__", StrError(ENXIO));
|
||||
StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
|
||||
result += line + "\n";
|
||||
}
|
||||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void WriteToFile(const string& body, const string& file) {
|
||||
FILE* fp = fopen(file.c_str(), "wb");
|
||||
fwrite(body.data(), 1, body.size(), fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
|
||||
CapturedStream* cap = s_captured_streams[STDERR_FILENO];
|
||||
CHECK(cap) << ": did you forget CaptureTestStderr()?";
|
||||
|
||||
cap->StopCapture();
|
||||
|
||||
// Run munge
|
||||
const string captured = Munge(cap->filename());
|
||||
const string golden = Munge(golden_filename);
|
||||
if (captured != golden) {
|
||||
fprintf(stderr,
|
||||
"Test with golden file failed. We'll try to show the diff:\n");
|
||||
string munged_golden = golden_filename + ".munged";
|
||||
WriteToFile(golden, munged_golden);
|
||||
string munged_captured = cap->filename() + ".munged";
|
||||
WriteToFile(captured, munged_captured);
|
||||
#ifdef OS_WINDOWS
|
||||
string diffcmd("fc " + munged_golden + " " + munged_captured);
|
||||
#else
|
||||
string diffcmd("diff -u " + munged_golden + " " + munged_captured);
|
||||
#endif
|
||||
if (system(diffcmd.c_str()) != 0) {
|
||||
fprintf(stderr, "diff command was failed.\n");
|
||||
}
|
||||
unlink(munged_golden.c_str());
|
||||
unlink(munged_captured.c_str());
|
||||
return false;
|
||||
}
|
||||
LOG(INFO) << "Diff was successful";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Save flags used from logging_unittest.cc.
|
||||
#ifndef HAVE_LIB_GFLAGS
|
||||
struct FlagSaver {
|
||||
FlagSaver()
|
||||
: v_(FLAGS_v),
|
||||
stderrthreshold_(FLAGS_stderrthreshold),
|
||||
logtostderr_(FLAGS_logtostderr),
|
||||
alsologtostderr_(FLAGS_alsologtostderr) {}
|
||||
~FlagSaver() {
|
||||
FLAGS_v = v_;
|
||||
FLAGS_stderrthreshold = stderrthreshold_;
|
||||
FLAGS_logtostderr = logtostderr_;
|
||||
FLAGS_alsologtostderr = alsologtostderr_;
|
||||
}
|
||||
int v_;
|
||||
int stderrthreshold_;
|
||||
bool logtostderr_;
|
||||
bool alsologtostderr_;
|
||||
};
|
||||
#endif
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
virtual ~Thread() {}
|
||||
|
||||
void SetJoinable(bool) {}
|
||||
#if defined(OS_WINDOWS) && !defined(OS_CYGWIN)
|
||||
void Start() {
|
||||
handle_ = CreateThread(NULL,
|
||||
0,
|
||||
(LPTHREAD_START_ROUTINE)&Thread::InvokeThread,
|
||||
(LPVOID)this,
|
||||
0,
|
||||
&th_);
|
||||
CHECK(handle_) << "CreateThread";
|
||||
}
|
||||
void Join() {
|
||||
WaitForSingleObject(handle_, INFINITE);
|
||||
}
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
void Start() {
|
||||
pthread_create(&th_, NULL, &Thread::InvokeThread, this);
|
||||
}
|
||||
void Join() {
|
||||
pthread_join(th_, NULL);
|
||||
}
|
||||
#else
|
||||
# error No thread implementation.
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void Run() = 0;
|
||||
|
||||
private:
|
||||
static void* InvokeThread(void* self) {
|
||||
((Thread*)self)->Run();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS) && !defined(OS_CYGWIN)
|
||||
HANDLE handle_;
|
||||
DWORD th_;
|
||||
#else
|
||||
pthread_t th_;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void SleepForMilliseconds(int t) {
|
||||
#ifndef OS_WINDOWS
|
||||
# if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
|
||||
const struct timespec req = {0, t * 1000 * 1000};
|
||||
nanosleep(&req, NULL);
|
||||
# else
|
||||
usleep(t * 1000);
|
||||
# endif
|
||||
#else
|
||||
Sleep(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Add hook for operator new to ensure there are no memory allocation.
|
||||
|
||||
void (*g_new_hook)() = NULL;
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
void* operator new(size_t size) {
|
||||
if (GOOGLE_NAMESPACE::g_new_hook) {
|
||||
GOOGLE_NAMESPACE::g_new_hook();
|
||||
}
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void* operator new[](size_t size) {
|
||||
return ::operator new(size);
|
||||
}
|
||||
|
||||
void operator delete(void* p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
void operator delete[](void* p) {
|
||||
::operator delete(p);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue