passenger 2.2.2 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (254) hide show
  1. data/DEVELOPERS.TXT +13 -3
  2. data/Rakefile +42 -33
  3. data/bin/passenger-install-apache2-module +1 -2
  4. data/bin/passenger-install-nginx-module +7 -19
  5. data/bin/passenger-status +64 -15
  6. data/bin/passenger-stress-test +2 -2
  7. data/doc/ApplicationPool algorithm.txt +26 -22
  8. data/doc/Users guide Apache.html +374 -149
  9. data/doc/Users guide Apache.txt +318 -51
  10. data/doc/Users guide Nginx.html +13 -13
  11. data/doc/Users guide Nginx.txt +7 -2
  12. data/doc/cxxapi/Bucket_8h-source.html +62 -25
  13. data/doc/cxxapi/Configuration_8h-source.html +343 -326
  14. data/doc/cxxapi/DirectoryMapper_8h-source.html +12 -12
  15. data/doc/cxxapi/Hooks_8h-source.html +1 -1
  16. data/doc/cxxapi/annotated.html +1 -1
  17. data/doc/cxxapi/classHooks-members.html +1 -1
  18. data/doc/cxxapi/classHooks.html +1 -1
  19. data/doc/cxxapi/classPassenger_1_1DirectoryMapper-members.html +2 -2
  20. data/doc/cxxapi/classPassenger_1_1DirectoryMapper.html +9 -9
  21. data/doc/cxxapi/classes.html +1 -1
  22. data/doc/cxxapi/definitions_8h-source.html +1 -1
  23. data/doc/cxxapi/files.html +1 -1
  24. data/doc/cxxapi/functions.html +2 -2
  25. data/doc/cxxapi/functions_func.html +2 -2
  26. data/doc/cxxapi/graph_legend.html +1 -1
  27. data/doc/cxxapi/group__Configuration.html +1 -1
  28. data/doc/cxxapi/group__Core.html +1 -1
  29. data/doc/cxxapi/group__Hooks.html +1 -1
  30. data/doc/cxxapi/group__Support.html +1 -1
  31. data/doc/cxxapi/main.html +1 -1
  32. data/doc/cxxapi/modules.html +1 -1
  33. data/doc/rdoc/classes/ConditionVariable.html +194 -0
  34. data/doc/rdoc/classes/Exception.html +120 -0
  35. data/doc/rdoc/classes/GC.html +113 -0
  36. data/doc/rdoc/classes/IO.html +169 -0
  37. data/doc/rdoc/classes/PhusionPassenger.html +238 -0
  38. data/doc/rdoc/classes/PhusionPassenger/AbstractInstaller.html +153 -0
  39. data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +517 -0
  40. data/doc/rdoc/classes/PhusionPassenger/AbstractServer.html +719 -0
  41. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerAlreadyStarted.html +97 -0
  42. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerError.html +96 -0
  43. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/ServerNotStarted.html +97 -0
  44. data/doc/rdoc/classes/PhusionPassenger/AbstractServer/UnknownMessage.html +96 -0
  45. data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +598 -0
  46. data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +140 -0
  47. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +317 -0
  48. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +138 -0
  49. data/doc/rdoc/classes/PhusionPassenger/AppInitError.html +154 -0
  50. data/doc/rdoc/classes/PhusionPassenger/Application.html +283 -0
  51. data/doc/rdoc/classes/PhusionPassenger/ConsoleTextTemplate.html +172 -0
  52. data/doc/rdoc/classes/PhusionPassenger/FrameworkInitError.html +145 -0
  53. data/doc/rdoc/classes/PhusionPassenger/HTMLTemplate.html +175 -0
  54. data/doc/rdoc/classes/PhusionPassenger/InitializationError.html +141 -0
  55. data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +92 -0
  56. data/doc/rdoc/classes/PhusionPassenger/MessageChannel.html +489 -0
  57. data/doc/rdoc/classes/PhusionPassenger/NativeSupport.html +350 -0
  58. data/doc/rdoc/classes/PhusionPassenger/Rack.html +91 -0
  59. data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +188 -0
  60. data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +194 -0
  61. data/doc/rdoc/classes/PhusionPassenger/Railz.html +95 -0
  62. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +442 -0
  63. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +98 -0
  64. data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +200 -0
  65. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +436 -0
  66. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +98 -0
  67. data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +155 -0
  68. data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +402 -0
  69. data/doc/rdoc/classes/PhusionPassenger/UnknownError.html +125 -0
  70. data/doc/rdoc/classes/PhusionPassenger/Utils.html +805 -0
  71. data/doc/rdoc/classes/PhusionPassenger/VersionNotFound.html +140 -0
  72. data/doc/rdoc/classes/PhusionPassenger/WSGI.html +89 -0
  73. data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +188 -0
  74. data/doc/rdoc/classes/PlatformInfo.html +831 -0
  75. data/doc/rdoc/classes/RakeExtensions.html +197 -0
  76. data/doc/rdoc/classes/Signal.html +131 -0
  77. data/doc/rdoc/created.rid +1 -0
  78. data/doc/rdoc/files/DEVELOPERS_TXT.html +255 -0
  79. data/doc/rdoc/files/README.html +157 -0
  80. data/doc/rdoc/files/ext/phusion_passenger/native_support_c.html +92 -0
  81. data/doc/rdoc/files/lib/phusion_passenger/abstract_installer_rb.html +129 -0
  82. data/doc/rdoc/files/lib/phusion_passenger/abstract_request_handler_rb.html +131 -0
  83. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +126 -0
  84. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_rb.html +130 -0
  85. data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +130 -0
  86. data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +122 -0
  87. data/doc/rdoc/files/lib/phusion_passenger/application_rb.html +127 -0
  88. data/doc/rdoc/files/lib/phusion_passenger/console_text_template_rb.html +126 -0
  89. data/doc/rdoc/files/lib/phusion_passenger/constants_rb.html +122 -0
  90. data/doc/rdoc/files/lib/phusion_passenger/dependencies_rb.html +134 -0
  91. data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +122 -0
  92. data/doc/rdoc/files/lib/phusion_passenger/exceptions_rb.html +122 -0
  93. data/doc/rdoc/files/lib/phusion_passenger/html_template_rb.html +126 -0
  94. data/doc/rdoc/files/lib/phusion_passenger/message_channel_rb.html +122 -0
  95. data/doc/rdoc/files/lib/phusion_passenger/packaging_rb.html +122 -0
  96. data/doc/rdoc/files/lib/phusion_passenger/platform_info_rb.html +127 -0
  97. data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +133 -0
  98. data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +127 -0
  99. data/doc/rdoc/files/lib/phusion_passenger/railz/application_spawner_rb.html +143 -0
  100. data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +126 -0
  101. data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +145 -0
  102. data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +127 -0
  103. data/doc/rdoc/files/lib/phusion_passenger/simple_benchmarking_rb.html +122 -0
  104. data/doc/rdoc/files/lib/phusion_passenger/spawn_manager_rb.html +161 -0
  105. data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +175 -0
  106. data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +129 -0
  107. data/doc/rdoc/files/misc/rake/extensions_rb.html +130 -0
  108. data/doc/rdoc/fr_class_index.html +90 -0
  109. data/doc/rdoc/fr_file_index.html +76 -0
  110. data/doc/rdoc/fr_method_index.html +200 -0
  111. data/doc/rdoc/index.html +26 -0
  112. data/doc/rdoc/rdoc-style.css +187 -0
  113. data/doc/users_guide_snippets/rackup_specifications.txt +2 -8
  114. data/ext/apache2/Bucket.cpp +71 -38
  115. data/ext/apache2/Bucket.h +53 -16
  116. data/ext/apache2/Configuration.cpp +15 -0
  117. data/ext/apache2/Configuration.h +19 -2
  118. data/ext/apache2/DirectoryMapper.h +10 -10
  119. data/ext/apache2/Hooks.cpp +334 -74
  120. data/ext/boost/mpl/apply.hpp +5 -1
  121. data/ext/boost/mpl/apply_wrap.hpp +5 -2
  122. data/ext/boost/mpl/aux_/full_lambda.hpp +5 -1
  123. data/ext/boost/mpl/bind.hpp +5 -1
  124. data/ext/common/Application.h +11 -31
  125. data/ext/common/ApplicationPool.h +2 -1
  126. data/ext/common/ApplicationPoolServer.h +61 -20
  127. data/ext/common/ApplicationPoolServerExecutable.cpp +132 -4
  128. data/ext/common/ApplicationPoolStatusReporter.h +189 -65
  129. data/ext/common/Base64.cpp +143 -0
  130. data/ext/common/Base64.h +57 -0
  131. data/ext/common/CachedFileStat.cpp +25 -82
  132. data/ext/common/CachedFileStat.h +11 -125
  133. data/ext/common/CachedFileStat.hpp +243 -0
  134. data/ext/common/Exceptions.h +13 -0
  135. data/ext/common/FileChangeChecker.h +209 -0
  136. data/ext/common/Logging.h +3 -2
  137. data/ext/common/MessageChannel.h +10 -10
  138. data/ext/common/PoolOptions.h +72 -5
  139. data/ext/common/SpawnManager.h +11 -8
  140. data/ext/common/StandardApplicationPool.h +38 -39
  141. data/ext/common/StaticString.h +1 -0
  142. data/ext/common/StringListCreator.h +83 -0
  143. data/ext/common/SystemTime.h +3 -2
  144. data/ext/common/Timer.h +88 -0
  145. data/ext/common/Utils.cpp +161 -42
  146. data/ext/common/Utils.h +62 -31
  147. data/ext/common/Version.h +1 -1
  148. data/ext/nginx/Configuration.c +0 -4
  149. data/ext/nginx/ContentHandler.c +8 -6
  150. data/ext/nginx/HelperServer.cpp +45 -55
  151. data/ext/nginx/HttpStatusExtractor.h +4 -0
  152. data/ext/nginx/StaticContentHandler.c +25 -5
  153. data/ext/nginx/config +3 -0
  154. data/ext/nginx/ngx_http_passenger_module.c +72 -17
  155. data/ext/nginx/ngx_http_passenger_module.h +2 -2
  156. data/lib/phusion_passenger/abstract_request_handler.rb +15 -7
  157. data/lib/phusion_passenger/abstract_server.rb +16 -2
  158. data/lib/phusion_passenger/admin_tools/control_process.rb +36 -25
  159. data/lib/phusion_passenger/constants.rb +1 -1
  160. data/lib/phusion_passenger/dependencies.rb +10 -0
  161. data/lib/phusion_passenger/platform_info.rb +1 -1
  162. data/lib/phusion_passenger/rack/application_spawner.rb +21 -2
  163. data/lib/phusion_passenger/rack/request_handler.rb +10 -0
  164. data/lib/phusion_passenger/railz/application_spawner.rb +38 -2
  165. data/lib/phusion_passenger/railz/framework_spawner.rb +26 -28
  166. data/lib/phusion_passenger/railz/request_handler.rb +5 -1
  167. data/lib/phusion_passenger/spawn_manager.rb +6 -2
  168. data/lib/phusion_passenger/utils.rb +79 -27
  169. data/misc/rake/cplusplus.rb +5 -5
  170. data/test/ApplicationPoolServerTest.cpp +42 -0
  171. data/test/ApplicationPoolTest.cpp +255 -267
  172. data/test/Base64Test.cpp +48 -0
  173. data/test/CachedFileStatTest.cpp +243 -103
  174. data/test/FileChangeCheckerTest.cpp +331 -0
  175. data/test/PoolOptionsTest.cpp +80 -0
  176. data/test/UtilsTest.cpp +5 -17
  177. data/test/integration_tests/apache2_tests.rb +15 -4
  178. data/test/integration_tests/mycook_spec.rb +3 -4
  179. data/test/oxt/syscall_interruption_test.cpp +2 -14
  180. data/test/ruby/abstract_server_collection_spec.rb +1 -1
  181. data/test/ruby/abstract_server_spec.rb +35 -1
  182. data/test/ruby/rack/application_spawner_spec.rb +23 -6
  183. data/test/ruby/rails/application_spawner_spec.rb +6 -6
  184. data/test/ruby/rails/framework_spawner_spec.rb +6 -5
  185. data/test/ruby/rails/minimal_spawner_spec.rb +19 -0
  186. data/test/ruby/rails/spawner_error_handling_spec.rb +62 -7
  187. data/test/ruby/spawn_manager_spec.rb +10 -7
  188. data/test/ruby/spawn_server_spec.rb +1 -1
  189. data/test/ruby/utils_spec.rb +193 -20
  190. data/test/ruby/wsgi/application_spawner_spec.rb +3 -1
  191. data/test/stub/apache2/httpd.conf.erb +3 -0
  192. data/test/stub/rack/config.ru +1 -1
  193. data/test/stub/rails_apps/mycook/app/controllers/welcome_controller.rb +8 -0
  194. data/test/support/Support.cpp +84 -0
  195. data/test/support/Support.h +66 -8
  196. data/test/support/config.rb +14 -2
  197. data/test/support/test_helper.rb +5 -0
  198. data/vendor/rack-1.0.0-git/lib/rack/auth/openid.rb +123 -116
  199. data/vendor/rack-1.0.0-git/lib/rack/cascade.rb +17 -12
  200. data/vendor/rack-1.0.0-git/lib/rack/commonlogger.rb +34 -43
  201. data/vendor/rack-1.0.0-git/lib/rack/handler/cgi.rb +1 -1
  202. data/vendor/rack-1.0.0-git/lib/rack/handler/fastcgi.rb +1 -1
  203. data/vendor/rack-1.0.0-git/lib/rack/handler/lsws.rb +1 -1
  204. data/vendor/rack-1.0.0-git/lib/rack/handler/mongrel.rb +1 -1
  205. data/vendor/rack-1.0.0-git/lib/rack/handler/scgi.rb +1 -1
  206. data/vendor/rack-1.0.0-git/lib/rack/handler/webrick.rb +1 -1
  207. data/vendor/rack-1.0.0-git/lib/rack/mock.rb +4 -17
  208. data/vendor/rack-1.0.0-git/lib/rack/request.rb +3 -9
  209. data/vendor/rack-1.0.0-git/lib/rack/rewindable_input.rb +2 -0
  210. data/vendor/rack-1.0.0-git/lib/rack/utils.rb +38 -12
  211. metadata +231 -186
  212. data/ext/common/FileChecker.h +0 -112
  213. data/test/FileCheckerTest.cpp +0 -79
  214. data/test/stub/minimal-railsapp/README +0 -3
  215. data/test/stub/minimal-railsapp/config/application.rb +0 -0
  216. data/test/stub/minimal-railsapp/config/environment.rb +0 -3
  217. data/test/stub/minimal-railsapp/vendor/rails/actionmailer/lib/action_mailer.rb +0 -0
  218. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +0 -10
  219. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_pack.rb +0 -0
  220. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_view.rb +0 -0
  221. data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +0 -7
  222. data/test/stub/minimal-railsapp/vendor/rails/activeresource/lib/active_resource.rb +0 -0
  223. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support.rb +0 -17
  224. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support/whiny_nil.rb +0 -0
  225. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/dispatcher.rb +0 -0
  226. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/initializer.rb +0 -8
  227. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/ruby_version_check.rb +0 -1
  228. data/test/stub/railsapp/app/controllers/application.rb +0 -12
  229. data/test/stub/railsapp/app/controllers/bar_controller.rb +0 -5
  230. data/test/stub/railsapp/app/controllers/bar_controller_1.txt +0 -5
  231. data/test/stub/railsapp/app/controllers/bar_controller_2.txt +0 -5
  232. data/test/stub/railsapp/app/controllers/foo_controller.rb +0 -9
  233. data/test/stub/railsapp/app/helpers/application_helper.rb +0 -3
  234. data/test/stub/railsapp/config/boot.rb +0 -108
  235. data/test/stub/railsapp/config/database.yml +0 -19
  236. data/test/stub/railsapp/config/environment.rb +0 -59
  237. data/test/stub/railsapp/config/environments/development.rb +0 -18
  238. data/test/stub/railsapp/config/environments/production.rb +0 -19
  239. data/test/stub/railsapp/config/initializers/inflections.rb +0 -10
  240. data/test/stub/railsapp/config/initializers/mime_types.rb +0 -5
  241. data/test/stub/railsapp/config/routes.rb +0 -35
  242. data/test/stub/railsapp/public/useless.txt +0 -1
  243. data/test/stub/railsapp2/app/controllers/application.rb +0 -12
  244. data/test/stub/railsapp2/app/controllers/foo_controller.rb +0 -5
  245. data/test/stub/railsapp2/app/helpers/application_helper.rb +0 -3
  246. data/test/stub/railsapp2/config/boot.rb +0 -108
  247. data/test/stub/railsapp2/config/database.yml +0 -19
  248. data/test/stub/railsapp2/config/environment.rb +0 -59
  249. data/test/stub/railsapp2/config/environments/development.rb +0 -18
  250. data/test/stub/railsapp2/config/environments/production.rb +0 -19
  251. data/test/stub/railsapp2/config/initializers/inflections.rb +0 -10
  252. data/test/stub/railsapp2/config/initializers/mime_types.rb +0 -5
  253. data/test/stub/railsapp2/config/routes.rb +0 -35
  254. data/test/stub/railsapp2/public/useless.txt +0 -1
