| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * This file will include OS specific functions which are not inlineable. |
| * Any inlineable functions should be defined in os-inline.c instead. |
| */ |
| |
| #include "httpd.h" |
| #include "http_core.h" |
| #include "os.h" |
| #include "scoreboard.h" |
| #include "http_log.h" |
| #include "http_conf_globals.h" |
| #ifdef TPF41 |
| #ifdef __PIPE_ |
| #include <ipc.h> |
| #include <shm.h> |
| static TPF_FD_LIST *tpf_fds = NULL; |
| #endif /* __PIPE_ */ |
| #else |
| #include <sys/ipc.h> |
| #include <sys/shm.h> |
| static TPF_FD_LIST *tpf_fds = NULL; |
| #endif /* TPF41 */ |
| |
| void *tpf_shm_static_ptr = NULL; |
| unsigned short zinet_model; |
| char *argv_ptr = NULL; |
| |
| static FILE *sock_fp; |
| static int sock_sd; |
| |
| int tpf_select(int maxfds, fd_set *reads, fd_set *writes, fd_set *excepts, |
| struct timeval *tv) |
| { |
| /* We're going to force our way through select. We're only interested reads |
| and TPF allows 2billion+ socket descriptors for we don't want an fd_set |
| that big. Just assume that maxfds-1 contains the socket descriptor we're |
| interested in. If it's 0, leave it alone. */ |
| |
| int sockets[1]; |
| int no_reads = 0; |
| int no_writes = 0; |
| int no_excepts = 0; |
| int timeout_seconds = 0; |
| int timeout_millisec = 0; |
| int rv = 0; |
| |
| if(maxfds) { |
| if(tv) |
| timeout_millisec = tv->tv_sec * 1000 + tv->tv_usec; |
| sockets[0] = maxfds-1; |
| no_reads++; |
| } |
| else |
| sockets[0] = 0; |
| |
| ap_check_signals(); |
| if ((no_reads + no_writes + no_excepts == 0) && |
| (tv) && (tv->tv_sec + tv->tv_usec != 0)) { |
| /* TPF's select immediately returns if the sum of |
| no_reads, no_writes, and no_excepts is zero. |
| The following code makes TPF's select work a little closer |
| to everyone else's select: |
| */ |
| #ifdef TPF_HAVE_SAWNC |
| struct ev0bk evnblock; |
| #endif |
| /* event processing uses seconds, select uses milliseconds */ |
| timeout_seconds = tv->tv_sec; |
| if (tv->tv_usec) { |
| timeout_seconds++; /* round up to seconds (like TPF's select does) */ |
| } |
| if (timeout_seconds > 0) { /* paranoid check for valid timeout */ |
| #ifdef TPF_HAVE_SAWNC |
| evnblock.evnpstinf.evnbkc1 = 1; /* nbr of posts needed */ |
| evntc(&evnblock, EVENT_CNT, 'N', timeout_seconds, EVNTC_1052); |
| tpf_sawnc(&evnblock, EVENT_CNT); |
| #else |
| sleep(timeout_seconds); |
| #endif |
| } |
| } else { |
| if (timeout_millisec < 0) { /* paranoid check for valid timeout */ |
| timeout_millisec = 0; |
| } |
| if (timeout_millisec != 0) |
| timeout_millisec += 1000; |
| |
| rv = select(sockets, no_reads, no_writes, no_excepts, timeout_millisec); |
| } |
| ap_check_signals(); |
| |
| return rv; |
| |
| } |
| |
| int tpf_accept(int sockfd, struct sockaddr *peer, int *paddrlen) |
| { |
| extern pid_t tpf_parent_pid; |
| int socks[1]; |
| int rv; |
| |
| socks[0] = sockfd; |
| rv = select(socks, 1, 0, 0, 1 * 1000); |
| ap_check_signals(); |
| if ((rv == 0) && (errno == 0)) { |
| /* select timed out */ |
| errno = EINTR; /* make errno look like accept was interruped */ |
| /* now's a good time to make sure our parent didn't abnormally exit */ |
| if (getppid() == 1) { |
| /* our parent is gone... close the socket so Apache can restart |
| (it shouldn't still be open but we're taking no chances) */ |
| closesocket(sockfd); |
| ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, NULL, |
| "child %d closing the socket because getppid()" |
| " returned 1 instead of parent pid %d", |
| getpid(), tpf_parent_pid); |
| errno = 0; |
| } |
| return -1; |
| } |
| /* paranoid check for rv == 0 and errno != 0, should never happen */ |
| if (rv == 0) { |
| rv = -1; |
| } |
| |
| if(rv>0) { |
| rv = accept(sockfd, peer, paddrlen); |
| errno = sock_errno(); |
| } |
| return rv; |
| } |
| |
| /* the getpass function is not usable on TPF */ |
| char *getpass(const char* prompt) |
| { |
| errno = EIO; |
| return((char *)NULL); |
| } |
| |
| /* fork and exec functions are not defined on |
| TPF due to the implementation of tpf_fork() */ |
| |
| pid_t fork(void) |
| { |
| errno = ENOSYS; |
| return(-1); |
| } |
| |
| int execl(const char *path, const char *arg0, ...) |
| { |
| errno = ENOSYS; |
| return(-1); |
| } |
| |
| int execle(const char *path, const char *arg0, ...) |
| { |
| errno = ENOSYS; |
| return(-1); |
| } |
| |
| int execve(const char *path, char *const argv[], char *const envp[]) |
| { |
| errno = ENOSYS; |
| return(-1); |
| } |
| |
| int execvp(const char *file, char *const argv[]) |
| { |
| errno = ENOSYS; |
| return(-1); |
| } |
| |
| |
| |
| int ap_tpf_spawn_child(pool *p, int (*func) (void *, child_info *), |
| void *data, enum kill_conditions kill_how, |
| int *pipe_in, int *pipe_out, int *pipe_err, |
| int out_fds[], int in_fds[], int err_fds[]) |
| |
| { |
| int i, temp_out=0, temp_in=0, temp_err=0, save_errno, pid, result=0; |
| int fd_flags_out=0, fd_flags_in=0, fd_flags_err=0; |
| struct tpf_fork_input fork_input; |
| TPF_FORK_CHILD *cld = (TPF_FORK_CHILD *) data; |
| #ifdef TPF_FORK_EXTENDED |
| #define WHITE " \t\n" |
| #define MAXARGC 49 |
| char *arguments; |
| char *args[MAXARGC + 1]; |
| char **envp = NULL; |
| pool *subpool = NULL; |
| |
| #include "util_script.h" |
| #else |
| array_header *env_arr = ap_table_elts ((array_header *) cld->subprocess_env); |
| table_entry *elts = (table_entry *) env_arr->elts; |
| #endif /* TPF_FORK_EXTENDED */ |
| |
| if (func) { |
| if ((result=func(data, NULL))) { |
| return 0; /* error from child function */ |
| } |
| } |
| |
| if (pipe_out) { |
| fd_flags_out = fcntl(out_fds[0], F_GETFD); |
| fcntl(out_fds[0], F_SETFD, FD_CLOEXEC); |
| temp_out = dup(STDOUT_FILENO); |
| fcntl(temp_out, F_SETFD, FD_CLOEXEC); |
| dup2(out_fds[1], STDOUT_FILENO); |
| } |
| |
| if (pipe_in) { |
| fd_flags_in = fcntl(in_fds[1], F_GETFD); |
| fcntl(in_fds[1], F_SETFD, FD_CLOEXEC); |
| temp_in = dup(STDIN_FILENO); |
| fcntl(temp_in, F_SETFD, FD_CLOEXEC); |
| dup2(in_fds[0], STDIN_FILENO); |
| } |
| |
| if (pipe_err) { |
| fd_flags_err = fcntl(err_fds[0], F_GETFD); |
| fcntl(err_fds[0], F_SETFD, FD_CLOEXEC); |
| temp_err = dup(STDERR_FILENO); |
| fcntl(temp_err, F_SETFD, FD_CLOEXEC); |
| dup2(err_fds[1], STDERR_FILENO); |
| } |
| |
| /* set up environment variables for the tpf_fork */ |
| if (cld->subprocess_env) { |
| #ifdef TPF_FORK_EXTENDED |
| /* with extended tpf_fork( ) we pass the pointer to a list of pointers */ |
| /* that point to "key=value" strings for each env variable */ |
| subpool = ap_make_sub_pool(p); |
| envp = ap_create_environment(subpool, cld->subprocess_env); |
| #else |
| /* without extended tpf_fork( ) we setenv( ) each env variable */ |
| /* so the child inherits them */ |
| for (i = 0; i < env_arr->nelts; ++i) { |
| if (!elts[i].key) |
| continue; |
| setenv (elts[i].key, elts[i].val, 1); |
| } |
| #endif /* TPF_FORK_EXTENDED */ |
| } |
| |
| fork_input.program = (const char*) cld->filename; |
| fork_input.prog_type = cld->prog_type; |
| fork_input.istream = TPF_FORK_IS_BALANCE; |
| fork_input.ebw_data_length = 0; |
| fork_input.ebw_data = NULL; |
| fork_input.parm_data = NULL; |
| |
| #ifdef TPF_FORK_EXTENDED |
| /* use a copy of cld->filename because strtok is destructive */ |
| arguments = ap_pstrdup(p, cld->filename); |
| args[0] = strtok(arguments, WHITE); |
| |
| for (i = 0; i < MAXARGC && args[i] ; i++) { |
| args[i + 1] = strtok(NULL, WHITE); |
| } |
| args[MAXARGC] = NULL; |
| |
| if ((pid = tpf_fork(&fork_input, |
| (const char **)args, |
| (const char **)envp)) < 0) { |
| #else |
| if ((pid = tpf_fork(&fork_input)) < 0) { |
| #endif /* TPF_FORK_EXTENDED */ |
| save_errno = errno; |
| if (pipe_out) { |
| close(out_fds[0]); |
| } |
| if (pipe_in) { |
| close(in_fds[1]); |
| } |
| if (pipe_err) { |
| close(err_fds[0]); |
| } |
| errno = save_errno; |
| pid = 0; |
| } |
| |
| #ifdef TPF_FORK_EXTENDED |
| if (subpool) { |
| ap_destroy_pool(subpool); |
| } |
| #else |
| if (cld->subprocess_env) { |
| for (i = 0; i < env_arr->nelts; ++i) { |
| if (!elts[i].key) |
| continue; |
| unsetenv (elts[i].key); |
| } |
| } |
| #endif /* TPF_FORK_EXTENDED */ |
| |
| if (pipe_out) { |
| close(out_fds[1]); |
| dup2(temp_out, STDOUT_FILENO); |
| close(temp_out); |
| fcntl(out_fds[0], F_SETFD, fd_flags_out); |
| } |
| |
| if (pipe_in) { |
| close(in_fds[0]); |
| dup2(temp_in, STDIN_FILENO); |
| close(temp_in); |
| fcntl(in_fds[1], F_SETFD, fd_flags_in); |
| } |
| |
| |
| if (pipe_err) { |
| close(err_fds[1]); |
| dup2(temp_err, STDERR_FILENO); |
| close(temp_err); |
| fcntl(err_fds[0], F_SETFD, fd_flags_err); |
| } |
| |
| |
| if (pid) { |
| |
| ap_note_subprocess(p, pid, kill_how); |
| |
| if (pipe_out) { |
| *pipe_out = out_fds[0]; |
| } |
| if (pipe_in) { |
| *pipe_in = in_fds[1]; |
| } |
| if (pipe_err) { |
| *pipe_err = err_fds[0]; |
| } |
| } |
| |
| return pid; |
| |
| } |
| |
| pid_t os_fork(server_rec *s, int slot) |
| { |
| struct tpf_fork_input fork_input; |
| APACHE_TPF_INPUT input_parms; |
| int count; |
| listen_rec *lr; |
| |
| input_parms.generation = ap_my_generation; |
| #ifdef USE_SHMGET_SCOREBOARD |
| input_parms.scoreboard_heap = ap_scoreboard_image; |
| #endif |
| |
| lr = ap_listeners; |
| count = 0; |
| do { |
| input_parms.listeners[count] = lr->fd; |
| lr = lr->next; |
| count++; |
| } while(lr != ap_listeners); |
| |
| input_parms.slot = slot; |
| input_parms.restart_time = ap_restart_time; |
| input_parms.shm_static_ptr = tpf_shm_static_ptr; |
| input_parms.tpf_fds = tpf_fds; |
| fork_input.ebw_data = &input_parms; |
| fork_input.program = ap_server_argv0; |
| fork_input.prog_type = TPF_FORK_NAME; |
| fork_input.istream = TPF_FORK_IS_BALANCE; |
| fork_input.ebw_data_length = sizeof(input_parms); |
| fork_input.parm_data = argv_ptr; |
| #ifdef TPF_FORK_EXTENDED |
| return tpf_fork(&fork_input, NULL, NULL); |
| #else |
| return tpf_fork(&fork_input); |
| #endif /* TPF_FORK_EXTENDED */ |
| } |
| |
| void ap_tpf_zinet_checks(int standalone, |
| const char *servername, |
| server_rec *s) { |
| |
| INETD_IDCT_ENTRY_PTR idct; |
| |
| /* explicitly disallow "ServerType inetd" on TPF */ |
| if (!standalone) { |
| ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, s, |
| TPF_SERVERTYPE_MSG); |
| exit(1); /* abort start-up of server */ |
| } |
| |
| /* figure out zinet model for our server from the idct slot */ |
| idct = inetd_getServer(servername); |
| if (idct) { |
| zinet_model = idct->model; |
| free(idct); |
| } else { |
| ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, s, |
| TPF_UNABLE_TO_DETERMINE_ZINET_MODEL, servername); |
| exit(1); /* abort start-up of server */ |
| } |
| |
| /* check for valid zinet models */ |
| if (zinet_model != INETD_IDCF_MODEL_DAEMON && |
| zinet_model != INETD_IDCF_MODEL_NOLISTEN) { |
| ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, s, |
| TPF_STANDALONE_CONFLICT_MSG); |
| exit(1); /* abort start-up of server */ |
| } |
| |
| #ifdef TPF_NOLISTEN_WARNING |
| /* nag about switching to DAEMON model */ |
| if (zinet_model == INETD_IDCF_MODEL_NOLISTEN) { |
| ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, s, |
| TPF_NOLISTEN_WARNING); |
| } |
| #endif |
| |
| } |
| |
| int os_check_server(char *server) { |
| int *current_acn; |
| |
| ap_check_signals(); |
| |
| /* check our InetD status */ |
| if (inetd_getServerStatus(server) != INETD_SERVER_STATUS_ACTIVE) { |
| return 1; /* shutdown */ |
| } |
| |
| /* if DAEMON model, make sure CLTZ parent is still around */ |
| if (zinet_model == INETD_IDCF_MODEL_DAEMON) { |
| if (getppid() == 1) { |
| return 1; /* shutdown */ |
| } |
| } else { |
| /* this is the NOLISTEN model (INETD_IDCF_MODEL_NOLISTEN) */ |
| /* check that the program activation number hasn't changed */ |
| current_acn = (int *)cinfc_fast(CINFC_CMMACNUM); |
| if (ecbp2()->ce2acn != *current_acn) { |
| return 1; /* shutdown */ |
| } |
| } |
| |
| return 0; /* keep on running... */ |
| } |
| |
| void os_note_additional_cleanups(pool *p, int sd) { |
| char sockfilename[50]; |
| /* write the socket to file so that TPF socket device driver |
| will close socket in case we happen to abend. */ |
| sprintf(sockfilename, "/dev/tpf.socket.file/%.8X", sd); |
| sock_fp = fopen(sockfilename, "r+"); |
| /* we don't want the children to inherit this fd */ |
| fcntl(fileno(sock_fp), F_SETFD, FD_CLOEXEC); |
| sock_sd = sd; |
| } |
| |
| void ap_tpf_save_argv(int argc, char **argv) { |
| |
| int i, len = 3; /* 3 for "-x " */ |
| |
| for (i = 1; i < argc; i++) { /* find len for calloc */ |
| len += strlen (argv[i]); |
| ++len; /* 1 for blank */ |
| } |
| |
| argv_ptr = malloc(len + 1); |
| strcpy(argv_ptr, "-x"); |
| for (i = 1; i < argc; i++) { |
| strcat(argv_ptr, " "); |
| strcat(argv_ptr, argv[i]); |
| } |
| } |
| |
| void os_tpf_child(APACHE_TPF_INPUT *input_parms) { |
| extern pid_t tpf_parent_pid; |
| extern char tpf_mutex_key[TPF_MUTEX_KEY_SIZE]; |
| |
| tpf_child = 1; |
| ap_my_generation = input_parms->generation; |
| ap_restart_time = input_parms->restart_time; |
| tpf_fds = input_parms->tpf_fds; |
| tpf_shm_static_ptr = input_parms->shm_static_ptr; |
| tpf_parent_pid = getppid(); |
| sprintf(tpf_mutex_key, "%.*x", (int) TPF_MUTEX_KEY_SIZE - 1, tpf_parent_pid); |
| } |
| |
| #if defined(TPF41) && !defined(__PIPE_) |
| |
| int pipe(int fildes[2]) |
| { |
| errno = ENOSYS; |
| return(-1); |
| } |
| |
| API_EXPORT(piped_log *) ap_open_piped_log(pool *p, const char *program) |
| |
| { |
| fprintf(stderr, "Pipes not supported on this TPF system\n"); |
| exit (1); |
| } |
| |
| #else |
| |
| void ap_tpf_detach_shared_mem(void *address) |
| { |
| if (*((void **)address)) { |
| shmdt(*((void **)address)); |
| *((void **)address) = NULL; |
| } |
| } |
| |
| static void *ap_tpf_get_shared_mem(size_t size) |
| { |
| key_t shmkey = IPC_PRIVATE; |
| int shmid = -1; |
| static void *result; |
| |
| if ((shmid = shmget(shmkey, size, IPC_CREAT | SHM_R | SHM_W)) == -1) { |
| perror("shmget failed in ap_tpf_get_shared_mem function"); |
| exit(1); |
| } |
| #define BADSHMAT ((void *)(-1)) |
| if ((result = shmat(shmid, 0, 0)) == BADSHMAT) { |
| perror("shmat failed in ap_tpf_get_shared_mem"); |
| } |
| if (shmctl(shmid, IPC_RMID, NULL) != 0) { |
| perror("shmctl(IPC_RMID) failed in ap_tpf_get_shared_mem"); |
| } |
| if (result == BADSHMAT) { /* now bailout */ |
| exit(1); |
| } |
| |
| return result; |
| } |
| |
| int ap_tpf_fd_lookup(enum FILE_TYPE file_type, const char *fname) |
| /* lookup a fd in the fd inheritance table */ |
| { |
| if (tpf_fds) { |
| int i; |
| TPF_FD_ITEM *fd_item = &tpf_fds->first_item; |
| |
| for (i = 1; i <= tpf_fds->nbr_of_items; i++, fd_item++) { |
| /* check for an fd with the same type and name */ |
| if ((file_type == fd_item->file_type) && |
| (strcmp(fname, fd_item->fname) == 0) ) { |
| /* we've got a match, check that fd is still open */ |
| struct stat stbuf; |
| |
| if (fstat(fd_item->fd, &stbuf) == 0) { |
| return(fd_item->fd); |
| } |
| else { |
| /* fd is not open - the entire fd table is suspect */ |
| fprintf(stderr, "fstat failed in ap_tpf_fd_lookup " |
| "for fd %i (filename/pipe to %s): %s\n", |
| fd_item->fd, fname, strerror(errno)); |
| ap_tpf_detach_shared_mem(&tpf_fds); |
| return(-1); |
| } |
| } |
| } |
| } |
| return(-1); |
| } |
| |
| void ap_tpf_add_fd(pool *p, int fd, enum FILE_TYPE file_type, const char *fname) |
| /* add a newly opened fd to the fd inheritance table */ |
| { |
| int fname_size; |
| |
| if (tpf_child) { |
| return; /* no kids allowed */ |
| } |
| if (tpf_fds == NULL) { |
| /* get shared memory if necessary */ |
| tpf_fds = ap_tpf_get_shared_mem((size_t)TPF_FD_LIST_SIZE); |
| if (tpf_fds) { |
| ap_register_cleanup(p, (void *)&tpf_fds, |
| ap_tpf_detach_shared_mem, ap_null_cleanup); |
| tpf_fds->nbr_of_items = 0; |
| tpf_fds->next_avail_byte = &tpf_fds->first_item; |
| tpf_fds->last_avail_byte = (char *)tpf_fds + TPF_FD_LIST_SIZE; |
| } |
| } |
| /* add fd */ |
| if (tpf_fds) { |
| TPF_FD_ITEM *fd_item; |
| |
| /* make sure there's room */ |
| fname_size = strlen(fname) + 1; |
| if (sizeof(TPF_FD_ITEM) + fname_size > |
| (char *)tpf_fds->last_avail_byte - |
| (char *)tpf_fds->next_avail_byte) { |
| fprintf(stderr, "fd inheritance table out of room, increase " |
| "TPF_FD_LIST_SIZE in os.h and recompile Apache\n"); |
| exit(1); |
| } |
| /* add the new item */ |
| fd_item = tpf_fds->next_avail_byte; |
| tpf_fds->next_avail_byte = fd_item + 1; |
| tpf_fds->last_avail_byte |
| = (char *)tpf_fds->last_avail_byte - fname_size; |
| fd_item->fname = tpf_fds->last_avail_byte; |
| strcpy(fd_item->fname, fname); |
| fd_item->fd = fd; |
| fd_item->file_type = file_type; |
| tpf_fds->nbr_of_items++; |
| } |
| } |
| |
| API_EXPORT(piped_log *) ap_open_piped_log(pool *p, const char *program) |
| { |
| int log_fd; |
| piped_log *pl; |
| |
| /* check fd inheritance table to see if this log is already open */ |
| log_fd = ap_tpf_fd_lookup(PIPE_OUT, program); |
| if (log_fd < 0) { |
| /* this is a new log - open it */ |
| FILE *dummy; |
| TPF_FORK_CHILD cld; |
| cld.filename = (char *)program; |
| cld.subprocess_env = NULL; |
| cld.prog_type = FORK_NAME; |
| |
| if (ap_spawn_child(p, NULL, &cld, kill_after_timeout, |
| &dummy, NULL, NULL)) { |
| log_fd = fileno(dummy); |
| /* add this log to the fd inheritance table */ |
| ap_tpf_add_fd(p, log_fd, PIPE_OUT, program); |
| } |
| else { |
| perror("ap_spawn_child"); |
| fprintf(stderr, "Couldn't fork child for piped log process\n"); |
| exit (1); |
| } |
| } |
| |
| pl = ap_palloc(p, sizeof (*pl)); |
| pl->p = p; |
| pl->fds[1] = log_fd; |
| |
| return pl; |
| } |
| |
| #endif /* TPF41 && ndef __PIPE_ */ |
| |
| /* The following functions are used for the tpf specific module called |
| mod_tpf_shm_static. This module is a clone of Apache's mod_mmap_static. |
| Because TPF doesn't support the system call mmap(), it is replaced by |
| shared memory, but uses the mmap directives, etc. */ |
| |
| union align{ |
| |
| /* Types which are likely to have the longest RELEVANT alignment |
| * restrictions... */ |
| |
| char *cp; |
| void (*f) (void); |
| long l; |
| FILE *fp; |
| double d; |
| }; |
| |
| #define CLICK_SZ (sizeof(union align)) |
| union block_hdr { |
| union align a; |
| |
| /* Actual header... */ |
| |
| struct { |
| char *endp; |
| union block_hdr *next; |
| char *first_avail; |
| #ifdef POOL_DEBUG |
| union block_hdr *global_next; |
| struct pool *owning_pool; |
| #endif |
| } h; |
| }; |
| |
| struct pool { |
| union block_hdr *first; |
| union block_hdr *last; |
| struct cleanup *cleanups; |
| struct process_chain *subprocesses; |
| struct pool *sub_pools; |
| struct pool *sub_next; |
| struct pool *sub_prev; |
| struct pool *parent; |
| char *free_first_avail; |
| #ifdef ALLOC_USE_MALLOC |
| void *allocation_list; |
| #endif |
| #ifdef POOL_DEBUG |
| struct pool *joined; |
| #endif |
| }; |
| |
| #include "ap_alloc.h" |
| #define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ)) |
| #define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ) |
| |
| pool * ap_get_shared_mem_pool(size_t size) |
| { |
| pool *new_pool; |
| union block_hdr *blok; |
| |
| blok = (union block_hdr *) ap_tpf_get_shared_mem(size); |
| /* if shm fails, it will exit blok will be valid here */ |
| memset((char *) blok, '\0', size); |
| blok->h.next = NULL; |
| blok->h.first_avail = (char *) (blok + 1); |
| blok->h.endp = size + blok->h.first_avail; |
| new_pool = (pool *) blok->h.first_avail; |
| blok->h.first_avail += POOL_HDR_BYTES; |
| new_pool->free_first_avail = blok->h.first_avail; |
| new_pool->first = new_pool->last = blok; |
| |
| return new_pool; |
| } |
| |
| int ap_check_shm_space(struct pool *a, int size) |
| { |
| union block_hdr *blok = a->last; |
| char *first_avail = blok->h.first_avail; |
| char *new_first_avail; |
| |
| new_first_avail = first_avail + size; |
| if (new_first_avail <= blok->h.endp) { |
| return (1); |
| } |
| else |
| return (0); |
| } |
| |
| /* |
| This function serves as an interim killpg for Apache shutdown purposes. |
| TPF won't have an actual killpg for a very long time, if ever. |
| (And kill with a negative pid doesn't work on TPF either.) |
| */ |
| int killpg(pid_t pgrp, int sig) |
| { |
| struct ev0bk evnblock; |
| struct timeval tv; |
| int i; |
| |
| ap_sync_scoreboard_image(); |
| |
| for (i = 0; i < HARD_SERVER_LIMIT; ++i) { |
| int pid = ap_scoreboard_image->parent[i].pid; |
| /* the pgrp check is so that we don't kill ourself: */ |
| if (pid && pid != pgrp) { |
| kill(pid, sig); |
| } |
| } |
| /* Allow time for the signals to get to the children. |
| Note that ap_select is signal interruptable, |
| so we use evnwc instead. */ |
| i = TPF_SHUTDOWN_SIGNAL_DELAY; |
| evnblock.evnpstinf.evnbkc1 = 1; /* nbr of posts needed */ |
| evntc(&evnblock, EVENT_CNT, 'N', i, EVNTC_1052); |
| evnwc(&evnblock, EVENT_CNT); |
| |
| if (sig == SIGTERM) { |
| /* get idle children's attention by closing the socket */ |
| closesocket(sock_sd); |
| /* and close the /dev/tpf.socket.file special file */ |
| fclose(sock_fp); |
| /* Allow the children some more time. |
| Note that ap_select is signal interruptable, |
| so we use evnwc instead. */ |
| i = TPF_SHUTDOWN_CLOSING_DELAY; |
| evnblock.evnpstinf.evnbkc1 = 1; /* nbr of posts needed */ |
| evntc(&evnblock, EVENT_CNT, 'N', i, EVNTC_1052); |
| evnwc(&evnblock, EVENT_CNT); |
| } |
| |
| return(0); |
| } |
| |
| /* |
| This function augments http_main's show_compile_settings function. |
| This way definitions that are only shown on TPF won't clutter up |
| main line code. |
| */ |
| void show_os_specific_compile_settings(void) |
| { |
| int i; |
| |
| #ifdef USE_TPF_SCOREBOARD |
| #error "USE_TPF_SCOREBOARD (system heap scoreboard)" |
| #error "is no longer supported." |
| #error "Replace with USE_SHMGET_SCOREBOARD to use" |
| #error "shared memory or remove entirely to use" |
| #error "scoreboard on file for pre-TPF41 PUT10 systems" |
| #endif |
| |
| #ifdef TPF_FORK_EXTENDED |
| printf(" -D TPF_FORK_EXTENDED\n"); |
| #endif |
| |
| #ifdef TPF_HAVE_NONSOCKET_SELECT |
| printf(" -D TPF_HAVE_NONSOCKET_SELECT\n"); |
| #endif |
| |
| #ifdef TPF_NO_NONSOCKET_SELECT |
| printf(" -D TPF_NO_NONSOCKET_SELECT\n"); |
| #endif |
| |
| #ifdef TPF_HAVE_SAWNC |
| printf(" -D TPF_HAVE_SAWNC\n"); |
| #endif |
| |
| #ifdef TPF_NO_SAWNC |
| printf(" -D TPF_NO_SAWNC\n"); |
| #endif |
| |
| #ifdef TPF_HAVE_NSD |
| printf(" -D TPF_HAVE_NSD\n"); |
| #endif |
| |
| #ifdef HAVE_SYSLOG |
| printf(" -D HAVE_SYSLOG\n"); |
| #endif |
| |
| /* round SCOREBOARD_MAINTENANCE_INTERVAL up to seconds */ |
| i = (SCOREBOARD_MAINTENANCE_INTERVAL + 999999) / 1000000; |
| if (i == 1) { |
| printf(" -D SCOREBOARD_MAINTENANCE_INTERVAL=1 SECOND\n"); |
| } else { |
| printf(" -D SCOREBOARD_MAINTENANCE_INTERVAL=%i SECONDS\n", i); |
| } |
| |
| #ifdef TPF_HAVE_SIGACTION |
| printf(" -D TPF_HAVE_SIGACTION\n"); |
| #endif |
| |
| #ifdef NO_USE_SIGACTION |
| printf(" -D NO_USE_SIGACTION\n"); |
| #endif |
| |
| } |