passenger 2.0.6 → 2.1.2

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 (497) hide show
  1. data/DEVELOPERS.TXT +10 -4
  2. data/LICENSE +1 -1
  3. data/NEWS +0 -0
  4. data/Rakefile +183 -117
  5. data/benchmark/dispatcher.rb +5 -9
  6. data/bin/passenger-install-apache2-module +52 -18
  7. data/bin/passenger-memory-stats +67 -13
  8. data/bin/passenger-spawn-server +8 -4
  9. data/bin/passenger-status +21 -46
  10. data/bin/passenger-stress-test +5 -5
  11. data/debian/postinst +1 -1
  12. data/doc/ApplicationPool algorithm.txt +180 -128
  13. data/doc/Architectural overview.html +1 -778
  14. data/doc/Security of user switching support.html +1 -643
  15. data/doc/Users guide Apache.html +3127 -0
  16. data/doc/Users guide Nginx.html +1458 -0
  17. data/doc/Users guide.html +1404 -467
  18. data/doc/Users guide.txt +843 -105
  19. data/doc/cxxapi/ApplicationPoolServer_8h-source.html +751 -641
  20. data/doc/cxxapi/ApplicationPool_8h-source.html +168 -171
  21. data/doc/cxxapi/Application_8h-source.html +494 -394
  22. data/doc/cxxapi/Bucket_8h-source.html +21 -15
  23. data/doc/cxxapi/CachedFileStat_8h-source.html +191 -0
  24. data/doc/cxxapi/Configuration_8h-source.html +311 -149
  25. data/doc/cxxapi/DirectoryMapper_8h-source.html +309 -0
  26. data/doc/cxxapi/DummySpawnManager_8h-source.html +3 -4
  27. data/doc/cxxapi/Exceptions_8h-source.html +182 -165
  28. data/doc/cxxapi/FileChecker_8h-source.html +130 -0
  29. data/doc/cxxapi/Hooks_8h-source.html +2 -3
  30. data/doc/cxxapi/Logging_8h-source.html +92 -89
  31. data/doc/cxxapi/MessageChannel_8h-source.html +585 -477
  32. data/doc/cxxapi/PoolOptions_8h-source.html +305 -0
  33. data/doc/cxxapi/SpawnManager_8h-source.html +515 -540
  34. data/doc/cxxapi/StandardApplicationPool_8h-source.html +779 -679
  35. data/doc/cxxapi/SystemTime_8h-source.html +104 -0
  36. data/doc/cxxapi/Utils_8h-source.html +331 -227
  37. data/doc/cxxapi/annotated.html +6 -7
  38. data/doc/cxxapi/classClient-members.html +1 -2
  39. data/doc/cxxapi/classClient.html +1 -2
  40. data/doc/cxxapi/classHooks-members.html +5 -2
  41. data/doc/cxxapi/classHooks.html +112 -2
  42. data/doc/cxxapi/classPassenger_1_1Application-members.html +2 -3
  43. data/doc/cxxapi/classPassenger_1_1Application.html +8 -9
  44. data/doc/cxxapi/classPassenger_1_1ApplicationPool-members.html +4 -4
  45. data/doc/cxxapi/classPassenger_1_1ApplicationPool.html +42 -81
  46. data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer-members.html +1 -2
  47. data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer.html +3 -4
  48. data/doc/cxxapi/classPassenger_1_1ApplicationPool__inherit__graph.png +0 -0
  49. data/doc/cxxapi/classPassenger_1_1Application_1_1Session-members.html +3 -2
  50. data/doc/cxxapi/classPassenger_1_1Application_1_1Session.html +74 -3
  51. data/doc/cxxapi/classPassenger_1_1BusyException-members.html +1 -2
  52. data/doc/cxxapi/classPassenger_1_1BusyException.html +2 -3
  53. data/doc/cxxapi/classPassenger_1_1ConfigurationException-members.html +1 -2
  54. data/doc/cxxapi/classPassenger_1_1ConfigurationException.html +2 -3
  55. data/doc/cxxapi/classPassenger_1_1DirectoryMapper-members.html +38 -0
  56. data/doc/cxxapi/classPassenger_1_1DirectoryMapper.html +256 -0
  57. data/doc/cxxapi/classPassenger_1_1DummySpawnManager-members.html +1 -2
  58. data/doc/cxxapi/classPassenger_1_1DummySpawnManager.html +2 -3
  59. data/doc/cxxapi/{classPassenger_1_1Thread-members.html → classPassenger_1_1FileChecker-members.html} +4 -5
  60. data/doc/cxxapi/classPassenger_1_1FileChecker.html +121 -0
  61. data/doc/cxxapi/classPassenger_1_1FileNotFoundException-members.html +1 -2
  62. data/doc/cxxapi/classPassenger_1_1FileNotFoundException.html +2 -3
  63. data/doc/cxxapi/classPassenger_1_1FileNotFoundException__inherit__graph.png +0 -0
  64. data/doc/cxxapi/classPassenger_1_1FileSystemException-members.html +2 -3
  65. data/doc/cxxapi/classPassenger_1_1FileSystemException.html +2 -3
  66. data/doc/cxxapi/classPassenger_1_1FileSystemException__inherit__graph.png +0 -0
  67. data/doc/cxxapi/classPassenger_1_1IOException-members.html +1 -2
  68. data/doc/cxxapi/classPassenger_1_1IOException.html +2 -3
  69. data/doc/cxxapi/classPassenger_1_1IOException__inherit__graph.png +0 -0
  70. data/doc/cxxapi/classPassenger_1_1MessageChannel-members.html +5 -2
  71. data/doc/cxxapi/classPassenger_1_1MessageChannel.html +155 -5
  72. data/doc/cxxapi/{classboost_1_1this__thread_1_1enable__syscall__interruption-members.html → classPassenger_1_1RuntimeException-members.html} +2 -3
  73. data/doc/cxxapi/{classboost_1_1this__thread_1_1enable__syscall__interruption.html → classPassenger_1_1RuntimeException.html} +10 -8
  74. data/doc/cxxapi/classPassenger_1_1SpawnException-members.html +1 -2
  75. data/doc/cxxapi/classPassenger_1_1SpawnException.html +2 -3
  76. data/doc/cxxapi/classPassenger_1_1SpawnManager-members.html +2 -3
  77. data/doc/cxxapi/classPassenger_1_1SpawnManager.html +15 -56
  78. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool-members.html +5 -4
  79. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool.html +20 -81
  80. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool__inherit__graph.png +0 -0
  81. data/doc/cxxapi/classPassenger_1_1SystemException-members.html +2 -3
  82. data/doc/cxxapi/classPassenger_1_1SystemException.html +9 -10
  83. data/doc/cxxapi/classPassenger_1_1SystemException__inherit__graph.png +0 -0
  84. data/doc/cxxapi/{classboost_1_1this__thread_1_1disable__syscall__interruption-members.html → classPassenger_1_1SystemTime-members.html} +5 -3
  85. data/doc/cxxapi/classPassenger_1_1SystemTime.html +86 -0
  86. data/doc/cxxapi/classPassenger_1_1TempFile-members.html +2 -3
  87. data/doc/cxxapi/classPassenger_1_1TempFile.html +17 -9
  88. data/doc/cxxapi/definitions_8h-source.html +1 -2
  89. data/doc/cxxapi/files.html +6 -3
  90. data/doc/cxxapi/functions.html +98 -35
  91. data/doc/cxxapi/functions_func.html +60 -32
  92. data/doc/cxxapi/functions_type.html +1 -2
  93. data/doc/cxxapi/functions_vars.html +27 -2
  94. data/doc/cxxapi/graph_legend.html +1 -2
  95. data/doc/cxxapi/graph_legend.png +0 -0
  96. data/doc/cxxapi/group__Configuration.html +3 -4
  97. data/doc/cxxapi/group__Configuration.png +0 -0
  98. data/doc/cxxapi/group__Core.html +3 -4
  99. data/doc/cxxapi/group__Core.png +0 -0
  100. data/doc/cxxapi/group__Exceptions.html +4 -2
  101. data/doc/cxxapi/group__Hooks.html +1 -6
  102. data/doc/cxxapi/group__Hooks.png +0 -0
  103. data/doc/cxxapi/group__Support.html +259 -36
  104. data/doc/cxxapi/hierarchy.html +6 -7
  105. data/doc/cxxapi/inherit__graph__0.map +1 -1
  106. data/doc/cxxapi/inherit__graph__0.md5 +1 -1
  107. data/doc/cxxapi/inherit__graph__0.png +0 -0
  108. data/doc/cxxapi/inherit__graph__1.map +1 -1
  109. data/doc/cxxapi/inherit__graph__1.md5 +1 -1
  110. data/doc/cxxapi/inherit__graph__1.png +0 -0
  111. data/doc/cxxapi/inherit__graph__10.map +1 -1
  112. data/doc/cxxapi/inherit__graph__10.md5 +1 -1
  113. data/doc/cxxapi/inherit__graph__10.png +0 -0
  114. data/doc/cxxapi/inherit__graph__11.map +1 -1
  115. data/doc/cxxapi/inherit__graph__11.md5 +1 -1
  116. data/doc/cxxapi/inherit__graph__11.png +0 -0
  117. data/doc/cxxapi/inherit__graph__12.map +2 -1
  118. data/doc/cxxapi/inherit__graph__12.md5 +1 -1
  119. data/doc/cxxapi/inherit__graph__12.png +0 -0
  120. data/doc/cxxapi/inherit__graph__13.map +1 -1
  121. data/doc/cxxapi/inherit__graph__13.md5 +1 -1
  122. data/doc/cxxapi/inherit__graph__13.png +0 -0
  123. data/doc/cxxapi/inherit__graph__14.map +1 -2
  124. data/doc/cxxapi/inherit__graph__14.md5 +1 -1
  125. data/doc/cxxapi/inherit__graph__14.png +0 -0
  126. data/doc/cxxapi/inherit__graph__15.map +1 -1
  127. data/doc/cxxapi/inherit__graph__15.md5 +1 -1
  128. data/doc/cxxapi/inherit__graph__15.png +0 -0
  129. data/doc/cxxapi/inherit__graph__16.map +1 -1
  130. data/doc/cxxapi/inherit__graph__16.md5 +1 -1
  131. data/doc/cxxapi/inherit__graph__16.png +0 -0
  132. data/doc/cxxapi/inherit__graph__17.png +0 -0
  133. data/doc/cxxapi/inherit__graph__18.png +0 -0
  134. data/doc/cxxapi/inherit__graph__19.png +0 -0
  135. data/doc/cxxapi/inherit__graph__2.map +1 -1
  136. data/doc/cxxapi/inherit__graph__2.md5 +1 -1
  137. data/doc/cxxapi/inherit__graph__2.png +0 -0
  138. data/doc/cxxapi/inherit__graph__20.map +1 -1
  139. data/doc/cxxapi/inherit__graph__20.md5 +1 -1
  140. data/doc/cxxapi/inherit__graph__20.png +0 -0
  141. data/doc/cxxapi/inherit__graph__21.map +1 -1
  142. data/doc/cxxapi/inherit__graph__21.md5 +1 -1
  143. data/doc/cxxapi/inherit__graph__21.png +0 -0
  144. data/doc/cxxapi/inherit__graph__3.map +1 -1
  145. data/doc/cxxapi/inherit__graph__3.md5 +1 -1
  146. data/doc/cxxapi/inherit__graph__3.png +0 -0
  147. data/doc/cxxapi/inherit__graph__4.map +1 -1
  148. data/doc/cxxapi/inherit__graph__4.md5 +1 -1
  149. data/doc/cxxapi/inherit__graph__4.png +0 -0
  150. data/doc/cxxapi/inherit__graph__5.map +2 -1
  151. data/doc/cxxapi/inherit__graph__5.md5 +1 -1
  152. data/doc/cxxapi/inherit__graph__5.png +0 -0
  153. data/doc/cxxapi/inherit__graph__6.map +1 -1
  154. data/doc/cxxapi/inherit__graph__6.md5 +1 -1
  155. data/doc/cxxapi/inherit__graph__6.png +0 -0
  156. data/doc/cxxapi/inherit__graph__7.map +1 -1
  157. data/doc/cxxapi/inherit__graph__7.md5 +1 -1
  158. data/doc/cxxapi/inherit__graph__7.png +0 -0
  159. data/doc/cxxapi/inherit__graph__8.map +1 -1
  160. data/doc/cxxapi/inherit__graph__8.md5 +1 -1
  161. data/doc/cxxapi/inherit__graph__8.png +0 -0
  162. data/doc/cxxapi/inherit__graph__9.map +1 -2
  163. data/doc/cxxapi/inherit__graph__9.md5 +1 -1
  164. data/doc/cxxapi/inherit__graph__9.png +0 -0
  165. data/doc/cxxapi/inherits.html +30 -31
  166. data/doc/cxxapi/main.html +1 -2
  167. data/doc/cxxapi/modules.html +1 -2
  168. data/doc/cxxapi/structPassenger_1_1AnythingToString-members.html +1 -2
  169. data/doc/cxxapi/structPassenger_1_1AnythingToString.html +2 -3
  170. data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4-members.html +1 -2
  171. data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4.html +2 -3
  172. data/doc/cxxapi/structPassenger_1_1PoolOptions-members.html +49 -0
  173. data/doc/cxxapi/structPassenger_1_1PoolOptions.html +404 -0
  174. data/doc/cxxapi/tree.html +18 -20
  175. data/doc/images/conservative_spawning.png +0 -0
  176. data/doc/images/conservative_spawning.svg +248 -0
  177. data/doc/images/smart-lv2.png +0 -0
  178. data/doc/images/smart-lv2.svg +320 -0
  179. data/doc/rdoc/classes/ConditionVariable.html +68 -34
  180. data/doc/rdoc/classes/Exception.html +16 -16
  181. data/doc/rdoc/classes/GC.html +9 -9
  182. data/doc/rdoc/classes/IO.html +36 -17
  183. data/doc/rdoc/classes/PhusionPassenger.html +183 -0
  184. data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +511 -0
  185. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer.html +285 -242
  186. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerAlreadyStarted.html +3 -3
  187. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerError.html +3 -3
  188. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerNotStarted.html +3 -3
  189. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/UnknownMessage.html +3 -3
  190. data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +598 -0
  191. data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +140 -0
  192. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +247 -0
  193. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +138 -0
  194. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AppInitError.html +36 -19
  195. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/Application.html +81 -96
  196. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/ConsoleTextTemplate.html +18 -18
  197. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/FrameworkInitError.html +20 -18
  198. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/HTMLTemplate.html +18 -18
  199. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/InitializationError.html +9 -9
  200. data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +92 -0
  201. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/MessageChannel.html +93 -92
  202. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/NativeSupport.html +55 -25
  203. data/doc/rdoc/classes/PhusionPassenger/Rack.html +91 -0
  204. data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +185 -0
  205. data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +182 -0
  206. data/doc/rdoc/classes/PhusionPassenger/Railz.html +95 -0
  207. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +424 -0
  208. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +98 -0
  209. data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +200 -0
  210. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +444 -0
  211. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +98 -0
  212. data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +154 -0
  213. data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +408 -0
  214. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/UnknownError.html +13 -13
  215. data/doc/rdoc/classes/PhusionPassenger/Utils.html +687 -0
  216. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/VersionNotFound.html +8 -8
  217. data/doc/rdoc/classes/PhusionPassenger/WSGI.html +89 -0
  218. data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +188 -0
  219. data/doc/rdoc/classes/PlatformInfo.html +663 -159
  220. data/doc/rdoc/classes/RakeExtensions.html +4 -4
  221. data/doc/rdoc/classes/Signal.html +134 -0
  222. data/doc/rdoc/created.rid +1 -1
  223. data/doc/rdoc/files/DEVELOPERS_TXT.html +15 -10
  224. data/doc/rdoc/files/README.html +5 -7
  225. data/doc/rdoc/files/ext/{passenger → phusion_passenger}/native_support_c.html +2 -2
  226. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/abstract_request_handler_rb.html +7 -9
  227. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +120 -0
  228. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/abstract_server_rb.html +7 -10
  229. data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +99 -0
  230. data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +92 -0
  231. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/application_rb.html +6 -8
  232. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/console_text_template_rb.html +5 -7
  233. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/constants_rb.html +4 -5
  234. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/dependencies_rb.html +6 -8
  235. data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +116 -0
  236. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/exceptions_rb.html +5 -7
  237. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/html_template_rb.html +5 -7
  238. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/message_channel_rb.html +5 -7
  239. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/platform_info_rb.html +6 -7
  240. data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +123 -0
  241. data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +117 -0
  242. data/doc/rdoc/files/lib/{passenger/utils_rb.html → phusion_passenger/railz/application_spawner_rb.html} +24 -17
  243. data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +126 -0
  244. data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +139 -0
  245. data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +118 -0
  246. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/simple_benchmarking_rb.html +5 -7
  247. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/spawn_manager_rb.html +40 -24
  248. data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +169 -0
  249. data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +120 -0
  250. data/doc/rdoc/files/lib/rake/extensions_rb.html +3 -4
  251. data/doc/rdoc/fr_class_index.html +37 -19
  252. data/doc/rdoc/fr_file_index.html +25 -14
  253. data/doc/rdoc/fr_method_index.html +145 -74
  254. data/ext/apache2/Application.h +145 -44
  255. data/ext/apache2/ApplicationPool.h +27 -29
  256. data/ext/apache2/ApplicationPoolServer.h +183 -72
  257. data/ext/apache2/ApplicationPoolServerExecutable.cpp +249 -42
  258. data/ext/apache2/Bucket.cpp +61 -9
  259. data/ext/apache2/Bucket.h +15 -8
  260. data/ext/apache2/CachedFileStat.cpp +114 -0
  261. data/ext/apache2/CachedFileStat.h +169 -0
  262. data/ext/apache2/Configuration.cpp +213 -22
  263. data/ext/apache2/Configuration.h +176 -13
  264. data/ext/apache2/DirectoryMapper.h +287 -0
  265. data/ext/apache2/Exceptions.h +30 -12
  266. data/ext/apache2/FileChecker.h +108 -0
  267. data/ext/apache2/Hooks.cpp +709 -493
  268. data/ext/apache2/LICENSE-CNRI.TXT +15 -0
  269. data/ext/apache2/Logging.h +26 -22
  270. data/ext/apache2/MessageChannel.h +124 -15
  271. data/ext/apache2/PoolOptions.h +283 -0
  272. data/ext/apache2/SpawnManager.h +75 -99
  273. data/ext/apache2/StandardApplicationPool.h +296 -195
  274. data/ext/apache2/SystemTime.cpp +28 -0
  275. data/ext/apache2/SystemTime.h +82 -0
  276. data/ext/apache2/Utils.cpp +172 -18
  277. data/ext/apache2/Utils.h +124 -19
  278. data/ext/boost/cstdint.hpp +4 -2
  279. data/ext/boost/current_function.hpp +67 -0
  280. data/ext/boost/detail/sp_counted_base.hpp +4 -4
  281. data/ext/boost/thread/exceptions.hpp +2 -1
  282. data/ext/boost/thread/pthread/thread.hpp +11 -3
  283. data/ext/boost/thread/pthread/thread_data.hpp +2 -1
  284. data/ext/oxt/backtrace.cpp +172 -0
  285. data/ext/oxt/backtrace.hpp +135 -0
  286. data/ext/oxt/detail/backtrace_disabled.hpp +39 -0
  287. data/ext/oxt/detail/backtrace_enabled.hpp +155 -0
  288. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +82 -0
  289. data/ext/oxt/detail/spin_lock_portable.hpp +38 -0
  290. data/ext/oxt/detail/spin_lock_pthreads.hpp +97 -0
  291. data/ext/oxt/detail/tracable_exception_disabled.hpp +46 -0
  292. data/ext/oxt/detail/tracable_exception_enabled.hpp +48 -0
  293. data/ext/oxt/macros.hpp +58 -0
  294. data/ext/oxt/spin_lock.hpp +55 -0
  295. data/ext/{apache2/System.cpp → oxt/system_calls.cpp} +87 -52
  296. data/ext/oxt/system_calls.hpp +234 -0
  297. data/ext/oxt/thread.cpp +32 -0
  298. data/ext/oxt/thread.hpp +223 -0
  299. data/ext/oxt/tracable_exception.cpp +87 -0
  300. data/ext/oxt/tracable_exception.hpp +35 -0
  301. data/{lib/passenger/constants.rb → ext/phusion_passenger/extconf.rb} +14 -9
  302. data/ext/{passenger → phusion_passenger}/native_support.c +33 -6
  303. data/lib/{passenger → phusion_passenger}/abstract_request_handler.rb +209 -93
  304. data/lib/{passenger → phusion_passenger}/abstract_server.rb +23 -8
  305. data/lib/phusion_passenger/abstract_server_collection.rb +301 -0
  306. data/lib/phusion_passenger/admin_tools.rb +25 -0
  307. data/lib/phusion_passenger/admin_tools/control_process.rb +107 -0
  308. data/lib/{passenger → phusion_passenger}/application.rb +13 -16
  309. data/lib/{passenger → phusion_passenger}/console_text_template.rb +2 -2
  310. data/{ext/passenger/extconf.rb → lib/phusion_passenger/constants.rb} +5 -5
  311. data/lib/{passenger → phusion_passenger}/dependencies.rb +38 -32
  312. data/lib/phusion_passenger/events.rb +45 -0
  313. data/lib/{passenger → phusion_passenger}/exceptions.rb +12 -5
  314. data/lib/{passenger → phusion_passenger}/html_template.rb +2 -2
  315. data/lib/{passenger → phusion_passenger}/message_channel.rb +3 -2
  316. data/lib/phusion_passenger/platform_info.rb +500 -0
  317. data/lib/{passenger → phusion_passenger}/rack/application_spawner.rb +29 -22
  318. data/lib/{passenger → phusion_passenger}/rack/request_handler.rb +14 -9
  319. data/lib/{passenger → phusion_passenger}/railz/application_spawner.rb +94 -74
  320. data/lib/{passenger → phusion_passenger}/railz/cgi_fixed.rb +2 -2
  321. data/lib/{passenger → phusion_passenger}/railz/framework_spawner.rb +86 -98
  322. data/lib/{passenger → phusion_passenger}/railz/request_handler.rb +6 -6
  323. data/lib/{passenger → phusion_passenger}/simple_benchmarking.rb +0 -0
  324. data/lib/{passenger → phusion_passenger}/spawn_manager.rb +136 -128
  325. data/lib/{passenger → phusion_passenger}/templates/apache2_config_snippets.txt.erb +0 -0
  326. data/lib/{passenger → phusion_passenger}/templates/apache_must_be_compiled_with_compatible_mpm.txt.erb +0 -0
  327. data/lib/phusion_passenger/templates/app_exited_during_initialization.html.erb +38 -0
  328. data/lib/{passenger → phusion_passenger}/templates/app_init_error.html.erb +0 -0
  329. data/lib/{passenger → phusion_passenger}/templates/database_error.html.erb +0 -0
  330. data/lib/{passenger → phusion_passenger}/templates/deployment_example.txt.erb +1 -1
  331. data/lib/{passenger → phusion_passenger}/templates/error_layout.css +0 -0
  332. data/lib/{passenger → phusion_passenger}/templates/error_layout.html.erb +0 -0
  333. data/lib/{passenger → phusion_passenger}/templates/framework_init_error.html.erb +0 -0
  334. data/lib/{passenger → phusion_passenger}/templates/general_error.html.erb +0 -0
  335. data/lib/{passenger → phusion_passenger}/templates/invalid_app_root.html.erb +1 -1
  336. data/lib/{passenger → phusion_passenger}/templates/load_error.html.erb +0 -0
  337. data/lib/{passenger → phusion_passenger}/templates/no_write_permission_to_passenger_root.txt.erb +0 -0
  338. data/lib/{passenger → phusion_passenger}/templates/possible_solutions_for_compilation_and_installation_problems.txt.erb +0 -0
  339. data/lib/{passenger → phusion_passenger}/templates/run_installer_as_root.txt.erb +0 -0
  340. data/lib/{passenger → phusion_passenger}/templates/version_not_found.html.erb +0 -0
  341. data/lib/{passenger → phusion_passenger}/templates/welcome.txt.erb +0 -0
  342. data/lib/{passenger → phusion_passenger}/utils.rb +210 -44
  343. data/lib/{passenger → phusion_passenger}/wsgi/application_spawner.rb +18 -15
  344. data/lib/{passenger → phusion_passenger}/wsgi/request_handler.py +7 -1
  345. data/man/passenger-memory-stats.8 +1 -1
  346. data/misc/render_error_pages.rb +1 -1
  347. data/test/ApplicationPoolServerTest.cpp +0 -28
  348. data/test/ApplicationPoolServer_ApplicationPoolTest.cpp +4 -0
  349. data/test/ApplicationPoolTest.cpp +307 -69
  350. data/test/CachedFileStatTest.cpp +262 -0
  351. data/test/FileCheckerTest.cpp +79 -0
  352. data/test/MessageChannelTest.cpp +3 -3
  353. data/test/PoolOptionsTest.cpp +37 -0
  354. data/test/SpawnManagerTest.cpp +4 -4
  355. data/test/StandardApplicationPoolTest.cpp +4 -0
  356. data/test/SystemTimeTest.cpp +37 -0
  357. data/test/UtilsTest.cpp +137 -0
  358. data/test/integration_tests.rb +270 -23
  359. data/test/oxt/backtrace_test.cpp +128 -0
  360. data/test/oxt/oxt_test_main.cpp +25 -0
  361. data/test/oxt/syscall_interruption_test.cpp +50 -0
  362. data/test/ruby/abstract_request_handler_spec.rb +83 -0
  363. data/test/ruby/abstract_server_collection_spec.rb +246 -0
  364. data/test/ruby/application_spec.rb +3 -3
  365. data/test/ruby/message_channel_spec.rb +2 -2
  366. data/test/ruby/rack/application_spawner_spec.rb +3 -5
  367. data/test/ruby/rails/application_spawner_spec.rb +54 -15
  368. data/test/ruby/rails/framework_spawner_spec.rb +6 -8
  369. data/test/ruby/rails/minimal_spawner_spec.rb +29 -0
  370. data/test/ruby/rails/spawner_error_handling_spec.rb +1 -1
  371. data/test/ruby/rails/spawner_privilege_lowering_spec.rb +3 -3
  372. data/test/ruby/spawn_manager_spec.rb +23 -12
  373. data/test/ruby/utils_spec.rb +36 -2
  374. data/test/ruby/wsgi/application_spawner_spec.rb +47 -0
  375. data/test/stub/apache2/httpd.conf.erb +3 -5
  376. data/test/stub/message_channel.rb +2 -2
  377. data/test/stub/message_channel_2.rb +2 -2
  378. data/test/stub/message_channel_3.rb +3 -3
  379. data/test/stub/minimal-railsapp/README +0 -0
  380. data/test/stub/minimal-railsapp/config/application.rb +0 -0
  381. data/test/stub/minimal-railsapp/config/environment.rb +0 -0
  382. data/test/stub/minimal-railsapp/vendor/rails/actionmailer/lib/action_mailer.rb +0 -0
  383. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +0 -0
  384. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_pack.rb +0 -0
  385. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_view.rb +0 -0
  386. data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +0 -0
  387. data/test/stub/minimal-railsapp/vendor/rails/activeresource/lib/active_resource.rb +0 -0
  388. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support.rb +0 -0
  389. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support/whiny_nil.rb +0 -0
  390. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/dispatcher.rb +0 -0
  391. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/initializer.rb +0 -0
  392. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/ruby_version_check.rb +0 -0
  393. data/test/stub/rails_apps/foobar/app/controllers/foo_controller.rb +8 -0
  394. data/test/stub/rails_apps/foobar/config/environments/development.rb +1 -2
  395. data/test/stub/rails_apps/mycook/app/controllers/welcome_controller.rb +21 -1
  396. data/test/stub/rails_apps/mycook/sites/some.site/public/uploads.html +26 -0
  397. data/test/stub/rails_apps/mycook/sites/some.site/public/welcome/cached.html +26 -0
  398. data/test/stub/railsapp/app/controllers/application.rb +0 -0
  399. data/test/stub/railsapp/app/controllers/bar_controller_1.rb +0 -0
  400. data/test/stub/railsapp/app/controllers/bar_controller_2.rb +1 -1
  401. data/test/stub/railsapp/app/controllers/foo_controller.rb +4 -0
  402. data/test/stub/railsapp/app/helpers/application_helper.rb +0 -0
  403. data/test/stub/railsapp/config/boot.rb +0 -0
  404. data/test/stub/railsapp/config/database.yml +0 -0
  405. data/test/stub/railsapp/config/environment.rb +0 -0
  406. data/test/stub/railsapp/config/environments/development.rb +0 -0
  407. data/test/stub/railsapp/config/environments/production.rb +0 -0
  408. data/test/stub/railsapp/config/initializers/inflections.rb +0 -0
  409. data/test/stub/railsapp/config/initializers/mime_types.rb +0 -0
  410. data/test/stub/railsapp/config/routes.rb +0 -0
  411. data/test/stub/railsapp/public/useless.txt +0 -0
  412. data/test/stub/spawn_server.rb +3 -4
  413. data/test/stub/wsgi/passenger_wsgi.pyc +0 -0
  414. data/test/support/apache2_controller.rb +57 -7
  415. data/test/support/tut.h +15 -0
  416. data/vendor/README +12 -0
  417. data/vendor/README_FOR_PACKAGERS +1 -0
  418. data/vendor/rack-0.9.1/AUTHORS +8 -0
  419. data/vendor/rack-0.9.1/COPYING +18 -0
  420. data/vendor/rack-0.9.1/ChangeLog +1423 -0
  421. data/vendor/rack-0.9.1/KNOWN-ISSUES +18 -0
  422. data/vendor/rack-0.9.1/README +306 -0
  423. data/vendor/rack-0.9.1/Rakefile +188 -0
  424. data/vendor/rack-0.9.1/SPEC +129 -0
  425. data/vendor/rack-0.9.1/lib/rack.rb +86 -0
  426. data/vendor/rack-0.9.1/lib/rack/adapter/camping.rb +22 -0
  427. data/vendor/rack-0.9.1/lib/rack/auth/abstract/handler.rb +28 -0
  428. data/vendor/rack-0.9.1/lib/rack/auth/abstract/request.rb +37 -0
  429. data/vendor/rack-0.9.1/lib/rack/auth/basic.rb +58 -0
  430. data/vendor/rack-0.9.1/lib/rack/auth/digest/md5.rb +124 -0
  431. data/vendor/rack-0.9.1/lib/rack/auth/digest/nonce.rb +51 -0
  432. data/vendor/rack-0.9.1/lib/rack/auth/digest/params.rb +55 -0
  433. data/vendor/rack-0.9.1/lib/rack/auth/digest/request.rb +40 -0
  434. data/vendor/rack-0.9.1/lib/rack/auth/openid.rb +438 -0
  435. data/vendor/rack-0.9.1/lib/rack/builder.rb +67 -0
  436. data/vendor/rack-0.9.1/lib/rack/cascade.rb +36 -0
  437. data/vendor/rack-0.9.1/lib/rack/commonlogger.rb +61 -0
  438. data/vendor/rack-0.9.1/lib/rack/conditionalget.rb +43 -0
  439. data/vendor/rack-0.9.1/lib/rack/content_length.rb +25 -0
  440. data/vendor/rack-0.9.1/lib/rack/deflater.rb +87 -0
  441. data/vendor/rack-0.9.1/lib/rack/directory.rb +150 -0
  442. data/vendor/rack-0.9.1/lib/rack/file.rb +85 -0
  443. data/vendor/rack-0.9.1/lib/rack/handler.rb +48 -0
  444. data/vendor/rack-0.9.1/lib/rack/handler/cgi.rb +57 -0
  445. data/vendor/rack-0.9.1/lib/rack/handler/evented_mongrel.rb +8 -0
  446. data/vendor/rack-0.9.1/lib/rack/handler/fastcgi.rb +86 -0
  447. data/vendor/rack-0.9.1/lib/rack/handler/lsws.rb +52 -0
  448. data/vendor/rack-0.9.1/lib/rack/handler/mongrel.rb +82 -0
  449. data/vendor/rack-0.9.1/lib/rack/handler/scgi.rb +57 -0
  450. data/vendor/rack-0.9.1/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  451. data/vendor/rack-0.9.1/lib/rack/handler/thin.rb +15 -0
  452. data/vendor/rack-0.9.1/lib/rack/handler/webrick.rb +61 -0
  453. data/vendor/rack-0.9.1/lib/rack/head.rb +19 -0
  454. data/vendor/rack-0.9.1/lib/rack/lint.rb +465 -0
  455. data/vendor/rack-0.9.1/lib/rack/lobster.rb +65 -0
  456. data/vendor/rack-0.9.1/lib/rack/methodoverride.rb +27 -0
  457. data/vendor/rack-0.9.1/lib/rack/mime.rb +204 -0
  458. data/vendor/rack-0.9.1/lib/rack/mock.rb +160 -0
  459. data/vendor/rack-0.9.1/lib/rack/recursive.rb +57 -0
  460. data/vendor/rack-0.9.1/lib/rack/reloader.rb +64 -0
  461. data/vendor/rack-0.9.1/lib/rack/request.rb +218 -0
  462. data/vendor/rack-0.9.1/lib/rack/response.rb +171 -0
  463. data/vendor/rack-0.9.1/lib/rack/session/abstract/id.rb +153 -0
  464. data/vendor/rack-0.9.1/lib/rack/session/cookie.rb +89 -0
  465. data/vendor/rack-0.9.1/lib/rack/session/memcache.rb +97 -0
  466. data/vendor/rack-0.9.1/lib/rack/session/pool.rb +73 -0
  467. data/vendor/rack-0.9.1/lib/rack/showexceptions.rb +348 -0
  468. data/vendor/rack-0.9.1/lib/rack/showstatus.rb +106 -0
  469. data/vendor/rack-0.9.1/lib/rack/static.rb +38 -0
  470. data/vendor/rack-0.9.1/lib/rack/urlmap.rb +48 -0
  471. data/vendor/rack-0.9.1/lib/rack/utils.rb +347 -0
  472. metadata +1197 -1055
  473. data/doc/cxxapi/System_8h-source.html +0 -251
  474. data/doc/cxxapi/classDirectoryMapper-members.html +0 -38
  475. data/doc/cxxapi/classDirectoryMapper.html +0 -203
  476. data/doc/cxxapi/classPassenger_1_1Thread.html +0 -100
  477. data/doc/cxxapi/classboost_1_1this__thread_1_1disable__syscall__interruption.html +0 -46
  478. data/doc/cxxapi/classboost_1_1this__thread_1_1restore__syscall__interruption-members.html +0 -33
  479. data/doc/cxxapi/classboost_1_1this__thread_1_1restore__syscall__interruption.html +0 -44
  480. data/doc/cxxapi/namespacePassenger.html +0 -208
  481. data/doc/cxxapi/namespacePassenger_1_1InterruptableCalls.html +0 -43
  482. data/doc/cxxapi/namespacemembers.html +0 -70
  483. data/doc/cxxapi/namespacemembers_func.html +0 -66
  484. data/doc/cxxapi/namespacemembers_type.html +0 -46
  485. data/doc/cxxapi/namespaces.html +0 -35
  486. data/doc/rdoc/classes/Passenger.html +0 -136
  487. data/doc/rdoc/classes/Passenger/AbstractRequestHandler.html +0 -402
  488. data/doc/rdoc/classes/Passenger/SpawnManager.html +0 -379
  489. data/doc/rdoc/classes/Passenger/Utils.html +0 -578
  490. data/ext/apache2/System.h +0 -228
  491. data/lib/passenger/platform_info.rb +0 -302
  492. data/lib/passenger/templates/app_exited_during_initialization.html.erb +0 -19
  493. data/test/stub/apache2/httpd.conf +0 -75
  494. data/test/stub/rails_apps/foobar/config/environments/test.rb +0 -22
  495. data/test/stub/rails_apps/mycook/config/environments/test.rb +0 -22
  496. data/test/stub/railsapp/config/environments/test.rb +0 -22
  497. data/test/stub/railsapp2/config/environments/test.rb +0 -22
