Skip to content
Browse files

Improve documentation.

  • Loading branch information...
1 parent 5fe3d4e commit 4d5a49571f11340523c065583262e9338838297a @FooBarWidget FooBarWidget committed
Showing with 7,552 additions and 1,614 deletions.
  1. +0 −2 .gitignore
  2. +461 −357 doc/cxxapi/ApplicationPoolClientServer_8h-source.html
  3. +370 −310 doc/cxxapi/ApplicationPool_8h-source.html
  4. +228 −215 doc/cxxapi/Application_8h-source.html
  5. +43 −42 doc/cxxapi/Configuration_8h-source.html
  6. +1 −1 doc/cxxapi/DummySpawnManager_8h-source.html
  7. +26 −5 doc/cxxapi/Exceptions_8h-source.html
  8. +1 −1 doc/cxxapi/Hooks_8h-source.html
  9. +413 −412 doc/cxxapi/MessageChannel_8h-source.html
  10. +146 −131 doc/cxxapi/SpawnManager_8h-source.html
  11. +115 −66 doc/cxxapi/Utils_8h-source.html
  12. +3 −1 doc/cxxapi/annotated.html
  13. +1 −1 doc/cxxapi/classPassenger_1_1Application-members.html
  14. +2 −2 doc/cxxapi/classPassenger_1_1Application.html
  15. +1 −1 doc/cxxapi/classPassenger_1_1ApplicationPool-members.html
  16. +11 −4 doc/cxxapi/classPassenger_1_1ApplicationPool.html
  17. +1 −1 doc/cxxapi/classPassenger_1_1ApplicationPoolServer-members.html
  18. +4 −4 doc/cxxapi/classPassenger_1_1ApplicationPoolServer.html
  19. +2 −1 doc/cxxapi/classPassenger_1_1Application_1_1Session-members.html
  20. +5 −1 doc/cxxapi/classPassenger_1_1Application_1_1Session.html
  21. +1 −1 doc/cxxapi/classPassenger_1_1DummySpawnManager-members.html
  22. +2 −2 doc/cxxapi/classPassenger_1_1DummySpawnManager.html
  23. +28 −0 doc/cxxapi/classPassenger_1_1FileNotFoundException-members.html
  24. +46 −0 doc/cxxapi/classPassenger_1_1FileNotFoundException.html
  25. +1 −0 doc/cxxapi/classPassenger_1_1FileNotFoundException__inherit__graph.map
  26. +1 −0 doc/cxxapi/classPassenger_1_1FileNotFoundException__inherit__graph.md5
  27. BIN doc/cxxapi/classPassenger_1_1FileNotFoundException__inherit__graph.png
  28. +1 −1 doc/cxxapi/classPassenger_1_1IOException-members.html
  29. +8 −3 doc/cxxapi/classPassenger_1_1IOException.html
  30. +1 −0 doc/cxxapi/classPassenger_1_1IOException__inherit__graph.map
  31. +1 −0 doc/cxxapi/classPassenger_1_1IOException__inherit__graph.md5
  32. BIN doc/cxxapi/classPassenger_1_1IOException__inherit__graph.png
  33. +1 −1 doc/cxxapi/classPassenger_1_1MessageChannel-members.html
  34. +3 −3 doc/cxxapi/classPassenger_1_1MessageChannel.html
  35. +28 −0 doc/cxxapi/classPassenger_1_1SpawnException-members.html
  36. +41 −0 doc/cxxapi/classPassenger_1_1SpawnException.html
  37. +2 −1 doc/cxxapi/classPassenger_1_1SpawnManager-members.html
  38. +28 −5 doc/cxxapi/classPassenger_1_1SpawnManager.html
  39. +1 −1 doc/cxxapi/classPassenger_1_1StandardApplicationPool-members.html
  40. +10 −3 doc/cxxapi/classPassenger_1_1StandardApplicationPool.html
  41. +1 −1 doc/cxxapi/classPassenger_1_1SystemException-members.html
  42. +1 −1 doc/cxxapi/classPassenger_1_1SystemException.html
  43. +2 −2 doc/cxxapi/definitions_8h-source.html
  44. +1 −1 doc/cxxapi/files.html
  45. +5 −2 doc/cxxapi/functions.html
  46. +5 −2 doc/cxxapi/functions_func.html
  47. +1 −1 doc/cxxapi/functions_type.html
  48. +1 −1 doc/cxxapi/graph_legend.html
  49. BIN doc/cxxapi/graph_legend.png
  50. +1 −1 doc/cxxapi/group__Configuration.html
  51. BIN doc/cxxapi/group__Configuration.png
  52. +1 −1 doc/cxxapi/group__Core.html
  53. BIN doc/cxxapi/group__Core.png
  54. +1 −1 doc/cxxapi/group__Exceptions.html
  55. +1 −1 doc/cxxapi/group__Hooks.html
  56. BIN doc/cxxapi/group__Hooks.png
  57. +186 −3 doc/cxxapi/group__Support.html
  58. +5 −1 doc/cxxapi/hierarchy.html
  59. +4 −2 doc/cxxapi/inherit__graph__5.map
  60. +1 −1 doc/cxxapi/inherit__graph__5.md5
  61. BIN doc/cxxapi/inherit__graph__5.png
  62. +2 −2 doc/cxxapi/inherits.html
  63. +1 −1 doc/cxxapi/main.html
  64. +2 −2 doc/cxxapi/modules.html
  65. +10 −4 doc/cxxapi/tree.html
  66. +1 −1 doc/definitions.h
  67. +158 −0 doc/rdoc/classes/ConditionVariable.html
  68. +113 −0 doc/rdoc/classes/GC.html
  69. +695 −0 doc/rdoc/classes/ModRails/AbstractServer.html
  70. +92 −0 doc/rdoc/classes/ModRails/AbstractServer/ServerAlreadyStarted.html
  71. +92 −0 doc/rdoc/classes/ModRails/AbstractServer/ServerNotStarted.html
  72. +96 −0 doc/rdoc/classes/ModRails/AbstractServer/UnknownMessage.html
  73. +204 −0 doc/rdoc/classes/ModRails/Application.html
  74. +264 −0 doc/rdoc/classes/ModRails/ApplicationSpawner.html
  75. +92 −0 doc/rdoc/classes/ModRails/ApplicationSpawner/SpawnError.html
  76. +92 −0 doc/rdoc/classes/ModRails/ApplicationSpawner/UserChangeError.html
  77. +203 −0 doc/rdoc/classes/ModRails/CGIFixed.html
  78. +361 −0 doc/rdoc/classes/ModRails/FrameworkSpawner.html
  79. +416 −0 doc/rdoc/classes/ModRails/MessageChannel.html
  80. +186 −0 doc/rdoc/classes/ModRails/RequestHandler.html
  81. +131 −0 doc/rdoc/classes/ModRails/RequestHandler/ResponseSender.html
  82. +191 −0 doc/rdoc/classes/ModRails/SpawnManager.html
  83. +215 −0 doc/rdoc/classes/ModRails/Utils.html
  84. +153 −0 doc/rdoc/classes/RakeExtensions.html
  85. +1 −0 doc/rdoc/created.rid
  86. +98 −0 doc/rdoc/files/lib/mod_rails/abstract_server_rb.html
  87. +92 −0 doc/rdoc/files/lib/mod_rails/application_rb.html
  88. +101 −0 doc/rdoc/files/lib/mod_rails/application_spawner_rb.html
  89. +97 −0 doc/rdoc/files/lib/mod_rails/cgi_fixed_rb.html
  90. +113 −0 doc/rdoc/files/lib/mod_rails/framework_spawner_rb.html
  91. +96 −0 doc/rdoc/files/lib/mod_rails/message_channel_rb.html
  92. +97 −0 doc/rdoc/files/lib/mod_rails/request_handler_rb.html
  93. +92 −0 doc/rdoc/files/lib/mod_rails/simple_benchmarking_rb.html
  94. +100 −0 doc/rdoc/files/lib/mod_rails/spawn_manager_rb.html
  95. +101 −0 doc/rdoc/files/lib/mod_rails/utils_rb.html
  96. +100 −0 doc/rdoc/files/lib/rake/extensions_rb.html
  97. +64 −0 doc/rdoc/fr_class_index.html
  98. +57 −0 doc/rdoc/fr_file_index.html
  99. +107 −0 doc/rdoc/fr_method_index.html
  100. +26 −0 doc/rdoc/index.html
  101. +175 −0 doc/rdoc/rdoc-style.css
  102. +4 −3 ext/apache2/ApplicationPoolClientServer.h
  103. +6 −0 ext/apache2/Utils.h
