passenger 3.0.21 → 3.9.1.beta

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 (835) hide show
  1. data/DEVELOPERS.TXT +4 -10
  2. data/NEWS +19 -27
  3. data/Rakefile +20 -19
  4. data/bin/passenger +3 -2
  5. data/bin/passenger-config +35 -5
  6. data/bin/passenger-install-apache2-module +12 -12
  7. data/bin/passenger-install-nginx-module +55 -38
  8. data/bin/passenger-memory-stats +3 -1
  9. data/bin/passenger-status +7 -35
  10. data/build/agents.rb +107 -21
  11. data/build/apache2.rb +11 -46
  12. data/build/basics.rb +61 -9
  13. data/build/common_library.rb +59 -142
  14. data/build/cxx_tests.rb +111 -110
  15. data/build/documentation.rb +33 -0
  16. data/build/misc.rb +30 -12
  17. data/build/nginx.rb +10 -39
  18. data/build/oxt_tests.rb +1 -0
  19. data/build/ruby_extension.rb +1 -5
  20. data/build/test_basics.rb +3 -2
  21. data/dev/copy_boost_headers.rb +2 -1
  22. data/doc/Architectural overview.html +49 -90
  23. data/doc/DebuggingAndStressTesting.txt.md +49 -0
  24. data/doc/Packaging.txt.md +254 -0
  25. data/doc/Security of user switching support.html +35 -66
  26. data/doc/Users guide Apache.html +588 -758
  27. data/doc/Users guide Apache.idmap.txt +253 -136
  28. data/doc/Users guide Apache.txt +154 -109
  29. data/doc/Users guide Nginx.html +544 -660
  30. data/doc/Users guide Nginx.idmap.txt +179 -91
  31. data/doc/Users guide Nginx.txt +192 -118
  32. data/doc/Users guide Standalone.html +65 -48
  33. data/doc/Users guide Standalone.idmap.txt +10 -2
  34. data/doc/Users guide Standalone.txt +4 -0
  35. data/doc/images/glyphicons-halflings-white.png +0 -0
  36. data/doc/images/glyphicons-halflings.png +0 -0
  37. data/doc/images/phusion_banner_small.png +0 -0
  38. data/doc/images/{smart-lv2.png → smart.png} +0 -0
  39. data/doc/images/{smart-lv2.svg → smart.svg} +0 -0
  40. data/doc/templates/bootstrap.min.css +397 -0
  41. data/doc/templates/markdown.html.erb +117 -0
  42. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +2 -1
  43. data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +26 -48
  44. data/doc/users_guide_snippets/passenger_spawn_method.txt +18 -30
  45. data/doc/users_guide_snippets/support_information.txt +30 -0
  46. data/ext/apache2/Bucket.cpp +9 -26
  47. data/ext/apache2/Bucket.h +13 -10
  48. data/ext/apache2/Configuration.cpp +70 -58
  49. data/ext/apache2/Configuration.hpp +19 -47
  50. data/ext/apache2/DirectoryMapper.h +7 -7
  51. data/ext/apache2/Hooks.cpp +150 -313
  52. data/ext/boost/algorithm/string/detail/case_conv.hpp +4 -2
  53. data/ext/boost/algorithm/string/detail/find_format.hpp +20 -20
  54. data/ext/boost/algorithm/string/detail/find_format_all.hpp +23 -23
  55. data/ext/boost/algorithm/string/detail/find_format_store.hpp +2 -2
  56. data/ext/boost/algorithm/string/detail/formatter.hpp +25 -0
  57. data/ext/boost/algorithm/string/formatter.hpp +20 -3
  58. data/ext/boost/assert.hpp +85 -4
  59. data/ext/boost/bind/bind.hpp +1 -1
  60. data/ext/boost/concept/detail/backward_compatibility.hpp +1 -1
  61. data/ext/boost/concept_check.hpp +140 -64
  62. data/ext/boost/config.hpp +1 -1
  63. data/ext/boost/config/auto_link.hpp +8 -6
  64. data/ext/boost/config/compiler/borland.hpp +12 -2
  65. data/ext/boost/config/compiler/clang.hpp +89 -30
  66. data/ext/boost/config/compiler/codegear.hpp +3 -2
  67. data/ext/boost/config/compiler/common_edg.hpp +7 -5
  68. data/ext/boost/config/compiler/cray.hpp +61 -0
  69. data/ext/boost/config/compiler/digitalmars.hpp +9 -1
  70. data/ext/boost/config/compiler/gcc.hpp +33 -24
  71. data/ext/boost/config/compiler/gcc_xml.hpp +4 -0
  72. data/ext/boost/config/compiler/hp_acc.hpp +12 -1
  73. data/ext/boost/config/compiler/intel.hpp +78 -4
  74. data/ext/boost/config/compiler/metrowerks.hpp +4 -1
  75. data/ext/boost/config/compiler/mpw.hpp +4 -1
  76. data/ext/boost/config/compiler/nvcc.hpp +8 -66
  77. data/ext/boost/config/compiler/pathscale.hpp +80 -0
  78. data/ext/boost/config/compiler/pgi.hpp +5 -5
  79. data/ext/boost/config/compiler/sunpro_cc.hpp +4 -1
  80. data/ext/boost/config/compiler/vacpp.hpp +37 -13
  81. data/ext/boost/config/compiler/visualc.hpp +24 -11
  82. data/ext/boost/config/platform/bsd.hpp +1 -1
  83. data/ext/boost/config/platform/cray.hpp +18 -0
  84. data/ext/boost/config/platform/cygwin.hpp +10 -0
  85. data/ext/boost/config/platform/linux.hpp +5 -0
  86. data/ext/boost/config/platform/macos.hpp +5 -4
  87. data/ext/boost/config/platform/symbian.hpp +5 -2
  88. data/ext/boost/config/platform/vms.hpp +25 -0
  89. data/ext/boost/config/platform/win32.hpp +7 -1
  90. data/ext/boost/config/select_compiler_config.hpp +8 -25
  91. data/ext/boost/config/select_platform_config.hpp +8 -1
  92. data/ext/boost/config/select_stdlib_config.hpp +9 -1
  93. data/ext/boost/config/stdlib/dinkumware.hpp +6 -9
  94. data/ext/boost/config/stdlib/libcomo.hpp +1 -4
  95. data/ext/boost/config/stdlib/libcpp.hpp +36 -0
  96. data/ext/boost/config/stdlib/libstdcpp3.hpp +37 -11
  97. data/ext/boost/config/stdlib/modena.hpp +1 -4
  98. data/ext/boost/config/stdlib/msl.hpp +1 -4
  99. data/ext/boost/config/stdlib/roguewave.hpp +9 -6
  100. data/ext/boost/config/stdlib/sgi.hpp +12 -4
  101. data/ext/boost/config/stdlib/stlport.hpp +11 -4
  102. data/ext/boost/config/stdlib/vacpp.hpp +11 -4
  103. data/ext/boost/config/suffix.hpp +71 -6
  104. data/ext/boost/config/warning_disable.hpp +1 -1
  105. data/ext/boost/container/container_fwd.hpp +177 -0
  106. data/ext/boost/cstdint.hpp +17 -12
  107. data/ext/boost/current_function.hpp +2 -1
  108. data/ext/boost/date_time/c_time.hpp +17 -1
  109. data/ext/boost/date_time/compiler_config.hpp +13 -15
  110. data/ext/boost/date_time/date_formatting.hpp +7 -1
  111. data/ext/boost/date_time/filetime_functions.hpp +4 -4
  112. data/ext/boost/date_time/gregorian_calendar.ipp +2 -2
  113. data/ext/boost/date_time/strings_from_facet.hpp +3 -3
  114. data/ext/boost/date_time/time_facet.hpp +101 -101
  115. data/ext/boost/detail/endian.hpp +4 -2
  116. data/ext/boost/detail/fenv.hpp +74 -0
  117. data/ext/boost/detail/sp_typeinfo.hpp +6 -0
  118. data/ext/boost/exception/detail/clone_current_exception.hpp +47 -0
  119. data/ext/boost/exception/detail/exception_ptr.hpp +194 -122
  120. data/ext/boost/exception/detail/type_info.hpp +3 -3
  121. data/ext/boost/exception/diagnostic_information.hpp +37 -21
  122. data/ext/boost/exception/exception.hpp +21 -1
  123. data/ext/boost/exception/info.hpp +0 -1
  124. data/ext/boost/function.hpp +2 -2
  125. data/ext/boost/function/function_base.hpp +15 -9
  126. data/ext/boost/function/function_template.hpp +26 -48
  127. data/ext/boost/integer_fwd.hpp +0 -16
  128. data/ext/boost/integer_traits.hpp +2 -2
  129. data/ext/boost/iterator.hpp +1 -1
  130. data/ext/boost/iterator/iterator_adaptor.hpp +1 -7
  131. data/ext/boost/iterator/iterator_facade.hpp +13 -13
  132. data/ext/boost/iterator/transform_iterator.hpp +5 -20
  133. data/ext/boost/lexical_cast.hpp +1655 -673
  134. data/ext/boost/math/policies/policy.hpp +982 -0
  135. data/ext/boost/math/special_functions/detail/fp_traits.hpp +570 -0
  136. data/ext/boost/math/special_functions/detail/round_fwd.hpp +80 -0
  137. data/ext/boost/math/special_functions/fpclassify.hpp +533 -0
  138. data/ext/boost/math/special_functions/math_fwd.hpp +1070 -0
  139. data/ext/boost/math/special_functions/sign.hpp +145 -0
  140. data/ext/boost/math/tools/config.hpp +321 -0
  141. data/ext/boost/math/tools/promotion.hpp +150 -0
  142. data/ext/boost/math/tools/real_cast.hpp +29 -0
  143. data/ext/boost/math/tools/user.hpp +97 -0
  144. data/ext/boost/move/move.hpp +1222 -0
  145. data/ext/boost/mpl/O1_size.hpp +40 -0
  146. data/ext/boost/mpl/O1_size_fwd.hpp +24 -0
  147. data/ext/boost/mpl/advance.hpp +76 -0
  148. data/ext/boost/mpl/advance_fwd.hpp +28 -0
  149. data/ext/boost/mpl/at.hpp +52 -0
  150. data/ext/boost/mpl/at_fwd.hpp +24 -0
  151. data/ext/boost/mpl/aux_/O1_size_impl.hpp +87 -0
  152. data/ext/boost/mpl/aux_/advance_backward.hpp +128 -0
  153. data/ext/boost/mpl/aux_/advance_forward.hpp +127 -0
  154. data/ext/boost/mpl/aux_/arithmetic_op.hpp +92 -0
  155. data/ext/boost/mpl/aux_/at_impl.hpp +45 -0
  156. data/ext/boost/mpl/aux_/begin_end_impl.hpp +101 -0
  157. data/ext/boost/mpl/aux_/clear_impl.hpp +35 -0
  158. data/ext/boost/mpl/aux_/comparison_op.hpp +83 -0
  159. data/ext/boost/mpl/aux_/config/forwarding.hpp +27 -0
  160. data/ext/boost/mpl/aux_/config/typeof.hpp +38 -0
  161. data/ext/boost/mpl/aux_/contains_impl.hpp +61 -0
  162. data/ext/boost/mpl/aux_/find_if_pred.hpp +31 -0
  163. data/ext/boost/mpl/aux_/fold_impl.hpp +43 -0
  164. data/ext/boost/mpl/aux_/has_begin.hpp +23 -0
  165. data/ext/boost/mpl/aux_/has_size.hpp +23 -0
  166. data/ext/boost/mpl/aux_/has_tag.hpp +23 -0
  167. data/ext/boost/mpl/aux_/inserter_algorithm.hpp +159 -0
  168. data/ext/boost/mpl/aux_/is_msvc_eti_arg.hpp +64 -0
  169. data/ext/boost/mpl/aux_/iter_apply.hpp +47 -0
  170. data/ext/boost/mpl/aux_/iter_fold_if_impl.hpp +210 -0
  171. data/ext/boost/mpl/aux_/iter_fold_impl.hpp +42 -0
  172. data/ext/boost/mpl/aux_/lambda_spec.hpp +49 -0
  173. data/ext/boost/mpl/aux_/largest_int.hpp +63 -0
  174. data/ext/boost/mpl/aux_/msvc_eti_base.hpp +77 -0
  175. data/ext/boost/mpl/aux_/msvc_type.hpp +62 -0
  176. data/ext/boost/mpl/aux_/numeric_cast_utils.hpp +77 -0
  177. data/ext/boost/mpl/aux_/numeric_op.hpp +315 -0
  178. data/ext/boost/mpl/aux_/preprocessed/gcc/advance_backward.hpp +97 -0
  179. data/ext/boost/mpl/aux_/preprocessed/gcc/advance_forward.hpp +97 -0
  180. data/ext/boost/mpl/aux_/preprocessed/gcc/equal_to.hpp +94 -0
  181. data/ext/boost/mpl/aux_/preprocessed/gcc/fold_impl.hpp +180 -0
  182. data/ext/boost/mpl/aux_/preprocessed/gcc/greater.hpp +94 -0
  183. data/ext/boost/mpl/aux_/preprocessed/gcc/greater_equal.hpp +94 -0
  184. data/ext/boost/mpl/aux_/preprocessed/gcc/iter_fold_if_impl.hpp +133 -0
  185. data/ext/boost/mpl/aux_/preprocessed/gcc/iter_fold_impl.hpp +180 -0
  186. data/ext/boost/mpl/aux_/preprocessed/gcc/less.hpp +94 -0
  187. data/ext/boost/mpl/aux_/preprocessed/gcc/less_equal.hpp +94 -0
  188. data/ext/boost/mpl/aux_/preprocessed/gcc/list.hpp +323 -0
  189. data/ext/boost/mpl/aux_/preprocessed/gcc/minus.hpp +146 -0
  190. data/ext/boost/mpl/aux_/preprocessed/gcc/not_equal_to.hpp +94 -0
  191. data/ext/boost/mpl/aux_/preprocessed/gcc/plus.hpp +146 -0
  192. data/ext/boost/mpl/aux_/preprocessed/gcc/reverse_fold_impl.hpp +231 -0
  193. data/ext/boost/mpl/aux_/preprocessed/gcc/times.hpp +146 -0
  194. data/ext/boost/mpl/aux_/preprocessed/gcc/vector.hpp +323 -0
  195. data/ext/boost/mpl/aux_/preprocessor/default_params.hpp +67 -0
  196. data/ext/boost/mpl/aux_/push_back_impl.hpp +70 -0
  197. data/ext/boost/mpl/aux_/push_front_impl.hpp +71 -0
  198. data/ext/boost/mpl/aux_/reverse_fold_impl.hpp +44 -0
  199. data/ext/boost/mpl/aux_/size_impl.hpp +52 -0
  200. data/ext/boost/mpl/aux_/traits_lambda_spec.hpp +63 -0
  201. data/ext/boost/mpl/back_fwd.hpp +24 -0
  202. data/ext/boost/mpl/back_inserter.hpp +34 -0
  203. data/ext/boost/mpl/begin_end.hpp +57 -0
  204. data/ext/boost/mpl/begin_end_fwd.hpp +27 -0
  205. data/ext/boost/mpl/clear.hpp +39 -0
  206. data/ext/boost/mpl/clear_fwd.hpp +24 -0
  207. data/ext/boost/mpl/comparison.hpp +24 -0
  208. data/ext/boost/mpl/contains.hpp +41 -0
  209. data/ext/boost/mpl/contains_fwd.hpp +25 -0
  210. data/ext/boost/mpl/deref.hpp +41 -0
  211. data/ext/boost/mpl/distance.hpp +78 -0
  212. data/ext/boost/mpl/distance_fwd.hpp +28 -0
  213. data/ext/boost/mpl/empty_fwd.hpp +24 -0
  214. data/ext/boost/mpl/equal_to.hpp +21 -0
  215. data/ext/boost/mpl/find.hpp +38 -0
  216. data/ext/boost/mpl/find_if.hpp +50 -0
  217. data/ext/boost/mpl/fold.hpp +48 -0
  218. data/ext/boost/mpl/front_fwd.hpp +24 -0
  219. data/ext/boost/mpl/front_inserter.hpp +33 -0
  220. data/ext/boost/mpl/greater.hpp +21 -0
  221. data/ext/boost/mpl/greater_equal.hpp +21 -0
  222. data/ext/boost/mpl/inserter.hpp +32 -0
  223. data/ext/boost/mpl/iter_fold.hpp +49 -0
  224. data/ext/boost/mpl/iter_fold_if.hpp +117 -0
  225. data/ext/boost/mpl/iterator_range.hpp +42 -0
  226. data/ext/boost/mpl/iterator_tags.hpp +27 -0
  227. data/ext/boost/mpl/less.hpp +21 -0
  228. data/ext/boost/mpl/less_equal.hpp +21 -0
  229. data/ext/boost/mpl/limits/list.hpp +21 -0
  230. data/ext/boost/mpl/limits/vector.hpp +21 -0
  231. data/ext/boost/mpl/list.hpp +57 -0
  232. data/ext/boost/mpl/list/aux_/O1_size.hpp +33 -0
  233. data/ext/boost/mpl/list/aux_/begin_end.hpp +44 -0
  234. data/ext/boost/mpl/list/aux_/clear.hpp +34 -0
  235. data/ext/boost/mpl/list/aux_/empty.hpp +34 -0
  236. data/ext/boost/mpl/list/aux_/front.hpp +33 -0
  237. data/ext/boost/mpl/list/aux_/include_preprocessed.hpp +35 -0
  238. data/ext/boost/mpl/list/aux_/item.hpp +55 -0
  239. data/ext/boost/mpl/list/aux_/iterator.hpp +76 -0
  240. data/ext/boost/mpl/list/aux_/pop_front.hpp +34 -0
  241. data/ext/boost/mpl/list/aux_/preprocessed/plain/list10.hpp +149 -0
  242. data/ext/boost/mpl/list/aux_/preprocessed/plain/list20.hpp +169 -0
  243. data/ext/boost/mpl/list/aux_/push_back.hpp +36 -0
  244. data/ext/boost/mpl/list/aux_/push_front.hpp +39 -0
  245. data/ext/boost/mpl/list/aux_/size.hpp +33 -0
  246. data/ext/boost/mpl/list/aux_/tag.hpp +24 -0
  247. data/ext/boost/mpl/list/list0.hpp +42 -0
  248. data/ext/boost/mpl/list/list10.hpp +43 -0
  249. data/ext/boost/mpl/list/list20.hpp +43 -0
  250. data/ext/boost/mpl/long.hpp +22 -0
  251. data/ext/boost/mpl/long_fwd.hpp +27 -0
  252. data/ext/boost/mpl/minus.hpp +21 -0
  253. data/ext/boost/mpl/multiplies.hpp +53 -0
  254. data/ext/boost/mpl/negate.hpp +81 -0
  255. data/ext/boost/mpl/not_equal_to.hpp +21 -0
  256. data/ext/boost/mpl/numeric_cast.hpp +41 -0
  257. data/ext/boost/mpl/pair.hpp +70 -0
  258. data/ext/boost/mpl/plus.hpp +21 -0
  259. data/ext/boost/mpl/pop_back_fwd.hpp +24 -0
  260. data/ext/boost/mpl/pop_front_fwd.hpp +24 -0
  261. data/ext/boost/mpl/prior.hpp +19 -0
  262. data/ext/boost/mpl/push_back.hpp +53 -0
  263. data/ext/boost/mpl/push_back_fwd.hpp +24 -0
  264. data/ext/boost/mpl/push_front.hpp +52 -0
  265. data/ext/boost/mpl/push_front_fwd.hpp +24 -0
  266. data/ext/boost/mpl/remove_if.hpp +83 -0
  267. data/ext/boost/mpl/reverse_fold.hpp +50 -0
  268. data/ext/boost/mpl/same_as.hpp +55 -0
  269. data/ext/boost/mpl/sequence_tag.hpp +124 -0
  270. data/ext/boost/mpl/sequence_tag_fwd.hpp +26 -0
  271. data/ext/boost/mpl/size.hpp +42 -0
  272. data/ext/boost/mpl/size_fwd.hpp +24 -0
  273. data/ext/boost/mpl/tag.hpp +52 -0
  274. data/ext/boost/mpl/times.hpp +21 -0
  275. data/ext/boost/mpl/vector.hpp +57 -0
  276. data/ext/boost/mpl/vector/aux_/O1_size.hpp +56 -0
  277. data/ext/boost/mpl/vector/aux_/at.hpp +116 -0
  278. data/ext/boost/mpl/vector/aux_/back.hpp +59 -0
  279. data/ext/boost/mpl/vector/aux_/begin_end.hpp +49 -0
  280. data/ext/boost/mpl/vector/aux_/clear.hpp +55 -0
  281. data/ext/boost/mpl/vector/aux_/empty.hpp +68 -0
  282. data/ext/boost/mpl/vector/aux_/front.hpp +56 -0
  283. data/ext/boost/mpl/vector/aux_/include_preprocessed.hpp +55 -0
  284. data/ext/boost/mpl/vector/aux_/item.hpp +103 -0
  285. data/ext/boost/mpl/vector/aux_/iterator.hpp +130 -0
  286. data/ext/boost/mpl/vector/aux_/pop_back.hpp +40 -0
  287. data/ext/boost/mpl/vector/aux_/pop_front.hpp +40 -0
  288. data/ext/boost/mpl/vector/aux_/preprocessed/plain/vector10.hpp +829 -0
  289. data/ext/boost/mpl/vector/aux_/preprocessed/plain/vector20.hpp +1144 -0
  290. data/ext/boost/mpl/vector/aux_/preprocessed/typeof_based/vector10.hpp +139 -0
  291. data/ext/boost/mpl/vector/aux_/preprocessed/typeof_based/vector20.hpp +159 -0
  292. data/ext/boost/mpl/vector/aux_/push_back.hpp +40 -0
  293. data/ext/boost/mpl/vector/aux_/push_front.hpp +40 -0
  294. data/ext/boost/mpl/vector/aux_/size.hpp +49 -0
  295. data/ext/boost/mpl/vector/aux_/tag.hpp +32 -0
  296. data/ext/boost/mpl/vector/aux_/vector0.hpp +52 -0
  297. data/ext/boost/mpl/vector/vector0.hpp +34 -0
  298. data/ext/boost/mpl/vector/vector10.hpp +45 -0
  299. data/ext/boost/mpl/vector/vector20.hpp +45 -0
  300. data/ext/boost/none.hpp +1 -1
  301. data/ext/boost/numeric/conversion/bounds.hpp +24 -0
  302. data/ext/boost/numeric/conversion/cast.hpp +61 -0
  303. data/ext/boost/numeric/conversion/conversion_traits.hpp +39 -0
  304. data/ext/boost/numeric/conversion/converter.hpp +68 -0
  305. data/ext/boost/numeric/conversion/converter_policies.hpp +186 -0
  306. data/ext/boost/numeric/conversion/detail/bounds.hpp +58 -0
  307. data/ext/boost/numeric/conversion/detail/conversion_traits.hpp +97 -0
  308. data/ext/boost/numeric/conversion/detail/converter.hpp +602 -0
  309. data/ext/boost/numeric/conversion/detail/int_float_mixture.hpp +72 -0
  310. data/ext/boost/numeric/conversion/detail/is_subranged.hpp +234 -0
  311. data/ext/boost/numeric/conversion/detail/meta.hpp +120 -0
  312. data/ext/boost/numeric/conversion/detail/numeric_cast_traits.hpp +138 -0
  313. data/ext/boost/numeric/conversion/detail/preprocessed/numeric_cast_traits_common.hpp +1741 -0
  314. data/ext/boost/numeric/conversion/detail/preprocessed/numeric_cast_traits_long_long.hpp +347 -0
  315. data/ext/boost/numeric/conversion/detail/sign_mixture.hpp +72 -0
  316. data/ext/boost/numeric/conversion/detail/udt_builtin_mixture.hpp +69 -0
  317. data/ext/boost/numeric/conversion/int_float_mixture_enum.hpp +29 -0
  318. data/ext/boost/numeric/conversion/numeric_cast_traits.hpp +31 -0
  319. data/ext/boost/numeric/conversion/sign_mixture_enum.hpp +29 -0
  320. data/ext/boost/numeric/conversion/udt_builtin_mixture_enum.hpp +26 -0
  321. data/ext/boost/operators.hpp +3 -1
  322. data/ext/boost/optional/optional.hpp +146 -79
  323. data/ext/boost/optional/optional_fwd.hpp +8 -1
  324. data/ext/boost/preprocessor/cat.hpp +2 -2
  325. data/ext/boost/preprocessor/config/config.hpp +39 -4
  326. data/ext/boost/preprocessor/facilities/intercept.hpp +277 -0
  327. data/ext/boost/preprocessor/facilities/overload.hpp +25 -0
  328. data/ext/boost/preprocessor/iteration/detail/iter/forward1.hpp +3 -3
  329. data/ext/boost/preprocessor/iteration/iterate.hpp +3 -3
  330. data/ext/boost/preprocessor/punctuation/paren.hpp +23 -0
  331. data/ext/boost/preprocessor/repetition/enum_shifted_params.hpp +44 -0
  332. data/ext/boost/preprocessor/seq/cat.hpp +5 -4
  333. data/ext/boost/preprocessor/seq/size.hpp +0 -1
  334. data/ext/boost/preprocessor/tuple/eat.hpp +83 -34
  335. data/ext/boost/preprocessor/tuple/elem.hpp +161 -355
  336. data/ext/boost/preprocessor/tuple/rem.hpp +110 -48
  337. data/ext/boost/preprocessor/tuple/to_list.hpp +90 -36
  338. data/ext/boost/preprocessor/variadic/elem.hpp +94 -0
  339. data/ext/boost/preprocessor/variadic/size.hpp +30 -0
  340. data/ext/boost/range/begin.hpp +17 -6
  341. data/ext/boost/range/concepts.hpp +37 -2
  342. data/ext/boost/range/detail/safe_bool.hpp +72 -0
  343. data/ext/boost/range/end.hpp +14 -9
  344. data/ext/boost/range/iterator_range_core.hpp +120 -12
  345. data/ext/boost/range/size.hpp +21 -5
  346. data/ext/boost/smart_ptr/detail/shared_count.hpp +88 -0
  347. data/ext/boost/smart_ptr/detail/sp_counted_base.hpp +3 -0
  348. data/ext/boost/smart_ptr/detail/sp_counted_base_aix.hpp +142 -0
  349. data/ext/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp +9 -0
  350. data/ext/boost/smart_ptr/detail/sp_counted_impl.hpp +10 -2
  351. data/ext/boost/smart_ptr/detail/sp_has_sync.hpp +5 -1
  352. data/ext/boost/smart_ptr/detail/spinlock.hpp +4 -1
  353. data/ext/boost/smart_ptr/detail/spinlock_gcc_arm.hpp +20 -3
  354. data/ext/boost/smart_ptr/detail/spinlock_pool.hpp +4 -0
  355. data/ext/boost/smart_ptr/make_shared.hpp +591 -22
  356. data/ext/boost/smart_ptr/shared_array.hpp +29 -1
  357. data/ext/boost/smart_ptr/shared_ptr.hpp +29 -13
  358. data/ext/boost/smart_ptr/weak_ptr.hpp +24 -12
  359. data/ext/boost/src/pthread/once.cpp +9 -7
  360. data/ext/boost/src/pthread/thread.cpp +32 -28
  361. data/ext/boost/src/pthread/timeconv.inl +4 -5
  362. data/ext/boost/src/tss_null.cpp +5 -1
  363. data/ext/boost/static_assert.hpp +8 -2
  364. data/ext/boost/thread/detail/config.hpp +19 -4
  365. data/ext/boost/thread/detail/move.hpp +11 -5
  366. data/ext/boost/thread/detail/thread.hpp +59 -43
  367. data/ext/boost/thread/exceptions.hpp +9 -9
  368. data/ext/boost/thread/future.hpp +150 -82
  369. data/ext/boost/thread/locks.hpp +101 -60
  370. data/ext/boost/thread/pthread/condition_variable.hpp +79 -32
  371. data/ext/boost/thread/pthread/condition_variable_fwd.hpp +12 -3
  372. data/ext/boost/thread/pthread/mutex.hpp +17 -14
  373. data/ext/boost/thread/pthread/once.hpp +3 -4
  374. data/ext/boost/thread/pthread/pthread_mutex_scoped_lock.hpp +12 -2
  375. data/ext/boost/thread/pthread/recursive_mutex.hpp +19 -19
  376. data/ext/boost/thread/pthread/shared_mutex.hpp +13 -13
  377. data/ext/boost/thread/pthread/thread_data.hpp +40 -12
  378. data/ext/boost/thread/thread_time.hpp +5 -0
  379. data/ext/boost/throw_exception.hpp +1 -1
  380. data/ext/boost/token_functions.hpp +34 -10
  381. data/ext/boost/type_traits/add_rvalue_reference.hpp +66 -0
  382. data/ext/boost/type_traits/alignment_of.hpp +1 -1
  383. data/ext/boost/type_traits/detail/bool_trait_def.hpp +26 -3
  384. data/ext/boost/type_traits/detail/bool_trait_undef.hpp +3 -2
  385. data/ext/boost/type_traits/detail/cv_traits_impl.hpp +1 -1
  386. data/ext/boost/type_traits/detail/size_t_trait_def.hpp +6 -4
  387. data/ext/boost/type_traits/detail/type_trait_def.hpp +8 -2
  388. data/ext/boost/type_traits/function_traits.hpp +1 -1
  389. data/ext/boost/type_traits/has_nothrow_constructor.hpp +53 -0
  390. data/ext/boost/type_traits/has_nothrow_copy.hpp +19 -5
  391. data/ext/boost/type_traits/has_trivial_constructor.hpp +51 -0
  392. data/ext/boost/type_traits/has_trivial_copy.hpp +20 -5
  393. data/ext/boost/type_traits/has_trivial_destructor.hpp +12 -5
  394. data/ext/boost/type_traits/intrinsics.hpp +119 -71
  395. data/ext/boost/type_traits/is_const.hpp +5 -5
  396. data/ext/boost/type_traits/is_convertible.hpp +14 -13
  397. data/ext/boost/type_traits/is_enum.hpp +1 -1
  398. data/ext/boost/type_traits/is_floating_point.hpp +27 -0
  399. data/ext/boost/type_traits/is_function.hpp +3 -3
  400. data/ext/boost/type_traits/is_fundamental.hpp +1 -1
  401. data/ext/boost/type_traits/is_member_function_pointer.hpp +2 -2
  402. data/ext/boost/type_traits/is_member_pointer.hpp +2 -2
  403. data/ext/boost/type_traits/is_pod.hpp +11 -3
  404. data/ext/boost/type_traits/is_pointer.hpp +2 -2
  405. data/ext/boost/type_traits/is_signed.hpp +8 -3
  406. data/ext/boost/type_traits/is_union.hpp +8 -0
  407. data/ext/boost/type_traits/is_unsigned.hpp +9 -4
  408. data/ext/boost/type_traits/is_volatile.hpp +5 -5
  409. data/ext/boost/type_traits/remove_cv.hpp +4 -3
  410. data/ext/boost/type_traits/remove_pointer.hpp +51 -2
  411. data/ext/boost/type_traits/remove_reference.hpp +2 -2
  412. data/ext/boost/type_traits/type_with_alignment.hpp +8 -2
  413. data/ext/boost/utility/declval.hpp +44 -0
  414. data/ext/boost/utility/detail/in_place_factory_prefix.hpp +36 -0
  415. data/ext/boost/utility/detail/in_place_factory_suffix.hpp +23 -0
  416. data/ext/boost/utility/detail/result_of_iterate.hpp +142 -0
  417. data/ext/boost/utility/in_place_factory.hpp +88 -0
  418. data/ext/boost/utility/result_of.hpp +103 -0
  419. data/ext/boost/utility/swap.hpp +55 -0
  420. data/ext/common/AnsiColorConstants.h +36 -0
  421. data/ext/common/ApplicationPool2/Common.h +87 -0
  422. data/ext/common/ApplicationPool2/ComponentInfo.h +53 -0
  423. data/ext/common/ApplicationPool2/Group.h +648 -0
  424. data/ext/common/ApplicationPool2/Implementation.cpp +580 -0
  425. data/ext/common/ApplicationPool2/Options.h +576 -0
  426. data/ext/common/ApplicationPool2/PipeWatcher.h +61 -0
  427. data/ext/common/ApplicationPool2/Pool.h +1181 -0
  428. data/ext/common/ApplicationPool2/Process.h +425 -0
  429. data/ext/common/ApplicationPool2/README.md +96 -0
  430. data/ext/common/ApplicationPool2/Session.h +158 -0
  431. data/ext/common/ApplicationPool2/Socket.h +246 -0
  432. data/ext/common/ApplicationPool2/Spawner.h +2212 -0
  433. data/ext/common/ApplicationPool2/SuperGroup.h +749 -0
  434. data/ext/common/BackgroundEventLoop.cpp +129 -0
  435. data/ext/common/BackgroundEventLoop.h +61 -0
  436. data/ext/common/Constants.h +3 -1
  437. data/ext/common/EventedBufferedInput.h +331 -0
  438. data/ext/common/EventedMessageServer.h +17 -34
  439. data/ext/common/EventedServer.h +2 -2
  440. data/ext/common/Exceptions.h +71 -19
  441. data/ext/common/FileDescriptor.h +8 -6
  442. data/ext/common/HttpConstants.h +167 -0
  443. data/ext/common/IniFile.h +24 -0
  444. data/ext/common/Logging.h +62 -849
  445. data/ext/common/MessageReadersWriters.h +19 -0
  446. data/ext/common/MessageServer.h +11 -14
  447. data/ext/common/MultiLibeio.cpp +198 -0
  448. data/ext/common/MultiLibeio.h +67 -0
  449. data/ext/common/ResourceLocator.h +24 -41
  450. data/ext/common/SafeLibev.h +186 -14
  451. data/ext/common/StaticString.h +23 -3
  452. data/ext/common/UnionStation.h +972 -0
  453. data/ext/common/Utils.cpp +168 -24
  454. data/ext/common/Utils.h +25 -3
  455. data/ext/common/Utils/CachedFileStat.hpp +4 -3
  456. data/ext/common/Utils/FileChangeChecker.h +2 -2
  457. data/ext/common/Utils/HashMap.h +50 -0
  458. data/ext/common/Utils/IOUtils.cpp +229 -68
  459. data/ext/common/Utils/IOUtils.h +134 -3
  460. data/ext/common/Utils/Lock.h +28 -0
  461. data/ext/common/Utils/MemoryBarrier.h +52 -0
  462. data/ext/common/Utils/PriorityQueue.h +54 -0
  463. data/ext/common/Utils/ProcessMetricsCollector.h +9 -11
  464. data/ext/common/Utils/ScopeGuard.h +50 -1
  465. data/ext/common/Utils/SmallVector.h +653 -0
  466. data/ext/common/Utils/StrIntUtils.cpp +26 -2
  467. data/ext/common/Utils/StrIntUtils.h +18 -2
  468. data/ext/common/Utils/StringMap.h +125 -8
  469. data/ext/common/Utils/Template.h +212 -0
  470. data/ext/common/Utils/fib.c +699 -0
  471. data/ext/common/Utils/fib.h +101 -0
  472. data/ext/common/Utils/fibpriv.h +67 -0
  473. data/ext/common/Utils/json-forwards.h +249 -0
  474. data/ext/common/Utils/json.h +1855 -0
  475. data/ext/common/Utils/jsoncpp.cpp +4230 -0
  476. data/ext/common/agents/Base.cpp +1126 -0
  477. data/ext/common/{AgentBase.h → agents/Base.h} +5 -1
  478. data/ext/common/agents/EnvPrinter.c +16 -0
  479. data/ext/common/agents/HelperAgent/AgentOptions.h +81 -0
  480. data/ext/common/{HelperAgent → agents/HelperAgent}/BacktracesServer.h +3 -2
  481. data/ext/common/agents/HelperAgent/FileBackedPipe.h +732 -0
  482. data/ext/common/agents/HelperAgent/Main.cpp +497 -0
  483. data/ext/common/agents/HelperAgent/RequestHandler.cpp +283 -0
  484. data/ext/common/agents/HelperAgent/RequestHandler.h +2139 -0
  485. data/ext/common/agents/HelperAgent/ScgiRequestParser.h +451 -0
  486. data/ext/common/{LoggingAgent → agents/LoggingAgent}/DataStoreId.h +1 -1
  487. data/ext/common/{LoggingAgent → agents/LoggingAgent}/FilterSupport.cpp +1 -1
  488. data/ext/common/{LoggingAgent → agents/LoggingAgent}/FilterSupport.h +0 -0
  489. data/ext/common/{LoggingAgent → agents/LoggingAgent}/LoggingServer.h +18 -16
  490. data/ext/common/{LoggingAgent → agents/LoggingAgent}/Main.cpp +15 -13
  491. data/ext/common/{LoggingAgent → agents/LoggingAgent}/RemoteSender.h +6 -6
  492. data/ext/common/agents/SpawnPreparer.cpp +127 -0
  493. data/ext/common/{Watchdog.cpp → agents/Watchdog/Main.cpp} +63 -25
  494. data/ext/libeio/Changes +72 -0
  495. data/ext/{google/COPYING → libeio/LICENSE} +17 -9
  496. data/ext/libeio/Makefile.am +15 -0
  497. data/ext/libeio/Makefile.in +694 -0
  498. data/ext/libeio/aclocal.m4 +9418 -0
  499. data/ext/libeio/autogen.sh +3 -0
  500. data/ext/libeio/config.guess +1501 -0
  501. data/ext/libeio/config.h.in +136 -0
  502. data/ext/libeio/config.sub +1705 -0
  503. data/ext/libeio/configure +14822 -0
  504. data/ext/libeio/configure.ac +22 -0
  505. data/ext/libeio/demo.c +194 -0
  506. data/ext/libeio/ecb.h +457 -0
  507. data/ext/libeio/eio.c +2816 -0
  508. data/ext/libeio/eio.h +411 -0
  509. data/ext/libeio/install-sh +520 -0
  510. data/ext/libeio/libeio.m4 +211 -0
  511. data/ext/libeio/ltmain.sh +9636 -0
  512. data/ext/libeio/missing +376 -0
  513. data/ext/libeio/xthread.h +166 -0
  514. data/ext/libev/Changes +125 -7
  515. data/ext/libev/Makefile.am +5 -3
  516. data/ext/libev/Makefile.in +209 -120
  517. data/ext/libev/aclocal.m4 +6027 -4619
  518. data/ext/libev/autogen.sh +1 -4
  519. data/ext/libev/config.h.in +11 -7
  520. data/ext/libev/configure +7312 -14993
  521. data/ext/libev/configure.ac +12 -5
  522. data/ext/libev/depcomp +630 -0
  523. data/ext/libev/ev++.h +48 -32
  524. data/ext/libev/ev.c +1173 -391
  525. data/ext/libev/ev.h +315 -181
  526. data/ext/libev/ev_epoll.c +66 -15
  527. data/ext/libev/ev_kqueue.c +20 -18
  528. data/ext/libev/ev_poll.c +27 -23
  529. data/ext/libev/ev_port.c +39 -19
  530. data/ext/libev/ev_select.c +23 -17
  531. data/ext/libev/ev_vars.h +25 -8
  532. data/ext/libev/ev_win32.c +6 -6
  533. data/ext/libev/ev_wrap.h +22 -2
  534. data/ext/libev/event.c +18 -17
  535. data/ext/libev/event.h +16 -4
  536. data/ext/libev/libev.m4 +10 -6
  537. data/ext/libev/ltmain.sh +7353 -5811
  538. data/ext/nginx/Configuration.c +74 -42
  539. data/ext/nginx/Configuration.h +3 -5
  540. data/ext/nginx/ContentHandler.c +26 -83
  541. data/ext/nginx/ContentHandler.h +1 -1
  542. data/ext/nginx/config +13 -9
  543. data/ext/nginx/ngx_http_passenger_module.c +3 -7
  544. data/ext/oxt/detail/backtrace_enabled.hpp +5 -102
  545. data/ext/oxt/detail/context.hpp +90 -0
  546. data/ext/oxt/detail/spin_lock_darwin.hpp +4 -0
  547. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +4 -0
  548. data/ext/oxt/detail/spin_lock_pthreads.hpp +14 -0
  549. data/ext/oxt/detail/tracable_exception_enabled.hpp +2 -2
  550. data/ext/oxt/dynamic_thread_group.hpp +27 -1
  551. data/ext/oxt/implementation.cpp +415 -0
  552. data/ext/oxt/{thread.cpp → initialize.hpp} +13 -6
  553. data/ext/oxt/macros.hpp +32 -1
  554. data/ext/oxt/spin_lock.hpp +6 -11
  555. data/ext/oxt/system_calls.cpp +204 -16
  556. data/ext/oxt/system_calls.hpp +85 -45
  557. data/ext/oxt/thread.hpp +13 -117
  558. data/ext/ruby/passenger_native_support.c +82 -237
  559. data/helper-scripts/backtrace-sanitizer.rb +114 -0
  560. data/helper-scripts/classic-rails-loader.rb +135 -0
  561. data/helper-scripts/classic-rails-preloader.rb +161 -0
  562. data/helper-scripts/node-loader.js +314 -0
  563. data/helper-scripts/rack-loader.rb +104 -0
  564. data/helper-scripts/rack-preloader.rb +132 -0
  565. data/helper-scripts/wsgi-loader.py +231 -0
  566. data/helper-scripts/wsgi-preloader.py +1 -0
  567. data/lib/phusion_passenger.rb +159 -61
  568. data/lib/phusion_passenger/abstract_installer.rb +182 -87
  569. data/lib/phusion_passenger/admin_tools/server_instance.rb +25 -19
  570. data/lib/phusion_passenger/analytics_logger.rb +5 -4
  571. data/lib/phusion_passenger/classic_rails/{request_handler.rb → thread_handler_extension.rb} +4 -40
  572. data/lib/phusion_passenger/classic_rails_extensions/init.rb +5 -3
  573. data/lib/phusion_passenger/common_library.rb +441 -0
  574. data/lib/phusion_passenger/console_text_template.rb +4 -16
  575. data/lib/phusion_passenger/constants.rb +1 -8
  576. data/lib/phusion_passenger/debug_logging.rb +5 -2
  577. data/lib/phusion_passenger/dependencies.rb +51 -13
  578. data/lib/phusion_passenger/loader_shared_helpers.rb +318 -0
  579. data/lib/phusion_passenger/message_channel.rb +3 -47
  580. data/lib/phusion_passenger/message_client.rb +2 -2
  581. data/lib/phusion_passenger/native_support.rb +36 -15
  582. data/lib/phusion_passenger/packaging.rb +8 -11
  583. data/lib/phusion_passenger/platform_info.rb +25 -17
  584. data/lib/phusion_passenger/platform_info/apache.rb +10 -7
  585. data/lib/phusion_passenger/platform_info/binary_compatibility.rb +10 -30
  586. data/lib/phusion_passenger/platform_info/compiler.rb +93 -34
  587. data/lib/phusion_passenger/platform_info/ruby.rb +37 -97
  588. data/lib/phusion_passenger/preloader_shared_helpers.rb +121 -0
  589. data/lib/phusion_passenger/public_api.rb +1 -4
  590. data/lib/phusion_passenger/rack/{request_handler.rb → thread_handler_extension.rb} +14 -63
  591. data/lib/phusion_passenger/rails3_extensions/init.rb +9 -8
  592. data/lib/phusion_passenger/request_handler.rb +500 -0
  593. data/lib/phusion_passenger/request_handler/thread_handler.rb +360 -0
  594. data/lib/phusion_passenger/ruby_core_enhancements.rb +142 -0
  595. data/lib/phusion_passenger/standalone/command.rb +36 -15
  596. data/lib/phusion_passenger/standalone/package_runtime_command.rb +16 -8
  597. data/lib/phusion_passenger/standalone/runtime_installer.rb +169 -72
  598. data/lib/phusion_passenger/standalone/start_command.rb +44 -39
  599. data/lib/phusion_passenger/standalone/utils.rb +5 -5
  600. data/lib/phusion_passenger/utils.rb +35 -914
  601. data/lib/phusion_passenger/utils/ansi_colors.rb +59 -0
  602. data/lib/phusion_passenger/utils/file_system_watcher.rb +1 -1
  603. data/lib/phusion_passenger/utils/robust_interruption.rb +134 -0
  604. data/lib/phusion_passenger/utils/tee_input.rb +174 -0
  605. data/lib/phusion_passenger/utils/tmpio.rb +33 -0
  606. data/lib/phusion_passenger/utils/unseekable_socket.rb +6 -0
  607. data/resources/mime.types +5 -1
  608. data/{lib/phusion_passenger/templates → resources}/standalone_default_root/index.html +0 -0
  609. data/{lib/phusion_passenger → resources}/templates/apache2/apache_must_be_compiled_with_compatible_mpm.txt.erb +0 -0
  610. data/{lib/phusion_passenger → resources}/templates/apache2/config_snippets.txt.erb +0 -0
  611. data/{lib/phusion_passenger → resources}/templates/apache2/deployment_example.txt.erb +0 -0
  612. data/{lib/phusion_passenger → resources}/templates/apache2/no_write_permission_to_passenger_root.txt.erb +0 -0
  613. data/{lib/phusion_passenger → resources}/templates/apache2/possible_solutions_for_compilation_and_installation_problems.txt.erb +0 -0
  614. data/{lib/phusion_passenger → resources}/templates/apache2/run_installer_as_root.txt.erb +0 -0
  615. data/{lib/phusion_passenger → resources}/templates/apache2/welcome.txt.erb +0 -0
  616. data/{lib/phusion_passenger → resources}/templates/error_layout.css +6 -0
  617. data/resources/templates/error_layout.html.template +89 -0
  618. data/resources/templates/general_error.html.template +1 -0
  619. data/resources/templates/general_error_with_html.html.template +1 -0
  620. data/{lib/phusion_passenger → resources}/templates/nginx/ask_for_extra_configure_flags.txt.erb +0 -0
  621. data/{lib/phusion_passenger → resources}/templates/nginx/cannot_write_to_dir.txt.erb +0 -0
  622. data/{lib/phusion_passenger → resources}/templates/nginx/config_snippets.txt.erb +0 -0
  623. data/{lib/phusion_passenger → resources}/templates/nginx/config_snippets_inserted.txt.erb +0 -0
  624. data/{lib/phusion_passenger → resources}/templates/nginx/confirm_extra_configure_flags.txt.erb +0 -0
  625. data/{lib/phusion_passenger → resources}/templates/nginx/deployment_example.txt.erb +0 -0
  626. data/resources/templates/nginx/not_available_when_natively_packaged.txt.erb +8 -0
  627. data/{lib/phusion_passenger → resources}/templates/nginx/pcre_could_not_be_downloaded.txt.erb +0 -0
  628. data/{lib/phusion_passenger → resources}/templates/nginx/pcre_could_not_be_extracted.txt.erb +0 -0
  629. data/{lib/phusion_passenger → resources}/templates/nginx/possible_solutions_for_compilation_and_installation_problems.txt.erb +0 -0
  630. data/{lib/phusion_passenger → resources}/templates/nginx/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -0
  631. data/{lib/phusion_passenger → resources}/templates/nginx/query_download_and_install.txt.erb +0 -0
  632. data/{lib/phusion_passenger → resources}/templates/nginx/run_installer_as_root.txt.erb +0 -0
  633. data/{lib/phusion_passenger → resources}/templates/nginx/welcome.txt.erb +0 -0
  634. data/{lib/phusion_passenger → resources}/templates/standalone/cannot_write_to_dir.txt.erb +0 -0
  635. data/{lib/phusion_passenger → resources}/templates/standalone/config.erb +26 -5
  636. data/{lib/phusion_passenger → resources}/templates/standalone/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -0
  637. data/{lib/phusion_passenger → resources}/templates/standalone/run_installer_as_root.txt.erb +0 -0
  638. data/{lib/phusion_passenger → resources}/templates/standalone/welcome.txt.erb +0 -0
  639. data/resources/templates/undisclosed_error.html.template +25 -0
  640. data/test/config.json.example +42 -0
  641. data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +86 -0
  642. data/test/cxx/ApplicationPool2/OptionsTest.cpp +44 -0
  643. data/test/cxx/ApplicationPool2/PoolTest.cpp +1234 -0
  644. data/test/cxx/ApplicationPool2/ProcessTest.cpp +131 -0
  645. data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +229 -0
  646. data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +744 -0
  647. data/test/cxx/BufferedIOTest.cpp +7 -7
  648. data/test/cxx/CxxTestMain.cpp +65 -2
  649. data/test/cxx/FileBackedPipeTest.cpp +626 -0
  650. data/test/cxx/FileChangeCheckerTest.cpp +20 -18
  651. data/test/cxx/FilterSupportTest.cpp +5 -5
  652. data/test/cxx/IOUtilsTest.cpp +11 -4
  653. data/test/cxx/MessageReadersWritersTest.cpp +1 -1
  654. data/test/cxx/MessageServerTest.cpp +31 -30
  655. data/test/cxx/RequestHandlerTest.cpp +777 -0
  656. data/test/cxx/ScgiRequestParserTest.cpp +36 -16
  657. data/test/cxx/ServerInstanceDirTest.cpp +1 -1
  658. data/test/cxx/StringMapTest.cpp +61 -0
  659. data/test/cxx/TemplateTest.cpp +118 -0
  660. data/test/cxx/TestSupport.cpp +25 -68
  661. data/test/cxx/TestSupport.h +81 -41
  662. data/test/cxx/{LoggingTest.cpp → UnionStationTest.cpp} +79 -74
  663. data/test/cxx/UtilsTest.cpp +59 -5
  664. data/test/integration_tests/apache2_tests.rb +2 -2
  665. data/test/integration_tests/nginx_tests.rb +1 -1
  666. data/test/integration_tests/spec_helper.rb +7 -5
  667. data/test/oxt/oxt_test_main.cpp +2 -0
  668. data/test/oxt/syscall_interruption_test.cpp +1 -0
  669. data/test/ruby/classic_rails/loader_spec.rb +48 -0
  670. data/test/ruby/classic_rails/preloader_spec.rb +54 -0
  671. data/test/ruby/rack/loader_spec.rb +62 -0
  672. data/test/ruby/rack/preloader_spec.rb +74 -0
  673. data/test/ruby/{abstract_request_handler_spec.rb → request_handler_spec.rb} +31 -68
  674. data/test/ruby/shared/loader_spec.rb +241 -0
  675. data/test/ruby/shared/rails/analytics_logging_extensions_spec.rb +141 -182
  676. data/test/ruby/shared/ruby_loader_spec.rb +55 -0
  677. data/test/ruby/spec_helper.rb +8 -53
  678. data/test/ruby/utils/file_system_watcher_spec.rb +9 -1
  679. data/test/ruby/utils_spec.rb +10 -683
  680. data/test/stub/rack/config.ru +28 -3
  681. data/test/stub/rack/start.rb +47 -0
  682. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/Rakefile +0 -0
  683. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/controllers/application_controller.rb +0 -2
  684. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/controllers/bar_controller_1.rb +0 -0
  685. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/controllers/bar_controller_2.rb +0 -0
  686. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/controllers/foo_controller.rb +0 -0
  687. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/app/helpers/application_helper.rb +0 -0
  688. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/boot.rb +0 -0
  689. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/database.yml +3 -3
  690. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/environment.rb +5 -2
  691. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/environments/development.rb +0 -0
  692. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/environments/production.rb +0 -0
  693. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/environments/staging.rb +0 -0
  694. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/initializers/inflections.rb +0 -0
  695. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/initializers/mime_types.rb +0 -0
  696. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/config/routes.rb +1 -0
  697. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/about +0 -0
  698. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/console +0 -0
  699. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/dbconsole +0 -0
  700. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/destroy +0 -0
  701. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/generate +0 -0
  702. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/performance/benchmarker +0 -0
  703. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/performance/profiler +0 -0
  704. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/performance/request +0 -0
  705. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/plugin +0 -0
  706. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/process/inspector +0 -0
  707. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/process/reaper +0 -0
  708. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/process/spawner +0 -0
  709. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/runner +0 -0
  710. data/test/stub/{rails_apps/2.3/foobar → rails2.3}/script/server +0 -0
  711. data/test/stub/{rails_apps/3.0/empty → rails3.0}/Gemfile +0 -0
  712. data/test/stub/rails3.0/Gemfile.lock +80 -0
  713. data/test/stub/{rails_apps/3.0/empty → rails3.0}/Rakefile +0 -0
  714. data/test/stub/{rails_apps/3.0/empty → rails3.0}/app/controllers/application_controller.rb +0 -0
  715. data/test/stub/{rails_apps/3.0/empty → rails3.0}/app/helpers/application_helper.rb +0 -0
  716. data/test/stub/{rails_apps/3.0/empty → rails3.0}/app/views/layouts/application.html.erb +0 -0
  717. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config.ru +0 -0
  718. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/application.rb +0 -0
  719. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/boot.rb +0 -0
  720. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/database.yml +0 -0
  721. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/environment.rb +0 -0
  722. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/environments/development.rb +0 -0
  723. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/environments/production.rb +0 -0
  724. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/environments/test.rb +0 -0
  725. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/backtrace_silencers.rb +0 -0
  726. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/inflections.rb +0 -0
  727. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/mime_types.rb +0 -0
  728. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/passenger.rb +0 -0
  729. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/secret_token.rb +0 -0
  730. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/initializers/session_store.rb +0 -0
  731. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/locales/en.yml +0 -0
  732. data/test/stub/{rails_apps/3.0/empty → rails3.0}/config/routes.rb +0 -0
  733. data/test/stub/{rails_apps/3.0/empty → rails3.0}/db/seeds.rb +0 -0
  734. data/test/stub/{rails_apps/3.0/empty → rails3.0}/doc/README_FOR_APP +0 -0
  735. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/404.html +0 -0
  736. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/422.html +0 -0
  737. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/500.html +0 -0
  738. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/favicon.ico +0 -0
  739. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/index.html +0 -0
  740. data/test/stub/{rails_apps/3.0/empty → rails3.0}/public/robots.txt +0 -0
  741. data/test/stub/{rails_apps/3.0/empty → rails3.0}/script/rails +0 -0
  742. data/test/stub/{rails_apps/3.0/empty → rails3.0}/test/performance/browsing_test.rb +0 -0
  743. data/test/stub/{rails_apps/3.0/empty → rails3.0}/test/test_helper.rb +0 -0
  744. data/test/stub/start_error.pl +24 -0
  745. data/test/stub/wsgi/passenger_wsgi.py +71 -3
  746. data/test/support/apache2_controller.rb +2 -2
  747. data/test/support/placebo-preloader.rb +88 -0
  748. data/test/support/test_helper.rb +1 -14
  749. data/test/tut/tut.h +11 -4
  750. metadata +590 -326
  751. data.tar.gz.asc +0 -12
  752. data/PACKAGING.TXT +0 -25
  753. data/build/config.rb +0 -46
  754. data/ext/apache2/HelperAgent.cpp +0 -364
  755. data/ext/boost/call_traits.hpp +0 -24
  756. data/ext/boost/detail/call_traits.hpp +0 -164
  757. data/ext/common/AbstractSpawnManager.h +0 -110
  758. data/ext/common/AgentBase.cpp +0 -432
  759. data/ext/common/ApplicationPool/Client.h +0 -788
  760. data/ext/common/ApplicationPool/Interface.h +0 -295
  761. data/ext/common/ApplicationPool/Pool.h +0 -1327
  762. data/ext/common/ApplicationPool/Server.h +0 -479
  763. data/ext/common/MessageChannel.h +0 -494
  764. data/ext/common/PoolOptions.h +0 -518
  765. data/ext/common/Process.h +0 -253
  766. data/ext/common/Session.h +0 -436
  767. data/ext/common/SpawnManager.h +0 -611
  768. data/ext/google/ChangeLog +0 -167
  769. data/ext/google/dense_hash_map +0 -310
  770. data/ext/google/dense_hash_set +0 -287
  771. data/ext/google/sparse_hash_map +0 -294
  772. data/ext/google/sparse_hash_set +0 -275
  773. data/ext/google/sparsehash/densehashtable.h +0 -1062
  774. data/ext/google/sparsehash/sparseconfig.h +0 -55
  775. data/ext/google/sparsehash/sparsehashtable.h +0 -1015
  776. data/ext/google/sparsetable +0 -1468
  777. data/ext/google/type_traits.h +0 -250
  778. data/ext/nginx/HelperAgent.cpp +0 -1355
  779. data/ext/nginx/ScgiRequestParser.h +0 -375
  780. data/ext/oxt/backtrace.cpp +0 -185
  781. data/ext/oxt/tracable_exception.cpp +0 -89
  782. data/helper-scripts/passenger-spawn-server +0 -106
  783. data/lib/phusion_passenger/abstract_request_handler.rb +0 -766
  784. data/lib/phusion_passenger/abstract_server.rb +0 -372
  785. data/lib/phusion_passenger/abstract_server_collection.rb +0 -335
  786. data/lib/phusion_passenger/app_process.rb +0 -174
  787. data/lib/phusion_passenger/classic_rails/application_spawner.rb +0 -344
  788. data/lib/phusion_passenger/classic_rails/framework_spawner.rb +0 -311
  789. data/lib/phusion_passenger/exceptions.rb +0 -103
  790. data/lib/phusion_passenger/html_template.rb +0 -107
  791. data/lib/phusion_passenger/rack/application_spawner.rb +0 -231
  792. data/lib/phusion_passenger/spawn_manager.rb +0 -359
  793. data/lib/phusion_passenger/templates/app_exited_during_initialization.html.erb +0 -38
  794. data/lib/phusion_passenger/templates/app_init_error.html.erb +0 -64
  795. data/lib/phusion_passenger/templates/database_error.html.erb +0 -66
  796. data/lib/phusion_passenger/templates/error_layout.html.erb +0 -39
  797. data/lib/phusion_passenger/templates/framework_init_error.html.erb +0 -39
  798. data/lib/phusion_passenger/templates/general_error.html.erb +0 -22
  799. data/lib/phusion_passenger/templates/load_error.html.erb +0 -46
  800. data/lib/phusion_passenger/templates/version_not_found.html.erb +0 -34
  801. data/lib/phusion_passenger/utils/rewindable_input.rb +0 -125
  802. data/lib/phusion_passenger/wsgi/application_spawner.rb +0 -108
  803. data/test/config.yml.example +0 -41
  804. data/test/cxx/ApplicationPool_PoolTest.cpp +0 -33
  805. data/test/cxx/ApplicationPool_PoolTestCases.cpp +0 -1029
  806. data/test/cxx/ApplicationPool_ServerTest.cpp +0 -308
  807. data/test/cxx/ApplicationPool_Server_PoolTest.cpp +0 -80
  808. data/test/cxx/MessageChannelTest.cpp +0 -557
  809. data/test/cxx/PoolOptionsTest.cpp +0 -116
  810. data/test/cxx/SpawnManagerTest.cpp +0 -161
  811. data/test/ruby/abstract_server_collection_spec.rb +0 -247
  812. data/test/ruby/abstract_server_spec.rb +0 -61
  813. data/test/ruby/app_process_spec.rb +0 -43
  814. data/test/ruby/classic_rails/application_spawner_spec.rb +0 -89
  815. data/test/ruby/classic_rails/framework_spawner_spec.rb +0 -92
  816. data/test/ruby/rack/application_spawner_spec.rb +0 -116
  817. data/test/ruby/shared/abstract_server_spec.rb +0 -23
  818. data/test/ruby/shared/spawners/classic_rails/framework_spawner_spec.rb +0 -38
  819. data/test/ruby/shared/spawners/classic_rails/lack_of_rails_gem_version_spec.rb +0 -19
  820. data/test/ruby/shared/spawners/classic_rails/spawner_spec.rb +0 -15
  821. data/test/ruby/shared/spawners/non_preloading_spawner_spec.rb +0 -27
  822. data/test/ruby/shared/spawners/preloading_spawner_spec.rb +0 -29
  823. data/test/ruby/shared/spawners/reload_all_spec.rb +0 -36
  824. data/test/ruby/shared/spawners/reload_single_spec.rb +0 -52
  825. data/test/ruby/shared/spawners/spawn_server_spec.rb +0 -28
  826. data/test/ruby/shared/spawners/spawner_spec.rb +0 -273
  827. data/test/ruby/shared/utils/pseudo_io_spec.rb +0 -60
  828. data/test/ruby/spawn_manager_spec.rb +0 -134
  829. data/test/ruby/wsgi/application_spawner_spec.rb +0 -50
  830. data/test/stub/message_channel.rb +0 -11
  831. data/test/stub/message_channel_2.rb +0 -12
  832. data/test/stub/message_channel_3.rb +0 -19
  833. data/test/stub/rails_apps/3.0/empty/Gemfile.lock +0 -73
  834. data/test/stub/spawn_server.rb +0 -22
  835. metadata.gz.asc +0 -12