@@ -10,7 +10,6 @@
10
10
  <ul>
11
11
  <li><a href="main.html"><span>Main&nbsp;Page</span></a></li>
12
12
  <li><a href="modules.html"><span>Modules</span></a></li>
13
- <li><a href="namespaces.html"><span>Namespaces</span></a></li>
14
13
  <li><a href="annotated.html"><span>Classes</span></a></li>
15
14
  <li class="current"><a href="files.html"><span>Files</span></a></li>
16
15
  </ul>
@@ -39,651 +38,762 @@
39
38
  <a name="l00022"></a>00022 <span class="preprocessor"></span>
40
39
  <a name="l00023"></a>00023 <span class="preprocessor">#include &lt;boost/shared_ptr.hpp&gt;</span>
41
40
  <a name="l00024"></a>00024 <span class="preprocessor">#include &lt;boost/thread/mutex.hpp&gt;</span>
42
- <a name="l00025"></a>00025
43
- <a name="l00026"></a>00026 <span class="preprocessor">#include &lt;sys/types.h&gt;</span>
44
- <a name="l00027"></a>00027 <span class="preprocessor">#include &lt;sys/stat.h&gt;</span>
45
- <a name="l00028"></a>00028 <span class="preprocessor">#include &lt;sys/wait.h&gt;</span>
46
- <a name="l00029"></a>00029 <span class="preprocessor">#include &lt;sys/socket.h&gt;</span>
47
- <a name="l00030"></a>00030 <span class="preprocessor">#include &lt;cstdio&gt;</span>
48
- <a name="l00031"></a>00031 <span class="preprocessor">#include &lt;cstdlib&gt;</span>
49
- <a name="l00032"></a>00032 <span class="preprocessor">#include &lt;limits.h&gt;</span>
50
- <a name="l00033"></a>00033 <span class="preprocessor">#include &lt;errno.h&gt;</span>
51
- <a name="l00034"></a>00034 <span class="preprocessor">#include &lt;unistd.h&gt;</span>
52
- <a name="l00035"></a>00035 <span class="preprocessor">#include &lt;signal.h&gt;</span>
53
- <a name="l00036"></a>00036 <span class="preprocessor">#include &lt;fcntl.h&gt;</span>
54
- <a name="l00037"></a>00037
55
- <a name="l00038"></a>00038 <span class="preprocessor">#include "MessageChannel.h"</span>
56
- <a name="l00039"></a>00039 <span class="preprocessor">#include "ApplicationPool.h"</span>
57
- <a name="l00040"></a>00040 <span class="preprocessor">#include "Application.h"</span>
58
- <a name="l00041"></a>00041 <span class="preprocessor">#include "Exceptions.h"</span>
59
- <a name="l00042"></a>00042 <span class="preprocessor">#include "Logging.h"</span>
60
- <a name="l00043"></a>00043 <span class="preprocessor">#include "System.h"</span>
61
- <a name="l00044"></a>00044
62
- <a name="l00045"></a>00045 <span class="keyword">namespace </span>Passenger {
63
- <a name="l00046"></a>00046
64
- <a name="l00047"></a>00047 <span class="keyword">using namespace </span>std;
65
- <a name="l00048"></a>00048 <span class="keyword">using namespace </span>boost;
66
- <a name="l00049"></a>00049
67
- <a name="l00050"></a>00050 <span class="comment"></span>
68
- <a name="l00051"></a>00051 <span class="comment">/**</span>
69
- <a name="l00052"></a>00052 <span class="comment"> * Multi-process usage support for ApplicationPool.</span>
70
- <a name="l00053"></a>00053 <span class="comment"> *</span>
71
- <a name="l00054"></a>00054 <span class="comment"> * ApplicationPoolServer implements a client/server architecture for ApplicationPool.</span>
72
- <a name="l00055"></a>00055 <span class="comment"> * This allows one to use ApplicationPool in a multi-process environment (unlike</span>
73
- <a name="l00056"></a>00056 <span class="comment"> * StandardApplicationPool). The cache/pool data is stored in the server. Different</span>
74
- <a name="l00057"></a>00057 <span class="comment"> * processes can then access the pool through the server.</span>
75
- <a name="l00058"></a>00058 <span class="comment"> *</span>
76
- <a name="l00059"></a>00059 <span class="comment"> * ApplicationPoolServer itself does not inherit ApplicationPool. Instead, it returns</span>
77
- <a name="l00060"></a>00060 <span class="comment"> * an ApplicationPool object via the connect() call. For example:</span>
78
- <a name="l00061"></a>00061 <span class="comment"> * @code</span>
79
- <a name="l00062"></a>00062 <span class="comment"> * // Create an ApplicationPoolServer.</span>
80
- <a name="l00063"></a>00063 <span class="comment"> * ApplicationPoolServer server(...);</span>
81
- <a name="l00064"></a>00064 <span class="comment"> * </span>
82
- <a name="l00065"></a>00065 <span class="comment"> * // Now fork a child process, like Apache's prefork MPM eventually will.</span>
83
- <a name="l00066"></a>00066 <span class="comment"> * pid_t pid = fork();</span>
84
- <a name="l00067"></a>00067 <span class="comment"> * if (pid == 0) {</span>
85
- <a name="l00068"></a>00068 <span class="comment"> * // Child process</span>
86
- <a name="l00069"></a>00069 <span class="comment"> * </span>
87
- <a name="l00070"></a>00070 <span class="comment"> * // Connect to the server. After connection, we have an ApplicationPool</span>
88
- <a name="l00071"></a>00071 <span class="comment"> * // object!</span>
89
- <a name="l00072"></a>00072 <span class="comment"> * ApplicationPoolPtr pool(server.connect());</span>
90
- <a name="l00073"></a>00073 <span class="comment"> *</span>
91
- <a name="l00074"></a>00074 <span class="comment"> * // We don't need to connect to the server anymore, so we detach from it.</span>
92
- <a name="l00075"></a>00075 <span class="comment"> * // This frees up some resources, such as file descriptors.</span>
93
- <a name="l00076"></a>00076 <span class="comment"> * server.detach();</span>
94
- <a name="l00077"></a>00077 <span class="comment"> *</span>
95
- <a name="l00078"></a>00078 <span class="comment"> * ApplicationPool::SessionPtr session(pool-&gt;get("/home/webapps/foo"));</span>
96
- <a name="l00079"></a>00079 <span class="comment"> * do_something_with(session);</span>
97
- <a name="l00080"></a>00080 <span class="comment"> *</span>
98
- <a name="l00081"></a>00081 <span class="comment"> * _exit(0);</span>
99
- <a name="l00082"></a>00082 <span class="comment"> * } else {</span>
100
- <a name="l00083"></a>00083 <span class="comment"> * // Parent process</span>
101
- <a name="l00084"></a>00084 <span class="comment"> * waitpid(pid, NULL, 0);</span>
102
- <a name="l00085"></a>00085 <span class="comment"> * }</span>
103
- <a name="l00086"></a>00086 <span class="comment"> * @endcode</span>
104
- <a name="l00087"></a>00087 <span class="comment"> *</span>
105
- <a name="l00088"></a>00088 <span class="comment"> * &lt;h2&gt;Implementation notes&lt;/h2&gt;</span>
41
+ <a name="l00025"></a>00025 <span class="preprocessor">#include &lt;oxt/system_calls.hpp&gt;</span>
42
+ <a name="l00026"></a>00026 <span class="preprocessor">#include &lt;oxt/backtrace.hpp&gt;</span>
43
+ <a name="l00027"></a>00027
44
+ <a name="l00028"></a>00028 <span class="preprocessor">#include &lt;sys/types.h&gt;</span>
45
+ <a name="l00029"></a>00029 <span class="preprocessor">#include &lt;sys/stat.h&gt;</span>
46
+ <a name="l00030"></a>00030 <span class="preprocessor">#include &lt;sys/wait.h&gt;</span>
47
+ <a name="l00031"></a>00031 <span class="preprocessor">#include &lt;sys/socket.h&gt;</span>
48
+ <a name="l00032"></a>00032 <span class="preprocessor">#include &lt;cstdio&gt;</span>
49
+ <a name="l00033"></a>00033 <span class="preprocessor">#include &lt;cstdlib&gt;</span>
50
+ <a name="l00034"></a>00034 <span class="preprocessor">#include &lt;limits.h&gt;</span>
51
+ <a name="l00035"></a>00035 <span class="preprocessor">#include &lt;errno.h&gt;</span>
52
+ <a name="l00036"></a>00036 <span class="preprocessor">#include &lt;unistd.h&gt;</span>
53
+ <a name="l00037"></a>00037 <span class="preprocessor">#include &lt;signal.h&gt;</span>
54
+ <a name="l00038"></a>00038 <span class="preprocessor">#include &lt;fcntl.h&gt;</span>
55
+ <a name="l00039"></a>00039
56
+ <a name="l00040"></a>00040 <span class="preprocessor">#include "MessageChannel.h"</span>
57
+ <a name="l00041"></a>00041 <span class="preprocessor">#include "ApplicationPool.h"</span>
58
+ <a name="l00042"></a>00042 <span class="preprocessor">#include "Application.h"</span>
59
+ <a name="l00043"></a>00043 <span class="preprocessor">#include "Exceptions.h"</span>
60
+ <a name="l00044"></a>00044 <span class="preprocessor">#include "Logging.h"</span>
61
+ <a name="l00045"></a>00045
62
+ <a name="l00046"></a>00046 <span class="keyword">namespace </span>Passenger {
63
+ <a name="l00047"></a>00047
64
+ <a name="l00048"></a>00048 <span class="keyword">using namespace </span>std;
65
+ <a name="l00049"></a>00049 <span class="keyword">using namespace </span>boost;
66
+ <a name="l00050"></a>00050 <span class="keyword">using namespace </span>oxt;
67
+ <a name="l00051"></a>00051
68
+ <a name="l00052"></a>00052 <span class="comment"></span>
69
+ <a name="l00053"></a>00053 <span class="comment">/**</span>
70
+ <a name="l00054"></a>00054 <span class="comment"> * Multi-process usage support for ApplicationPool.</span>
71
+ <a name="l00055"></a>00055 <span class="comment"> *</span>
72
+ <a name="l00056"></a>00056 <span class="comment"> * ApplicationPoolServer implements a client/server architecture for ApplicationPool.</span>
73
+ <a name="l00057"></a>00057 <span class="comment"> * This allows one to use ApplicationPool in a multi-process environment (unlike</span>
74
+ <a name="l00058"></a>00058 <span class="comment"> * StandardApplicationPool). The cache/pool data is stored in the server. Different</span>
75
+ <a name="l00059"></a>00059 <span class="comment"> * processes can then access the pool through the server.</span>
76
+ <a name="l00060"></a>00060 <span class="comment"> *</span>
77
+ <a name="l00061"></a>00061 <span class="comment"> * ApplicationPoolServer itself does not inherit ApplicationPool. Instead, it returns</span>
78
+ <a name="l00062"></a>00062 <span class="comment"> * an ApplicationPool object via the connect() call. For example:</span>
79
+ <a name="l00063"></a>00063 <span class="comment"> * @code</span>
80
+ <a name="l00064"></a>00064 <span class="comment"> * // Create an ApplicationPoolServer.</span>
81
+ <a name="l00065"></a>00065 <span class="comment"> * ApplicationPoolServer server(...);</span>
82
+ <a name="l00066"></a>00066 <span class="comment"> * </span>
83
+ <a name="l00067"></a>00067 <span class="comment"> * // Now fork a child process, like Apache's prefork MPM eventually will.</span>
84
+ <a name="l00068"></a>00068 <span class="comment"> * pid_t pid = fork();</span>
85
+ <a name="l00069"></a>00069 <span class="comment"> * if (pid == 0) {</span>
86
+ <a name="l00070"></a>00070 <span class="comment"> * // Child process</span>
87
+ <a name="l00071"></a>00071 <span class="comment"> * </span>
88
+ <a name="l00072"></a>00072 <span class="comment"> * // Connect to the server. After connection, we have an ApplicationPool</span>
89
+ <a name="l00073"></a>00073 <span class="comment"> * // object!</span>
90
+ <a name="l00074"></a>00074 <span class="comment"> * ApplicationPoolPtr pool(server.connect());</span>
91
+ <a name="l00075"></a>00075 <span class="comment"> *</span>
92
+ <a name="l00076"></a>00076 <span class="comment"> * // We don't need to connect to the server anymore, so we detach from it.</span>
93
+ <a name="l00077"></a>00077 <span class="comment"> * // This frees up some resources, such as file descriptors.</span>
94
+ <a name="l00078"></a>00078 <span class="comment"> * server.detach();</span>
95
+ <a name="l00079"></a>00079 <span class="comment"> *</span>
96
+ <a name="l00080"></a>00080 <span class="comment"> * ApplicationPool::SessionPtr session(pool-&gt;get("/home/webapps/foo"));</span>
97
+ <a name="l00081"></a>00081 <span class="comment"> * do_something_with(session);</span>
98
+ <a name="l00082"></a>00082 <span class="comment"> *</span>
99
+ <a name="l00083"></a>00083 <span class="comment"> * _exit(0);</span>
100
+ <a name="l00084"></a>00084 <span class="comment"> * } else {</span>
101
+ <a name="l00085"></a>00085 <span class="comment"> * // Parent process</span>
102
+ <a name="l00086"></a>00086 <span class="comment"> * waitpid(pid, NULL, 0);</span>
103
+ <a name="l00087"></a>00087 <span class="comment"> * }</span>
104
+ <a name="l00088"></a>00088 <span class="comment"> * @endcode</span>
106
105
  <a name="l00089"></a>00089 <span class="comment"> *</span>
107
- <a name="l00090"></a>00090 <span class="comment"> * &lt;h3&gt;Separate server executable&lt;/h3&gt;</span>
108
- <a name="l00091"></a>00091 <span class="comment"> * The actual server is implemented in ApplicationPoolServerExecutable.cpp, this class is</span>
109
- <a name="l00092"></a>00092 <span class="comment"> * just a convenience class for starting/stopping the server executable and connecting</span>
110
- <a name="l00093"></a>00093 <span class="comment"> * to it.</span>
111
- <a name="l00094"></a>00094 <span class="comment"> *</span>
112
- <a name="l00095"></a>00095 <span class="comment"> * In the past, the server logic itself was implemented in this class. This implies that</span>
113
- <a name="l00096"></a>00096 <span class="comment"> * the ApplicationPool server ran inside the Apache process. This presented us with several</span>
114
- <a name="l00097"></a>00097 <span class="comment"> * problems:</span>
115
- <a name="l00098"></a>00098 <span class="comment"> * - Because of the usage of threads in the ApplicationPool server, the Apache VM size would</span>
116
- <a name="l00099"></a>00099 <span class="comment"> * go way up. This gave people the (wrong) impression that Passenger uses a lot of memory,</span>
117
- <a name="l00100"></a>00100 <span class="comment"> * or that it leaks memory.</span>
118
- <a name="l00101"></a>00101 <span class="comment"> * - Although it's not entirely confirmed, we suspect that it caused heap fragmentation as</span>
119
- <a name="l00102"></a>00102 <span class="comment"> * well. Apache allocates lots and lots of small objects on the heap, and ApplicationPool</span>
120
- <a name="l00103"></a>00103 <span class="comment"> * server isn't exactly helping. This too gave people the (wrong) impression that</span>
121
- <a name="l00104"></a>00104 <span class="comment"> * Passenger leaks memory.</span>
122
- <a name="l00105"></a>00105 <span class="comment"> * - It would unnecessarily bloat the VM size of Apache worker processes.</span>
123
- <a name="l00106"></a>00106 <span class="comment"> * - We had to resort to all kinds of tricks to make sure that fork()ing a process doesn't</span>
124
- <a name="l00107"></a>00107 <span class="comment"> * result in file descriptor leaks.</span>
125
- <a name="l00108"></a>00108 <span class="comment"> * - Despite everything, there was still a small chance that file descriptor leaks would</span>
126
- <a name="l00109"></a>00109 <span class="comment"> * occur, and this could not be fixed. The reason for this is that the Apache control</span>
127
- <a name="l00110"></a>00110 <span class="comment"> * process may call fork() right after the ApplicationPool server has established a new</span>
128
- <a name="l00111"></a>00111 <span class="comment"> * connection with a client.</span>
129
- <a name="l00112"></a>00112 <span class="comment"> *</span>
130
- <a name="l00113"></a>00113 <span class="comment"> * Because of these problems, it was decided to split the ApplicationPool server to a</span>
131
- <a name="l00114"></a>00114 <span class="comment"> * separate executable. This comes with no performance hit.</span>
132
- <a name="l00115"></a>00115 <span class="comment"> *</span>
133
- <a name="l00116"></a>00116 <span class="comment"> * &lt;h3&gt;Anonymous server socket&lt;/h3&gt;</span>
134
- <a name="l00117"></a>00117 <span class="comment"> * Notice that ApplicationPoolServer does do not use TCP sockets at all, or even named Unix</span>
135
- <a name="l00118"></a>00118 <span class="comment"> * sockets, despite being a server that can handle multiple clients! So ApplicationPoolServer</span>
136
- <a name="l00119"></a>00119 <span class="comment"> * will expose no open ports or temporary Unix socket files. Only child processes are able</span>
137
- <a name="l00120"></a>00120 <span class="comment"> * to use the ApplicationPoolServer.</span>
138
- <a name="l00121"></a>00121 <span class="comment"> *</span>
139
- <a name="l00122"></a>00122 <span class="comment"> * This is implemented through anonymous Unix sockets (&lt;tt&gt;socketpair()&lt;/tt&gt;) and file descriptor</span>
140
- <a name="l00123"></a>00123 <span class="comment"> * passing. It allows one to emulate &lt;tt&gt;accept()&lt;/tt&gt;. ApplicationPoolServer is connected to</span>
141
- <a name="l00124"></a>00124 <span class="comment"> * the server executable through a Unix socket pair. connect() sends a connect request to the</span>
142
- <a name="l00125"></a>00125 <span class="comment"> * server through that socket. The server will then create a new socket pair, and pass one of</span>
143
- <a name="l00126"></a>00126 <span class="comment"> * them back. This new socket pair represents the newly established connection.</span>
144
- <a name="l00127"></a>00127 <span class="comment"> *</span>
145
- <a name="l00128"></a>00128 <span class="comment"> * @ingroup Support</span>
146
- <a name="l00129"></a>00129 <span class="comment"> */</span>
147
- <a name="l00130"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html">00130</a> <span class="keyword">class </span><a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a> {
148
- <a name="l00131"></a>00131 <span class="keyword">private</span>:<span class="comment"></span>
149
- <a name="l00132"></a>00132 <span class="comment"> /**</span>
150
- <a name="l00133"></a>00133 <span class="comment"> * Contains data shared between RemoteSession and Client.</span>
151
- <a name="l00134"></a>00134 <span class="comment"> * Since RemoteSession and Client have different life times, i.e. one may be</span>
152
- <a name="l00135"></a>00135 <span class="comment"> * destroyed before the other, they both use a smart pointer that points to</span>
153
- <a name="l00136"></a>00136 <span class="comment"> * a SharedData. This way, the SharedData object is only destroyed when</span>
154
- <a name="l00137"></a>00137 <span class="comment"> * both the RemoteSession and the Client object has been destroyed.</span>
155
- <a name="l00138"></a>00138 <span class="comment"> */</span>
156
- <a name="l00139"></a>00139 <span class="keyword">struct </span>SharedData {<span class="comment"></span>
157
- <a name="l00140"></a>00140 <span class="comment"> /**</span>
158
- <a name="l00141"></a>00141 <span class="comment"> * The socket connection to the ApplicationPool server, as was</span>
159
- <a name="l00142"></a>00142 <span class="comment"> * established by ApplicationPoolServer::connect().</span>
160
- <a name="l00143"></a>00143 <span class="comment"> */</span>
161
- <a name="l00144"></a>00144 <span class="keywordtype">int</span> server;
162
- <a name="l00145"></a>00145
163
- <a name="l00146"></a>00146 mutex lock;
164
- <a name="l00147"></a>00147
165
- <a name="l00148"></a>00148 ~SharedData() {
166
- <a name="l00149"></a>00149 <span class="keywordtype">int</span> ret;
167
- <a name="l00150"></a>00150 <span class="keywordflow">do</span> {
168
- <a name="l00151"></a>00151 ret = close(server);
169
- <a name="l00152"></a>00152 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
170
- <a name="l00153"></a>00153 }
171
- <a name="l00154"></a>00154 };
172
- <a name="l00155"></a>00155
173
- <a name="l00156"></a>00156 <span class="keyword">typedef</span> shared_ptr&lt;SharedData&gt; SharedDataPtr;
174
- <a name="l00157"></a>00157 <span class="comment"></span>
175
- <a name="l00158"></a>00158 <span class="comment"> /**</span>
176
- <a name="l00159"></a>00159 <span class="comment"> * An Application::Session which works together with ApplicationPoolServer.</span>
177
- <a name="l00160"></a>00160 <span class="comment"> */</span>
178
- <a name="l00161"></a>00161 <span class="keyword">class </span>RemoteSession: <span class="keyword">public</span> <a class="code" href="classPassenger_1_1Application.html" title="Represents a single Ruby on Rails or Rack application instance.">Application</a>::Session {
179
- <a name="l00162"></a>00162 <span class="keyword">private</span>:
180
- <a name="l00163"></a>00163 SharedDataPtr data;
181
- <a name="l00164"></a>00164 <span class="keywordtype">int</span> id;
182
- <a name="l00165"></a>00165 <span class="keywordtype">int</span> fd;
183
- <a name="l00166"></a>00166 pid_t pid;
184
- <a name="l00167"></a>00167 <span class="keyword">public</span>:
185
- <a name="l00168"></a>00168 RemoteSession(SharedDataPtr data, pid_t pid, <span class="keywordtype">int</span> <span class="keywordtype">id</span>, <span class="keywordtype">int</span> fd) {
186
- <a name="l00169"></a>00169 this-&gt;data = data;
187
- <a name="l00170"></a>00170 this-&gt;pid = pid;
188
- <a name="l00171"></a>00171 this-&gt;<span class="keywordtype">id</span> = id;
189
- <a name="l00172"></a>00172 this-&gt;fd = fd;
190
- <a name="l00173"></a>00173 }
191
- <a name="l00174"></a>00174
192
- <a name="l00175"></a>00175 <span class="keyword">virtual</span> ~RemoteSession() {
193
- <a name="l00176"></a>00176 closeStream();
194
- <a name="l00177"></a>00177 mutex::scoped_lock(data-&gt;lock);
195
- <a name="l00178"></a>00178 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a>(data-&gt;server).write(<span class="stringliteral">"close"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(<span class="keywordtype">id</span>).c_str(), NULL);
196
- <a name="l00179"></a>00179 }
197
- <a name="l00180"></a>00180
198
- <a name="l00181"></a>00181 <span class="keyword">virtual</span> <span class="keywordtype">int</span> getStream()<span class="keyword"> const </span>{
199
- <a name="l00182"></a>00182 <span class="keywordflow">return</span> fd;
200
- <a name="l00183"></a>00183 }
201
- <a name="l00184"></a>00184
202
- <a name="l00185"></a>00185 <span class="keyword">virtual</span> <span class="keywordtype">void</span> shutdownReader() {
203
- <a name="l00186"></a>00186 <span class="keywordflow">if</span> (fd != -1) {
204
- <a name="l00187"></a>00187 <span class="keywordtype">int</span> ret = InterruptableCalls::shutdown(fd, SHUT_RD);
205
- <a name="l00188"></a>00188 <span class="keywordflow">if</span> (ret == -1) {
206
- <a name="l00189"></a>00189 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot shutdown the writer stream"</span>,
207
- <a name="l00190"></a>00190 errno);
208
- <a name="l00191"></a>00191 }
209
- <a name="l00192"></a>00192 }
210
- <a name="l00193"></a>00193 }
211
- <a name="l00194"></a>00194
212
- <a name="l00195"></a>00195 <span class="keyword">virtual</span> <span class="keywordtype">void</span> shutdownWriter() {
213
- <a name="l00196"></a>00196 <span class="keywordflow">if</span> (fd != -1) {
214
- <a name="l00197"></a>00197 <span class="keywordtype">int</span> ret = InterruptableCalls::shutdown(fd, SHUT_WR);
215
- <a name="l00198"></a>00198 <span class="keywordflow">if</span> (ret == -1) {
216
- <a name="l00199"></a>00199 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot shutdown the writer stream"</span>,
217
- <a name="l00200"></a>00200 errno);
218
- <a name="l00201"></a>00201 }
219
- <a name="l00202"></a>00202 }
220
- <a name="l00203"></a>00203 }
221
- <a name="l00204"></a>00204
222
- <a name="l00205"></a>00205 <span class="keyword">virtual</span> <span class="keywordtype">void</span> closeStream() {
223
- <a name="l00206"></a>00206 <span class="keywordflow">if</span> (fd != -1) {
224
- <a name="l00207"></a>00207 <span class="keywordtype">int</span> ret = InterruptableCalls::close(fd);
225
- <a name="l00208"></a>00208 <span class="keywordflow">if</span> (ret == -1) {
226
- <a name="l00209"></a>00209 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot close the session stream"</span>,
227
- <a name="l00210"></a>00210 errno);
228
- <a name="l00211"></a>00211 }
229
- <a name="l00212"></a>00212 fd = -1;
230
- <a name="l00213"></a>00213 }
231
- <a name="l00214"></a>00214 }
232
- <a name="l00215"></a>00215
233
- <a name="l00216"></a>00216 <span class="keyword">virtual</span> <span class="keywordtype">void</span> discardStream() {
234
- <a name="l00217"></a>00217 fd = -1;
106
+ <a name="l00090"></a>00090 <span class="comment"> * &lt;h2&gt;Implementation notes&lt;/h2&gt;</span>
107
+ <a name="l00091"></a>00091 <span class="comment"> *</span>
108
+ <a name="l00092"></a>00092 <span class="comment"> * &lt;h3&gt;Separate server executable&lt;/h3&gt;</span>
109
+ <a name="l00093"></a>00093 <span class="comment"> * The actual server is implemented in ApplicationPoolServerExecutable.cpp, this class is</span>
110
+ <a name="l00094"></a>00094 <span class="comment"> * just a convenience class for starting/stopping the server executable and connecting</span>
111
+ <a name="l00095"></a>00095 <span class="comment"> * to it.</span>
112
+ <a name="l00096"></a>00096 <span class="comment"> *</span>
113
+ <a name="l00097"></a>00097 <span class="comment"> * In the past, the server logic itself was implemented in this class. This implies that</span>
114
+ <a name="l00098"></a>00098 <span class="comment"> * the ApplicationPool server ran inside the Apache process. This presented us with several</span>
115
+ <a name="l00099"></a>00099 <span class="comment"> * problems:</span>
116
+ <a name="l00100"></a>00100 <span class="comment"> * - Because of the usage of threads in the ApplicationPool server, the Apache VM size would</span>
117
+ <a name="l00101"></a>00101 <span class="comment"> * go way up. This gave people the (wrong) impression that Passenger uses a lot of memory,</span>
118
+ <a name="l00102"></a>00102 <span class="comment"> * or that it leaks memory.</span>
119
+ <a name="l00103"></a>00103 <span class="comment"> * - Although it's not entirely confirmed, we suspect that it caused heap fragmentation as</span>
120
+ <a name="l00104"></a>00104 <span class="comment"> * well. Apache allocates lots and lots of small objects on the heap, and ApplicationPool</span>
121
+ <a name="l00105"></a>00105 <span class="comment"> * server isn't exactly helping. This too gave people the (wrong) impression that</span>
122
+ <a name="l00106"></a>00106 <span class="comment"> * Passenger leaks memory.</span>
123
+ <a name="l00107"></a>00107 <span class="comment"> * - It would unnecessarily bloat the VM size of Apache worker processes.</span>
124
+ <a name="l00108"></a>00108 <span class="comment"> * - We had to resort to all kinds of tricks to make sure that fork()ing a process doesn't</span>
125
+ <a name="l00109"></a>00109 <span class="comment"> * result in file descriptor leaks.</span>
126
+ <a name="l00110"></a>00110 <span class="comment"> * - Despite everything, there was still a small chance that file descriptor leaks would</span>
127
+ <a name="l00111"></a>00111 <span class="comment"> * occur, and this could not be fixed. The reason for this is that the Apache control</span>
128
+ <a name="l00112"></a>00112 <span class="comment"> * process may call fork() right after the ApplicationPool server has established a new</span>
129
+ <a name="l00113"></a>00113 <span class="comment"> * connection with a client.</span>
130
+ <a name="l00114"></a>00114 <span class="comment"> *</span>
131
+ <a name="l00115"></a>00115 <span class="comment"> * Because of these problems, it was decided to split the ApplicationPool server to a</span>
132
+ <a name="l00116"></a>00116 <span class="comment"> * separate executable. This comes with no performance hit.</span>
133
+ <a name="l00117"></a>00117 <span class="comment"> *</span>
134
+ <a name="l00118"></a>00118 <span class="comment"> * &lt;h3&gt;Anonymous server socket&lt;/h3&gt;</span>
135
+ <a name="l00119"></a>00119 <span class="comment"> * Notice that ApplicationPoolServer does do not use TCP sockets at all, or even named Unix</span>
136
+ <a name="l00120"></a>00120 <span class="comment"> * sockets, despite being a server that can handle multiple clients! So ApplicationPoolServer</span>
137
+ <a name="l00121"></a>00121 <span class="comment"> * will expose no open ports or temporary Unix socket files. Only child processes are able</span>
138
+ <a name="l00122"></a>00122 <span class="comment"> * to use the ApplicationPoolServer.</span>
139
+ <a name="l00123"></a>00123 <span class="comment"> *</span>
140
+ <a name="l00124"></a>00124 <span class="comment"> * This is implemented through anonymous Unix sockets (&lt;tt&gt;socketpair()&lt;/tt&gt;) and file descriptor</span>
141
+ <a name="l00125"></a>00125 <span class="comment"> * passing. It allows one to emulate &lt;tt&gt;accept()&lt;/tt&gt;. ApplicationPoolServer is connected to</span>
142
+ <a name="l00126"></a>00126 <span class="comment"> * the server executable through a Unix socket pair. connect() sends a connect request to the</span>
143
+ <a name="l00127"></a>00127 <span class="comment"> * server through that socket. The server will then create a new socket pair, and pass one of</span>
144
+ <a name="l00128"></a>00128 <span class="comment"> * them back. This new socket pair represents the newly established connection.</span>
145
+ <a name="l00129"></a>00129 <span class="comment"> *</span>
146
+ <a name="l00130"></a>00130 <span class="comment"> * @ingroup Support</span>
147
+ <a name="l00131"></a>00131 <span class="comment"> */</span>
148
+ <a name="l00132"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html">00132</a> <span class="keyword">class </span><a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a> {
149
+ <a name="l00133"></a>00133 <span class="keyword">private</span>:<span class="comment"></span>
150
+ <a name="l00134"></a>00134 <span class="comment"> /**</span>
151
+ <a name="l00135"></a>00135 <span class="comment"> * Contains data shared between RemoteSession and Client.</span>
152
+ <a name="l00136"></a>00136 <span class="comment"> * Since RemoteSession and Client have different life times, i.e. one may be</span>
153
+ <a name="l00137"></a>00137 <span class="comment"> * destroyed before the other, they both use a smart pointer that points to</span>
154
+ <a name="l00138"></a>00138 <span class="comment"> * a SharedData. This way, the SharedData object is only destroyed when</span>
155
+ <a name="l00139"></a>00139 <span class="comment"> * both the RemoteSession and the Client object has been destroyed.</span>
156
+ <a name="l00140"></a>00140 <span class="comment"> */</span>
157
+ <a name="l00141"></a>00141 <span class="keyword">struct </span>SharedData {<span class="comment"></span>
158
+ <a name="l00142"></a>00142 <span class="comment"> /**</span>
159
+ <a name="l00143"></a>00143 <span class="comment"> * The socket connection to the ApplicationPool server, as was</span>
160
+ <a name="l00144"></a>00144 <span class="comment"> * established by ApplicationPoolServer::connect().</span>
161
+ <a name="l00145"></a>00145 <span class="comment"> *</span>
162
+ <a name="l00146"></a>00146 <span class="comment"> * The value may be -1, which indicates that the connection has</span>
163
+ <a name="l00147"></a>00147 <span class="comment"> * been closed.</span>
164
+ <a name="l00148"></a>00148 <span class="comment"> */</span>
165
+ <a name="l00149"></a>00149 <span class="keywordtype">int</span> server;
166
+ <a name="l00150"></a>00150
167
+ <a name="l00151"></a>00151 <span class="keyword">mutable</span> boost::mutex lock;
168
+ <a name="l00152"></a>00152
169
+ <a name="l00153"></a>00153 ~SharedData() {
170
+ <a name="l00154"></a>00154 TRACE_POINT();
171
+ <a name="l00155"></a>00155 <span class="keywordflow">if</span> (server != -1) {
172
+ <a name="l00156"></a>00156 disconnect();
173
+ <a name="l00157"></a>00157 }
174
+ <a name="l00158"></a>00158 }
175
+ <a name="l00159"></a>00159 <span class="comment"></span>
176
+ <a name="l00160"></a>00160 <span class="comment"> /**</span>
177
+ <a name="l00161"></a>00161 <span class="comment"> * Disconnect from the ApplicationPool server.</span>
178
+ <a name="l00162"></a>00162 <span class="comment"> */</span>
179
+ <a name="l00163"></a>00163 <span class="keywordtype">void</span> disconnect() {
180
+ <a name="l00164"></a>00164 TRACE_POINT();
181
+ <a name="l00165"></a>00165 <span class="keywordtype">int</span> ret;
182
+ <a name="l00166"></a>00166 <span class="keywordflow">do</span> {
183
+ <a name="l00167"></a>00167 ret = close(server);
184
+ <a name="l00168"></a>00168 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
185
+ <a name="l00169"></a>00169 server = -1;
186
+ <a name="l00170"></a>00170 }
187
+ <a name="l00171"></a>00171 };
188
+ <a name="l00172"></a>00172
189
+ <a name="l00173"></a>00173 <span class="keyword">typedef</span> shared_ptr&lt;SharedData&gt; SharedDataPtr;
190
+ <a name="l00174"></a>00174 <span class="comment"></span>
191
+ <a name="l00175"></a>00175 <span class="comment"> /**</span>
192
+ <a name="l00176"></a>00176 <span class="comment"> * An Application::Session which works together with ApplicationPoolServer.</span>
193
+ <a name="l00177"></a>00177 <span class="comment"> */</span>
194
+ <a name="l00178"></a>00178 <span class="keyword">class </span>RemoteSession: <span class="keyword">public</span> <a class="code" href="classPassenger_1_1Application.html" title="Represents a single Ruby on Rails or Rack application instance.">Application</a>::Session {
195
+ <a name="l00179"></a>00179 <span class="keyword">private</span>:
196
+ <a name="l00180"></a>00180 SharedDataPtr data;
197
+ <a name="l00181"></a>00181 <span class="keywordtype">int</span> id;
198
+ <a name="l00182"></a>00182 <span class="keywordtype">int</span> fd;
199
+ <a name="l00183"></a>00183 pid_t pid;
200
+ <a name="l00184"></a>00184 <span class="keyword">public</span>:
201
+ <a name="l00185"></a>00185 RemoteSession(SharedDataPtr data, pid_t pid, <span class="keywordtype">int</span> <span class="keywordtype">id</span>, <span class="keywordtype">int</span> fd) {
202
+ <a name="l00186"></a>00186 this-&gt;data = data;
203
+ <a name="l00187"></a>00187 this-&gt;pid = pid;
204
+ <a name="l00188"></a>00188 this-&gt;<span class="keywordtype">id</span> = id;
205
+ <a name="l00189"></a>00189 this-&gt;fd = fd;
206
+ <a name="l00190"></a>00190 }
207
+ <a name="l00191"></a>00191
208
+ <a name="l00192"></a>00192 <span class="keyword">virtual</span> ~RemoteSession() {
209
+ <a name="l00193"></a>00193 closeStream();
210
+ <a name="l00194"></a>00194 boost::mutex::scoped_lock(data-&gt;lock);
211
+ <a name="l00195"></a>00195 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a>(data-&gt;server).write(<span class="stringliteral">"close"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(<span class="keywordtype">id</span>).c_str(), NULL);
212
+ <a name="l00196"></a>00196 }
213
+ <a name="l00197"></a>00197
214
+ <a name="l00198"></a>00198 <span class="keyword">virtual</span> <span class="keywordtype">int</span> getStream()<span class="keyword"> const </span>{
215
+ <a name="l00199"></a>00199 <span class="keywordflow">return</span> fd;
216
+ <a name="l00200"></a>00200 }
217
+ <a name="l00201"></a>00201
218
+ <a name="l00202"></a>00202 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setReaderTimeout(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> msec) {
219
+ <a name="l00203"></a>00203 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a>(fd).setReadTimeout(msec);
220
+ <a name="l00204"></a>00204 }
221
+ <a name="l00205"></a>00205
222
+ <a name="l00206"></a>00206 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setWriterTimeout(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> msec) {
223
+ <a name="l00207"></a>00207 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a>(fd).setWriteTimeout(msec);
224
+ <a name="l00208"></a>00208 }
225
+ <a name="l00209"></a>00209
226
+ <a name="l00210"></a>00210 <span class="keyword">virtual</span> <span class="keywordtype">void</span> shutdownReader() {
227
+ <a name="l00211"></a>00211 <span class="keywordflow">if</span> (fd != -1) {
228
+ <a name="l00212"></a>00212 <span class="keywordtype">int</span> ret = syscalls::shutdown(fd, SHUT_RD);
229
+ <a name="l00213"></a>00213 <span class="keywordflow">if</span> (ret == -1) {
230
+ <a name="l00214"></a>00214 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot shutdown the writer stream"</span>,
231
+ <a name="l00215"></a>00215 errno);
232
+ <a name="l00216"></a>00216 }
233
+ <a name="l00217"></a>00217 }
235
234
  <a name="l00218"></a>00218 }
236
235
  <a name="l00219"></a>00219
237
- <a name="l00220"></a>00220 <span class="keyword">virtual</span> pid_t getPid()<span class="keyword"> const </span>{
238
- <a name="l00221"></a>00221 <span class="keywordflow">return</span> pid;
239
- <a name="l00222"></a>00222 }
240
- <a name="l00223"></a>00223 };
241
- <a name="l00224"></a>00224 <span class="comment"></span>
242
- <a name="l00225"></a>00225 <span class="comment"> /**</span>
243
- <a name="l00226"></a>00226 <span class="comment"> * An ApplicationPool implementation that works together with ApplicationPoolServer.</span>
244
- <a name="l00227"></a>00227 <span class="comment"> * It doesn't do much by itself, its job is mostly to forward queries/commands to</span>
245
- <a name="l00228"></a>00228 <span class="comment"> * the server and returning the result. Most of the logic is in the server executable.</span>
246
- <a name="l00229"></a>00229 <span class="comment"> */</span>
247
- <a name="l00230"></a>00230 <span class="keyword">class </span><a class="code" href="classClient.html#e625bb32c95bde75bfa4bdfdb8ee56db" title="Create a new Client object.">Client</a>: <span class="keyword">public</span> <a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a> {
248
- <a name="l00231"></a>00231 <span class="keyword">private</span>:
249
- <a name="l00232"></a>00232 <span class="comment">// The smart pointer only serves to keep the shared data alive.</span>
250
- <a name="l00233"></a>00233 <span class="comment">// We access the shared data via a normal pointer, for performance.</span>
251
- <a name="l00234"></a>00234 SharedDataPtr dataSmartPointer;
252
- <a name="l00235"></a>00235 SharedData *data;
253
- <a name="l00236"></a>00236
254
- <a name="l00237"></a>00237 <span class="keyword">public</span>:<span class="comment"></span>
255
- <a name="l00238"></a>00238 <span class="comment"> /**</span>
256
- <a name="l00239"></a>00239 <span class="comment"> * Create a new Client.</span>
257
- <a name="l00240"></a>00240 <span class="comment"> *</span>
258
- <a name="l00241"></a>00241 <span class="comment"> * @param sock The newly established socket connection with the ApplicationPoolServer.</span>
259
- <a name="l00242"></a>00242 <span class="comment"> */</span>
260
- <a name="l00243"></a>00243 Client(<span class="keywordtype">int</span> sock) {
261
- <a name="l00244"></a>00244 dataSmartPointer = <a class="code" href="group__Support.html#g41b6c4a82fed72531a147de0505a8396" title="Convenience shortcut for creating a shared_ptr.">ptr</a>(<span class="keyword">new</span> SharedData());
262
- <a name="l00245"></a>00245 data = dataSmartPointer.get();
263
- <a name="l00246"></a>00246 data-&gt;server = sock;
236
+ <a name="l00220"></a>00220 <span class="keyword">virtual</span> <span class="keywordtype">void</span> shutdownWriter() {
237
+ <a name="l00221"></a>00221 <span class="keywordflow">if</span> (fd != -1) {
238
+ <a name="l00222"></a>00222 <span class="keywordtype">int</span> ret = syscalls::shutdown(fd, SHUT_WR);
239
+ <a name="l00223"></a>00223 <span class="keywordflow">if</span> (ret == -1) {
240
+ <a name="l00224"></a>00224 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot shutdown the writer stream"</span>,
241
+ <a name="l00225"></a>00225 errno);
242
+ <a name="l00226"></a>00226 }
243
+ <a name="l00227"></a>00227 }
244
+ <a name="l00228"></a>00228 }
245
+ <a name="l00229"></a>00229
246
+ <a name="l00230"></a>00230 <span class="keyword">virtual</span> <span class="keywordtype">void</span> closeStream() {
247
+ <a name="l00231"></a>00231 <span class="keywordflow">if</span> (fd != -1) {
248
+ <a name="l00232"></a>00232 <span class="keywordtype">int</span> ret = syscalls::close(fd);
249
+ <a name="l00233"></a>00233 <span class="keywordflow">if</span> (ret == -1) {
250
+ <a name="l00234"></a>00234 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot close the session stream"</span>,
251
+ <a name="l00235"></a>00235 errno);
252
+ <a name="l00236"></a>00236 }
253
+ <a name="l00237"></a>00237 fd = -1;
254
+ <a name="l00238"></a>00238 }
255
+ <a name="l00239"></a>00239 }
256
+ <a name="l00240"></a>00240
257
+ <a name="l00241"></a>00241 <span class="keyword">virtual</span> <span class="keywordtype">void</span> discardStream() {
258
+ <a name="l00242"></a>00242 fd = -1;
259
+ <a name="l00243"></a>00243 }
260
+ <a name="l00244"></a>00244
261
+ <a name="l00245"></a>00245 <span class="keyword">virtual</span> pid_t getPid()<span class="keyword"> const </span>{
262
+ <a name="l00246"></a>00246 <span class="keywordflow">return</span> pid;
264
263
  <a name="l00247"></a>00247 }
265
- <a name="l00248"></a>00248
266
- <a name="l00249"></a>00249 <span class="keyword">virtual</span> <span class="keywordtype">void</span> clear() {
267
- <a name="l00250"></a>00250 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
268
- <a name="l00251"></a>00251 mutex::scoped_lock l(data-&gt;lock);
269
- <a name="l00252"></a>00252 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"clear"</span>, NULL);
270
- <a name="l00253"></a>00253 }
271
- <a name="l00254"></a>00254
272
- <a name="l00255"></a>00255 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMaxIdleTime(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> seconds) {
273
- <a name="l00256"></a>00256 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
274
- <a name="l00257"></a>00257 mutex::scoped_lock l(data-&gt;lock);
275
- <a name="l00258"></a>00258 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"setMaxIdleTime"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(seconds).c_str(), NULL);
276
- <a name="l00259"></a>00259 }
277
- <a name="l00260"></a>00260
278
- <a name="l00261"></a>00261 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMax(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max) {
279
- <a name="l00262"></a>00262 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
280
- <a name="l00263"></a>00263 mutex::scoped_lock l(data-&gt;lock);
281
- <a name="l00264"></a>00264 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"setMax"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(max).c_str(), NULL);
282
- <a name="l00265"></a>00265 }
283
- <a name="l00266"></a>00266
284
- <a name="l00267"></a>00267 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> getActive()<span class="keyword"> const </span>{
285
- <a name="l00268"></a>00268 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
286
- <a name="l00269"></a>00269 mutex::scoped_lock l(data-&gt;lock);
287
- <a name="l00270"></a>00270 vector&lt;string&gt; args;
288
- <a name="l00271"></a>00271
289
- <a name="l00272"></a>00272 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"getActive"</span>, NULL);
290
- <a name="l00273"></a>00273 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Read an array message from the underlying file descriptor.">read</a>(args);
291
- <a name="l00274"></a>00274 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[0].c_str());
292
- <a name="l00275"></a>00275 }
293
- <a name="l00276"></a>00276
294
- <a name="l00277"></a>00277 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> getCount()<span class="keyword"> const </span>{
295
- <a name="l00278"></a>00278 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
296
- <a name="l00279"></a>00279 mutex::scoped_lock l(data-&gt;lock);
297
- <a name="l00280"></a>00280 vector&lt;string&gt; args;
298
- <a name="l00281"></a>00281
299
- <a name="l00282"></a>00282 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"getCount"</span>, NULL);
300
- <a name="l00283"></a>00283 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Read an array message from the underlying file descriptor.">read</a>(args);
301
- <a name="l00284"></a>00284 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[0].c_str());
302
- <a name="l00285"></a>00285 }
303
- <a name="l00286"></a>00286
304
- <a name="l00287"></a>00287 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMaxPerApp(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max) {
305
- <a name="l00288"></a>00288 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
306
- <a name="l00289"></a>00289 mutex::scoped_lock l(data-&gt;lock);
307
- <a name="l00290"></a>00290 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"setMaxPerApp"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(max).c_str(), NULL);
308
- <a name="l00291"></a>00291 }
309
- <a name="l00292"></a>00292
310
- <a name="l00293"></a>00293 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setUseGlobalQueue(<span class="keywordtype">bool</span> value) {
311
- <a name="l00294"></a>00294 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
312
- <a name="l00295"></a>00295 boost::mutex::scoped_lock l(data-&gt;lock);
313
- <a name="l00296"></a>00296 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"setUseGlobalQueue"</span>, value ? <span class="stringliteral">"true"</span> : <span class="stringliteral">"false"</span>, NULL);
314
- <a name="l00297"></a>00297 }
315
- <a name="l00298"></a>00298
316
- <a name="l00299"></a>00299 <span class="keyword">virtual</span> pid_t getSpawnServerPid()<span class="keyword"> const </span>{
317
- <a name="l00300"></a>00300 <a class="code" href="classboost_1_1this__thread_1_1disable__syscall__interruption.html" title="Create this struct on the stack to temporarily disable system call interruption,...">this_thread::disable_syscall_interruption</a> dsi;
318
- <a name="l00301"></a>00301 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
319
- <a name="l00302"></a>00302 mutex::scoped_lock l(data-&gt;lock);
320
- <a name="l00303"></a>00303 vector&lt;string&gt; args;
321
- <a name="l00304"></a>00304
322
- <a name="l00305"></a>00305 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"getSpawnServerPid"</span>, NULL);
323
- <a name="l00306"></a>00306 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Read an array message from the underlying file descriptor.">read</a>(args);
324
- <a name="l00307"></a>00307 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[0].c_str());
325
- <a name="l00308"></a>00308 }
326
- <a name="l00309"></a>00309
327
- <a name="l00310"></a>00310 <span class="keyword">virtual</span> <a class="code" href="classPassenger_1_1Application.html#d14f673494991460b16246a527ad8ad9" title="Convenient alias for Session smart pointer.">Application::SessionPtr</a> <span class="keyword">get</span>(
328
- <a name="l00311"></a>00311 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;appRoot,
329
- <a name="l00312"></a>00312 <span class="keywordtype">bool</span> lowerPrivilege = <span class="keyword">true</span>,
330
- <a name="l00313"></a>00313 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;lowestUser = <span class="stringliteral">"nobody"</span>,
331
- <a name="l00314"></a>00314 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;environment = <span class="stringliteral">"production"</span>,
332
- <a name="l00315"></a>00315 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;spawnMethod = <span class="stringliteral">"smart"</span>,
333
- <a name="l00316"></a>00316 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;appType = <span class="stringliteral">"rails"</span>
334
- <a name="l00317"></a>00317 ) {
335
- <a name="l00318"></a>00318 <a class="code" href="classboost_1_1this__thread_1_1disable__syscall__interruption.html" title="Create this struct on the stack to temporarily disable system call interruption,...">this_thread::disable_syscall_interruption</a> dsi;
336
- <a name="l00319"></a>00319 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
337
- <a name="l00320"></a>00320 mutex::scoped_lock l(data-&gt;lock);
338
- <a name="l00321"></a>00321 vector&lt;string&gt; args;
339
- <a name="l00322"></a>00322 <span class="keywordtype">int</span> stream;
340
- <a name="l00323"></a>00323 <span class="keywordtype">bool</span> result;
341
- <a name="l00324"></a>00324
342
- <a name="l00325"></a>00325 <span class="keywordflow">try</span> {
343
- <a name="l00326"></a>00326 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#9ad7a978cf8409e01ab2f0a2b6be5a0a" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"get"</span>, appRoot.c_str(),
344
- <a name="l00327"></a>00327 (lowerPrivilege) ? <span class="stringliteral">"true"</span> : <span class="stringliteral">"false"</span>,
345
- <a name="l00328"></a>00328 lowestUser.c_str(),
346
- <a name="l00329"></a>00329 environment.c_str(),
347
- <a name="l00330"></a>00330 spawnMethod.c_str(),
348
- <a name="l00331"></a>00331 appType.c_str(),
349
- <a name="l00332"></a>00332 NULL);
350
- <a name="l00333"></a>00333 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a> &amp;) {
351
- <a name="l00334"></a>00334 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(<span class="stringliteral">"The ApplicationPool server exited unexpectedly."</span>);
352
- <a name="l00335"></a>00335 }
353
- <a name="l00336"></a>00336 <span class="keywordflow">try</span> {
354
- <a name="l00337"></a>00337 result = channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Read an array message from the underlying file descriptor.">read</a>(args);
355
- <a name="l00338"></a>00338 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a> &amp;e) {
356
- <a name="l00339"></a>00339 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Could not read a message from "</span>
357
- <a name="l00340"></a>00340 <span class="stringliteral">"the ApplicationPool server"</span>, e.<a class="code" href="classPassenger_1_1SystemException.html#ee7a6672bf79b72a4c3ee70c57d6a47c" title="The value of errno at the time the error occured.">code</a>());
358
- <a name="l00341"></a>00341 }
359
- <a name="l00342"></a>00342 <span class="keywordflow">if</span> (!result) {
360
- <a name="l00343"></a>00343 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(<span class="stringliteral">"The ApplicationPool server unexpectedly "</span>
361
- <a name="l00344"></a>00344 <span class="stringliteral">"closed the connection."</span>);
362
- <a name="l00345"></a>00345 }
363
- <a name="l00346"></a>00346 <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"ok"</span>) {
364
- <a name="l00347"></a>00347 stream = channel.<a class="code" href="classPassenger_1_1MessageChannel.html#1561b7e4a0f4d39ea431f456e5655488" title="Receive a file descriptor, which had been passed over the underlying file descriptor...">readFileDescriptor</a>();
365
- <a name="l00348"></a>00348 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g41b6c4a82fed72531a147de0505a8396" title="Convenience shortcut for creating a shared_ptr.">ptr</a>(<span class="keyword">new</span> RemoteSession(dataSmartPointer,
366
- <a name="l00349"></a>00349 <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[1]), <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[2]), stream));
367
- <a name="l00350"></a>00350 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"SpawnException"</span>) {
368
- <a name="l00351"></a>00351 <span class="keywordflow">if</span> (args[2] == <span class="stringliteral">"true"</span>) {
369
- <a name="l00352"></a>00352 <span class="keywordtype">string</span> errorPage;
370
- <a name="l00353"></a>00353
371
- <a name="l00354"></a>00354 <span class="keywordflow">if</span> (!channel.<a class="code" href="classPassenger_1_1MessageChannel.html#4ce6a0e751b5e3563bee583c231569bc" title="Read a scalar message from the underlying file descriptor.">readScalar</a>(errorPage)) {
372
- <a name="l00355"></a>00355 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(<span class="stringliteral">"The ApplicationPool server "</span>
373
- <a name="l00356"></a>00356 <span class="stringliteral">"unexpectedly closed the connection."</span>);
374
- <a name="l00357"></a>00357 }
375
- <a name="l00358"></a>00358 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SpawnException.html" title="Thrown when SpawnManager or ApplicationPool fails to spawn an application instance...">SpawnException</a>(args[1], errorPage);
376
- <a name="l00359"></a>00359 } <span class="keywordflow">else</span> {
377
- <a name="l00360"></a>00360 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SpawnException.html" title="Thrown when SpawnManager or ApplicationPool fails to spawn an application instance...">SpawnException</a>(args[1]);
378
- <a name="l00361"></a>00361 }
379
- <a name="l00362"></a>00362 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"BusyException"</span>) {
380
- <a name="l00363"></a>00363 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1BusyException.html" title="The application pool is too busy and cannot fulfill a get() request.">BusyException</a>(args[1]);
381
- <a name="l00364"></a>00364 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"IOException"</span>) {
382
- <a name="l00365"></a>00365 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(args[1]);
383
- <a name="l00366"></a>00366 } <span class="keywordflow">else</span> {
384
- <a name="l00367"></a>00367 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(<span class="stringliteral">"The ApplicationPool server returned "</span>
385
- <a name="l00368"></a>00368 <span class="stringliteral">"an unknown message: "</span> + <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(args));
386
- <a name="l00369"></a>00369 }
387
- <a name="l00370"></a>00370 }
388
- <a name="l00371"></a>00371 };
389
- <a name="l00372"></a>00372
390
- <a name="l00373"></a>00373
391
- <a name="l00374"></a>00374 <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">int</span> SERVER_SOCKET_FD = 3;
392
- <a name="l00375"></a>00375
393
- <a name="l00376"></a>00376 <span class="keywordtype">string</span> m_serverExecutable;
394
- <a name="l00377"></a>00377 <span class="keywordtype">string</span> m_spawnServerCommand;
395
- <a name="l00378"></a>00378 <span class="keywordtype">string</span> m_logFile;
396
- <a name="l00379"></a>00379 <span class="keywordtype">string</span> m_rubyCommand;
397
- <a name="l00380"></a>00380 <span class="keywordtype">string</span> m_user;
398
- <a name="l00381"></a>00381 <span class="keywordtype">string</span> statusReportFIFO;
399
- <a name="l00382"></a>00382 <span class="comment"></span>
400
- <a name="l00383"></a>00383 <span class="comment"> /**</span>
401
- <a name="l00384"></a>00384 <span class="comment"> * The PID of the ApplicationPool server process. If no server process</span>
402
- <a name="l00385"></a>00385 <span class="comment"> * is running, then &lt;tt&gt;serverPid == 0&lt;/tt&gt;.</span>
403
- <a name="l00386"></a>00386 <span class="comment"> *</span>
404
- <a name="l00387"></a>00387 <span class="comment"> * @invariant</span>
405
- <a name="l00388"></a>00388 <span class="comment"> * if serverPid == 0:</span>
406
- <a name="l00389"></a>00389 <span class="comment"> * serverSocket == -1</span>
407
- <a name="l00390"></a>00390 <span class="comment"> */</span>
408
- <a name="l00391"></a>00391 pid_t serverPid;
409
- <a name="l00392"></a>00392 <span class="comment"></span>
410
- <a name="l00393"></a>00393 <span class="comment"> /**</span>
411
- <a name="l00394"></a>00394 <span class="comment"> * The connection to the ApplicationPool server process. If no server</span>
412
- <a name="l00395"></a>00395 <span class="comment"> * process is running, then &lt;tt&gt;serverSocket == -1&lt;/tt&gt;.</span>
413
- <a name="l00396"></a>00396 <span class="comment"> *</span>
414
- <a name="l00397"></a>00397 <span class="comment"> * @invariant</span>
415
- <a name="l00398"></a>00398 <span class="comment"> * if serverPid == 0:</span>
416
- <a name="l00399"></a>00399 <span class="comment"> * serverSocket == -1</span>
417
- <a name="l00400"></a>00400 <span class="comment"> */</span>
418
- <a name="l00401"></a>00401 <span class="keywordtype">int</span> serverSocket;
419
- <a name="l00402"></a>00402 <span class="comment"></span>
420
- <a name="l00403"></a>00403 <span class="comment"> /**</span>
421
- <a name="l00404"></a>00404 <span class="comment"> * Shutdown the currently running ApplicationPool server process.</span>
422
- <a name="l00405"></a>00405 <span class="comment"> *</span>
423
- <a name="l00406"></a>00406 <span class="comment"> * @pre System call interruption is disabled.</span>
424
- <a name="l00407"></a>00407 <span class="comment"> * @pre serverSocket != -1 &amp;&amp; serverPid != 0</span>
425
- <a name="l00408"></a>00408 <span class="comment"> * @post serverSocket == -1 &amp;&amp; serverPid == 0</span>
426
- <a name="l00409"></a>00409 <span class="comment"> */</span>
427
- <a name="l00410"></a>00410 <span class="keywordtype">void</span> shutdownServer() {
428
- <a name="l00411"></a>00411 <a class="code" href="classboost_1_1this__thread_1_1disable__syscall__interruption.html" title="Create this struct on the stack to temporarily disable system call interruption,...">this_thread::disable_syscall_interruption</a> dsi;
429
- <a name="l00412"></a>00412 <span class="keywordtype">int</span> ret;
430
- <a name="l00413"></a>00413 time_t begin;
431
- <a name="l00414"></a>00414 <span class="keywordtype">bool</span> done = <span class="keyword">false</span>;
432
- <a name="l00415"></a>00415
433
- <a name="l00416"></a>00416 InterruptableCalls::close(serverSocket);
434
- <a name="l00417"></a>00417 <span class="keywordflow">if</span> (!statusReportFIFO.empty()) {
435
- <a name="l00418"></a>00418 <span class="keywordflow">do</span> {
436
- <a name="l00419"></a>00419 ret = unlink(statusReportFIFO.c_str());
437
- <a name="l00420"></a>00420 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
438
- <a name="l00421"></a>00421 }
439
- <a name="l00422"></a>00422
440
- <a name="l00423"></a>00423 P_TRACE(2, <span class="stringliteral">"Waiting for existing ApplicationPoolServerExecutable (PID "</span> &lt;&lt;
441
- <a name="l00424"></a>00424 serverPid &lt;&lt; <span class="stringliteral">") to exit..."</span>);
442
- <a name="l00425"></a>00425 begin = InterruptableCalls::time(NULL);
443
- <a name="l00426"></a>00426 <span class="keywordflow">while</span> (!done &amp;&amp; InterruptableCalls::time(NULL) &lt; begin + 5) {
444
- <a name="l00427"></a>00427 <span class="comment">/*</span>
445
- <a name="l00428"></a>00428 <span class="comment"> * Some Apache modules fork(), but don't close file descriptors.</span>
446
- <a name="l00429"></a>00429 <span class="comment"> * mod_wsgi is one such example. Because of that, closing serverSocket</span>
447
- <a name="l00430"></a>00430 <span class="comment"> * won't always cause the ApplicationPool server to exit. So we send it a</span>
448
- <a name="l00431"></a>00431 <span class="comment"> * signal.</span>
449
- <a name="l00432"></a>00432 <span class="comment"> */</span>
450
- <a name="l00433"></a>00433 InterruptableCalls::kill(serverPid, SIGINT);
451
- <a name="l00434"></a>00434
452
- <a name="l00435"></a>00435 ret = InterruptableCalls::waitpid(serverPid, NULL, WNOHANG);
453
- <a name="l00436"></a>00436 done = ret &gt; 0 || ret == -1;
454
- <a name="l00437"></a>00437 <span class="keywordflow">if</span> (!done) {
455
- <a name="l00438"></a>00438 InterruptableCalls::usleep(100000);
456
- <a name="l00439"></a>00439 }
457
- <a name="l00440"></a>00440 }
458
- <a name="l00441"></a>00441 <span class="keywordflow">if</span> (done) {
459
- <a name="l00442"></a>00442 P_TRACE(2, <span class="stringliteral">"ApplicationPoolServerExecutable exited."</span>);
460
- <a name="l00443"></a>00443 } <span class="keywordflow">else</span> {
461
- <a name="l00444"></a>00444 P_DEBUG(<span class="stringliteral">"ApplicationPoolServerExecutable not exited in time. Killing it..."</span>);
462
- <a name="l00445"></a>00445 InterruptableCalls::kill(serverPid, SIGTERM);
463
- <a name="l00446"></a>00446 InterruptableCalls::waitpid(serverPid, NULL, 0);
464
- <a name="l00447"></a>00447 }
465
- <a name="l00448"></a>00448
466
- <a name="l00449"></a>00449 serverSocket = -1;
467
- <a name="l00450"></a>00450 serverPid = 0;
468
- <a name="l00451"></a>00451 }
469
- <a name="l00452"></a>00452 <span class="comment"></span>
470
- <a name="l00453"></a>00453 <span class="comment"> /**</span>
471
- <a name="l00454"></a>00454 <span class="comment"> * Start an ApplicationPool server process. If there's already one running,</span>
472
- <a name="l00455"></a>00455 <span class="comment"> * then the currently running one will be shutdown.</span>
473
- <a name="l00456"></a>00456 <span class="comment"> *</span>
474
- <a name="l00457"></a>00457 <span class="comment"> * @pre System call interruption is disabled.</span>
475
- <a name="l00458"></a>00458 <span class="comment"> * @post serverSocket != -1 &amp;&amp; serverPid != 0</span>
476
- <a name="l00459"></a>00459 <span class="comment"> * @throw SystemException Something went wrong.</span>
477
- <a name="l00460"></a>00460 <span class="comment"> */</span>
478
- <a name="l00461"></a>00461 <span class="keywordtype">void</span> restartServer() {
479
- <a name="l00462"></a>00462 <span class="keywordtype">int</span> fds[2];
480
- <a name="l00463"></a>00463 pid_t pid;
481
- <a name="l00464"></a>00464
482
- <a name="l00465"></a>00465 <span class="keywordflow">if</span> (serverPid != 0) {
483
- <a name="l00466"></a>00466 shutdownServer();
484
- <a name="l00467"></a>00467 }
485
- <a name="l00468"></a>00468
486
- <a name="l00469"></a>00469 <span class="keywordflow">if</span> (InterruptableCalls::socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
487
- <a name="l00470"></a>00470 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot create a Unix socket pair"</span>, errno);
488
- <a name="l00471"></a>00471 }
489
- <a name="l00472"></a>00472
490
- <a name="l00473"></a>00473 createStatusReportFIFO();
491
- <a name="l00474"></a>00474
492
- <a name="l00475"></a>00475 pid = InterruptableCalls::fork();
493
- <a name="l00476"></a>00476 <span class="keywordflow">if</span> (pid == 0) { <span class="comment">// Child process.</span>
494
- <a name="l00477"></a>00477 dup2(fds[0], SERVER_SOCKET_FD);
495
- <a name="l00478"></a>00478
496
- <a name="l00479"></a>00479 <span class="comment">// Close all unnecessary file descriptors</span>
497
- <a name="l00480"></a>00480 <span class="keywordflow">for</span> (<span class="keywordtype">long</span> i = sysconf(_SC_OPEN_MAX) - 1; i &gt; SERVER_SOCKET_FD; i--) {
498
- <a name="l00481"></a>00481 close(i);
499
- <a name="l00482"></a>00482 }
500
- <a name="l00483"></a>00483
501
- <a name="l00484"></a>00484 execlp(
502
- <a name="l00485"></a>00485 #<span class="keywordflow">if</span> 0
503
- <a name="l00486"></a>00486 <span class="stringliteral">"valgrind"</span>,
504
- <a name="l00487"></a>00487 <span class="stringliteral">"valgrind"</span>,
505
- <a name="l00488"></a>00488 #<span class="keywordflow">else</span>
506
- <a name="l00489"></a>00489 m_serverExecutable.c_str(),
507
- <a name="l00490"></a>00490 <span class="preprocessor"> #endif</span>
508
- <a name="l00491"></a>00491 <span class="preprocessor"></span> m_serverExecutable.c_str(),
509
- <a name="l00492"></a>00492 <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(Passenger::getLogLevel()).c_str(),
510
- <a name="l00493"></a>00493 m_spawnServerCommand.c_str(),
511
- <a name="l00494"></a>00494 m_logFile.c_str(),
512
- <a name="l00495"></a>00495 m_rubyCommand.c_str(),
513
- <a name="l00496"></a>00496 m_user.c_str(),
514
- <a name="l00497"></a>00497 statusReportFIFO.c_str(),
515
- <a name="l00498"></a>00498 NULL);
516
- <a name="l00499"></a>00499 <span class="keywordtype">int</span> e = errno;
517
- <a name="l00500"></a>00500 fprintf(stderr, <span class="stringliteral">"*** Passenger ERROR: Cannot execute %s: %s (%d)\n"</span>,
518
- <a name="l00501"></a>00501 m_serverExecutable.c_str(), strerror(e), e);
519
- <a name="l00502"></a>00502 fflush(stderr);
520
- <a name="l00503"></a>00503 _exit(1);
521
- <a name="l00504"></a>00504 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (pid == -1) { <span class="comment">// Error.</span>
522
- <a name="l00505"></a>00505 InterruptableCalls::close(fds[0]);
523
- <a name="l00506"></a>00506 InterruptableCalls::close(fds[1]);
524
- <a name="l00507"></a>00507 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot create a new process"</span>, errno);
525
- <a name="l00508"></a>00508 } <span class="keywordflow">else</span> { <span class="comment">// Parent process.</span>
526
- <a name="l00509"></a>00509 InterruptableCalls::close(fds[0]);
527
- <a name="l00510"></a>00510 serverSocket = fds[1];
528
- <a name="l00511"></a>00511
529
- <a name="l00512"></a>00512 <span class="keywordtype">int</span> flags = fcntl(serverSocket, F_GETFD);
530
- <a name="l00513"></a>00513 <span class="keywordflow">if</span> (flags != -1) {
531
- <a name="l00514"></a>00514 fcntl(serverSocket, F_SETFD, flags | FD_CLOEXEC);
532
- <a name="l00515"></a>00515 }
533
- <a name="l00516"></a>00516
534
- <a name="l00517"></a>00517 serverPid = pid;
535
- <a name="l00518"></a>00518 }
536
- <a name="l00519"></a>00519 }
537
- <a name="l00520"></a>00520
538
- <a name="l00521"></a>00521 <span class="keywordtype">void</span> createStatusReportFIFO() {
539
- <a name="l00522"></a>00522 <span class="keywordtype">char</span> filename[PATH_MAX];
540
- <a name="l00523"></a>00523 <span class="keywordtype">int</span> ret;
541
- <a name="l00524"></a>00524
542
- <a name="l00525"></a>00525 snprintf(filename, <span class="keyword">sizeof</span>(filename), <span class="stringliteral">"/tmp/passenger_status.%d.fifo"</span>,
543
- <a name="l00526"></a>00526 getpid());
544
- <a name="l00527"></a>00527 filename[PATH_MAX - 1] = <span class="charliteral">'\0'</span>;
545
- <a name="l00528"></a>00528 <span class="keywordflow">do</span> {
546
- <a name="l00529"></a>00529 ret = mkfifo(filename, S_IRUSR | S_IWUSR);
547
- <a name="l00530"></a>00530 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
548
- <a name="l00531"></a>00531 <span class="keywordflow">if</span> (ret == -1 &amp;&amp; errno != EEXIST) {
549
- <a name="l00532"></a>00532 <span class="keywordtype">int</span> e = errno;
550
- <a name="l00533"></a>00533 P_WARN(<span class="stringliteral">"*** WARNING: Could not create FIFO '"</span> &lt;&lt; filename &lt;&lt;
551
- <a name="l00534"></a>00534 <span class="stringliteral">"': "</span> &lt;&lt; strerror(e) &lt;&lt; <span class="stringliteral">" ("</span> &lt;&lt; e &lt;&lt; <span class="stringliteral">")"</span> &lt;&lt; endl &lt;&lt;
552
- <a name="l00535"></a>00535 <span class="stringliteral">"Disabling Passenger ApplicationPool status reporting."</span>);
553
- <a name="l00536"></a>00536 statusReportFIFO = <span class="stringliteral">""</span>;
554
- <a name="l00537"></a>00537 } <span class="keywordflow">else</span> {
555
- <a name="l00538"></a>00538 statusReportFIFO = filename;
556
- <a name="l00539"></a>00539 }
557
- <a name="l00540"></a>00540 }
558
- <a name="l00541"></a>00541
559
- <a name="l00542"></a>00542 <span class="keyword">public</span>:<span class="comment"></span>
560
- <a name="l00543"></a>00543 <span class="comment"> /**</span>
561
- <a name="l00544"></a>00544 <span class="comment"> * Create a new ApplicationPoolServer object.</span>
562
- <a name="l00545"></a>00545 <span class="comment"> *</span>
563
- <a name="l00546"></a>00546 <span class="comment"> * @param serverExecutable The filename of the ApplicationPool server</span>
564
- <a name="l00547"></a>00547 <span class="comment"> * executable to use.</span>
565
- <a name="l00548"></a>00548 <span class="comment"> * @param spawnServerCommand The filename of the spawn server to use.</span>
566
- <a name="l00549"></a>00549 <span class="comment"> * @param logFile Specify a log file that the spawn server should use.</span>
567
- <a name="l00550"></a>00550 <span class="comment"> * Messages on its standard output and standard error channels</span>
568
- <a name="l00551"></a>00551 <span class="comment"> * will be written to this log file. If an empty string is</span>
569
- <a name="l00552"></a>00552 <span class="comment"> * specified, no log file will be used, and the spawn server</span>
570
- <a name="l00553"></a>00553 <span class="comment"> * will use the same standard output/error channels as the</span>
571
- <a name="l00554"></a>00554 <span class="comment"> * current process.</span>
572
- <a name="l00555"></a>00555 <span class="comment"> * @param rubyCommand The Ruby interpreter's command.</span>
573
- <a name="l00556"></a>00556 <span class="comment"> * @param user The user that the spawn manager should run as. This</span>
574
- <a name="l00557"></a>00557 <span class="comment"> * parameter only has effect if the current process is</span>
575
- <a name="l00558"></a>00558 <span class="comment"> * running as root. If the empty string is given, or if</span>
576
- <a name="l00559"></a>00559 <span class="comment"> * the &lt;tt&gt;user&lt;/tt&gt; is not a valid username, then</span>
577
- <a name="l00560"></a>00560 <span class="comment"> * the spawn manager will be run as the current user.</span>
578
- <a name="l00561"></a>00561 <span class="comment"> * @throws SystemException An error occured while trying to setup the spawn server</span>
579
- <a name="l00562"></a>00562 <span class="comment"> * or the server socket.</span>
580
- <a name="l00563"></a>00563 <span class="comment"> * @throws IOException The specified log file could not be opened.</span>
581
- <a name="l00564"></a>00564 <span class="comment"> */</span>
582
- <a name="l00565"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#2203db62a022579d569ceddff8ef6ca9">00565</a> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#2203db62a022579d569ceddff8ef6ca9" title="Create a new ApplicationPoolServer object.">ApplicationPoolServer</a>(<span class="keyword">const</span> <span class="keywordtype">string</span> &amp;serverExecutable,
583
- <a name="l00566"></a>00566 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;spawnServerCommand,
584
- <a name="l00567"></a>00567 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;logFile = <span class="stringliteral">""</span>,
585
- <a name="l00568"></a>00568 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;rubyCommand = <span class="stringliteral">"ruby"</span>,
586
- <a name="l00569"></a>00569 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;user = <span class="stringliteral">""</span>)
587
- <a name="l00570"></a>00570 : m_serverExecutable(serverExecutable),
588
- <a name="l00571"></a>00571 m_spawnServerCommand(spawnServerCommand),
589
- <a name="l00572"></a>00572 m_logFile(logFile),
590
- <a name="l00573"></a>00573 m_rubyCommand(rubyCommand),
591
- <a name="l00574"></a>00574 m_user(user) {
592
- <a name="l00575"></a>00575 serverSocket = -1;
593
- <a name="l00576"></a>00576 serverPid = 0;
594
- <a name="l00577"></a>00577 <a class="code" href="classboost_1_1this__thread_1_1disable__syscall__interruption.html" title="Create this struct on the stack to temporarily disable system call interruption,...">this_thread::disable_syscall_interruption</a> dsi;
595
- <a name="l00578"></a>00578 restartServer();
596
- <a name="l00579"></a>00579 }
597
- <a name="l00580"></a>00580
598
- <a name="l00581"></a>00581 ~<a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a>() {
599
- <a name="l00582"></a>00582 <span class="keywordflow">if</span> (serverSocket != -1) {
600
- <a name="l00583"></a>00583 <a class="code" href="classboost_1_1this__thread_1_1disable__syscall__interruption.html" title="Create this struct on the stack to temporarily disable system call interruption,...">this_thread::disable_syscall_interruption</a> dsi;
601
- <a name="l00584"></a>00584 shutdownServer();
602
- <a name="l00585"></a>00585 }
603
- <a name="l00586"></a>00586 }
604
- <a name="l00587"></a>00587 <span class="comment"></span>
605
- <a name="l00588"></a>00588 <span class="comment"> /**</span>
606
- <a name="l00589"></a>00589 <span class="comment"> * Connects to the server and returns a usable ApplicationPool object.</span>
607
- <a name="l00590"></a>00590 <span class="comment"> * All cache/pool data of this ApplicationPool is actually stored on</span>
608
- <a name="l00591"></a>00591 <span class="comment"> * the server and shared with other clients, but that is totally</span>
609
- <a name="l00592"></a>00592 <span class="comment"> * transparent to the user of the ApplicationPool object.</span>
610
- <a name="l00593"></a>00593 <span class="comment"> *</span>
611
- <a name="l00594"></a>00594 <span class="comment"> * @note</span>
612
- <a name="l00595"></a>00595 <span class="comment"> * All methods of the returned ApplicationPool object may throw</span>
613
- <a name="l00596"></a>00596 <span class="comment"> * SystemException, IOException or boost::thread_interrupted.</span>
614
- <a name="l00597"></a>00597 <span class="comment"> *</span>
615
- <a name="l00598"></a>00598 <span class="comment"> * @warning</span>
616
- <a name="l00599"></a>00599 <span class="comment"> * One may only use the returned ApplicationPool object for handling</span>
617
- <a name="l00600"></a>00600 <span class="comment"> * one session at a time. For example, don't do stuff like this:</span>
618
- <a name="l00601"></a>00601 <span class="comment"> * @code</span>
619
- <a name="l00602"></a>00602 <span class="comment"> * ApplicationPoolPtr pool = server.connect();</span>
620
- <a name="l00603"></a>00603 <span class="comment"> * Application::SessionPtr session1 = pool-&gt;get(...);</span>
621
- <a name="l00604"></a>00604 <span class="comment"> * Application::SessionPtr session2 = pool-&gt;get(...);</span>
622
- <a name="l00605"></a>00605 <span class="comment"> * @endcode</span>
623
- <a name="l00606"></a>00606 <span class="comment"> * Otherwise, a deadlock can occur under certain circumstances.</span>
624
- <a name="l00607"></a>00607 <span class="comment"> * @warning</span>
625
- <a name="l00608"></a>00608 <span class="comment"> * Instead, one should call connect() multiple times:</span>
626
- <a name="l00609"></a>00609 <span class="comment"> * @code</span>
627
- <a name="l00610"></a>00610 <span class="comment"> * ApplicationPoolPtr pool1 = server.connect();</span>
628
- <a name="l00611"></a>00611 <span class="comment"> * Application::SessionPtr session1 = pool1-&gt;get(...);</span>
629
- <a name="l00612"></a>00612 <span class="comment"> * </span>
630
- <a name="l00613"></a>00613 <span class="comment"> * ApplicationPoolPtr pool2 = server.connect();</span>
631
- <a name="l00614"></a>00614 <span class="comment"> * Application::SessionPtr session2 = pool2-&gt;get(...);</span>
632
- <a name="l00615"></a>00615 <span class="comment"> * @endcode</span>
633
- <a name="l00616"></a>00616 <span class="comment"> *</span>
634
- <a name="l00617"></a>00617 <span class="comment"> * @throws SystemException Something went wrong.</span>
635
- <a name="l00618"></a>00618 <span class="comment"> * @throws IOException Something went wrong.</span>
636
- <a name="l00619"></a>00619 <span class="comment"> */</span>
637
- <a name="l00620"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#18f77057cc28e7924a8f4d1397aa0468">00620</a> ApplicationPoolPtr <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#18f77057cc28e7924a8f4d1397aa0468" title="Connects to the server and returns a usable ApplicationPool object.">connect</a>() {
638
- <a name="l00621"></a>00621 <span class="keywordflow">try</span> {
639
- <a name="l00622"></a>00622 <a class="code" href="classboost_1_1this__thread_1_1disable__syscall__interruption.html" title="Create this struct on the stack to temporarily disable system call interruption,...">this_thread::disable_syscall_interruption</a> dsi;
640
- <a name="l00623"></a>00623 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(serverSocket);
641
- <a name="l00624"></a>00624 <span class="keywordtype">int</span> clientConnection;
642
- <a name="l00625"></a>00625
643
- <a name="l00626"></a>00626 <span class="comment">// Write some random data to wake up the server.</span>
644
- <a name="l00627"></a>00627 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#069314e4c7e1fe8c8ab36e16d2cc5fef" title="Send a block of data over the underlying file descriptor.">writeRaw</a>(<span class="stringliteral">"x"</span>, 1);
645
- <a name="l00628"></a>00628
646
- <a name="l00629"></a>00629 clientConnection = channel.<a class="code" href="classPassenger_1_1MessageChannel.html#1561b7e4a0f4d39ea431f456e5655488" title="Receive a file descriptor, which had been passed over the underlying file descriptor...">readFileDescriptor</a>();
647
- <a name="l00630"></a>00630 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g41b6c4a82fed72531a147de0505a8396" title="Convenience shortcut for creating a shared_ptr.">ptr</a>(<span class="keyword">new</span> Client(clientConnection));
648
- <a name="l00631"></a>00631 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a> &amp;e) {
649
- <a name="l00632"></a>00632 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Could not connect to the ApplicationPool server"</span>, e.<a class="code" href="classPassenger_1_1SystemException.html#ee7a6672bf79b72a4c3ee70c57d6a47c" title="The value of errno at the time the error occured.">code</a>());
650
- <a name="l00633"></a>00633 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a> &amp;e) {
651
- <a name="l00634"></a>00634 <span class="keywordtype">string</span> message(<span class="stringliteral">"Could not connect to the ApplicationPool server: "</span>);
652
- <a name="l00635"></a>00635 message.append(e.<a class="code" href="classPassenger_1_1IOException.html#1b65d0fdb9bc5136f5b7df759c14768a">what</a>());
653
- <a name="l00636"></a>00636 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(message);
654
- <a name="l00637"></a>00637 }
655
- <a name="l00638"></a>00638 }
656
- <a name="l00639"></a>00639 <span class="comment"></span>
657
- <a name="l00640"></a>00640 <span class="comment"> /**</span>
658
- <a name="l00641"></a>00641 <span class="comment"> * Detach the server, thereby telling it that we don't want to connect</span>
659
- <a name="l00642"></a>00642 <span class="comment"> * to it anymore. This frees up some resources in the current process,</span>
660
- <a name="l00643"></a>00643 <span class="comment"> * such as file descriptors.</span>
661
- <a name="l00644"></a>00644 <span class="comment"> *</span>
662
- <a name="l00645"></a>00645 <span class="comment"> * This method is particularily useful to Apache worker processes that</span>
663
- <a name="l00646"></a>00646 <span class="comment"> * have just established a connection with the ApplicationPool server.</span>
664
- <a name="l00647"></a>00647 <span class="comment"> * Any sessions that are opened prior to calling detach(), will keep</span>
665
- <a name="l00648"></a>00648 <span class="comment"> * working even after a detach().</span>
666
- <a name="l00649"></a>00649 <span class="comment"> *</span>
667
- <a name="l00650"></a>00650 <span class="comment"> * This method may only be called once. The ApplicationPoolServer object</span>
668
- <a name="l00651"></a>00651 <span class="comment"> * will become unusable once detach() has been called, so call connect()</span>
669
- <a name="l00652"></a>00652 <span class="comment"> * before calling detach().</span>
670
- <a name="l00653"></a>00653 <span class="comment"> */</span>
671
- <a name="l00654"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce">00654</a> <span class="keywordtype">void</span> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce" title="Detach the server, thereby telling it that we don&amp;#39;t want to connect to it anymore...">detach</a>() {
672
- <a name="l00655"></a>00655 <span class="keywordtype">int</span> ret;
673
- <a name="l00656"></a>00656 <span class="keywordflow">do</span> {
674
- <a name="l00657"></a>00657 ret = close(serverSocket);
675
- <a name="l00658"></a>00658 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
676
- <a name="l00659"></a>00659 serverSocket = -1;
677
- <a name="l00660"></a>00660 }
678
- <a name="l00661"></a>00661 };
679
- <a name="l00662"></a>00662
680
- <a name="l00663"></a>00663 <span class="keyword">typedef</span> shared_ptr&lt;ApplicationPoolServer&gt; ApplicationPoolServerPtr;
681
- <a name="l00664"></a>00664
682
- <a name="l00665"></a>00665 } <span class="comment">// namespace Passenger</span>
683
- <a name="l00666"></a>00666
684
- <a name="l00667"></a>00667 <span class="preprocessor">#endif </span><span class="comment">/* _PASSENGER_APPLICATION_POOL_SERVER_H_ */</span>
264
+ <a name="l00248"></a>00248 };
265
+ <a name="l00249"></a>00249 <span class="comment"></span>
266
+ <a name="l00250"></a>00250 <span class="comment"> /**</span>
267
+ <a name="l00251"></a>00251 <span class="comment"> * An ApplicationPool implementation that works together with ApplicationPoolServer.</span>
268
+ <a name="l00252"></a>00252 <span class="comment"> * It doesn't do much by itself, its job is mostly to forward queries/commands to</span>
269
+ <a name="l00253"></a>00253 <span class="comment"> * the server and returning the result. Most of the logic is in the server executable.</span>
270
+ <a name="l00254"></a>00254 <span class="comment"> */</span>
271
+ <a name="l00255"></a>00255 <span class="keyword">class </span><a class="code" href="classClient.html#e625bb32c95bde75bfa4bdfdb8ee56db" title="Create a new Client object.">Client</a>: <span class="keyword">public</span> <a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a> {
272
+ <a name="l00256"></a>00256 <span class="keyword">private</span>:
273
+ <a name="l00257"></a>00257 <span class="comment">// The smart pointer only serves to keep the shared data alive.</span>
274
+ <a name="l00258"></a>00258 <span class="comment">// We access the shared data via a normal pointer, for performance.</span>
275
+ <a name="l00259"></a>00259 SharedDataPtr dataSmartPointer;
276
+ <a name="l00260"></a>00260 SharedData *data;
277
+ <a name="l00261"></a>00261
278
+ <a name="l00262"></a>00262 <span class="keyword">public</span>:<span class="comment"></span>
279
+ <a name="l00263"></a>00263 <span class="comment"> /**</span>
280
+ <a name="l00264"></a>00264 <span class="comment"> * Create a new Client.</span>
281
+ <a name="l00265"></a>00265 <span class="comment"> *</span>
282
+ <a name="l00266"></a>00266 <span class="comment"> * @param sock The newly established socket connection with the ApplicationPoolServer.</span>
283
+ <a name="l00267"></a>00267 <span class="comment"> */</span>
284
+ <a name="l00268"></a>00268 Client(<span class="keywordtype">int</span> sock) {
285
+ <a name="l00269"></a>00269 dataSmartPointer = <a class="code" href="group__Support.html#g41b6c4a82fed72531a147de0505a8396" title="Convenience shortcut for creating a shared_ptr.">ptr</a>(<span class="keyword">new</span> SharedData());
286
+ <a name="l00270"></a>00270 data = dataSmartPointer.get();
287
+ <a name="l00271"></a>00271 data-&gt;server = sock;
288
+ <a name="l00272"></a>00272 }
289
+ <a name="l00273"></a>00273
290
+ <a name="l00274"></a>00274 <span class="keyword">virtual</span> <span class="keywordtype">bool</span> connected()<span class="keyword"> const </span>{
291
+ <a name="l00275"></a>00275 boost::mutex::scoped_lock(data-&gt;lock);
292
+ <a name="l00276"></a>00276 <span class="keywordflow">return</span> data-&gt;server != -1;
293
+ <a name="l00277"></a>00277 }
294
+ <a name="l00278"></a>00278
295
+ <a name="l00279"></a>00279 <span class="keyword">virtual</span> <span class="keywordtype">void</span> clear() {
296
+ <a name="l00280"></a>00280 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
297
+ <a name="l00281"></a>00281 boost::mutex::scoped_lock l(data-&gt;lock);
298
+ <a name="l00282"></a>00282 <span class="keywordflow">try</span> {
299
+ <a name="l00283"></a>00283 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#150f68bc47e060dcc6ca35bee047914d" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"clear"</span>, NULL);
300
+ <a name="l00284"></a>00284 } <span class="keywordflow">catch</span> (...) {
301
+ <a name="l00285"></a>00285 data-&gt;disconnect();
302
+ <a name="l00286"></a>00286 <span class="keywordflow">throw</span>;
303
+ <a name="l00287"></a>00287 }
304
+ <a name="l00288"></a>00288 }
305
+ <a name="l00289"></a>00289
306
+ <a name="l00290"></a>00290 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMaxIdleTime(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> seconds) {
307
+ <a name="l00291"></a>00291 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
308
+ <a name="l00292"></a>00292 boost::mutex::scoped_lock l(data-&gt;lock);
309
+ <a name="l00293"></a>00293 <span class="keywordflow">try</span> {
310
+ <a name="l00294"></a>00294 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#150f68bc47e060dcc6ca35bee047914d" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"setMaxIdleTime"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(seconds).c_str(), NULL);
311
+ <a name="l00295"></a>00295 } <span class="keywordflow">catch</span> (...) {
312
+ <a name="l00296"></a>00296 data-&gt;disconnect();
313
+ <a name="l00297"></a>00297 <span class="keywordflow">throw</span>;
314
+ <a name="l00298"></a>00298 }
315
+ <a name="l00299"></a>00299 }
316
+ <a name="l00300"></a>00300
317
+ <a name="l00301"></a>00301 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMax(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max) {
318
+ <a name="l00302"></a>00302 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
319
+ <a name="l00303"></a>00303 boost::mutex::scoped_lock l(data-&gt;lock);
320
+ <a name="l00304"></a>00304 <span class="keywordflow">try</span> {
321
+ <a name="l00305"></a>00305 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#150f68bc47e060dcc6ca35bee047914d" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"setMax"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(max).c_str(), NULL);
322
+ <a name="l00306"></a>00306 } <span class="keywordflow">catch</span> (...) {
323
+ <a name="l00307"></a>00307 data-&gt;disconnect();
324
+ <a name="l00308"></a>00308 <span class="keywordflow">throw</span>;
325
+ <a name="l00309"></a>00309 }
326
+ <a name="l00310"></a>00310 }
327
+ <a name="l00311"></a>00311
328
+ <a name="l00312"></a>00312 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> getActive()<span class="keyword"> const </span>{
329
+ <a name="l00313"></a>00313 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
330
+ <a name="l00314"></a>00314 boost::mutex::scoped_lock l(data-&gt;lock);
331
+ <a name="l00315"></a>00315 vector&lt;string&gt; args;
332
+ <a name="l00316"></a>00316
333
+ <a name="l00317"></a>00317 <span class="keywordflow">try</span> {
334
+ <a name="l00318"></a>00318 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#150f68bc47e060dcc6ca35bee047914d" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"getActive"</span>, NULL);
335
+ <a name="l00319"></a>00319 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Read an array message from the underlying file descriptor.">read</a>(args);
336
+ <a name="l00320"></a>00320 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[0].c_str());
337
+ <a name="l00321"></a>00321 } <span class="keywordflow">catch</span> (...) {
338
+ <a name="l00322"></a>00322 data-&gt;disconnect();
339
+ <a name="l00323"></a>00323 <span class="keywordflow">throw</span>;
340
+ <a name="l00324"></a>00324 }
341
+ <a name="l00325"></a>00325 }
342
+ <a name="l00326"></a>00326
343
+ <a name="l00327"></a>00327 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> getCount()<span class="keyword"> const </span>{
344
+ <a name="l00328"></a>00328 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
345
+ <a name="l00329"></a>00329 boost::mutex::scoped_lock l(data-&gt;lock);
346
+ <a name="l00330"></a>00330 vector&lt;string&gt; args;
347
+ <a name="l00331"></a>00331
348
+ <a name="l00332"></a>00332 <span class="keywordflow">try</span> {
349
+ <a name="l00333"></a>00333 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#150f68bc47e060dcc6ca35bee047914d" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"getCount"</span>, NULL);
350
+ <a name="l00334"></a>00334 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Read an array message from the underlying file descriptor.">read</a>(args);
351
+ <a name="l00335"></a>00335 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[0].c_str());
352
+ <a name="l00336"></a>00336 } <span class="keywordflow">catch</span> (...) {
353
+ <a name="l00337"></a>00337 data-&gt;disconnect();
354
+ <a name="l00338"></a>00338 <span class="keywordflow">throw</span>;
355
+ <a name="l00339"></a>00339 }
356
+ <a name="l00340"></a>00340 }
357
+ <a name="l00341"></a>00341
358
+ <a name="l00342"></a>00342 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMaxPerApp(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max) {
359
+ <a name="l00343"></a>00343 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
360
+ <a name="l00344"></a>00344 boost::mutex::scoped_lock l(data-&gt;lock);
361
+ <a name="l00345"></a>00345 <span class="keywordflow">try</span> {
362
+ <a name="l00346"></a>00346 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#150f68bc47e060dcc6ca35bee047914d" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"setMaxPerApp"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(max).c_str(), NULL);
363
+ <a name="l00347"></a>00347 } <span class="keywordflow">catch</span> (...) {
364
+ <a name="l00348"></a>00348 data-&gt;disconnect();
365
+ <a name="l00349"></a>00349 <span class="keywordflow">throw</span>;
366
+ <a name="l00350"></a>00350 }
367
+ <a name="l00351"></a>00351 }
368
+ <a name="l00352"></a>00352
369
+ <a name="l00353"></a>00353 <span class="keyword">virtual</span> pid_t getSpawnServerPid()<span class="keyword"> const </span>{
370
+ <a name="l00354"></a>00354 this_thread::disable_syscall_interruption dsi;
371
+ <a name="l00355"></a>00355 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
372
+ <a name="l00356"></a>00356 boost::mutex::scoped_lock l(data-&gt;lock);
373
+ <a name="l00357"></a>00357 vector&lt;string&gt; args;
374
+ <a name="l00358"></a>00358
375
+ <a name="l00359"></a>00359 <span class="keywordflow">try</span> {
376
+ <a name="l00360"></a>00360 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#150f68bc47e060dcc6ca35bee047914d" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(<span class="stringliteral">"getSpawnServerPid"</span>, NULL);
377
+ <a name="l00361"></a>00361 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Read an array message from the underlying file descriptor.">read</a>(args);
378
+ <a name="l00362"></a>00362 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[0].c_str());
379
+ <a name="l00363"></a>00363 } <span class="keywordflow">catch</span> (...) {
380
+ <a name="l00364"></a>00364 data-&gt;disconnect();
381
+ <a name="l00365"></a>00365 <span class="keywordflow">throw</span>;
382
+ <a name="l00366"></a>00366 }
383
+ <a name="l00367"></a>00367 }
384
+ <a name="l00368"></a>00368
385
+ <a name="l00369"></a>00369 <span class="keyword">virtual</span> <a class="code" href="classPassenger_1_1Application.html#d14f673494991460b16246a527ad8ad9" title="Convenient alias for Session smart pointer.">Application::SessionPtr</a> <span class="keyword">get</span>(<span class="keyword">const</span> <a class="code" href="structPassenger_1_1PoolOptions.html" title="This struct encapsulates information for ApplicationPool::get() and for SpawnManager::spawn()...">PoolOptions</a> &amp;options) {
386
+ <a name="l00370"></a>00370 this_thread::disable_syscall_interruption dsi;
387
+ <a name="l00371"></a>00371 TRACE_POINT();
388
+ <a name="l00372"></a>00372
389
+ <a name="l00373"></a>00373 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
390
+ <a name="l00374"></a>00374 boost::mutex::scoped_lock l(data-&gt;lock);
391
+ <a name="l00375"></a>00375 vector&lt;string&gt; args;
392
+ <a name="l00376"></a>00376 <span class="keywordtype">int</span> stream;
393
+ <a name="l00377"></a>00377 <span class="keywordtype">bool</span> result;
394
+ <a name="l00378"></a>00378
395
+ <a name="l00379"></a>00379 <span class="keywordflow">try</span> {
396
+ <a name="l00380"></a>00380 vector&lt;string&gt; args;
397
+ <a name="l00381"></a>00381
398
+ <a name="l00382"></a>00382 args.push_back(<span class="stringliteral">"get"</span>);
399
+ <a name="l00383"></a>00383 options.toVector(args);
400
+ <a name="l00384"></a>00384 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#150f68bc47e060dcc6ca35bee047914d" title="Send an array message, which consists of the given elements, over the underlying...">write</a>(args);
401
+ <a name="l00385"></a>00385 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a> &amp;e) {
402
+ <a name="l00386"></a>00386 UPDATE_TRACE_POINT();
403
+ <a name="l00387"></a>00387 data-&gt;disconnect();
404
+ <a name="l00388"></a>00388
405
+ <a name="l00389"></a>00389 <span class="keywordtype">string</span> message(<span class="stringliteral">"Could not send data to the ApplicationPool server: "</span>);
406
+ <a name="l00390"></a>00390 message.append(e.<a class="code" href="classPassenger_1_1SystemException.html#84fa2ab4f5b7b96704734fcdfdaa0269" title="Returns a brief version of the exception message.">brief</a>());
407
+ <a name="l00391"></a>00391 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(message, e.<a class="code" href="classPassenger_1_1SystemException.html#ee7a6672bf79b72a4c3ee70c57d6a47c" title="The value of errno at the time the error occured.">code</a>());
408
+ <a name="l00392"></a>00392 }
409
+ <a name="l00393"></a>00393 <span class="keywordflow">try</span> {
410
+ <a name="l00394"></a>00394 UPDATE_TRACE_POINT();
411
+ <a name="l00395"></a>00395 result = channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Read an array message from the underlying file descriptor.">read</a>(args);
412
+ <a name="l00396"></a>00396 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a> &amp;e) {
413
+ <a name="l00397"></a>00397 UPDATE_TRACE_POINT();
414
+ <a name="l00398"></a>00398 data-&gt;disconnect();
415
+ <a name="l00399"></a>00399 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Could not read a message from "</span>
416
+ <a name="l00400"></a>00400 <span class="stringliteral">"the ApplicationPool server"</span>, e.<a class="code" href="classPassenger_1_1SystemException.html#ee7a6672bf79b72a4c3ee70c57d6a47c" title="The value of errno at the time the error occured.">code</a>());
417
+ <a name="l00401"></a>00401 }
418
+ <a name="l00402"></a>00402 <span class="keywordflow">if</span> (!result) {
419
+ <a name="l00403"></a>00403 UPDATE_TRACE_POINT();
420
+ <a name="l00404"></a>00404 data-&gt;disconnect();
421
+ <a name="l00405"></a>00405 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(<span class="stringliteral">"The ApplicationPool server unexpectedly "</span>
422
+ <a name="l00406"></a>00406 <span class="stringliteral">"closed the connection."</span>);
423
+ <a name="l00407"></a>00407 }
424
+ <a name="l00408"></a>00408 <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"ok"</span>) {
425
+ <a name="l00409"></a>00409 UPDATE_TRACE_POINT();
426
+ <a name="l00410"></a>00410 pid_t pid = (pid_t) <a class="code" href="group__Support.html#g7b50461f1bc2b370c956967870da2762" title="Converts the given string to a long integer.">atol</a>(args[1]);
427
+ <a name="l00411"></a>00411 <span class="keywordtype">int</span> sessionID = <a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[2]);
428
+ <a name="l00412"></a>00412
429
+ <a name="l00413"></a>00413 <span class="keywordflow">try</span> {
430
+ <a name="l00414"></a>00414 stream = channel.<a class="code" href="classPassenger_1_1MessageChannel.html#1561b7e4a0f4d39ea431f456e5655488" title="Receive a file descriptor, which had been passed over the underlying file descriptor...">readFileDescriptor</a>();
431
+ <a name="l00415"></a>00415 } <span class="keywordflow">catch</span> (...) {
432
+ <a name="l00416"></a>00416 UPDATE_TRACE_POINT();
433
+ <a name="l00417"></a>00417 data-&gt;disconnect();
434
+ <a name="l00418"></a>00418 <span class="keywordflow">throw</span>;
435
+ <a name="l00419"></a>00419 }
436
+ <a name="l00420"></a>00420
437
+ <a name="l00421"></a>00421 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g41b6c4a82fed72531a147de0505a8396" title="Convenience shortcut for creating a shared_ptr.">ptr</a>(<span class="keyword">new</span> RemoteSession(dataSmartPointer,
438
+ <a name="l00422"></a>00422 pid, sessionID, stream));
439
+ <a name="l00423"></a>00423 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"SpawnException"</span>) {
440
+ <a name="l00424"></a>00424 UPDATE_TRACE_POINT();
441
+ <a name="l00425"></a>00425 <span class="keywordflow">if</span> (args[2] == <span class="stringliteral">"true"</span>) {
442
+ <a name="l00426"></a>00426 <span class="keywordtype">string</span> errorPage;
443
+ <a name="l00427"></a>00427
444
+ <a name="l00428"></a>00428 <span class="keywordflow">try</span> {
445
+ <a name="l00429"></a>00429 result = channel.<a class="code" href="classPassenger_1_1MessageChannel.html#4ce6a0e751b5e3563bee583c231569bc" title="Read a scalar message from the underlying file descriptor.">readScalar</a>(errorPage);
446
+ <a name="l00430"></a>00430 } <span class="keywordflow">catch</span> (...) {
447
+ <a name="l00431"></a>00431 data-&gt;disconnect();
448
+ <a name="l00432"></a>00432 <span class="keywordflow">throw</span>;
449
+ <a name="l00433"></a>00433 }
450
+ <a name="l00434"></a>00434 <span class="keywordflow">if</span> (!result) {
451
+ <a name="l00435"></a>00435 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(<span class="stringliteral">"The ApplicationPool server "</span>
452
+ <a name="l00436"></a>00436 <span class="stringliteral">"unexpectedly closed the connection."</span>);
453
+ <a name="l00437"></a>00437 }
454
+ <a name="l00438"></a>00438 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SpawnException.html" title="Thrown when SpawnManager or ApplicationPool fails to spawn an application instance...">SpawnException</a>(args[1], errorPage);
455
+ <a name="l00439"></a>00439 } <span class="keywordflow">else</span> {
456
+ <a name="l00440"></a>00440 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SpawnException.html" title="Thrown when SpawnManager or ApplicationPool fails to spawn an application instance...">SpawnException</a>(args[1]);
457
+ <a name="l00441"></a>00441 }
458
+ <a name="l00442"></a>00442 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"BusyException"</span>) {
459
+ <a name="l00443"></a>00443 UPDATE_TRACE_POINT();
460
+ <a name="l00444"></a>00444 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1BusyException.html" title="The application pool is too busy and cannot fulfill a get() request.">BusyException</a>(args[1]);
461
+ <a name="l00445"></a>00445 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"IOException"</span>) {
462
+ <a name="l00446"></a>00446 UPDATE_TRACE_POINT();
463
+ <a name="l00447"></a>00447 data-&gt;disconnect();
464
+ <a name="l00448"></a>00448 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(args[1]);
465
+ <a name="l00449"></a>00449 } <span class="keywordflow">else</span> {
466
+ <a name="l00450"></a>00450 UPDATE_TRACE_POINT();
467
+ <a name="l00451"></a>00451 data-&gt;disconnect();
468
+ <a name="l00452"></a>00452 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(<span class="stringliteral">"The ApplicationPool server returned "</span>
469
+ <a name="l00453"></a>00453 <span class="stringliteral">"an unknown message: "</span> + <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(args));
470
+ <a name="l00454"></a>00454 }
471
+ <a name="l00455"></a>00455 }
472
+ <a name="l00456"></a>00456 };
473
+ <a name="l00457"></a>00457
474
+ <a name="l00458"></a>00458
475
+ <a name="l00459"></a>00459 <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">int</span> SERVER_SOCKET_FD = 3;
476
+ <a name="l00460"></a>00460
477
+ <a name="l00461"></a>00461 <span class="keywordtype">string</span> m_serverExecutable;
478
+ <a name="l00462"></a>00462 <span class="keywordtype">string</span> m_spawnServerCommand;
479
+ <a name="l00463"></a>00463 <span class="keywordtype">string</span> m_logFile;
480
+ <a name="l00464"></a>00464 <span class="keywordtype">string</span> m_rubyCommand;
481
+ <a name="l00465"></a>00465 <span class="keywordtype">string</span> m_user;
482
+ <a name="l00466"></a>00466 <span class="keywordtype">string</span> statusReportFIFO;
483
+ <a name="l00467"></a>00467 <span class="comment"></span>
484
+ <a name="l00468"></a>00468 <span class="comment"> /**</span>
485
+ <a name="l00469"></a>00469 <span class="comment"> * The PID of the ApplicationPool server process. If no server process</span>
486
+ <a name="l00470"></a>00470 <span class="comment"> * is running, then &lt;tt&gt;serverPid == 0&lt;/tt&gt;.</span>
487
+ <a name="l00471"></a>00471 <span class="comment"> *</span>
488
+ <a name="l00472"></a>00472 <span class="comment"> * @invariant</span>
489
+ <a name="l00473"></a>00473 <span class="comment"> * if serverPid == 0:</span>
490
+ <a name="l00474"></a>00474 <span class="comment"> * serverSocket == -1</span>
491
+ <a name="l00475"></a>00475 <span class="comment"> */</span>
492
+ <a name="l00476"></a>00476 pid_t serverPid;
493
+ <a name="l00477"></a>00477 <span class="comment"></span>
494
+ <a name="l00478"></a>00478 <span class="comment"> /**</span>
495
+ <a name="l00479"></a>00479 <span class="comment"> * The connection to the ApplicationPool server process. If no server</span>
496
+ <a name="l00480"></a>00480 <span class="comment"> * process is running, then &lt;tt&gt;serverSocket == -1&lt;/tt&gt;.</span>
497
+ <a name="l00481"></a>00481 <span class="comment"> *</span>
498
+ <a name="l00482"></a>00482 <span class="comment"> * @invariant</span>
499
+ <a name="l00483"></a>00483 <span class="comment"> * if serverPid == 0:</span>
500
+ <a name="l00484"></a>00484 <span class="comment"> * serverSocket == -1</span>
501
+ <a name="l00485"></a>00485 <span class="comment"> */</span>
502
+ <a name="l00486"></a>00486 <span class="keywordtype">int</span> serverSocket;
503
+ <a name="l00487"></a>00487 <span class="comment"></span>
504
+ <a name="l00488"></a>00488 <span class="comment"> /**</span>
505
+ <a name="l00489"></a>00489 <span class="comment"> * Shutdown the currently running ApplicationPool server process.</span>
506
+ <a name="l00490"></a>00490 <span class="comment"> *</span>
507
+ <a name="l00491"></a>00491 <span class="comment"> * @pre System call interruption is disabled.</span>
508
+ <a name="l00492"></a>00492 <span class="comment"> * @pre serverSocket != -1 &amp;&amp; serverPid != 0</span>
509
+ <a name="l00493"></a>00493 <span class="comment"> * @post serverSocket == -1 &amp;&amp; serverPid == 0</span>
510
+ <a name="l00494"></a>00494 <span class="comment"> */</span>
511
+ <a name="l00495"></a>00495 <span class="keywordtype">void</span> shutdownServer() {
512
+ <a name="l00496"></a>00496 TRACE_POINT();
513
+ <a name="l00497"></a>00497 this_thread::disable_syscall_interruption dsi;
514
+ <a name="l00498"></a>00498 <span class="keywordtype">int</span> ret;
515
+ <a name="l00499"></a>00499 time_t begin;
516
+ <a name="l00500"></a>00500 <span class="keywordtype">bool</span> done = <span class="keyword">false</span>;
517
+ <a name="l00501"></a>00501
518
+ <a name="l00502"></a>00502 syscalls::close(serverSocket);
519
+ <a name="l00503"></a>00503 <span class="keywordflow">if</span> (!statusReportFIFO.empty()) {
520
+ <a name="l00504"></a>00504 <span class="keywordflow">do</span> {
521
+ <a name="l00505"></a>00505 ret = unlink(statusReportFIFO.c_str());
522
+ <a name="l00506"></a>00506 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
523
+ <a name="l00507"></a>00507 }
524
+ <a name="l00508"></a>00508
525
+ <a name="l00509"></a>00509 P_TRACE(2, <span class="stringliteral">"Waiting for existing ApplicationPoolServerExecutable (PID "</span> &lt;&lt;
526
+ <a name="l00510"></a>00510 serverPid &lt;&lt; <span class="stringliteral">") to exit..."</span>);
527
+ <a name="l00511"></a>00511 begin = syscalls::time(NULL);
528
+ <a name="l00512"></a>00512 <span class="keywordflow">while</span> (!done &amp;&amp; syscalls::time(NULL) &lt; begin + 5) {
529
+ <a name="l00513"></a>00513 <span class="comment">/*</span>
530
+ <a name="l00514"></a>00514 <span class="comment"> * Some Apache modules fork(), but don't close file descriptors.</span>
531
+ <a name="l00515"></a>00515 <span class="comment"> * mod_wsgi is one such example. Because of that, closing serverSocket</span>
532
+ <a name="l00516"></a>00516 <span class="comment"> * won't always cause the ApplicationPool server to exit. So we send it a</span>
533
+ <a name="l00517"></a>00517 <span class="comment"> * signal.</span>
534
+ <a name="l00518"></a>00518 <span class="comment"> */</span>
535
+ <a name="l00519"></a>00519 syscalls::kill(serverPid, SIGINT);
536
+ <a name="l00520"></a>00520
537
+ <a name="l00521"></a>00521 ret = syscalls::waitpid(serverPid, NULL, WNOHANG);
538
+ <a name="l00522"></a>00522 done = ret &gt; 0 || ret == -1;
539
+ <a name="l00523"></a>00523 <span class="keywordflow">if</span> (!done) {
540
+ <a name="l00524"></a>00524 syscalls::usleep(100000);
541
+ <a name="l00525"></a>00525 }
542
+ <a name="l00526"></a>00526 }
543
+ <a name="l00527"></a>00527 <span class="keywordflow">if</span> (done) {
544
+ <a name="l00528"></a>00528 P_TRACE(2, <span class="stringliteral">"ApplicationPoolServerExecutable exited."</span>);
545
+ <a name="l00529"></a>00529 } <span class="keywordflow">else</span> {
546
+ <a name="l00530"></a>00530 P_DEBUG(<span class="stringliteral">"ApplicationPoolServerExecutable not exited in time. Killing it..."</span>);
547
+ <a name="l00531"></a>00531 syscalls::kill(serverPid, SIGTERM);
548
+ <a name="l00532"></a>00532 syscalls::waitpid(serverPid, NULL, 0);
549
+ <a name="l00533"></a>00533 }
550
+ <a name="l00534"></a>00534
551
+ <a name="l00535"></a>00535 serverSocket = -1;
552
+ <a name="l00536"></a>00536 serverPid = 0;
553
+ <a name="l00537"></a>00537 }
554
+ <a name="l00538"></a>00538 <span class="comment"></span>
555
+ <a name="l00539"></a>00539 <span class="comment"> /**</span>
556
+ <a name="l00540"></a>00540 <span class="comment"> * Start an ApplicationPool server process. If there's already one running,</span>
557
+ <a name="l00541"></a>00541 <span class="comment"> * then the currently running one will be shutdown.</span>
558
+ <a name="l00542"></a>00542 <span class="comment"> *</span>
559
+ <a name="l00543"></a>00543 <span class="comment"> * @pre System call interruption is disabled.</span>
560
+ <a name="l00544"></a>00544 <span class="comment"> * @post serverSocket != -1 &amp;&amp; serverPid != 0</span>
561
+ <a name="l00545"></a>00545 <span class="comment"> * @throw SystemException Something went wrong.</span>
562
+ <a name="l00546"></a>00546 <span class="comment"> */</span>
563
+ <a name="l00547"></a>00547 <span class="keywordtype">void</span> restartServer() {
564
+ <a name="l00548"></a>00548 TRACE_POINT();
565
+ <a name="l00549"></a>00549 <span class="keywordtype">int</span> fds[2];
566
+ <a name="l00550"></a>00550 pid_t pid;
567
+ <a name="l00551"></a>00551
568
+ <a name="l00552"></a>00552 <span class="keywordflow">if</span> (serverPid != 0) {
569
+ <a name="l00553"></a>00553 shutdownServer();
570
+ <a name="l00554"></a>00554 }
571
+ <a name="l00555"></a>00555
572
+ <a name="l00556"></a>00556 <span class="keywordflow">if</span> (syscalls::socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
573
+ <a name="l00557"></a>00557 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot create a Unix socket pair"</span>, errno);
574
+ <a name="l00558"></a>00558 }
575
+ <a name="l00559"></a>00559
576
+ <a name="l00560"></a>00560 createStatusReportFIFO();
577
+ <a name="l00561"></a>00561
578
+ <a name="l00562"></a>00562 pid = syscalls::fork();
579
+ <a name="l00563"></a>00563 <span class="keywordflow">if</span> (pid == 0) { <span class="comment">// Child process.</span>
580
+ <a name="l00564"></a>00564 dup2(STDERR_FILENO, STDOUT_FILENO); <span class="comment">// Redirect stdout to the same channel as stderr.</span>
581
+ <a name="l00565"></a>00565 dup2(fds[0], SERVER_SOCKET_FD);
582
+ <a name="l00566"></a>00566
583
+ <a name="l00567"></a>00567 <span class="comment">// Close all unnecessary file descriptors</span>
584
+ <a name="l00568"></a>00568 <span class="keywordflow">for</span> (<span class="keywordtype">long</span> i = sysconf(_SC_OPEN_MAX) - 1; i &gt; SERVER_SOCKET_FD; i--) {
585
+ <a name="l00569"></a>00569 close(i);
586
+ <a name="l00570"></a>00570 }
587
+ <a name="l00571"></a>00571
588
+ <a name="l00572"></a>00572 execlp(
589
+ <a name="l00573"></a>00573 #<span class="keywordflow">if</span> 0
590
+ <a name="l00574"></a>00574 <span class="stringliteral">"valgrind"</span>,
591
+ <a name="l00575"></a>00575 <span class="stringliteral">"valgrind"</span>,
592
+ <a name="l00576"></a>00576 #<span class="keywordflow">else</span>
593
+ <a name="l00577"></a>00577 m_serverExecutable.c_str(),
594
+ <a name="l00578"></a>00578 <span class="preprocessor"> #endif</span>
595
+ <a name="l00579"></a>00579 <span class="preprocessor"></span> m_serverExecutable.c_str(),
596
+ <a name="l00580"></a>00580 <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(Passenger::getLogLevel()).c_str(),
597
+ <a name="l00581"></a>00581 m_spawnServerCommand.c_str(),
598
+ <a name="l00582"></a>00582 m_logFile.c_str(),
599
+ <a name="l00583"></a>00583 m_rubyCommand.c_str(),
600
+ <a name="l00584"></a>00584 m_user.c_str(),
601
+ <a name="l00585"></a>00585 statusReportFIFO.c_str(),
602
+ <a name="l00586"></a>00586 (<span class="keywordtype">char</span> *) 0);
603
+ <a name="l00587"></a>00587 <span class="keywordtype">int</span> e = errno;
604
+ <a name="l00588"></a>00588 fprintf(stderr, <span class="stringliteral">"*** Passenger ERROR (%s:%d):\n"</span>
605
+ <a name="l00589"></a>00589 <span class="stringliteral">"Cannot execute %s: %s (%d)\n"</span>,
606
+ <a name="l00590"></a>00590 __FILE__, __LINE__,
607
+ <a name="l00591"></a>00591 m_serverExecutable.c_str(), strerror(e), e);
608
+ <a name="l00592"></a>00592 fflush(stderr);
609
+ <a name="l00593"></a>00593 _exit(1);
610
+ <a name="l00594"></a>00594 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (pid == -1) { <span class="comment">// Error.</span>
611
+ <a name="l00595"></a>00595 syscalls::close(fds[0]);
612
+ <a name="l00596"></a>00596 syscalls::close(fds[1]);
613
+ <a name="l00597"></a>00597 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Cannot create a new process"</span>, errno);
614
+ <a name="l00598"></a>00598 } <span class="keywordflow">else</span> { <span class="comment">// Parent process.</span>
615
+ <a name="l00599"></a>00599 syscalls::close(fds[0]);
616
+ <a name="l00600"></a>00600 serverSocket = fds[1];
617
+ <a name="l00601"></a>00601
618
+ <a name="l00602"></a>00602 <span class="keywordtype">int</span> flags = fcntl(serverSocket, F_GETFD);
619
+ <a name="l00603"></a>00603 <span class="keywordflow">if</span> (flags != -1) {
620
+ <a name="l00604"></a>00604 fcntl(serverSocket, F_SETFD, flags | FD_CLOEXEC);
621
+ <a name="l00605"></a>00605 }
622
+ <a name="l00606"></a>00606
623
+ <a name="l00607"></a>00607 serverPid = pid;
624
+ <a name="l00608"></a>00608 }
625
+ <a name="l00609"></a>00609 }
626
+ <a name="l00610"></a>00610
627
+ <a name="l00611"></a>00611 <span class="keywordtype">void</span> createStatusReportFIFO() {
628
+ <a name="l00612"></a>00612 TRACE_POINT();
629
+ <a name="l00613"></a>00613 <span class="keywordtype">char</span> filename[PATH_MAX];
630
+ <a name="l00614"></a>00614 <span class="keywordtype">int</span> ret;
631
+ <a name="l00615"></a>00615 mode_t permissions;
632
+ <a name="l00616"></a>00616
633
+ <a name="l00617"></a>00617 createPassengerTempDir();
634
+ <a name="l00618"></a>00618
635
+ <a name="l00619"></a>00619 <span class="keywordflow">if</span> (m_user.empty()) {
636
+ <a name="l00620"></a>00620 permissions = S_IRUSR | S_IWUSR;
637
+ <a name="l00621"></a>00621 } <span class="keywordflow">else</span> {
638
+ <a name="l00622"></a>00622 permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
639
+ <a name="l00623"></a>00623 }
640
+ <a name="l00624"></a>00624
641
+ <a name="l00625"></a>00625 snprintf(filename, <span class="keyword">sizeof</span>(filename), <span class="stringliteral">"%s/status.fifo"</span>,
642
+ <a name="l00626"></a>00626 <a class="code" href="group__Support.html#g5d3a5c5fe2944a898e425e30b53ac0ac" title="Return the path name for the directory in which Phusion Passenger-specific temporary...">getPassengerTempDir</a>().c_str());
643
+ <a name="l00627"></a>00627 filename[PATH_MAX - 1] = <span class="charliteral">'\0'</span>;
644
+ <a name="l00628"></a>00628 <span class="keywordflow">do</span> {
645
+ <a name="l00629"></a>00629 ret = mkfifo(filename, permissions);
646
+ <a name="l00630"></a>00630 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
647
+ <a name="l00631"></a>00631 <span class="keywordflow">if</span> (ret == -1 &amp;&amp; errno != EEXIST) {
648
+ <a name="l00632"></a>00632 <span class="keywordtype">int</span> e = errno;
649
+ <a name="l00633"></a>00633 P_WARN(<span class="stringliteral">"*** WARNING: Could not create FIFO '"</span> &lt;&lt; filename &lt;&lt;
650
+ <a name="l00634"></a>00634 <span class="stringliteral">"': "</span> &lt;&lt; strerror(e) &lt;&lt; <span class="stringliteral">" ("</span> &lt;&lt; e &lt;&lt; <span class="stringliteral">")"</span> &lt;&lt; endl &lt;&lt;
651
+ <a name="l00635"></a>00635 <span class="stringliteral">"Disabling Passenger ApplicationPool status reporting."</span>);
652
+ <a name="l00636"></a>00636 statusReportFIFO = <span class="stringliteral">""</span>;
653
+ <a name="l00637"></a>00637 } <span class="keywordflow">else</span> {
654
+ <a name="l00638"></a>00638 statusReportFIFO = filename;
655
+ <a name="l00639"></a>00639
656
+ <a name="l00640"></a>00640 <span class="comment">// It seems that the permissions passed to mkfifo()</span>
657
+ <a name="l00641"></a>00641 <span class="comment">// aren't respected, so here we chmod the file.</span>
658
+ <a name="l00642"></a>00642 <span class="keywordflow">do</span> {
659
+ <a name="l00643"></a>00643 ret = chmod(filename, permissions);
660
+ <a name="l00644"></a>00644 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
661
+ <a name="l00645"></a>00645 }
662
+ <a name="l00646"></a>00646 }
663
+ <a name="l00647"></a>00647
664
+ <a name="l00648"></a>00648 <span class="keyword">public</span>:<span class="comment"></span>
665
+ <a name="l00649"></a>00649 <span class="comment"> /**</span>
666
+ <a name="l00650"></a>00650 <span class="comment"> * Create a new ApplicationPoolServer object.</span>
667
+ <a name="l00651"></a>00651 <span class="comment"> *</span>
668
+ <a name="l00652"></a>00652 <span class="comment"> * @param serverExecutable The filename of the ApplicationPool server</span>
669
+ <a name="l00653"></a>00653 <span class="comment"> * executable to use.</span>
670
+ <a name="l00654"></a>00654 <span class="comment"> * @param spawnServerCommand The filename of the spawn server to use.</span>
671
+ <a name="l00655"></a>00655 <span class="comment"> * @param logFile Specify a log file that the spawn server should use.</span>
672
+ <a name="l00656"></a>00656 <span class="comment"> * Messages on its standard output and standard error channels</span>
673
+ <a name="l00657"></a>00657 <span class="comment"> * will be written to this log file. If an empty string is</span>
674
+ <a name="l00658"></a>00658 <span class="comment"> * specified, no log file will be used, and the spawn server</span>
675
+ <a name="l00659"></a>00659 <span class="comment"> * will use the same standard output/error channels as the</span>
676
+ <a name="l00660"></a>00660 <span class="comment"> * current process.</span>
677
+ <a name="l00661"></a>00661 <span class="comment"> * @param rubyCommand The Ruby interpreter's command.</span>
678
+ <a name="l00662"></a>00662 <span class="comment"> * @param user The user that the spawn manager should run as. This</span>
679
+ <a name="l00663"></a>00663 <span class="comment"> * parameter only has effect if the current process is</span>
680
+ <a name="l00664"></a>00664 <span class="comment"> * running as root. If the empty string is given, or if</span>
681
+ <a name="l00665"></a>00665 <span class="comment"> * the &lt;tt&gt;user&lt;/tt&gt; is not a valid username, then</span>
682
+ <a name="l00666"></a>00666 <span class="comment"> * the spawn manager will be run as the current user.</span>
683
+ <a name="l00667"></a>00667 <span class="comment"> * @throws SystemException An error occured while trying to setup the spawn server</span>
684
+ <a name="l00668"></a>00668 <span class="comment"> * or the server socket.</span>
685
+ <a name="l00669"></a>00669 <span class="comment"> * @throws IOException The specified log file could not be opened.</span>
686
+ <a name="l00670"></a>00670 <span class="comment"> */</span>
687
+ <a name="l00671"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#2203db62a022579d569ceddff8ef6ca9">00671</a> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#2203db62a022579d569ceddff8ef6ca9" title="Create a new ApplicationPoolServer object.">ApplicationPoolServer</a>(<span class="keyword">const</span> <span class="keywordtype">string</span> &amp;serverExecutable,
688
+ <a name="l00672"></a>00672 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;spawnServerCommand,
689
+ <a name="l00673"></a>00673 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;logFile = <span class="stringliteral">""</span>,
690
+ <a name="l00674"></a>00674 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;rubyCommand = <span class="stringliteral">"ruby"</span>,
691
+ <a name="l00675"></a>00675 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;user = <span class="stringliteral">""</span>)
692
+ <a name="l00676"></a>00676 : m_serverExecutable(serverExecutable),
693
+ <a name="l00677"></a>00677 m_spawnServerCommand(spawnServerCommand),
694
+ <a name="l00678"></a>00678 m_logFile(logFile),
695
+ <a name="l00679"></a>00679 m_rubyCommand(rubyCommand),
696
+ <a name="l00680"></a>00680 m_user(user) {
697
+ <a name="l00681"></a>00681 TRACE_POINT();
698
+ <a name="l00682"></a>00682 serverSocket = -1;
699
+ <a name="l00683"></a>00683 serverPid = 0;
700
+ <a name="l00684"></a>00684 this_thread::disable_syscall_interruption dsi;
701
+ <a name="l00685"></a>00685 restartServer();
702
+ <a name="l00686"></a>00686 }
703
+ <a name="l00687"></a>00687
704
+ <a name="l00688"></a>00688 ~<a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a>() {
705
+ <a name="l00689"></a>00689 TRACE_POINT();
706
+ <a name="l00690"></a>00690 <span class="keywordflow">if</span> (serverSocket != -1) {
707
+ <a name="l00691"></a>00691 UPDATE_TRACE_POINT();
708
+ <a name="l00692"></a>00692 this_thread::disable_syscall_interruption dsi;
709
+ <a name="l00693"></a>00693 shutdownServer();
710
+ <a name="l00694"></a>00694 }
711
+ <a name="l00695"></a>00695 }
712
+ <a name="l00696"></a>00696 <span class="comment"></span>
713
+ <a name="l00697"></a>00697 <span class="comment"> /**</span>
714
+ <a name="l00698"></a>00698 <span class="comment"> * Connects to the server and returns a usable ApplicationPool object.</span>
715
+ <a name="l00699"></a>00699 <span class="comment"> * All cache/pool data of this ApplicationPool is actually stored on</span>
716
+ <a name="l00700"></a>00700 <span class="comment"> * the server and shared with other clients, but that is totally</span>
717
+ <a name="l00701"></a>00701 <span class="comment"> * transparent to the user of the ApplicationPool object.</span>
718
+ <a name="l00702"></a>00702 <span class="comment"> *</span>
719
+ <a name="l00703"></a>00703 <span class="comment"> * @note</span>
720
+ <a name="l00704"></a>00704 <span class="comment"> * All methods of the returned ApplicationPool object may throw</span>
721
+ <a name="l00705"></a>00705 <span class="comment"> * SystemException, IOException or boost::thread_interrupted.</span>
722
+ <a name="l00706"></a>00706 <span class="comment"> *</span>
723
+ <a name="l00707"></a>00707 <span class="comment"> * @warning</span>
724
+ <a name="l00708"></a>00708 <span class="comment"> * One may only use the returned ApplicationPool object for handling</span>
725
+ <a name="l00709"></a>00709 <span class="comment"> * one session at a time. For example, don't do stuff like this:</span>
726
+ <a name="l00710"></a>00710 <span class="comment"> * @code</span>
727
+ <a name="l00711"></a>00711 <span class="comment"> * ApplicationPoolPtr pool = server.connect();</span>
728
+ <a name="l00712"></a>00712 <span class="comment"> * Application::SessionPtr session1 = pool-&gt;get(...);</span>
729
+ <a name="l00713"></a>00713 <span class="comment"> * Application::SessionPtr session2 = pool-&gt;get(...);</span>
730
+ <a name="l00714"></a>00714 <span class="comment"> * @endcode</span>
731
+ <a name="l00715"></a>00715 <span class="comment"> * Otherwise, a deadlock can occur under certain circumstances.</span>
732
+ <a name="l00716"></a>00716 <span class="comment"> * @warning</span>
733
+ <a name="l00717"></a>00717 <span class="comment"> * Instead, one should call connect() multiple times:</span>
734
+ <a name="l00718"></a>00718 <span class="comment"> * @code</span>
735
+ <a name="l00719"></a>00719 <span class="comment"> * ApplicationPoolPtr pool1 = server.connect();</span>
736
+ <a name="l00720"></a>00720 <span class="comment"> * Application::SessionPtr session1 = pool1-&gt;get(...);</span>
737
+ <a name="l00721"></a>00721 <span class="comment"> * </span>
738
+ <a name="l00722"></a>00722 <span class="comment"> * ApplicationPoolPtr pool2 = server.connect();</span>
739
+ <a name="l00723"></a>00723 <span class="comment"> * Application::SessionPtr session2 = pool2-&gt;get(...);</span>
740
+ <a name="l00724"></a>00724 <span class="comment"> * @endcode</span>
741
+ <a name="l00725"></a>00725 <span class="comment"> *</span>
742
+ <a name="l00726"></a>00726 <span class="comment"> * @throws SystemException Something went wrong.</span>
743
+ <a name="l00727"></a>00727 <span class="comment"> * @throws IOException Something went wrong.</span>
744
+ <a name="l00728"></a>00728 <span class="comment"> */</span>
745
+ <a name="l00729"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#18f77057cc28e7924a8f4d1397aa0468">00729</a> ApplicationPoolPtr <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#18f77057cc28e7924a8f4d1397aa0468" title="Connects to the server and returns a usable ApplicationPool object.">connect</a>() {
746
+ <a name="l00730"></a>00730 TRACE_POINT();
747
+ <a name="l00731"></a>00731 <span class="keywordflow">try</span> {
748
+ <a name="l00732"></a>00732 this_thread::disable_syscall_interruption dsi;
749
+ <a name="l00733"></a>00733 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(serverSocket);
750
+ <a name="l00734"></a>00734 <span class="keywordtype">int</span> clientConnection;
751
+ <a name="l00735"></a>00735
752
+ <a name="l00736"></a>00736 <span class="comment">// Write some random data to wake up the server.</span>
753
+ <a name="l00737"></a>00737 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#069314e4c7e1fe8c8ab36e16d2cc5fef" title="Send a block of data over the underlying file descriptor.">writeRaw</a>(<span class="stringliteral">"x"</span>, 1);
754
+ <a name="l00738"></a>00738
755
+ <a name="l00739"></a>00739 clientConnection = channel.<a class="code" href="classPassenger_1_1MessageChannel.html#1561b7e4a0f4d39ea431f456e5655488" title="Receive a file descriptor, which had been passed over the underlying file descriptor...">readFileDescriptor</a>();
756
+ <a name="l00740"></a>00740 <span class="keywordflow">return</span> <a class="code" href="group__Support.html#g41b6c4a82fed72531a147de0505a8396" title="Convenience shortcut for creating a shared_ptr.">ptr</a>(<span class="keyword">new</span> Client(clientConnection));
757
+ <a name="l00741"></a>00741 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a> &amp;e) {
758
+ <a name="l00742"></a>00742 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SystemException.html" title="Represents an error returned by a system call or a standard library call.">SystemException</a>(<span class="stringliteral">"Could not connect to the ApplicationPool server"</span>, e.<a class="code" href="classPassenger_1_1SystemException.html#ee7a6672bf79b72a4c3ee70c57d6a47c" title="The value of errno at the time the error occured.">code</a>());
759
+ <a name="l00743"></a>00743 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a> &amp;e) {
760
+ <a name="l00744"></a>00744 <span class="keywordtype">string</span> message(<span class="stringliteral">"Could not connect to the ApplicationPool server: "</span>);
761
+ <a name="l00745"></a>00745 message.append(e.<a class="code" href="classPassenger_1_1IOException.html#1b65d0fdb9bc5136f5b7df759c14768a">what</a>());
762
+ <a name="l00746"></a>00746 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1IOException.html" title="Represents an error that occured during an I/O operation.">IOException</a>(message);
763
+ <a name="l00747"></a>00747 }
764
+ <a name="l00748"></a>00748 }
765
+ <a name="l00749"></a>00749 <span class="comment"></span>
766
+ <a name="l00750"></a>00750 <span class="comment"> /**</span>
767
+ <a name="l00751"></a>00751 <span class="comment"> * Detach the server, thereby telling it that we don't want to connect</span>
768
+ <a name="l00752"></a>00752 <span class="comment"> * to it anymore. This frees up some resources in the current process,</span>
769
+ <a name="l00753"></a>00753 <span class="comment"> * such as file descriptors.</span>
770
+ <a name="l00754"></a>00754 <span class="comment"> *</span>
771
+ <a name="l00755"></a>00755 <span class="comment"> * This method is particularily useful to Apache worker processes that</span>
772
+ <a name="l00756"></a>00756 <span class="comment"> * have just established a connection with the ApplicationPool server.</span>
773
+ <a name="l00757"></a>00757 <span class="comment"> * Any sessions that are opened prior to calling detach(), will keep</span>
774
+ <a name="l00758"></a>00758 <span class="comment"> * working even after a detach().</span>
775
+ <a name="l00759"></a>00759 <span class="comment"> *</span>
776
+ <a name="l00760"></a>00760 <span class="comment"> * This method may only be called once. The ApplicationPoolServer object</span>
777
+ <a name="l00761"></a>00761 <span class="comment"> * will become unusable once detach() has been called, so call connect()</span>
778
+ <a name="l00762"></a>00762 <span class="comment"> * before calling detach().</span>
779
+ <a name="l00763"></a>00763 <span class="comment"> */</span>
780
+ <a name="l00764"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce">00764</a> <span class="keywordtype">void</span> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce" title="Detach the server, thereby telling it that we don&amp;#39;t want to connect to it anymore...">detach</a>() {
781
+ <a name="l00765"></a>00765 TRACE_POINT();
782
+ <a name="l00766"></a>00766 <span class="keywordtype">int</span> ret;
783
+ <a name="l00767"></a>00767 <span class="keywordflow">do</span> {
784
+ <a name="l00768"></a>00768 ret = close(serverSocket);
785
+ <a name="l00769"></a>00769 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
786
+ <a name="l00770"></a>00770 serverSocket = -1;
787
+ <a name="l00771"></a>00771 }
788
+ <a name="l00772"></a>00772 };
789
+ <a name="l00773"></a>00773
790
+ <a name="l00774"></a>00774 <span class="keyword">typedef</span> shared_ptr&lt;ApplicationPoolServer&gt; ApplicationPoolServerPtr;
791
+ <a name="l00775"></a>00775
792
+ <a name="l00776"></a>00776 } <span class="comment">// namespace Passenger</span>
793
+ <a name="l00777"></a>00777
794
+ <a name="l00778"></a>00778 <span class="preprocessor">#endif </span><span class="comment">/* _PASSENGER_APPLICATION_POOL_SERVER_H_ */</span>
685
795
  </pre></div></div>
686
- <hr size="1"><address style="text-align: right;"><small>Generated on Mon Dec 15 15:27:24 2008 for Passenger by&nbsp;
796
+ <hr size="1"><address style="text-align: right;"><small>Generated on Fri Mar 13 19:24:32 2009 for Passenger by&nbsp;
687
797
  <a href="http://www.doxygen.org/index.html">
688
798
  <img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.5 </small></address>
689
799
  </body>