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

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

Issue 10823329: rlz/mac: Make sure a crashing process doesn't leave a stale lockfile behind. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 4 months 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
« rlz/lib/rlz_lib_test.cc ('K') | « rlz/lib/rlz_lib_test.cc ('k') | no next file » | 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/eintr_wrapper.h"
7 #include "base/mac/foundation_util.h" 8 #include "base/mac/foundation_util.h"
8 #include "base/file_path.h" 9 #include "base/file_path.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/sys_string_conversions.h" 11 #include "base/sys_string_conversions.h"
11 #include "rlz/lib/assert.h" 12 #include "rlz/lib/assert.h"
12 #include "rlz/lib/lib_values.h" 13 #include "rlz/lib/lib_values.h"
13 #include "rlz/lib/rlz_lib.h" 14 #include "rlz/lib/rlz_lib.h"
14 15
15 #import <Foundation/Foundation.h> 16 #import <Foundation/Foundation.h>
16 #include <pthread.h> 17 #include <pthread.h>
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 // directory of |lock_file| must exist. 229 // directory of |lock_file| must exist.
229 bool TryGetCrossProcessLock(NSString* lock_filename); 230 bool TryGetCrossProcessLock(NSString* lock_filename);
230 231
231 // Releases the lock. Should always be called, even if 232 // Releases the lock. Should always be called, even if
232 // TryGetCrossProcessLock() returns false. 233 // TryGetCrossProcessLock() returns false.
233 void ReleaseLock(); 234 void ReleaseLock();
234 235
235 pthread_mutex_t recursive_lock_; 236 pthread_mutex_t recursive_lock_;
236 pthread_t locking_thread_; 237 pthread_t locking_thread_;
237 238
238 NSDistributedLock* file_lock_; 239 int file_lock_;
239 } g_recursive_lock = { 240 } g_recursive_lock = {
240 // PTHREAD_RECURSIVE_MUTEX_INITIALIZER doesn't exist before 10.7 and is buggy 241 // PTHREAD_RECURSIVE_MUTEX_INITIALIZER doesn't exist before 10.7 and is buggy
241 // on 10.7 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51906#c34), so emulate 242 // on 10.7 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51906#c34), so emulate
242 // recursive locking with a normal non-recursive mutex. 243 // recursive locking with a normal non-recursive mutex.
243 PTHREAD_MUTEX_INITIALIZER 244 PTHREAD_MUTEX_INITIALIZER,
245 0,
246 -1
244 }; 247 };
245 248
246 bool RecursiveCrossProcessLock::TryGetCrossProcessLock( 249 bool RecursiveCrossProcessLock::TryGetCrossProcessLock(
247 NSString* lock_filename) { 250 NSString* lock_filename) {
248 bool just_got_lock = false; 251 bool just_got_lock = false;
249 252
250 // Emulate a recursive mutex with a non-recursive one. 253 // Emulate a recursive mutex with a non-recursive one.
251 if (pthread_mutex_trylock(&recursive_lock_) == EBUSY) { 254 if (pthread_mutex_trylock(&recursive_lock_) == EBUSY) {
252 if (pthread_equal(pthread_self(), locking_thread_) == 0) { 255 if (pthread_equal(pthread_self(), locking_thread_) == 0) {
253 // Some other thread has the lock, wait for it. 256 // Some other thread has the lock, wait for it.
254 pthread_mutex_lock(&recursive_lock_); 257 pthread_mutex_lock(&recursive_lock_);
255 CHECK(locking_thread_ == 0); 258 CHECK(locking_thread_ == 0);
256 just_got_lock = true; 259 just_got_lock = true;
257 } 260 }
258 } else { 261 } else {
259 just_got_lock = true; 262 just_got_lock = true;
260 } 263 }
261 264
262 locking_thread_ = pthread_self(); 265 locking_thread_ = pthread_self();
263 266
264 // Try to acquire file lock. 267 // Try to acquire file lock.
265 if (just_got_lock) { 268 if (just_got_lock) {
266 const int kMaxTimeoutMS = 5000; // Matches windows. 269 const int kMaxTimeoutMS = 5000; // Matches windows.
267 const int kSleepPerTryMS = 200; 270 const int kSleepPerTryMS = 200;
268 271
269 CHECK(!file_lock_); 272 CHECK(file_lock_ == -1);
270 file_lock_ = [[NSDistributedLock alloc] initWithPath:lock_filename]; 273 file_lock_ = open([lock_filename fileSystemRepresentation], O_CREAT, 0755);
Mark Mentovai 2012/08/15 13:36:28 Use 0666 for the mode argument. There’s no need to
274 if (file_lock_ == -1)
275 return false;
271 276
272 BOOL got_file_lock = NO; 277 int flock_result = -1;
273 int elapsedMS = 0; 278 int elapsed_ms = 0;
274 while (!(got_file_lock = [file_lock_ tryLock]) && 279 while ((flock_result =
275 elapsedMS < kMaxTimeoutMS) { 280 HANDLE_EINTR(flock(file_lock_, LOCK_EX | LOCK_NB))) == -1 &&
276 usleep(kSleepPerTryMS * 1000); 281 errno == EWOULDBLOCK &&
277 elapsedMS += kSleepPerTryMS; 282 elapsed_ms < kMaxTimeoutMS) {
283 ignore_result(HANDLE_EINTR(usleep(kSleepPerTryMS * 1000)));
Mark Mentovai 2012/08/15 13:36:28 Remove HANDLE_EINTR as described. The correct way
284 elapsed_ms += kSleepPerTryMS;
278 } 285 }
279 286
280 if (!got_file_lock) { 287 if (flock_result == -1) {
281 [file_lock_ release]; 288 close(file_lock_);
282 file_lock_ = nil; 289 file_lock_ = -1;
283 return false; 290 return false;
284 } 291 }
285 return true; 292 return true;
286 } else { 293 } else {
287 return file_lock_ != nil; 294 return file_lock_ != -1;
288 } 295 }
289 } 296 }
290 297
291 void RecursiveCrossProcessLock::ReleaseLock() { 298 void RecursiveCrossProcessLock::ReleaseLock() {
292 if (file_lock_) { 299 if (file_lock_) {
293 [file_lock_ unlock]; 300 flock(file_lock_, LOCK_UN);
294 [file_lock_ release]; 301 close(file_lock_);
Mark Mentovai 2012/08/15 13:36:28 You can put your unlock and close in HANDLE_EINTRs
Nico 2012/08/15 14:52:50 Done for close. man flock says it can't EINTR (it'
Mark Mentovai 2012/08/15 16:10:00 Nico wrote:
Nico 2012/08/15 17:02:27 flock is even explicitly mentioned on the list in
295 file_lock_ = nil; 302 file_lock_ = -1;
296 } 303 }
297 304
298 locking_thread_ = 0; 305 locking_thread_ = 0;
299 pthread_mutex_unlock(&recursive_lock_); 306 pthread_mutex_unlock(&recursive_lock_);
300 } 307 }
301 308
302 309
303 // This is set during test execution, to write RLZ files into a temporary 310 // This is set during test execution, to write RLZ files into a temporary
304 // directory instead of the user's Application Support folder. 311 // directory instead of the user's Application Support folder.
305 NSString* g_test_folder; 312 NSString* g_test_folder;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 // Returns the path of the rlz plist store, also creates the parent directory 347 // Returns the path of the rlz plist store, also creates the parent directory
341 // path if it doesn't exist. 348 // path if it doesn't exist.
342 NSString* RlzPlistFilename() { 349 NSString* RlzPlistFilename() {
343 NSString* const kRlzFile = @"RlzStore.plist"; 350 NSString* const kRlzFile = @"RlzStore.plist";
344 return [CreateRlzDirectory() stringByAppendingPathComponent:kRlzFile]; 351 return [CreateRlzDirectory() stringByAppendingPathComponent:kRlzFile];
345 } 352 }
346 353
347 // Returns the path of the rlz lock file, also creates the parent directory 354 // Returns the path of the rlz lock file, also creates the parent directory
348 // path if it doesn't exist. 355 // path if it doesn't exist.
349 NSString* RlzLockFilename() { 356 NSString* RlzLockFilename() {
350 NSString* const kRlzFile = @"lockfile"; 357 NSString* const kRlzFile = @"flockfile";
351 return [CreateRlzDirectory() stringByAppendingPathComponent:kRlzFile]; 358 return [CreateRlzDirectory() stringByAppendingPathComponent:kRlzFile];
352 } 359 }
353 360
354 } // namespace 361 } // namespace
355 362
356 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() { 363 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
357 bool got_distributed_lock = 364 bool got_distributed_lock =
358 g_recursive_lock.TryGetCrossProcessLock(RlzLockFilename()); 365 g_recursive_lock.TryGetCrossProcessLock(RlzLockFilename());
359 // At this point, we hold the in-process lock, no matter the value of 366 // At this point, we hold the in-process lock, no matter the value of
360 // |got_distributed_lock|. 367 // |got_distributed_lock|.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 g_store_object = NULL; 416 g_store_object = NULL;
410 417
411 NSDictionary* dict = 418 NSDictionary* dict =
412 static_cast<RlzValueStoreMac*>(store_.get())->dictionary(); 419 static_cast<RlzValueStoreMac*>(store_.get())->dictionary();
413 VERIFY([dict writeToFile:RlzPlistFilename() atomically:YES]); 420 VERIFY([dict writeToFile:RlzPlistFilename() atomically:YES]);
414 } 421 }
415 422
416 // Check that "store_ set" => "file_lock acquired". The converse isn't true, 423 // Check that "store_ set" => "file_lock acquired". The converse isn't true,
417 // for example if the rlz data file can't be read. 424 // for example if the rlz data file can't be read.
418 if (store_.get()) 425 if (store_.get())
419 CHECK(g_recursive_lock.file_lock_); 426 CHECK(g_recursive_lock.file_lock_ != -1);
420 if (!g_recursive_lock.file_lock_) 427 if (g_recursive_lock.file_lock_ == -1)
421 CHECK(!store_.get()); 428 CHECK(!store_.get());
422 429
423 g_recursive_lock.ReleaseLock(); 430 g_recursive_lock.ReleaseLock();
424 } 431 }
425 432
426 RlzValueStore* ScopedRlzValueStoreLock::GetStore() { 433 RlzValueStore* ScopedRlzValueStoreLock::GetStore() {
427 return store_.get(); 434 return store_.get();
428 } 435 }
429 436
430 namespace testing { 437 namespace testing {
431 438
432 void SetRlzStoreDirectory(const FilePath& directory) { 439 void SetRlzStoreDirectory(const FilePath& directory) {
433 base::mac::ScopedNSAutoreleasePool pool; 440 base::mac::ScopedNSAutoreleasePool pool;
434 441
435 [g_test_folder release]; 442 [g_test_folder release];
436 if (directory.empty()) { 443 if (directory.empty()) {
437 g_test_folder = nil; 444 g_test_folder = nil;
438 } else { 445 } else {
439 // Not Unsafe on OS X. 446 // Not Unsafe on OS X.
440 g_test_folder = 447 g_test_folder =
441 [[NSString alloc] initWithUTF8String:directory.AsUTF8Unsafe().c_str()]; 448 [[NSString alloc] initWithUTF8String:directory.AsUTF8Unsafe().c_str()];
442 } 449 }
443 } 450 }
444 451
445 } // namespace testing 452 } // namespace testing
446 453
447 } // namespace rlz_lib 454 } // namespace rlz_lib
OLDNEW
« rlz/lib/rlz_lib_test.cc ('K') | « rlz/lib/rlz_lib_test.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698