Set svn:eol-style = LF on files in base from which it is missing
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1648 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
132
base/at_exit.cc
132
base/at_exit.cc
@ -1,66 +1,66 @@
|
||||
// Copyright (c) 2006-2008 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/at_exit.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Keep a stack of registered AtExitManagers. We always operate on the most
|
||||
// recent, and we should never have more than one outside of testing, when we
|
||||
// use the shadow version of the constructor. We don't protect this for
|
||||
// thread-safe access, since it will only be modified in testing.
|
||||
static AtExitManager* g_top_manager = NULL;
|
||||
|
||||
AtExitManager::AtExitManager() : next_manager_(NULL) {
|
||||
DCHECK(!g_top_manager);
|
||||
g_top_manager = this;
|
||||
}
|
||||
|
||||
AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
|
||||
DCHECK(shadow || !g_top_manager);
|
||||
g_top_manager = this;
|
||||
}
|
||||
|
||||
AtExitManager::~AtExitManager() {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
DCHECK(g_top_manager == this);
|
||||
|
||||
ProcessCallbacksNow();
|
||||
g_top_manager = next_manager_;
|
||||
}
|
||||
|
||||
// static
|
||||
void AtExitManager::RegisterCallback(AtExitCallbackType func) {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(g_top_manager->lock_);
|
||||
g_top_manager->stack_.push(func);
|
||||
}
|
||||
|
||||
// static
|
||||
void AtExitManager::ProcessCallbacksNow() {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(g_top_manager->lock_);
|
||||
|
||||
while (!g_top_manager->stack_.empty()) {
|
||||
AtExitCallbackType func = g_top_manager->stack_.top();
|
||||
g_top_manager->stack_.pop();
|
||||
if (func)
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Copyright (c) 2006-2008 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/at_exit.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Keep a stack of registered AtExitManagers. We always operate on the most
|
||||
// recent, and we should never have more than one outside of testing, when we
|
||||
// use the shadow version of the constructor. We don't protect this for
|
||||
// thread-safe access, since it will only be modified in testing.
|
||||
static AtExitManager* g_top_manager = NULL;
|
||||
|
||||
AtExitManager::AtExitManager() : next_manager_(NULL) {
|
||||
DCHECK(!g_top_manager);
|
||||
g_top_manager = this;
|
||||
}
|
||||
|
||||
AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
|
||||
DCHECK(shadow || !g_top_manager);
|
||||
g_top_manager = this;
|
||||
}
|
||||
|
||||
AtExitManager::~AtExitManager() {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
DCHECK(g_top_manager == this);
|
||||
|
||||
ProcessCallbacksNow();
|
||||
g_top_manager = next_manager_;
|
||||
}
|
||||
|
||||
// static
|
||||
void AtExitManager::RegisterCallback(AtExitCallbackType func) {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(g_top_manager->lock_);
|
||||
g_top_manager->stack_.push(func);
|
||||
}
|
||||
|
||||
// static
|
||||
void AtExitManager::ProcessCallbacksNow() {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLock lock(g_top_manager->lock_);
|
||||
|
||||
while (!g_top_manager->stack_.empty()) {
|
||||
AtExitCallbackType func = g_top_manager->stack_.top();
|
||||
g_top_manager->stack_.pop();
|
||||
if (func)
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
|
130
base/at_exit.h
130
base/at_exit.h
@ -1,65 +1,65 @@
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_AT_EXIT_H_
|
||||
#define BASE_AT_EXIT_H_
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/lock.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// This class provides a facility similar to the CRT atexit(), except that
|
||||
// we control when the callbacks are executed. Under Windows for a DLL they
|
||||
// happen at a really bad time and under the loader lock. This facility is
|
||||
// mostly used by base::Singleton.
|
||||
//
|
||||
// The usage is simple. Early in the main() or WinMain() scope create an
|
||||
// AtExitManager object on the stack:
|
||||
// int main(...) {
|
||||
// base::AtExitManager exit_manager;
|
||||
//
|
||||
// }
|
||||
// When the exit_manager object goes out of scope, all the registered
|
||||
// callbacks and singleton destructors will be called.
|
||||
|
||||
class AtExitManager {
|
||||
protected:
|
||||
// This constructor will allow this instance of AtExitManager to be created
|
||||
// even if one already exists. This should only be used for testing!
|
||||
// AtExitManagers are kept on a global stack, and it will be removed during
|
||||
// destruction. This allows you to shadow another AtExitManager.
|
||||
AtExitManager(bool shadow);
|
||||
|
||||
public:
|
||||
typedef void (*AtExitCallbackType)();
|
||||
|
||||
AtExitManager();
|
||||
|
||||
// The dtor calls all the registered callbacks. Do not try to register more
|
||||
// callbacks after this point.
|
||||
~AtExitManager();
|
||||
|
||||
// Registers the specified function to be called at exit. The prototype of
|
||||
// the callback function is void func().
|
||||
static void RegisterCallback(AtExitCallbackType func);
|
||||
|
||||
// Calls the functions registered with RegisterCallback in LIFO order. It
|
||||
// is possible to register new callbacks after calling this function.
|
||||
static void ProcessCallbacksNow();
|
||||
|
||||
private:
|
||||
Lock lock_;
|
||||
std::stack<AtExitCallbackType> stack_;
|
||||
AtExitManager* next_manager_; // Stack of managers to allow shadowing.
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtExitManager);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_AT_EXIT_H_
|
||||
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_AT_EXIT_H_
|
||||
#define BASE_AT_EXIT_H_
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/lock.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// This class provides a facility similar to the CRT atexit(), except that
|
||||
// we control when the callbacks are executed. Under Windows for a DLL they
|
||||
// happen at a really bad time and under the loader lock. This facility is
|
||||
// mostly used by base::Singleton.
|
||||
//
|
||||
// The usage is simple. Early in the main() or WinMain() scope create an
|
||||
// AtExitManager object on the stack:
|
||||
// int main(...) {
|
||||
// base::AtExitManager exit_manager;
|
||||
//
|
||||
// }
|
||||
// When the exit_manager object goes out of scope, all the registered
|
||||
// callbacks and singleton destructors will be called.
|
||||
|
||||
class AtExitManager {
|
||||
protected:
|
||||
// This constructor will allow this instance of AtExitManager to be created
|
||||
// even if one already exists. This should only be used for testing!
|
||||
// AtExitManagers are kept on a global stack, and it will be removed during
|
||||
// destruction. This allows you to shadow another AtExitManager.
|
||||
AtExitManager(bool shadow);
|
||||
|
||||
public:
|
||||
typedef void (*AtExitCallbackType)();
|
||||
|
||||
AtExitManager();
|
||||
|
||||
// The dtor calls all the registered callbacks. Do not try to register more
|
||||
// callbacks after this point.
|
||||
~AtExitManager();
|
||||
|
||||
// Registers the specified function to be called at exit. The prototype of
|
||||
// the callback function is void func().
|
||||
static void RegisterCallback(AtExitCallbackType func);
|
||||
|
||||
// Calls the functions registered with RegisterCallback in LIFO order. It
|
||||
// is possible to register new callbacks after calling this function.
|
||||
static void ProcessCallbacksNow();
|
||||
|
||||
private:
|
||||
Lock lock_;
|
||||
std::stack<AtExitCallbackType> stack_;
|
||||
AtExitManager* next_manager_; // Stack of managers to allow shadowing.
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtExitManager);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_AT_EXIT_H_
|
||||
|
||||
|
@ -1,69 +1,69 @@
|
||||
// Copyright (c) 2006-2008 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/at_exit.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Don't test the global AtExitManager, because asking it to process its
|
||||
// AtExit callbacks can ruin the global state that other tests may depend on.
|
||||
class ShadowingAtExitManager : public base::AtExitManager {
|
||||
public:
|
||||
ShadowingAtExitManager() : AtExitManager(true) {}
|
||||
};
|
||||
|
||||
int g_test_counter_1 = 0;
|
||||
int g_test_counter_2 = 0;
|
||||
|
||||
void IncrementTestCounter1() {
|
||||
++g_test_counter_1;
|
||||
}
|
||||
|
||||
void IncrementTestCounter2() {
|
||||
++g_test_counter_2;
|
||||
}
|
||||
|
||||
void ZeroTestCounters() {
|
||||
g_test_counter_1 = 0;
|
||||
g_test_counter_2 = 0;
|
||||
}
|
||||
|
||||
void ExpectCounter1IsZero() {
|
||||
EXPECT_EQ(0, g_test_counter_1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(AtExitTest, Basic) {
|
||||
ShadowingAtExitManager shadowing_at_exit_manager;
|
||||
|
||||
ZeroTestCounters();
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter2);
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
|
||||
|
||||
EXPECT_EQ(0, g_test_counter_1);
|
||||
EXPECT_EQ(0, g_test_counter_2);
|
||||
base::AtExitManager::ProcessCallbacksNow();
|
||||
EXPECT_EQ(2, g_test_counter_1);
|
||||
EXPECT_EQ(1, g_test_counter_2);
|
||||
}
|
||||
|
||||
TEST(AtExitTest, LIFOOrder) {
|
||||
ShadowingAtExitManager shadowing_at_exit_manager;
|
||||
|
||||
ZeroTestCounters();
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
|
||||
base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero);
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter2);
|
||||
|
||||
EXPECT_EQ(0, g_test_counter_1);
|
||||
EXPECT_EQ(0, g_test_counter_2);
|
||||
base::AtExitManager::ProcessCallbacksNow();
|
||||
EXPECT_EQ(1, g_test_counter_1);
|
||||
EXPECT_EQ(1, g_test_counter_2);
|
||||
}
|
||||
|
||||
// Copyright (c) 2006-2008 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/at_exit.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Don't test the global AtExitManager, because asking it to process its
|
||||
// AtExit callbacks can ruin the global state that other tests may depend on.
|
||||
class ShadowingAtExitManager : public base::AtExitManager {
|
||||
public:
|
||||
ShadowingAtExitManager() : AtExitManager(true) {}
|
||||
};
|
||||
|
||||
int g_test_counter_1 = 0;
|
||||
int g_test_counter_2 = 0;
|
||||
|
||||
void IncrementTestCounter1() {
|
||||
++g_test_counter_1;
|
||||
}
|
||||
|
||||
void IncrementTestCounter2() {
|
||||
++g_test_counter_2;
|
||||
}
|
||||
|
||||
void ZeroTestCounters() {
|
||||
g_test_counter_1 = 0;
|
||||
g_test_counter_2 = 0;
|
||||
}
|
||||
|
||||
void ExpectCounter1IsZero() {
|
||||
EXPECT_EQ(0, g_test_counter_1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(AtExitTest, Basic) {
|
||||
ShadowingAtExitManager shadowing_at_exit_manager;
|
||||
|
||||
ZeroTestCounters();
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter2);
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
|
||||
|
||||
EXPECT_EQ(0, g_test_counter_1);
|
||||
EXPECT_EQ(0, g_test_counter_2);
|
||||
base::AtExitManager::ProcessCallbacksNow();
|
||||
EXPECT_EQ(2, g_test_counter_1);
|
||||
EXPECT_EQ(1, g_test_counter_2);
|
||||
}
|
||||
|
||||
TEST(AtExitTest, LIFOOrder) {
|
||||
ShadowingAtExitManager shadowing_at_exit_manager;
|
||||
|
||||
ZeroTestCounters();
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter1);
|
||||
base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero);
|
||||
base::AtExitManager::RegisterCallback(&IncrementTestCounter2);
|
||||
|
||||
EXPECT_EQ(0, g_test_counter_1);
|
||||
EXPECT_EQ(0, g_test_counter_2);
|
||||
base::AtExitManager::ProcessCallbacksNow();
|
||||
EXPECT_EQ(1, g_test_counter_1);
|
||||
EXPECT_EQ(1, g_test_counter_2);
|
||||
}
|
||||
|
||||
|
@ -1,65 +1,65 @@
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
// This is a low level implementation of atomic semantics for reference
|
||||
// counting. Please use base/ref_counted.h directly instead.
|
||||
|
||||
#ifndef BASE_ATOMIC_REF_COUNT_H_
|
||||
#define BASE_ATOMIC_REF_COUNT_H_
|
||||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
typedef base::subtle::Atomic32 AtomicRefCount;
|
||||
|
||||
// Increment a reference count by "increment", which must exceed 0.
|
||||
inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
|
||||
AtomicRefCount increment) {
|
||||
base::subtle::NoBarrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
// Decrement a reference count by "decrement", which must exceed 0,
|
||||
// and return whether the result is non-zero.
|
||||
// Insert barriers to ensure that state written before the reference count
|
||||
// became zero will be visible to a thread that has just made the count zero.
|
||||
inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr,
|
||||
AtomicRefCount decrement) {
|
||||
return base::subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0;
|
||||
}
|
||||
|
||||
// Increment a reference count by 1.
|
||||
inline void AtomicRefCountInc(volatile AtomicRefCount *ptr) {
|
||||
base::AtomicRefCountIncN(ptr, 1);
|
||||
}
|
||||
|
||||
// Decrement a reference count by 1 and return whether the result is non-zero.
|
||||
// Insert barriers to ensure that state written before the reference count
|
||||
// became zero will be visible to a thread that has just made the count zero.
|
||||
inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) {
|
||||
return base::AtomicRefCountDecN(ptr, 1);
|
||||
}
|
||||
|
||||
// Return whether the reference count is one. If the reference count is used
|
||||
// in the conventional way, a refrerence count of 1 implies that the current
|
||||
// thread owns the reference and no other thread shares it. This call performs
|
||||
// the test for a reference count of one, and performs the memory barrier
|
||||
// needed for the owning thread to act on the object, knowing that it has
|
||||
// exclusive access to the object.
|
||||
inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) {
|
||||
return base::subtle::Acquire_Load(ptr) == 1;
|
||||
}
|
||||
|
||||
// Return whether the reference count is zero. With conventional object
|
||||
// referencing counting, the object will be destroyed, so the reference count
|
||||
// should never be zero. Hence this is generally used for a debug check.
|
||||
inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) {
|
||||
return base::subtle::Acquire_Load(ptr) == 0;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMIC_REF_COUNT_H_
|
||||
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
// This is a low level implementation of atomic semantics for reference
|
||||
// counting. Please use base/ref_counted.h directly instead.
|
||||
|
||||
#ifndef BASE_ATOMIC_REF_COUNT_H_
|
||||
#define BASE_ATOMIC_REF_COUNT_H_
|
||||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
typedef base::subtle::Atomic32 AtomicRefCount;
|
||||
|
||||
// Increment a reference count by "increment", which must exceed 0.
|
||||
inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
|
||||
AtomicRefCount increment) {
|
||||
base::subtle::NoBarrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
// Decrement a reference count by "decrement", which must exceed 0,
|
||||
// and return whether the result is non-zero.
|
||||
// Insert barriers to ensure that state written before the reference count
|
||||
// became zero will be visible to a thread that has just made the count zero.
|
||||
inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr,
|
||||
AtomicRefCount decrement) {
|
||||
return base::subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0;
|
||||
}
|
||||
|
||||
// Increment a reference count by 1.
|
||||
inline void AtomicRefCountInc(volatile AtomicRefCount *ptr) {
|
||||
base::AtomicRefCountIncN(ptr, 1);
|
||||
}
|
||||
|
||||
// Decrement a reference count by 1 and return whether the result is non-zero.
|
||||
// Insert barriers to ensure that state written before the reference count
|
||||
// became zero will be visible to a thread that has just made the count zero.
|
||||
inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) {
|
||||
return base::AtomicRefCountDecN(ptr, 1);
|
||||
}
|
||||
|
||||
// Return whether the reference count is one. If the reference count is used
|
||||
// in the conventional way, a refrerence count of 1 implies that the current
|
||||
// thread owns the reference and no other thread shares it. This call performs
|
||||
// the test for a reference count of one, and performs the memory barrier
|
||||
// needed for the owning thread to act on the object, knowing that it has
|
||||
// exclusive access to the object.
|
||||
inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) {
|
||||
return base::subtle::Acquire_Load(ptr) == 1;
|
||||
}
|
||||
|
||||
// Return whether the reference count is zero. With conventional object
|
||||
// referencing counting, the object will be destroyed, so the reference count
|
||||
// should never be zero. Hence this is generally used for a debug check.
|
||||
inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) {
|
||||
return base::subtle::Acquire_Load(ptr) == 0;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMIC_REF_COUNT_H_
|
||||
|
||||
|
@ -1,45 +1,45 @@
|
||||
// Copyright (c) 2006-2008 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/base_paths_linux.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/string_piece.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
bool PathProviderLinux(int key, std::wstring* result) {
|
||||
std::wstring cur;
|
||||
switch (key) {
|
||||
case base::FILE_EXE:
|
||||
case base::FILE_MODULE: { // TODO(evanm): is this correct?
|
||||
char bin_dir[PATH_MAX + 1];
|
||||
int bin_dir_size = readlink("/proc/self/exe", bin_dir, PATH_MAX);
|
||||
if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
|
||||
NOTREACHED() << "Unable to resolve /proc/self/exe.";
|
||||
return false;
|
||||
}
|
||||
bin_dir[bin_dir_size] = 0;
|
||||
*result = base::SysNativeMBToWide(bin_dir);
|
||||
return true;
|
||||
}
|
||||
case base::DIR_SOURCE_ROOT:
|
||||
// On linux, unit tests execute two levels deep from the source root.
|
||||
// For example: chrome/{Debug|Hammer}/net_unittest
|
||||
PathService::Get(base::DIR_EXE, &cur);
|
||||
file_util::UpOneDirectory(&cur);
|
||||
file_util::UpOneDirectory(&cur);
|
||||
*result = cur;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Copyright (c) 2006-2008 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/base_paths_linux.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/string_piece.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
bool PathProviderLinux(int key, std::wstring* result) {
|
||||
std::wstring cur;
|
||||
switch (key) {
|
||||
case base::FILE_EXE:
|
||||
case base::FILE_MODULE: { // TODO(evanm): is this correct?
|
||||
char bin_dir[PATH_MAX + 1];
|
||||
int bin_dir_size = readlink("/proc/self/exe", bin_dir, PATH_MAX);
|
||||
if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
|
||||
NOTREACHED() << "Unable to resolve /proc/self/exe.";
|
||||
return false;
|
||||
}
|
||||
bin_dir[bin_dir_size] = 0;
|
||||
*result = base::SysNativeMBToWide(bin_dir);
|
||||
return true;
|
||||
}
|
||||
case base::DIR_SOURCE_ROOT:
|
||||
// On linux, unit tests execute two levels deep from the source root.
|
||||
// For example: chrome/{Debug|Hammer}/net_unittest
|
||||
PathService::Get(base::DIR_EXE, &cur);
|
||||
file_util::UpOneDirectory(&cur);
|
||||
file_util::UpOneDirectory(&cur);
|
||||
*result = cur;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
|
@ -1,31 +1,31 @@
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_BASE_PATHS_LINUX_H_
|
||||
#define BASE_BASE_PATHS_LINUX_H_
|
||||
|
||||
// This file declares Linux-specific path keys for the base module.
|
||||
// These can be used with the PathService to access various special
|
||||
// directories and files.
|
||||
|
||||
namespace base {
|
||||
|
||||
enum {
|
||||
PATH_LINUX_START = 200,
|
||||
|
||||
FILE_EXE, // Path and filename of the current executable.
|
||||
FILE_MODULE, // Path and filename of the module containing the code for the
|
||||
// PathService (which could differ from FILE_EXE if the
|
||||
// PathService were compiled into a shared object, for example).
|
||||
DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
|
||||
// for tests that need to locate various resources. It
|
||||
// should not be used outside of test code.
|
||||
|
||||
PATH_LINUX_END
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_LINUX_H_
|
||||
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_BASE_PATHS_LINUX_H_
|
||||
#define BASE_BASE_PATHS_LINUX_H_
|
||||
|
||||
// This file declares Linux-specific path keys for the base module.
|
||||
// These can be used with the PathService to access various special
|
||||
// directories and files.
|
||||
|
||||
namespace base {
|
||||
|
||||
enum {
|
||||
PATH_LINUX_START = 200,
|
||||
|
||||
FILE_EXE, // Path and filename of the current executable.
|
||||
FILE_MODULE, // Path and filename of the module containing the code for the
|
||||
// PathService (which could differ from FILE_EXE if the
|
||||
// PathService were compiled into a shared object, for example).
|
||||
DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
|
||||
// for tests that need to locate various resources. It
|
||||
// should not be used outside of test code.
|
||||
|
||||
PATH_LINUX_END
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_LINUX_H_
|
||||
|
||||
|
@ -1,32 +1,32 @@
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_BASE_PATHS_MAC_H_
|
||||
#define BASE_BASE_PATHS_MAC_H_
|
||||
|
||||
// This file declares Mac-specific path keys for the base module.
|
||||
// These can be used with the PathService to access various special
|
||||
// directories and files.
|
||||
|
||||
namespace base {
|
||||
|
||||
enum {
|
||||
PATH_MAC_START = 200,
|
||||
|
||||
FILE_EXE, // path and filename of the current executable
|
||||
FILE_MODULE, // path and filename of the module containing the code for the
|
||||
// PathService (which could differ from FILE_EXE if the
|
||||
// PathService were compiled into a library, for example)
|
||||
DIR_APP_DATA, // ~/Library/Application Support/Google/Chrome
|
||||
DIR_LOCAL_APP_DATA, // same as above (can we remove?)
|
||||
DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
|
||||
// for tests that need to locate various resources. It
|
||||
// should not be used outside of test code.
|
||||
PATH_MAC_END
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_MAC_H_
|
||||
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_BASE_PATHS_MAC_H_
|
||||
#define BASE_BASE_PATHS_MAC_H_
|
||||
|
||||
// This file declares Mac-specific path keys for the base module.
|
||||
// These can be used with the PathService to access various special
|
||||
// directories and files.
|
||||
|
||||
namespace base {
|
||||
|
||||
enum {
|
||||
PATH_MAC_START = 200,
|
||||
|
||||
FILE_EXE, // path and filename of the current executable
|
||||
FILE_MODULE, // path and filename of the module containing the code for the
|
||||
// PathService (which could differ from FILE_EXE if the
|
||||
// PathService were compiled into a library, for example)
|
||||
DIR_APP_DATA, // ~/Library/Application Support/Google/Chrome
|
||||
DIR_LOCAL_APP_DATA, // same as above (can we remove?)
|
||||
DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
|
||||
// for tests that need to locate various resources. It
|
||||
// should not be used outside of test code.
|
||||
PATH_MAC_END
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_MAC_H_
|
||||
|
||||
|
@ -1,328 +1,328 @@
|
||||
// Copyright (c) 2006-2008 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/file_util.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <fts.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/string_util.h"
|
||||
|
||||
namespace file_util {
|
||||
|
||||
std::wstring GetDirectoryFromPath(const std::wstring& path) {
|
||||
if (EndsWithSeparator(path)) {
|
||||
std::wstring dir = path;
|
||||
TrimTrailingSeparator(&dir);
|
||||
return dir;
|
||||
} else {
|
||||
char full_path[PATH_MAX];
|
||||
base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path));
|
||||
return UTF8ToWide(dirname(full_path));
|
||||
}
|
||||
}
|
||||
|
||||
bool AbsolutePath(std::wstring* path) {
|
||||
char full_path[PATH_MAX];
|
||||
if (realpath(WideToUTF8(*path).c_str(), full_path) == NULL)
|
||||
return false;
|
||||
*path = UTF8ToWide(full_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
|
||||
// which works both with and without the recursive flag. I'm not sure we need
|
||||
// that functionality. If not, remove from file_util_win.cc, otherwise add it
|
||||
// here.
|
||||
bool Delete(const std::wstring& path, bool recursive) {
|
||||
const char* utf8_path = WideToUTF8(path).c_str();
|
||||
struct stat64 file_info;
|
||||
int test = stat64(utf8_path, &file_info);
|
||||
if (test != 0) {
|
||||
// The Windows version defines this condition as success.
|
||||
bool ret = (errno == ENOENT || errno == ENOTDIR);
|
||||
return ret;
|
||||
}
|
||||
if (!S_ISDIR(file_info.st_mode))
|
||||
return (unlink(utf8_path) == 0);
|
||||
if (!recursive)
|
||||
return (rmdir(utf8_path) == 0);
|
||||
|
||||
bool success = true;
|
||||
int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
|
||||
char top_dir[PATH_MAX];
|
||||
base::strlcpy(top_dir, utf8_path, sizeof(top_dir));
|
||||
char* dir_list[2] = { top_dir, NULL };
|
||||
FTS* fts = fts_open(dir_list, ftsflags, NULL);
|
||||
if (fts) {
|
||||
FTSENT* fts_ent = fts_read(fts);
|
||||
while (success && fts_ent != NULL) {
|
||||
switch (fts_ent->fts_info) {
|
||||
case FTS_DNR:
|
||||
case FTS_ERR:
|
||||
// log error
|
||||
success = false;
|
||||
continue;
|
||||
break;
|
||||
case FTS_DP:
|
||||
rmdir(fts_ent->fts_accpath);
|
||||
break;
|
||||
case FTS_D:
|
||||
break;
|
||||
case FTS_NSOK:
|
||||
case FTS_F:
|
||||
case FTS_SL:
|
||||
case FTS_SLNONE:
|
||||
unlink(fts_ent->fts_accpath);
|
||||
break;
|
||||
default:
|
||||
DCHECK(false);
|
||||
break;
|
||||
}
|
||||
fts_ent = fts_read(fts);
|
||||
}
|
||||
fts_close(fts);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Move(const std::wstring& from_path, const std::wstring& to_path) {
|
||||
return (rename(WideToUTF8(from_path).c_str(),
|
||||
WideToUTF8(to_path).c_str()) == 0);
|
||||
}
|
||||
|
||||
bool CopyTree(const std::wstring& from_path, const std::wstring& to_path) {
|
||||
// TODO(erikkay): implement
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PathExists(const std::wstring& path) {
|
||||
struct stat64 file_info;
|
||||
return (stat64(WideToUTF8(path).c_str(), &file_info) == 0);
|
||||
}
|
||||
|
||||
// TODO(erikkay): implement
|
||||
#if 0
|
||||
bool GetFileCreationLocalTimeFromHandle(int fd,
|
||||
LPSYSTEMTIME creation_time) {
|
||||
if (!file_handle)
|
||||
return false;
|
||||
|
||||
FILETIME utc_filetime;
|
||||
if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
|
||||
return false;
|
||||
|
||||
FILETIME local_filetime;
|
||||
if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
|
||||
return false;
|
||||
|
||||
return !!FileTimeToSystemTime(&local_filetime, creation_time);
|
||||
}
|
||||
|
||||
bool GetFileCreationLocalTime(const std::string& filename,
|
||||
LPSYSTEMTIME creation_time) {
|
||||
ScopedHandle file_handle(
|
||||
CreateFile(filename.c_str(), GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
|
||||
return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CreateTemporaryFileName(std::wstring* temp_file) {
|
||||
std::wstring tmpdir;
|
||||
if (!GetTempDir(&tmpdir))
|
||||
return false;
|
||||
tmpdir.append(L"com.google.chrome.XXXXXX");
|
||||
// this should be OK since mktemp just replaces characters in place
|
||||
char* buffer = const_cast<char*>(WideToUTF8(tmpdir).c_str());
|
||||
*temp_file = UTF8ToWide(mktemp(buffer));
|
||||
int fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateNewTempDirectory(const std::wstring& prefix,
|
||||
std::wstring* new_temp_path) {
|
||||
std::wstring tmpdir;
|
||||
if (!GetTempDir(&tmpdir))
|
||||
return false;
|
||||
tmpdir.append(L"/com.google.chrome.XXXXXX");
|
||||
// this should be OK since mkdtemp just replaces characters in place
|
||||
char* buffer = const_cast<char*>(WideToUTF8(tmpdir).c_str());
|
||||
char* dtemp = mkdtemp(buffer);
|
||||
if (!dtemp)
|
||||
return false;
|
||||
*new_temp_path = UTF8ToWide(dtemp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateDirectory(const std::wstring& full_path) {
|
||||
std::vector<std::wstring> components;
|
||||
PathComponents(full_path, &components);
|
||||
std::wstring path;
|
||||
std::vector<std::wstring>::iterator i = components.begin();
|
||||
for (; i != components.end(); ++i) {
|
||||
if (path.length() == 0)
|
||||
path = *i;
|
||||
else
|
||||
AppendToPath(&path, *i);
|
||||
if (!PathExists(path)) {
|
||||
if (mkdir(WideToUTF8(path).c_str(), 0777) != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetFileSize(const std::wstring& file_path, int64* file_size) {
|
||||
struct stat64 file_info;
|
||||
if (stat64(WideToUTF8(file_path).c_str(), &file_info) != 0)
|
||||
return false;
|
||||
*file_size = file_info.st_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ReadFile(const std::wstring& filename, char* data, int size) {
|
||||
int fd = open(WideToUTF8(filename).c_str(), O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
int ret_value = read(fd, data, size);
|
||||
close(fd);
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
int WriteFile(const std::wstring& filename, const char* data, int size) {
|
||||
int fd = open(WideToUTF8(filename).c_str(), O_WRONLY | O_CREAT | O_TRUNC,
|
||||
0666);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
int ret_value = write(fd, data, size);
|
||||
close(fd);
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
// Gets the current working directory for the process.
|
||||
bool GetCurrentDirectory(std::wstring* dir) {
|
||||
char system_buffer[PATH_MAX] = "";
|
||||
getcwd(system_buffer, sizeof(system_buffer));
|
||||
*dir = UTF8ToWide(system_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sets the current working directory for the process.
|
||||
bool SetCurrentDirectory(const std::wstring& current_directory) {
|
||||
int ret = chdir(WideToUTF8(current_directory).c_str());
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
FileEnumerator::FileEnumerator(const std::wstring& root_path,
|
||||
bool recursive,
|
||||
FileEnumerator::FILE_TYPE file_type)
|
||||
: recursive_(recursive),
|
||||
file_type_(file_type),
|
||||
is_in_find_op_(false),
|
||||
fts_(NULL) {
|
||||
pending_paths_.push(root_path);
|
||||
}
|
||||
|
||||
FileEnumerator::FileEnumerator(const std::wstring& root_path,
|
||||
bool recursive,
|
||||
FileEnumerator::FILE_TYPE file_type,
|
||||
const std::wstring& pattern)
|
||||
: recursive_(recursive),
|
||||
file_type_(file_type),
|
||||
pattern_(root_path),
|
||||
is_in_find_op_(false),
|
||||
fts_(NULL) {
|
||||
// The Windows version of this code only matches against items in the top-most
|
||||
// directory, and we're comparing fnmatch against full paths, so this is the
|
||||
// easiest way to get the right pattern.
|
||||
AppendToPath(&pattern_, pattern);
|
||||
pending_paths_.push(root_path);
|
||||
}
|
||||
|
||||
FileEnumerator::~FileEnumerator() {
|
||||
if (fts_)
|
||||
fts_close(fts_);
|
||||
}
|
||||
|
||||
// As it stands, this method calls itself recursively when the next item of
|
||||
// the fts enumeration doesn't match (type, pattern, etc.). In the case of
|
||||
// large directories with many files this can be quite deep.
|
||||
// TODO(erikkay) - get rid of this recursive pattern
|
||||
std::wstring FileEnumerator::Next() {
|
||||
if (!is_in_find_op_) {
|
||||
if (pending_paths_.empty())
|
||||
return std::wstring();
|
||||
|
||||
// The last find FindFirstFile operation is done, prepare a new one.
|
||||
root_path_ = pending_paths_.top();
|
||||
TrimTrailingSeparator(&root_path_);
|
||||
pending_paths_.pop();
|
||||
|
||||
// Start a new find operation.
|
||||
int ftsflags = FTS_LOGICAL;
|
||||
char top_dir[PATH_MAX];
|
||||
base::strlcpy(top_dir, WideToUTF8(root_path_).c_str(), sizeof(top_dir));
|
||||
char* dir_list[2] = { top_dir, NULL };
|
||||
fts_ = fts_open(dir_list, ftsflags, NULL);
|
||||
if (!fts_)
|
||||
return Next();
|
||||
is_in_find_op_ = true;
|
||||
}
|
||||
|
||||
FTSENT* fts_ent = fts_read(fts_);
|
||||
if (fts_ent == NULL) {
|
||||
fts_close(fts_);
|
||||
fts_ = NULL;
|
||||
is_in_find_op_ = false;
|
||||
return Next();
|
||||
}
|
||||
|
||||
// Level 0 is the top, which is always skipped.
|
||||
if (fts_ent->fts_level == 0)
|
||||
return Next();
|
||||
|
||||
// Patterns are only matched on the items in the top-most directory.
|
||||
// (see Windows implementation)
|
||||
if (fts_ent->fts_level == 1 && pattern_.length() > 0) {
|
||||
const char* utf8_pattern = WideToUTF8(pattern_).c_str();
|
||||
if (fnmatch(utf8_pattern, fts_ent->fts_path, 0) != 0) {
|
||||
if (fts_ent->fts_info == FTS_D)
|
||||
fts_set(fts_, fts_ent, FTS_SKIP);
|
||||
return Next();
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring cur_file(UTF8ToWide(fts_ent->fts_path));
|
||||
if (fts_ent->fts_info == FTS_D) {
|
||||
// If not recursive, then prune children.
|
||||
if (!recursive_)
|
||||
fts_set(fts_, fts_ent, FTS_SKIP);
|
||||
return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
|
||||
} else if (fts_ent->fts_info == FTS_F) {
|
||||
return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
|
||||
}
|
||||
// TODO(erikkay) - verify that the other fts_info types aren't interesting
|
||||
return Next();
|
||||
}
|
||||
|
||||
|
||||
} // namespace file_util
|
||||
|
||||
|
||||
// Copyright (c) 2006-2008 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/file_util.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <fts.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/string_util.h"
|
||||
|
||||
namespace file_util {
|
||||
|
||||
std::wstring GetDirectoryFromPath(const std::wstring& path) {
|
||||
if (EndsWithSeparator(path)) {
|
||||
std::wstring dir = path;
|
||||
TrimTrailingSeparator(&dir);
|
||||
return dir;
|
||||
} else {
|
||||
char full_path[PATH_MAX];
|
||||
base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path));
|
||||
return UTF8ToWide(dirname(full_path));
|
||||
}
|
||||
}
|
||||
|
||||
bool AbsolutePath(std::wstring* path) {
|
||||
char full_path[PATH_MAX];
|
||||
if (realpath(WideToUTF8(*path).c_str(), full_path) == NULL)
|
||||
return false;
|
||||
*path = UTF8ToWide(full_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
|
||||
// which works both with and without the recursive flag. I'm not sure we need
|
||||
// that functionality. If not, remove from file_util_win.cc, otherwise add it
|
||||
// here.
|
||||
bool Delete(const std::wstring& path, bool recursive) {
|
||||
const char* utf8_path = WideToUTF8(path).c_str();
|
||||
struct stat64 file_info;
|
||||
int test = stat64(utf8_path, &file_info);
|
||||
if (test != 0) {
|
||||
// The Windows version defines this condition as success.
|
||||
bool ret = (errno == ENOENT || errno == ENOTDIR);
|
||||
return ret;
|
||||
}
|
||||
if (!S_ISDIR(file_info.st_mode))
|
||||
return (unlink(utf8_path) == 0);
|
||||
if (!recursive)
|
||||
return (rmdir(utf8_path) == 0);
|
||||
|
||||
bool success = true;
|
||||
int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
|
||||
char top_dir[PATH_MAX];
|
||||
base::strlcpy(top_dir, utf8_path, sizeof(top_dir));
|
||||
char* dir_list[2] = { top_dir, NULL };
|
||||
FTS* fts = fts_open(dir_list, ftsflags, NULL);
|
||||
if (fts) {
|
||||
FTSENT* fts_ent = fts_read(fts);
|
||||
while (success && fts_ent != NULL) {
|
||||
switch (fts_ent->fts_info) {
|
||||
case FTS_DNR:
|
||||
case FTS_ERR:
|
||||
// log error
|
||||
success = false;
|
||||
continue;
|
||||
break;
|
||||
case FTS_DP:
|
||||
rmdir(fts_ent->fts_accpath);
|
||||
break;
|
||||
case FTS_D:
|
||||
break;
|
||||
case FTS_NSOK:
|
||||
case FTS_F:
|
||||
case FTS_SL:
|
||||
case FTS_SLNONE:
|
||||
unlink(fts_ent->fts_accpath);
|
||||
break;
|
||||
default:
|
||||
DCHECK(false);
|
||||
break;
|
||||
}
|
||||
fts_ent = fts_read(fts);
|
||||
}
|
||||
fts_close(fts);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Move(const std::wstring& from_path, const std::wstring& to_path) {
|
||||
return (rename(WideToUTF8(from_path).c_str(),
|
||||
WideToUTF8(to_path).c_str()) == 0);
|
||||
}
|
||||
|
||||
bool CopyTree(const std::wstring& from_path, const std::wstring& to_path) {
|
||||
// TODO(erikkay): implement
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PathExists(const std::wstring& path) {
|
||||
struct stat64 file_info;
|
||||
return (stat64(WideToUTF8(path).c_str(), &file_info) == 0);
|
||||
}
|
||||
|
||||
// TODO(erikkay): implement
|
||||
#if 0
|
||||
bool GetFileCreationLocalTimeFromHandle(int fd,
|
||||
LPSYSTEMTIME creation_time) {
|
||||
if (!file_handle)
|
||||
return false;
|
||||
|
||||
FILETIME utc_filetime;
|
||||
if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
|
||||
return false;
|
||||
|
||||
FILETIME local_filetime;
|
||||
if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
|
||||
return false;
|
||||
|
||||
return !!FileTimeToSystemTime(&local_filetime, creation_time);
|
||||
}
|
||||
|
||||
bool GetFileCreationLocalTime(const std::string& filename,
|
||||
LPSYSTEMTIME creation_time) {
|
||||
ScopedHandle file_handle(
|
||||
CreateFile(filename.c_str(), GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
|
||||
return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CreateTemporaryFileName(std::wstring* temp_file) {
|
||||
std::wstring tmpdir;
|
||||
if (!GetTempDir(&tmpdir))
|
||||
return false;
|
||||
tmpdir.append(L"com.google.chrome.XXXXXX");
|
||||
// this should be OK since mktemp just replaces characters in place
|
||||
char* buffer = const_cast<char*>(WideToUTF8(tmpdir).c_str());
|
||||
*temp_file = UTF8ToWide(mktemp(buffer));
|
||||
int fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateNewTempDirectory(const std::wstring& prefix,
|
||||
std::wstring* new_temp_path) {
|
||||
std::wstring tmpdir;
|
||||
if (!GetTempDir(&tmpdir))
|
||||
return false;
|
||||
tmpdir.append(L"/com.google.chrome.XXXXXX");
|
||||
// this should be OK since mkdtemp just replaces characters in place
|
||||
char* buffer = const_cast<char*>(WideToUTF8(tmpdir).c_str());
|
||||
char* dtemp = mkdtemp(buffer);
|
||||
if (!dtemp)
|
||||
return false;
|
||||
*new_temp_path = UTF8ToWide(dtemp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateDirectory(const std::wstring& full_path) {
|
||||
std::vector<std::wstring> components;
|
||||
PathComponents(full_path, &components);
|
||||
std::wstring path;
|
||||
std::vector<std::wstring>::iterator i = components.begin();
|
||||
for (; i != components.end(); ++i) {
|
||||
if (path.length() == 0)
|
||||
path = *i;
|
||||
else
|
||||
AppendToPath(&path, *i);
|
||||
if (!PathExists(path)) {
|
||||
if (mkdir(WideToUTF8(path).c_str(), 0777) != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetFileSize(const std::wstring& file_path, int64* file_size) {
|
||||
struct stat64 file_info;
|
||||
if (stat64(WideToUTF8(file_path).c_str(), &file_info) != 0)
|
||||
return false;
|
||||
*file_size = file_info.st_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ReadFile(const std::wstring& filename, char* data, int size) {
|
||||
int fd = open(WideToUTF8(filename).c_str(), O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
int ret_value = read(fd, data, size);
|
||||
close(fd);
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
int WriteFile(const std::wstring& filename, const char* data, int size) {
|
||||
int fd = open(WideToUTF8(filename).c_str(), O_WRONLY | O_CREAT | O_TRUNC,
|
||||
0666);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
int ret_value = write(fd, data, size);
|
||||
close(fd);
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
// Gets the current working directory for the process.
|
||||
bool GetCurrentDirectory(std::wstring* dir) {
|
||||
char system_buffer[PATH_MAX] = "";
|
||||
getcwd(system_buffer, sizeof(system_buffer));
|
||||
*dir = UTF8ToWide(system_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sets the current working directory for the process.
|
||||
bool SetCurrentDirectory(const std::wstring& current_directory) {
|
||||
int ret = chdir(WideToUTF8(current_directory).c_str());
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
FileEnumerator::FileEnumerator(const std::wstring& root_path,
|
||||
bool recursive,
|
||||
FileEnumerator::FILE_TYPE file_type)
|
||||
: recursive_(recursive),
|
||||
file_type_(file_type),
|
||||
is_in_find_op_(false),
|
||||
fts_(NULL) {
|
||||
pending_paths_.push(root_path);
|
||||
}
|
||||
|
||||
FileEnumerator::FileEnumerator(const std::wstring& root_path,
|
||||
bool recursive,
|
||||
FileEnumerator::FILE_TYPE file_type,
|
||||
const std::wstring& pattern)
|
||||
: recursive_(recursive),
|
||||
file_type_(file_type),
|
||||
pattern_(root_path),
|
||||
is_in_find_op_(false),
|
||||
fts_(NULL) {
|
||||
// The Windows version of this code only matches against items in the top-most
|
||||
// directory, and we're comparing fnmatch against full paths, so this is the
|
||||
// easiest way to get the right pattern.
|
||||
AppendToPath(&pattern_, pattern);
|
||||
pending_paths_.push(root_path);
|
||||
}
|
||||
|
||||
FileEnumerator::~FileEnumerator() {
|
||||
if (fts_)
|
||||
fts_close(fts_);
|
||||
}
|
||||
|
||||
// As it stands, this method calls itself recursively when the next item of
|
||||
// the fts enumeration doesn't match (type, pattern, etc.). In the case of
|
||||
// large directories with many files this can be quite deep.
|
||||
// TODO(erikkay) - get rid of this recursive pattern
|
||||
std::wstring FileEnumerator::Next() {
|
||||
if (!is_in_find_op_) {
|
||||
if (pending_paths_.empty())
|
||||
return std::wstring();
|
||||
|
||||
// The last find FindFirstFile operation is done, prepare a new one.
|
||||
root_path_ = pending_paths_.top();
|
||||
TrimTrailingSeparator(&root_path_);
|
||||
pending_paths_.pop();
|
||||
|
||||
// Start a new find operation.
|
||||
int ftsflags = FTS_LOGICAL;
|
||||
char top_dir[PATH_MAX];
|
||||
base::strlcpy(top_dir, WideToUTF8(root_path_).c_str(), sizeof(top_dir));
|
||||
char* dir_list[2] = { top_dir, NULL };
|
||||
fts_ = fts_open(dir_list, ftsflags, NULL);
|
||||
if (!fts_)
|
||||
return Next();
|
||||
is_in_find_op_ = true;
|
||||
}
|
||||
|
||||
FTSENT* fts_ent = fts_read(fts_);
|
||||
if (fts_ent == NULL) {
|
||||
fts_close(fts_);
|
||||
fts_ = NULL;
|
||||
is_in_find_op_ = false;
|
||||
return Next();
|
||||
}
|
||||
|
||||
// Level 0 is the top, which is always skipped.
|
||||
if (fts_ent->fts_level == 0)
|
||||
return Next();
|
||||
|
||||
// Patterns are only matched on the items in the top-most directory.
|
||||
// (see Windows implementation)
|
||||
if (fts_ent->fts_level == 1 && pattern_.length() > 0) {
|
||||
const char* utf8_pattern = WideToUTF8(pattern_).c_str();
|
||||
if (fnmatch(utf8_pattern, fts_ent->fts_path, 0) != 0) {
|
||||
if (fts_ent->fts_info == FTS_D)
|
||||
fts_set(fts_, fts_ent, FTS_SKIP);
|
||||
return Next();
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring cur_file(UTF8ToWide(fts_ent->fts_path));
|
||||
if (fts_ent->fts_info == FTS_D) {
|
||||
// If not recursive, then prune children.
|
||||
if (!recursive_)
|
||||
fts_set(fts_, fts_ent, FTS_SKIP);
|
||||
return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
|
||||
} else if (fts_ent->fts_info == FTS_F) {
|
||||
return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
|
||||
}
|
||||
// TODO(erikkay) - verify that the other fts_info types aren't interesting
|
||||
return Next();
|
||||
}
|
||||
|
||||
|
||||
} // namespace file_util
|
||||
|
||||
|
||||
|
@ -1,75 +1,75 @@
|
||||
// Copyright (c) 2006-2008 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/message_pump_default.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
MessagePumpDefault::MessagePumpDefault()
|
||||
: keep_running_(true),
|
||||
event_(false, false) {
|
||||
}
|
||||
|
||||
void MessagePumpDefault::Run(Delegate* delegate) {
|
||||
DCHECK(keep_running_) << "Quit must have been called outside of Run!";
|
||||
|
||||
for (;;) {
|
||||
bool did_work = delegate->DoWork();
|
||||
if (!keep_running_)
|
||||
break;
|
||||
|
||||
did_work |= delegate->DoDelayedWork(&delayed_work_time_);
|
||||
if (!keep_running_)
|
||||
break;
|
||||
|
||||
if (did_work)
|
||||
continue;
|
||||
|
||||
did_work = delegate->DoIdleWork();
|
||||
if (!keep_running_)
|
||||
break;
|
||||
|
||||
if (did_work)
|
||||
continue;
|
||||
|
||||
if (delayed_work_time_.is_null()) {
|
||||
event_.Wait();
|
||||
} else {
|
||||
TimeDelta delay = delayed_work_time_ - Time::Now();
|
||||
if (delay > TimeDelta()) {
|
||||
event_.TimedWait(delay);
|
||||
} else {
|
||||
// It looks like delayed_work_time_ indicates a time in the past, so we
|
||||
// need to call DoDelayedWork now.
|
||||
delayed_work_time_ = Time();
|
||||
}
|
||||
}
|
||||
// Since event_ is auto-reset, we don't need to do anything special here
|
||||
// other than service each delegate method.
|
||||
}
|
||||
|
||||
keep_running_ = true;
|
||||
}
|
||||
|
||||
void MessagePumpDefault::Quit() {
|
||||
keep_running_ = false;
|
||||
}
|
||||
|
||||
void MessagePumpDefault::ScheduleWork() {
|
||||
// Since this can be called on any thread, we need to ensure that our Run
|
||||
// loop wakes up.
|
||||
event_.Signal();
|
||||
}
|
||||
|
||||
void MessagePumpDefault::ScheduleDelayedWork(const Time& delayed_work_time) {
|
||||
// We know that we can't be blocked on Wait right now since this method can
|
||||
// only be called on the same thread as Run, so we only need to update our
|
||||
// record of how long to sleep when we do sleep.
|
||||
delayed_work_time_ = delayed_work_time;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Copyright (c) 2006-2008 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/message_pump_default.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
MessagePumpDefault::MessagePumpDefault()
|
||||
: keep_running_(true),
|
||||
event_(false, false) {
|
||||
}
|
||||
|
||||
void MessagePumpDefault::Run(Delegate* delegate) {
|
||||
DCHECK(keep_running_) << "Quit must have been called outside of Run!";
|
||||
|
||||
for (;;) {
|
||||
bool did_work = delegate->DoWork();
|
||||
if (!keep_running_)
|
||||
break;
|
||||
|
||||
did_work |= delegate->DoDelayedWork(&delayed_work_time_);
|
||||
if (!keep_running_)
|
||||
break;
|
||||
|
||||
if (did_work)
|
||||
continue;
|
||||
|
||||
did_work = delegate->DoIdleWork();
|
||||
if (!keep_running_)
|
||||
break;
|
||||
|
||||
if (did_work)
|
||||
continue;
|
||||
|
||||
if (delayed_work_time_.is_null()) {
|
||||
event_.Wait();
|
||||
} else {
|
||||
TimeDelta delay = delayed_work_time_ - Time::Now();
|
||||
if (delay > TimeDelta()) {
|
||||
event_.TimedWait(delay);
|
||||
} else {
|
||||
// It looks like delayed_work_time_ indicates a time in the past, so we
|
||||
// need to call DoDelayedWork now.
|
||||
delayed_work_time_ = Time();
|
||||
}
|
||||
}
|
||||
// Since event_ is auto-reset, we don't need to do anything special here
|
||||
// other than service each delegate method.
|
||||
}
|
||||
|
||||
keep_running_ = true;
|
||||
}
|
||||
|
||||
void MessagePumpDefault::Quit() {
|
||||
keep_running_ = false;
|
||||
}
|
||||
|
||||
void MessagePumpDefault::ScheduleWork() {
|
||||
// Since this can be called on any thread, we need to ensure that our Run
|
||||
// loop wakes up.
|
||||
event_.Signal();
|
||||
}
|
||||
|
||||
void MessagePumpDefault::ScheduleDelayedWork(const Time& delayed_work_time) {
|
||||
// We know that we can't be blocked on Wait right now since this method can
|
||||
// only be called on the same thread as Run, so we only need to update our
|
||||
// record of how long to sleep when we do sleep.
|
||||
delayed_work_time_ = delayed_work_time;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
|
@ -1,41 +1,41 @@
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_MESSAGE_PUMP_DEFAULT_H_
|
||||
#define BASE_MESSAGE_PUMP_DEFAULT_H_
|
||||
|
||||
#include "base/message_pump.h"
|
||||
#include "base/time.h"
|
||||
#include "base/waitable_event.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class MessagePumpDefault : public MessagePump {
|
||||
public:
|
||||
MessagePumpDefault();
|
||||
~MessagePumpDefault() {}
|
||||
|
||||
// MessagePump methods:
|
||||
virtual void Run(Delegate* delegate);
|
||||
virtual void Quit();
|
||||
virtual void ScheduleWork();
|
||||
virtual void ScheduleDelayedWork(const Time& delayed_work_time);
|
||||
|
||||
private:
|
||||
// This flag is set to false when Run should return.
|
||||
bool keep_running_;
|
||||
|
||||
// Used to sleep until there is more work to do.
|
||||
WaitableEvent event_;
|
||||
|
||||
// The time at which we should call DoDelayedWork.
|
||||
Time delayed_work_time_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MESSAGE_PUMP_DEFAULT_H_
|
||||
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_MESSAGE_PUMP_DEFAULT_H_
|
||||
#define BASE_MESSAGE_PUMP_DEFAULT_H_
|
||||
|
||||
#include "base/message_pump.h"
|
||||
#include "base/time.h"
|
||||
#include "base/waitable_event.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class MessagePumpDefault : public MessagePump {
|
||||
public:
|
||||
MessagePumpDefault();
|
||||
~MessagePumpDefault() {}
|
||||
|
||||
// MessagePump methods:
|
||||
virtual void Run(Delegate* delegate);
|
||||
virtual void Quit();
|
||||
virtual void ScheduleWork();
|
||||
virtual void ScheduleDelayedWork(const Time& delayed_work_time);
|
||||
|
||||
private:
|
||||
// This flag is set to false when Run should return.
|
||||
bool keep_running_;
|
||||
|
||||
// Used to sleep until there is more work to do.
|
||||
WaitableEvent event_;
|
||||
|
||||
// The time at which we should call DoDelayedWork.
|
||||
Time delayed_work_time_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MESSAGE_PUMP_DEFAULT_H_
|
||||
|
||||
|
@ -1,37 +1,37 @@
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_PLATFORM_TEST_H_
|
||||
#define BASE_PLATFORM_TEST_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#ifdef __OBJC__
|
||||
@class NSAutoreleasePool;
|
||||
#else
|
||||
class NSAutoreleasePool;
|
||||
#endif
|
||||
|
||||
// The purpose of this class us to provide a hook for platform-specific
|
||||
// SetUp and TearDown across unit tests. For example, on the Mac, it
|
||||
// creates and releases an outer AutoreleasePool for each test. For now, it's
|
||||
// only implemented on the Mac. To enable this for another platform, just
|
||||
// adjust the #ifdefs and add a platform_test_<platform>.cc implementation file.
|
||||
class PlatformTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
private:
|
||||
NSAutoreleasePool* pool_;
|
||||
};
|
||||
#else
|
||||
typedef testing::Test PlatformTest;
|
||||
#endif // OS_MACOSX
|
||||
|
||||
#endif // BASE_PLATFORM_TEST_H_
|
||||
|
||||
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_PLATFORM_TEST_H_
|
||||
#define BASE_PLATFORM_TEST_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#ifdef __OBJC__
|
||||
@class NSAutoreleasePool;
|
||||
#else
|
||||
class NSAutoreleasePool;
|
||||
#endif
|
||||
|
||||
// The purpose of this class us to provide a hook for platform-specific
|
||||
// SetUp and TearDown across unit tests. For example, on the Mac, it
|
||||
// creates and releases an outer AutoreleasePool for each test. For now, it's
|
||||
// only implemented on the Mac. To enable this for another platform, just
|
||||
// adjust the #ifdefs and add a platform_test_<platform>.cc implementation file.
|
||||
class PlatformTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
private:
|
||||
NSAutoreleasePool* pool_;
|
||||
};
|
||||
#else
|
||||
typedef testing::Test PlatformTest;
|
||||
#endif // OS_MACOSX
|
||||
|
||||
#endif // BASE_PLATFORM_TEST_H_
|
||||
|
||||
|
||||
|
@ -1,36 +1,36 @@
|
||||
// Copyright (c) 2006-2008 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/sys_string_conversions.h"
|
||||
|
||||
#include "base/string_piece.h"
|
||||
#include "base/string_util.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
std::string SysWideToUTF8(const std::wstring& wide) {
|
||||
// In theory this should be using the system-provided conversion rather
|
||||
// than our ICU, but this will do for now.
|
||||
return WideToUTF8(wide);
|
||||
}
|
||||
std::wstring SysUTF8ToWide(const StringPiece& utf8) {
|
||||
// In theory this should be using the system-provided conversion rather
|
||||
// than our ICU, but this will do for now.
|
||||
std::wstring out;
|
||||
UTF8ToWide(utf8.data(), utf8.size(), &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string SysWideToNativeMB(const std::wstring& wide) {
|
||||
// TODO(evanm): we can't assume Linux is UTF-8.
|
||||
return SysWideToUTF8(wide);
|
||||
}
|
||||
|
||||
std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
|
||||
// TODO(evanm): we can't assume Linux is UTF-8.
|
||||
return SysUTF8ToWide(native_mb);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Copyright (c) 2006-2008 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/sys_string_conversions.h"
|
||||
|
||||
#include "base/string_piece.h"
|
||||
#include "base/string_util.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
std::string SysWideToUTF8(const std::wstring& wide) {
|
||||
// In theory this should be using the system-provided conversion rather
|
||||
// than our ICU, but this will do for now.
|
||||
return WideToUTF8(wide);
|
||||
}
|
||||
std::wstring SysUTF8ToWide(const StringPiece& utf8) {
|
||||
// In theory this should be using the system-provided conversion rather
|
||||
// than our ICU, but this will do for now.
|
||||
std::wstring out;
|
||||
UTF8ToWide(utf8.data(), utf8.size(), &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string SysWideToNativeMB(const std::wstring& wide) {
|
||||
// TODO(evanm): we can't assume Linux is UTF-8.
|
||||
return SysWideToUTF8(wide);
|
||||
}
|
||||
|
||||
std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
|
||||
// TODO(evanm): we can't assume Linux is UTF-8.
|
||||
return SysUTF8ToWide(native_mb);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
|
@ -440,39 +440,63 @@ void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type) {
|
||||
// that timers work properly in all configurations.
|
||||
|
||||
TEST(TimerTest, TimerComparison) {
|
||||
Time s = Time::Now();
|
||||
RunTest_TimerComparison(MessageLoop::TYPE_DEFAULT);
|
||||
RunTest_TimerComparison(MessageLoop::TYPE_UI);
|
||||
RunTest_TimerComparison(MessageLoop::TYPE_IO);
|
||||
Time e = Time::Now();
|
||||
TimeDelta el = e - s;
|
||||
printf("comparison elapsed time %lld\n", el.ToInternalValue());
|
||||
}
|
||||
|
||||
TEST(TimerTest, BasicTimer) {
|
||||
Time s = Time::Now();
|
||||
RunTest_BasicTimer(MessageLoop::TYPE_DEFAULT);
|
||||
RunTest_BasicTimer(MessageLoop::TYPE_UI);
|
||||
RunTest_BasicTimer(MessageLoop::TYPE_IO);
|
||||
Time e = Time::Now();
|
||||
TimeDelta el = e - s;
|
||||
printf("basic elapsed time %lld\n", el.ToInternalValue());
|
||||
}
|
||||
|
||||
TEST(TimerTest, BrokenTimer) {
|
||||
Time s = Time::Now();
|
||||
RunTest_BrokenTimer(MessageLoop::TYPE_DEFAULT);
|
||||
RunTest_BrokenTimer(MessageLoop::TYPE_UI);
|
||||
RunTest_BrokenTimer(MessageLoop::TYPE_IO);
|
||||
Time e = Time::Now();
|
||||
TimeDelta el = e - s;
|
||||
printf("broken elapsed time %lld\n", el.ToInternalValue());
|
||||
}
|
||||
|
||||
TEST(TimerTest, DeleteFromRun) {
|
||||
Time s = Time::Now();
|
||||
RunTest_DeleteFromRun(MessageLoop::TYPE_DEFAULT);
|
||||
RunTest_DeleteFromRun(MessageLoop::TYPE_UI);
|
||||
RunTest_DeleteFromRun(MessageLoop::TYPE_IO);
|
||||
Time e = Time::Now();
|
||||
TimeDelta el = e - s;
|
||||
printf("delete elapsed time %lld\n", el.ToInternalValue());
|
||||
}
|
||||
|
||||
TEST(TimerTest, Reset) {
|
||||
Time s = Time::Now();
|
||||
RunTest_Reset(MessageLoop::TYPE_DEFAULT);
|
||||
RunTest_Reset(MessageLoop::TYPE_UI);
|
||||
RunTest_Reset(MessageLoop::TYPE_IO);
|
||||
Time e = Time::Now();
|
||||
TimeDelta el = e - s;
|
||||
printf("reset elapsed time %lld\n", el.ToInternalValue());
|
||||
}
|
||||
|
||||
TEST(TimerTest, FifoOrder) {
|
||||
Time s = Time::Now();
|
||||
RunTest_FifoOrder(MessageLoop::TYPE_DEFAULT);
|
||||
RunTest_FifoOrder(MessageLoop::TYPE_UI);
|
||||
RunTest_FifoOrder(MessageLoop::TYPE_IO);
|
||||
Time e = Time::Now();
|
||||
TimeDelta el = e - s;
|
||||
printf("fifo elapsed time %lld\n", el.ToInternalValue());
|
||||
}
|
||||
|
||||
TEST(TimerTest, OneShotTimer) {
|
||||
|
@ -1,83 +1,83 @@
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_WAITABLE_EVENT_H_
|
||||
#define BASE_WAITABLE_EVENT_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
typedef void* HANDLE;
|
||||
#else
|
||||
#include "base/condition_variable.h"
|
||||
#include "base/lock.h"
|
||||
#endif
|
||||
|
||||
class TimeDelta;
|
||||
|
||||
namespace base {
|
||||
|
||||
// A WaitableEvent can be a useful thread synchronization tool when you want to
|
||||
// allow one thread to wait for another thread to finish some work.
|
||||
//
|
||||
// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
|
||||
// protect a simple boolean value. However, if you find yourself using a
|
||||
// WaitableEvent in conjunction with a Lock to wait for a more complex state
|
||||
// change (e.g., for an item to be added to a queue), then you should probably
|
||||
// be using a ConditionVariable instead of a WaitableEvent.
|
||||
//
|
||||
// NOTE: On Windows, this class provides a subset of the functionality afforded
|
||||
// by a Windows event object. This is intentional. If you are writing Windows
|
||||
// specific code and you need other features of a Windows event, then you might
|
||||
// be better off just using an Windows event directly.
|
||||
//
|
||||
class WaitableEvent {
|
||||
public:
|
||||
// If manual_reset is true, then to set the event state to non-signaled, a
|
||||
// consumer must call the Reset method. If this parameter is false, then the
|
||||
// system automatically resets the event state to non-signaled after a single
|
||||
// waiting thread has been released.
|
||||
WaitableEvent(bool manual_reset, bool initially_signaled);
|
||||
|
||||
// WARNING: Destroying a WaitableEvent while threads are waiting on it is not
|
||||
// supported. Doing so will cause crashes or other instability.
|
||||
~WaitableEvent();
|
||||
|
||||
// Put the event in the un-signaled state.
|
||||
void Reset();
|
||||
|
||||
// Put the event in the signaled state. Causing any thread blocked on Wait
|
||||
// to be woken up.
|
||||
void Signal();
|
||||
|
||||
// Returns true if the event is in the signaled state, else false. If this
|
||||
// is not a manual reset event, then this test will cause a reset.
|
||||
bool IsSignaled();
|
||||
|
||||
// Wait indefinitely for the event to be signaled. Returns true if the event
|
||||
// was signaled, else false is returned to indicate that waiting failed.
|
||||
bool Wait();
|
||||
|
||||
// Wait up until max_time has passed for the event to be signaled. Returns
|
||||
// true if the event was signaled. If this method returns false, then it
|
||||
// does not necessarily mean that max_time was exceeded.
|
||||
bool TimedWait(const TimeDelta& max_time);
|
||||
|
||||
private:
|
||||
#if defined(OS_WIN)
|
||||
HANDLE event_;
|
||||
#else
|
||||
Lock lock_; // Needs to be listed first so it will be constructed first.
|
||||
ConditionVariable cvar_;
|
||||
bool signaled_;
|
||||
bool manual_reset_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_WAITABLE_EVENT_H_
|
||||
|
||||
// Copyright (c) 2006-2008 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.
|
||||
|
||||
#ifndef BASE_WAITABLE_EVENT_H_
|
||||
#define BASE_WAITABLE_EVENT_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
typedef void* HANDLE;
|
||||
#else
|
||||
#include "base/condition_variable.h"
|
||||
#include "base/lock.h"
|
||||
#endif
|
||||
|
||||
class TimeDelta;
|
||||
|
||||
namespace base {
|
||||
|
||||
// A WaitableEvent can be a useful thread synchronization tool when you want to
|
||||
// allow one thread to wait for another thread to finish some work.
|
||||
//
|
||||
// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
|
||||
// protect a simple boolean value. However, if you find yourself using a
|
||||
// WaitableEvent in conjunction with a Lock to wait for a more complex state
|
||||
// change (e.g., for an item to be added to a queue), then you should probably
|
||||
// be using a ConditionVariable instead of a WaitableEvent.
|
||||
//
|
||||
// NOTE: On Windows, this class provides a subset of the functionality afforded
|
||||
// by a Windows event object. This is intentional. If you are writing Windows
|
||||
// specific code and you need other features of a Windows event, then you might
|
||||
// be better off just using an Windows event directly.
|
||||
//
|
||||
class WaitableEvent {
|
||||
public:
|
||||
// If manual_reset is true, then to set the event state to non-signaled, a
|
||||
// consumer must call the Reset method. If this parameter is false, then the
|
||||
// system automatically resets the event state to non-signaled after a single
|
||||
// waiting thread has been released.
|
||||
WaitableEvent(bool manual_reset, bool initially_signaled);
|
||||
|
||||
// WARNING: Destroying a WaitableEvent while threads are waiting on it is not
|
||||
// supported. Doing so will cause crashes or other instability.
|
||||
~WaitableEvent();
|
||||
|
||||
// Put the event in the un-signaled state.
|
||||
void Reset();
|
||||
|
||||
// Put the event in the signaled state. Causing any thread blocked on Wait
|
||||
// to be woken up.
|
||||
void Signal();
|
||||
|
||||
// Returns true if the event is in the signaled state, else false. If this
|
||||
// is not a manual reset event, then this test will cause a reset.
|
||||
bool IsSignaled();
|
||||
|
||||
// Wait indefinitely for the event to be signaled. Returns true if the event
|
||||
// was signaled, else false is returned to indicate that waiting failed.
|
||||
bool Wait();
|
||||
|
||||
// Wait up until max_time has passed for the event to be signaled. Returns
|
||||
// true if the event was signaled. If this method returns false, then it
|
||||
// does not necessarily mean that max_time was exceeded.
|
||||
bool TimedWait(const TimeDelta& max_time);
|
||||
|
||||
private:
|
||||
#if defined(OS_WIN)
|
||||
HANDLE event_;
|
||||
#else
|
||||
Lock lock_; // Needs to be listed first so it will be constructed first.
|
||||
ConditionVariable cvar_;
|
||||
bool signaled_;
|
||||
bool manual_reset_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_WAITABLE_EVENT_H_
|
||||
|
||||
|
@ -1,66 +1,66 @@
|
||||
// Copyright (c) 2006-2008 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/waitable_event.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/time.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
|
||||
: event_(CreateEvent(NULL, manual_reset, signaled, NULL)) {
|
||||
// We're probably going to crash anyways if this is ever NULL, so we might as
|
||||
// well make our stack reports more informative by crashing here.
|
||||
CHECK(event_);
|
||||
}
|
||||
|
||||
WaitableEvent::~WaitableEvent() {
|
||||
CloseHandle(event_);
|
||||
}
|
||||
|
||||
void WaitableEvent::Reset() {
|
||||
ResetEvent(event_);
|
||||
}
|
||||
|
||||
void WaitableEvent::Signal() {
|
||||
SetEvent(event_);
|
||||
}
|
||||
|
||||
bool WaitableEvent::IsSignaled() {
|
||||
return TimedWait(TimeDelta::FromMilliseconds(0));
|
||||
}
|
||||
|
||||
bool WaitableEvent::Wait() {
|
||||
DWORD result = WaitForSingleObject(event_, INFINITE);
|
||||
// It is most unexpected that this should ever fail. Help consumers learn
|
||||
// about it if it should ever fail.
|
||||
DCHECK(result == WAIT_OBJECT_0) << "WaitForSingleObject failed";
|
||||
return result == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
|
||||
DCHECK(max_time >= TimeDelta::FromMicroseconds(0));
|
||||
// Be careful here. TimeDelta has a precision of microseconds, but this API
|
||||
// is in milliseconds. If there are 5.5ms left, should the delay be 5 or 6?
|
||||
// It should be 6 to avoid returning too early.
|
||||
double timeout = ceil(max_time.InMillisecondsF());
|
||||
DWORD result = WaitForSingleObject(event_, static_cast<DWORD>(timeout));
|
||||
switch (result) {
|
||||
case WAIT_OBJECT_0:
|
||||
return true;
|
||||
case WAIT_TIMEOUT:
|
||||
return false;
|
||||
}
|
||||
// It is most unexpected that this should ever fail. Help consumers learn
|
||||
// about it if it should ever fail.
|
||||
NOTREACHED() << "WaitForSingleObject failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Copyright (c) 2006-2008 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/waitable_event.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/time.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
|
||||
: event_(CreateEvent(NULL, manual_reset, signaled, NULL)) {
|
||||
// We're probably going to crash anyways if this is ever NULL, so we might as
|
||||
// well make our stack reports more informative by crashing here.
|
||||
CHECK(event_);
|
||||
}
|
||||
|
||||
WaitableEvent::~WaitableEvent() {
|
||||
CloseHandle(event_);
|
||||
}
|
||||
|
||||
void WaitableEvent::Reset() {
|
||||
ResetEvent(event_);
|
||||
}
|
||||
|
||||
void WaitableEvent::Signal() {
|
||||
SetEvent(event_);
|
||||
}
|
||||
|
||||
bool WaitableEvent::IsSignaled() {
|
||||
return TimedWait(TimeDelta::FromMilliseconds(0));
|
||||
}
|
||||
|
||||
bool WaitableEvent::Wait() {
|
||||
DWORD result = WaitForSingleObject(event_, INFINITE);
|
||||
// It is most unexpected that this should ever fail. Help consumers learn
|
||||
// about it if it should ever fail.
|
||||
DCHECK(result == WAIT_OBJECT_0) << "WaitForSingleObject failed";
|
||||
return result == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
|
||||
DCHECK(max_time >= TimeDelta::FromMicroseconds(0));
|
||||
// Be careful here. TimeDelta has a precision of microseconds, but this API
|
||||
// is in milliseconds. If there are 5.5ms left, should the delay be 5 or 6?
|
||||
// It should be 6 to avoid returning too early.
|
||||
double timeout = ceil(max_time.InMillisecondsF());
|
||||
DWORD result = WaitForSingleObject(event_, static_cast<DWORD>(timeout));
|
||||
switch (result) {
|
||||
case WAIT_OBJECT_0:
|
||||
return true;
|
||||
case WAIT_TIMEOUT:
|
||||
return false;
|
||||
}
|
||||
// It is most unexpected that this should ever fail. Help consumers learn
|
||||
// about it if it should ever fail.
|
||||
NOTREACHED() << "WaitForSingleObject failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
|
Reference in New Issue
Block a user