native/common/jk_shm.c (867 lines of code) (raw):

/* * 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. */ /*************************************************************************** * Description: Shared Memory support * * Author: Mladen Turk <mturk@jboss.com> * * Author: Rainer Jung <rjung@apache.org> * ***************************************************************************/ #include "jk_global.h" #include "jk_pool.h" #include "jk_util.h" #include "jk_mt.h" #include "jk_lb_worker.h" #include "jk_ajp13_worker.h" #include "jk_ajp14_worker.h" #include "jk_shm.h" /** jk shm header core data structure * This is always the first slot in shared memory. */ struct jk_shm_header_data { /* Shared memory magic JK_SHM_MAGIC */ char magic[JK_SHM_MAGIC_SIZ]; unsigned int size; unsigned int pos; unsigned int childs; unsigned int workers; unsigned int maintain_checking; volatile time_t maintain_time; }; typedef struct jk_shm_header_data jk_shm_header_data_t; /** jk shm header record structure */ struct jk_shm_header { union { jk_shm_header_data_t data; char alignbuf[JK_SHM_SLOT_SIZE]; } h; char buf[1]; }; typedef struct jk_shm_header jk_shm_header_t; /** jk shm in memory structure. */ struct jk_shm { unsigned int size; unsigned int ajp_workers; unsigned int lb_sub_workers; unsigned int lb_workers; char *filename; char *lockname; int fd; int fd_lock; int attached; jk_shm_header_t *hdr; JK_CRIT_SEC cs; }; typedef struct jk_shm jk_shm_t; static const char shm_signature[] = { JK_SHM_MAGIC }; static jk_shm_t jk_shmem = { 0, 0, 0, 0, NULL, NULL, -1, -1, 0, NULL}; #if defined (WIN32) static HANDLE jk_shm_map = NULL; static HANDLE jk_shm_hlock = NULL; #endif static int jk_shm_inited_cs = 0; static size_t jk_shm_calculate_slot_size() { int align = 64; size_t slot_size = 0; size_t this_size = 0; this_size = sizeof(jk_shm_header_data_t); if (this_size > slot_size) slot_size = this_size; this_size = sizeof(jk_shm_worker_header_t); if (this_size > slot_size) slot_size = this_size; this_size = sizeof(jk_shm_ajp_worker_t); if (this_size > slot_size) slot_size = this_size; this_size = sizeof(jk_shm_lb_sub_worker_t); if (this_size > slot_size) slot_size = this_size; this_size = sizeof(jk_shm_lb_worker_t); if (this_size > slot_size) slot_size = this_size; slot_size = JK_ALIGN(slot_size, align); return slot_size; } /* Calculate needed shm size */ int jk_shm_calculate_size(jk_map_t *init_data, jk_log_context_t *l) { char **worker_list; size_t needed_slot_size = 0; unsigned int i; unsigned int num_of_workers; int num_of_ajp_workers = 0; int num_of_lb_sub_workers = 0; int num_of_lb_workers = 0; JK_TRACE_ENTER(l); if (jk_get_worker_list(init_data, &worker_list, &num_of_workers) == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Could not get worker list from map"); JK_TRACE_EXIT(l); return 0; } needed_slot_size = jk_shm_calculate_slot_size(); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "JK_SHM_SLOT_SIZE defined as %d, need at least %d", JK_SHM_SLOT_SIZE , needed_slot_size); if (needed_slot_size > JK_SHM_SLOT_SIZE) { jk_log(l, JK_LOG_ERROR, "JK_SHM_SLOT_SIZE %d is too small, need at least %d", JK_SHM_SLOT_SIZE, needed_slot_size); JK_TRACE_EXIT(l); return 0; } for (i = 0; i < num_of_workers; i++) { const char *type = jk_get_worker_type(init_data, worker_list[i]); if (!strcmp(type, JK_AJP13_WORKER_NAME) || !strcmp(type, JK_AJP14_WORKER_NAME)) { num_of_ajp_workers++; } else if (!strcmp(type, JK_LB_WORKER_NAME)) { char **member_list; unsigned int num_of_members; num_of_lb_workers++; if (jk_get_lb_worker_list(init_data, worker_list[i], &member_list, &num_of_members) == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Could not get member list for lb worker from map"); } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s of type %s has %u members", worker_list[i], JK_LB_WORKER_NAME, num_of_members); num_of_lb_sub_workers += num_of_members; } } } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "shared memory will contain %d ajp workers and %d lb workers with %d members", num_of_ajp_workers, num_of_lb_workers, num_of_lb_sub_workers); jk_shmem.ajp_workers = num_of_ajp_workers; jk_shmem.lb_sub_workers = num_of_lb_sub_workers; jk_shmem.lb_workers = num_of_lb_workers; JK_TRACE_EXIT(l); return (JK_SHM_SLOT_SIZE * (jk_shmem.ajp_workers + jk_shmem.lb_sub_workers * 2 + jk_shmem.lb_workers)); } #if defined (WIN32) /* Use plain memory */ int jk_shm_open(const char *fname, int sz, jk_log_context_t *l) { int rc = -1; int attached = 0; char lkname[MAX_PATH]; char shname[MAX_PATH] = ""; JK_TRACE_ENTER(l); if (!jk_shm_inited_cs) { jk_shm_inited_cs = 1; JK_INIT_CS(&jk_shmem.cs, rc); } JK_ENTER_CS(&jk_shmem.cs); if (jk_shmem.hdr) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Shared memory is already opened"); JK_TRACE_EXIT(l); JK_LEAVE_CS(&jk_shmem.cs); return 0; } if (sz < 0) { jk_log(l, JK_LOG_ERROR, "Invalid shared memory size (%d)", sz); JK_TRACE_EXIT(l); return EINVAL; } jk_shmem.size = JK_SHM_ALIGN(JK_SHM_SLOT_SIZE + sz); #if defined (WIN32) jk_shm_map = NULL; jk_shm_hlock = NULL; if (fname) { int i; SIZE_T shmsz = 0; strcpy(shname, "Local\\"); strncat(shname, fname, MAX_PATH - 8); for(i = 7; i < (int)strlen(shname); i++) { if (!jk_isalnum(shname[i])) shname[i] = '_'; else shname[i] = toupper(shname[i]); } strcpy(lkname, shname); strncat(lkname, "_MUTEX", MAX_PATH - 1); jk_shm_hlock = CreateMutex(jk_get_sa_with_null_dacl(), TRUE, lkname); if (jk_shm_hlock == NULL) { if (GetLastError() == ERROR_ALREADY_EXISTS) { attached = 1; jk_shm_hlock = OpenMutex(MUTEX_ALL_ACCESS, FALSE, lkname); } } else if (GetLastError() == ERROR_ALREADY_EXISTS) attached = 1; if (jk_shm_hlock == NULL) { rc = GetLastError(); jk_log(l, JK_LOG_ERROR, "Failed to open shared memory mutex %s with errno=%d", lkname, rc); JK_LEAVE_CS(&jk_shmem.cs); JK_TRACE_EXIT(l); return rc; } if (attached) { DWORD ws = WaitForSingleObject(jk_shm_hlock, INFINITE); if (ws == WAIT_FAILED) { rc = GetLastError(); CloseHandle(jk_shm_hlock); jk_shm_hlock = NULL; JK_LEAVE_CS(&jk_shmem.cs); JK_TRACE_EXIT(l); return rc; } jk_shm_map = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, shname); if (jk_shm_map == NULL) { rc = GetLastError(); jk_log(l, JK_LOG_ERROR, "Failed to open shared memory %s with errno=%d", shname, rc); } } if (jk_shm_map == NULL) { shmsz = jk_shmem.size; jk_shm_map = CreateFileMapping(INVALID_HANDLE_VALUE, jk_get_sa_with_null_dacl(), PAGE_READWRITE, 0, (DWORD)shmsz, shname); } if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE) { rc = GetLastError(); jk_log(l, JK_LOG_ERROR, "Failed to map shared memory %s with errno=%d", fname, rc); CloseHandle(jk_shm_hlock); jk_shm_hlock = NULL; jk_shm_map = NULL; JK_LEAVE_CS(&jk_shmem.cs); JK_TRACE_EXIT(l); return rc; } jk_shmem.hdr = (jk_shm_header_t *)MapViewOfFile(jk_shm_map, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, shmsz); } else #endif jk_shmem.hdr = (jk_shm_header_t *)calloc(1, jk_shmem.size); if (!jk_shmem.hdr) { #if defined (WIN32) rc = GetLastError(); if (jk_shm_map) { CloseHandle(jk_shm_map); jk_shm_map = NULL; } if (jk_shm_hlock) { CloseHandle(jk_shm_hlock); jk_shm_hlock = NULL; } #endif JK_LEAVE_CS(&jk_shmem.cs); JK_TRACE_EXIT(l); return rc; } if (!jk_shmem.filename) { if (shname[0]) jk_shmem.filename = strdup(shname); else jk_shmem.filename = strdup("memory"); } jk_shmem.fd = 0; jk_shmem.attached = attached; if (!attached) { memset(jk_shmem.hdr, 0, jk_shmem.size); memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ); jk_shmem.hdr->h.data.size = sz; jk_shmem.hdr->h.data.childs = 1; jk_shmem.hdr->h.data.maintain_checking = 0; jk_shmem.hdr->h.data.maintain_time = time(NULL); } else { jk_shmem.hdr->h.data.childs++; /* * Reset the shared memory so that * alloc works even for attached memory. * XXX: This might break already used memory * if the number of workers change between * open and attach or between two attach operations. */ #if 0 if (jk_shmem.hdr->h.data.childs > 1) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Resetting the shared memory for child %d", jk_shmem.hdr->h.data.childs); } } jk_shmem.hdr->h.data.pos = 0; jk_shmem.hdr->h.data.workers = 0; #endif } #if defined (WIN32) if (jk_shm_hlock != NULL) { /* Unlock shared memory */ ReleaseMutex(jk_shm_hlock); } #endif JK_LEAVE_CS(&jk_shmem.cs); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "%s shared memory %s [%d] size=%u workers=%d free=%u addr=%#lx", attached ? "Attached" : "Initialized", jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size, jk_shmem.hdr->h.data.workers - 1, jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, jk_shmem.hdr); JK_TRACE_EXIT(l); return 0; } int jk_shm_attach(const char *fname, int sz, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (!jk_shm_open(fname, sz, l)) { if (!jk_shmem.attached) { jk_shmem.attached = 1; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Attached shared memory %s [%d] size=%u free=%u addr=%#lx", jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size, jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, jk_shmem.hdr); } } JK_TRACE_EXIT(l); return 0; } else { JK_TRACE_EXIT(l); return -1; } } void jk_shm_close(jk_log_context_t *l) { if (jk_shm_inited_cs) { JK_ENTER_CS(&jk_shmem.cs); } if (jk_shmem.hdr) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Closed shared memory %s childs=%u", jk_shm_name(), jk_shmem.hdr->h.data.childs); } #if defined (WIN32) if (jk_shm_hlock) { WaitForSingleObject(jk_shm_hlock, 60000); ReleaseMutex(jk_shm_hlock); CloseHandle(jk_shm_hlock); jk_shm_hlock = NULL; } if (jk_shm_map) { --jk_shmem.hdr->h.data.childs; UnmapViewOfFile(jk_shmem.hdr); CloseHandle(jk_shm_map); jk_shm_map = NULL; } else #endif free(jk_shmem.hdr); } jk_shmem.hdr = NULL; if (jk_shmem.filename) { free(jk_shmem.filename); jk_shmem.filename = NULL; } if (jk_shm_inited_cs) { JK_LEAVE_CS(&jk_shmem.cs); } } #else #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/uio.h> #ifndef MAP_FAILED #define MAP_FAILED (-1) #endif #ifndef MAP_FILE #define MAP_FILE (0) #endif static int do_shm_open_lock(const char *fname, int attached, jk_log_context_t *l) { int rc; char flkname[256]; #ifdef AS400_UTF8 char *wptr; #endif JK_TRACE_ENTER(l); if (attached && jk_shmem.lockname) { #ifdef JK_SHM_LOCK_REOPEN jk_shmem.fd_lock = open(jk_shmem.lockname, O_RDWR, 0666); #else errno = EINVAL; #endif if (jk_shmem.fd_lock == -1) { rc = errno; JK_TRACE_EXIT(l); return rc; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Duplicated shared memory lock %s", jk_shmem.lockname); JK_TRACE_EXIT(l); return 0; } if (!jk_shmem.lockname) { #ifdef JK_SHM_LOCK_REOPEN int i; jk_shmem.fd_lock = -1; mode_t mask = umask(0); for (i = 0; i < 8; i++) { strcpy(flkname, "/tmp/jkshmlock.XXXXXX"); if (mktemp(flkname)) { jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0666); if (jk_shmem.fd_lock >= 0) break; } } umask(mask); #else strcpy(flkname, fname); strcat(flkname, ".lock"); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(flkname) + 1); jk_ascii2ebcdic((char *)flkname, wptr); jk_shmem.fd_lock = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0666); free(wptr); #else jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0666); #endif #endif if (jk_shmem.fd_lock == -1) { rc = errno; JK_TRACE_EXIT(l); return rc; } jk_shmem.lockname = strdup(flkname); } else { /* Nothing to do */ JK_TRACE_EXIT(l); return 0; } if (ftruncate(jk_shmem.fd_lock, 1)) { rc = errno; close(jk_shmem.fd_lock); jk_shmem.fd_lock = -1; JK_TRACE_EXIT(l); return rc; } if (lseek(jk_shmem.fd_lock, 0, SEEK_SET) != 0) { rc = errno; close(jk_shmem.fd_lock); jk_shmem.fd_lock = -1; return rc; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Opened shared memory lock %s", jk_shmem.lockname); JK_TRACE_EXIT(l); return 0; } static int do_shm_open(const char *fname, int attached, int sz, jk_log_context_t *l) { int rc; int fd; void *base; #ifdef AS400_UTF8 char *wptr; #endif JK_TRACE_ENTER(l); if (!jk_shm_inited_cs) { jk_shm_inited_cs = 1; JK_INIT_CS(&jk_shmem.cs, rc); } if (jk_shmem.hdr) { /* Probably a call from vhost */ if (!attached) attached = 1; } else if (attached) { /* We should already have a header * Use memory if we don't */ JK_TRACE_EXIT(l); return 0; } if (sz < 0) { jk_log(l, JK_LOG_ERROR, "Invalid shared memory size (%d)", sz); JK_TRACE_EXIT(l); return EINVAL; } jk_shmem.size = JK_SHM_ALIGN(JK_SHM_SLOT_SIZE + sz); if (!fname) { /* Use plain memory in case there is no file name */ if (!jk_shmem.filename) jk_shmem.filename = strdup("memory"); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Using process memory as shared memory"); JK_TRACE_EXIT(l); return 0; } if (!jk_shmem.filename) { jk_shmem.filename = (char *)malloc(strlen(fname) + 32); sprintf(jk_shmem.filename, "%s.%" JK_PID_T_FMT, fname, getpid()); } if (!attached) { size_t size; jk_shmem.attached = 0; #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); fd = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0666); free(wptr); #else fd = open(jk_shmem.filename, O_RDWR|O_CREAT|O_TRUNC, 0666); #endif if (fd == -1) { jk_shmem.size = 0; JK_TRACE_EXIT(l); return errno; } size = lseek(fd, 0, SEEK_END); if (size < jk_shmem.size) { size = jk_shmem.size; if (ftruncate(fd, jk_shmem.size)) { rc = errno; close(fd); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif jk_shmem.size = 0; JK_TRACE_EXIT(l); return rc; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Truncated shared memory to %u", size); } if (lseek(fd, 0, SEEK_SET) != 0) { rc = errno; close(fd); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif jk_shmem.size = 0; JK_TRACE_EXIT(l); return rc; } base = mmap((caddr_t)0, jk_shmem.size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); if (base == (caddr_t)MAP_FAILED || base == (caddr_t)0) { rc = errno; close(fd); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif jk_shmem.size = 0; JK_TRACE_EXIT(l); return rc; } jk_shmem.hdr = base; jk_shmem.fd = fd; memset(jk_shmem.hdr, 0, jk_shmem.size); memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ); jk_shmem.hdr->h.data.size = sz; jk_shmem.hdr->h.data.childs = 1; jk_shmem.hdr->h.data.maintain_checking = 0; jk_shmem.hdr->h.data.maintain_time = time(NULL); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Initialized shared memory %s size=%u free=%u addr=%#lx", jk_shm_name(), jk_shmem.size, jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, jk_shmem.hdr); } else { jk_shmem.hdr->h.data.childs++; jk_shmem.attached = (int)getpid(); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Attached shared memory %s [%d] size=%u workers=%u free=%u addr=%#lx", jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size, jk_shmem.hdr->h.data.workers - 1, jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, jk_shmem.hdr); #if 0 /* * Reset the shared memory so that * alloc works even for attached memory. * XXX: This might break already used memory * if the number of workers change between * open and attach or between two attach operations. */ if (nchild > 1) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Resetting the shared memory for child %d", nchild); } } jk_shmem.hdr->h.data.pos = 0; jk_shmem.hdr->h.data.workers = 0; #endif } if ((rc = do_shm_open_lock(jk_shmem.filename, attached, l))) { if (!attached) { munmap((void *)jk_shmem.hdr, jk_shmem.size); close(jk_shmem.fd); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif } jk_shmem.hdr = NULL; jk_shmem.fd = -1; JK_TRACE_EXIT(l); return rc; } JK_TRACE_EXIT(l); return 0; } int jk_shm_open(const char *fname, int sz, jk_log_context_t *l) { return do_shm_open(fname, 0, sz, l); } int jk_shm_attach(const char *fname, int sz, jk_log_context_t *l) { return do_shm_open(fname, 1, sz, l); } void jk_shm_close(jk_log_context_t *l) { #ifdef AS400_UTF8 char *wptr; #endif if (jk_shmem.hdr) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Closed shared memory %s childs=%u", jk_shm_name(), jk_shmem.hdr->h.data.childs); } --jk_shmem.hdr->h.data.childs; #ifdef JK_SHM_LOCK_REOPEN if (jk_shmem.fd_lock >= 0) { close(jk_shmem.fd_lock); jk_shmem.fd_lock = -1; } #endif if (jk_shmem.attached) { int p = (int)getpid(); if (p == jk_shmem.attached) { /* In case this is a forked child * do not close the shared memory. * It will be closed by the parent. */ jk_shmem.size = 0; jk_shmem.hdr = NULL; jk_shmem.fd = -1; return; } } if (jk_shmem.fd >= 0) { munmap((void *)jk_shmem.hdr, jk_shmem.size); close(jk_shmem.fd); } if (jk_shmem.fd_lock >= 0) close(jk_shmem.fd_lock); if (jk_shmem.lockname) { #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.lockname) + 1); jk_ascii2ebcdic((char *)jk_shmem.lockname, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.lockname); #endif free(jk_shmem.lockname); jk_shmem.lockname = NULL; } if (jk_shmem.filename) { #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif free(jk_shmem.filename); jk_shmem.filename = NULL; } } jk_shmem.size = 0; jk_shmem.hdr = NULL; jk_shmem.fd = -1; jk_shmem.fd_lock = -1; } #endif static int jk_shm_check_str_length(const char *name, const char *value, jk_log_context_t *l) { size_t len = strlen(value); if (len >= JK_SHM_STR_SIZ) { jk_log(l, JK_LOG_ERROR, "Worker %s '%s' is %d bytes too long, " "a maximum of %d bytes is supported", name, value, len - (JK_SHM_STR_SIZ - 1), JK_SHM_STR_SIZ - 1); return JK_FALSE; } return JK_TRUE; } int jk_shm_str_init(shm_str dst, const char *src, const char *name, jk_log_context_t *l) { if (jk_shm_check_str_length(name, src, l) == JK_FALSE) { return JK_FALSE; } strncpy(dst, src, JK_SHM_STR_SIZ - 1); dst[JK_SHM_STR_SIZ - 1] = '\0'; return JK_TRUE; } int jk_shm_str_init_ne(shm_str dst, const char *src, const char *name, jk_log_context_t *l) { if (jk_shm_check_str_length(name, src, l) == JK_FALSE) { return -1; } if (!strncmp(dst, src, JK_SHM_STR_SIZ)) { return 0; } strncpy(dst, src, JK_SHM_STR_SIZ - 1); dst[JK_SHM_STR_SIZ - 1] = '\0'; return 1; } void jk_shm_str_copy(shm_str dst, shm_str src, jk_log_context_t *l) { memcpy((dst), (src), JK_SHM_STR_SIZ); } jk_shm_worker_header_t *jk_shm_alloc_worker(jk_pool_t *p, int type, int parent_id, const char *name, jk_log_context_t *l) { unsigned int i; jk_shm_worker_header_t *w = 0; shm_str str; if (jk_shm_str_init(str, name, "name", l) == JK_FALSE) { return NULL; } if (jk_shmem.hdr) { jk_shm_lock(); for (i = 0; i < jk_shmem.hdr->h.data.pos; i += JK_SHM_SLOT_SIZE) { w = (jk_shm_worker_header_t *)(jk_shmem.hdr->buf + i); if (w->type == type && w-> parent_id == parent_id && strcmp(w->name, name) == 0) { /* We have found already created worker */ jk_shm_unlock(); return w; } } /* Allocate new worker */ if ((jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos) >= JK_SHM_SLOT_SIZE) { w = (jk_shm_worker_header_t *)(jk_shmem.hdr->buf + jk_shmem.hdr->h.data.pos); memset(w, 0, JK_SHM_SLOT_SIZE); jk_shm_str_copy(w->name, str, l); jk_shmem.hdr->h.data.workers++; w->id = jk_shmem.hdr->h.data.workers; w->type = type; w->parent_id = parent_id; jk_shmem.hdr->h.data.pos += JK_SHM_SLOT_SIZE; } else { /* No more free memory left. */ jk_log(l, JK_LOG_ERROR, "Could not allocate shared memory for worker %s", name); w = NULL; } jk_shm_unlock(); } else if (p) { w = (jk_shm_worker_header_t *)jk_pool_alloc(p, JK_SHM_SLOT_SIZE); if (w) { memset(w, 0, JK_SHM_SLOT_SIZE); jk_shm_str_copy(w->name, str, l); w->id = 0; w->type = type; w->parent_id = parent_id; } } return w; } const char *jk_shm_name() { return jk_shmem.filename; } int jk_shm_check_maintain(time_t trigger) { int rv = JK_FALSE; int maintain_checking = JK_ATOMIC_INCREMENT(&(jk_shmem.hdr->h.data.maintain_checking)); /* Another process (or thread) is already checking */ if (maintain_checking > 1) { JK_ATOMIC_DECREMENT(&(jk_shmem.hdr->h.data.maintain_checking)); return rv; } if (jk_shmem.hdr->h.data.maintain_time <= trigger) { jk_shmem.hdr->h.data.maintain_time = time(NULL); rv = JK_TRUE; } JK_ATOMIC_DECREMENT(&(jk_shmem.hdr->h.data.maintain_checking)); return rv; } int jk_shm_lock() { int rc = JK_TRUE; if (!jk_shm_inited_cs) return JK_FALSE; JK_ENTER_CS(&jk_shmem.cs); #if defined (WIN32) if (jk_shm_hlock != NULL) { if (WaitForSingleObject(jk_shm_hlock, INFINITE) == WAIT_FAILED) rc = JK_FALSE; } #else if (jk_shmem.fd_lock != -1) { JK_ENTER_LOCK(jk_shmem.fd_lock, rc); } #endif return rc; } int jk_shm_unlock() { int rc = JK_TRUE; if (!jk_shm_inited_cs) return JK_FALSE; #if defined (WIN32) if (jk_shm_hlock != NULL) { ReleaseMutex(jk_shm_hlock); } #else if (jk_shmem.fd_lock != -1) { JK_LEAVE_LOCK(jk_shmem.fd_lock, rc); } #endif JK_LEAVE_CS(&jk_shmem.cs); return rc; } jk_shm_ajp_worker_t *jk_shm_alloc_ajp_worker(jk_pool_t *p, const char *name, jk_log_context_t *l) { return (jk_shm_ajp_worker_t *)jk_shm_alloc_worker(p, JK_AJP13_WORKER_TYPE, 0, name, l); } jk_shm_lb_sub_worker_t *jk_shm_alloc_lb_sub_worker(jk_pool_t *p, int lb_id, const char *name, jk_log_context_t *l) { return (jk_shm_lb_sub_worker_t *)jk_shm_alloc_worker(p, JK_LB_SUB_WORKER_TYPE, lb_id, name, l); } jk_shm_lb_worker_t *jk_shm_alloc_lb_worker(jk_pool_t *p, const char *name, jk_log_context_t *l) { return (jk_shm_lb_worker_t *)jk_shm_alloc_worker(p, JK_LB_WORKER_TYPE, 0, name, l); }