bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / threadproc / netware / proc.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_arch_threadproc.h"
18 #include "apr_arch_file_io.h"
19 #include "apr_strings.h"
20 #include "apr_portable.h"
21
22 #include <proc.h>
23
24 apr_status_t apr_netware_proc_cleanup(void *theproc)
25 {
26     apr_proc_t *proc = theproc;
27     int exit_int;
28     int waitpid_options = WUNTRACED | WNOHANG;
29
30     if (proc->pid > 0) {
31         waitpid(proc->pid, &exit_int, waitpid_options);
32     }
33
34 /*      NXVmDestroy(proc->pid); */
35     return APR_SUCCESS;
36 }
37
38 APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new,apr_pool_t *pool)
39 {
40     (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
41
42     if ((*new) == NULL) {
43         return APR_ENOMEM;
44     }
45     (*new)->pool = pool;
46     (*new)->cmdtype = APR_PROGRAM;
47     /* Default to a current path since NetWare doesn't handle it very well */
48     apr_filepath_get(&((*new)->currdir), APR_FILEPATH_NATIVE, pool);
49     (*new)->detached = 1;
50     return APR_SUCCESS;
51
52 }
53
54 APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, apr_int32_t in, 
55                                  apr_int32_t out, apr_int32_t err)
56 {
57     apr_status_t status;
58     if (in != 0) {
59         if ((status = apr_file_pipe_create(&attr->child_in, &attr->parent_in, 
60                                    attr->pool)) != APR_SUCCESS) {
61             return status;
62         }
63         switch (in) {
64         case APR_FULL_BLOCK:
65             break;
66         case APR_PARENT_BLOCK:
67             apr_file_pipe_timeout_set(attr->child_in, 0);
68             break;
69         case APR_CHILD_BLOCK:
70             apr_file_pipe_timeout_set(attr->parent_in, 0);
71             break;
72         default:
73             apr_file_pipe_timeout_set(attr->child_in, 0);
74             apr_file_pipe_timeout_set(attr->parent_in, 0);
75         }
76     } 
77     if (out) {
78         if ((status = apr_file_pipe_create(&attr->parent_out, &attr->child_out, 
79                                    attr->pool)) != APR_SUCCESS) {
80             return status;
81         }
82         switch (out) {
83         case APR_FULL_BLOCK:
84             break;
85         case APR_PARENT_BLOCK:
86             apr_file_pipe_timeout_set(attr->child_out, 0);
87             break;
88         case APR_CHILD_BLOCK:
89             apr_file_pipe_timeout_set(attr->parent_out, 0);
90             break;
91         default:
92             apr_file_pipe_timeout_set(attr->child_out, 0);
93             apr_file_pipe_timeout_set(attr->parent_out, 0);
94         }
95     } 
96     if (err) {
97         if ((status = apr_file_pipe_create(&attr->parent_err, &attr->child_err, 
98                                    attr->pool)) != APR_SUCCESS) {
99             return status;
100         }
101         switch (err) {
102         case APR_FULL_BLOCK:
103             break;
104         case APR_PARENT_BLOCK:
105             apr_file_pipe_timeout_set(attr->child_err, 0);
106             break;
107         case APR_CHILD_BLOCK:
108             apr_file_pipe_timeout_set(attr->parent_err, 0);
109             break;
110         default:
111             apr_file_pipe_timeout_set(attr->child_err, 0);
112             apr_file_pipe_timeout_set(attr->parent_err, 0);
113         }
114     } 
115     return APR_SUCCESS;
116 }
117
118
119 APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in,
120                                    apr_file_t *parent_in)
121 {
122     if (attr->child_in == NULL && attr->parent_in == NULL)
123         apr_file_pipe_create(&attr->child_in, &attr->parent_in, attr->pool);
124
125     if (child_in != NULL)
126         apr_file_dup2(attr->child_in, child_in, attr->pool);
127
128     if (parent_in != NULL)
129         apr_file_dup2(attr->parent_in, parent_in, attr->pool);
130
131     return APR_SUCCESS;
132 }
133
134
135 APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out,
136                                     apr_file_t *parent_out)
137 {
138     if (attr->child_out == NULL && attr->parent_out == NULL)
139         apr_file_pipe_create(&attr->child_out, &attr->parent_out, attr->pool);
140
141     if (child_out != NULL)
142         apr_file_dup2(attr->child_out, child_out, attr->pool);
143
144     if (parent_out != NULL)
145         apr_file_dup2(attr->parent_out, parent_out, attr->pool);
146
147     return APR_SUCCESS;
148 }
149
150
151 APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err,
152                                    apr_file_t *parent_err)
153 {
154     if (attr->child_err == NULL && attr->parent_err == NULL)
155         apr_file_pipe_create(&attr->child_err, &attr->parent_err, attr->pool);
156
157     if (child_err != NULL)
158         apr_file_dup2(attr->child_err, child_err, attr->pool);
159
160     if (parent_err != NULL)
161         apr_file_dup2(attr->parent_err, parent_err, attr->pool);
162
163     return APR_SUCCESS;
164 }
165
166
167 APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr, 
168                                const char *dir) 
169 {
170     return apr_filepath_merge(&attr->currdir, NULL, dir, 
171                               APR_FILEPATH_NATIVE, attr->pool);
172 }
173
174 APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
175                                      apr_cmdtype_e cmd) 
176 {
177     /* won't ever be called on this platform, so don't save the flag */
178     return APR_SUCCESS;
179 }
180
181 APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach) 
182 {
183     attr->detached = detach;
184     return APR_SUCCESS;
185 }
186
187 #if APR_HAS_FORK
188 APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool)
189 {
190     int pid;
191     
192     if ((pid = fork()) < 0) {
193         return errno;
194     }
195     else if (pid == 0) {
196         proc->pid = pid;
197         proc->in = NULL; 
198         proc->out = NULL; 
199         proc->err = NULL; 
200         return APR_INCHILD;
201     }
202     proc->pid = pid;
203     proc->in = NULL; 
204     proc->out = NULL; 
205     proc->err = NULL; 
206     return APR_INPARENT;
207 }
208 #endif
209
210 static apr_status_t limit_proc(apr_procattr_t *attr)
211 {
212 #if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT
213 #ifdef RLIMIT_CPU
214     if (attr->limit_cpu != NULL) {
215         if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) {
216             return errno;
217         }
218     }
219 #endif
220 #ifdef RLIMIT_NPROC
221     if (attr->limit_nproc != NULL) {
222         if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) {
223             return errno;
224         }
225     }
226 #endif
227 #if defined(RLIMIT_AS)
228     if (attr->limit_mem != NULL) {
229         if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) {
230             return errno;
231         }
232     }
233 #elif defined(RLIMIT_DATA)
234     if (attr->limit_mem != NULL) {
235         if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) {
236             return errno;
237         }
238     }
239 #elif defined(RLIMIT_VMEM)
240     if (attr->limit_mem != NULL) {
241         if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) {
242             return errno;
243         }
244     }
245 #endif
246 #else
247     /*
248      * Maybe make a note in error_log that setrlimit isn't supported??
249      */
250
251 #endif
252     return APR_SUCCESS;
253 }
254
255 APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
256                                                        apr_child_errfn_t *errfn)
257 {
258     /* won't ever be called on this platform, so don't save the function pointer */
259     return APR_SUCCESS;
260 }
261
262 APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
263                                                        apr_int32_t chk)
264 {
265     /* won't ever be used on this platform, so don't save the flag */
266     return APR_SUCCESS;
267 }
268
269 APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
270                                                        apr_int32_t addrspace)
271 {
272     attr->addrspace = addrspace;
273     return APR_SUCCESS;
274 }
275
276 APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *newproc,
277                                                                         const char *progname, 
278                                                                         const char * const *args, 
279                                                                         const char * const *env,
280                                         apr_procattr_t *attr, 
281                                         apr_pool_t *pool)
282 {
283         wiring_t                wire;
284     int             addr_space;
285
286     wire.infd  = attr->child_in ? attr->child_in->filedes : FD_UNUSED;
287     wire.outfd = attr->child_out ? attr->child_out->filedes : FD_UNUSED;
288     wire.errfd = attr->child_err ? attr->child_err->filedes : FD_UNUSED;
289
290     newproc->in = attr->parent_in;
291     newproc->out = attr->parent_out;
292     newproc->err = attr->parent_err;
293
294     /* attr->detached and PROC_DETACHED do not mean the same thing.  attr->detached means
295      * start the NLM in a separate address space.  PROC_DETACHED means don't wait for the
296      * NLM to unload by calling wait() or waitpid(), just clean up */
297     addr_space = PROC_LOAD_SILENT | (attr->addrspace ? 0 : PROC_CURRENT_SPACE);
298     addr_space |= (attr->detached ? PROC_DETACHED : 0);
299
300     if (attr->currdir) {
301         char *fullpath = NULL;
302         apr_status_t rv;
303
304         if ((rv = apr_filepath_merge(&fullpath, attr->currdir, progname, 
305                                      APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) {
306             return rv;
307         }
308         progname = fullpath;
309     } 
310
311     if ((newproc->pid = procve(progname, addr_space, (const char**)env, &wire, 
312         NULL, NULL, 0, NULL, (const char **)args)) == -1) {
313         return errno;
314     }
315
316     if (attr->child_in) {
317         apr_pool_cleanup_kill(apr_file_pool_get(attr->child_in), 
318                               attr->child_in, apr_unix_file_cleanup);
319         apr_file_close(attr->child_in);
320     }
321     if (attr->child_out) {
322         apr_pool_cleanup_kill(apr_file_pool_get(attr->child_out), 
323                               attr->child_out, apr_unix_file_cleanup);
324         apr_file_close(attr->child_out);
325     }
326     if (attr->child_err) {
327         apr_pool_cleanup_kill(apr_file_pool_get(attr->child_err), 
328                               attr->child_err, apr_unix_file_cleanup);
329         apr_file_close(attr->child_err);
330     }
331
332
333     apr_pool_cleanup_register(pool, (void *)newproc, apr_netware_proc_cleanup,
334         apr_pool_cleanup_null);
335
336     return APR_SUCCESS;
337 }
338
339 APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
340                                                   int *exitcode,
341                                                   apr_exit_why_e *exitwhy,
342                                                   apr_wait_how_e waithow,
343                                                   apr_pool_t *p)
344 {
345     proc->pid = -1;
346     return apr_proc_wait(proc, exitcode, exitwhy, waithow);
347 }
348
349 APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc,
350                                         int *exitcode, apr_exit_why_e *exitwhy,
351                                         apr_wait_how_e waithow)
352 {
353     pid_t pstatus;
354     int waitpid_options = WUNTRACED;
355     int exit_int;
356     int ignore;
357     apr_exit_why_e ignorewhy;
358
359     if (exitcode == NULL) {
360         exitcode = &ignore;
361     }
362
363     if (exitwhy == NULL) {
364         exitwhy = &ignorewhy;
365     }
366
367     if (waithow != APR_WAIT) {
368         waitpid_options |= WNOHANG;
369     }
370
371     /* If the pid is 0 then the process was started detached. There 
372        is no need to wait since there is nothing to wait for on a 
373        detached process.  Starting a process as non-detached and
374        then calling wait or waitpid could cause the thread to hang.
375        The reason for this is because NetWare does not have a way 
376        to kill or even signal a process to be killed.  Starting 
377        all processes as detached avoids the possibility of a 
378        thread hanging. */
379     if (proc->pid == 0) {
380         *exitwhy = APR_PROC_EXIT;
381         *exitcode = 0;
382         return APR_CHILD_DONE;
383     }
384
385     if ((pstatus = waitpid(proc->pid, &exit_int, waitpid_options)) > 0) {
386         proc->pid = pstatus;
387
388         if (WIFEXITED(exit_int)) {
389             *exitwhy = APR_PROC_EXIT;
390             *exitcode = WEXITSTATUS(exit_int);
391         }
392         else if (WIFSIGNALED(exit_int)) {
393             *exitwhy = APR_PROC_SIGNAL;
394             *exitcode = WIFTERMSIG(exit_int);
395         }
396         else {
397             /* unexpected condition */
398             return APR_EGENERAL;
399         }
400
401         return APR_CHILD_DONE;
402     }
403     else if (pstatus == 0) {
404         return APR_CHILD_NOTDONE;
405     }
406
407     return errno;
408 }
409
410 APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr, apr_int32_t what, 
411                           struct rlimit *limit)
412 {
413     switch(what) {
414         case APR_LIMIT_CPU:
415 #ifdef RLIMIT_CPU
416             attr->limit_cpu = limit;
417             break;
418 #else
419             return APR_ENOTIMPL;
420 #endif
421         case APR_LIMIT_MEM:
422 #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
423             attr->limit_mem = limit;
424             break;
425 #else
426             return APR_ENOTIMPL;
427 #endif
428         case APR_LIMIT_NPROC:
429 #ifdef RLIMIT_NPROC
430             attr->limit_nproc = limit;
431             break;
432 #else
433             return APR_ENOTIMPL;
434 #endif
435     }
436     return APR_SUCCESS;
437 }  
438