@@ -0,0 +1,61 @@
1
+ /*
2
+ * Phusion Passenger - http://www.modrails.com/
3
+ * Copyright (c) 2012 Phusion
4
+ *
5
+ * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ */
25
+ #ifndef _PASSENGER_APPLICATION_POOL_PIPE_WATCHER_H_
26
+ #define _PASSENGER_APPLICATION_POOL_PIPE_WATCHER_H_
27
+
28
+ #include <boost/shared_ptr.hpp>
29
+ #include <boost/enable_shared_from_this.hpp>
30
+ #include <SafeLibev.h>
31
+ #include <FileDescriptor.h>
32
+ #include <ev++.h>
33
+
34
+ namespace Passenger {
35
+ namespace ApplicationPool2 {
36
+
37
+ using namespace boost;
38
+
39
+
40
+ struct PipeWatcher: public enable_shared_from_this<PipeWatcher> {
41
+ SafeLibevPtr libev;
42
+ FileDescriptor fd;
43
+ ev::io watcher;
44
+ shared_ptr<PipeWatcher> selfPointer;
45
+ int fdToForwardTo;
46
+
47
+ PipeWatcher(const SafeLibevPtr &_libev,
48
+ const FileDescriptor &_fd,
49
+ int _fdToForwardTo);
50
+ ~PipeWatcher();
51
+ void start();
52
+ void onReadable(ev::io &io, int revents);
53
+ };
54
+
55
+ typedef shared_ptr<PipeWatcher> PipeWatcherPtr;
56
+
57
+
58
+ } // namespace ApplicationPool2
59
+ } // namespace Passenger
60
+
61
+ #endif /* _PASSENGER_APPLICATION_POOL_PIPE_WATCHER_H_ */
@@ -0,0 +1,1181 @@
1
+ /*
2
+ * Phusion Passenger - http://www.modrails.com/
3
+ * Copyright (c) 2011, 2012 Phusion
4
+ *
5
+ * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ */
25
+ #ifndef _PASSENGER_APPLICATION_POOL2_POOL_H_
26
+ #define _PASSENGER_APPLICATION_POOL2_POOL_H_
27
+
28
+ #include <string>
29
+ #include <vector>
30
+ #include <utility>
31
+ #include <sstream>
32
+ #include <iomanip>
33
+ #include <boost/thread.hpp>
34
+ #include <boost/bind.hpp>
35
+ #include <boost/shared_ptr.hpp>
36
+ #include <boost/make_shared.hpp>
37
+ #include <boost/function.hpp>
38
+ #include <oxt/dynamic_thread_group.hpp>
39
+ #include <oxt/backtrace.hpp>
40
+ #include <ApplicationPool2/Common.h>
41
+ #include <ApplicationPool2/Process.h>
42
+ #include <ApplicationPool2/Group.h>
43
+ #include <ApplicationPool2/SuperGroup.h>
44
+ #include <ApplicationPool2/Session.h>
45
+ #include <ApplicationPool2/Spawner.h>
46
+ #include <ApplicationPool2/Options.h>
47
+ #include <UnionStation.h>
48
+ #include <Logging.h>
49
+ #include <SafeLibev.h>
50
+ #include <AnsiColorConstants.h>
51
+ #include <Exceptions.h>
52
+ #include <RandomGenerator.h>
53
+ #include <Utils/Lock.h>
54
+ #include <Utils/SystemTime.h>
55
+ #include <Utils/VariantMap.h>
56
+ #include <Utils/ProcessMetricsCollector.h>
57
+
58
+ namespace Passenger {
59
+ namespace ApplicationPool2 {
60
+
61
+ using namespace std;
62
+ using namespace boost;
63
+ using namespace oxt;
64
+
65
+
66
+ class Pool: public enable_shared_from_this<Pool> {
67
+ public:
68
+ struct InspectOptions {
69
+ bool colorize;
70
+ bool verbose;
71
+
72
+ InspectOptions()
73
+ : colorize(false),
74
+ verbose(false)
75
+ { }
76
+
77
+ InspectOptions(const VariantMap &options)
78
+ : colorize(options.getBool("colorize", false, false)),
79
+ verbose(options.getBool("verbose", false, false))
80
+ { }
81
+ };
82
+
83
+ // Actually private, but marked public so that unit tests can access the fields.
84
+ public:
85
+ friend class SuperGroup;
86
+ friend class Group;
87
+ typedef UnionStation::LoggerFactory LoggerFactory;
88
+ typedef UnionStation::LoggerFactoryPtr LoggerFactoryPtr;
89
+ typedef UnionStation::LoggerPtr LoggerPtr;
90
+
91
+ SpawnerFactoryPtr spawnerFactory;
92
+ LoggerFactoryPtr loggerFactory;
93
+ RandomGeneratorPtr randomGenerator;
94
+
95
+ mutable boost::mutex syncher;
96
+ SafeLibev *libev;
97
+ unsigned int max;
98
+ unsigned long long maxIdleTime;
99
+
100
+ ev::timer garbageCollectionTimer;
101
+ ev::timer analyticsCollectionTimer;
102
+
103
+ /**
104
+ * Code can register background threads in one of these dynamic thread groups
105
+ * to ensure that threads are interrupted and/or joined properly upon Pool
106
+ * destruction.
107
+ * All threads in 'interruptableThreads' will be interrupted and joined upon
108
+ * Pool destruction.
109
+ * All threads in 'nonInterruptableThreads' will be joined, but not interrupted,
110
+ * upon Pool destruction.
111
+ */
112
+ dynamic_thread_group interruptableThreads;
113
+ dynamic_thread_group nonInterruptableThreads;
114
+
115
+ SuperGroupMap superGroups;
116
+
117
+ /**
118
+ * get() requests that...
119
+ * - cannot be immediately satisfied because the pool is at full
120
+ * capacity and no existing processes can be killed,
121
+ * - and for which the super group isn't in the pool,
122
+ * ...are put on this wait list.
123
+ *
124
+ * This wait list is processed when one of the following things happen:
125
+ *
126
+ * - A process has been spawned but its associated group has
127
+ * no get waiters. This process can be killed and the resulting
128
+ * free capacity will be used to use spawn a process for this
129
+ * get request.
130
+ * - A process (that has apparently been spawned after getWaitlist
131
+ * was populated) is done processing a request. This process can
132
+ * then be killed to free capacity.
133
+ * - A process has failed to spawn, resulting in capacity to
134
+ * become free.
135
+ * - A SuperGroup failed to initialize, resulting in free capacity.
136
+ * - Someone commanded Pool to detach a process, resulting in free
137
+ * capacity.
138
+ * - Someone commanded Pool to detach a SuperGroup, resulting in
139
+ * free capacity.
140
+ * - The 'max' option has been increased, resulting in free capacity.
141
+ *
142
+ * Invariant 1:
143
+ * for all options in getWaitlist:
144
+ * options.getAppGroupName() is not in 'superGroups'.
145
+ *
146
+ * Invariant 2:
147
+ * if getWaitlist is non-empty:
148
+ * atFullCapacity()
149
+ * Equivalently:
150
+ * if !atFullCapacity():
151
+ * getWaitlist is empty.
152
+ */
153
+ vector<GetWaiter> getWaitlist;
154
+
155
+ mutable boost::mutex debugSyncher;
156
+ unsigned short spawnLoopIteration;
157
+
158
+ static void runAllActions(const vector<Callback> &actions) {
159
+ vector<Callback>::const_iterator it, end = actions.end();
160
+ for (it = actions.begin(); it != end; it++) {
161
+ (*it)();
162
+ }
163
+ }
164
+
165
+ static void runAllActionsWithCopy(vector<Callback> actions) {
166
+ runAllActions(actions);
167
+ }
168
+
169
+ static const char *maybeColorize(const InspectOptions &options, const char *color) {
170
+ if (options.colorize) {
171
+ return color;
172
+ } else {
173
+ return "";
174
+ }
175
+ }
176
+
177
+ void verifyInvariants() const {
178
+ // !a || b: logical equivalent of a IMPLIES b.
179
+ P_ASSERT(!( !getWaitlist.empty() ) || ( atFullCapacity(false) ));
180
+ P_ASSERT(!( !atFullCapacity(false) ) || ( getWaitlist.empty() ));
181
+ }
182
+
183
+ void verifyExpensiveInvariants() const {
184
+ #ifndef NDEBUG
185
+ vector<GetWaiter>::const_iterator it, end = getWaitlist.end();
186
+ for (it = getWaitlist.begin(); it != end; it++) {
187
+ const GetWaiter &waiter = *it;
188
+ P_ASSERT(superGroups.get(waiter.options.getAppGroupName()) == NULL);
189
+ }
190
+ #endif
191
+ }
192
+
193
+ ProcessPtr findOldestIdleProcess() const {
194
+ ProcessPtr oldestIdleProcess;
195
+
196
+ SuperGroupMap::const_iterator it, end = superGroups.end();
197
+ for (it = superGroups.begin(); it != end; it++) {
198
+ const SuperGroupPtr &superGroup = it->second;
199
+ const vector<GroupPtr> &groups = superGroup->groups;
200
+ vector<GroupPtr>::const_iterator g_it, g_end = groups.end();
201
+ for (g_it = groups.begin(); g_it != g_end; g_it++) {
202
+ const GroupPtr &group = *g_it;
203
+ const ProcessList &processes = group->processes;
204
+ ProcessList::const_iterator p_it, p_end = processes.end();
205
+ for (p_it = processes.begin(); p_it != p_end; p_it++) {
206
+ const ProcessPtr process = *p_it;
207
+ if (process->utilization() == 0
208
+ && (oldestIdleProcess == NULL
209
+ || process->lastUsed < oldestIdleProcess->lastUsed)
210
+ ) {
211
+ oldestIdleProcess = process;
212
+ }
213
+ }
214
+ }
215
+ }
216
+
217
+ return oldestIdleProcess;
218
+ }
219
+
220
+ ProcessPtr findBestProcessToTrash() const {
221
+ ProcessPtr oldestProcess;
222
+
223
+ SuperGroupMap::const_iterator it, end = superGroups.end();
224
+ for (it = superGroups.begin(); it != end; it++) {
225
+ const SuperGroupPtr &superGroup = it->second;
226
+ const vector<GroupPtr> &groups = superGroup->groups;
227
+ vector<GroupPtr>::const_iterator g_it, g_end = groups.end();
228
+ for (g_it = groups.begin(); g_it != g_end; g_it++) {
229
+ const GroupPtr &group = *g_it;
230
+ const ProcessList &processes = group->processes;
231
+ ProcessList::const_iterator p_it, p_end = processes.end();
232
+ for (p_it = processes.begin(); p_it != p_end; p_it++) {
233
+ const ProcessPtr process = *p_it;
234
+ if (oldestProcess == NULL
235
+ || process->lastUsed < oldestProcess->lastUsed) {
236
+ oldestProcess = process;
237
+ }
238
+ }
239
+ }
240
+ }
241
+
242
+ return oldestProcess;
243
+ }
244
+
245
+ /** Process all waiters on the getWaitlist. Call when capacity has become free.
246
+ * This function assigns sessions to them by calling get() on the corresponding
247
+ * SuperGroups, or by creating more SuperGroups, in so far the new capacity allows.
248
+ */
249
+ void assignSessionsToGetWaiters(vector<Callback> &postLockActions) {
250
+ bool done = false;
251
+ vector<GetWaiter>::iterator it, end = getWaitlist.end();
252
+ vector<GetWaiter> newWaitlist;
253
+
254
+ for (it = getWaitlist.begin(); it != end && !done; it++) {
255
+ GetWaiter &waiter = *it;
256
+
257
+ SuperGroup *superGroup = findMatchingSuperGroup(waiter.options);
258
+ if (superGroup != NULL) {
259
+ SessionPtr session = superGroup->get(waiter.options, waiter.callback);
260
+ if (session != NULL) {
261
+ postLockActions.push_back(boost::bind(
262
+ waiter.callback, session, ExceptionPtr()));
263
+ }
264
+ /* else: the callback has now been put in
265
+ * the group's get wait list.
266
+ */
267
+ } else if (!atFullCapacity(false)) {
268
+ createSuperGroupAndAsyncGetFromIt(waiter.options, waiter.callback);
269
+ } else {
270
+ /* Still cannot satisfy this get request. Keep it on the get
271
+ * wait list and try again later.
272
+ */
273
+ newWaitlist.push_back(waiter);
274
+ }
275
+ }
276
+
277
+ getWaitlist = newWaitlist;
278
+ }
279
+
280
+ void possiblySpawnMoreProcessesForExistingGroups() {
281
+ SuperGroupMap::iterator it, end = superGroups.end();
282
+ for (it = superGroups.begin(); it != end; it++) {
283
+ SuperGroupPtr &superGroup = it->second;
284
+ vector<GroupPtr> &groups = superGroup->groups;
285
+ vector<GroupPtr>::iterator g_it, g_end = groups.end();
286
+ for (g_it = groups.begin(); g_it != g_end; g_it++) {
287
+ GroupPtr &group = *g_it;
288
+ if (!group->getWaitlist.empty() && group->shouldSpawn()) {
289
+ group->spawn();
290
+ }
291
+ group->verifyInvariants();
292
+ }
293
+ }
294
+ }
295
+
296
+ void migrateGroupGetWaitlistToPool(const GroupPtr &group) {
297
+ getWaitlist.reserve(getWaitlist.size() + group->getWaitlist.size());
298
+ while (!group->getWaitlist.empty()) {
299
+ getWaitlist.push_back(group->getWaitlist.front());
300
+ group->getWaitlist.pop();
301
+ }
302
+ }
303
+
304
+ void migrateSuperGroupGetWaitlistToPool(const SuperGroupPtr &superGroup) {
305
+ getWaitlist.reserve(getWaitlist.size() + superGroup->getWaitlist.size());
306
+ while (!superGroup->getWaitlist.empty()) {
307
+ getWaitlist.push_back(superGroup->getWaitlist.front());
308
+ superGroup->getWaitlist.pop();
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Forcefully destroys and detaches the given SuperGroup. After detaching
314
+ * the SuperGroup may have a non-empty getWaitlist so be sure to do
315
+ * something with it.
316
+ *
317
+ * 'superGroup' is a non-const non-reference smart pointer so that
318
+ * it does not get destroy immediately after the 'superGroups.remove()'
319
+ * call.
320
+ */
321
+ void forceDetachSuperGroup(SuperGroupPtr superGroup, vector<Callback> &postLockActions) {
322
+ bool removed = superGroups.remove(superGroup->name);
323
+ P_ASSERT(removed);
324
+ (void) removed; // Shut up compiler warning.
325
+ superGroup->destroy(postLockActions, false);
326
+ superGroup->setPool(PoolPtr());
327
+ }
328
+
329
+ bool detachProcessUnlocked(const ProcessPtr &process, vector<Callback> &postLockActions) {
330
+ GroupPtr group = process->getGroup();
331
+ if (group != NULL && group->getPool().get() == this) {
332
+ verifyInvariants();
333
+
334
+ SuperGroupPtr superGroup = group->getSuperGroup();
335
+ P_ASSERT(superGroup->state != SuperGroup::INITIALIZING);
336
+ P_ASSERT(superGroup->getWaitlist.empty());
337
+
338
+ group->detach(process, postLockActions);
339
+ if (group->processes.empty()
340
+ && !group->spawning()
341
+ && !group->getWaitlist.empty()) {
342
+ migrateGroupGetWaitlistToPool(group);
343
+ }
344
+ group->verifyInvariants();
345
+ superGroup->verifyInvariants();
346
+
347
+ assignSessionsToGetWaiters(postLockActions);
348
+
349
+ if (superGroup->garbageCollectable()) {
350
+ // possiblySpawnMoreProcessesForExistingGroups()
351
+ // already called via detachSuperGroup().
352
+ detachSuperGroup(superGroup, false, &postLockActions);
353
+ } else {
354
+ possiblySpawnMoreProcessesForExistingGroups();
355
+ }
356
+
357
+ verifyInvariants();
358
+ verifyExpensiveInvariants();
359
+
360
+ return true;
361
+ } else {
362
+ return false;
363
+ }
364
+ }
365
+
366
+ static void syncGetCallback(Ticket *ticket, const SessionPtr &session, const ExceptionPtr &e) {
367
+ ScopedLock lock(ticket->syncher);
368
+ if (OXT_LIKELY(session != NULL)) {
369
+ ticket->session = session;
370
+ } else {
371
+ ticket->exception = e;
372
+ }
373
+ ticket->cond.notify_one();
374
+ }
375
+
376
+ SuperGroup *findMatchingSuperGroup(const Options &options) {
377
+ return superGroups.get(options.getAppGroupName()).get();
378
+ }
379
+
380
+ void garbageCollect(ev::timer &timer, int revents) {
381
+ PoolPtr self = shared_from_this(); // Keep pool object alive.
382
+ TRACE_POINT();
383
+ ScopedLock lock(syncher);
384
+ SuperGroupMap::iterator it, end = superGroups.end();
385
+ vector<SuperGroupPtr> superGroupsToDetach;
386
+ vector<Callback> actions;
387
+ unsigned long long now = SystemTime::getUsec();
388
+ unsigned long long nextGcRunTime = 0;
389
+
390
+ P_DEBUG("Garbage collection time");
391
+ verifyInvariants();
392
+
393
+ // For all supergroups and groups...
394
+ for (it = superGroups.begin(); it != end; it++) {
395
+ SuperGroupPtr superGroup = it->second;
396
+ vector<GroupPtr> &groups = superGroup->groups;
397
+ vector<GroupPtr>::iterator g_it, g_end = groups.end();
398
+
399
+ superGroup->verifyInvariants();
400
+
401
+ for (g_it = groups.begin(); g_it != g_end; g_it++) {
402
+ GroupPtr group = *g_it;
403
+ ProcessList &processes = group->processes;
404
+ ProcessList::iterator p_it, p_end = processes.end();
405
+
406
+ for (p_it = processes.begin(); p_it != p_end; p_it++) {
407
+ ProcessPtr process = *p_it;
408
+
409
+ // ...detach processes that have been idle for more than maxIdleTime.
410
+ unsigned long long processGcTime =
411
+ process->lastUsed + maxIdleTime;
412
+ if (process->sessions == 0
413
+ && now >= processGcTime
414
+ && (unsigned long) group->count > group->options.minProcesses) {
415
+ ProcessList::iterator prev = p_it;
416
+ prev--;
417
+ P_DEBUG("Garbage collect idle process: " << process->inspect() <<
418
+ ", group=" << group->name);
419
+ group->detach(process, actions);
420
+ p_it = prev;
421
+ } else if (nextGcRunTime == 0
422
+ || processGcTime < nextGcRunTime) {
423
+ nextGcRunTime = processGcTime;
424
+ }
425
+ }
426
+
427
+ group->verifyInvariants();
428
+
429
+ // ...cleanup the spawner if it's been idle for more than preloaderIdleTime.
430
+ if (group->spawner->cleanable()) {
431
+ unsigned long long spawnerGcTime =
432
+ group->spawner->lastUsed() +
433
+ group->options.getMaxPreloaderIdleTime() * 1000000;
434
+ if (now >= spawnerGcTime) {
435
+ P_DEBUG("Garbage collect idle spawner: group=" << group->name);
436
+ group->asyncCleanupSpawner();
437
+ } else if (nextGcRunTime == 0
438
+ || spawnerGcTime < nextGcRunTime) {
439
+ nextGcRunTime = spawnerGcTime;
440
+ }
441
+ }
442
+ }
443
+
444
+ // ...remove entire supergroup if it has become garbage
445
+ // collectable after detaching idle processes.
446
+ if (superGroup->garbageCollectable(now)) {
447
+ superGroupsToDetach.push_back(superGroup);
448
+ }
449
+
450
+ superGroup->verifyInvariants();
451
+ }
452
+
453
+ vector<SuperGroupPtr>::const_iterator it2;
454
+ for (it2 = superGroupsToDetach.begin(); it2 != superGroupsToDetach.end(); it2++) {
455
+ P_DEBUG("Garbage collect SuperGroup: " << (*it2)->inspect());
456
+ detachSuperGroup(*it2, false, &actions);
457
+ }
458
+
459
+ verifyInvariants();
460
+
461
+ // Schedule next garbage collection run.
462
+ ev_tstamp tstamp;
463
+ if (nextGcRunTime == 0 || nextGcRunTime <= now) {
464
+ tstamp = maxIdleTime / 1000000.0;
465
+ } else {
466
+ tstamp = (nextGcRunTime - now) / 1000000.0;
467
+ }
468
+ P_DEBUG("Garbage collection done; next garbage collect in " <<
469
+ std::fixed << std::setprecision(3) << tstamp << " sec");
470
+
471
+ lock.unlock();
472
+ runAllActions(actions);
473
+ timer.start(tstamp, 0.0);
474
+ }
475
+
476
+ struct ProcessAnalyticsLogEntry {
477
+ string groupName;
478
+ string key;
479
+ stringstream data;
480
+ };
481
+
482
+ typedef shared_ptr<ProcessAnalyticsLogEntry> ProcessAnalyticsLogEntryPtr;
483
+
484
+ void collectAnalytics(ev::timer &timer, int revents) {
485
+ try {
486
+ realCollectAnalytics(timer);
487
+ } catch (const tracable_exception &e) {
488
+ P_WARN("ERROR: " << e.what() << "\n Backtrace:\n" << e.backtrace());
489
+ }
490
+ }
491
+
492
+ void realCollectAnalytics(ev::timer &timer) {
493
+ PoolPtr self = shared_from_this(); // Keep pool object alive.
494
+ TRACE_POINT();
495
+ this_thread::disable_interruption di;
496
+ this_thread::disable_syscall_interruption dsi;
497
+ vector<pid_t> pids;
498
+ unsigned int max;
499
+
500
+ // Collect all the PIDs.
501
+ {
502
+ UPDATE_TRACE_POINT();
503
+ LockGuard l(syncher);
504
+ max = this->max;
505
+ }
506
+ pids.reserve(max);
507
+ {
508
+ UPDATE_TRACE_POINT();
509
+ LockGuard l(syncher);
510
+ SuperGroupMap::const_iterator sg_it, sg_end = superGroups.end();
511
+
512
+ for (sg_it = superGroups.begin(); sg_it != sg_end; sg_it++) {
513
+ const SuperGroupPtr &superGroup = sg_it->second;
514
+ vector<GroupPtr>::const_iterator g_it, g_end = superGroup->groups.end();
515
+
516
+ for (g_it = superGroup->groups.begin(); g_it != g_end; g_it++) {
517
+ const GroupPtr &group = *g_it;
518
+ ProcessList::const_iterator p_it, p_end = group->processes.end();
519
+
520
+ for (p_it = group->processes.begin(); p_it != p_end; p_it++) {
521
+ const ProcessPtr &process = *p_it;
522
+ pids.push_back(process->pid);
523
+ }
524
+
525
+ p_end = group->disabledProcesses.end();
526
+ for (p_it = group->disabledProcesses.begin(); p_it != p_end; p_it++) {
527
+ const ProcessPtr &process = *p_it;
528
+ pids.push_back(process->pid);
529
+ }
530
+ }
531
+ }
532
+ }
533
+
534
+ ProcessMetricMap allMetrics;
535
+ try {
536
+ // Now collect the process metrics and store them in the
537
+ // data structures, and log the state into the analytics logs.
538
+ UPDATE_TRACE_POINT();
539
+ allMetrics = ProcessMetricsCollector().collect(pids);
540
+ } catch (const ProcessMetricsCollector::ParseException &) {
541
+ P_WARN("Unable to collect process metrics: cannot parse 'ps' output.");
542
+ goto end;
543
+ }
544
+
545
+ {
546
+ UPDATE_TRACE_POINT();
547
+ vector<ProcessAnalyticsLogEntryPtr> logEntries;
548
+ ScopedLock l(syncher);
549
+ SuperGroupMap::iterator sg_it, sg_end = superGroups.end();
550
+
551
+ UPDATE_TRACE_POINT();
552
+ for (sg_it = superGroups.begin(); sg_it != sg_end; sg_it++) {
553
+ const SuperGroupPtr &superGroup = sg_it->second;
554
+ vector<GroupPtr>::iterator g_it, g_end = superGroup->groups.end();
555
+
556
+ for (g_it = superGroup->groups.begin(); g_it != g_end; g_it++) {
557
+ const GroupPtr &group = *g_it;
558
+ ProcessList::iterator p_it, p_end = group->processes.end();
559
+
560
+ for (p_it = group->processes.begin(); p_it != p_end; p_it++) {
561
+ ProcessPtr &process = *p_it;
562
+ ProcessMetricMap::const_iterator metrics_it =
563
+ allMetrics.find(process->pid);
564
+ if (metrics_it != allMetrics.end()) {
565
+ process->metrics = metrics_it->second;
566
+ }
567
+ }
568
+
569
+ p_end = group->disabledProcesses.end();
570
+ for (p_it = group->disabledProcesses.begin(); p_it != p_end; p_it++) {
571
+ ProcessPtr &process = *p_it;
572
+ ProcessMetricMap::const_iterator metrics_it =
573
+ allMetrics.find(process->pid);
574
+ if (metrics_it != allMetrics.end()) {
575
+ process->metrics = metrics_it->second;
576
+ }
577
+ }
578
+
579
+ // Log to Union Station.
580
+ if (group->options.analytics && loggerFactory != NULL) {
581
+ ProcessAnalyticsLogEntryPtr entry = make_shared<ProcessAnalyticsLogEntry>();
582
+ stringstream &xml = entry->data;
583
+
584
+ entry->groupName = group->name;
585
+ entry->key = group->options.unionStationKey;
586
+ xml << "Group: <group>";
587
+ group->inspectXml(xml, false);
588
+ xml << "</group>";
589
+ }
590
+ }
591
+ }
592
+
593
+ l.unlock();
594
+ while (!logEntries.empty()) {
595
+ ProcessAnalyticsLogEntryPtr entry = logEntries.back();
596
+ logEntries.pop_back();
597
+ LoggerPtr logger = loggerFactory->newTransaction(entry->groupName,
598
+ "processes", entry->key);
599
+ logger->message(entry->data.str());
600
+ }
601
+ }
602
+
603
+ end:
604
+ // Sleep for about 4 seconds, aligned to seconds boundary
605
+ // for saving power on laptops.
606
+ ev_now_update(libev->getLoop());
607
+ unsigned long long currentTime = SystemTime::getUsec();
608
+ unsigned long long deadline =
609
+ roundUp<unsigned long long>(currentTime, 1000000) + 4000000;
610
+ timer.start((deadline - currentTime) / 1000000.0, 0.0);
611
+ }
612
+
613
+ SuperGroupPtr createSuperGroup(const Options &options) {
614
+ SuperGroupPtr superGroup = make_shared<SuperGroup>(shared_from_this(),
615
+ options);
616
+ superGroup->initialize();
617
+ superGroups.set(options.getAppGroupName(), superGroup);
618
+ return superGroup;
619
+ }
620
+
621
+ SuperGroupPtr createSuperGroupAndAsyncGetFromIt(const Options &options,
622
+ const GetCallback &callback)
623
+ {
624
+ SuperGroupPtr superGroup = createSuperGroup(options);
625
+ SessionPtr session = superGroup->get(options, callback);
626
+ /* Callback should now have been put on the wait list,
627
+ * unless something has changed and we forgot to update
628
+ * some code here...
629
+ */
630
+ P_ASSERT(session == NULL);
631
+ return superGroup;
632
+ }
633
+
634
+ // Debugging helper function, implemented in .cpp file so that GDB can access it.
635
+ const SuperGroupPtr getSuperGroup(const char *name);
636
+
637
+ public:
638
+ Pool(SafeLibev *libev, const SpawnerFactoryPtr &spawnerFactory,
639
+ const LoggerFactoryPtr &loggerFactory = LoggerFactoryPtr(),
640
+ const RandomGeneratorPtr &randomGenerator = RandomGeneratorPtr())
641
+ {
642
+ this->libev = libev;
643
+ this->spawnerFactory = spawnerFactory;
644
+ this->loggerFactory = loggerFactory;
645
+ if (randomGenerator != NULL) {
646
+ this->randomGenerator = randomGenerator;
647
+ } else {
648
+ this->randomGenerator = make_shared<RandomGenerator>();
649
+ }
650
+
651
+ max = 6;
652
+ maxIdleTime = 60 * 1000000;
653
+
654
+ garbageCollectionTimer.set<Pool, &Pool::garbageCollect>(this);
655
+ garbageCollectionTimer.set(maxIdleTime / 1000000.0, 0.0);
656
+ libev->start(garbageCollectionTimer);
657
+ analyticsCollectionTimer.set<Pool, &Pool::collectAnalytics>(this);
658
+ analyticsCollectionTimer.set(3.0, 0.0);
659
+ libev->start(analyticsCollectionTimer);
660
+
661
+ spawnLoopIteration = 0;
662
+ }
663
+
664
+ ~Pool() {
665
+ TRACE_POINT();
666
+ destroy();
667
+ }
668
+
669
+ void destroy() {
670
+ TRACE_POINT();
671
+ libev->stop(garbageCollectionTimer);
672
+ libev->stop(analyticsCollectionTimer);
673
+
674
+ UPDATE_TRACE_POINT();
675
+ interruptableThreads.interrupt_and_join_all();
676
+ nonInterruptableThreads.join_all();
677
+
678
+ UPDATE_TRACE_POINT();
679
+ ScopedLock l(syncher);
680
+ SuperGroupMap::iterator it;
681
+ vector<SuperGroupPtr>::iterator it2;
682
+ vector<SuperGroupPtr> superGroupsToDetach;
683
+ vector<Callback> actions;
684
+ for (it = superGroups.begin(); it != superGroups.end(); it++) {
685
+ superGroupsToDetach.push_back(it->second);
686
+ }
687
+ for (it2 = superGroupsToDetach.begin(); it2 != superGroupsToDetach.end(); it2++) {
688
+ detachSuperGroup(*it2, false, &actions);
689
+ }
690
+
691
+ verifyInvariants();
692
+ verifyExpensiveInvariants();
693
+ l.unlock();
694
+ runAllActions(actions);
695
+
696
+ // detachSuperGroup() may launch additional threads, so wait for them.
697
+ interruptableThreads.interrupt_and_join_all();
698
+ nonInterruptableThreads.join_all();
699
+ }
700
+
701
+ // 'lockNow == false' may only be used during unit tests. Normally we
702
+ // should never call the callback while holding the lock.
703
+ void asyncGet(const Options &options, const GetCallback &callback, bool lockNow = true) {
704
+ DynamicScopedLock lock(syncher, lockNow);
705
+
706
+ verifyInvariants();
707
+ P_TRACE(2, "asyncGet(appRoot=" << options.appRoot << ")");
708
+
709
+ SuperGroup *existingSuperGroup = findMatchingSuperGroup(options);
710
+ if (OXT_LIKELY(existingSuperGroup != NULL)) {
711
+ /* Best case: the app super group is already in the pool. Let's use it. */
712
+ P_TRACE(2, "Found existing SuperGroup");
713
+ existingSuperGroup->verifyInvariants();
714
+ SessionPtr session = existingSuperGroup->get(options, callback);
715
+ existingSuperGroup->verifyInvariants();
716
+ verifyInvariants();
717
+ P_TRACE(2, "asyncGet() finished");
718
+ if (lockNow) {
719
+ lock.unlock();
720
+ }
721
+ if (session != NULL) {
722
+ callback(session, ExceptionPtr());
723
+ }
724
+
725
+ } else if (!atFullCapacity(false)) {
726
+ /* The app super group isn't in the pool and we have enough free
727
+ * resources to make a new one.
728
+ */
729
+ P_TRACE(2, "Spawning new SuperGroup");
730
+ SuperGroupPtr superGroup = createSuperGroupAndAsyncGetFromIt(options, callback);
731
+ superGroup->verifyInvariants();
732
+ verifyInvariants();
733
+ P_TRACE(2, "asyncGet() finished");
734
+
735
+ } else {
736
+ vector<Callback> actions;
737
+
738
+ /* Uh oh, the app super group isn't in the pool but we don't
739
+ * have the resources to make a new one. The sysadmin should
740
+ * configure the system to let something like this happen
741
+ * as least as possible, but let's try to handle it as well
742
+ * as we can.
743
+ *
744
+ * First, try to trash an idle process that's the oldest.
745
+ */
746
+ P_TRACE(2, "Pool is at full capacity; trying to free a process...");
747
+ ProcessPtr process = findOldestIdleProcess();
748
+ if (process == NULL) {
749
+ /* All processes are doing something. We have no choice
750
+ * but to trash a non-idle process.
751
+ */
752
+ if (options.allowTrashingNonIdleProcesses) {
753
+ process = findBestProcessToTrash();
754
+ }
755
+ } else {
756
+ // Check invariant.
757
+ P_ASSERT(process->getGroup()->getWaitlist.empty());
758
+ }
759
+ if (process == NULL) {
760
+ /* All (super)groups are currently initializing/restarting/spawning/etc
761
+ * so nothing can be killed. We have no choice but to satisfy this
762
+ * get() action later when resources become available.
763
+ */
764
+ P_TRACE(2, "Could not free a process; putting request to getWaitlist");
765
+ getWaitlist.push_back(GetWaiter(options, callback));
766
+ } else {
767
+ GroupPtr group;
768
+ SuperGroupPtr superGroup;
769
+
770
+ P_TRACE(2, "Freeing process " << process->inspect());
771
+ group = process->getGroup();
772
+ P_ASSERT(group != NULL);
773
+ superGroup = group->getSuperGroup();
774
+ P_ASSERT(superGroup != NULL);
775
+
776
+ group->detach(process, actions);
777
+ if (superGroup->garbageCollectable()) {
778
+ P_ASSERT(group->garbageCollectable());
779
+ forceDetachSuperGroup(superGroup, actions);
780
+ P_ASSERT(superGroup->getWaitlist.empty());
781
+ } else if (group->processes.empty()
782
+ && !group->spawning()
783
+ && !group->getWaitlist.empty())
784
+ {
785
+ /* This group no longer has any processes - either
786
+ * spawning or alive - to satisfy its get waiters.
787
+ * We migrate the group's get wait list to the pool's
788
+ * get wait list. The group's original get waiters
789
+ * will get their chances later.
790
+ */
791
+ migrateGroupGetWaitlistToPool(group);
792
+ }
793
+ group->verifyInvariants();
794
+ superGroup->verifyInvariants();
795
+
796
+ /* Now that a process has been trashed we can create
797
+ * the missing SuperGroup.
798
+ */
799
+ superGroup = make_shared<SuperGroup>(shared_from_this(), options);
800
+ superGroup->initialize();
801
+ superGroups.set(options.getAppGroupName(), superGroup);
802
+ SessionPtr session = superGroup->get(options, callback);
803
+ /* The SuperGroup is still initializing so the callback
804
+ * should now have been put on the wait list,
805
+ * unless something has changed and we forgot to update
806
+ * some code here...
807
+ */
808
+ P_ASSERT(session == NULL);
809
+ superGroup->verifyInvariants();
810
+ }
811
+
812
+ P_ASSERT(atFullCapacity(false));
813
+ verifyInvariants();
814
+ verifyExpensiveInvariants();
815
+ P_TRACE(2, "asyncGet() finished");
816
+
817
+ if (!actions.empty()) {
818
+ if (lockNow) {
819
+ lock.unlock();
820
+ runAllActions(actions);
821
+ } else {
822
+ // This state is not allowed. If we reach
823
+ // here then it probably indicates a bug in
824
+ // the test suite.
825
+ P_ABORT();
826
+ }
827
+ }
828
+ }
829
+ }
830
+
831
+ SessionPtr get(const Options &options, Ticket *ticket) {
832
+ ticket->session.reset();
833
+ ticket->exception.reset();
834
+
835
+ asyncGet(options, boost::bind(syncGetCallback, ticket, _1, _2));
836
+
837
+ ScopedLock lock(ticket->syncher);
838
+ while (ticket->session == NULL && ticket->exception == NULL) {
839
+ ticket->cond.wait(lock);
840
+ }
841
+ lock.unlock();
842
+
843
+ if (OXT_LIKELY(ticket->session != NULL)) {
844
+ SessionPtr session = ticket->session;
845
+ ticket->session.reset();
846
+ return session;
847
+ } else {
848
+ rethrowException(ticket->exception);
849
+ return SessionPtr(); // Shut up compiler warning.
850
+ }
851
+ }
852
+
853
+ GroupPtr findOrCreateGroup(const Options &options) {
854
+ Options options2 = options;
855
+ options2.noop = true;
856
+
857
+ Ticket ticket;
858
+ {
859
+ LockGuard l(syncher);
860
+ if (superGroups.get(options.getAppGroupName()) == NULL) {
861
+ // Forcefully create SuperGroup, don't care whether resource limits
862
+ // actually allow it.
863
+ createSuperGroup(options);
864
+ }
865
+ }
866
+ return get(options2, &ticket)->getProcess()->getGroup();
867
+ }
868
+
869
+ void setMax(unsigned int max) {
870
+ ScopedLock l(syncher);
871
+ P_ASSERT(max > 0);
872
+ verifyInvariants();
873
+ verifyExpensiveInvariants();
874
+ bool bigger = max > this->max;
875
+ this->max = max;
876
+ if (bigger) {
877
+ /* If there are clients waiting for resources
878
+ * to become free, spawn more processes now that
879
+ * we have the capacity.
880
+ *
881
+ * We favor waiters on the pool over waiters on the
882
+ * the groups because the latter already have the
883
+ * resources to eventually complete. Favoring waiters
884
+ * on the pool should be fairer.
885
+ */
886
+ vector<Callback> actions;
887
+ assignSessionsToGetWaiters(actions);
888
+ possiblySpawnMoreProcessesForExistingGroups();
889
+
890
+ verifyInvariants();
891
+ verifyExpensiveInvariants();
892
+ l.unlock();
893
+ runAllActions(actions);
894
+ } else {
895
+ verifyInvariants();
896
+ verifyExpensiveInvariants();
897
+ }
898
+ }
899
+
900
+ void activateNewMaxIdleTime() {
901
+ LockGuard l(syncher);
902
+ garbageCollectionTimer.stop();
903
+ garbageCollectionTimer.start(maxIdleTime / 1000000.0, 0.0);
904
+ }
905
+
906
+ void setMaxIdleTime(unsigned long long value) {
907
+ {
908
+ LockGuard l(syncher);
909
+ maxIdleTime = value;
910
+ }
911
+ libev->run(boost::bind(&Pool::activateNewMaxIdleTime, this));
912
+ }
913
+
914
+ unsigned int utilization(bool lock = true) const {
915
+ DynamicScopedLock l(syncher, lock);
916
+ SuperGroupMap::const_iterator it, end = superGroups.end();
917
+ int result = 0;
918
+ for (it = superGroups.begin(); it != end; it++) {
919
+ const SuperGroupPtr &superGroup = it->second;
920
+ result += superGroup->utilization();
921
+ }
922
+ return result;
923
+ }
924
+
925
+ bool atFullCapacity(bool lock = true) const {
926
+ DynamicScopedLock l(syncher, lock);
927
+ return utilization(false) >= max;
928
+ }
929
+
930
+ vector<ProcessPtr> getProcesses() const {
931
+ LockGuard l(syncher);
932
+ vector<ProcessPtr> result;
933
+ SuperGroupMap::const_iterator it, end = superGroups.end();
934
+ for (it = superGroups.begin(); OXT_LIKELY(it != end); it++) {
935
+ const SuperGroupPtr &superGroup = it->second;
936
+ vector<GroupPtr> &groups = superGroup->groups;
937
+ vector<GroupPtr>::const_iterator g_it, g_end = groups.end();
938
+ for (g_it = groups.begin(); g_it != g_end; g_it++) {
939
+ const GroupPtr &group = *g_it;
940
+ ProcessList::const_iterator p_it;
941
+
942
+ for (p_it = group->processes.begin(); p_it != group->processes.end(); p_it++) {
943
+ result.push_back(*p_it);
944
+ }
945
+ for (p_it = group->disabledProcesses.begin(); p_it != group->disabledProcesses.end(); p_it++) {
946
+ result.push_back(*p_it);
947
+ }
948
+ }
949
+ }
950
+ return result;
951
+ }
952
+
953
+ unsigned int getProcessCount(bool lock = true) const {
954
+ DynamicScopedLock l(syncher, lock);
955
+ unsigned int result = 0;
956
+ SuperGroupMap::const_iterator it, end = superGroups.end();
957
+ for (it = superGroups.begin(); OXT_LIKELY(it != end); it++) {
958
+ const SuperGroupPtr &superGroup = it->second;
959
+ result += superGroup->getProcessCount();
960
+ }
961
+ return result;
962
+ }
963
+
964
+ SuperGroupPtr findSuperGroupBySecret(const string &secret, bool lock = true) const {
965
+ DynamicScopedLock l(syncher, lock);
966
+ SuperGroupMap::const_iterator it, end = superGroups.end();
967
+ for (it = superGroups.begin(); OXT_LIKELY(it != end); it++) {
968
+ const SuperGroupPtr &superGroup = it->second;
969
+ if (superGroup->secret == secret) {
970
+ return superGroup;
971
+ }
972
+ }
973
+ return SuperGroupPtr();
974
+ }
975
+
976
+ ProcessPtr findProcessByGupid(const string &gupid, bool lock = true) const {
977
+ DynamicScopedLock l(syncher, lock);
978
+ SuperGroupMap::const_iterator it, end = superGroups.end();
979
+ for (it = superGroups.begin(); OXT_LIKELY(it != end); it++) {
980
+ const SuperGroupPtr &superGroup = it->second;
981
+ vector<GroupPtr> &groups = superGroup->groups;
982
+ vector<GroupPtr>::const_iterator g_it, g_end = groups.end();
983
+ for (g_it = groups.begin(); g_it != g_end; g_it++) {
984
+ const GroupPtr &group = *g_it;
985
+ const ProcessList &processes = group->processes;
986
+ ProcessList::const_iterator p_it, p_end = processes.end();
987
+ for (p_it = processes.begin(); p_it != p_end; p_it++) {
988
+ const ProcessPtr &process = *p_it;
989
+ if (process->gupid == gupid) {
990
+ return process;
991
+ }
992
+ }
993
+ }
994
+ }
995
+ return ProcessPtr();
996
+ }
997
+
998
+ bool detachSuperGroup(const SuperGroupPtr &superGroup, bool lock = true,
999
+ vector<Callback> *postLockActions = NULL)
1000
+ {
1001
+ P_ASSERT(lock || postLockActions != NULL);
1002
+ DynamicScopedLock l(syncher, lock);
1003
+
1004
+ if (OXT_LIKELY(superGroup->getPool().get() == this)) {
1005
+ if (OXT_LIKELY(superGroups.get(superGroup->name) != NULL)) {
1006
+ verifyInvariants();
1007
+ verifyExpensiveInvariants();
1008
+
1009
+ vector<Callback> actions;
1010
+
1011
+ forceDetachSuperGroup(superGroup, actions);
1012
+ /* If this SuperGroup had get waiters, either
1013
+ * on itself or in one of its groups, then we must
1014
+ * reprocess them immediately. Detaching such a
1015
+ * SuperGroup is essentially the same as restarting it.
1016
+ */
1017
+ migrateSuperGroupGetWaitlistToPool(superGroup);
1018
+
1019
+ assignSessionsToGetWaiters(actions);
1020
+ possiblySpawnMoreProcessesForExistingGroups();
1021
+
1022
+ verifyInvariants();
1023
+ verifyExpensiveInvariants();
1024
+
1025
+ if (lock) {
1026
+ l.unlock();
1027
+ runAllActions(actions);
1028
+ } else if (postLockActions->empty()) {
1029
+ *postLockActions = actions;
1030
+ } else {
1031
+ postLockActions->reserve(postLockActions->size() +
1032
+ actions.size());
1033
+ for (unsigned int i = 0; i < actions.size(); i++) {
1034
+ postLockActions->push_back(actions[i]);
1035
+ }
1036
+ }
1037
+
1038
+ return true;
1039
+ } else {
1040
+ return false;
1041
+ }
1042
+ } else {
1043
+ return false;
1044
+ }
1045
+ }
1046
+
1047
+ bool detachProcess(const ProcessPtr &process) {
1048
+ ScopedLock l(syncher);
1049
+ vector<Callback> actions;
1050
+ bool result = detachProcessUnlocked(process, actions);
1051
+ l.unlock();
1052
+ runAllActions(actions);
1053
+ return result;
1054
+ }
1055
+
1056
+ bool detachSuperGroup(const string &superGroupSecret) {
1057
+ LockGuard l(syncher);
1058
+ SuperGroupPtr superGroup = findSuperGroupBySecret(superGroupSecret, false);
1059
+ if (superGroup != NULL) {
1060
+ return detachSuperGroup(superGroup, false);
1061
+ } else {
1062
+ return false;
1063
+ }
1064
+ }
1065
+
1066
+ bool detachProcess(const string &gupid) {
1067
+ ScopedLock l(syncher);
1068
+ ProcessPtr process = findProcessByGupid(gupid, false);
1069
+ if (process != NULL) {
1070
+ vector<Callback> actions;
1071
+ bool result = detachProcessUnlocked(process, actions);
1072
+ l.unlock();
1073
+ runAllActions(actions);
1074
+ return result;
1075
+ } else {
1076
+ return false;
1077
+ }
1078
+ }
1079
+
1080
+ string inspect(const InspectOptions &options = InspectOptions(), bool lock = true) const {
1081
+ DynamicScopedLock l(syncher, lock);
1082
+ stringstream result;
1083
+ const char *headerColor = maybeColorize(options, ANSI_COLOR_YELLOW ANSI_COLOR_BLUE_BG ANSI_COLOR_BOLD);
1084
+ const char *resetColor = maybeColorize(options, ANSI_COLOR_RESET);
1085
+
1086
+ result << headerColor << "----------- General information -----------" << resetColor << endl;
1087
+ result << "Max pool size : " << max << endl;
1088
+ result << "Processes : " << getProcessCount(false) << endl;
1089
+ result << "Requests in queue : " << getWaitlist.size() << endl;
1090
+ //result << "active = " << active << endl;
1091
+ //result << "inactive = " << inactiveApps.size() << endl;
1092
+ result << endl;
1093
+
1094
+ result << headerColor << "----------- Application groups -----------" << resetColor << endl;
1095
+ SuperGroupMap::const_iterator sg_it, sg_end = superGroups.end();
1096
+ for (sg_it = superGroups.begin(); sg_it != sg_end; sg_it++) {
1097
+ const SuperGroupPtr &superGroup = sg_it->second;
1098
+ const Group *group = superGroup->defaultGroup;
1099
+ ProcessList::const_iterator p_it;
1100
+
1101
+ if (group != NULL) {
1102
+ result << group->name << ":" << endl;
1103
+ result << " App root: " << group->options.appRoot << endl;
1104
+ if (group->spawning()) {
1105
+ result << " (spawning new process...)" << endl;
1106
+ }
1107
+ result << " Requests in queue: " << group->getWaitlist.size() << endl;
1108
+ for (p_it = group->processes.begin(); p_it != group->processes.end(); p_it++) {
1109
+ const ProcessPtr &process = *p_it;
1110
+ char buf[128];
1111
+
1112
+ snprintf(buf, sizeof(buf),
1113
+ "* PID: %-5lu Sessions: %-2u Processed: %-5u Uptime: %s",
1114
+ (unsigned long) process->pid,
1115
+ process->sessions,
1116
+ process->processed,
1117
+ process->uptime().c_str());
1118
+ result << " " << buf << endl;
1119
+ const Socket *socket;
1120
+ if (options.verbose && (socket = process->sockets->findSocketWithName("http")) != NULL) {
1121
+ result << " URL : http://" << replaceString(socket->address, "tcp://", "") << endl;
1122
+ result << " Password: " << process->connectPassword << endl;
1123
+ }
1124
+ }
1125
+ result << endl;
1126
+ }
1127
+ }
1128
+ return result.str();
1129
+ }
1130
+
1131
+ string toXml(bool includeSecrets = true) const {
1132
+ LockGuard l(syncher);
1133
+ stringstream result;
1134
+ SuperGroupMap::const_iterator sg_it;
1135
+ vector<GroupPtr>::const_iterator g_it;
1136
+ ProcessList::const_iterator p_it;
1137
+
1138
+ result << "<?xml version=\"1.0\" encoding=\"iso8859-1\" ?>\n";
1139
+ result << "<info version=\"2\">";
1140
+
1141
+ result << "<process_count>" << getProcessCount(false) << "</process_count>";
1142
+ result << "<max>" << max << "</max>";
1143
+ result << "<utilization>" << utilization(false) << "</utilization>";
1144
+ result << "<get_wait_list_size>" << getWaitlist.size() << "</get_wait_list_size>";
1145
+
1146
+ result << "<supergroups>";
1147
+ for (sg_it = superGroups.begin(); sg_it != superGroups.end(); sg_it++) {
1148
+ const SuperGroupPtr &superGroup = sg_it->second;
1149
+
1150
+ result << "<name>" << escapeForXml(superGroup->name) << "</name>";
1151
+ result << "<state>" << superGroup->getStateName() << "</state>";
1152
+ result << "<get_wait_list_size>" << superGroup->getWaitlist.size() << "</get_wait_list_size>";
1153
+ result << "<utilization>" << superGroup->utilization() << "</utilization>";
1154
+ if (includeSecrets) {
1155
+ result << "<secret>" << escapeForXml(superGroup->secret) << "</secret>";
1156
+ }
1157
+
1158
+ for (g_it = superGroup->groups.begin(); g_it != superGroup->groups.end(); g_it++) {
1159
+ const GroupPtr &group = *g_it;
1160
+
1161
+ if (group->componentInfo.isDefault) {
1162
+ result << "<group default=\"true\">";
1163
+ } else {
1164
+ result << "<group>";
1165
+ }
1166
+ group->inspectXml(result, includeSecrets);
1167
+ result << "</group>";
1168
+ }
1169
+ }
1170
+ result << "</supergroups>";
1171
+
1172
+ result << "</info>";
1173
+ return result.str();
1174
+ }
1175
+ };
1176
+
1177
+
1178
+ } // namespace ApplicationPool2
1179
+ } // namespace Passenger
1180
+
1181
+ #endif /* _PASSENGER_APPLICATION_POOL2_POOL_H_ */