@@ -135,7 +135,10 @@ struct apply
135
135
 
136
136
  ///// iteration, depth == 1
137
137
 
138
- #elif BOOST_PP_ITERATION_DEPTH() == 1
138
+ // For gcc 4.4 compatability, we must include the
139
+ // BOOST_PP_ITERATION_DEPTH test inside an #else clause.
140
+ #else // BOOST_PP_IS_ITERATING
141
+ #if BOOST_PP_ITERATION_DEPTH() == 1
139
142
 
140
143
  # define i_ BOOST_PP_FRAME_ITERATION(1)
141
144
 
@@ -222,4 +225,5 @@ struct apply_chooser<i_>
222
225
 
223
226
  # undef i_
224
227
 
228
+ #endif // BOOST_PP_ITERATION_DEPTH()
225
229
  #endif // BOOST_PP_IS_ITERATING
@@ -78,7 +78,10 @@ namespace boost { namespace mpl {
78
78
 
79
79
  ///// iteration, depth == 1
80
80
 
81
- #elif BOOST_PP_ITERATION_DEPTH() == 1
81
+ // For gcc 4.4 compatability, we must include the
82
+ // BOOST_PP_ITERATION_DEPTH test inside an #else clause.
83
+ #else
84
+ #if BOOST_PP_ITERATION_DEPTH() == 1
82
85
 
83
86
  # define i_ BOOST_PP_FRAME_ITERATION(1)
84
87
 
@@ -196,5 +199,5 @@ struct BOOST_PP_CAT(apply_wrap_impl,i_)<
196
199
  };
197
200
 
198
201
  # undef j_
199
-
202
+ #endif // BOOST_PP_ITERATION_DEPTH()
200
203
  #endif // BOOST_PP_IS_ITERATING
@@ -227,7 +227,10 @@ BOOST_MPL_AUX_NA_SPEC2(2, 3, lambda)
227
227
 
228
228
  ///// iteration, depth == 1
229
229
 
230
- #elif BOOST_PP_ITERATION_DEPTH() == 1
230
+ // For gcc 4.4 compatability, we must include the
231
+ // BOOST_PP_ITERATION_DEPTH test inside an #else clause.
232
+ #else // BOOST_PP_IS_ITERATING
233
+ #if BOOST_PP_ITERATION_DEPTH() == 1
231
234
  #define i_ BOOST_PP_FRAME_ITERATION(1)
232
235
 
233
236
  #if i_ > 0
@@ -347,4 +350,5 @@ struct lambda<
347
350
  };
