| #include "fcgid_proctbl.h" |
| #include "apr_version.h" |
| #include "apr_shm.h" |
| #include "apr_global_mutex.h" |
| #include "fcgid_global.h" |
| #include "fcgid_conf.h" |
| #include "unixd.h" |
| #include <unistd.h> |
| |
| static apr_shm_t *g_sharemem = NULL; |
| static apr_global_mutex_t *g_sharelock = NULL; |
| char g_sharelock_name[L_tmpnam]; |
| static fcgid_procnode *g_proc_array = NULL; /* Contain all process slot */ |
| static fcgid_procnode *g_free_list_header = NULL; /* Attach to no process list */ |
| static fcgid_procnode *g_busy_list_header = NULL; /* Attach to a working process list */ |
| static fcgid_procnode *g_idle_list_header = NULL; /* Attach to an idle process list */ |
| static fcgid_procnode *g_error_list_header = NULL; /* Attach to an error process list */ |
| static fcgid_share *_global_memory = NULL; |
| static fcgid_global_share *g_global_share = NULL; /* global information */ |
| static size_t g_table_size = FCGID_PROC_TABLE_SIZE; |
| |
| /* apr version 0.x not support apr_shm_remove, I have to copy it from apr version 1.x */ |
| #if (APR_MAJOR_VERSION < 1) |
| #ifdef HAVE_SYS_MMAN_H |
| #include <sys/mman.h> |
| #endif |
| #ifdef HAVE_SYS_IPC_H |
| #include <sys/ipc.h> |
| #endif |
| #ifdef HAVE_SYS_MUTEX_H |
| #include <sys/mutex.h> |
| #endif |
| #ifdef HAVE_SYS_SHM_H |
| #include <sys/shm.h> |
| #endif |
| #if !defined(SHM_R) |
| #define SHM_R 0400 |
| #endif |
| #if !defined(SHM_W) |
| #define SHM_W 0200 |
| #endif |
| #ifdef HAVE_SYS_FILE_H |
| #include <sys/file.h> |
| #endif |
| |
| static apr_status_t apr_shm_remove(const char *filename, apr_pool_t * pool) |
| { |
| #if APR_USE_SHMEM_SHMGET |
| apr_status_t status; |
| apr_file_t *file; |
| key_t shmkey; |
| int shmid; |
| #endif |
| |
| #if APR_USE_SHMEM_MMAP_TMP |
| return apr_file_remove(filename, pool); |
| #endif |
| #if APR_USE_SHMEM_MMAP_SHM |
| if (shm_unlink(filename) == -1) { |
| return errno; |
| } |
| return APR_SUCCESS; |
| #endif |
| #if APR_USE_SHMEM_SHMGET |
| /* Presume that the file already exists; just open for writing */ |
| status = apr_file_open(&file, filename, APR_WRITE, |
| APR_OS_DEFAULT, pool); |
| if (status) { |
| return status; |
| } |
| |
| /* ftok() (on solaris at least) requires that the file actually |
| * exist before calling ftok(). */ |
| shmkey = ftok(filename, 1); |
| if (shmkey == (key_t) - 1) { |
| goto shm_remove_failed; |
| } |
| |
| apr_file_close(file); |
| |
| if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) < 0) { |
| goto shm_remove_failed; |
| } |
| |
| /* Indicate that the segment is to be destroyed as soon |
| * as all processes have detached. This also disallows any |
| * new attachments to the segment. */ |
| if (shmctl(shmid, IPC_RMID, NULL) == -1) { |
| goto shm_remove_failed; |
| } |
| return apr_file_remove(filename, pool); |
| |
| shm_remove_failed: |
| status = errno; |
| /* ensure the file has been removed anyway. */ |
| apr_file_remove(filename, pool); |
| return status; |
| #endif |
| |
| /* No support for anonymous shm */ |
| return APR_ENOTIMPL; |
| } |
| #endif /* APR_MAJOR_VERSION<1 */ |
| |
| apr_status_t |
| proctable_post_config(server_rec * main_server, apr_pool_t * configpool) |
| { |
| size_t shmem_size = sizeof(fcgid_share); |
| fcgid_procnode *ptmpnode = NULL; |
| int i; |
| apr_status_t rv; |
| const char *fname; |
| |
| fname = get_shmpath(main_server); |
| |
| /* Remove share memory first */ |
| apr_shm_remove(fname, main_server->process->pconf); |
| |
| /* Create share memory */ |
| if ((rv = apr_shm_create(&g_sharemem, shmem_size, fname, |
| main_server->process->pconf)) != APR_SUCCESS) |
| { |
| ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server, |
| "mod_fcgid: Can't create share memory for size %zu byte", |
| shmem_size); |
| exit(1); |
| } |
| if ((_global_memory = apr_shm_baseaddr_get(g_sharemem)) == NULL) { |
| ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), |
| main_server, |
| "mod_fcgid: Can't get base address of share memory"); |
| exit(1); |
| } |
| |
| /* Create global mutex */ |
| if ((rv = |
| apr_global_mutex_create(&g_sharelock, tmpnam(g_sharelock_name), |
| APR_LOCK_DEFAULT, |
| main_server->process->pconf)) != |
| APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server, |
| "mod_fcgid: Can't create global mutex"); |
| exit(1); |
| } |
| if ((rv = unixd_set_global_mutex_perms(g_sharelock)) != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server, |
| "mod_fcgid: Can't set global mutex perms"); |
| exit(1); |
| } |
| |
| memset(_global_memory, 0, shmem_size); |
| g_proc_array = _global_memory->procnode_array; |
| g_global_share = &_global_memory->global; |
| |
| g_global_share->must_exit = 0; |
| |
| /* Init the array */ |
| g_idle_list_header = g_proc_array; |
| g_busy_list_header = g_idle_list_header + 1; |
| g_error_list_header = g_busy_list_header + 1; |
| g_free_list_header = g_error_list_header + 1; |
| ptmpnode = g_free_list_header; |
| for (i = 0; i < FCGID_MAX_APPLICATION; i++) { |
| ptmpnode->next_index = ptmpnode - g_proc_array + 1; |
| ptmpnode++; |
| } |
| |
| return APR_SUCCESS; |
| } |
| |
| apr_status_t |
| proctable_child_init(server_rec * main_server, apr_pool_t * configpool) |
| { |
| apr_status_t rv; |
| |
| if ((rv = apr_global_mutex_child_init(&g_sharelock, |
| g_sharelock_name, |
| main_server->process->pconf)) != |
| APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server, |
| "mod_fcgid: apr_global_mutex_child_init error"); |
| exit(1); |
| } |
| |
| return rv; |
| } |
| |
| apr_status_t proctable_lock_table(void) |
| { |
| return apr_global_mutex_lock(g_sharelock); |
| } |
| |
| apr_status_t proctable_unlock_table(void) |
| { |
| return apr_global_mutex_unlock(g_sharelock); |
| } |
| |
| fcgid_procnode *proctable_get_free_list(void) |
| { |
| return g_free_list_header; |
| } |
| |
| fcgid_procnode *proctable_get_busy_list(void) |
| { |
| return g_busy_list_header; |
| } |
| |
| fcgid_procnode *proctable_get_idle_list(void) |
| { |
| return g_idle_list_header; |
| } |
| |
| fcgid_procnode *proctable_get_table_array(void) |
| { |
| return g_proc_array; |
| } |
| |
| fcgid_procnode *proctable_get_error_list(void) |
| { |
| return g_error_list_header; |
| } |
| |
| fcgid_global_share *proctable_get_globalshare(void) |
| { |
| return g_global_share; |
| } |
| |
| size_t proctable_get_table_size(void) |
| { |
| return g_table_size; |
| } |
| |
| void safe_lock(server_rec * main_server) |
| { |
| apr_status_t rv; |
| |
| if (g_global_share->must_exit) { |
| ap_log_error(APLOG_MARK, APLOG_EMERG, 0, main_server, |
| "mod_fcgid: server is restarted, %d must exit", |
| getpid()); |
| kill(getpid(), SIGTERM); |
| } |
| |
| /* Lock error is a fatal error */ |
| if ((rv = proctable_lock_table()) != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server, |
| "mod_fcgid: can't get lock, pid: %d", getpid()); |
| exit(1); |
| } |
| } |
| |
| void safe_unlock(server_rec * main_server) |
| { |
| /* Lock error is a fatal error */ |
| apr_status_t rv; |
| |
| if ((rv = proctable_unlock_table()) != APR_SUCCESS) { |
| ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server, |
| "mod_fcgid: can't unlock, pid: %d", getpid()); |
| exit(1); |
| } |
| } |
| |
| void proctable_print_debug_info(server_rec * main_server) |
| { |
| int freecount = 0; |
| fcgid_procnode *current_node; |
| |
| for (current_node = &g_proc_array[g_free_list_header->next_index]; |
| current_node != g_proc_array; |
| current_node = &g_proc_array[current_node->next_index]) |
| freecount++; |
| |
| ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server, |
| "mod_fcgid: total node count: %d, free node count: %d", |
| FCGID_MAX_APPLICATION, freecount); |
| |
| for (current_node = &g_proc_array[g_idle_list_header->next_index]; |
| current_node != g_proc_array; |
| current_node = &g_proc_array[current_node->next_index]) { |
| ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server, |
| "mod_fcgid: idle node index: %d", |
| current_node - g_proc_array); |
| } |
| |
| for (current_node = &g_proc_array[g_busy_list_header->next_index]; |
| current_node != g_proc_array; |
| current_node = &g_proc_array[current_node->next_index]) { |
| ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server, |
| "mod_fcgid: busy node index: %d", |
| current_node - g_proc_array); |
| } |
| |
| for (current_node = &g_proc_array[g_error_list_header->next_index]; |
| current_node != g_proc_array; |
| current_node = &g_proc_array[current_node->next_index]) { |
| ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server, |
| "mod_fcgid: error node index: %d", |
| current_node - g_proc_array); |
| } |
| } |