1 /* rivet_prefork_mpm.c: dynamically loaded MPM aware functions for prefork module */
2 
3 /*
4     Licensed to the Apache Software Foundation (ASF) under one
5     or more contributor license agreements.  See the NOTICE file
6     distributed with this work for additional information
7     regarding copyright ownership.  The ASF licenses this file
8     to you under the Apache License, Version 2.0 (the
9     "License"); you may not use this file except in compliance
10     with the License.  You may obtain a copy of the License at
11 
12       http://www.apache.org/licenses/LICENSE-2.0
13 
14     Unless required by applicable law or agreed to in writing,
15     software distributed under the License is distributed on an
16     "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17     KIND, either express or implied.  See the License for the
18     specific language governing permissions and limitations
19     under the License.
20  */
21 
22 #include <apr_strings.h>
23 
24 #include "mod_rivet.h"
25 #include "mod_rivet_common.h"
26 #include "mod_rivet_generator.h"
27 #include "mod_rivet_cache.h"
28 #include "httpd.h"
29 #include "rivetChannel.h"
30 #include "apache_config.h"
31 #include "rivet.h"
32 #include "rivetCore.h"
33 #include "worker_prefork_common.h"
34 
35 extern DLLIMPORT mod_rivet_globals* module_globals;
36 extern DLLIMPORT apr_threadkey_t*   rivet_thread_key;
37 extern module    rivet_module;
38 
39 rivet_thread_private*   Rivet_VirtualHostsInterps (rivet_thread_private* private);
40 
41 /* -- PreforkBridge_Finalize */
42 
PreforkBridge_Finalize(void * data)43 apr_status_t PreforkBridge_Finalize (void* data)
44 {
45     rivet_thread_private*   private;
46     server_rec* s = (server_rec*) data;
47 
48     RIVET_PRIVATE_DATA_NOT_NULL(rivet_thread_key,private)
49     ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s, "Running prefork bridge finalize method");
50 
51     // No, we don't do any clean up anymore as we are just shutting this process down
52     // Rivet_ProcessorCleanup(private);
53 
54     return OK;
55 }
56 
57 /* -- PreforkBridge_ChildInit: bridge child process initialization
58  *
59  */
60 
61 
PreforkBridge_ChildInit(apr_pool_t * pool,server_rec * server)62 void PreforkBridge_ChildInit (apr_pool_t* pool, server_rec* server)
63 {
64     rivet_server_conf*      rsc = RIVET_SERVER_CONF (module_globals->server->module_config);
65     rivet_thread_private*   private;
66 
67     ap_assert (apr_threadkey_private_create (&rivet_thread_key, NULL, pool) == APR_SUCCESS);
68 
69     /*
70      * This is the only execution thread in this process so we create
71      * the Tcl thread private data here. In a fork capable OS
72      * private data should have been created by the httpd parent process
73      */
74 
75     private = Rivet_ExecutionThreadInit();
76     private->ext = apr_pcalloc(private->pool,sizeof(mpm_bridge_specific));
77     private->ext->interps =
78         apr_pcalloc(private->pool,module_globals->vhosts_count*sizeof(rivet_thread_interp));
79 
80 
81     /* we now establish the full rivet core command set for the root interpreter */
82 
83     Rivet_InitCore (module_globals->server_interp->interp,private);
84 
85     /* The root interpreter is created without a rivet cache (that wouldn't make sense
86      * in that context. We create the cache now */
87 
88     module_globals->server_interp->cache_size = rsc->default_cache_size;
89     if (module_globals->server_interp->cache_size < 0) {
90         module_globals->server_interp->cache_size = RivetCache_DefaultSize();
91     }
92     module_globals->server_interp->cache_free = module_globals->server_interp->cache_size;
93     ap_log_error(APLOG_MARK,APLOG_DEBUG,APR_SUCCESS,server,"root interpreter cache size: %d (free: %d)",
94                                                             module_globals->server_interp->cache_size,
95                                                             module_globals->server_interp->cache_free);
96 
97     RivetCache_Create(module_globals->pool,module_globals->server_interp);
98 
99 #ifdef RIVET_NAMESPACE_IMPORT
100     {
101         char* tcl_import_cmd = "namespace eval :: { namespace import -force ::rivet::* }\n";
102 
103         Tcl_Eval (module_globals->server_interp->interp,tcl_import_cmd);
104     }
105 #endif
106 
107     /*
108      * We proceed creating the vhost interpreters database
109      */
110 
111     if (Rivet_VirtualHostsInterps(private) == NULL)
112     {
113         ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server, MODNAME ": Tcl Interpreters creation fails");
114         exit(1);
115     }
116 }
117 
118 /*
119  * -- PreforkBridge_Request
120  *
121  *  The prefork implementation of this function is basically a wrapper of
122  *  Rivet_SendContent. The real job is fetching the thread private data
123  *
124  * Arguments:
125  *
126  *   request_rec* rec
127  *
128  * Returned value:
129  *
130  *   HTTP status code (see the Apache HTTP web server documentation)
131  */
132 
PreforkBridge_Request(request_rec * r,rivet_req_ctype ctype)133 int PreforkBridge_Request (request_rec* r,rivet_req_ctype ctype)
134 {
135     rivet_thread_private*   private;
136 
137     /* fetching the thread private data to be passed to Rivet_SendContent */
138 
139     RIVET_PRIVATE_DATA_NOT_NULL (rivet_thread_key, private);
140 
141     private->ctype = ctype;
142     private->req_cnt++;
143     private->r = r;
144 
145     return Rivet_SendContent(private);
146 }
147 
148 /*
149  * -- MPM_MasterInterp
150  *
151  *
152  *
153  */
154 
MPM_MasterInterp(server_rec * server)155 rivet_thread_interp* MPM_MasterInterp(server_rec* server)
156 {
157     rivet_thread_private*   private;
158     int                     tcl_status;
159 
160     RIVET_PRIVATE_DATA_NOT_NULL (rivet_thread_key, private);
161 
162     module_globals->server_interp->channel = private->channel;
163 
164     /*
165      * We are returning the interpreter inherited from
166      * the parent process. The fork preserves the internal status
167      * of the process, math engine status included. This fact implies
168      * the random number generator has the same seed and every
169      * child process for which SeparateVirtualInterps would generate
170      * the same random number sequence. We therefore reseed the RNG
171      * calling a Tcl script fragment
172      */
173 
174     tcl_status = Tcl_Eval(module_globals->server_interp->interp,"expr {srand([clock clicks] + [pid])}");
175     if (tcl_status != TCL_OK)
176     {
177         ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server,
178                      MODNAME ": Tcl interpreter random number generation reseeding failed");
179 
180     }
181     return module_globals->server_interp;
182 }
183 
184 /*
185  * -- PreforkBridge_ExitHandler
186  *
187  *  Just calling Tcl_Exit
188  *
189  *  Arguments:
190  *      int code
191  *
192  * Side Effects:
193  *
194  *  the thread running the Tcl script will exit
195  */
196 
PreforkBridge_ExitHandler(rivet_thread_private * private)197 int PreforkBridge_ExitHandler(rivet_thread_private* private)
198 {
199     Tcl_Exit(private->exit_status);
200 
201     /* actually we'll never get here but we return
202      * the Tcl return code anyway to silence the
203      * compilation warning
204      */
205     return TCL_OK;
206 }
207 
PreforkBridge_Interp(rivet_thread_private * private,rivet_server_conf * conf,rivet_thread_interp * interp)208 rivet_thread_interp* PreforkBridge_Interp (rivet_thread_private* private,
209                                          rivet_server_conf*    conf,
210                                          rivet_thread_interp*  interp)
211 {
212     if (interp != NULL) { private->ext->interps[conf->idx] = interp; }
213 
214     return private->ext->interps[conf->idx];
215 }
216 
217 /*
218  *  -- PreforkBridge_ServerInit
219  *
220  * Bridge server wide inizialization:
221  *
222  */
223 
PreforkBridge_ServerInit(apr_pool_t * pPool,apr_pool_t * pLog,apr_pool_t * pTemp,server_rec * s)224 int PreforkBridge_ServerInit (apr_pool_t* pPool,apr_pool_t* pLog,apr_pool_t* pTemp,server_rec* s)
225 {
226     /* Whether single_thread_exit is 1 or 0 doesn't make any difference for
227      * the prefork bridge, we set the default value anyway in case it hadn't been
228      * set already in the configuration */
229 
230     if (module_globals->single_thread_exit == SINGLE_THREAD_EXIT_UNDEF)
231     {
232         module_globals->single_thread_exit = 0;
233     }
234 
235     /* The root interpreter is created without a rivet cache (that wouldn't make sense
236      * in that context. We create the cache now */
237 
238     if (module_globals->server_interp->cache_size) {
239         RivetCache_Create(pPool,module_globals->server_interp);
240     }
241     return OK;
242 }
243 
244 /* Table of bridge control functions */
245 
246 DLLEXPORT
247 RIVET_MPM_BRIDGE {
248     PreforkBridge_ServerInit,
249     PreforkBridge_ChildInit,
250     PreforkBridge_Request,
251     PreforkBridge_Finalize,
252     PreforkBridge_ExitHandler,
253     PreforkBridge_Interp
254 };
255 
256