summaryrefslogtreecommitdiff
blob: 75cb63a2fb112ca67bd235c9acb14c3ef1021a82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
From bfc2af4cf9c5e9280f0e7d74de226b7af7c18a2a Mon Sep 17 00:00:00 2001
From: Chris Roberts <code@chrisroberts.org>
Date: Mon, 27 Mar 2017 12:55:15 -0700
Subject: [PATCH] Always provide timeout on thread join to prevent deadlock
 errors

---
 lib/vagrant/batch_action.rb   | 6 ++++--
 lib/vagrant/environment.rb    | 2 +-
 lib/vagrant/shared_helpers.rb | 6 ++++++
 lib/vagrant/ui.rb             | 6 +++---
 4 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/lib/vagrant/batch_action.rb b/lib/vagrant/batch_action.rb
index 9b6900f..d27e87d 100644
--- a/lib/vagrant/batch_action.rb
+++ b/lib/vagrant/batch_action.rb
@@ -123,7 +123,9 @@ def run
         # Set some attributes on the thread for later
         thread[:machine] = machine
 
-        thread.join if !par
+        if !par
+          thread.join(THREAD_MAX_JOIN_TIMEOUT) while thread.alive?
+        end
         threads << thread
       end
 
@@ -131,7 +133,7 @@ def run
 
       threads.each do |thread|
         # Wait for the thread to complete
-        thread.join
+        thread.join(THREAD_MAX_JOIN_TIMEOUT) while thread.alive?
 
         # If the thread had an error, then store the error to show later
         if thread[:error]
diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb
index 8fad272..125070f 100644
--- a/lib/vagrant/environment.rb
+++ b/lib/vagrant/environment.rb
@@ -295,7 +295,7 @@ def batch(parallel=true)
     #
     # @return [Hash]
     def checkpoint
-      @checkpoint_thr.join
+      @checkpoint_thr.join(THREAD_MAX_JOIN_TIMEOUT)
       return @checkpoint_thr[:result]
     end
 
diff --git a/lib/vagrant/shared_helpers.rb b/lib/vagrant/shared_helpers.rb
index c5d6ea6..5522272 100644
--- a/lib/vagrant/shared_helpers.rb
+++ b/lib/vagrant/shared_helpers.rb
@@ -12,6 +12,12 @@ module Vagrant
   # @return [String]
   DEFAULT_SERVER_URL = "https://atlas.hashicorp.com"
 
+  # Max number of seconds to wait for joining an active thread.
+  #
+  # @return [Integer]
+  # @note This is not the maxium time for a thread to complete.
+  THREAD_MAX_JOIN_TIMEOUT = 60
+
   # This holds a global lock for the duration of the block. This should
   # be invoked around anything that is modifying process state (such as
   # environmental variables).
diff --git a/lib/vagrant/ui.rb b/lib/vagrant/ui.rb
index 8092493..2a52c90 100644
--- a/lib/vagrant/ui.rb
+++ b/lib/vagrant/ui.rb
@@ -53,7 +53,7 @@ def initialize_copy(original)
             # We're being called in a trap-context. Wrap in a thread.
             Thread.new do
               @logger.info { "#{method}: #{message}" }
-            end.join
+            end.join(THREAD_MAX_JOIN_TIMEOUT)
           end
         end
       end
@@ -128,7 +128,7 @@ def machine(type, *data)
           @lock.synchronize do
             safe_puts("#{Time.now.utc.to_i},#{target},#{type},#{data.join(",")}")
           end
-        end.join
+        end.join(THREAD_MAX_JOIN_TIMEOUT)
       end
     end
 
@@ -244,7 +244,7 @@ def say(type, message, **opts)
             safe_puts(format_message(type, message, **opts),
                       io: channel, printer: printer)
           end
-        end.join
+        end.join(THREAD_MAX_JOIN_TIMEOUT)
       end
 
       def format_message(type, message, **opts)