Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |