From 36ad4d53cfb23af43c6bd0a008f24ed80541431c Mon Sep 17 00:00:00 2001 From: Darragh Bailey Date: Fri, 25 Mar 2016 13:42:54 +0000 Subject: [PATCH] core: Multi machine use of active_machines requires locking of index Ensure multi machine access of other machine state information through iterating `active_machines` and retrieval of cached machines cannot have multiple threads update the state of machines simultaneously as this triggers a Machine Lock exception. Machine state information retrieved from the index, returns a locked object. Since iteration of active_machine, and retrieval of each machine from the cache can be triggered by any plugin, it is possible for another machine to inadvertently access the state and trigger an update, which the thread owning the machine is currently in the process of updating it already. This results in a Machine Locked exception occurring if the attempt to retrieve the cached state from the index occurs before the other thread calls release. Partially-Fixes: #6526 --- lib/vagrant/machine.rb | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/vagrant/machine.rb b/lib/vagrant/machine.rb index f9ba4bcdf..da259ef7b 100644 --- a/lib/vagrant/machine.rb +++ b/lib/vagrant/machine.rb @@ -109,6 +109,7 @@ module Vagrant @provider_options = provider_options @ui = Vagrant::UI::Prefixed.new(@env.ui, @name) @ui_mutex = Mutex.new + @state_mutex = Mutex.new # Read the ID, which is usually in local storage @id = nil @@ -505,11 +506,17 @@ module Vagrant # master index. uuid = index_uuid if uuid - entry = @env.machine_index.get(uuid) - if entry - entry.state = result.short_description - @env.machine_index.set(entry) - @env.machine_index.release(entry) + # active_machines provides access to query this info on each machine + # from a different thread, ensure multiple machines do not access + # the locked entry simultaneously as this triggers a locked machine + # exception. + @state_mutex.synchronize do + entry = @env.machine_index.get(uuid) + if entry + entry.state = result.short_description + @env.machine_index.set(entry) + @env.machine_index.release(entry) + end end end