348
351
 
349
352
  #undef i_
353
+ #endif // BOOST_PP_ITERATION_DEPTH()
350
354
  #endif // BOOST_PP_IS_ITERATING
@@ -361,7 +361,10 @@ BOOST_MPL_AUX_TEMPLATE_ARITY_SPEC(
361
361
 
362
362
  ///// iteration, depth == 1
363
363
 
364
- #elif BOOST_PP_ITERATION_DEPTH() == 1
364
+ // For gcc 4.4 compatability, we must include the
365
+ // BOOST_PP_ITERATION_DEPTH test inside an #else clause.
366
+ #else // BOOST_PP_IS_ITERATING
367
+ #if BOOST_PP_ITERATION_DEPTH() == 1
365
368
 
366
369
  # define i_ BOOST_PP_FRAME_ITERATION(1)
367
370
 
@@ -544,4 +547,5 @@ struct bind_chooser<i_>
544
547
  # endif
545
548
  # undef j_
546
549
 
550
+ #endif // BOOST_PP_ITERATION_DEPTH()
547
551
  #endif // BOOST_PP_IS_ITERATING
@@ -283,7 +283,7 @@ private:
283
283
  if (fd != -1) {
284
284
  int ret = syscalls::shutdown(fd, SHUT_RD);
285
285
  if (ret == -1) {
286
- throw SystemException("Cannot shutdown the writer stream",
286
+ throw SystemException("Cannot shutdown the reader stream",
287
287
  errno);
288
288
  }
289
289
  }
@@ -304,11 +304,16 @@ private:
304
304
  TRACE_POINT();
305
305
  if (fd != -1) {
306
306
  int ret = syscalls::close(fd);
307
+ fd = -1;
307
308
  if (ret == -1) {
308
- throw SystemException("Cannot close the session stream",
309
- errno);
309
+ if (errno == EIO) {
310
+ throw SystemException("A write operation on the session stream failed",
311
+ errno);
312
+ } else {
313
+ throw SystemException("Cannot close the session stream",
314
+ errno);
315
+ }
310
316
  }
311
- fd = -1;
312
317
  }
313
318
  }
314
319
 
@@ -329,33 +334,7 @@ private:
329
334
 
330
335
  SessionPtr connectToUnixServer(const function<void()> &closeCallback) const {
331
336
  TRACE_POINT();
332
- int fd, ret;
333
-
334
- do {
335
- fd = socket(PF_UNIX, SOCK_STREAM, 0);
336
- } while (fd == -1 && errno == EINTR);
337
- if (fd == -1) {
338
- throw SystemException("Cannot create a new unconnected Unix socket", errno);
339
- }
340
-
341
- struct sockaddr_un addr;
342
- addr.sun_family = AF_UNIX;
343
- strncpy(addr.sun_path, listenSocketName.c_str(), sizeof(addr.sun_path));
344
- addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
345
- do {
346
- ret = ::connect(fd, (const sockaddr *) &addr, sizeof(addr));
347
- } while (ret == -1 && errno == EINTR);
348
- if (ret == -1) {
349
- int e = errno;
350
- string message("Cannot connect to Unix socket '");
351
- message.append(listenSocketName);
352
- message.append("'");
353
- do {
354
- ret = close(fd);
355
- } while (ret == -1 && errno == EINTR);
356
- throw SystemException(message, e);
357
- }
358
-
337
+ int fd = Passenger::connectToUnixServer(listenSocketName.c_str());
359
338
  return ptr(new StandardSession(pid, closeCallback, fd));
360
339
  }
361
340
 
@@ -510,6 +489,7 @@ public:
510
489
  * @post this->getSessions() == old->getSessions() + 1
511
490
  * @throws SystemException Something went wrong during the connection process.
512
491
  * @throws IOException Something went wrong during the connection process.
492
+ * @throws boost::thread_interrupted
513
493
  */
514
494
  SessionPtr connect(const function<void()> &closeCallback) const {
515
495
  TRACE_POINT();
@@ -126,7 +126,8 @@ public:
126
126
  * @throw BusyException The application pool is too busy right now, and cannot
127
127
  * satisfy the request. One should either abort, or try again later.
128
128
  * @throw IOException Something else went wrong.
129
- * @throw thread_interrupted
129
+ * @throw boost::thread_interrupted
130
+ * @throws Anything thrown by options.environmentVariables->getItems().
130
131
  * @note Applications are uniquely identified with the application root
131
132
  * string. So although <tt>appRoot</tt> does not have to be absolute, it
132
133
  * should be. If one calls <tt>get("/home/foo")</tt> and
@@ -216,7 +216,7 @@ private:
216
216
  if (fd != -1) {
217
217
  int ret = syscalls::shutdown(fd, SHUT_RD);
218
218
  if (ret == -1) {
219
- throw SystemException("Cannot shutdown the writer stream",
219
+ throw SystemException("Cannot shutdown the reader stream",
220
220
  errno);
221
221
  }
222
222
  }
@@ -235,11 +235,16 @@ private:
235
235
  virtual void closeStream() {
236
236
  if (fd != -1) {
237
237
  int ret = syscalls::close(fd);
238
+ fd = -1;
238
239
  if (ret == -1) {
239
- throw SystemException("Cannot close the session stream",
240
- errno);
240
+ if (errno == EIO) {
241
+ throw SystemException("A write operation on the session stream failed",
242
+ errno);
243
+ } else {
244
+ throw SystemException("Cannot close the session stream",
245
+ errno);
246
+ }
241
247
  }
242
- fd = -1;
243
248
  }
244
249
  }
245
250
 
@@ -380,12 +385,18 @@ private:
380
385
  vector<string> args;
381
386
  int stream;
382
387
  bool result;
388
+ bool serverMightNeedEnvironmentVariables = true;
383
389
 
390
+ /* Send a 'get' request to the ApplicationPool server.
391
+ * For efficiency reasons, we do not send the data for
392
+ * options.environmentVariables over the wire yet until
393
+ * it's necessary.
394
+ */
384
395
  try {
385
396
  vector<string> args;
386
397
 
387
398
  args.push_back("get");
388
- options.toVector(args);
399
+ options.toVector(args, false);
389
400
  channel.write(args);
390
401
  } catch (const SystemException &e) {
391
402
  UPDATE_TRACE_POINT();
@@ -395,22 +406,52 @@ private:
395
406
  message.append(e.brief());
396
407
  throw SystemException(message, e.code());
397
408
  }
398
- try {
399
- UPDATE_TRACE_POINT();
400
- result = channel.read(args);
401
- } catch (const SystemException &e) {
402
- UPDATE_TRACE_POINT();
403
- data->disconnect();
404
- throw SystemException("Could not read a message from "
405
- "the ApplicationPool server", e.code());
406
- }
407
- if (!result) {
408
- UPDATE_TRACE_POINT();
409
- data->disconnect();
410
- throw IOException("The ApplicationPool server unexpectedly "
411
- "closed the connection while we're reading a response "
412
- "for the 'get' command.");
409
+
410
+ /* The first few replies from the server might be for requesting
411
+ * environment variables in the pool options object, so keep handling
412
+ * these requests until we receive a different reply.
413
+ */
414
+ while (serverMightNeedEnvironmentVariables) {
415
+ try {
416
+ result = channel.read(args);
417
+ } catch (const SystemException &e) {
418
+ UPDATE_TRACE_POINT();
419
+ data->disconnect();
420
+ throw SystemException("Could not read a response from "
421
+ "the ApplicationPool server for the 'get' command", e.code());
422
+ }
423
+ if (!result) {
424
+ UPDATE_TRACE_POINT();
425
+ data->disconnect();
426
+ throw IOException("The ApplicationPool server unexpectedly "
427
+ "closed the connection while we're reading a response "
428
+ "for the 'get' command.");
429
+ }
430
+
431
+ if (args[0] == "getEnvironmentVariables") {
432
+ try {
433
+ if (options.environmentVariables) {
434
+ UPDATE_TRACE_POINT();
435
+ channel.writeScalar(options.serializeEnvironmentVariables());
436
+ } else {
437
+ UPDATE_TRACE_POINT();
438
+ channel.writeScalar("");
439
+ }
440
+ } catch (const SystemException &e) {
441
+ data->disconnect();
442
+ throw SystemException("Could not send a response "
443
+ "for the 'getEnvironmentVariables' request "
444
+ "to the ApplicationPool server",
445
+ e.code());
446
+ }
447
+ } else {
448
+ serverMightNeedEnvironmentVariables = false;
449
+ }
413
450
  }
451
+
452
+ /* We've now received a reply other than "getEnvironmentVariables".
453
+ * Handle this...
454
+ */
414
455
  if (args[0] == "ok") {
415
456
  UPDATE_TRACE_POINT();
416
457
  pid_t pid = (pid_t) atol(args[1]);
@@ -288,6 +288,131 @@ private:
288
288
  /** Last used session ID. */
289
289
  int lastSessionID;
290
290
 
291
+ class ClientCommunicationError: public oxt::tracable_exception {
292
+ private:
293
+ string briefMessage;
294
+ string systemMessage;
295
+ string fullMessage;
296
+ int m_code;
297
+ public:
298
+ /**
299
+ * Create a new ClientCommunicationError.
300
+ *
301
+ * @param briefMessage A brief message describing the error.
302
+ * @param errorCode An optional error code, i.e. the value of errno right after the error occured, if applicable.
303
+ * @note A system description of the error will be appended to the given message.
304
+ * For example, if <tt>errorCode</tt> is <tt>EBADF</tt>, and <tt>briefMessage</tt>
305
+ * is <em>"Something happened"</em>, then what() will return <em>"Something happened: Bad
306
+ * file descriptor (10)"</em> (if 10 is the number for EBADF).
307
+ * @post code() == errorCode
308
+ * @post brief() == briefMessage
309
+ */
310
+ ClientCommunicationError(const string &briefMessage, int errorCode = -1) {
311
+ if (errorCode != -1) {
312
+ stringstream str;
313
+
314
+ str << strerror(errorCode) << " (" << errorCode << ")";
315
+ systemMessage = str.str();
316
+ }
317
+ setBriefMessage(briefMessage);
318
+ m_code = errorCode;
319
+ }
320
+
321
+ virtual ~ClientCommunicationError() throw() {}
322
+
323
+ virtual const char *what() const throw() {
324
+ return fullMessage.c_str();
325
+ }
326
+
327
+ void setBriefMessage(const string &message) {
328
+ briefMessage = message;
329
+ if (systemMessage.empty()) {
330
+ fullMessage = briefMessage;
331
+ } else {
332
+ fullMessage = briefMessage + ": " + systemMessage;
333
+ }
334
+ }
335
+
336
+ /**
337
+ * The value of <tt>errno</tt> at the time the error occured.
338
+ */
339
+ int code() const throw() {
340
+ return m_code;
341
+ }
342
+
343
+ /**
344
+ * Returns a brief version of the exception message. This message does
345
+ * not include the system error description, and is equivalent to the
346
+ * value of the <tt>message</tt> parameter as passed to the constructor.
347
+ */
348
+ string brief() const throw() {
349
+ return briefMessage;
350
+ }
351
+
352
+ /**
353
+ * Returns the system's error message. This message contains both the
354
+ * content of <tt>strerror(errno)</tt> and the errno number itself.
355
+ *
356
+ * @post if code() == -1: result.empty()
357
+ */
358
+ string sys() const throw() {
359
+ return systemMessage;
360
+ }
361
+ };
362
+
363
+ /**
364
+ * A StringListCreator which fetches its items from the client.
365
+ * Used as an optimization for ApplicationPoolServer::Client.get():
366
+ * environment variables are only serialized by the client process
367
+ * if a new backend process is being spawned.
368
+ */
369
+ class EnvironmentVariablesFetcher: public StringListCreator {
370
+ private:
371
+ MessageChannel &channel;
372
+ PoolOptions &options;
373
+ public:
374
+ EnvironmentVariablesFetcher(MessageChannel &theChannel, PoolOptions &theOptions)
375
+ : channel(theChannel),
376
+ options(theOptions)
377
+ { }
378
+
379
+ /**
380
+ * @throws ClientCommunicationError
381
+ */
382
+ virtual const StringListPtr getItems() const {
383
+ string data;
384
+
385
+ /* If an I/O error occurred while communicating with the client,
386
+ * then throw a ClientCommunicationException, which will bubble
387
+ * all the way up to the thread main loop, where the connection
388
+ * with the client will be broken.
389
+ */
390
+ try {
391
+ channel.write("getEnvironmentVariables", NULL);
392
+ } catch (const SystemException &e) {
393
+ throw ClientCommunicationError(
394
+ "Unable to send a 'getEnvironmentVariables' request to the client",
395
+ e.code());
396
+ }
397
+ try {
398
+ if (!channel.readScalar(data)) {
399
+ throw ClientCommunicationError("Unable to read a reply from the client for the 'getEnvironmentVariables' request.");
400
+ }
401
+ } catch (const SystemException &e) {
402
+ throw ClientCommunicationError(
403
+ "Unable to read a reply from the client for the 'getEnvironmentVariables' request",
404
+ e.code());
405
+ }
406
+
407
+ if (!data.empty()) {
408
+ SimpleStringListCreator list(data);
409
+ return list.getItems();
410
+ } else {
411
+ return ptr(new StringList());
412
+ }
413
+ }
414
+ };
415
+
291
416
  void processGet(const vector<string> &args) {
292
417
  TRACE_POINT();
293
418
  Application::SessionPtr session;
@@ -295,6 +420,7 @@ private:
295
420
 
296
421
  try {
297
422
  PoolOptions options(args, 1);
423
+ options.environmentVariables = ptr(new EnvironmentVariablesFetcher(channel, options));
298
424
  session = server.pool->get(options);
299
425
  sessions[lastSessionID] = session;
300
426
  lastSessionID++;
@@ -331,12 +457,14 @@ private:
331
457
  UPDATE_TRACE_POINT();
332
458
  channel.write("ok", toString(session->getPid()).c_str(),
333
459
  toString(lastSessionID - 1).c_str(), NULL);
460
+ UPDATE_TRACE_POINT();
334
461
  channel.writeFileDescriptor(session->getStream());
335
- session->closeStream();
336
- } catch (const exception &) {
337
462
  UPDATE_TRACE_POINT();
338
- P_TRACE(3, "Client " << this << ": something went wrong "
339
- "while sending 'ok' back to the client.");
463
+ session->closeStream();
464
+ } catch (const exception &e) {
465
+ P_TRACE(3, "Client " << this << ": could not send "
466
+ "'ok' back to the ApplicationPool client: " <<
467
+ e.what());
340
468
  sessions.erase(lastSessionID - 1);
341
469
  throw;
342
470
  }
@@ -33,6 +33,8 @@
33
33
 
34
34
  #include <string>
35
35
  #include <sys/types.h>
36
+ #include <sys/socket.h>
37
+ #include <sys/un.h>
36
38
  #include <sys/stat.h>
37
39
  #include <cstdio>
38
40
  #include <unistd.h>
@@ -40,6 +42,7 @@
40
42
 
41
43
  #include "StandardApplicationPool.h"
42
44
  #include "MessageChannel.h"
45
+ #include "Exceptions.h"
43
46
  #include "Logging.h"
44
47
  #include "Utils.h"
45
48
 
@@ -51,72 +54,176 @@ using namespace std;
51
54
 
52
55
  /**
53
56
  * An ApplicationPoolStatusReporter allows commandline admin tools to inspect
54
- * the status of a StandardApplicationPool. It does so by creating a FIFO
55
- * in the Passenger temp folder.
57
+ * the status of a StandardApplicationPool. It does so by creating a Unix socket
58
+ * in the Passenger temp folder, which tools can connect to to query for
59
+ * information.
56
60
  *
57
- * An ApplicationPoolStatusReporter creates a background thread, which
58
- * continuously sends new information through the FIFO. This thread will
59
- * be automatically cleaned up upon destroying the ApplicationPoolStatusReporter
60
- * object.
61
+ * An ApplicationPoolStatusReporter creates a background thread for handling
62
+ * connections on the socket. This thread will be automatically cleaned up upon
63
+ * destroying the ApplicationPoolStatusReporter object.
61
64
  */
62
65
  class ApplicationPoolStatusReporter {
63
66
  private:
67
+ /**
68
+ * Wrapper class around a file descriptor integer, for RAII behavior.
69
+ *
70
+ * A FileDescriptor object behaves just like an int, so that you can pass it to
71
+ * system calls such as read(). It performs reference counting. When the last
72
+ * copy of a FileDescriptor has been destroyed, the underlying file descriptor
73
+ * will be automatically closed.
74
+ */
75
+ class FileDescriptor {
76
+ private:
77
+ struct SharedData {
78
+ int fd;
79
+
80
+ /**
81
+ * Constructor to assign this file descriptor's handle.
82
+ */
83
+ SharedData(int fd) {
84
+ this->fd = fd;
85
+ }
86
+
87
+ /**
88
+ * Attempts to close this file descriptor. When created on the stack,
89
+ * this destructor will automatically be invoked as a result of C++
90
+ * semantics when exiting the scope this object was created in. This
91
+ * ensures that stack created objects with destructors like these will
92
+ * de-allocate their resources upon leaving their corresponding scope.
93
+ * This pattern is also known Resource Acquisition Is Initialization (RAII).
94
+ *
95
+ * @throws SystemException File descriptor could not be closed.
96
+ */
97
+ ~SharedData() {
98
+ this_thread::disable_syscall_interruption dsi;
99
+ if (syscalls::close(fd) == -1) {
100
+ throw SystemException("Cannot close file descriptor", errno);
101
+ }
102
+ }
103
+ };
104
+
105
+ /* Shared pointer for reference counting on this file descriptor */
106
+ shared_ptr<SharedData> data;
107
+
108
+ public:
109
+ FileDescriptor() {
110
+ // Do nothing.
111
+ }
112
+
113
+ /**
114
+ * Creates a new FileDescriptor instance with the given fd as a handle.
115
+ */
116
+ FileDescriptor(int fd) {
117
+ data = ptr(new SharedData(fd));
118
+ }
119
+
120
+ /**
121
+ * Overloads the integer cast operator so that it will return the file
122
+ * descriptor handle as an integer.
123
+ *
124
+ * @return This file descriptor's handle as an integer.
125
+ */
126
+ operator int () const {
127
+ return data->fd;
128
+ }
129
+ };
130
+
64
131
  /** The application pool to monitor. */
65
132
  StandardApplicationPoolPtr pool;
66
133
 
67
- /** The FIFO's filename. */
134
+ /** The socket's filename. */
68
135
  char filename[PATH_MAX];
69
136
 
70
- /** The background thread. */
71
- oxt::thread *thr;
137
+ /** The socket's file descriptor. */
138
+ int serverFd;
139
+
140
+ /** The main thread. */
141
+ oxt::thread *mainThread;
72
142
 
73
- void threadMain() {
143
+ /** The mutex which protects the 'threads' member. */
144
+ boost::mutex threadsLock;
145
+
146
+ /** A map which maps a client file descriptor to its handling thread. */
147
+ map< int, shared_ptr<oxt::thread> > threads;
148
+
149
+ void writeScalarAndIgnoreErrors(MessageChannel &channel, const string &data) {
150
+ try {
151
+ channel.writeScalar(data);
152
+ } catch (const SystemException &e) {
153
+ // Don't care about write errors.
154
+ }
155
+ }
156
+
157
+ void mainThreadFunction() {
74
158
  TRACE_POINT();
75
159
  try {
76
160
  while (!this_thread::interruption_requested()) {
77
- struct stat buf;
78
- int ret;
79
-
80
161
  UPDATE_TRACE_POINT();
81
- do {
82
- ret = stat(filename, &buf);
83
- } while (ret == -1 && errno == EINTR);
84
- if (ret == -1 || !S_ISFIFO(buf.st_mode)) {
85
- // Something bad happened with the status
86
- // report FIFO, so we bail out.
87
- break;
88
- }
162
+ sockaddr_un addr;
163
+ socklen_t addr_len = sizeof(addr);
89
164
 
90
- UPDATE_TRACE_POINT();
91
- FILE *f = syscalls::fopen(filename, "w");
92
- if (f == NULL) {
165
+ FileDescriptor fd(syscalls::accept(serverFd, (struct sockaddr *) &addr, &addr_len));
166
+ if (fd == -1) {
93
167
  int e = errno;
94
- P_ERROR("Cannot open status report FIFO " <<
95
- filename << ": " <<
168
+ P_ERROR("Cannot accept new client on status reporter socket: " <<
96
169
  strerror(e) << " (" << e << ")");
97
170
  break;
98
171
  }
99
172
 
100
- UPDATE_TRACE_POINT();
101
- MessageChannel channel(fileno(f));
102
- string report;
103
- report.append("----------- Backtraces -----------\n");
104
- report.append(oxt::thread::all_backtraces());
105
- report.append("\n\n");
106
- report.append(pool->toString());
173
+ boost::lock_guard<boost::mutex> l(threadsLock);
174
+ this_thread::disable_syscall_interruption dsi;
175
+ this_thread::disable_interruption di;
176
+ shared_ptr<oxt::thread> thread(new oxt::thread(
177
+ bind(&ApplicationPoolStatusReporter::clientThreadFunction, this, fd),
178
+ "Status reporter client thread " + toString(fd),
179
+ 1024 * 128
180
+ ));
181
+ threads[fd] = thread;
182
+ }
183
+ } catch (const boost::thread_interrupted &) {
184
+ P_TRACE(2, "Status reporter main thread interrupted.");
185
+ } catch (const exception &e) {
186
+ P_ERROR("Error in status reporter main thread: " << e.what());
187
+ }
188
+ }
189
+
190
+ void clientThreadFunction(FileDescriptor fd) {
191
+ TRACE_POINT();
192
+ MessageChannel channel(fd);
193
+
194
+ try {
195
+ while (!this_thread::interruption_requested()) {
196
+ vector<string> args;
107
197
 
108
198
  UPDATE_TRACE_POINT();
109
- try {
110
- channel.writeScalar(report);
111
- channel.writeScalar(pool->toXml());
112
- } catch (...) {
113
- // Ignore write errors.
199
+ if (!channel.read(args) || args.size() < 1) {
200
+ break;
201
+ }
202
+
203
+ if (args[0] == "backtraces") {
204
+ UPDATE_TRACE_POINT();
205
+ writeScalarAndIgnoreErrors(channel, oxt::thread::all_backtraces());
206
+ } else if (args[0] == "status") {
207
+ UPDATE_TRACE_POINT();
208
+ writeScalarAndIgnoreErrors(channel, pool->toString());
209
+ } else if (args[0] == "status_xml") {
210
+ UPDATE_TRACE_POINT();
211
+ writeScalarAndIgnoreErrors(channel, pool->toXml());
212
+ } else {
213
+ P_ERROR("Error in status reporter client thread: unknown query '" <<
214
+ args[0] << "'.");
114
215
  }
115
- syscalls::fclose(f);
116
216
  }
117
217
  } catch (const boost::thread_interrupted &) {
118
- P_TRACE(2, "Status report thread interrupted.");
218
+ P_TRACE(2, "Status reporter client thread " << fd << " interrupted.");
219
+ } catch (const exception &e) {
220
+ P_ERROR("Error in status reporter client thread: " << e.what());
119
221
  }
222
+
223
+ boost::lock_guard<boost::mutex> l(threadsLock);
224
+ this_thread::disable_syscall_interruption dsi;
225
+ this_thread::disable_interruption di;
226
+ threads.erase(fd);
120
227
  }
121
228
 
122
229
  public:
@@ -134,9 +241,11 @@ public:
134
241
  * -1 if the current user should be set as owner.
135
242
  * @param gid The GID of the user who should own the FIFO file, or
136
243
  * -1 if the current group should be set as group.
137
- * @throws SystemException An error occurred while creating the FIFO.
244
+ * @throws RuntimeException An error occurred.
245
+ * @throws SystemException An error occurred while creating the server socket.
138
246
  * @throws boost::thread_resource_error Something went wrong during
139
247
  * creation of the thread.
248
+ * @throws boost::thread_interrupted A system call has been interrupted.
140
249
  */
141
250
  ApplicationPoolStatusReporter(StandardApplicationPoolPtr &pool,
142
251
  bool userSwitching,
@@ -149,27 +258,17 @@ public:
149
258
  createPassengerTempDir(getSystemTempDir(), userSwitching,
150
259
  "nobody", geteuid(), getegid());
151
260
 
152
- snprintf(filename, sizeof(filename) - 1, "%s/info/status.fifo",
261
+ snprintf(filename, sizeof(filename) - 1, "%s/info/status.socket",
153
262
  getPassengerTempDir().c_str());
154
263
  filename[PATH_MAX - 1] = '\0';
264
+ serverFd = createUnixServer(filename, 10);
155
265
 
156
- do {
157
- ret = mkfifo(filename, permissions);
158
- } while (ret == -1 && errno == EINTR);
159
- if (ret == -1 && errno != EEXIST) {
160
- int e = errno;
161
- string message("Cannot create FIFO '");
162
- message.append(filename);
163
- message.append("'");
164
- throw SystemException(message, e);
165
- }
166
-
167
- // It seems that the permissions passed to mkfifo()
168
- // aren't respected, so here we chmod the file.
266
+ /* Set the socket file's permissions... */
169
267
  do {
170
268
  ret = chmod(filename, permissions);
171
269
  } while (ret == -1 && errno == EINTR);
172
270
 
271
+ /* ...and ownership. */
173
272
  if (uid != (uid_t) -1 && gid != (gid_t) -1) {
174
273
  do {
175
274
  ret = chown(filename, uid, gid);
@@ -179,31 +278,56 @@ public:
179
278
  char message[1024];
180
279
 
181
280
  snprintf(message, sizeof(message) - 1,
182
- "Cannot set the FIFO file '%s' its owner to %lld and group to %lld",
281
+ "Cannot set the owner for socket file '%s' to %lld and its group to %lld",
183
282
  filename, (long long) uid, (long long) gid);
184
283
  message[sizeof(message) - 1] = '\0';
284
+ do {
285
+ ret = close(serverFd);
286
+ } while (ret == -1 && errno == EINTR);
185
287
  throw SystemException(message, e);
186
288
  }
187
289
  }
188
290
 
189
- thr = new oxt::thread(
190
- bind(&ApplicationPoolStatusReporter::threadMain, this),
191
- "Status report thread",
192
- 1024 * 128
193
- );
291
+ try {
292
+ mainThread = new oxt::thread(
293
+ bind(&ApplicationPoolStatusReporter::mainThreadFunction, this),
294
+ "Status reporter main thread",
295
+ 1024 * 128
296
+ );
297
+ } catch (...) {
298
+ do {
299
+ ret = close(serverFd);
300
+ } while (ret == -1 && errno == EINTR);
301
+ throw;
302
+ }
194
303
  }
195
304
 
196
305
  ~ApplicationPoolStatusReporter() {
197
306
  this_thread::disable_syscall_interruption dsi;
198
307
  this_thread::disable_interruption di;
199
-
200
- thr->interrupt_and_join();
201
- delete thr;
202
-
203
308
  int ret;
309
+
204
310
  do {
205
311
  ret = unlink(filename);
206
312
  } while (ret == -1 && errno == EINTR);
313
+
314
+ mainThread->interrupt_and_join();
315
+ delete mainThread;
316
+
317
+ do {
318
+ ret = close(serverFd);
319
+ } while (ret == -1 && errno == EINTR);
320
+
321
+ /* We make a copy of the data structure here to avoid deadlocks. */
322
+ map< int, shared_ptr<oxt::thread> > threadsCopy;
323
+ {
324
+ boost::lock_guard<boost::mutex> l(threadsLock);
325
+ threadsCopy = threads;
326
+ }
327
+ map< int, shared_ptr<oxt::thread> >::iterator it;
328
+ for (it = threadsCopy.begin(); it != threadsCopy.end(); it++) {
329
+ it->second->interrupt_and_join();
330
+ }
207
331
  }
208
332
  };
209
333