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.h" 18#include "apr_arch_misc.h" 19#include "apr_arch_threadproc.h" 20#include "apr_arch_file_io.h" 21 22#if APR_HAS_OTHER_CHILD 23 24#ifdef HAVE_TIME_H 25#include <sys/time.h> 26#endif 27#ifdef HAVE_SYS_SELECT_H 28#include <sys/select.h> 29#endif 30#if APR_HAVE_SYS_WAIT_H 31#include <sys/wait.h> 32#endif 33#ifdef BEOS 34#include <sys/socket.h> /* for fd_set definition! */ 35#endif 36 37static apr_other_child_rec_t *other_children = NULL; 38 39static apr_status_t other_child_cleanup(void *data) 40{ 41 apr_other_child_rec_t **pocr, *nocr; 42 43 for (pocr = &other_children; *pocr; pocr = &(*pocr)->next) { 44 if ((*pocr)->data == data) { 45 nocr = (*pocr)->next; 46 (*(*pocr)->maintenance) (APR_OC_REASON_UNREGISTER, (*pocr)->data, -1); 47 *pocr = nocr; 48 /* XXX: um, well we've just wasted some space in pconf ? */ 49 return APR_SUCCESS; 50 } 51 } 52 return APR_SUCCESS; 53} 54 55APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc, 56 void (*maintenance) (int reason, void *, int status), 57 void *data, apr_file_t *write_fd, apr_pool_t *p) 58{ 59 apr_other_child_rec_t *ocr; 60 61 ocr = apr_palloc(p, sizeof(*ocr)); 62 ocr->p = p; 63 ocr->proc = proc; 64 ocr->maintenance = maintenance; 65 ocr->data = data; 66 if (write_fd == NULL) { 67 ocr->write_fd = (apr_os_file_t) -1; 68 } 69 else { 70#ifdef WIN32 71 /* This should either go away as part of eliminating apr_proc_probe_writable_fds 72 * or write_fd should point to an apr_file_t 73 */ 74 ocr->write_fd = write_fd->filehand; 75#else 76 ocr->write_fd = write_fd->filedes; 77#endif 78 79 } 80 ocr->next = other_children; 81 other_children = ocr; 82 apr_pool_cleanup_register(p, ocr->data, other_child_cleanup, 83 apr_pool_cleanup_null); 84} 85 86APR_DECLARE(void) apr_proc_other_child_unregister(void *data) 87{ 88 apr_other_child_rec_t *cur; 89 90 cur = other_children; 91 while (cur) { 92 if (cur->data == data) { 93 break; 94 } 95 cur = cur->next; 96 } 97 98 /* segfault if this function called with invalid parm */ 99 apr_pool_cleanup_kill(cur->p, cur->data, other_child_cleanup); 100 other_child_cleanup(data); 101} 102 103APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc, 104 int reason, 105 int status) 106{ 107 apr_other_child_rec_t *ocr, *nocr; 108 109 for (ocr = other_children; ocr; ocr = nocr) { 110 nocr = ocr->next; 111 if (ocr->proc->pid != proc->pid) 112 continue; 113 114 ocr->proc = NULL; 115 (*ocr->maintenance) (reason, ocr->data, status); 116 return APR_SUCCESS; 117 } 118 return APR_EPROC_UNKNOWN; 119} 120 121APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr, 122 int reason) 123{ 124 /* Todo: 125 * Implement code to detect if pipes are still alive. 126 */ 127#ifdef WIN32 128 DWORD status; 129 130 if (ocr->proc == NULL) 131 return; 132 133 if (!ocr->proc->hproc) { 134 /* Already mopped up, perhaps we apr_proc_kill'ed it, 135 * they should have already unregistered! 136 */ 137 ocr->proc = NULL; 138 (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1); 139 } 140 else if (!GetExitCodeProcess(ocr->proc->hproc, &status)) { 141 CloseHandle(ocr->proc->hproc); 142 ocr->proc->hproc = NULL; 143 ocr->proc = NULL; 144 (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1); 145 } 146 else if (status == STILL_ACTIVE) { 147 (*ocr->maintenance) (reason, ocr->data, -1); 148 } 149 else { 150 CloseHandle(ocr->proc->hproc); 151 ocr->proc->hproc = NULL; 152 ocr->proc = NULL; 153 (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status); 154 } 155 156#else /* ndef Win32 */ 157 pid_t waitret; 158 int status; 159 160 if (ocr->proc == NULL) 161 return; 162 163 waitret = waitpid(ocr->proc->pid, &status, WNOHANG); 164 if (waitret == ocr->proc->pid) { 165 ocr->proc = NULL; 166 (*ocr->maintenance) (APR_OC_REASON_DEATH, ocr->data, status); 167 } 168 else if (waitret == 0) { 169 (*ocr->maintenance) (reason, ocr->data, -1); 170 } 171 else if (waitret == -1) { 172 /* uh what the heck? they didn't call unregister? */ 173 ocr->proc = NULL; 174 (*ocr->maintenance) (APR_OC_REASON_LOST, ocr->data, -1); 175 } 176#endif 177} 178 179APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason) 180{ 181 apr_other_child_rec_t *ocr, *next_ocr; 182 183 for (ocr = other_children; ocr; ocr = next_ocr) { 184 next_ocr = ocr->next; 185 apr_proc_other_child_refresh(ocr, reason); 186 } 187} 188 189#else /* !APR_HAS_OTHER_CHILD */ 190 191APR_DECLARE(void) apr_proc_other_child_register(apr_proc_t *proc, 192 void (*maintenance) (int reason, void *, int status), 193 void *data, apr_file_t *write_fd, apr_pool_t *p) 194{ 195 return; 196} 197 198APR_DECLARE(void) apr_proc_other_child_unregister(void *data) 199{ 200 return; 201} 202 203APR_DECLARE(apr_status_t) apr_proc_other_child_alert(apr_proc_t *proc, 204 int reason, 205 int status) 206{ 207 return APR_ENOTIMPL; 208} 209 210APR_DECLARE(void) apr_proc_other_child_refresh(apr_other_child_rec_t *ocr, 211 int reason) 212{ 213 return; 214} 215 216APR_DECLARE(void) apr_proc_other_child_refresh_all(int reason) 217{ 218 return; 219} 220 221#endif /* APR_HAS_OTHER_CHILD */ 222