summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorivankr@chromium.org <ivankr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-29 14:00:12 +0000
committerivankr@chromium.org <ivankr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-29 14:00:12 +0000
commit95b42e2745a2380a16112a059bd0e842d81f0c0a (patch)
tree8715285e587b94807bcc70cf135d99bdbec662fb
parent1b14a45ac508a066cc3c060dd37327c3a13a6fda (diff)
downloadchromium_src-95b42e2745a2380a16112a059bd0e842d81f0c0a.zip
chromium_src-95b42e2745a2380a16112a059bd0e842d81f0c0a.tar.gz
chromium_src-95b42e2745a2380a16112a059bd0e842d81f0c0a.tar.bz2
[cros] RlzValueStore made protected by a cross-process lock and not persisted over browser lifetime (like on Mac).
*) Moved RecursiveCrossProcessLock out of .mm file to a common _posix file. *) Added static method to ImportantFileWriter that does blocking write on the current thread. *) Dedicated RLZ thread gone, replaced back with shutdown-blocking worker pool. BUG=157348,62328 Review URL: https://chromiumcodereview.appspot.com/11308196 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170179 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/files/important_file_writer.cc29
-rw-r--r--base/files/important_file_writer.h5
-rw-r--r--chrome/browser/rlz/rlz.cc53
-rw-r--r--chrome/browser/rlz/rlz.h15
-rw-r--r--chrome/browser/rlz/rlz_unittest.cc42
-rw-r--r--rlz/chromeos/lib/rlz_value_store_chromeos.cc253
-rw-r--r--rlz/chromeos/lib/rlz_value_store_chromeos.h55
-rw-r--r--rlz/lib/recursive_cross_process_lock_posix.cc81
-rw-r--r--rlz/lib/recursive_cross_process_lock_posix.h43
-rw-r--r--rlz/lib/recursive_lock.cc40
-rw-r--r--rlz/lib/recursive_lock.h34
-rw-r--r--rlz/lib/recursive_lock_unittest.cc234
-rw-r--r--rlz/lib/rlz_lib.cc14
-rw-r--r--rlz/lib/rlz_lib.h15
-rw-r--r--rlz/lib/rlz_lib_test.cc7
-rw-r--r--rlz/lib/rlz_value_store.h18
-rw-r--r--rlz/mac/lib/rlz_value_store_mac.mm101
-rw-r--r--rlz/rlz.gyp16
-rw-r--r--rlz/test/rlz_test_helpers.cc28
-rw-r--r--rlz/test/rlz_test_helpers.h15
20 files changed, 361 insertions, 737 deletions
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index 536b0fb..351adc2 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -42,7 +42,11 @@ void LogFailure(const FilePath& path, TempFileFailure failure_code,
<< " : " << message;
}
-void WriteToDiskTask(const FilePath& path, const std::string& data) {
+} // namespace
+
+// static
+bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
+ const std::string& data) {
// Write the data to a temp file then rename to avoid data loss if we crash
// while writing the file. Ensure that the temp file is on the same volume
// as target file, so it can be moved in one step, and that the temp file
@@ -50,7 +54,7 @@ void WriteToDiskTask(const FilePath& path, const std::string& data) {
FilePath tmp_file_path;
if (!file_util::CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
LogFailure(path, FAILED_CREATING, "could not create temporary file");
- return;
+ return false;
}
int flags = PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE;
@@ -58,7 +62,7 @@ void WriteToDiskTask(const FilePath& path, const std::string& data) {
CreatePlatformFile(tmp_file_path, flags, NULL, NULL);
if (tmp_file == kInvalidPlatformFileValue) {
LogFailure(path, FAILED_OPENING, "could not open temporary file");
- return;
+ return false;
}
// If this happens in the wild something really bad is going on.
@@ -70,24 +74,24 @@ void WriteToDiskTask(const FilePath& path, const std::string& data) {
if (!ClosePlatformFile(tmp_file)) {
LogFailure(path, FAILED_CLOSING, "failed to close temporary file");
file_util::Delete(tmp_file_path, false);
- return;
+ return false;
}
if (bytes_written < static_cast<int>(data.length())) {
LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" +
IntToString(bytes_written));
file_util::Delete(tmp_file_path, false);
- return;
+ return false;
}
if (!file_util::ReplaceFile(tmp_file_path, path)) {
LogFailure(path, FAILED_RENAMING, "could not rename temporary file");
file_util::Delete(tmp_file_path, false);
- return;
+ return false;
}
-}
-} // namespace
+ return true;
+}
ImportantFileWriter::ImportantFileWriter(
const FilePath& path, base::SequencedTaskRunner* task_runner)
@@ -122,14 +126,17 @@ void ImportantFileWriter::WriteNow(const std::string& data) {
if (HasPendingWrite())
timer_.Stop();
- if (!task_runner_->PostTask(FROM_HERE,
- MakeCriticalClosure(Bind(&WriteToDiskTask, path_, data)))) {
+ if (!task_runner_->PostTask(
+ FROM_HERE,
+ MakeCriticalClosure(
+ Bind(IgnoreResult(&ImportantFileWriter::WriteFileAtomically),
+ path_, data)))) {
// Posting the task to background message loop is not expected
// to fail, but if it does, avoid losing data and just hit the disk
// on the current thread.
NOTREACHED();
- WriteToDiskTask(path_, data);
+ WriteFileAtomically(path_, data);
}
}
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
index ae814d5..9bc8f07 100644
--- a/base/files/important_file_writer.h
+++ b/base/files/important_file_writer.h
@@ -51,6 +51,11 @@ class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
virtual ~DataSerializer() {}
};
+ // Save |data| to |path| in an atomic manner (see the class comment above).
+ // Blocks and writes data on the current thread.
+ static bool WriteFileAtomically(const FilePath& path,
+ const std::string& data);
+
// Initialize the writer.
// |path| is the name of file to write.
// |task_runner| is the SequencedTaskRunner instance where on which we will
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc
index 7005e32..6032dd9 100644
--- a/chrome/browser/rlz/rlz.cc
+++ b/chrome/browser/rlz/rlz.cc
@@ -26,10 +26,6 @@
#include "content/public/browser/notification_service.h"
#include "net/http/http_util.h"
-#if defined(OS_CHROMEOS)
-#include "base/threading/sequenced_worker_pool.h"
-#endif
-
#if defined(OS_WIN)
#include "chrome/installer/util/google_update_settings.h"
#else
@@ -56,8 +52,6 @@ using content::NavigationEntry;
namespace {
-const char kRlzThreadName[] = "RLZ_thread";
-
bool IsBrandOrganic(const std::string& brand) {
return brand.empty() || google_util::IsOrganic(brand);
}
@@ -177,9 +171,6 @@ RLZTracker::RLZTracker()
is_google_default_search_(false),
is_google_homepage_(false),
is_google_in_startpages_(false),
- rlz_thread_(kRlzThreadName),
- blocking_task_runner_(NULL),
- url_request_context_(NULL),
already_ran_(false),
omnibox_used_(false),
homepage_used_(false) {
@@ -208,9 +199,6 @@ bool RLZTracker::Init(bool first_run,
is_google_homepage_ = is_google_homepage;
is_google_in_startpages_ = is_google_in_startpages;
- if (!InitWorkers())
- return false;
-
// A negative delay means that a financial ping should be sent immediately
// after a first search is recorded, without waiting for the next restart
// of chrome. However, we only want this behaviour on first run.
@@ -246,7 +234,7 @@ bool RLZTracker::Init(bool first_run,
content::NotificationService::AllSources());
}
- url_request_context_ = g_browser_process->system_request_context();
+ rlz_lib::SetURLRequestContext(g_browser_process->system_request_context());
ScheduleDelayedInit(delay);
return true;
@@ -255,35 +243,14 @@ bool RLZTracker::Init(bool first_run,
void RLZTracker::ScheduleDelayedInit(int delay) {
// The RLZTracker is a singleton object that outlives any runnable tasks
// that will be queued up.
- blocking_task_runner_->PostDelayedTask(
+ BrowserThread::GetBlockingPool()->PostDelayedTask(
FROM_HERE,
base::Bind(&RLZTracker::DelayedInit, base::Unretained(this)),
base::TimeDelta::FromMilliseconds(delay));
}
-bool RLZTracker::InitWorkers() {
- base::Thread::Options options;
- options.message_loop_type = MessageLoop::TYPE_IO;
- if (!rlz_thread_.StartWithOptions(options))
- return false;
- blocking_task_runner_ = rlz_thread_.message_loop_proxy();
-
-#if defined(OS_CHROMEOS)
- base::SequencedWorkerPool* worker_pool =
- content::BrowserThread::GetBlockingPool();
- if (!worker_pool)
- return false;
- rlz_lib::SetIOTaskRunner(
- worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
- worker_pool->GetSequenceToken(),
- base::SequencedWorkerPool::BLOCK_SHUTDOWN));
-#endif
- return true;
-}
-
void RLZTracker::DelayedInit() {
- if (!already_ran_)
- rlz_lib::SetURLRequestContext(url_request_context_);
+ worker_pool_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
bool schedule_ping = false;
@@ -316,7 +283,8 @@ void RLZTracker::DelayedInit() {
}
void RLZTracker::ScheduleFinancialPing() {
- blocking_task_runner_->PostTask(
+ BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
+ worker_pool_token_,
FROM_HERE,
base::Bind(&RLZTracker::PingNowImpl, base::Unretained(this)));
}
@@ -421,12 +389,13 @@ bool RLZTracker::ScheduleRecordProductEvent(rlz_lib::Product product,
rlz_lib::Event event_id) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
return false;
- if (!blocking_task_runner_) {
+ if (!already_ran_) {
LOG(ERROR) << "Attempted recording RLZ event before RLZ init.";
return true;
}
- blocking_task_runner_->PostTask(
+ BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
+ worker_pool_token_,
FROM_HERE,
base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEvent),
product, point, event_id));
@@ -454,7 +423,8 @@ void RLZTracker::RecordFirstSearch(rlz_lib::AccessPoint point) {
bool RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
return false;
- blocking_task_runner_->PostTask(
+ BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
+ worker_pool_token_,
FROM_HERE,
base::Bind(&RLZTracker::RecordFirstSearch,
base::Unretained(this), point));
@@ -522,7 +492,8 @@ bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) {
return false;
string16* not_used = NULL;
- blocking_task_runner_->PostTask(
+ BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
+ worker_pool_token_,
FROM_HERE,
base::Bind(base::IgnoreResult(&RLZTracker::GetAccessPointRlz), point,
not_used));
diff --git a/chrome/browser/rlz/rlz.h b/chrome/browser/rlz/rlz.h
index 6a1d3c2..e41b5a3 100644
--- a/chrome/browser/rlz/rlz.h
+++ b/chrome/browser/rlz/rlz.h
@@ -15,7 +15,7 @@
#include "base/basictypes.h"
#include "base/memory/singleton.h"
#include "base/string16.h"
-#include "base/threading/thread.h"
+#include "base/threading/sequenced_worker_pool.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "rlz/lib/rlz_lib.h"
@@ -113,10 +113,6 @@ class RLZTracker : public content::NotificationObserver {
bool google_default_homepage,
bool is_google_in_startpages);
- // Initializes task runners for tasks that access RlzValueStore and perform
- // disk I/O.
- virtual bool InitWorkers();
-
// Implementation called from RecordProductEvent() static method.
bool RecordProductEventImpl(rlz_lib::Product product,
rlz_lib::AccessPoint point,
@@ -169,12 +165,9 @@ class RLZTracker : public content::NotificationObserver {
bool is_google_homepage_;
bool is_google_in_startpages_;
- // Dedicated RLZ thread for accessing RlzValueStore and doing I/O.
- base::Thread rlz_thread_;
-
- // Sequenced task runner used to post blocking tasks that access
- // RlzValueStore.
- base::SequencedTaskRunner* blocking_task_runner_;
+ // Unique sequence token so that tasks posted by RLZTracker are executed
+ // sequentially in the blocking pool.
+ base::SequencedWorkerPool::SequenceToken worker_pool_token_;
// URLRequestContextGetter used by RLZ library.
net::URLRequestContextGetter* url_request_context_;
diff --git a/chrome/browser/rlz/rlz_unittest.cc b/chrome/browser/rlz/rlz_unittest.cc
index b1ccca9..165652f 100644
--- a/chrome/browser/rlz/rlz_unittest.cc
+++ b/chrome/browser/rlz/rlz_unittest.cc
@@ -28,12 +28,9 @@
#include "base/test/test_reg_util_win.h"
#include "base/win/registry.h"
#include "rlz/win/lib/rlz_lib.h" // InitializeTempHivesForTesting
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
#include "rlz/lib/rlz_value_store.h" // SetRlzStoreDirectory
#endif
-#if defined(OS_CHROMEOS)
-#include "rlz/chromeos/lib/rlz_value_store_chromeos.h"
-#endif
using content::NavigationEntry;
using testing::AssertionResult;
@@ -119,10 +116,6 @@ class TestRLZTracker : public RLZTracker {
}
private:
- virtual bool InitWorkers() OVERRIDE {
- return true;
- }
-
virtual void ScheduleDelayedInit(int delay) OVERRIDE {
// If the delay is 0, invoke the delayed init now. Otherwise,
// don't schedule anything, it will be manually called during tests.
@@ -172,10 +165,6 @@ class TestRLZTracker : public RLZTracker {
class RlzLibTest : public testing::Test {
public:
-#if defined(OS_CHROMEOS)
- RlzLibTest();
-#endif
-
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
@@ -197,22 +186,12 @@ class RlzLibTest : public testing::Test {
TestRLZTracker tracker_;
#if defined(OS_WIN)
RegistryOverrideManager override_manager_;
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
base::ScopedTempDir temp_dir_;
scoped_ptr<google_util::BrandForTesting> brand_override_;
#endif
-#if defined(OS_CHROMEOS)
- MessageLoop loop_;
- base::Thread io_thread_;
-#endif
};
-#if defined(OS_CHROMEOS)
-RlzLibTest::RlzLibTest()
- : io_thread_("RlzLibTest-io") {
-}
-#endif
-
void RlzLibTest::SetUp() {
testing::Test::SetUp();
@@ -247,19 +226,11 @@ void RlzLibTest::SetUp() {
// initialization performed above.
override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, kRlzTempHklm);
override_manager_.OverrideRegistry(HKEY_CURRENT_USER, kRlzTempHkcu);
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
rlz_lib::testing::SetRlzStoreDirectory(temp_dir_.path());
#endif
-#if defined(OS_CHROMEOS)
- base::Thread::Options options;
- options.message_loop_type = MessageLoop::TYPE_IO;
- ASSERT_TRUE(io_thread_.StartWithOptions(options));
- rlz_lib::SetIOTaskRunner(io_thread_.message_loop_proxy());
- rlz_lib::RlzValueStoreChromeOS::ResetForTesting();
-#endif
-
// Make sure a non-organic brand code is set in the registry or the RLZTracker
// is pretty much a no-op.
SetMainBrand("TEST");
@@ -267,19 +238,16 @@ void RlzLibTest::SetUp() {
}
void RlzLibTest::TearDown() {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
rlz_lib::testing::SetRlzStoreDirectory(FilePath());
#endif
-#if defined(OS_CHROMEOS)
- io_thread_.Stop();
-#endif // defined(OS_CHROMEOS)
testing::Test::TearDown();
}
void RlzLibTest::SetMainBrand(const char* brand) {
#if defined(OS_WIN)
SetRegistryBrandValue(google_update::kRegRLZBrandField, brand);
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
brand_override_.reset(new google_util::BrandForTesting(brand));
#endif
std::string check_brand;
diff --git a/rlz/chromeos/lib/rlz_value_store_chromeos.cc b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
index ddf73e7..bb9c431 100644
--- a/rlz/chromeos/lib/rlz_value_store_chromeos.cc
+++ b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
@@ -4,16 +4,16 @@
#include "rlz/chromeos/lib/rlz_value_store_chromeos.h"
-#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/prefs/json_pref_store.h"
#include "base/sequenced_task_runner.h"
#include "base/string_number_conversions.h"
#include "base/values.h"
#include "rlz/lib/lib_values.h"
-#include "rlz/lib/recursive_lock.h"
+#include "rlz/lib/recursive_cross_process_lock_posix.h"
#include "rlz/lib/rlz_lib.h"
namespace rlz_lib {
@@ -36,6 +36,10 @@ const char kNoSupplementaryBrand[] = "_";
// RLZ store filename.
const FilePath::CharType kRLZDataFileName[] = FILE_PATH_LITERAL("RLZ Data");
+// RLZ store lock filename
+const FilePath::CharType kRLZLockFileName[] =
+ FILE_PATH_LITERAL("RLZ Data.lock");
+
// RLZ store path for testing.
FilePath g_testing_rlz_store_path_;
@@ -46,6 +50,13 @@ FilePath GetRlzStorePath() {
g_testing_rlz_store_path_.Append(kRLZDataFileName);
}
+// Returns file path of the RLZ storage lock file.
+FilePath GetRlzStoreLockPath() {
+ return g_testing_rlz_store_path_.empty() ?
+ file_util::GetHomeDir().Append(kRLZLockFileName) :
+ g_testing_rlz_store_path_.Append(kRLZLockFileName);
+}
+
// Returns the dictionary key for storing access point-related prefs.
std::string GetKeyName(std::string key, AccessPoint access_point) {
std::string brand = SupplementaryBranding::GetBrand();
@@ -64,89 +75,58 @@ std::string GetKeyName(std::string key, Product product) {
} // namespace
-// static
-base::SequencedTaskRunner* RlzValueStoreChromeOS::io_task_runner_ = NULL;
-
-// static
-bool RlzValueStoreChromeOS::created_;
-
-// static
-RlzValueStoreChromeOS* RlzValueStoreChromeOS::GetInstance() {
- return Singleton<RlzValueStoreChromeOS>::get();
-}
-
-// static
-void RlzValueStoreChromeOS::SetIOTaskRunner(
- base::SequencedTaskRunner* io_task_runner) {
- io_task_runner_ = io_task_runner;
- // Make sure |io_task_runner_| lives until constructor is called.
- io_task_runner_->AddRef();
-}
-
-// static
-void RlzValueStoreChromeOS::ResetForTesting() {
- // Make sure we don't create an instance if it didn't exist.
- if (created_)
- GetInstance()->ReadPrefs();
-}
-
-// static
-void RlzValueStoreChromeOS::Cleanup() {
- if (created_)
- GetInstance()->rlz_store_ = NULL;
-}
-
-RlzValueStoreChromeOS::RlzValueStoreChromeOS() {
- ReadPrefs();
- created_ = true;
+RlzValueStoreChromeOS::RlzValueStoreChromeOS(const FilePath& store_path)
+ : rlz_store_(new base::DictionaryValue),
+ store_path_(store_path),
+ read_only_(true) {
+ ReadStore();
}
RlzValueStoreChromeOS::~RlzValueStoreChromeOS() {
+ WriteStore();
}
bool RlzValueStoreChromeOS::HasAccess(AccessType type) {
- return type == kReadAccess || !rlz_store_->ReadOnly();
+ DCHECK(CalledOnValidThread());
+ return type == kReadAccess || !read_only_;
}
bool RlzValueStoreChromeOS::WritePingTime(Product product, int64 time) {
- std::string value = base::Int64ToString(time);
- rlz_store_->SetValue(GetKeyName(kPingTimeKey, product),
- base::Value::CreateStringValue(value));
+ DCHECK(CalledOnValidThread());
+ rlz_store_->SetString(GetKeyName(kPingTimeKey, product),
+ base::Int64ToString(time));
return true;
}
bool RlzValueStoreChromeOS::ReadPingTime(Product product, int64* time) {
- const base::Value* value = NULL;
- rlz_store_->GetValue(GetKeyName(kPingTimeKey, product), &value);
- std::string s_value;
- return value && value->GetAsString(&s_value) &&
- base::StringToInt64(s_value, time);
+ DCHECK(CalledOnValidThread());
+ std::string ping_time;
+ return rlz_store_->GetString(GetKeyName(kPingTimeKey, product), &ping_time) &&
+ base::StringToInt64(ping_time, time);
}
bool RlzValueStoreChromeOS::ClearPingTime(Product product) {
- rlz_store_->RemoveValue(GetKeyName(kPingTimeKey, product));
+ DCHECK(CalledOnValidThread());
+ rlz_store_->Remove(GetKeyName(kPingTimeKey, product), NULL);
return true;
}
bool RlzValueStoreChromeOS::WriteAccessPointRlz(AccessPoint access_point,
const char* new_rlz) {
- rlz_store_->SetValue(
- GetKeyName(kAccessPointKey, access_point),
- base::Value::CreateStringValue(new_rlz));
+ DCHECK(CalledOnValidThread());
+ rlz_store_->SetString(
+ GetKeyName(kAccessPointKey, access_point), new_rlz);
return true;
}
bool RlzValueStoreChromeOS::ReadAccessPointRlz(AccessPoint access_point,
char* rlz,
size_t rlz_size) {
- const base::Value* value = NULL;
- rlz_store_->GetValue(
- GetKeyName(kAccessPointKey, access_point), &value);
- std::string s_value;
- if (value)
- value->GetAsString(&s_value);
- if (s_value.size() < rlz_size) {
- strncpy(rlz, s_value.c_str(), rlz_size);
+ DCHECK(CalledOnValidThread());
+ std::string rlz_value;
+ rlz_store_->GetString(GetKeyName(kAccessPointKey, access_point), &rlz_value);
+ if (rlz_value.size() < rlz_size) {
+ strncpy(rlz, rlz_value.c_str(), rlz_size);
return true;
}
if (rlz_size > 0)
@@ -155,13 +135,14 @@ bool RlzValueStoreChromeOS::ReadAccessPointRlz(AccessPoint access_point,
}
bool RlzValueStoreChromeOS::ClearAccessPointRlz(AccessPoint access_point) {
- rlz_store_->RemoveValue(
- GetKeyName(kAccessPointKey, access_point));
+ DCHECK(CalledOnValidThread());
+ rlz_store_->Remove(GetKeyName(kAccessPointKey, access_point), NULL);
return true;
}
bool RlzValueStoreChromeOS::AddProductEvent(Product product,
const char* event_rlz) {
+ DCHECK(CalledOnValidThread());
return AddValueToList(GetKeyName(kProductEventKey, product),
base::Value::CreateStringValue(event_rlz));
}
@@ -169,8 +150,9 @@ bool RlzValueStoreChromeOS::AddProductEvent(Product product,
bool RlzValueStoreChromeOS::ReadProductEvents(
Product product,
std::vector<std::string>* events) {
- base::ListValue* events_list = GetList(GetKeyName(kProductEventKey, product));
- if (!events_list)
+ DCHECK(CalledOnValidThread());
+ base::ListValue* events_list = NULL; ;
+ if (!rlz_store_->GetList(GetKeyName(kProductEventKey, product), &events_list))
return false;
events->clear();
for (size_t i = 0; i < events_list->GetSize(); ++i) {
@@ -183,99 +165,162 @@ bool RlzValueStoreChromeOS::ReadProductEvents(
bool RlzValueStoreChromeOS::ClearProductEvent(Product product,
const char* event_rlz) {
+ DCHECK(CalledOnValidThread());
base::StringValue event_value(event_rlz);
return RemoveValueFromList(GetKeyName(kProductEventKey, product),
event_value);
}
bool RlzValueStoreChromeOS::ClearAllProductEvents(Product product) {
- rlz_store_->RemoveValue(GetKeyName(kProductEventKey, product));
+ DCHECK(CalledOnValidThread());
+ rlz_store_->Remove(GetKeyName(kProductEventKey, product), NULL);
return true;
}
bool RlzValueStoreChromeOS::AddStatefulEvent(Product product,
const char* event_rlz) {
+ DCHECK(CalledOnValidThread());
return AddValueToList(GetKeyName(kStatefulEventKey, product),
base::Value::CreateStringValue(event_rlz));
}
bool RlzValueStoreChromeOS::IsStatefulEvent(Product product,
const char* event_rlz) {
- base::ListValue* events_list =
- GetList(GetKeyName(kStatefulEventKey, product));
+ DCHECK(CalledOnValidThread());
base::StringValue event_value(event_rlz);
- return events_list && events_list->Find(event_value) != events_list->end();
+ base::ListValue* events_list = NULL;
+ return rlz_store_->GetList(GetKeyName(kStatefulEventKey, product),
+ &events_list) &&
+ events_list->Find(event_value) != events_list->end();
}
bool RlzValueStoreChromeOS::ClearAllStatefulEvents(Product product) {
- rlz_store_->RemoveValue(GetKeyName(kStatefulEventKey, product));
+ DCHECK(CalledOnValidThread());
+ rlz_store_->Remove(GetKeyName(kStatefulEventKey, product), NULL);
return true;
}
void RlzValueStoreChromeOS::CollectGarbage() {
+ DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
-void RlzValueStoreChromeOS::ReadPrefs() {
- DCHECK(io_task_runner_)
- << "Calling GetInstance or ResetForTesting before SetIOTaskRunner?";
- rlz_store_ = new JsonPrefStore(GetRlzStorePath(), io_task_runner_);
- rlz_store_->ReadPrefs();
- switch (rlz_store_->GetReadError()) {
- case PersistentPrefStore::PREF_READ_ERROR_NONE:
- case PersistentPrefStore::PREF_READ_ERROR_NO_FILE:
+void RlzValueStoreChromeOS::ReadStore() {
+ int error_code = 0;
+ std::string error_msg;
+ JSONFileValueSerializer serializer(store_path_);
+ scoped_ptr<base::Value> value(
+ serializer.Deserialize(&error_code, &error_msg));
+ switch (error_code) {
+ case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
+ read_only_ = false;
+ break;
+ case JSONFileValueSerializer::JSON_NO_ERROR:
+ read_only_ = false;
+ rlz_store_.reset(static_cast<base::DictionaryValue*>(value.release()));
break;
default:
- LOG(ERROR) << "Error read RLZ store: " << rlz_store_->GetReadError();
+ LOG(ERROR) << "Error reading RLZ store: " << error_msg;
}
- // Restore refcount modified by SetIOTaskRunner().
- io_task_runner_->Release();
- io_task_runner_ = NULL;
}
-base::ListValue* RlzValueStoreChromeOS::GetList(std::string list_name) {
- base::Value* list_value = NULL;
- rlz_store_->GetMutableValue(list_name, &list_value);
- base::ListValue* list = NULL;
- if (!list_value || !list_value->GetAsList(&list))
- return NULL;
- return list;
+void RlzValueStoreChromeOS::WriteStore() {
+ std::string json_data;
+ JSONStringValueSerializer serializer(&json_data);
+ serializer.set_pretty_print(true);
+ scoped_ptr<DictionaryValue> copy(rlz_store_->DeepCopyWithoutEmptyChildren());
+ if (!serializer.Serialize(*copy.get())) {
+ LOG(ERROR) << "Failed to serialize RLZ data";
+ NOTREACHED();
+ return;
+ }
+ if (!base::ImportantFileWriter::WriteFileAtomically(store_path_, json_data))
+ LOG(ERROR) << "Error writing RLZ store";
}
bool RlzValueStoreChromeOS::AddValueToList(std::string list_name,
base::Value* value) {
- base::ListValue* list = GetList(list_name);
- if (!list) {
- list = new base::ListValue;
- rlz_store_->SetValue(list_name, list);
+ base::ListValue* list_value = NULL;
+ if (!rlz_store_->GetList(list_name, &list_value)) {
+ list_value = new base::ListValue;
+ rlz_store_->Set(list_name, list_value);
}
- if (list->AppendIfNotPresent(value))
- rlz_store_->ReportValueChanged(list_name);
+ list_value->AppendIfNotPresent(value);
return true;
}
bool RlzValueStoreChromeOS::RemoveValueFromList(std::string list_name,
const base::Value& value) {
- base::ListValue* list = GetList(list_name);
- if (!list)
+ base::ListValue* list_value = NULL;
+ if (!rlz_store_->GetList(list_name, &list_value))
return false;
- rlz_store_->MarkNeedsEmptyValue(list_name);
size_t index;
- if (list->Remove(value, &index))
- rlz_store_->ReportValueChanged(list_name);
+ list_value->Remove(value, &index);
return true;
}
+namespace {
-ScopedRlzValueStoreLock::ScopedRlzValueStoreLock()
- : store_(RlzValueStoreChromeOS::GetInstance()) {
+// RlzValueStoreChromeOS keeps its data in memory and only writes it to disk
+// when ScopedRlzValueStoreLock goes out of scope. Hence, if several
+// ScopedRlzValueStoreLocks are nested, they all need to use the same store
+// object.
+
+RecursiveCrossProcessLock g_recursive_lock =
+ RECURSIVE_CROSS_PROCESS_LOCK_INITIALIZER;
+
+// This counts the nesting depth of |ScopedRlzValueStoreLock|.
+int g_lock_depth = 0;
+
+// This is the shared store object. Non-|NULL| only when |g_lock_depth > 0|.
+RlzValueStoreChromeOS* g_store = NULL;
+
+} // namespace
+
+ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
+ bool got_cross_process_lock =
+ g_recursive_lock.TryGetCrossProcessLock(GetRlzStoreLockPath());
+ // At this point, we hold the in-process lock, no matter the value of
+ // |got_cross_process_lock|.
+
+ ++g_lock_depth;
+ if (!got_cross_process_lock) {
+ // Acquiring cross-process lock failed, so simply return here.
+ // In-process lock will be released in dtor.
+ DCHECK(!g_store);
+ return;
+ }
+
+ if (g_lock_depth > 1) {
+ // Reuse the already existing store object.
+ DCHECK(g_store);
+ store_.reset(g_store);
+ return;
+ }
+
+ // This is the topmost lock, create a new store object.
+ DCHECK(!g_store);
+ g_store = new RlzValueStoreChromeOS(GetRlzStorePath());
+ store_.reset(g_store);
}
ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() {
+ --g_lock_depth;
+ DCHECK(g_lock_depth >= 0);
+
+ if (g_lock_depth > 0) {
+ // Other locks are still using store_, so don't free it yet.
+ ignore_result(store_.release());
+ return;
+ }
+
+ g_store = NULL;
+
+ g_recursive_lock.ReleaseLock();
}
RlzValueStore* ScopedRlzValueStoreLock::GetStore() {
- return store_;
+ return store_.get();
}
namespace testing {
@@ -284,6 +329,10 @@ void SetRlzStoreDirectory(const FilePath& directory) {
g_testing_rlz_store_path_ = directory;
}
+std::string RlzStoreFilenameStr() {
+ return GetRlzStorePath().value();
+}
+
} // namespace testing
} // namespace rlz_lib
diff --git a/rlz/chromeos/lib/rlz_value_store_chromeos.h b/rlz/chromeos/lib/rlz_value_store_chromeos.h
index c9456a8..4760418 100644
--- a/rlz/chromeos/lib/rlz_value_store_chromeos.h
+++ b/rlz/chromeos/lib/rlz_value_store_chromeos.h
@@ -5,8 +5,9 @@
#ifndef RLZ_CHROMEOS_LIB_RLZ_VALUE_STORE_CHROMEOS_H_
#define RLZ_CHROMEOS_LIB_RLZ_VALUE_STORE_CHROMEOS_H_
-#include "base/prefs/persistent_pref_store.h"
+#include "base/file_path.h"
#include "base/threading/non_thread_safe.h"
+#include "base/values.h"
#include "rlz/lib/rlz_value_store.h"
namespace base {
@@ -15,28 +16,19 @@ class SequencedTaskRunner;
class Value;
}
-template <typename T> struct DefaultSingletonTraits;
-
namespace rlz_lib {
-// An implementation of RlzValueStore for ChromeOS. Unlike Mac and Win
-// counterparts, it's non thread-safe and should only be accessed on a single
-// Thread instance that has a MessageLoop.
-class RlzValueStoreChromeOS : public RlzValueStore {
+// An implementation of RlzValueStore for ChromeOS.
+class RlzValueStoreChromeOS : public RlzValueStore,
+ public base::NonThreadSafe {
public:
- static RlzValueStoreChromeOS* GetInstance();
-
- // Sets the MessageLoopProxy that underlying PersistentPrefStore will post I/O
- // tasks to. Must be called before the first GetInstance() call.
- static void SetIOTaskRunner(base::SequencedTaskRunner* io_task_runner);
-
- // Must be invoked during shutdown to commit pending I/O.
- static void Cleanup();
+ // // Sets the task runner that will be used by ImportantFileWriter for write
+ // // operations.
+ // static void SetFileTaskRunner(base::SequencedTaskRunner* file_task_runner);
- // Resets the store to its initial state. Should only be used for testing.
- // Same restrictions as for calling GetInstance() for the first time apply,
- // i.e. must call SetIOTaskRunner first.
- static void ResetForTesting();
+ // Creates new instance and synchronously reads data from file.
+ RlzValueStoreChromeOS(const FilePath& store_path);
+ virtual ~RlzValueStoreChromeOS();
// RlzValueStore overrides:
virtual bool HasAccess(AccessType type) OVERRIDE;
@@ -68,28 +60,23 @@ class RlzValueStoreChromeOS : public RlzValueStore {
virtual void CollectGarbage() OVERRIDE;
private:
- friend struct DefaultSingletonTraits<RlzValueStoreChromeOS>;
-
- // Used by JsonPrefStore for write operations.
- static base::SequencedTaskRunner* io_task_runner_;
+ // Reads RLZ store from file.
+ void ReadStore();
- static bool created_;
+ // Writes RLZ store back to file.
+ void WriteStore();
- RlzValueStoreChromeOS();
- virtual ~RlzValueStoreChromeOS();
-
- // Initializes RLZ store.
- void ReadPrefs();
-
- // Retrieves list at path |list_name| from JSON store.
- base::ListValue* GetList(std::string list_name);
// Adds |value| to list at |list_name| path in JSON store.
bool AddValueToList(std::string list_name, base::Value* value);
// Removes |value| from list at |list_name| path in JSON store.
bool RemoveValueFromList(std::string list_name, const base::Value& value);
- // Store with RLZ data.
- scoped_refptr<PersistentPrefStore> rlz_store_;
+ // In-memory store with RLZ data.
+ scoped_ptr<base::DictionaryValue> rlz_store_;
+
+ FilePath store_path_;
+
+ bool read_only_;
DISALLOW_COPY_AND_ASSIGN(RlzValueStoreChromeOS);
};
diff --git a/rlz/lib/recursive_cross_process_lock_posix.cc b/rlz/lib/recursive_cross_process_lock_posix.cc
new file mode 100644
index 0000000..071bf8c
--- /dev/null
+++ b/rlz/lib/recursive_cross_process_lock_posix.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "rlz/lib/recursive_cross_process_lock_posix.h"
+
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace rlz_lib {
+
+bool RecursiveCrossProcessLock::TryGetCrossProcessLock(
+ const FilePath& lock_filename) {
+ bool just_got_lock = false;
+
+ // Emulate a recursive mutex with a non-recursive one.
+ if (pthread_mutex_trylock(&recursive_lock_) == EBUSY) {
+ if (pthread_equal(pthread_self(), locking_thread_) == 0) {
+ // Some other thread has the lock, wait for it.
+ pthread_mutex_lock(&recursive_lock_);
+ CHECK(locking_thread_ == 0);
+ just_got_lock = true;
+ }
+ } else {
+ just_got_lock = true;
+ }
+
+ locking_thread_ = pthread_self();
+
+ // Try to acquire file lock.
+ if (just_got_lock) {
+ const int kMaxTimeoutMS = 5000; // Matches Windows.
+ const int kSleepPerTryMS = 200;
+
+ CHECK(file_lock_ == -1);
+ file_lock_ = open(lock_filename.value().c_str(), O_RDWR | O_CREAT, 0666);
+ if (file_lock_ == -1) {
+ perror("open");
+ return false;
+ }
+
+ int flock_result = -1;
+ int elapsed_ms = 0;
+ while ((flock_result =
+ HANDLE_EINTR(flock(file_lock_, LOCK_EX | LOCK_NB))) == -1 &&
+ errno == EWOULDBLOCK &&
+ elapsed_ms < kMaxTimeoutMS) {
+ usleep(kSleepPerTryMS * 1000);
+ elapsed_ms += kSleepPerTryMS;
+ }
+
+ if (flock_result == -1) {
+ perror("flock");
+ ignore_result(HANDLE_EINTR(close(file_lock_)));
+ file_lock_ = -1;
+ return false;
+ }
+ return true;
+ } else {
+ return file_lock_ != -1;
+ }
+}
+
+void RecursiveCrossProcessLock::ReleaseLock() {
+ if (file_lock_ != -1) {
+ ignore_result(HANDLE_EINTR(flock(file_lock_, LOCK_UN)));
+ ignore_result(HANDLE_EINTR(close(file_lock_)));
+ file_lock_ = -1;
+ }
+
+ locking_thread_ = 0;
+ pthread_mutex_unlock(&recursive_lock_);
+}
+
+} // namespace rlz_lib
diff --git a/rlz/lib/recursive_cross_process_lock_posix.h b/rlz/lib/recursive_cross_process_lock_posix.h
new file mode 100644
index 0000000..a39d473
--- /dev/null
+++ b/rlz/lib/recursive_cross_process_lock_posix.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef RLZ_LIB_RECURSIVE_CROSS_PROCESS_LOCK_POSIX_H_
+#define RLZ_LIB_RECURSIVE_CROSS_PROCESS_LOCK_POSIX_H_
+
+#include <pthread.h>
+
+class FilePath;
+
+namespace rlz_lib {
+
+// Creating a recursive cross-process mutex on Windows is one line. On POSIX,
+// there's no primitive for that, so this lock is emulated by an in-process
+// mutex to get the recursive part, followed by a cross-process lock for the
+// cross-process part.
+// This is a struct so that it doesn't need a static initializer.
+struct RecursiveCrossProcessLock {
+ // Tries to acquire a recursive cross-process lock. Note that this _always_
+ // acquires the in-process lock (if it wasn't already acquired). The parent
+ // directory of |lock_file| must exist.
+ bool TryGetCrossProcessLock(const FilePath& lock_filename);
+
+ // Releases the lock. Should always be called, even if
+ // TryGetCrossProcessLock() returned |false|.
+ void ReleaseLock();
+
+ pthread_mutex_t recursive_lock_;
+ pthread_t locking_thread_;
+
+ int file_lock_;
+};
+
+// On Mac, PTHREAD_RECURSIVE_MUTEX_INITIALIZER doesn't exist before 10.7 and
+// is buggy on 10.7 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51906#c34),
+// so emulate recursive locking with a normal non-recursive mutex.
+#define RECURSIVE_CROSS_PROCESS_LOCK_INITIALIZER \
+ { PTHREAD_MUTEX_INITIALIZER, 0, -1 }
+
+} // namespace rlz_lib
+
+#endif // RLZ_LIB_RECURSIVE_CROSS_PROCESS_LOCK_POSIX_H_
diff --git a/rlz/lib/recursive_lock.cc b/rlz/lib/recursive_lock.cc
deleted file mode 100644
index 686cf0e..0000000
--- a/rlz/lib/recursive_lock.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "rlz/lib/recursive_lock.h"
-
-#include "base/logging.h"
-
-namespace rlz_lib {
-
-RecursiveLock::RecursiveLock()
- : owner_(),
- recursion_() {
-}
-
-RecursiveLock::~RecursiveLock() {
-}
-
-void RecursiveLock::Acquire() {
- base::subtle::Atomic32 me = base::PlatformThread::CurrentId();
- if (me != base::subtle::NoBarrier_Load(&owner_)) {
- lock_.Acquire();
- DCHECK(!recursion_);
- DCHECK(!owner_);
- base::subtle::NoBarrier_Store(&owner_, me);
- }
- ++recursion_;
-}
-
-void RecursiveLock::Release() {
- DCHECK_EQ(base::subtle::NoBarrier_Load(&owner_),
- base::PlatformThread::CurrentId());
- DCHECK_GT(recursion_, 0);
- if (!--recursion_) {
- base::subtle::NoBarrier_Store(&owner_, 0);
- lock_.Release();
- }
-}
-
-} // namespace rlz_lib
diff --git a/rlz/lib/recursive_lock.h b/rlz/lib/recursive_lock.h
deleted file mode 100644
index 43c95747..0000000
--- a/rlz/lib/recursive_lock.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
-#define RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
-
-#include "base/atomicops.h"
-#include "base/basictypes.h"
-#include "base/synchronization/lock.h"
-
-namespace rlz_lib {
-
-
-class RecursiveLock {
- public:
- RecursiveLock();
- ~RecursiveLock();
-
- void Acquire();
- void Release();
-
- private:
- // Underlying non-recursive lock.
- base::Lock lock_;
- // Owner thread ID.
- base::subtle::Atomic32 owner_;
- // Recursion lock depth.
- int recursion_;
-};
-
-} // namespace rlz_lib
-
-#endif // RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
diff --git a/rlz/lib/recursive_lock_unittest.cc b/rlz/lib/recursive_lock_unittest.cc
deleted file mode 100644
index 916af7f..0000000
--- a/rlz/lib/recursive_lock_unittest.cc
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "rlz/lib/recursive_lock.h"
-
-#include <stdlib.h>
-
-#include "base/compiler_specific.h"
-#include "base/threading/platform_thread.h"
-#include "base/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::kNullThreadHandle;
-using base::PlatformThread;
-using base::PlatformThreadHandle;
-using base::TimeDelta;
-
-namespace rlz_lib {
-
-// Basic test to make sure that Acquire()/Release() don't crash.
-class BasicLockTestThread : public PlatformThread::Delegate {
- public:
- BasicLockTestThread(RecursiveLock* lock) : lock_(lock), acquired_(0) {}
-
- virtual void ThreadMain() OVERRIDE {
- for (int i = 0; i < 10; i++) {
- lock_->Acquire();
- acquired_++;
- lock_->Release();
- }
- for (int i = 0; i < 10; i++) {
- lock_->Acquire();
- acquired_++;
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
- lock_->Release();
- }
- }
-
- int acquired() const { return acquired_; }
-
- private:
- RecursiveLock* lock_;
- int acquired_;
-
- DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
-};
-
-TEST(RecursiveLockTest, Basic) {
- RecursiveLock lock;
- BasicLockTestThread thread(&lock);
- PlatformThreadHandle handle = kNullThreadHandle;
-
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-
- int acquired = 0;
- for (int i = 0; i < 5; i++) {
- lock.Acquire();
- acquired++;
- lock.Release();
- }
- for (int i = 0; i < 10; i++) {
- lock.Acquire();
- acquired++;
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
- lock.Release();
- }
- for (int i = 0; i < 5; i++) {
- lock.Acquire();
- acquired++;
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
- lock.Release();
- }
-
- PlatformThread::Join(handle);
-
- EXPECT_EQ(acquired, 20);
- EXPECT_EQ(thread.acquired(), 20);
-}
-
-// Tests that locks are actually exclusive.
-class MutexLockTestThread : public PlatformThread::Delegate {
- public:
- MutexLockTestThread(RecursiveLock* lock, int* value)
- : lock_(lock),
- value_(value) {
- }
-
- // Static helper which can also be called from the main thread.
- static void DoStuff(RecursiveLock* lock, int* value) {
- for (int i = 0; i < 40; i++) {
- lock->Acquire();
- int v = *value;
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
- *value = v + 1;
- lock->Release();
- }
- }
-
- virtual void ThreadMain() OVERRIDE {
- DoStuff(lock_, value_);
- }
-
- private:
- RecursiveLock* lock_;
- int* value_;
-
- DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
-};
-
-TEST(RecursiveLockTest, MutexTwoThreads) {
- RecursiveLock lock;
- int value = 0;
-
- MutexLockTestThread thread(&lock, &value);
- PlatformThreadHandle handle = kNullThreadHandle;
-
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-
- MutexLockTestThread::DoStuff(&lock, &value);
-
- PlatformThread::Join(handle);
-
- EXPECT_EQ(2 * 40, value);
-}
-
-TEST(RecursiveLockTest, MutexFourThreads) {
- RecursiveLock lock;
- int value = 0;
-
- MutexLockTestThread thread1(&lock, &value);
- MutexLockTestThread thread2(&lock, &value);
- MutexLockTestThread thread3(&lock, &value);
- PlatformThreadHandle handle1 = kNullThreadHandle;
- PlatformThreadHandle handle2 = kNullThreadHandle;
- PlatformThreadHandle handle3 = kNullThreadHandle;
-
- ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
- ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
- ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
-
- MutexLockTestThread::DoStuff(&lock, &value);
-
- PlatformThread::Join(handle1);
- PlatformThread::Join(handle2);
- PlatformThread::Join(handle3);
-
- EXPECT_EQ(4 * 40, value);
-}
-
-// Tests that locks are recursive.
-class MutexRecursiveLockTestThread : public PlatformThread::Delegate {
- public:
- MutexRecursiveLockTestThread(RecursiveLock* lock, int* value)
- : lock_(lock),
- value_(value) {
- }
-
- // Static helper which can also be called from the main thread.
- static void DoStuff(RecursiveLock* lock, int* value) {
- for (int i = 0; i < 20; i++) {
- // First lock.
- lock->Acquire();
- int v = *value;
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
- *value = v + 1;
- {
- // Recursive lock.
- lock->Acquire();
- int v = *value;
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
- *value = v + 1;
- lock->Release();
- }
- v = *value;
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
- *value = v + 1;
- lock->Release();
- }
- }
-
- virtual void ThreadMain() OVERRIDE {
- DoStuff(lock_, value_);
- }
-
- private:
- RecursiveLock* lock_;
- int* value_;
-
- DISALLOW_COPY_AND_ASSIGN(MutexRecursiveLockTestThread);
-};
-
-
-TEST(RecursiveLockTest, MutexTwoThreadsRecursive) {
- RecursiveLock lock;
- int value = 0;
-
- MutexRecursiveLockTestThread thread(&lock, &value);
- PlatformThreadHandle handle = kNullThreadHandle;
-
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-
- MutexRecursiveLockTestThread::DoStuff(&lock, &value);
-
- PlatformThread::Join(handle);
-
- EXPECT_EQ(2 * 60, value);
-}
-
-TEST(RecursiveLockTest, MutexFourThreadsRecursive) {
- RecursiveLock lock;
- int value = 0;
-
- MutexRecursiveLockTestThread thread1(&lock, &value);
- MutexRecursiveLockTestThread thread2(&lock, &value);
- MutexRecursiveLockTestThread thread3(&lock, &value);
- PlatformThreadHandle handle1 = kNullThreadHandle;
- PlatformThreadHandle handle2 = kNullThreadHandle;
- PlatformThreadHandle handle3 = kNullThreadHandle;
-
- ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
- ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
- ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
-
- MutexRecursiveLockTestThread::DoStuff(&lock, &value);
-
- PlatformThread::Join(handle1);
- PlatformThread::Join(handle2);
- PlatformThread::Join(handle3);
-
- EXPECT_EQ(4 * 60, value);
-}
-
-} // namespace rlz_lib
diff --git a/rlz/lib/rlz_lib.cc b/rlz/lib/rlz_lib.cc
index a820d27..8a1b729 100644
--- a/rlz/lib/rlz_lib.cc
+++ b/rlz/lib/rlz_lib.cc
@@ -16,10 +16,6 @@
#include "rlz/lib/rlz_value_store.h"
#include "rlz/lib/string_utils.h"
-#if defined(OS_CHROMEOS)
-#include "rlz/chromeos/lib/rlz_value_store_chromeos.h"
-#endif // defined(OS_CHROMEOS)
-
namespace {
// Event information returned from ping response.
@@ -218,16 +214,6 @@ bool SetURLRequestContext(net::URLRequestContextGetter* context) {
}
#endif
-#if defined(OS_CHROMEOS)
-void RLZ_LIB_API SetIOTaskRunner(base::SequencedTaskRunner* io_task_runner) {
- RlzValueStoreChromeOS::SetIOTaskRunner(io_task_runner);
-}
-
-void RLZ_LIB_API CleanupRlz() {
- RlzValueStoreChromeOS::Cleanup();
-}
-#endif
-
bool GetProductEventsAsCgi(Product product, char* cgi, size_t cgi_size) {
if (!cgi || cgi_size <= 0) {
ASSERT_STRING("GetProductEventsAsCgi: Invalid buffer");
diff --git a/rlz/lib/rlz_lib.h b/rlz/lib/rlz_lib.h
index 956fc9e..1f8be5c 100644
--- a/rlz/lib/rlz_lib.h
+++ b/rlz/lib/rlz_lib.h
@@ -44,12 +44,6 @@
#endif
#endif
-#if defined(OS_CHROMEOS)
-namespace base {
-class SequencedTaskRunner;
-} // namespace base
-#endif
-
#if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
namespace net {
class URLRequestContextGetter;
@@ -77,15 +71,6 @@ const size_t kMaxPingResponseLength = 0x4000; // 16K
bool RLZ_LIB_API SetURLRequestContext(net::URLRequestContextGetter* context);
#endif
-#if defined(OS_CHROMEOS)
-// Set the MessageLoopProxy used by RLZ store to run I/O tasks on. Should be
-// called before any other API calls.
-void RLZ_LIB_API SetIOTaskRunner(base::SequencedTaskRunner* io_task_runner);
-
-// Must be invoked during shutdown to finish any remaining tasks.
-void RLZ_LIB_API CleanupRlz();
-#endif
-
// RLZ storage functions.
// Get all the events reported by this product as a CGI string to append to
diff --git a/rlz/lib/rlz_lib_test.cc b/rlz/lib/rlz_lib_test.cc
index 338473b..86e659c 100644
--- a/rlz/lib/rlz_lib_test.cc
+++ b/rlz/lib/rlz_lib_test.cc
@@ -788,7 +788,7 @@ TEST_F(RlzLibTest, BrandingWithStatefulEvents) {
EXPECT_STREQ("events=I7S", value);
}
-#if defined(OS_MACOSX)
+#if defined(OS_POSIX)
class ReadonlyRlzDirectoryTest : public RlzLibTestNoMachineState {
protected:
virtual void SetUp() OVERRIDE;
@@ -799,7 +799,6 @@ void ReadonlyRlzDirectoryTest::SetUp() {
// Make the rlz directory non-writeable.
int chmod_result = chmod(temp_dir_.path().value().c_str(), 0500);
ASSERT_EQ(0, chmod_result);
-
}
TEST_F(ReadonlyRlzDirectoryTest, WriteFails) {
@@ -873,7 +872,7 @@ TEST_F(RlzLibTest, ConcurrentStoreAccessWithProcessExitsWhileLockHeld) {
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL));
}
-TEST_F(RlzLibTest, LockAcquistionSucceedsButPlistCannotBeCreated) {
+TEST_F(RlzLibTest, LockAcquistionSucceedsButStoreFileCannotBeCreated) {
// See the comment at the top of WriteFails.
if (!rlz_lib::SupplementaryBranding::GetBrand().empty())
return;
@@ -881,7 +880,7 @@ TEST_F(RlzLibTest, LockAcquistionSucceedsButPlistCannotBeCreated) {
// Create a directory where the rlz file is supposed to appear. This way,
// the lock file can be created successfully, but creation of the rlz file
// itself will fail.
- int mkdir_result = mkdir(rlz_lib::testing::RlzPlistFilenameStr().c_str(),
+ int mkdir_result = mkdir(rlz_lib::testing::RlzStoreFilenameStr().c_str(),
0500);
ASSERT_EQ(0, mkdir_result);
diff --git a/rlz/lib/rlz_value_store.h b/rlz/lib/rlz_value_store.h
index 807f100..46e87df 100644
--- a/rlz/lib/rlz_value_store.h
+++ b/rlz/lib/rlz_value_store.h
@@ -95,12 +95,7 @@ class ScopedRlzValueStoreLock {
RlzValueStore* GetStore();
private:
-#if defined(OS_WIN) || defined(OS_MACOSX)
- // On ChromeOS, there is a singleton instance of RlzValueStore.
scoped_ptr<RlzValueStore> store_;
-#elif defined(OS_CHROMEOS)
- class RlzValueStoreChromeOS* store_;
-#endif
#if defined(OS_WIN)
LibMutex lock_;
#elif defined(OS_MACOSX)
@@ -108,20 +103,15 @@ class ScopedRlzValueStoreLock {
#endif
};
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
namespace testing {
// Prefix |directory| to the path where the RLZ data file lives, for tests.
void SetRlzStoreDirectory(const FilePath& directory);
-} // namespace testing
-#endif // defined(OS_MACOSX) || defined(OS_CHROMEOS)
-#if defined(OS_MACOSX)
-namespace testing {
-// Returns the path of the plist file used as data store.
-std::string RlzPlistFilenameStr();
+// Returns the path of the file used as data store.
+std::string RlzStoreFilenameStr();
} // namespace testing
-#endif // defined(OS_MACOSX)
-
+#endif // defined(OS_POSIX)
} // namespace rlz_lib
diff --git a/rlz/mac/lib/rlz_value_store_mac.mm b/rlz/mac/lib/rlz_value_store_mac.mm
index 6148e54..6b8e6f4 100644
--- a/rlz/mac/lib/rlz_value_store_mac.mm
+++ b/rlz/mac/lib/rlz_value_store_mac.mm
@@ -7,11 +7,11 @@
#include "base/mac/foundation_util.h"
#include "base/file_path.h"
#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
#include "base/sys_string_conversions.h"
#include "rlz/lib/assert.h"
#include "rlz/lib/lib_values.h"
#include "rlz/lib/rlz_lib.h"
+#include "rlz/lib/recursive_cross_process_lock_posix.h"
#import <Foundation/Foundation.h>
#include <pthread.h>
@@ -217,97 +217,8 @@ NSMutableDictionary* RlzValueStoreMac::ProductDict(Product p) {
namespace {
-// Creating a recursive cross-process mutex on windows is one line. On mac,
-// there's no primitve for that, so this lock is emulated by an in-process
-// mutex to get the recursive part, followed by a cross-process lock for the
-// cross-process part.
-
-// This is a struct so that it doesn't need a static initializer.
-struct RecursiveCrossProcessLock {
- // Tries to acquire a recursive cross-process lock. Note that this _always_
- // acquires the in-process lock (if it wasn't already acquired). The parent
- // directory of |lock_file| must exist.
- bool TryGetCrossProcessLock(NSString* lock_filename);
-
- // Releases the lock. Should always be called, even if
- // TryGetCrossProcessLock() returns false.
- void ReleaseLock();
-
- pthread_mutex_t recursive_lock_;
- pthread_t locking_thread_;
-
- int file_lock_;
-} g_recursive_lock = {
- // PTHREAD_RECURSIVE_MUTEX_INITIALIZER doesn't exist before 10.7 and is buggy
- // on 10.7 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51906#c34), so emulate
- // recursive locking with a normal non-recursive mutex.
- PTHREAD_MUTEX_INITIALIZER,
- 0,
- -1
-};
-
-bool RecursiveCrossProcessLock::TryGetCrossProcessLock(
- NSString* lock_filename) {
- bool just_got_lock = false;
-
- // Emulate a recursive mutex with a non-recursive one.
- if (pthread_mutex_trylock(&recursive_lock_) == EBUSY) {
- if (pthread_equal(pthread_self(), locking_thread_) == 0) {
- // Some other thread has the lock, wait for it.
- pthread_mutex_lock(&recursive_lock_);
- CHECK(locking_thread_ == 0);
- just_got_lock = true;
- }
- } else {
- just_got_lock = true;
- }
-
- locking_thread_ = pthread_self();
-
- // Try to acquire file lock.
- if (just_got_lock) {
- const int kMaxTimeoutMS = 5000; // Matches windows.
- const int kSleepPerTryMS = 200;
-
- CHECK(file_lock_ == -1);
- file_lock_ = open([lock_filename fileSystemRepresentation],
- O_RDWR | O_CREAT,
- 0666);
- if (file_lock_ == -1)
- return false;
-
- int flock_result = -1;
- int elapsed_ms = 0;
- while ((flock_result =
- HANDLE_EINTR(flock(file_lock_, LOCK_EX | LOCK_NB))) == -1 &&
- errno == EWOULDBLOCK &&
- elapsed_ms < kMaxTimeoutMS) {
- usleep(kSleepPerTryMS * 1000);
- elapsed_ms += kSleepPerTryMS;
- }
-
- if (flock_result == -1) {
- ignore_result(HANDLE_EINTR(close(file_lock_)));
- file_lock_ = -1;
- return false;
- }
- return true;
- } else {
- return file_lock_ != -1;
- }
-}
-
-void RecursiveCrossProcessLock::ReleaseLock() {
- if (file_lock_ != -1) {
- ignore_result(HANDLE_EINTR(flock(file_lock_, LOCK_UN)));
- ignore_result(HANDLE_EINTR(close(file_lock_)));
- file_lock_ = -1;
- }
-
- locking_thread_ = 0;
- pthread_mutex_unlock(&recursive_lock_);
-}
-
+RecursiveCrossProcessLock g_recursive_lock =
+ RECURSIVE_CROSS_PROCESS_LOCK_INITIALIZER;
// This is set during test execution, to write RLZ files into a temporary
// directory instead of the user's Application Support folder.
@@ -363,8 +274,8 @@ NSString* RlzLockFilename() {
} // namespace
ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
- bool got_distributed_lock =
- g_recursive_lock.TryGetCrossProcessLock(RlzLockFilename());
+ bool got_distributed_lock = g_recursive_lock.TryGetCrossProcessLock(
+ FilePath([RlzLockFilename() fileSystemRepresentation]));
// At this point, we hold the in-process lock, no matter the value of
// |got_distributed_lock|.
@@ -451,7 +362,7 @@ void SetRlzStoreDirectory(const FilePath& directory) {
}
}
-std::string RlzPlistFilenameStr() {
+std::string RlzStoreFilenameStr() {
@autoreleasepool {
return std::string([RlzPlistFilename() fileSystemRepresentation]);
}
diff --git a/rlz/rlz.gyp b/rlz/rlz.gyp
index 3e04654..0d4b330 100644
--- a/rlz/rlz.gyp
+++ b/rlz/rlz.gyp
@@ -45,8 +45,8 @@
'lib/lib_values.cc',
'lib/machine_id.cc',
'lib/machine_id.h',
- 'lib/recursive_lock.cc',
- 'lib/recursive_lock.h',
+ 'lib/recursive_cross_process_lock_posix.cc',
+ 'lib/recursive_cross_process_lock_posix.h',
'lib/rlz_enums.h',
'lib/rlz_lib.cc',
'lib/rlz_lib.h',
@@ -97,12 +97,6 @@
],
},
}],
- ['chromeos==0', {
- 'sources!': [
- 'lib/recursive_lock.cc',
- 'lib/recursive_lock.h',
- ]
- }],
],
},
{
@@ -122,7 +116,6 @@
'lib/financial_ping_test.cc',
'lib/lib_values_unittest.cc',
'lib/machine_id_unittest.cc',
- 'lib/recursive_lock_unittest.cc',
'lib/rlz_lib_test.cc',
'lib/string_utils_unittest.cc',
'test/rlz_test_helpers.cc',
@@ -136,11 +129,6 @@
'../net/net.gyp:net_test_support',
],
}],
- ['chromeos==0', {
- 'sources!': [
- 'lib/recursive_lock_unittest.cc',
- ],
- }]
],
},
{
diff --git a/rlz/test/rlz_test_helpers.cc b/rlz/test/rlz_test_helpers.cc
index 4fe12d4..32719e0 100644
--- a/rlz/test/rlz_test_helpers.cc
+++ b/rlz/test/rlz_test_helpers.cc
@@ -13,13 +13,10 @@
#include <shlwapi.h>
#include "base/win/registry.h"
#include "rlz/win/lib/rlz_lib.h"
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
#include "base/file_path.h"
#include "rlz/lib/rlz_value_store.h"
#endif
-#if defined(OS_CHROMEOS)
-#include "rlz/chromeos/lib/rlz_value_store_chromeos.h"
-#endif
#if defined(OS_WIN)
namespace {
@@ -62,41 +59,24 @@ void UndoOverrideRegistryHives() {
} // namespace
#endif // defined(OS_WIN)
-
-#if defined(OS_CHROMEOS)
-RlzLibTestNoMachineState::RlzLibTestNoMachineState()
- : pref_store_io_thread_("test_rlz_pref_store_io_thread") {
-}
-#endif // defined(OS_CHROMEOS)
-
void RlzLibTestNoMachineState::SetUp() {
#if defined(OS_WIN)
OverrideRegistryHives();
#elif defined(OS_MACOSX)
base::mac::ScopedNSAutoreleasePool pool;
#endif // defined(OS_WIN)
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
rlz_lib::testing::SetRlzStoreDirectory(temp_dir_.path());
-#endif // defined(OS_MACOSX) || defined(OS_CHROMEOS)
-#if defined(OS_CHROMEOS)
- base::Thread::Options options;
- options.message_loop_type = MessageLoop::TYPE_IO;
- ASSERT_TRUE(pref_store_io_thread_.StartWithOptions(options));
- rlz_lib::SetIOTaskRunner(pref_store_io_thread_.message_loop_proxy());
- rlz_lib::RlzValueStoreChromeOS::ResetForTesting();
-#endif // defined(OS_CHROMEOS)
+#endif // defined(OS_POSIX)
}
void RlzLibTestNoMachineState::TearDown() {
#if defined(OS_WIN)
UndoOverrideRegistryHives();
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
rlz_lib::testing::SetRlzStoreDirectory(FilePath());
#endif // defined(OS_WIN)
-#if defined(OS_CHROMEOS)
- pref_store_io_thread_.Stop();
-#endif // defined(OS_CHROMEOS)
}
void RlzLibTestBase::SetUp() {
diff --git a/rlz/test/rlz_test_helpers.h b/rlz/test/rlz_test_helpers.h
index 8b0565d..a78764f 100644
--- a/rlz/test/rlz_test_helpers.h
+++ b/rlz/test/rlz_test_helpers.h
@@ -10,30 +10,19 @@
#include "base/compiler_specific.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
#include "base/files/scoped_temp_dir.h"
#endif
-#if defined(OS_CHROMEOS)
-#include "base/message_loop.h"
-#include "base/threading/thread.h"
-#endif
class RlzLibTestNoMachineState : public ::testing::Test {
protected:
-#if defined(OS_CHROMEOS)
- RlzLibTestNoMachineState();
-#endif
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
base::ScopedTempDir temp_dir_;
#endif
-#if defined(OS_CHROMEOS)
- base::Thread pref_store_io_thread_;
- MessageLoop message_loop_;
-#endif
};
class RlzLibTestBase : public RlzLibTestNoMachineState {