summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/sync/engine/syncapi.cc1
-rw-r--r--chrome/browser/sync/syncable/syncable.cc26
-rw-r--r--chrome/browser/sync/syncable/syncable.h20
-rw-r--r--chrome/browser/sync/syncable/syncable_unittest.cc398
4 files changed, 234 insertions, 211 deletions
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index 969b4fb..397e552 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -41,6 +41,7 @@
#include "chrome/browser/sync/util/crypto_helpers.h"
#include "chrome/browser/sync/util/event_sys.h"
#include "chrome/browser/sync/util/path_helpers.h"
+#include "chrome/browser/sync/util/pthread_helpers.h"
#include "chrome/browser/sync/util/user_settings.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/browser/sync/syncable/syncable.cc b/chrome/browser/sync/syncable/syncable.cc
index aa4832e..4d7b1c0 100644
--- a/chrome/browser/sync/syncable/syncable.cc
+++ b/chrome/browser/sync/syncable/syncable.cc
@@ -202,7 +202,6 @@ Directory::Kernel::Kernel(const PathString& db_path,
next_metahandle(info.max_metahandle + 1),
next_id(info.kernel_info.next_id) {
info_status_ = Directory::KERNEL_SHARE_INFO_VALID;
- CHECK(0 == pthread_mutex_init(&mutex, NULL));
}
inline void DeleteEntry(EntryKernel* kernel) {
@@ -222,7 +221,6 @@ Directory::Kernel::~Kernel() {
CHECK(0 == refcount);
delete channel;
delete changes_channel;
- CHECK(0 == pthread_mutex_destroy(&mutex));
delete unsynced_metahandles;
delete unapplied_update_metahandles;
delete extended_attributes;
@@ -764,7 +762,9 @@ void Directory::TakeSnapshotForSaveChanges(SaveChangesSnapshot* snapshot) {
bool Directory::SaveChanges() {
bool success = false;
DCHECK(store_);
- PThreadScopedLock<PThreadMutex> lock(&kernel_->save_changes_mutex);
+
+ AutoLock scoped_lock(kernel_->save_changes_mutex);
+
// Snapshot and save.
SaveChangesSnapshot snapshot;
TakeSnapshotForSaveChanges(&snapshot);
@@ -1104,22 +1104,7 @@ void Directory::CheckTreeInvariants(syncable::BaseTransaction* trans,
// ScopedKernelLocks
ScopedKernelLock::ScopedKernelLock(const Directory* dir)
- : dir_(const_cast<Directory*>(dir)) {
- // Swap out the dbhandle to enforce the "No IO while holding kernel
- // lock" rule.
- // HA!! Yeah right. What about your pre-cached queries :P
- pthread_mutex_lock(&dir->kernel_->mutex);
-}
-ScopedKernelLock::~ScopedKernelLock() {
- pthread_mutex_unlock(&dir_->kernel_->mutex);
-}
-
-ScopedKernelUnlock::ScopedKernelUnlock(ScopedKernelLock* lock)
- : lock_(lock) {
- pthread_mutex_unlock(&lock->dir_->kernel_->mutex);
-}
-ScopedKernelUnlock::~ScopedKernelUnlock() {
- pthread_mutex_lock(&lock_->dir_->kernel_->mutex);
+ : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) {
}
///////////////////////////////////////////////////////////////////////////
@@ -1167,7 +1152,7 @@ void BaseTransaction::UnlockAndLog(OriginalEntries* originals_arg) {
return;
}
- dirkernel_->changes_channel_mutex.Lock();
+ AutoLock scoped_lock(dirkernel_->changes_channel_mutex);
// Tell listeners to calculate changes while we still have the mutex.
DirectoryChangeEvent event = { DirectoryChangeEvent::CALCULATE_CHANGES,
originals.get(), this, writer_ };
@@ -1179,7 +1164,6 @@ void BaseTransaction::UnlockAndLog(OriginalEntries* originals_arg) {
{ DirectoryChangeEvent::TRANSACTION_COMPLETE,
NULL, NULL, INVALID };
dirkernel_->changes_channel->NotifyListeners(complete_event);
- dirkernel_->changes_channel_mutex.Unlock();
}
ReadTransaction::ReadTransaction(Directory* directory, const char* file,
diff --git a/chrome/browser/sync/syncable/syncable.h b/chrome/browser/sync/syncable/syncable.h
index 086d169..9e55348 100644
--- a/chrome/browser/sync/syncable/syncable.h
+++ b/chrome/browser/sync/syncable/syncable.h
@@ -23,11 +23,9 @@
#include "chrome/browser/sync/syncable/path_name_cmp.h"
#include "chrome/browser/sync/syncable/syncable_id.h"
#include "chrome/browser/sync/util/compat_file.h"
-#include "chrome/browser/sync/util/compat_pthread.h"
#include "chrome/browser/sync/util/dbgq.h"
#include "chrome/browser/sync/util/event_sys.h"
#include "chrome/browser/sync/util/path_helpers.h"
-#include "chrome/browser/sync/util/pthread_helpers.h"
#include "chrome/browser/sync/util/row_iterator.h"
#include "chrome/browser/sync/util/sync_types.h"
@@ -797,7 +795,6 @@ struct ExtendedAttributeValue {
typedef std::map<ExtendedAttributeKey, ExtendedAttributeValue>
ExtendedAttributes;
-typedef PThreadScopedLock<PThreadMutex> ScopedTransactionLock;
typedef std::set<int64> MetahandleSet;
// A list of metahandles whose metadata should not be purged.
@@ -1114,7 +1111,7 @@ class Directory {
//
// Never hold the mutex and do anything with the database or any
// other buffered IO. Violating this rule will result in deadlock.
- pthread_mutex_t mutex; // TODO(chron): Swap this out for Chrome Lock
+ Lock mutex;
MetahandlesIndex* metahandles_index; // Entries indexed by metahandle
IdsIndex* ids_index; // Entries indexed by id
ParentIdAndNamesIndex* parent_id_and_names_index;
@@ -1137,7 +1134,7 @@ class Directory {
// while holding the transaction mutex and released after
// releasing the transaction mutex.
ChangesChannel* const changes_channel;
- PThreadMutex changes_channel_mutex;
+ Lock changes_channel_mutex;
KernelShareInfoStatus info_status_;
// These 5 members are backed in the share_info table, and
// their state is marked by the flag above.
@@ -1154,7 +1151,7 @@ class Directory {
// It doesn't make sense for two threads to run SaveChanges at the same
// time; this mutex protects that activity.
- PThreadMutex save_changes_mutex;
+ Lock save_changes_mutex;
// The next metahandle and id are protected by kernel mutex.
int64 next_metahandle;
@@ -1173,20 +1170,13 @@ class Directory {
class ScopedKernelLock {
public:
explicit ScopedKernelLock(const Directory*);
- ~ScopedKernelLock();
+ ~ScopedKernelLock() {}
+ AutoLock scoped_lock_;
Directory* const dir_;
DISALLOW_COPY_AND_ASSIGN(ScopedKernelLock);
};
-class ScopedKernelUnlock {
- public:
- explicit ScopedKernelUnlock(ScopedKernelLock* lock);
- ~ScopedKernelUnlock();
- ScopedKernelLock* const lock_;
- DISALLOW_COPY_AND_ASSIGN(ScopedKernelUnlock);
-};
-
// Transactions are now processed FIFO (+overlapping reads).
class BaseTransaction {
friend class Entry;
diff --git a/chrome/browser/sync/syncable/syncable_unittest.cc b/chrome/browser/sync/syncable/syncable_unittest.cc
index b1e1b10..cbfcfbe 100644
--- a/chrome/browser/sync/syncable/syncable_unittest.cc
+++ b/chrome/browser/sync/syncable/syncable_unittest.cc
@@ -31,6 +31,7 @@
#include "base/at_exit.h"
#include "base/logging.h"
+#include "base/platform_thread.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/sync/syncable/directory_backing_store.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
@@ -784,18 +785,27 @@ TEST(SyncableDirectoryManager, TestFileRelease) {
ASSERT_TRUE(0 == PathRemove(dm.GetSyncDataDatabasePath()));
}
-static void* OpenTestThreadMain(void* arg) {
- DirectoryManager* const dm = reinterpret_cast<DirectoryManager*>(arg);
- CHECK(dm->Open(PSTR("Open")));
- return 0;
-}
+class ThreadOpenTestDelegate : public PlatformThread::Delegate {
+ public:
+ explicit ThreadOpenTestDelegate(DirectoryManager* dm)
+ : directory_manager_(dm) {}
+ DirectoryManager* const directory_manager_;
+
+ private:
+ // PlatformThread::Delegate methods:
+ virtual void ThreadMain() {
+ CHECK(directory_manager_->Open(PSTR("Open")));
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadOpenTestDelegate);
+};
TEST(SyncableDirectoryManager, ThreadOpenTest) {
DirectoryManager dm(PSTR("."));
- pthread_t thread;
- ASSERT_TRUE(0 == pthread_create(&thread, 0, OpenTestThreadMain, &dm));
- void* result;
- ASSERT_TRUE(0 == pthread_join(thread, &result));
+ PlatformThreadHandle thread_handle;
+ ThreadOpenTestDelegate test_delegate(&dm);
+ ASSERT_TRUE(PlatformThread::Create(0, &test_delegate, &thread_handle));
+ PlatformThread::Join(thread_handle);
{
ScopedDirLookup dir(&dm, PSTR("Open"));
ASSERT_TRUE(dir.good());
@@ -805,107 +815,114 @@ TEST(SyncableDirectoryManager, ThreadOpenTest) {
ASSERT_FALSE(dir.good());
}
-namespace ThreadBug1 {
- struct Step {
- PThreadMutex mutex;
- PThreadCondVar condvar;
- int number;
- int64 metahandle;
- };
- struct ThreadArg {
- int role; // 0 or 1, meaning this thread does the odd or event steps.
- Step* step;
- DirectoryManager* dirman;
- };
+struct Step {
+ Step() : condvar(&mutex), number(0) {}
- void* ThreadMain(void* arg) {
- ThreadArg* const args = reinterpret_cast<ThreadArg*>(arg);
- const int role = args->role;
- Step* const step = args->step;
- DirectoryManager* const dirman = args->dirman;
- const PathString dirname = PSTR("ThreadBug1");
- PThreadScopedLock<PThreadMutex> lock(&step->mutex);
- while (step->number < 3) {
- while (step->number % 2 != role)
- pthread_cond_wait(&step->condvar.condvar_, &step->mutex.mutex_);
- switch (step->number) {
+ Lock mutex;
+ ConditionVariable condvar;
+ int number;
+ int64 metahandle;
+};
+
+class ThreadBugDelegate : public PlatformThread::Delegate {
+ public:
+ // a role is 0 or 1, meaning this thread does the odd or event steps.
+ ThreadBugDelegate(int role, Step* step, DirectoryManager* dirman)
+ : role_(role), step_(step), directory_manager_(dirman) {}
+
+ protected:
+ const int role_;
+ Step* const step_;
+ DirectoryManager* const directory_manager_;
+
+ // PlatformThread::Delegate methods:
+ virtual void ThreadMain() {
+ const PathString dirname = PSTR("ThreadBug1");
+ AutoLock scoped_lock(step_->mutex);
+
+ while (step_->number < 3) {
+ while (step_->number % 2 != role_) {
+ step_->condvar.Wait();
+ }
+ switch (step_->number) {
case 0:
- dirman->Open(dirname);
+ directory_manager_->Open(dirname);
break;
case 1:
{
- dirman->Close(dirname);
- dirman->Open(dirname);
- ScopedDirLookup dir(dirman, dirname);
+ directory_manager_->Close(dirname);
+ directory_manager_->Open(dirname);
+ ScopedDirLookup dir(directory_manager_, dirname);
CHECK(dir.good());
WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
MutableEntry me(&trans, CREATE, trans.root_id(), PSTR("Jeff"));
- step->metahandle = me.Get(META_HANDLE);
+ step_->metahandle = me.Get(META_HANDLE);
me.Put(IS_UNSYNCED, true);
}
break;
case 2:
{
- ScopedDirLookup dir(dirman, dirname);
+ ScopedDirLookup dir(directory_manager_, dirname);
CHECK(dir.good());
ReadTransaction trans(dir, __FILE__, __LINE__);
- Entry e(&trans, GET_BY_HANDLE, step->metahandle);
+ Entry e(&trans, GET_BY_HANDLE, step_->metahandle);
CHECK(e.good()); // Failed due to ThreadBug1
}
- dirman->Close(dirname);
+ directory_manager_->Close(dirname);
break;
- }
- step->number += 1;
- pthread_cond_signal(&step->condvar.condvar_);
- }
- return 0;
- }
-}
+ }
+ step_->number += 1;
+ step_->condvar.Signal();
+ }
+ }
-TEST(SyncableDirectoryManager, ThreadBug1) {
- using ThreadBug1::Step;
- using ThreadBug1::ThreadArg;
- using ThreadBug1::ThreadMain;
+ DISALLOW_COPY_AND_ASSIGN(ThreadBugDelegate);
+};
+TEST(SyncableDirectoryManager, ThreadBug1) {
Step step;
step.number = 0;
DirectoryManager dirman(PSTR("."));
- ThreadArg arg1 = { 0, &step, &dirman };
- ThreadArg arg2 = { 1, &step, &dirman };
- pthread_t thread1, thread2;
- ASSERT_TRUE(0 == pthread_create(&thread1, NULL, &ThreadMain, &arg1));
- ASSERT_TRUE(0 == pthread_create(&thread2, NULL, &ThreadMain, &arg2));
- void* retval;
- ASSERT_TRUE(0 == pthread_join(thread1, &retval));
- ASSERT_TRUE(0 == pthread_join(thread2, &retval));
+ ThreadBugDelegate thread_delegate_1(0, &step, &dirman);
+ ThreadBugDelegate thread_delegate_2(1, &step, &dirman);
+
+ PlatformThreadHandle thread_handle_1;
+ PlatformThreadHandle thread_handle_2;
+
+ ASSERT_TRUE(PlatformThread::Create(0, &thread_delegate_1, &thread_handle_1));
+ ASSERT_TRUE(PlatformThread::Create(0, &thread_delegate_2, &thread_handle_2));
+
+ PlatformThread::Join(thread_handle_1);
+ PlatformThread::Join(thread_handle_2);
}
-namespace DirectoryKernelStalenessBug {
- // The in-memory information would get out of sync because a
- // directory would be closed and re-opened, and then an old
- // Directory::Kernel with stale information would get saved to the db.
- typedef ThreadBug1::Step Step;
- typedef ThreadBug1::ThreadArg ThreadArg;
- void* ThreadMain(void* arg) {
+// The in-memory information would get out of sync because a
+// directory would be closed and re-opened, and then an old
+// Directory::Kernel with stale information would get saved to the db.
+class DirectoryKernelStalenessBugDelegate : public ThreadBugDelegate {
+ public:
+ DirectoryKernelStalenessBugDelegate(int role, Step* step,
+ DirectoryManager* dirman)
+ : ThreadBugDelegate(role, step, dirman) {}
+
+ virtual void ThreadMain() {
const char test_bytes[] = "test data";
- ThreadArg* const args = reinterpret_cast<ThreadArg*>(arg);
- const int role = args->role;
- Step* const step = args->step;
- DirectoryManager* const dirman = args->dirman;
const PathString dirname = PSTR("DirectoryKernelStalenessBug");
- PThreadScopedLock<PThreadMutex> lock(&step->mutex);
- while (step->number < 4) {
- while (step->number % 2 != role)
- pthread_cond_wait(&step->condvar.condvar_, &step->mutex.mutex_);
- switch (step->number) {
+ AutoLock scoped_lock(step_->mutex);
+
+ while (step_->number < 4) {
+ while (step_->number % 2 != role_) {
+ step_->condvar.Wait();
+ }
+ switch (step_->number) {
case 0:
{
// Clean up remnants of earlier test runs.
- PathRemove(dirman->GetSyncDataDatabasePath());
+ PathRemove(directory_manager_->GetSyncDataDatabasePath());
// Test.
- dirman->Open(dirname);
- ScopedDirLookup dir(dirman, dirname);
+ directory_manager_->Open(dirname);
+ ScopedDirLookup dir(directory_manager_, dirname);
CHECK(dir.good());
WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
MutableEntry me(&trans, CREATE, trans.root_id(), PSTR("Jeff"));
@@ -915,28 +932,28 @@ namespace DirectoryKernelStalenessBug {
sizeof(test_bytes));
}
{
- ScopedDirLookup dir(dirman, dirname);
+ ScopedDirLookup dir(directory_manager_, dirname);
CHECK(dir.good());
dir->SaveChanges();
}
- dirman->Close(dirname);
+ directory_manager_->Close(dirname);
break;
case 1:
{
- dirman->Open(dirname);
- ScopedDirLookup dir(dirman, dirname);
+ directory_manager_->Open(dirname);
+ ScopedDirLookup dir(directory_manager_, dirname);
CHECK(dir.good());
}
break;
case 2:
{
- ScopedDirLookup dir(dirman, dirname);
+ ScopedDirLookup dir(directory_manager_, dirname);
CHECK(dir.good());
}
break;
case 3:
{
- ScopedDirLookup dir(dirman, dirname);
+ ScopedDirLookup dir(directory_manager_, dirname);
CHECK(dir.good());
ReadTransaction trans(dir, __FILE__, __LINE__);
Entry e(&trans, GET_BY_PATH, PSTR("Jeff"));
@@ -944,120 +961,151 @@ namespace DirectoryKernelStalenessBug {
sizeof(test_bytes));
}
// Same result as CloseAllDirectories, but more code coverage.
- dirman->Close(dirname);
+ directory_manager_->Close(dirname);
break;
}
- step->number += 1;
- pthread_cond_signal(&step->condvar.condvar_);
+ step_->number += 1;
+ step_->condvar.Signal();
}
- return 0;
}
-}
-TEST(SyncableDirectoryManager, DirectoryKernelStalenessBug) {
- using DirectoryKernelStalenessBug::Step;
- using DirectoryKernelStalenessBug::ThreadArg;
- using DirectoryKernelStalenessBug::ThreadMain;
+ DISALLOW_COPY_AND_ASSIGN(DirectoryKernelStalenessBugDelegate);
+};
+TEST(SyncableDirectoryManager, DirectoryKernelStalenessBug) {
Step step;
- step.number = 0;
- DirectoryManager dirman(PSTR("."));
- ThreadArg arg1 = { 0, &step, &dirman };
- ThreadArg arg2 = { 1, &step, &dirman };
- pthread_t thread1, thread2;
- ASSERT_TRUE(0 == pthread_create(&thread1, NULL, &ThreadMain, &arg1));
- ASSERT_TRUE(0 == pthread_create(&thread2, NULL, &ThreadMain, &arg2));
- void* retval;
- ASSERT_TRUE(0 == pthread_join(thread1, &retval));
- ASSERT_TRUE(0 == pthread_join(thread2, &retval));
-}
-timespec operator + (const timespec& a, const timespec& b) {
- const long nanos = a.tv_nsec + b.tv_nsec;
- static const long nanos_per_second = 1000000000;
- timespec r = { a.tv_sec + b.tv_sec + (nanos / nanos_per_second),
- nanos % nanos_per_second };
- return r;
-}
+ DirectoryManager dirman(PSTR("."));
+ DirectoryKernelStalenessBugDelegate thread_delegate_1(0, &step, &dirman);
+ DirectoryKernelStalenessBugDelegate thread_delegate_2(1, &step, &dirman);
-void SleepMs(int milliseconds) {
-#ifdef OS_WIN
- Sleep(milliseconds);
-#else
- usleep(milliseconds * 1000);
-#endif
-}
+ PlatformThreadHandle thread_handle_1;
+ PlatformThreadHandle thread_handle_2;
-namespace StressTransaction {
- struct Globals {
- DirectoryManager* dirman;
- PathString dirname;
- };
+ ASSERT_TRUE(PlatformThread::Create(0, &thread_delegate_1, &thread_handle_1));
+ ASSERT_TRUE(PlatformThread::Create(0, &thread_delegate_2, &thread_handle_2));
- struct ThreadArg {
- Globals* globals;
- int thread_number;
- };
+ PlatformThread::Join(thread_handle_1);
+ PlatformThread::Join(thread_handle_2);
+}
- void* ThreadMain(void* arg) {
- ThreadArg* const args = reinterpret_cast<ThreadArg*>(arg);
- Globals* const globals = args->globals;
- ScopedDirLookup dir(globals->dirman, globals->dirname);
- CHECK(dir.good());
- int entry_count = 0;
- PathString path_name;
- for (int i = 0; i < 20; ++i) {
- const int rand_action = rand() % 10;
- if (rand_action < 4 && !path_name.empty()) {
- ReadTransaction trans(dir, __FILE__, __LINE__);
- Entry e(&trans, GET_BY_PARENTID_AND_NAME, trans.root_id(), path_name);
- SleepMs(rand() % 10);
- CHECK(e.good());
- } else {
- string unique_name = StringPrintf("%d.%d", args->thread_number,
- entry_count++);
- path_name.assign(unique_name.begin(), unique_name.end());
- WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
- MutableEntry e(&trans, CREATE, trans.root_id(), path_name);
- CHECK(e.good());
- SleepMs(rand() % 20);
- e.Put(IS_UNSYNCED, true);
- if (e.Put(ID, TestIdFactory::FromNumber(rand())) &&
- e.Get(ID).ServerKnows() && !e.Get(ID).IsRoot())
- e.Put(BASE_VERSION, 1);
- }
+class StressTransactionsDelegate : public PlatformThread::Delegate {
+ public:
+ StressTransactionsDelegate(DirectoryManager* dm, PathString dirname,
+ int thread_number)
+ : directory_manager_(dm), dirname_(dirname),
+ thread_number_(thread_number) {}
+
+ private:
+ DirectoryManager* const directory_manager_;
+ PathString dirname_;
+ const int thread_number_;
+
+ // PlatformThread::Delegate methods:
+ virtual void ThreadMain() {
+ ScopedDirLookup dir(directory_manager_, dirname_);
+ CHECK(dir.good());
+ int entry_count = 0;
+ PathString path_name;
+
+ for (int i = 0; i < 20; ++i) {
+ const int rand_action = rand() % 10;
+ if (rand_action < 4 && !path_name.empty()) {
+ ReadTransaction trans(dir, __FILE__, __LINE__);
+ Entry e(&trans, GET_BY_PARENTID_AND_NAME, trans.root_id(), path_name);
+ PlatformThread::Sleep(rand() % 10);
+ CHECK(e.good());
+ } else {
+ string unique_name = StringPrintf("%d.%d", thread_number_,
+ entry_count++);
+ path_name.assign(unique_name.begin(), unique_name.end());
+ WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__);
+ MutableEntry e(&trans, CREATE, trans.root_id(), path_name);
+ CHECK(e.good());
+ PlatformThread::Sleep(rand() % 20);
+ e.Put(IS_UNSYNCED, true);
+ if (e.Put(ID, TestIdFactory::FromNumber(rand())) &&
+ e.Get(ID).ServerKnows() && !e.Get(ID).IsRoot())
+ e.Put(BASE_VERSION, 1);
+ }
}
- return 0;
- }
-}
+ }
-TEST(SyncableDirectory, StressTransactions) {
- using StressTransaction::Globals;
- using StressTransaction::ThreadArg;
- using StressTransaction::ThreadMain;
+ DISALLOW_COPY_AND_ASSIGN(StressTransactionsDelegate);
+};
+TEST(SyncableDirectory, StressTransactions) {
DirectoryManager dirman(PSTR("."));
- Globals globals;
- globals.dirname = PSTR("stress");
- globals.dirman = &dirman;
+ PathString dirname = PSTR("stress");
PathRemove(dirman.GetSyncDataDatabasePath());
- dirman.Open(globals.dirname);
+ dirman.Open(dirname);
+
const int kThreadCount = 7;
- pthread_t threads[kThreadCount];
- ThreadArg thread_args[kThreadCount];
+ PlatformThreadHandle threads[kThreadCount];
+ scoped_ptr<StressTransactionsDelegate> thread_delegates[kThreadCount];
+
+ for (int i = 0; i < kThreadCount; ++i) {
+ thread_delegates[i].reset(
+ new StressTransactionsDelegate(&dirman, dirname, i));
+ ASSERT_TRUE(
+ PlatformThread::Create(0, thread_delegates[i].get(), &threads[i]));
+ }
+
for (int i = 0; i < kThreadCount; ++i) {
- thread_args[i].thread_number = i;
- thread_args[i].globals = &globals;
- ASSERT_TRUE(0 == pthread_create(threads + i, NULL, &ThreadMain,
- thread_args + i));
+ PlatformThread::Join(threads[i]);
}
- void* retval;
- for (pthread_t* i = threads; i < threads + kThreadCount; ++i)
- ASSERT_TRUE(0 == pthread_join(*i, &retval));
- dirman.Close(globals.dirname);
+
+ dirman.Close(dirname);
PathRemove(dirman.GetSyncDataDatabasePath());
}
+static PathString UTF8ToPathStringQuick(const char* str) {
+ PathString ret;
+ CHECK(browser_sync::UTF8ToPathString(str, strlen(str), &ret));
+ return ret;
+}
+
+// Returns number of chars used. Max possible is 4.
+// This algorithm was coded from the table at
+// http://en.wikipedia.org/w/index.php?title=UTF-8&oldid=153391259
+// There are no endian issues.
+static int UTF32ToUTF8(uint32 incode, unsigned char* out) {
+ if (incode <= 0x7f) {
+ out[0] = incode;
+ return 1;
+ }
+ if (incode <= 0x7ff) {
+ out[0] = 0xC0;
+ out[0] |= (incode >> 6);
+ out[1] = 0x80;
+ out[1] |= (incode & 0x3F);
+ return 2;
+ }
+ if (incode <= 0xFFFF) {
+ if ((incode > 0xD7FF) && (incode < 0xE000))
+ return 0;
+ out[0] = 0xE0;
+ out[0] |= (incode >> 12);
+ out[1] = 0x80;
+ out[1] |= (incode >> 6) & 0x3F;
+ out[2] = 0x80;
+ out[2] |= incode & 0x3F;
+ return 3;
+ }
+ if (incode <= 0x10FFFF) {
+ out[0] = 0xF0;
+ out[0] |= incode >> 18;
+ out[1] = 0x80;
+ out[1] |= (incode >> 12) & 0x3F;
+ out[2] = 0x80;
+ out[2] |= (incode >> 6) & 0x3F;
+ out[3] = 0x80;
+ out[3] |= incode & 0x3F;
+ return 4;
+ }
+ return 0;
+}
+
TEST(Syncable, ComparePathNames) {
struct {
char a;