View
2 .gitignore
@@ -14,6 +14,4 @@ test/Apache2ModuleTests
test/stub/railsapp/log/*
test/stub/railsapp2/log/*
benchmark/DummyRequestHandler
-doc/rdoc
-doc/c++api
pkg
View
818 doc/cxxapi/ApplicationPoolClientServer_8h-source.html
@@ -77,368 +77,472 @@
<a name="l00062"></a>00062 <span class="comment"> *</span>
<a name="l00063"></a>00063 <span class="comment"> * @warning</span>
<a name="l00064"></a>00064 <span class="comment"> * ApplicationPoolServer uses threads internally. Threads will disappear after a fork(),</span>
-<a name="l00065"></a>00065 <span class="comment"> * so ApplicationPoolServer will become usable after a fork(). So in case of Apache with</span>
-<a name="l00066"></a>00066 <span class="comment"> * the prefork MPM, be sure to create an ApplicationPoolServer() &lt;em&gt;after&lt;/em&gt; Apache</span>
-<a name="l00067"></a>00067 <span class="comment"> * has daemonized.</span>
-<a name="l00068"></a>00068 <span class="comment"> *</span>
-<a name="l00069"></a>00069 <span class="comment"> * &lt;h2&gt;Implementation notes&lt;/h2&gt;</span>
-<a name="l00070"></a>00070 <span class="comment"> * Notice that ApplicationPoolServer does do not use TCP sockets at all, or even named Unix</span>
-<a name="l00071"></a>00071 <span class="comment"> * sockets, depite being a server that can handle multiple clients! So ApplicationPoolServer</span>
-<a name="l00072"></a>00072 <span class="comment"> * will expose no open ports or temporary Unix socket files. Only child processes are able</span>
-<a name="l00073"></a>00073 <span class="comment"> * to use the ApplicationPoolServer.</span>
-<a name="l00074"></a>00074 <span class="comment"> *</span>
-<a name="l00075"></a>00075 <span class="comment"> * This is implemented through anonymous Unix sockets (&lt;tt&gt;socketpair()&lt;/tt&gt;) and file descriptor</span>
-<a name="l00076"></a>00076 <span class="comment"> * passing. It allows one to emulate &lt;tt&gt;accept()&lt;/tt&gt;. During initialization,</span>
-<a name="l00077"></a>00077 <span class="comment"> * ApplicationPoolServer creates a pair of Unix sockets, one called &lt;tt&gt;serverSocket&lt;/tt&gt;</span>
-<a name="l00078"></a>00078 <span class="comment"> * and the other called &lt;tt&gt;connectSocket&lt;/tt&gt;. There is a thread which continuously</span>
-<a name="l00079"></a>00079 <span class="comment"> * listens on serverSocket for incoming data. The data itself is not important, because it</span>
-<a name="l00080"></a>00080 <span class="comment"> * only serves to wake up the thread. ApplicationPoolServer::connect() sends some data through</span>
-<a name="l00081"></a>00081 <span class="comment"> * connectSocket, which wakes up the server thread. The server thread will then create</span>
-<a name="l00082"></a>00082 <span class="comment"> * a pair of Unix sockets. One of them is passed through serverSocket. The other will be</span>
-<a name="l00083"></a>00083 <span class="comment"> * handled by a newly created client thread. So the socket that was passed through serverSocket</span>
-<a name="l00084"></a>00084 <span class="comment"> * is the client's connection to the server, while the other socket is the server's connection</span>
-<a name="l00085"></a>00085 <span class="comment"> * to the client.</span>
-<a name="l00086"></a>00086 <span class="comment"> *</span>
-<a name="l00087"></a>00087 <span class="comment"> * Note that serverSocket and connectSocket are solely used for setting up new connections</span>
-<a name="l00088"></a>00088 <span class="comment"> * ala accept(). They are not used for any actual data. In fact, they cannot be used in any</span>
-<a name="l00089"></a>00089 <span class="comment"> * other way without some sort of synchronization mechanism, because all child processes</span>
-<a name="l00090"></a>00090 <span class="comment"> * are connected to the same serverSocket. In contrast, ApplicationPool::connect() sets up</span>
-<a name="l00091"></a>00091 <span class="comment"> * a private communicate channel between the server and the current child process.</span>
-<a name="l00092"></a>00092 <span class="comment"> *</span>
-<a name="l00093"></a>00093 <span class="comment"> * Also note that each client is handled by a seperate thread. This is necessary because</span>
-<a name="l00094"></a>00094 <span class="comment"> * ApplicationPoolServer internally uses StandardApplicationPool, and the current algorithm</span>
-<a name="l00095"></a>00095 <span class="comment"> * for StandardApplicationPool::get() can block (in the case that the spawning limit has</span>
-<a name="l00096"></a>00096 <span class="comment"> * been exceeded). While it is possible to get around this problem without using threads,</span>
-<a name="l00097"></a>00097 <span class="comment"> * a thread-based implementation is easier to write.</span>
-<a name="l00098"></a>00098 <span class="comment"> *</span>
-<a name="l00099"></a>00099 <span class="comment"> * @ingroup Support</span>
-<a name="l00100"></a>00100 <span class="comment"> */</span>
-<a name="l00101"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html">00101</a> <span class="keyword">class </span><a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a> {
-<a name="l00102"></a>00102 <span class="keyword">private</span>:<span class="comment"></span>
-<a name="l00103"></a>00103 <span class="comment"> /**</span>
-<a name="l00104"></a>00104 <span class="comment"> * Contains data shared between RemoteSession and Client.</span>
-<a name="l00105"></a>00105 <span class="comment"> * Since RemoteSession and Client have different life times, i.e. one may be</span>
-<a name="l00106"></a>00106 <span class="comment"> * destroyed before the other, they both use a smart pointer that points to</span>
-<a name="l00107"></a>00107 <span class="comment"> * a SharedData. This way, the SharedData object is only destroyed when</span>
-<a name="l00108"></a>00108 <span class="comment"> * both the RemoteSession and the Client object has been destroyed.</span>
-<a name="l00109"></a>00109 <span class="comment"> */</span>
-<a name="l00110"></a>00110 <span class="keyword">struct </span>SharedData {<span class="comment"></span>
-<a name="l00111"></a>00111 <span class="comment"> /**</span>
-<a name="l00112"></a>00112 <span class="comment"> * The socket connection to the server, as was established by</span>
-<a name="l00113"></a>00113 <span class="comment"> * ApplicationPoolServer::connect().</span>
-<a name="l00114"></a>00114 <span class="comment"> */</span>
-<a name="l00115"></a>00115 <span class="keywordtype">int</span> server;
-<a name="l00116"></a>00116
-<a name="l00117"></a>00117 ~SharedData() {
-<a name="l00118"></a>00118 close(server);
-<a name="l00119"></a>00119 }
-<a name="l00120"></a>00120 };
-<a name="l00121"></a>00121
-<a name="l00122"></a>00122 <span class="keyword">typedef</span> shared_ptr&lt;SharedData&gt; SharedDataPtr;
-<a name="l00123"></a>00123 <span class="comment"></span>
-<a name="l00124"></a>00124 <span class="comment"> /**</span>
-<a name="l00125"></a>00125 <span class="comment"> * An Application::Session which works together with ApplicationPoolServer.</span>
-<a name="l00126"></a>00126 <span class="comment"> * </span>
-<a name="l00127"></a>00127 <span class="comment"> */</span>
-<a name="l00128"></a>00128 <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 application instance.">Application</a>::Session {
-<a name="l00129"></a>00129 <span class="keyword">private</span>:
-<a name="l00130"></a>00130 SharedDataPtr data;
-<a name="l00131"></a>00131 <span class="keywordtype">int</span> id;
-<a name="l00132"></a>00132 <span class="keywordtype">int</span> reader;
-<a name="l00133"></a>00133 <span class="keywordtype">int</span> writer;
-<a name="l00134"></a>00134 <span class="keyword">public</span>:
-<a name="l00135"></a>00135 RemoteSession(SharedDataPtr data, <span class="keywordtype">int</span> <span class="keywordtype">id</span>, <span class="keywordtype">int</span> reader, <span class="keywordtype">int</span> writer) {
-<a name="l00136"></a>00136 this-&gt;data = data;
-<a name="l00137"></a>00137 this-&gt;<span class="keywordtype">id</span> = id;
-<a name="l00138"></a>00138 this-&gt;reader = reader;
-<a name="l00139"></a>00139 this-&gt;writer = writer;
-<a name="l00140"></a>00140 }
-<a name="l00141"></a>00141
-<a name="l00142"></a>00142 <span class="keyword">virtual</span> ~RemoteSession() {
-<a name="l00143"></a>00143 closeReader();
-<a name="l00144"></a>00144 closeWriter();
-<a name="l00145"></a>00145 <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>, toString(<span class="keywordtype">id</span>).c_str(), NULL);
-<a name="l00146"></a>00146 }
-<a name="l00147"></a>00147
-<a name="l00148"></a>00148 <span class="keyword">virtual</span> <span class="keywordtype">int</span> getReader() {
-<a name="l00149"></a>00149 <span class="keywordflow">return</span> reader;
+<a name="l00065"></a>00065 <span class="comment"> * so ApplicationPoolServer will become usable as a server after a fork(). After a fork(),</span>
+<a name="l00066"></a>00066 <span class="comment"> * you can still call connect() (and, of course, detach()), but the same</span>
+<a name="l00067"></a>00067 <span class="comment"> * ApplicationPoolServer better still be running in the parent process. So in case of</span>
+<a name="l00068"></a>00068 <span class="comment"> * Apache with the prefork MPM, be sure to create an ApplicationPoolServer</span>
+<a name="l00069"></a>00069 <span class="comment"> * &lt;em&gt;after&lt;/em&gt; Apache has daemonized.</span>
+<a name="l00070"></a>00070 <span class="comment"> *</span>
+<a name="l00071"></a>00071 <span class="comment"> * &lt;h2&gt;Implementation notes&lt;/h2&gt;</span>
+<a name="l00072"></a>00072 <span class="comment"> * Notice that ApplicationPoolServer does do not use TCP sockets at all, or even named Unix</span>
+<a name="l00073"></a>00073 <span class="comment"> * sockets, depite being a server that can handle multiple clients! So ApplicationPoolServer</span>
+<a name="l00074"></a>00074 <span class="comment"> * will expose no open ports or temporary Unix socket files. Only child processes are able</span>
+<a name="l00075"></a>00075 <span class="comment"> * to use the ApplicationPoolServer.</span>
+<a name="l00076"></a>00076 <span class="comment"> *</span>
+<a name="l00077"></a>00077 <span class="comment"> * This is implemented through anonymous Unix sockets (&lt;tt&gt;socketpair()&lt;/tt&gt;) and file descriptor</span>
+<a name="l00078"></a>00078 <span class="comment"> * passing. It allows one to emulate &lt;tt&gt;accept()&lt;/tt&gt;. During initialization,</span>
+<a name="l00079"></a>00079 <span class="comment"> * ApplicationPoolServer creates a pair of Unix sockets, one called &lt;tt&gt;serverSocket&lt;/tt&gt;</span>
+<a name="l00080"></a>00080 <span class="comment"> * and the other called &lt;tt&gt;connectSocket&lt;/tt&gt;. There is a thread which continuously</span>
+<a name="l00081"></a>00081 <span class="comment"> * listens on serverSocket for incoming data. The data itself is not important, because it</span>
+<a name="l00082"></a>00082 <span class="comment"> * only serves to wake up the thread. ApplicationPoolServer::connect() sends some data through</span>
+<a name="l00083"></a>00083 <span class="comment"> * connectSocket, which wakes up the server thread. The server thread will then create</span>
+<a name="l00084"></a>00084 <span class="comment"> * a pair of Unix sockets. One of them is passed through serverSocket. The other will be</span>
+<a name="l00085"></a>00085 <span class="comment"> * handled by a newly created client thread. So the socket that was passed through serverSocket</span>
+<a name="l00086"></a>00086 <span class="comment"> * is the client's connection to the server, while the other socket is the server's connection</span>
+<a name="l00087"></a>00087 <span class="comment"> * to the client.</span>
+<a name="l00088"></a>00088 <span class="comment"> *</span>
+<a name="l00089"></a>00089 <span class="comment"> * Note that serverSocket and connectSocket are solely used for setting up new connections</span>
+<a name="l00090"></a>00090 <span class="comment"> * ala accept(). They are not used for any actual data. In fact, they cannot be used in any</span>
+<a name="l00091"></a>00091 <span class="comment"> * other way without some sort of inter-process synchronization mechanism, because all</span>
+<a name="l00092"></a>00092 <span class="comment"> * child processes are connected to the same serverSocket. In contrast,</span>
+<a name="l00093"></a>00093 <span class="comment"> * ApplicationPoolServer::connect() allows one to setup a private communicate channel between</span>
+<a name="l00094"></a>00094 <span class="comment"> * the server and the current child process.</span>
+<a name="l00095"></a>00095 <span class="comment"> *</span>
+<a name="l00096"></a>00096 <span class="comment"> * Also note that each client is handled by a seperate thread. This is necessary because</span>
+<a name="l00097"></a>00097 <span class="comment"> * ApplicationPoolServer internally uses StandardApplicationPool, and the current algorithm</span>
+<a name="l00098"></a>00098 <span class="comment"> * for StandardApplicationPool::get() can block (in the case that the spawning limit has</span>
+<a name="l00099"></a>00099 <span class="comment"> * been exceeded). While it is possible to get around this problem without using threads,</span>
+<a name="l00100"></a>00100 <span class="comment"> * a thread-based implementation is easier to write.</span>
+<a name="l00101"></a>00101 <span class="comment"> *</span>
+<a name="l00102"></a>00102 <span class="comment"> * @ingroup Support</span>
+<a name="l00103"></a>00103 <span class="comment"> */</span>
+<a name="l00104"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html">00104</a> <span class="keyword">class </span><a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a> {
+<a name="l00105"></a>00105 <span class="keyword">private</span>:<span class="comment"></span>
+<a name="l00106"></a>00106 <span class="comment"> /**</span>
+<a name="l00107"></a>00107 <span class="comment"> * Contains data shared between RemoteSession and Client.</span>
+<a name="l00108"></a>00108 <span class="comment"> * Since RemoteSession and Client have different life times, i.e. one may be</span>
+<a name="l00109"></a>00109 <span class="comment"> * destroyed before the other, they both use a smart pointer that points to</span>
+<a name="l00110"></a>00110 <span class="comment"> * a SharedData. This way, the SharedData object is only destroyed when</span>
+<a name="l00111"></a>00111 <span class="comment"> * both the RemoteSession and the Client object has been destroyed.</span>
+<a name="l00112"></a>00112 <span class="comment"> */</span>
+<a name="l00113"></a>00113 <span class="keyword">struct </span>SharedData {<span class="comment"></span>
+<a name="l00114"></a>00114 <span class="comment"> /**</span>
+<a name="l00115"></a>00115 <span class="comment"> * The socket connection to the server, as was established by</span>
+<a name="l00116"></a>00116 <span class="comment"> * ApplicationPoolServer::connect().</span>
+<a name="l00117"></a>00117 <span class="comment"> */</span>
+<a name="l00118"></a>00118 <span class="keywordtype">int</span> server;
+<a name="l00119"></a>00119
+<a name="l00120"></a>00120 ~SharedData() {
+<a name="l00121"></a>00121 close(server);
+<a name="l00122"></a>00122 }
+<a name="l00123"></a>00123 };
+<a name="l00124"></a>00124
+<a name="l00125"></a>00125 <span class="keyword">typedef</span> shared_ptr&lt;SharedData&gt; SharedDataPtr;
+<a name="l00126"></a>00126 <span class="comment"></span>
+<a name="l00127"></a>00127 <span class="comment"> /**</span>
+<a name="l00128"></a>00128 <span class="comment"> * An Application::Session which works together with ApplicationPoolServer.</span>
+<a name="l00129"></a>00129 <span class="comment"> */</span>
+<a name="l00130"></a>00130 <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 application instance.">Application</a>::Session {
+<a name="l00131"></a>00131 <span class="keyword">private</span>:
+<a name="l00132"></a>00132 SharedDataPtr data;
+<a name="l00133"></a>00133 <span class="keywordtype">int</span> id;
+<a name="l00134"></a>00134 <span class="keywordtype">int</span> reader;
+<a name="l00135"></a>00135 <span class="keywordtype">int</span> writer;
+<a name="l00136"></a>00136 pid_t pid;
+<a name="l00137"></a>00137 <span class="keyword">public</span>:
+<a name="l00138"></a>00138 RemoteSession(SharedDataPtr data, pid_t pid, <span class="keywordtype">int</span> <span class="keywordtype">id</span>, <span class="keywordtype">int</span> reader, <span class="keywordtype">int</span> writer) {
+<a name="l00139"></a>00139 this-&gt;data = data;
+<a name="l00140"></a>00140 this-&gt;pid = pid;
+<a name="l00141"></a>00141 this-&gt;<span class="keywordtype">id</span> = id;
+<a name="l00142"></a>00142 this-&gt;reader = reader;
+<a name="l00143"></a>00143 this-&gt;writer = writer;
+<a name="l00144"></a>00144 }
+<a name="l00145"></a>00145
+<a name="l00146"></a>00146 <span class="keyword">virtual</span> ~RemoteSession() {
+<a name="l00147"></a>00147 closeReader();
+<a name="l00148"></a>00148 closeWriter();
+<a name="l00149"></a>00149 <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);
<a name="l00150"></a>00150 }
<a name="l00151"></a>00151
-<a name="l00152"></a>00152 <span class="keyword">virtual</span> <span class="keywordtype">void</span> closeReader() {
-<a name="l00153"></a>00153 <span class="keywordflow">if</span> (reader != -1) {
-<a name="l00154"></a>00154 close(reader);
-<a name="l00155"></a>00155 reader = -1;
-<a name="l00156"></a>00156 }
-<a name="l00157"></a>00157 }
-<a name="l00158"></a>00158
-<a name="l00159"></a>00159 <span class="keyword">virtual</span> <span class="keywordtype">int</span> getWriter() {
-<a name="l00160"></a>00160 <span class="keywordflow">return</span> writer;
+<a name="l00152"></a>00152 <span class="keyword">virtual</span> <span class="keywordtype">int</span> getReader() {
+<a name="l00153"></a>00153 <span class="keywordflow">return</span> reader;
+<a name="l00154"></a>00154 }
+<a name="l00155"></a>00155
+<a name="l00156"></a>00156 <span class="keyword">virtual</span> <span class="keywordtype">void</span> closeReader() {
+<a name="l00157"></a>00157 <span class="keywordflow">if</span> (reader != -1) {
+<a name="l00158"></a>00158 close(reader);
+<a name="l00159"></a>00159 reader = -1;
+<a name="l00160"></a>00160 }
<a name="l00161"></a>00161 }
<a name="l00162"></a>00162
-<a name="l00163"></a>00163 <span class="keyword">virtual</span> <span class="keywordtype">void</span> closeWriter() {
-<a name="l00164"></a>00164 <span class="keywordflow">if</span> (writer != -1) {
-<a name="l00165"></a>00165 close(writer);
-<a name="l00166"></a>00166 writer = -1;
-<a name="l00167"></a>00167 }
-<a name="l00168"></a>00168 }
-<a name="l00169"></a>00169 };
-<a name="l00170"></a>00170 <span class="comment"></span>
-<a name="l00171"></a>00171 <span class="comment"> /**</span>
-<a name="l00172"></a>00172 <span class="comment"> * An ApplicationPool implementation that works together with ApplicationPoolServer.</span>
-<a name="l00173"></a>00173 <span class="comment"> * It doesn't do much by itself, its job is mostly to forward queries/commands to</span>
-<a name="l00174"></a>00174 <span class="comment"> * the server and returning the result. Most of the logic is in the server.</span>
-<a name="l00175"></a>00175 <span class="comment"> */</span>
-<a name="l00176"></a>00176 <span class="keyword">class </span>Client: <span class="keyword">public</span> <a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a> {
-<a name="l00177"></a>00177 <span class="keyword">private</span>:
-<a name="l00178"></a>00178 SharedDataPtr data;
-<a name="l00179"></a>00179
-<a name="l00180"></a>00180 <span class="keyword">public</span>:<span class="comment"></span>
-<a name="l00181"></a>00181 <span class="comment"> /**</span>
-<a name="l00182"></a>00182 <span class="comment"> * Create a new Client.</span>
-<a name="l00183"></a>00183 <span class="comment"> *</span>
-<a name="l00184"></a>00184 <span class="comment"> * @param sock The newly established socket connection with the ApplicationPoolServer.</span>
-<a name="l00185"></a>00185 <span class="comment"> */</span>
-<a name="l00186"></a>00186 Client(<span class="keywordtype">int</span> sock) {
-<a name="l00187"></a>00187 data = ptr(<span class="keyword">new</span> SharedData());
-<a name="l00188"></a>00188 data-&gt;server = sock;
-<a name="l00189"></a>00189 }
-<a name="l00190"></a>00190
-<a name="l00191"></a>00191 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMax(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max) {
-<a name="l00192"></a>00192 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
-<a name="l00193"></a>00193 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>, toString(max).c_str(), NULL);
-<a name="l00194"></a>00194 }
-<a name="l00195"></a>00195
-<a name="l00196"></a>00196 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> getActive()<span class="keyword"> const </span>{
-<a name="l00197"></a>00197 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
-<a name="l00198"></a>00198 vector&lt;string&gt; args;
-<a name="l00199"></a>00199
-<a name="l00200"></a>00200 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);
-<a name="l00201"></a>00201 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Receive a message from the underlying file descriptor.">read</a>(args);
-<a name="l00202"></a>00202 <span class="keywordflow">return</span> atoi(args[0].c_str());
-<a name="l00203"></a>00203 }
-<a name="l00204"></a>00204
-<a name="l00205"></a>00205 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> getCount()<span class="keyword"> const </span>{
-<a name="l00206"></a>00206 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
-<a name="l00207"></a>00207 vector&lt;string&gt; args;
-<a name="l00208"></a>00208
-<a name="l00209"></a>00209 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);
-<a name="l00210"></a>00210 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Receive a message from the underlying file descriptor.">read</a>(args);
-<a name="l00211"></a>00211 <span class="keywordflow">return</span> atoi(args[0].c_str());
-<a name="l00212"></a>00212 }
-<a name="l00213"></a>00213
-<a name="l00214"></a>00214 <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> <span class="keywordtype">string</span> &amp;appRoot, <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;user = <span class="stringliteral">""</span>, <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;group = <span class="stringliteral">""</span>) {
-<a name="l00215"></a>00215 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
-<a name="l00216"></a>00216 vector&lt;string&gt; args;
-<a name="l00217"></a>00217 <span class="keywordtype">int</span> reader, writer;
-<a name="l00218"></a>00218
-<a name="l00219"></a>00219 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(), user.c_str(), group.c_str(), NULL);
-<a name="l00220"></a>00220 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Receive a message from the underlying file descriptor.">read</a>(args);
-<a name="l00221"></a>00221 reader = 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>();
-<a name="l00222"></a>00222 writer = 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>();
-<a name="l00223"></a>00223 <span class="keywordflow">return</span> ptr(<span class="keyword">new</span> RemoteSession(data, atoi(args[0].c_str()), reader, writer));
-<a name="l00224"></a>00224 }
-<a name="l00225"></a>00225 };
-<a name="l00226"></a>00226 <span class="comment"></span>
-<a name="l00227"></a>00227 <span class="comment"> /**</span>
-<a name="l00228"></a>00228 <span class="comment"> * Contains information about exactly one client.</span>
-<a name="l00229"></a>00229 <span class="comment"> */</span>
-<a name="l00230"></a>00230 <span class="keyword">struct </span>ClientInfo {<span class="comment"></span>
-<a name="l00231"></a>00231 <span class="comment"> /** The connection to the client. */</span>
-<a name="l00232"></a>00232 <span class="keywordtype">int</span> fd;<span class="comment"></span>
-<a name="l00233"></a>00233 <span class="comment"> /** The thread which handles the client. */</span>
-<a name="l00234"></a>00234 thread *thr;
-<a name="l00235"></a>00235
-<a name="l00236"></a>00236 ~ClientInfo() {
-<a name="l00237"></a>00237 close(fd);
-<a name="l00238"></a>00238 <span class="keyword">delete</span> thr;
-<a name="l00239"></a>00239 }
-<a name="l00240"></a>00240 };
-<a name="l00241"></a>00241
-<a name="l00242"></a>00242 <span class="keyword">typedef</span> shared_ptr&lt;ClientInfo&gt; ClientInfoPtr;
-<a name="l00243"></a>00243
-<a name="l00244"></a>00244 <a class="code" href="classPassenger_1_1StandardApplicationPool.html" title="A standard implementation of ApplicationPool for single-process environments.">StandardApplicationPool</a> pool;
-<a name="l00245"></a>00245 <span class="keywordtype">int</span> serverSocket;
-<a name="l00246"></a>00246 <span class="keywordtype">int</span> connectSocket;
-<a name="l00247"></a>00247 <span class="keywordtype">bool</span> done, detached;
-<a name="l00248"></a>00248
-<a name="l00249"></a>00249 mutex lock;
-<a name="l00250"></a>00250 thread *serverThread;
-<a name="l00251"></a>00251 set&lt;ClientInfoPtr&gt; clients;
-<a name="l00252"></a>00252
-<a name="l00253"></a>00253 <span class="comment">// TODO: check for exceptions in threads, possibly forwarding them</span>
-<a name="l00254"></a>00254 <span class="comment"></span>
-<a name="l00255"></a>00255 <span class="comment"> /**</span>
-<a name="l00256"></a>00256 <span class="comment"> * The entry point of the server thread which sets up private connections.</span>
-<a name="l00257"></a>00257 <span class="comment"> * See the class overview's implementation notes for details.</span>
-<a name="l00258"></a>00258 <span class="comment"> */</span>
-<a name="l00259"></a>00259 <span class="keywordtype">void</span> serverThreadMainLoop() {
-<a name="l00260"></a>00260 <span class="keywordflow">while</span> (!done) {
-<a name="l00261"></a>00261 <span class="keywordtype">int</span> fds[2], ret;
-<a name="l00262"></a>00262 <span class="keywordtype">char</span> x;
-<a name="l00263"></a>00263
-<a name="l00264"></a>00264 <span class="comment">// The received data only serves to wake up the server socket,</span>
-<a name="l00265"></a>00265 <span class="comment">// and is not important.</span>
-<a name="l00266"></a>00266 <span class="keywordflow">do</span> {
-<a name="l00267"></a>00267 ret = read(serverSocket, &amp;x, 1);
-<a name="l00268"></a>00268 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
-<a name="l00269"></a>00269 <span class="keywordflow">if</span> (ret == 0) {
-<a name="l00270"></a>00270 <span class="keywordflow">break</span>;
-<a name="l00271"></a>00271 }
-<a name="l00272"></a>00272
-<a name="l00273"></a>00273 socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
-<a name="l00274"></a>00274 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a>(serverSocket).writeFileDescriptor(fds[1]);
-<a name="l00275"></a>00275 close(fds[1]);
-<a name="l00276"></a>00276
-<a name="l00277"></a>00277 ClientInfoPtr info(<span class="keyword">new</span> ClientInfo());
-<a name="l00278"></a>00278 info-&gt;fd = fds[0];
-<a name="l00279"></a>00279 info-&gt;thr = <span class="keyword">new</span> thread(bind(&amp;ApplicationPoolServer::clientThreadMainLoop, <span class="keyword">this</span>, info));
-<a name="l00280"></a>00280 mutex::scoped_lock l(lock);
-<a name="l00281"></a>00281 clients.insert(info);
-<a name="l00282"></a>00282 }
-<a name="l00283"></a>00283 }
-<a name="l00284"></a>00284 <span class="comment"></span>
-<a name="l00285"></a>00285 <span class="comment"> /**</span>
-<a name="l00286"></a>00286 <span class="comment"> * The entry point of a thread which handles exactly one client.</span>
-<a name="l00287"></a>00287 <span class="comment"> */</span>
-<a name="l00288"></a>00288 <span class="keywordtype">void</span> clientThreadMainLoop(ClientInfoPtr client) {
-<a name="l00289"></a>00289 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(client-&gt;fd);
-<a name="l00290"></a>00290 vector&lt;string&gt; args;
-<a name="l00291"></a>00291 map&lt;int, Application::SessionPtr&gt; sessions;
-<a name="l00292"></a>00292 <span class="keywordtype">int</span> lastID = 0;
-<a name="l00293"></a>00293
+<a name="l00163"></a>00163 <span class="keyword">virtual</span> <span class="keywordtype">int</span> getWriter() {
+<a name="l00164"></a>00164 <span class="keywordflow">return</span> writer;
+<a name="l00165"></a>00165 }
+<a name="l00166"></a>00166
+<a name="l00167"></a>00167 <span class="keyword">virtual</span> <span class="keywordtype">void</span> closeWriter() {
+<a name="l00168"></a>00168 <span class="keywordflow">if</span> (writer != -1) {
+<a name="l00169"></a>00169 close(writer);
+<a name="l00170"></a>00170 writer = -1;
+<a name="l00171"></a>00171 }
+<a name="l00172"></a>00172 }
+<a name="l00173"></a>00173
+<a name="l00174"></a>00174 <span class="keyword">virtual</span> pid_t getPid() {
+<a name="l00175"></a>00175 <span class="keywordflow">return</span> pid;
+<a name="l00176"></a>00176 }
+<a name="l00177"></a>00177 };
+<a name="l00178"></a>00178 <span class="comment"></span>
+<a name="l00179"></a>00179 <span class="comment"> /**</span>
+<a name="l00180"></a>00180 <span class="comment"> * An ApplicationPool implementation that works together with ApplicationPoolServer.</span>
+<a name="l00181"></a>00181 <span class="comment"> * It doesn't do much by itself, its job is mostly to forward queries/commands to</span>
+<a name="l00182"></a>00182 <span class="comment"> * the server and returning the result. Most of the logic is in the server.</span>
+<a name="l00183"></a>00183 <span class="comment"> */</span>
+<a name="l00184"></a>00184 <span class="keyword">class </span>Client: <span class="keyword">public</span> <a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a> {
+<a name="l00185"></a>00185 <span class="keyword">private</span>:
+<a name="l00186"></a>00186 SharedDataPtr data;
+<a name="l00187"></a>00187
+<a name="l00188"></a>00188 <span class="keyword">public</span>:<span class="comment"></span>
+<a name="l00189"></a>00189 <span class="comment"> /**</span>
+<a name="l00190"></a>00190 <span class="comment"> * Create a new Client.</span>
+<a name="l00191"></a>00191 <span class="comment"> *</span>
+<a name="l00192"></a>00192 <span class="comment"> * @param sock The newly established socket connection with the ApplicationPoolServer.</span>
+<a name="l00193"></a>00193 <span class="comment"> */</span>
+<a name="l00194"></a>00194 Client(<span class="keywordtype">int</span> sock) {
+<a name="l00195"></a>00195 data = <a class="code" href="group__Support.html#g41b6c4a82fed72531a147de0505a8396" title="Convenience shortcut for creating a shared_ptr.">ptr</a>(<span class="keyword">new</span> SharedData());
+<a name="l00196"></a>00196 data-&gt;server = sock;
+<a name="l00197"></a>00197 }
+<a name="l00198"></a>00198
+<a name="l00199"></a>00199 <span class="keyword">virtual</span> <span class="keywordtype">void</span> setMax(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max) {
+<a name="l00200"></a>00200 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
+<a name="l00201"></a>00201 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);
+<a name="l00202"></a>00202 }
+<a name="l00203"></a>00203
+<a name="l00204"></a>00204 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> getActive()<span class="keyword"> const </span>{
+<a name="l00205"></a>00205 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
+<a name="l00206"></a>00206 vector&lt;string&gt; args;
+<a name="l00207"></a>00207
+<a name="l00208"></a>00208 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);
+<a name="l00209"></a>00209 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Receive a message from the underlying file descriptor.">read</a>(args);
+<a name="l00210"></a>00210 <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());
+<a name="l00211"></a>00211 }
+<a name="l00212"></a>00212
+<a name="l00213"></a>00213 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> getCount()<span class="keyword"> const </span>{
+<a name="l00214"></a>00214 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
+<a name="l00215"></a>00215 vector&lt;string&gt; args;
+<a name="l00216"></a>00216
+<a name="l00217"></a>00217 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);
+<a name="l00218"></a>00218 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Receive a message from the underlying file descriptor.">read</a>(args);
+<a name="l00219"></a>00219 <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());
+<a name="l00220"></a>00220 }
+<a name="l00221"></a>00221
+<a name="l00222"></a>00222 <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> <span class="keywordtype">string</span> &amp;appRoot, <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;user = <span class="stringliteral">""</span>, <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;group = <span class="stringliteral">""</span>) {
+<a name="l00223"></a>00223 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(data-&gt;server);
+<a name="l00224"></a>00224 vector&lt;string&gt; args;
+<a name="l00225"></a>00225 <span class="keywordtype">int</span> reader, writer;
+<a name="l00226"></a>00226
+<a name="l00227"></a>00227 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(), user.c_str(), group.c_str(), NULL);
+<a name="l00228"></a>00228 <span class="keywordflow">if</span> (!channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Receive a message from the underlying file descriptor.">read</a>(args)) {
+<a name="l00229"></a>00229 <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 closed the connection."</span>);
+<a name="l00230"></a>00230 }
+<a name="l00231"></a>00231 <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"ok"</span>) {
+<a name="l00232"></a>00232 reader = 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>();
+<a name="l00233"></a>00233 writer = 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>();
+<a name="l00234"></a>00234 <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(data, <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]), reader, writer));
+<a name="l00235"></a>00235 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"SpawnException"</span>) {
+<a name="l00236"></a>00236 <span class="keywordflow">throw</span> <a class="code" href="classPassenger_1_1SpawnException.html" title="Thrown when SpawnManager or ApplicationPool fail to spawn an application instance...">SpawnException</a>(args[1]);
+<a name="l00237"></a>00237 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"IOException"</span>) {
+<a name="l00238"></a>00238 <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]);
+<a name="l00239"></a>00239 } <span class="keywordflow">else</span> {
+<a name="l00240"></a>00240 <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 an unknown message."</span>);
+<a name="l00241"></a>00241 }
+<a name="l00242"></a>00242 }
+<a name="l00243"></a>00243 };
+<a name="l00244"></a>00244 <span class="comment"></span>
+<a name="l00245"></a>00245 <span class="comment"> /**</span>
+<a name="l00246"></a>00246 <span class="comment"> * Contains information about exactly one client.</span>
+<a name="l00247"></a>00247 <span class="comment"> */</span>
+<a name="l00248"></a>00248 <span class="keyword">struct </span>ClientInfo {<span class="comment"></span>
+<a name="l00249"></a>00249 <span class="comment"> /** The connection to the client. */</span>
+<a name="l00250"></a>00250 <span class="keywordtype">int</span> fd;<span class="comment"></span>
+<a name="l00251"></a>00251 <span class="comment"> /** The thread which handles the client. */</span>
+<a name="l00252"></a>00252 thread *thr;
+<a name="l00253"></a>00253 <span class="keywordtype">bool</span> detached;
+<a name="l00254"></a>00254
+<a name="l00255"></a>00255 ClientInfo() {
+<a name="l00256"></a>00256 detached = <span class="keyword">false</span>;
+<a name="l00257"></a>00257 }
+<a name="l00258"></a>00258
+<a name="l00259"></a>00259 <span class="keywordtype">void</span> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce" title="Detach the server by freeing up some server resources such as file descriptors.">detach</a>() {
+<a name="l00260"></a>00260 detached = <span class="keyword">true</span>;
+<a name="l00261"></a>00261 }
+<a name="l00262"></a>00262
+<a name="l00263"></a>00263 ~ClientInfo() {
+<a name="l00264"></a>00264 close(fd);
+<a name="l00265"></a>00265 <span class="comment">// For some reason, joining or deleting (detaching)</span>
+<a name="l00266"></a>00266 <span class="comment">// the thread after fork() will cause a segfault.</span>
+<a name="l00267"></a>00267 <span class="comment">// I haven't figured out why that happens, so for now</span>
+<a name="l00268"></a>00268 <span class="comment">// I'll just ignore the thread (which isn't running</span>
+<a name="l00269"></a>00269 <span class="comment">// anyway).</span>
+<a name="l00270"></a>00270 <span class="keywordflow">if</span> (!detached) {
+<a name="l00271"></a>00271 <span class="keyword">delete</span> thr;
+<a name="l00272"></a>00272 }
+<a name="l00273"></a>00273 }
+<a name="l00274"></a>00274 };
+<a name="l00275"></a>00275
+<a name="l00276"></a>00276 <span class="keyword">typedef</span> shared_ptr&lt;ClientInfo&gt; ClientInfoPtr;
+<a name="l00277"></a>00277
+<a name="l00278"></a>00278 <a class="code" href="classPassenger_1_1StandardApplicationPool.html" title="A standard implementation of ApplicationPool for single-process environments.">StandardApplicationPool</a> pool;
+<a name="l00279"></a>00279 <span class="keywordtype">int</span> serverSocket;
+<a name="l00280"></a>00280 <span class="keywordtype">int</span> connectSocket;
+<a name="l00281"></a>00281 <span class="keywordtype">bool</span> done, detached;
+<a name="l00282"></a>00282
+<a name="l00283"></a>00283 mutex lock;
+<a name="l00284"></a>00284 thread *serverThread;
+<a name="l00285"></a>00285 set&lt;ClientInfoPtr&gt; clients;
+<a name="l00286"></a>00286
+<a name="l00287"></a>00287 <span class="comment">// TODO: check for exceptions in threads, possibly forwarding them</span>
+<a name="l00288"></a>00288 <span class="comment"></span>
+<a name="l00289"></a>00289 <span class="comment"> /**</span>
+<a name="l00290"></a>00290 <span class="comment"> * The entry point of the server thread which sets up private connections.</span>
+<a name="l00291"></a>00291 <span class="comment"> * See the class overview's implementation notes for details.</span>
+<a name="l00292"></a>00292 <span class="comment"> */</span>
+<a name="l00293"></a>00293 <span class="keywordtype">void</span> serverThreadMainLoop() {
<a name="l00294"></a>00294 <span class="keywordflow">while</span> (!done) {
-<a name="l00295"></a>00295 <span class="keywordflow">if</span> (!channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Receive a message from the underlying file descriptor.">read</a>(args)) {
-<a name="l00296"></a>00296 <span class="keywordflow">break</span>;
-<a name="l00297"></a>00297 }
-<a name="l00298"></a>00298
-<a name="l00299"></a>00299 <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"get"</span> &amp;&amp; args.size() == 4) {
-<a name="l00300"></a>00300 <a class="code" href="classPassenger_1_1Application.html#d14f673494991460b16246a527ad8ad9" title="Convenient alias for Session smart pointer.">Application::SessionPtr</a> session(pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#cb338093c3368bf1cbcba02099c6c76e" title="Open a new session with the application specified by appRoot.">get</a>(args[1], args[2], args[3]));
-<a name="l00301"></a>00301 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>(toString(lastID).c_str(), NULL);
-<a name="l00302"></a>00302 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#73e3f3cda384c085a2af0e820ccd3e98" title="Pass a file descriptor.">writeFileDescriptor</a>(session-&gt;getReader());
-<a name="l00303"></a>00303 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#73e3f3cda384c085a2af0e820ccd3e98" title="Pass a file descriptor.">writeFileDescriptor</a>(session-&gt;getWriter());
-<a name="l00304"></a>00304 session-&gt;closeReader();
-<a name="l00305"></a>00305 session-&gt;closeWriter();
-<a name="l00306"></a>00306 sessions[lastID] = session;
-<a name="l00307"></a>00307 lastID++;
-<a name="l00308"></a>00308 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"close"</span> &amp;&amp; args.size() == 2) {
-<a name="l00309"></a>00309 sessions.erase(atoi(args[1].c_str()));
-<a name="l00310"></a>00310 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"setMax"</span>) {
-<a name="l00311"></a>00311 pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#04ef8c92da189520ad2022f4f82e9553" title="Set a hard limit on the number of application instances that this ApplicationPool...">setMax</a>(atoi(args[1].c_str()));
-<a name="l00312"></a>00312 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"getActive"</span>) {
-<a name="l00313"></a>00313 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>(toString(pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#7773c4a3dfbd88eac72401d063831788" title="Get the number of active applications in the pool.">getActive</a>()).c_str(), NULL);
-<a name="l00314"></a>00314 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"getCount"</span>) {
-<a name="l00315"></a>00315 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>(toString(pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#cdbfe2b9ffacdab4438c879c2411bf02" title="Get the number of active applications in the pool.">getCount</a>()).c_str(), NULL);
-<a name="l00316"></a>00316 }
-<a name="l00317"></a>00317 }
-<a name="l00318"></a>00318
-<a name="l00319"></a>00319 mutex::scoped_lock l(lock);
-<a name="l00320"></a>00320 clients.erase(client);
-<a name="l00321"></a>00321 }
-<a name="l00322"></a>00322
-<a name="l00323"></a>00323 <span class="keyword">public</span>:<span class="comment"></span>
-<a name="l00324"></a>00324 <span class="comment"> /**</span>
-<a name="l00325"></a>00325 <span class="comment"> * Create a new ApplicationPoolServer object.</span>
-<a name="l00326"></a>00326 <span class="comment"> *</span>
-<a name="l00327"></a>00327 <span class="comment"> * @param spawnServerCommand The filename of the spawn server to use.</span>
-<a name="l00328"></a>00328 <span class="comment"> * @param logFile Specify a log file that the spawn server should use.</span>
-<a name="l00329"></a>00329 <span class="comment"> * Messages on its standard output and standard error channels</span>
-<a name="l00330"></a>00330 <span class="comment"> * will be written to this log file. If an empty string is</span>
-<a name="l00331"></a>00331 <span class="comment"> * specified, no log file will be used, and the spawn server</span>
-<a name="l00332"></a>00332 <span class="comment"> * will use the same standard output/error channels as the</span>
-<a name="l00333"></a>00333 <span class="comment"> * current process.</span>
-<a name="l00334"></a>00334 <span class="comment"> * @param environment The RAILS_ENV environment that all RoR applications</span>
-<a name="l00335"></a>00335 <span class="comment"> * should use. If an empty string is specified, the current value</span>
-<a name="l00336"></a>00336 <span class="comment"> * of the RAILS_ENV environment variable will be used.</span>
-<a name="l00337"></a>00337 <span class="comment"> * @param rubyCommand The Ruby interpreter's command.</span>
-<a name="l00338"></a>00338 <span class="comment"> * @throws SystemException An error occured while trying to setup the spawn server</span>
-<a name="l00339"></a>00339 <span class="comment"> * or the server socket.</span>
-<a name="l00340"></a>00340 <span class="comment"> * @throws IOException The specified log file could not be opened.</span>
-<a name="l00341"></a>00341 <span class="comment"> */</span>
-<a name="l00342"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#0c6c9869ae4e1768f620bb03ee7a6b03">00342</a> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#0c6c9869ae4e1768f620bb03ee7a6b03" title="Create a new ApplicationPoolServer object.">ApplicationPoolServer</a>(<span class="keyword">const</span> <span class="keywordtype">string</span> &amp;spawnServerCommand,
-<a name="l00343"></a>00343 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;logFile = <span class="stringliteral">""</span>,
-<a name="l00344"></a>00344 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;environment = <span class="stringliteral">"production"</span>,
-<a name="l00345"></a>00345 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;rubyCommand = <span class="stringliteral">"ruby"</span>)
-<a name="l00346"></a>00346 : pool(spawnServerCommand, logFile, environment, rubyCommand) {
-<a name="l00347"></a>00347 <span class="keywordtype">int</span> fds[2];
-<a name="l00348"></a>00348
-<a name="l00349"></a>00349 <span class="keywordflow">if</span> (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
-<a name="l00350"></a>00350 <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);
-<a name="l00351"></a>00351 }
-<a name="l00352"></a>00352 serverSocket = fds[0];
-<a name="l00353"></a>00353 connectSocket = fds[1];
-<a name="l00354"></a>00354 done = <span class="keyword">false</span>;
-<a name="l00355"></a>00355 detached = <span class="keyword">false</span>;
-<a name="l00356"></a>00356 serverThread = <span class="keyword">new</span> thread(bind(&amp;ApplicationPoolServer::serverThreadMainLoop, <span class="keyword">this</span>));
-<a name="l00357"></a>00357 }
-<a name="l00358"></a>00358
-<a name="l00359"></a>00359 ~<a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a>() {
-<a name="l00360"></a>00360 <span class="keywordflow">if</span> (!detached) {
-<a name="l00361"></a>00361 done = <span class="keyword">true</span>;
-<a name="l00362"></a>00362 close(connectSocket);
-<a name="l00363"></a>00363 serverThread-&gt;join();
-<a name="l00364"></a>00364 <span class="keyword">delete</span> serverThread;
-<a name="l00365"></a>00365 close(serverSocket);
-<a name="l00366"></a>00366
-<a name="l00367"></a>00367 set&lt;ClientInfoPtr&gt; clientsCopy;
-<a name="l00368"></a>00368 {
-<a name="l00369"></a>00369 mutex::scoped_lock l(lock);
-<a name="l00370"></a>00370 clientsCopy = clients;
-<a name="l00371"></a>00371 }
-<a name="l00372"></a>00372 set&lt;ClientInfoPtr&gt;::iterator it;
-<a name="l00373"></a>00373 <span class="keywordflow">for</span> (it = clientsCopy.begin(); it != clientsCopy.end(); it++) {
-<a name="l00374"></a>00374 (*it)-&gt;thr-&gt;join();
-<a name="l00375"></a>00375 }
-<a name="l00376"></a>00376 }
-<a name="l00377"></a>00377 }
-<a name="l00378"></a>00378 <span class="comment"></span>
-<a name="l00379"></a>00379 <span class="comment"> /**</span>
-<a name="l00380"></a>00380 <span class="comment"> * Connects to the server and returns a usable ApplicationPool object.</span>
-<a name="l00381"></a>00381 <span class="comment"> * All cache/pool data of this ApplicationPool is actually stored on the server</span>
-<a name="l00382"></a>00382 <span class="comment"> * and shared with other clients, but that is totally transparent.</span>
-<a name="l00383"></a>00383 <span class="comment"> *</span>
-<a name="l00384"></a>00384 <span class="comment"> * @throws SystemException Something went wrong.</span>
-<a name="l00385"></a>00385 <span class="comment"> * @throws IOException Something went wrong.</span>
-<a name="l00386"></a>00386 <span class="comment"> */</span>
-<a name="l00387"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#18f77057cc28e7924a8f4d1397aa0468">00387</a> ApplicationPoolPtr <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#18f77057cc28e7924a8f4d1397aa0468" title="Connects to the server and returns a usable ApplicationPool object.">connect</a>() {
-<a name="l00388"></a>00388 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(connectSocket);
-<a name="l00389"></a>00389 <span class="keywordtype">int</span> fd;
-<a name="l00390"></a>00390
-<a name="l00391"></a>00391 <span class="comment">// Write some random data to wake up the server.</span>
-<a name="l00392"></a>00392 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);
-<a name="l00393"></a>00393
-<a name="l00394"></a>00394 fd = 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>();
-<a name="l00395"></a>00395 <span class="keywordflow">return</span> ptr(<span class="keyword">new</span> Client(fd));
-<a name="l00396"></a>00396 }
-<a name="l00397"></a>00397 <span class="comment"></span>
-<a name="l00398"></a>00398 <span class="comment"> /**</span>
-<a name="l00399"></a>00399 <span class="comment"> * Detach the server by freeing up some server resources such as file descriptors.</span>
-<a name="l00400"></a>00400 <span class="comment"> * This should be called by child processes that wish to use a server, but do</span>
-<a name="l00401"></a>00401 <span class="comment"> * not run the server itself.</span>
-<a name="l00402"></a>00402 <span class="comment"> *</span>
-<a name="l00403"></a>00403 <span class="comment"> * This method may only be called once. The ApplicationPoolServer object</span>
-<a name="l00404"></a>00404 <span class="comment"> * will become unusable once detach() has been called.</span>
-<a name="l00405"></a>00405 <span class="comment"> *</span>
-<a name="l00406"></a>00406 <span class="comment"> * @warning Never call this method in the process in which this</span>
-<a name="l00407"></a>00407 <span class="comment"> * ApplicationPoolServer was created!</span>
-<a name="l00408"></a>00408 <span class="comment"> */</span>
-<a name="l00409"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce">00409</a> <span class="keywordtype">void</span> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce" title="Detach the server by freeing up some server resources such as file descriptors.">detach</a>() {
-<a name="l00410"></a>00410 detached = <span class="keyword">true</span>;
-<a name="l00411"></a>00411 close(connectSocket);
-<a name="l00412"></a>00412 close(serverSocket);
-<a name="l00413"></a>00413 <span class="preprocessor"> #ifdef VALGRIND_FRIENDLY</span>
-<a name="l00414"></a>00414 <span class="preprocessor"></span> <span class="keyword">delete</span> serverThread;
-<a name="l00415"></a>00415 <span class="preprocessor"> #endif</span>
-<a name="l00416"></a>00416 <span class="preprocessor"></span> clients.clear();
-<a name="l00417"></a>00417 pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#047ba4c66c67d5913c8edc36524c5eac">detach</a>();
-<a name="l00418"></a>00418 }
-<a name="l00419"></a>00419 };
-<a name="l00420"></a>00420
-<a name="l00421"></a>00421 <span class="keyword">typedef</span> shared_ptr&lt;ApplicationPoolServer&gt; ApplicationPoolServerPtr;
-<a name="l00422"></a>00422
-<a name="l00423"></a>00423 } <span class="comment">// namespace Passenger</span>
-<a name="l00424"></a>00424
-<a name="l00425"></a>00425 <span class="preprocessor">#endif </span><span class="comment">/* _PASSENGER_APPLICATION_POOL_CLIENT_SERVER_H_ */</span>
-</pre></div><hr size="1"><address style="text-align: right;"><small>Generated on Fri Feb 8 20:08:48 2008 for Passenger by&nbsp;
+<a name="l00295"></a>00295 <span class="keywordtype">int</span> fds[2], ret;
+<a name="l00296"></a>00296 <span class="keywordtype">char</span> x;
+<a name="l00297"></a>00297
+<a name="l00298"></a>00298 <span class="comment">// The received data only serves to wake up the server socket,</span>
+<a name="l00299"></a>00299 <span class="comment">// and is not important.</span>
+<a name="l00300"></a>00300 <span class="keywordflow">do</span> {
+<a name="l00301"></a>00301 ret = read(serverSocket, &amp;x, 1);
+<a name="l00302"></a>00302 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
+<a name="l00303"></a>00303 <span class="keywordflow">if</span> (ret == 0) {
+<a name="l00304"></a>00304 <span class="keywordflow">break</span>;
+<a name="l00305"></a>00305 }
+<a name="l00306"></a>00306
+<a name="l00307"></a>00307 <span class="comment">// Incoming connect request.</span>
+<a name="l00308"></a>00308 <span class="keywordflow">do</span> {
+<a name="l00309"></a>00309 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+<a name="l00310"></a>00310 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
+<a name="l00311"></a>00311 <span class="keywordflow">if</span> (ret == -1) {
+<a name="l00312"></a>00312 <span class="keywordtype">int</span> e = errno;
+<a name="l00313"></a>00313 P_ERROR(<span class="stringliteral">"Cannot create an anonymous Unix socket: "</span> &lt;&lt;
+<a name="l00314"></a>00314 strerror(e) &lt;&lt; <span class="stringliteral">" ("</span> &lt;&lt; e &lt;&lt; <span class="stringliteral">")"</span>);
+<a name="l00315"></a>00315 abort();
+<a name="l00316"></a>00316
+<a name="l00317"></a>00317 <span class="comment">// Shut up compiler warning.</span>
+<a name="l00318"></a>00318 <span class="keywordtype">bool</span> x = <span class="keyword">false</span>;
+<a name="l00319"></a>00319 <span class="keywordflow">if</span> (x) {
+<a name="l00320"></a>00320 printf(<span class="stringliteral">"%d"</span>, e);
+<a name="l00321"></a>00321 }
+<a name="l00322"></a>00322 }
+<a name="l00323"></a>00323
+<a name="l00324"></a>00324 <span class="keywordflow">try</span> {
+<a name="l00325"></a>00325 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a>(serverSocket).writeFileDescriptor(fds[1]);
+<a name="l00326"></a>00326 <span class="keywordflow">do</span> {
+<a name="l00327"></a>00327 ret = close(fds[1]);
+<a name="l00328"></a>00328 } <span class="keywordflow">while</span> (ret == -1 &amp;&amp; errno == EINTR);
+<a name="l00329"></a>00329 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> exception &amp;e) {
+<a name="l00330"></a>00330 P_ERROR(<span class="stringliteral">"Cannot send a file descriptor: "</span> &lt;&lt; e.what());
+<a name="l00331"></a>00331 abort();
+<a name="l00332"></a>00332 }
+<a name="l00333"></a>00333
+<a name="l00334"></a>00334 ClientInfoPtr info(<span class="keyword">new</span> ClientInfo());
+<a name="l00335"></a>00335 info-&gt;fd = fds[0];
+<a name="l00336"></a>00336 info-&gt;thr = <span class="keyword">new</span> thread(bind(&amp;ApplicationPoolServer::clientThreadMainLoop, <span class="keyword">this</span>, info));
+<a name="l00337"></a>00337 mutex::scoped_lock l(lock);
+<a name="l00338"></a>00338 clients.insert(info);
+<a name="l00339"></a>00339 }
+<a name="l00340"></a>00340 }
+<a name="l00341"></a>00341 <span class="comment"></span>
+<a name="l00342"></a>00342 <span class="comment"> /**</span>
+<a name="l00343"></a>00343 <span class="comment"> * The entry point of a thread which handles exactly one client.</span>
+<a name="l00344"></a>00344 <span class="comment"> */</span>
+<a name="l00345"></a>00345 <span class="keywordtype">void</span> clientThreadMainLoop(ClientInfoPtr client) {
+<a name="l00346"></a>00346 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(client-&gt;fd);
+<a name="l00347"></a>00347 vector&lt;string&gt; args;
+<a name="l00348"></a>00348 map&lt;int, Application::SessionPtr&gt; sessions;
+<a name="l00349"></a>00349 <span class="keywordtype">int</span> lastID = 0;
+<a name="l00350"></a>00350
+<a name="l00351"></a>00351 <span class="keywordflow">try</span> {
+<a name="l00352"></a>00352 <span class="keywordflow">while</span> (!done) {
+<a name="l00353"></a>00353 <span class="keywordflow">if</span> (!channel.<a class="code" href="classPassenger_1_1MessageChannel.html#129659b60d1a663337873d2af944431e" title="Receive a message from the underlying file descriptor.">read</a>(args)) {
+<a name="l00354"></a>00354 <span class="keywordflow">break</span>;
+<a name="l00355"></a>00355 }
+<a name="l00356"></a>00356
+<a name="l00357"></a>00357 <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"get"</span> &amp;&amp; args.size() == 4) {
+<a name="l00358"></a>00358 <a class="code" href="classPassenger_1_1Application.html#d14f673494991460b16246a527ad8ad9" title="Convenient alias for Session smart pointer.">Application::SessionPtr</a> session;
+<a name="l00359"></a>00359 <span class="keywordtype">bool</span> failed = <span class="keyword">false</span>;
+<a name="l00360"></a>00360 <span class="keywordflow">try</span> {
+<a name="l00361"></a>00361 session = pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#cb338093c3368bf1cbcba02099c6c76e" title="Open a new session with the application specified by appRoot.">get</a>(args[1], args[2], args[3]);
+<a name="l00362"></a>00362 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> <a class="code" href="classPassenger_1_1SpawnException.html" title="Thrown when SpawnManager or ApplicationPool fail to spawn an application instance...">SpawnException</a> &amp;e) {
+<a name="l00363"></a>00363 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">"SpawnException"</span>, e.<a class="code" href="classPassenger_1_1SpawnException.html#d2da180f89a43423a4b37248249972ff">what</a>(), NULL);
+<a name="l00364"></a>00364 failed = <span class="keyword">true</span>;
+<a name="l00365"></a>00365 } <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) {
+<a name="l00366"></a>00366 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">"IOException"</span>, e.<a class="code" href="classPassenger_1_1IOException.html#1b65d0fdb9bc5136f5b7df759c14768a">what</a>(), NULL);
+<a name="l00367"></a>00367 failed = <span class="keyword">true</span>;
+<a name="l00368"></a>00368 }
+<a name="l00369"></a>00369 <span class="keywordflow">if</span> (!failed) {
+<a name="l00370"></a>00370 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">"ok"</span>, <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(session-&gt;getPid()).c_str(),
+<a name="l00371"></a>00371 <a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(lastID).c_str(), NULL);
+<a name="l00372"></a>00372 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#73e3f3cda384c085a2af0e820ccd3e98" title="Pass a file descriptor.">writeFileDescriptor</a>(session-&gt;getReader());
+<a name="l00373"></a>00373 channel.<a class="code" href="classPassenger_1_1MessageChannel.html#73e3f3cda384c085a2af0e820ccd3e98" title="Pass a file descriptor.">writeFileDescriptor</a>(session-&gt;getWriter());
+<a name="l00374"></a>00374 session-&gt;closeReader();
+<a name="l00375"></a>00375 session-&gt;closeWriter();
+<a name="l00376"></a>00376 sessions[lastID] = session;
+<a name="l00377"></a>00377 lastID++;
+<a name="l00378"></a>00378 }
+<a name="l00379"></a>00379
+<a name="l00380"></a>00380 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"close"</span> &amp;&amp; args.size() == 2) {
+<a name="l00381"></a>00381 sessions.erase(<a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[1]));
+<a name="l00382"></a>00382
+<a name="l00383"></a>00383 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"setMax"</span> &amp;&amp; args.size() == 2) {
+<a name="l00384"></a>00384 pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#04ef8c92da189520ad2022f4f82e9553" title="Set a hard limit on the number of application instances that this ApplicationPool...">setMax</a>(<a class="code" href="group__Support.html#g73b17b509ee44938a56bf16cbf82fb48" title="Converts the given string to an integer.">atoi</a>(args[1]));
+<a name="l00385"></a>00385
+<a name="l00386"></a>00386 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"getActive"</span> &amp;&amp; args.size() == 1) {
+<a name="l00387"></a>00387 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>(<a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#7773c4a3dfbd88eac72401d063831788" title="Get the number of active applications in the pool.">getActive</a>()).c_str(), NULL);
+<a name="l00388"></a>00388
+<a name="l00389"></a>00389 } <span class="keywordflow">else</span> <span class="keywordflow">if</span> (args[0] == <span class="stringliteral">"getCount"</span> &amp;&amp; args.size() == 1) {
+<a name="l00390"></a>00390 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>(<a class="code" href="group__Support.html#gf6fab368d70c18fdf16bf5a24f630407" title="Convert anything to a string.">toString</a>(pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#cdbfe2b9ffacdab4438c879c2411bf02" title="Get the number of active applications in the pool.">getCount</a>()).c_str(), NULL);
+<a name="l00391"></a>00391
+<a name="l00392"></a>00392 } <span class="keywordflow">else</span> {
+<a name="l00393"></a>00393 <span class="keywordtype">string</span> name;
+<a name="l00394"></a>00394 <span class="keywordflow">if</span> (args.empty()) {
+<a name="l00395"></a>00395 name = <span class="stringliteral">"(null)"</span>;
+<a name="l00396"></a>00396 } <span class="keywordflow">else</span> {
+<a name="l00397"></a>00397 name = args[0];
+<a name="l00398"></a>00398 }
+<a name="l00399"></a>00399 P_WARN(<span class="stringliteral">"An ApplicationPoolServer client sent an invalid command: "</span>
+<a name="l00400"></a>00400 &lt;&lt; name &lt;&lt; <span class="stringliteral">" ("</span> &lt;&lt; args.size() &lt;&lt; <span class="stringliteral">" elements)"</span>);
+<a name="l00401"></a>00401 done = <span class="keyword">true</span>;
+<a name="l00402"></a>00402 }
+<a name="l00403"></a>00403 }
+<a name="l00404"></a>00404 } <span class="keywordflow">catch</span> (<span class="keyword">const</span> exception &amp;e) {
+<a name="l00405"></a>00405 P_WARN(<span class="stringliteral">"Uncaught exception in ApplicationPoolServer client thread: "</span> &lt;&lt;
+<a name="l00406"></a>00406 e.what());
+<a name="l00407"></a>00407 }
+<a name="l00408"></a>00408
+<a name="l00409"></a>00409 mutex::scoped_lock l(lock);
+<a name="l00410"></a>00410 clients.erase(client);
+<a name="l00411"></a>00411 }
+<a name="l00412"></a>00412
+<a name="l00413"></a>00413 <span class="keyword">public</span>:<span class="comment"></span>
+<a name="l00414"></a>00414 <span class="comment"> /**</span>
+<a name="l00415"></a>00415 <span class="comment"> * Create a new ApplicationPoolServer object.</span>
+<a name="l00416"></a>00416 <span class="comment"> *</span>
+<a name="l00417"></a>00417 <span class="comment"> * @param spawnServerCommand The filename of the spawn server to use.</span>
+<a name="l00418"></a>00418 <span class="comment"> * @param logFile Specify a log file that the spawn server should use.</span>
+<a name="l00419"></a>00419 <span class="comment"> * Messages on its standard output and standard error channels</span>
+<a name="l00420"></a>00420 <span class="comment"> * will be written to this log file. If an empty string is</span>
+<a name="l00421"></a>00421 <span class="comment"> * specified, no log file will be used, and the spawn server</span>
+<a name="l00422"></a>00422 <span class="comment"> * will use the same standard output/error channels as the</span>
+<a name="l00423"></a>00423 <span class="comment"> * current process.</span>
+<a name="l00424"></a>00424 <span class="comment"> * @param environment The RAILS_ENV environment that all RoR applications</span>
+<a name="l00425"></a>00425 <span class="comment"> * should use. If an empty string is specified, the current value</span>
+<a name="l00426"></a>00426 <span class="comment"> * of the RAILS_ENV environment variable will be used.</span>
+<a name="l00427"></a>00427 <span class="comment"> * @param rubyCommand The Ruby interpreter's command.</span>
+<a name="l00428"></a>00428 <span class="comment"> * @throws SystemException An error occured while trying to setup the spawn server</span>
+<a name="l00429"></a>00429 <span class="comment"> * or the server socket.</span>
+<a name="l00430"></a>00430 <span class="comment"> * @throws IOException The specified log file could not be opened.</span>
+<a name="l00431"></a>00431 <span class="comment"> */</span>
+<a name="l00432"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#0c6c9869ae4e1768f620bb03ee7a6b03">00432</a> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#0c6c9869ae4e1768f620bb03ee7a6b03" title="Create a new ApplicationPoolServer object.">ApplicationPoolServer</a>(<span class="keyword">const</span> <span class="keywordtype">string</span> &amp;spawnServerCommand,
+<a name="l00433"></a>00433 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;logFile = <span class="stringliteral">""</span>,
+<a name="l00434"></a>00434 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;environment = <span class="stringliteral">"production"</span>,
+<a name="l00435"></a>00435 <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;rubyCommand = <span class="stringliteral">"ruby"</span>)
+<a name="l00436"></a>00436 : pool(spawnServerCommand, logFile, environment, rubyCommand) {
+<a name="l00437"></a>00437 <span class="keywordtype">int</span> fds[2];
+<a name="l00438"></a>00438
+<a name="l00439"></a>00439 <span class="keywordflow">if</span> (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
+<a name="l00440"></a>00440 <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);
+<a name="l00441"></a>00441 }
+<a name="l00442"></a>00442 serverSocket = fds[0];
+<a name="l00443"></a>00443 connectSocket = fds[1];
+<a name="l00444"></a>00444 done = <span class="keyword">false</span>;
+<a name="l00445"></a>00445 detached = <span class="keyword">false</span>;
+<a name="l00446"></a>00446 serverThread = <span class="keyword">new</span> thread(bind(&amp;ApplicationPoolServer::serverThreadMainLoop, <span class="keyword">this</span>));
+<a name="l00447"></a>00447 }
+<a name="l00448"></a>00448
+<a name="l00449"></a>00449 ~<a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a>() {
+<a name="l00450"></a>00450 <span class="keywordflow">if</span> (!detached) {
+<a name="l00451"></a>00451 done = <span class="keyword">true</span>;
+<a name="l00452"></a>00452 close(connectSocket);
+<a name="l00453"></a>00453 serverThread-&gt;join();
+<a name="l00454"></a>00454 <span class="keyword">delete</span> serverThread;
+<a name="l00455"></a>00455 close(serverSocket);
+<a name="l00456"></a>00456
+<a name="l00457"></a>00457 set&lt;ClientInfoPtr&gt; clientsCopy;
+<a name="l00458"></a>00458 {
+<a name="l00459"></a>00459 mutex::scoped_lock l(lock);
+<a name="l00460"></a>00460 clientsCopy = clients;
+<a name="l00461"></a>00461 }
+<a name="l00462"></a>00462 set&lt;ClientInfoPtr&gt;::iterator it;
+<a name="l00463"></a>00463 <span class="keywordflow">for</span> (it = clientsCopy.begin(); it != clientsCopy.end(); it++) {
+<a name="l00464"></a>00464 (*it)-&gt;thr-&gt;join();
+<a name="l00465"></a>00465 }
+<a name="l00466"></a>00466 }
+<a name="l00467"></a>00467 }
+<a name="l00468"></a>00468 <span class="comment"></span>
+<a name="l00469"></a>00469 <span class="comment"> /**</span>
+<a name="l00470"></a>00470 <span class="comment"> * Connects to the server and returns a usable ApplicationPool object.</span>
+<a name="l00471"></a>00471 <span class="comment"> * All cache/pool data of this ApplicationPool is actually stored on the server</span>
+<a name="l00472"></a>00472 <span class="comment"> * and shared with other clients, but that is totally transparent.</span>
+<a name="l00473"></a>00473 <span class="comment"> *</span>
+<a name="l00474"></a>00474 <span class="comment"> * @throws SystemException Something went wrong.</span>
+<a name="l00475"></a>00475 <span class="comment"> * @throws IOException Something went wrong.</span>
+<a name="l00476"></a>00476 <span class="comment"> */</span>
+<a name="l00477"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#18f77057cc28e7924a8f4d1397aa0468">00477</a> ApplicationPoolPtr <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#18f77057cc28e7924a8f4d1397aa0468" title="Connects to the server and returns a usable ApplicationPool object.">connect</a>() {
+<a name="l00478"></a>00478 <a class="code" href="classPassenger_1_1MessageChannel.html" title="Convenience class for I/O operations on file descriptors.">MessageChannel</a> channel(connectSocket);
+<a name="l00479"></a>00479 <span class="keywordtype">int</span> fd;
+<a name="l00480"></a>00480
+<a name="l00481"></a>00481 <span class="comment">// Write some random data to wake up the server.</span>
+<a name="l00482"></a>00482 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);
+<a name="l00483"></a>00483
+<a name="l00484"></a>00484 fd = 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>();
+<a name="l00485"></a>00485 <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(fd));
+<a name="l00486"></a>00486 }
+<a name="l00487"></a>00487 <span class="comment"></span>
+<a name="l00488"></a>00488 <span class="comment"> /**</span>
+<a name="l00489"></a>00489 <span class="comment"> * Detach the server by freeing up some server resources such as file descriptors.</span>
+<a name="l00490"></a>00490 <span class="comment"> * This should be called by child processes that wish to use a server, but do</span>
+<a name="l00491"></a>00491 <span class="comment"> * not run the server itself.</span>
+<a name="l00492"></a>00492 <span class="comment"> *</span>
+<a name="l00493"></a>00493 <span class="comment"> * This method may only be called once. The ApplicationPoolServer object</span>
+<a name="l00494"></a>00494 <span class="comment"> * will become unusable once detach() has been called.</span>
+<a name="l00495"></a>00495 <span class="comment"> *</span>
+<a name="l00496"></a>00496 <span class="comment"> * @warning Never call this method in the process in which this</span>
+<a name="l00497"></a>00497 <span class="comment"> * ApplicationPoolServer was created!</span>
+<a name="l00498"></a>00498 <span class="comment"> */</span>
+<a name="l00499"></a><a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce">00499</a> <span class="keywordtype">void</span> <a class="code" href="classPassenger_1_1ApplicationPoolServer.html#b13957e32ae8ca36ba85f2e6ffefd5ce" title="Detach the server by freeing up some server resources such as file descriptors.">detach</a>() {
+<a name="l00500"></a>00500 detached = <span class="keyword">true</span>;
+<a name="l00501"></a>00501 close(connectSocket);
+<a name="l00502"></a>00502 close(serverSocket);
+<a name="l00503"></a>00503 serverThread-&gt;join();
+<a name="l00504"></a>00504 <span class="keyword">delete</span> serverThread;
+<a name="l00505"></a>00505
+<a name="l00506"></a>00506 <span class="comment">// A client thread might have a reference to a ClientInfo</span>
+<a name="l00507"></a>00507 <span class="comment">// object. And because that thread doesn't run anymore after a</span>
+<a name="l00508"></a>00508 <span class="comment">// fork(), the reference never gets removed and the ClientInfo</span>
+<a name="l00509"></a>00509 <span class="comment">// object never gets destroyed. So we forcefully delete</span>
+<a name="l00510"></a>00510 <span class="comment">// ClientInfo objects in order to close the client file</span>
+<a name="l00511"></a>00511 <span class="comment">// descriptors.</span>
+<a name="l00512"></a>00512 set&lt;ClientInfoPtr&gt;::iterator it;
+<a name="l00513"></a>00513 <span class="keywordflow">for</span> (it = clients.begin(); it != clients.end(); it++) {
+<a name="l00514"></a>00514 <span class="keywordflow">if</span> (!it-&gt;unique()) {
+<a name="l00515"></a>00515 (*it)-&gt;detach();
+<a name="l00516"></a>00516 <span class="keyword">delete</span> it-&gt;get();
+<a name="l00517"></a>00517 }
+<a name="l00518"></a>00518 }
+<a name="l00519"></a>00519 clients.clear();
+<a name="l00520"></a>00520
+<a name="l00521"></a>00521 pool.<a class="code" href="classPassenger_1_1StandardApplicationPool.html#047ba4c66c67d5913c8edc36524c5eac">detach</a>();
+<a name="l00522"></a>00522 }
+<a name="l00523"></a>00523 };
+<a name="l00524"></a>00524
+<a name="l00525"></a>00525 <span class="keyword">typedef</span> shared_ptr&lt;ApplicationPoolServer&gt; ApplicationPoolServerPtr;
+<a name="l00526"></a>00526
+<a name="l00527"></a>00527 } <span class="comment">// namespace Passenger</span>
+<a name="l00528"></a>00528
+<a name="l00529"></a>00529 <span class="preprocessor">#endif </span><span class="comment">/* _PASSENGER_APPLICATION_POOL_CLIENT_SERVER_H_ */</span>
+</pre></div><hr size="1"><address style="text-align: right;"><small>Generated on Fri Feb 22 10:18:25 2008 for Passenger by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.3 </small></address>
</body>
View
680 doc/cxxapi/ApplicationPool_8h-source.html
@@ -80,58 +80,58 @@
<a name="l00065"></a>00065 <span class="comment"> * session = app-&gt;connect("/home/webapps/bar")</span>
<a name="l00066"></a>00066 <span class="comment"> * @endcode</span>
<a name="l00067"></a>00067 <span class="comment"> *</span>
-<a name="l00068"></a>00068 <span class="comment"> * Internally, Application::get() will keep spawned applications instances in</span>
+<a name="l00068"></a>00068 <span class="comment"> * Internally, ApplicationPool::get() will keep spawned applications instances in</span>
<a name="l00069"></a>00069 <span class="comment"> * memory, and reuse them if possible. It will try to keep spawning to a minimum.</span>
<a name="l00070"></a>00070 <span class="comment"> * Furthermore, if an application instance hasn't been used for a while, it</span>
-<a name="l00071"></a>00071 <span class="comment"> * will be automatically shutdown in order to save memory. And finally, one can</span>
-<a name="l00072"></a>00072 <span class="comment"> * set a hard limit on the maximum number of applications instances that may be</span>
-<a name="l00073"></a>00073 <span class="comment"> * spawned (see ApplicationPool::setMax()).</span>
-<a name="l00074"></a>00074 <span class="comment"> *</span>
-<a name="l00075"></a>00075 <span class="comment"> * Note that ApplicationPool is just an interface (i.e. a pure virtual class).</span>
-<a name="l00076"></a>00076 <span class="comment"> * For concrete classes, see StandardApplicationPool and ApplicationPoolServer.</span>
+<a name="l00071"></a>00071 <span class="comment"> * will be automatically shutdown in order to save memory. Restart requests are</span>
+<a name="l00072"></a>00072 <span class="comment"> * honored: if an application has the file 'restart.txt' in its 'tmp' folder,</span>
+<a name="l00073"></a>00073 <span class="comment"> * then get() will shutdown existing instances of that application and spawn</span>
+<a name="l00074"></a>00074 <span class="comment"> * a new instance (this is useful when a new version of an application has been</span>
+<a name="l00075"></a>00075 <span class="comment"> * deployed). And finally, one can set a hard limit on the maximum number of</span>
+<a name="l00076"></a>00076 <span class="comment"> * applications instances that may be spawned (see ApplicationPool::setMax()).</span>
<a name="l00077"></a>00077 <span class="comment"> *</span>
-<a name="l00078"></a>00078 <span class="comment"> * @ingroup Support</span>
-<a name="l00079"></a>00079 <span class="comment"> */</span>
-<a name="l00080"></a><a class="code" href="classPassenger_1_1ApplicationPool.html">00080</a> <span class="keyword">class </span><a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a> {
-<a name="l00081"></a>00081 <span class="keyword">public</span>:
-<a name="l00082"></a>00082 <span class="keyword">virtual</span> ~<a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a>() {};
-<a name="l00083"></a>00083 <span class="comment"></span>
-<a name="l00084"></a>00084 <span class="comment"> /**</span>
-<a name="l00085"></a>00085 <span class="comment"> * Open a new session with the application specified by &lt;tt&gt;appRoot&lt;/tt&gt;.</span>
-<a name="l00086"></a>00086 <span class="comment"> * See the class description for ApplicationPool, as well as Application::connect(),</span>
-<a name="l00087"></a>00087 <span class="comment"> * on how to use the returned session object.</span>
-<a name="l00088"></a>00088 <span class="comment"> *</span>
-<a name="l00089"></a>00089 <span class="comment"> * @param appRoot The application root of a RoR application, i.e. the folder that</span>
-<a name="l00090"></a>00090 <span class="comment"> * contains 'app/', 'public/', 'config/', etc. This must be a valid</span>
-<a name="l00091"></a>00091 <span class="comment"> * directory, but does not have to be an absolute path.</span>
-<a name="l00092"></a>00092 <span class="comment"> * @param user The user to run the application instance as.</span>
-<a name="l00093"></a>00093 <span class="comment"> * @param group The group to run the application instance as.</span>
-<a name="l00094"></a>00094 <span class="comment"> * @return A session object.</span>
-<a name="l00095"></a>00095 <span class="comment"> * @note Applications are uniquely identified with the application root</span>
-<a name="l00096"></a>00096 <span class="comment"> * string. So although &lt;tt&gt;appRoot&lt;/tt&gt; does not have to be absolute, it</span>
-<a name="l00097"></a>00097 <span class="comment"> * should be. If one calls &lt;tt&gt;get("/home/foo")&lt;/tt&gt; and</span>
-<a name="l00098"></a>00098 <span class="comment"> * &lt;tt&gt;get("/home/../home/foo")&lt;/tt&gt;, then ApplicationPool will think</span>
-<a name="l00099"></a>00099 <span class="comment"> * they're 2 different applications, and thus will spawn 2 application instances.</span>
-<a name="l00100"></a>00100 <span class="comment"> */</span>
-<a name="l00101"></a>00101 <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> <span class="keywordtype">string</span> &amp;appRoot, <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;user = <span class="stringliteral">""</span>, <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;group = <span class="stringliteral">""</span>) = 0;
-<a name="l00102"></a>00102 <span class="comment"></span>
-<a name="l00103"></a>00103 <span class="comment"> /**</span>
-<a name="l00104"></a>00104 <span class="comment"> * Set a hard limit on the number of application instances that this ApplicationPool</span>
-<a name="l00105"></a>00105 <span class="comment"> * may spawn. The exact behavior depends on the used algorithm, and is not specified by</span>
-<a name="l00106"></a>00106 <span class="comment"> * these API docs.</span>
-<a name="l00107"></a>00107 <span class="comment"> *</span>
-<a name="l00108"></a>00108 <span class="comment"> * It is allowed to set a limit lower than the current number of spawned applications.</span>
+<a name="l00078"></a>00078 <span class="comment"> * Note that ApplicationPool is just an interface (i.e. a pure virtual class).</span>
+<a name="l00079"></a>00079 <span class="comment"> * For concrete classes, see StandardApplicationPool and ApplicationPoolServer.</span>
+<a name="l00080"></a>00080 <span class="comment"> * The exact pooling algorithm depends on the implementation class.</span>
+<a name="l00081"></a>00081 <span class="comment"> *</span>
+<a name="l00082"></a>00082 <span class="comment"> * @ingroup Support</span>
+<a name="l00083"></a>00083 <span class="comment"> */</span>
+<a name="l00084"></a><a class="code" href="classPassenger_1_1ApplicationPool.html">00084</a> <span class="keyword">class </span><a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a> {
+<a name="l00085"></a>00085 <span class="keyword">public</span>:
+<a name="l00086"></a>00086 <span class="keyword">virtual</span> ~<a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a>() {};
+<a name="l00087"></a>00087 <span class="comment"></span>
+<a name="l00088"></a>00088 <span class="comment"> /**</span>
+<a name="l00089"></a>00089 <span class="comment"> * Open a new session with the application specified by &lt;tt&gt;appRoot&lt;/tt&gt;.</span>
+<a name="l00090"></a>00090 <span class="comment"> * See the class description for ApplicationPool, as well as Application::connect(),</span>
+<a name="l00091"></a>00091 <span class="comment"> * on how to use the returned session object.</span>
+<a name="l00092"></a>00092 <span class="comment"> *</span>
+<a name="l00093"></a>00093 <span class="comment"> * Internally, this method may either spawn a new application instance, or use</span>
+<a name="l00094"></a>00094 <span class="comment"> * an existing one.</span>
+<a name="l00095"></a>00095 <span class="comment"> *</span>
+<a name="l00096"></a>00096 <span class="comment"> * @param appRoot The application root of a RoR application, i.e. the folder that</span>
+<a name="l00097"></a>00097 <span class="comment"> * contains 'app/', 'public/', 'config/', etc. This must be a valid</span>
+<a name="l00098"></a>00098 <span class="comment"> * directory, but does not have to be an absolute path.</span>
+<a name="l00099"></a>00099 <span class="comment"> * @param user The user to run the application instance as.</span>
+<a name="l00100"></a>00100 <span class="comment"> * @param group The group to run the application instance as.</span>
+<a name="l00101"></a>00101 <span class="comment"> * @return A session object.</span>
+<a name="l00102"></a>00102 <span class="comment"> * @throw SpawnException An attempt was made to spawn a new application instance, but that attempt failed.</span>
+<a name="l00103"></a>00103 <span class="comment"> * @throw IOException Something else went wrong.</span>
+<a name="l00104"></a>00104 <span class="comment"> * @note Applications are uniquely identified with the application root</span>
+<a name="l00105"></a>00105 <span class="comment"> * string. So although &lt;tt&gt;appRoot&lt;/tt&gt; does not have to be absolute, it</span>
+<a name="l00106"></a>00106 <span class="comment"> * should be. If one calls &lt;tt&gt;get("/home/foo")&lt;/tt&gt; and</span>
+<a name="l00107"></a>00107 <span class="comment"> * &lt;tt&gt;get("/home/../home/foo")&lt;/tt&gt;, then ApplicationPool will think</span>
+<a name="l00108"></a>00108 <span class="comment"> * they're 2 different applications, and thus will spawn 2 application instances.</span>
<a name="l00109"></a>00109 <span class="comment"> */</span>
-<a name="l00110"></a>00110 <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classPassenger_1_1ApplicationPool.html#0e0f21972ab130c9c0f90c2212328794" title="Set a hard limit on the number of application instances that this ApplicationPool...">setMax</a>(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max) = 0;
+<a name="l00110"></a>00110 <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> <span class="keywordtype">string</span> &amp;appRoot, <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;user = <span class="stringliteral">""</span>, <span class="keyword">const</span> <span class="keywordtype">string</span> &amp;group = <span class="stringliteral">""</span>) = 0;
<a name="l00111"></a>00111 <span class="comment"></span>
<a name="l00112"></a>00112 <span class="comment"> /**</span>
-<a name="l00113"></a>00113 <span class="comment"> * Get the number of active applications in the pool.</span>
-<a name="l00114"></a>00114 <span class="comment"> *</span>
-<a name="l00115"></a>00115 <span class="comment"> * This method exposes an implementation detail of the underlying pooling algorithm.</span>
-<a name="l00116"></a>00116 <span class="comment"> * It is used by unit tests to verify that the implementation is correct,</span>
-<a name="l00117"></a>00117 <span class="comment"> * and thus should not be called directly.</span>
+<a name="l00113"></a>00113 <span class="comment"> * Set a hard limit on the number of application instances that this ApplicationPool</span>
+<a name="l00114"></a>00114 <span class="comment"> * may spawn. The exact behavior depends on the used algorithm, and is not specified by</span>
+<a name="l00115"></a>00115 <span class="comment"> * these API docs.</span>
+<a name="l00116"></a>00116 <span class="comment"> *</span>
+<a name="l00117"></a>00117 <span class="comment"> * It is allowed to set a limit lower than the current number of spawned applications.</span>
<a name="l00118"></a>00118 <span class="comment"> */</span>
-<a name="l00119"></a>00119 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> <a class="code" href="classPassenger_1_1ApplicationPool.html#06d1eae044d4d761ce77cf09049df8c8" title="Get the number of active applications in the pool.">getActive</a>() <span class="keyword">const</span> = 0;
+<a name="l00119"></a>00119 <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a class="code" href="classPassenger_1_1ApplicationPool.html#0e0f21972ab130c9c0f90c2212328794" title="Set a hard limit on the number of application instances that this ApplicationPool...">setMax</a>(<span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max) = 0;
<a name="l00120"></a>00120 <span class="comment"></span>
<a name="l00121"></a>00121 <span class="comment"> /**</span>
<a name="l00122"></a>00122 <span class="comment"> * Get the number of active applications in the pool.</span>
@@ -140,271 +140,331 @@
<a name="l00125"></a>00125 <span class="comment"> * It is used by unit tests to verify that the implementation is correct,</span>
<a name="l00126"></a>00126 <span class="comment"> * and thus should not be called directly.</span>
<a name="l00127"></a>00127 <span class="comment"> */</span>
-<a name="l00128"></a>00128 <span class="keyword">virtual</span> <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> <a class="code" href="classPassenger_1_1ApplicationPool.html#93b0277beb510855f85fee5de5c369bb" title="Get the number of active applications in the pool.">getCount</a>() <span class="keyword">const</span> = 0;
-<a name="l00129"></a>00129 };
-<a name="l00130"></a>00130
-<a name="l00131"></a>00131 <span class="keyword">class </span><a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a>;
-<a name="l00132"></a>00132 <span class="comment"></span>
-<a name="l00133"></a>00133 <span class="comment">/**</span>
-<a name="l00134"></a>00134 <span class="comment"> * A standard implementation of ApplicationPool for single-process environments.</span>
-<a name="l00135"></a>00135 <span class="comment"> *</span>
-<a name="l00136"></a>00136 <span class="comment"> * The environment may or may not be multithreaded - StandardApplicationPool is completely</span>
-<a name="l00137"></a>00137 <span class="comment"> * thread-safe. Apache with the threading MPM is an example of a multithreaded single-process</span>
-<a name="l00138"></a>00138 <span class="comment"> * environment.</span>
-<a name="l00139"></a>00139 <span class="comment"> *</span>
-<a name="l00140"></a>00140 <span class="comment"> * This class is unusable in multi-process environments such as Apache with the prefork MPM.</span>
-<a name="l00141"></a>00141 <span class="comment"> * The reasons as as follows:</span>
-<a name="l00142"></a>00142 <span class="comment"> * - StandardApplicationPool uses threads internally. Because threads disappear after a fork(),</span>
-<a name="l00143"></a>00143 <span class="comment"> * a StandardApplicationPool object will become unusable after a fork().</span>
-<a name="l00144"></a>00144 <span class="comment"> * - StandardApplicationPool stores its internal cache on the heap. Different processes</span>
-<a name="l00145"></a>00145 <span class="comment"> * cannot share their heaps, so they will not be able to access each others' pool cache.</span>
-<a name="l00146"></a>00146 <span class="comment"> * - StandardApplicationPool has a connection to the spawn server. If there are multiple</span>
-<a name="l00147"></a>00147 <span class="comment"> * processes, and they all use the spawn servers's connection at the same time without</span>
-<a name="l00148"></a>00148 <span class="comment"> * some sort of synchronization, then bad things will happen.</span>
-<a name="l00149"></a>00149 <span class="comment"> *</span>
-<a name="l00150"></a>00150 <span class="comment"> * (Of course, StandardApplicationPool &lt;em&gt;is&lt;/em&gt; usable if each process creates its own</span>
-<a name="l00151"></a>00151 <span class="comment"> * StandardApplicationPool object, but that would defeat the point of having a shared pool.)</span>
-<a name="l00152"></a>00152 <span class="comment"> *</span>
-<a name="l00153"></a>00153 <span class="comment"> * For multi-process environments, one should use ApplicationPoolServer instead.</span>
-<a name="l00154"></a>00154 <span class="comment"> *</span>
-<a name="l00155"></a>00155 <span class="comment"> * @ingroup Support</span>
-<a name="l00156"></a>00156 <span class="comment"> */</span>
-<a name="l00157"></a><a class="code" href="classPassenger_1_1StandardApplicationPool.html">00157</a> <span class="keyword">class </span><a class="code" href="classPassenger_1_1StandardApplicationPool.html" title="A standard implementation of ApplicationPool for single-process environments.">StandardApplicationPool</a>: <span class="keyword">public</span> <a class="code" href="classPassenger_1_1ApplicationPool.html" title="A persistent pool of Applications.">ApplicationPool</a> {
-<a name="l00158"></a>00158 <span class="keyword">private</span>:
-<a name="l00159"></a>00159 <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">int</span> CLEAN_INTERVAL = 62;
-<a name="l00160"></a>00160 <span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">int</span> MAX_IDLE_TIME = 60;
-<a name="l00161"></a>00161
-<a name="l00162"></a>00162 <span class="keyword">friend</span> <span class="keyword">class </span><a class="code" href="classPassenger_1_1ApplicationPoolServer.html" title="Multi-process usage support for ApplicationPool.">ApplicationPoolServer</a>;
-<a name="l00163"></a>00163
-<a name="l00164"></a>00164 <span class="keyword">typedef</span> list&lt;ApplicationPtr&gt; ApplicationList;
-<a name="l00165"></a>00165 <span class="keyword">typedef</span> shared_ptr&lt;ApplicationList&gt; ApplicationListPtr;
-<a name="l00166"></a>00166 <span class="keyword">typedef</span> map&lt;string, ApplicationListPtr&gt; ApplicationMap;
-<a name="l00167"></a>00167
-<a name="l00168"></a>00168 <span class="keyword">struct </span>SharedData {
-<a name="l00169"></a>00169 mutex lock;
-<a name="l00170"></a>00170 condition countOrMaxChanged;
-<a name="l00171"></a>00171
-<a name="l00172"></a>00172 ApplicationMap apps;
-<a name="l00173"></a>00173 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> max;
-<a name="l00174"></a>00174 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> count;
-<a name="l00175"></a>00175 <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> active;
-<a name="l00176"></a>00176 };
-<a name="l00177"></a>00177
-<a name="l00178"></a>00178 <span class="keyword">typedef</span> shared_ptr&lt;SharedData&gt; SharedDataPtr;
-<a name="l00179"></a>00179
-<a name="l00180"></a>00180 <span class="keyword">struct </span>SessionCloseCallback {
-<a name="l00181"></a>00181 SharedDataPtr data;
-<a name="l00182"></a>00182 weak_ptr&lt;Application&gt; app;
-<a name="l00183"></a>00183
-<a name="l00184"></a>00184 SessionCloseCallback(SharedDataPtr data, weak_ptr&lt;Application&gt; app) {
-<a name="l00185"></a>00185 this-&gt;data = data;
-<a name="l00186"></a>00186 this-&gt;app = app;
-<a name="l00187"></a>00187 }
-<a name="l00188"></a>00188
-<a name="l00189"></a>00189 <span class="keywordtype">void</span> operator()(<a class="code" href="classPassenger_1_1Application_1_1Session.html" title="Represents the life time of a single request/response pair of a Ruby on Rails application...">Application::Session</a> &amp;session) {
-<a name="l00190"></a>00190 mutex::scoped_lock l(data-&gt;lock);
-<a name="l00191"></a>00191 ApplicationPtr app(this-&gt;app.lock());
-<a name="l00192"></a>00192
-<a name="l00193"></a>00193 <span class="keywordflow">if</span> (app != NULL) {
-<a name="l00194"></a>00194 ApplicationMap::iterator it(data-&gt;apps.find(app-&gt;getAppRoot()));
-<a name="l00195"></a>00195 <span class="keywordflow">if</span> (it != data-&gt;apps.end()) {
-<a name="l00196"></a>00196 <span class="keywordflow">if</span> (app-&gt;getSessions() == 0) {
-<a name="l00197"></a>00197 <span class="comment">// TODO: make this operation constant time</span>
-<a name="l00198"></a>00198 it-&gt;second-&gt;remove(app);
-<a name="l00199"></a>00199 it-&gt;second-&gt;push_front(app);
-<a name="l00200"></a>00200 }
-<a name="l00201"></a>00201 data-&gt;active--;
-<a name="l00202"></a>00202 }
-<a name="l00203"></a>00203 app-&gt;setLastUsed(time(NULL));
-<a name="l00204"></a>00204 }
-<a name="l00205">