Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(184)

Side by Side Diff: rlz/mac/lib/rlz_value_store_mac.mm

Issue 11308196: [cros] RlzValueStore made protected by a cross-process lock and not persisted over browser lifetime… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « rlz/lib/rlz_value_store.h ('k') | rlz/rlz.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "rlz/mac/lib/rlz_value_store_mac.h" 5 #include "rlz/mac/lib/rlz_value_store_mac.h"
6 6
7 #include "base/mac/foundation_util.h" 7 #include "base/mac/foundation_util.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/posix/eintr_wrapper.h"
11 #include "base/sys_string_conversions.h" 10 #include "base/sys_string_conversions.h"
12 #include "rlz/lib/assert.h" 11 #include "rlz/lib/assert.h"
13 #include "rlz/lib/lib_values.h" 12 #include "rlz/lib/lib_values.h"
14 #include "rlz/lib/rlz_lib.h" 13 #include "rlz/lib/rlz_lib.h"
14 #include "rlz/lib/recursive_cross_process_lock_posix.h"
15 15
16 #import <Foundation/Foundation.h> 16 #import <Foundation/Foundation.h>
17 #include <pthread.h> 17 #include <pthread.h>
18 18
19 using base::mac::ObjCCast; 19 using base::mac::ObjCCast;
20 20
21 namespace rlz_lib { 21 namespace rlz_lib {
22 22
23 // These are written to disk and should not be changed. 23 // These are written to disk and should not be changed.
24 NSString* const kPingTimeKey = @"pingTime"; 24 NSString* const kPingTimeKey = @"pingTime";
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 return GetOrCreateDict(dict_.get(), brand_ns); 210 return GetOrCreateDict(dict_.get(), brand_ns);
211 } 211 }
212 212
213 NSMutableDictionary* RlzValueStoreMac::ProductDict(Product p) { 213 NSMutableDictionary* RlzValueStoreMac::ProductDict(Product p) {
214 return GetOrCreateDict(WorkingDict(), GetNSProductName(p)); 214 return GetOrCreateDict(WorkingDict(), GetNSProductName(p));
215 } 215 }
216 216
217 217
218 namespace { 218 namespace {
219 219
220 // Creating a recursive cross-process mutex on windows is one line. On mac, 220 RecursiveCrossProcessLock g_recursive_lock =
221 // there's no primitve for that, so this lock is emulated by an in-process 221 RECURSIVE_CROSS_PROCESS_LOCK_INITIALIZER;
222 // mutex to get the recursive part, followed by a cross-process lock for the
223 // cross-process part.
224
225 // This is a struct so that it doesn't need a static initializer.
226 struct RecursiveCrossProcessLock {
227 // Tries to acquire a recursive cross-process lock. Note that this _always_
228 // acquires the in-process lock (if it wasn't already acquired). The parent
229 // directory of |lock_file| must exist.
230 bool TryGetCrossProcessLock(NSString* lock_filename);
231
232 // Releases the lock. Should always be called, even if
233 // TryGetCrossProcessLock() returns false.
234 void ReleaseLock();
235
236 pthread_mutex_t recursive_lock_;
237 pthread_t locking_thread_;
238
239 int file_lock_;
240 } g_recursive_lock = {
241 // PTHREAD_RECURSIVE_MUTEX_INITIALIZER doesn't exist before 10.7 and is buggy
242 // on 10.7 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51906#c34), so emulate
243 // recursive locking with a normal non-recursive mutex.
244 PTHREAD_MUTEX_INITIALIZER,
245 0,
246 -1
247 };
248
249 bool RecursiveCrossProcessLock::TryGetCrossProcessLock(
250 NSString* lock_filename) {
251 bool just_got_lock = false;
252
253 // Emulate a recursive mutex with a non-recursive one.
254 if (pthread_mutex_trylock(&recursive_lock_) == EBUSY) {
255 if (pthread_equal(pthread_self(), locking_thread_) == 0) {
256 // Some other thread has the lock, wait for it.
257 pthread_mutex_lock(&recursive_lock_);
258 CHECK(locking_thread_ == 0);
259 just_got_lock = true;
260 }
261 } else {
262 just_got_lock = true;
263 }
264
265 locking_thread_ = pthread_self();
266
267 // Try to acquire file lock.
268 if (just_got_lock) {
269 const int kMaxTimeoutMS = 5000; // Matches windows.
270 const int kSleepPerTryMS = 200;
271
272 CHECK(file_lock_ == -1);
273 file_lock_ = open([lock_filename fileSystemRepresentation],
274 O_RDWR | O_CREAT,
275 0666);
276 if (file_lock_ == -1)
277 return false;
278
279 int flock_result = -1;
280 int elapsed_ms = 0;
281 while ((flock_result =
282 HANDLE_EINTR(flock(file_lock_, LOCK_EX | LOCK_NB))) == -1 &&
283 errno == EWOULDBLOCK &&
284 elapsed_ms < kMaxTimeoutMS) {
285 usleep(kSleepPerTryMS * 1000);
286 elapsed_ms += kSleepPerTryMS;
287 }
288
289 if (flock_result == -1) {
290 ignore_result(HANDLE_EINTR(close(file_lock_)));
291 file_lock_ = -1;
292 return false;
293 }
294 return true;
295 } else {
296 return file_lock_ != -1;
297 }
298 }
299
300 void RecursiveCrossProcessLock::ReleaseLock() {
301 if (file_lock_ != -1) {
302 ignore_result(HANDLE_EINTR(flock(file_lock_, LOCK_UN)));
303 ignore_result(HANDLE_EINTR(close(file_lock_)));
304 file_lock_ = -1;
305 }
306
307 locking_thread_ = 0;
308 pthread_mutex_unlock(&recursive_lock_);
309 }
310
311 222
312 // This is set during test execution, to write RLZ files into a temporary 223 // This is set during test execution, to write RLZ files into a temporary
313 // directory instead of the user's Application Support folder. 224 // directory instead of the user's Application Support folder.
314 NSString* g_test_folder; 225 NSString* g_test_folder;
315 226
316 // RlzValueStoreMac keeps its data in memory and only writes it to disk when 227 // RlzValueStoreMac keeps its data in memory and only writes it to disk when
317 // ScopedRlzValueStoreLock goes out of scope. Hence, if several 228 // ScopedRlzValueStoreLock goes out of scope. Hence, if several
318 // ScopedRlzValueStoreLocks are nested, they all need to use the same store 229 // ScopedRlzValueStoreLocks are nested, they all need to use the same store
319 // object. 230 // object.
320 231
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 // Returns the path of the rlz lock file, also creates the parent directory 267 // Returns the path of the rlz lock file, also creates the parent directory
357 // path if it doesn't exist. 268 // path if it doesn't exist.
358 NSString* RlzLockFilename() { 269 NSString* RlzLockFilename() {
359 NSString* const kRlzLockfile = @"flockfile"; 270 NSString* const kRlzLockfile = @"flockfile";
360 return [CreateRlzDirectory() stringByAppendingPathComponent:kRlzLockfile]; 271 return [CreateRlzDirectory() stringByAppendingPathComponent:kRlzLockfile];
361 } 272 }
362 273
363 } // namespace 274 } // namespace
364 275
365 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() { 276 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
366 bool got_distributed_lock = 277 bool got_distributed_lock = g_recursive_lock.TryGetCrossProcessLock(
367 g_recursive_lock.TryGetCrossProcessLock(RlzLockFilename()); 278 FilePath([RlzLockFilename() fileSystemRepresentation]));
368 // At this point, we hold the in-process lock, no matter the value of 279 // At this point, we hold the in-process lock, no matter the value of
369 // |got_distributed_lock|. 280 // |got_distributed_lock|.
370 281
371 ++g_lock_depth; 282 ++g_lock_depth;
372 283
373 if (!got_distributed_lock) { 284 if (!got_distributed_lock) {
374 // Give up. |store_| isn't set, which signals to callers that acquiring 285 // Give up. |store_| isn't set, which signals to callers that acquiring
375 // the lock failed. |g_recursive_lock| will be released by the 286 // the lock failed. |g_recursive_lock| will be released by the
376 // destructor. 287 // destructor.
377 CHECK(!g_store_object); 288 CHECK(!g_store_object);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 [g_test_folder release]; 355 [g_test_folder release];
445 if (directory.empty()) { 356 if (directory.empty()) {
446 g_test_folder = nil; 357 g_test_folder = nil;
447 } else { 358 } else {
448 // Not Unsafe on OS X. 359 // Not Unsafe on OS X.
449 g_test_folder = 360 g_test_folder =
450 [[NSString alloc] initWithUTF8String:directory.AsUTF8Unsafe().c_str()]; 361 [[NSString alloc] initWithUTF8String:directory.AsUTF8Unsafe().c_str()];
451 } 362 }
452 } 363 }
453 364
454 std::string RlzPlistFilenameStr() { 365 std::string RlzStoreFilenameStr() {
455 @autoreleasepool { 366 @autoreleasepool {
456 return std::string([RlzPlistFilename() fileSystemRepresentation]); 367 return std::string([RlzPlistFilename() fileSystemRepresentation]);
457 } 368 }
458 } 369 }
459 370
460 } // namespace testing 371 } // namespace testing
461 372
462 } // namespace rlz_lib 373 } // namespace rlz_lib
OLDNEW
« no previous file with comments | « rlz/lib/rlz_value_store.h ('k') | rlz/rlz.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698