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
This commit is contained in:
Darragh Bailey 2016-03-25 13:42:54 +00:00
parent b0aec1d162
commit 36ad4d53cf
1 changed files with 12 additions and 5 deletions

View File

@ -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