blob: c348e1f1753049543ee98fff8c6c4c81292a0895 [file] [log] [blame]
#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);
}
}