diff options
author | Serdar Sutay <serdar@opscode.com> | 2013-10-25 15:49:43 -0700 |
---|---|---|
committer | Serdar Sutay <serdar@opscode.com> | 2013-10-25 15:49:43 -0700 |
commit | ba5988b1981752ff7cbe9ae97fcf1653dd2d597f (patch) | |
tree | 34b4fac2a42eb2cb0426bd7cf6258560d7ce70b5 | |
parent | 667f072ac6eb764d39708aae2f304f031b98d0ce (diff) | |
parent | 492b3347e33115cdcff99f6a5ce41eb6d8baca32 (diff) | |
download | chef-ba5988b1981752ff7cbe9ae97fcf1653dd2d597f.tar.gz |
Merge pull request #1092 from opscode/runlock-windows-access
Check before creating a new system mutex on windows.
-rw-r--r-- | lib/chef/win32/mutex.rb | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/lib/chef/win32/mutex.rb b/lib/chef/win32/mutex.rb index b0a9ba210e..0b7d99f111 100644 --- a/lib/chef/win32/mutex.rb +++ b/lib/chef/win32/mutex.rb @@ -22,25 +22,10 @@ class Chef module ReservedNames::Win32 class Mutex include Chef::ReservedNames::Win32::API::Synchronization - extend Chef::ReservedNames::Win32::API::Synchronization def initialize(name) @name = name - # First check if there exists a mutex in the system with the - # given name. - - # In the initial creation of the mutex initial_owner is set to - # false so that mutex will not be acquired until someone calls - # acquire. - # In order to call "*W" windows apis, strings needs to be - # encoded as wide strings. - @handle = CreateMutexW(nil, false, name.to_wstring) - - # Fail early if we can't get a handle to the named mutex - if @handle == 0 - Chef::Log.error("Failed to create system mutex with name'#{name}'") - Chef::ReservedNames::Win32::Error.raise! - end + create_system_mutex end attr_reader :handle @@ -57,17 +42,27 @@ class Chef ##################################################### # Attempts to grab the mutex and waits until it is acquired. def wait - wait_result = WaitForSingleObject(handle, INFINITE) - case wait_result - when WAIT_ABANDONED - # Previous owner of the mutex died before it can release the - # mutex. Log a warning and continue. - Chef::Log.debug "Existing owner of the mutex exited prematurely." - when WAIT_OBJECT_0 - # Mutex is successfully acquired. - else - Chef::Log.error("Failed to acquire system mutex '#{name}'. Return code: #{wait_result}") - Chef::ReservedNames::Win32::Error.raise! + loop do + wait_result = WaitForSingleObject(handle, 1000) + case wait_result + when WAIT_TIMEOUT + # We are periodically waking up in order to give ruby a + # chance to process any signal it got while we were + # sleeping. This condition shouldn't contain any logic + # other than sleeping. + sleep 0.1 + when WAIT_ABANDONED + # Previous owner of the mutex died before it can release the + # mutex. Log a warning and continue. + Chef::Log.debug "Existing owner of the mutex exited prematurely." + break + when WAIT_OBJECT_0 + # Mutex is successfully acquired. + break + else + Chef::Log.error("Failed to acquire system mutex '#{name}'. Return code: #{wait_result}") + Chef::ReservedNames::Win32::Error.raise! + end end end @@ -87,6 +82,34 @@ if the mutex is attempted to be acquired by other threads.") Chef::ReservedNames::Win32::Error.raise! end end + + private + + def create_system_mutex + # First check if there exists a mutex in the system with the + # given name. We need only synchronize rights if a mutex is + # already created. + # InheritHandle is set to true so that subprocesses can + # inherit the ownership of the mutex. + @handle = OpenMutexW(SYNCHRONIZE, true, name.to_wstring) + + if @handle == 0 + # Mutext doesn't exist so create one. + # In the initial creation of the mutex initial_owner is set to + # false so that mutex will not be acquired until someone calls + # acquire. + # In order to call "*W" windows apis, strings needs to be + # encoded as wide strings. + @handle = CreateMutexW(nil, false, name.to_wstring) + + # Looks like we can't create the mutex for some reason. + # Fail early. + if @handle == 0 + Chef::Log.error("Failed to create system mutex with name'#{name}'") + Chef::ReservedNames::Win32::Error.raise! + end + end + end end end end |