2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 /***************************************************************************
19 * Description: Shared Memory support *
20 * Author: Mladen Turk <mturk@jboss.com> *
21 * Author: Rainer Jung <rjung@apache.org> *
22 * Version: $Revision: 704548 $ *
23 ***************************************************************************/
25 #include "jk_global.h"
29 #include "jk_lb_worker.h"
30 #include "jk_ajp13_worker.h"
31 #include "jk_ajp14_worker.h"
34 /** jk shm header core data structure */
35 struct jk_shm_header_data
37 /* Shared memory magic JK_SHM_MAGIC */
38 char magic[JK_SHM_MAGIC_SIZ];
46 typedef struct jk_shm_header_data jk_shm_header_data_t;
48 /** jk shm header record structure */
52 jk_shm_header_data_t data;
53 char alignbuf[JK_SHM_ALIGN(sizeof(jk_shm_header_data_t))];
58 typedef struct jk_shm_header jk_shm_header_t;
60 /** jk shm structure */
65 unsigned lb_sub_workers;
76 typedef struct jk_shm jk_shm_t;
78 static const char shm_signature[] = { JK_SHM_MAGIC };
79 static jk_shm_t jk_shmem = { 0, 0, 0, 0, NULL, NULL, -1, -1, 0, NULL};
80 static time_t jk_workers_modified_time = 0;
81 static time_t jk_workers_access_time = 0;
83 static HANDLE jk_shm_map = NULL;
84 static HANDLE jk_shm_hlock = NULL;
87 /* Calculate needed shm size */
88 size_t jk_shm_calculate_size(jk_map_t *init_data, jk_logger_t *l)
92 unsigned num_of_workers;
93 int num_of_ajp_workers = 0;
94 int num_of_lb_sub_workers = 0;
95 int num_of_lb_workers = 0;
99 if (jk_get_worker_list(init_data, &worker_list,
100 &num_of_workers) == JK_FALSE) {
101 jk_log(l, JK_LOG_ERROR,
102 "Could not get worker list from map");
107 for (i = 0; i < num_of_workers; i++) {
108 const char *type = jk_get_worker_type(init_data, worker_list[i]);
110 if (!strcmp(type, JK_AJP13_WORKER_NAME) ||
111 !strcmp(type, JK_AJP14_WORKER_NAME)) {
112 num_of_ajp_workers++;
114 else if (!strcmp(type, JK_LB_WORKER_NAME)) {
116 unsigned num_of_members;
118 if (jk_get_lb_worker_list(init_data, worker_list[i],
119 &member_list, &num_of_members) == JK_FALSE) {
120 jk_log(l, JK_LOG_ERROR,
121 "Could not get member list for lb worker from map");
124 if (JK_IS_DEBUG_LEVEL(l))
125 jk_log(l, JK_LOG_DEBUG, "worker %s of type %s has %u members",
126 worker_list[i], JK_LB_WORKER_NAME, num_of_members);
127 num_of_lb_sub_workers += num_of_members;
131 if (JK_IS_DEBUG_LEVEL(l))
132 jk_log(l, JK_LOG_DEBUG, "shared memory will contain %d ajp workers of size %d and %d lb workers of size %d with %d members of size %d+%d",
133 num_of_ajp_workers, JK_SHM_AJP_SIZE(1),
134 num_of_lb_workers, JK_SHM_LB_SIZE(1),
135 num_of_lb_sub_workers, JK_SHM_LB_SUB_SIZE(1), JK_SHM_AJP_SIZE(1));
136 jk_shmem.ajp_workers = num_of_ajp_workers;
137 jk_shmem.lb_sub_workers = num_of_lb_sub_workers;
138 jk_shmem.lb_workers = num_of_lb_workers;
140 return JK_SHM_AJP_SIZE(jk_shmem.ajp_workers) +
141 JK_SHM_LB_SUB_SIZE(jk_shmem.lb_sub_workers) +
142 JK_SHM_AJP_SIZE(jk_shmem.lb_sub_workers) +
143 JK_SHM_LB_SIZE(jk_shmem.lb_workers);
147 #if defined (WIN32) || defined(NETWARE)
149 /* Use plain memory */
150 int jk_shm_open(const char *fname, size_t sz, jk_logger_t *l)
154 char lkname[MAX_PATH];
157 if (JK_IS_DEBUG_LEVEL(l))
158 jk_log(l, JK_LOG_DEBUG, "Shared memory is already opened");
163 jk_shmem.size = JK_SHM_ALIGN(sizeof(jk_shm_header_t) + sz);
167 jk_shm_map = CreateFileMapping(INVALID_HANDLE_VALUE,
171 (DWORD)(sizeof(jk_shm_header_t) + sz),
173 if (GetLastError() == ERROR_ALREADY_EXISTS) {
175 if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE) {
176 jk_shm_map = OpenFileMapping(PAGE_READWRITE, FALSE, fname);
179 if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE) {
183 sprintf(lkname, "Global\\%s_MUTEX", fname);
185 jk_shm_hlock = OpenMutex(MUTEX_ALL_ACCESS, FALSE, lkname);
188 jk_shm_hlock = CreateMutex(NULL, FALSE, lkname);
190 if (jk_shm_hlock == NULL || jk_shm_hlock == INVALID_HANDLE_VALUE) {
191 CloseHandle(jk_shm_map);
196 jk_shmem.hdr = (jk_shm_header_t *)MapViewOfFile(jk_shm_map,
204 jk_shmem.hdr = (jk_shm_header_t *)calloc(1, jk_shmem.size);
208 CloseHandle(jk_shm_map);
212 CloseHandle(jk_shm_hlock);
219 if (!jk_shmem.filename) {
221 jk_shmem.filename = strdup(fname);
223 jk_shmem.filename = strdup("memory");
226 jk_shmem.attached = attached;
228 memcpy(jk_shmem.hdr->h.data.magic, shm_signature,
230 jk_shmem.hdr->h.data.size = sz;
231 jk_shmem.hdr->h.data.childs = 1;
234 jk_shmem.hdr->h.data.childs++;
236 * Reset the shared memory so that
237 * alloc works even for attached memory.
238 * XXX: This might break already used memory
239 * if the number of workers change between
240 * open and attach or between two attach operations.
242 if (jk_shmem.hdr->h.data.childs > 1) {
243 if (JK_IS_DEBUG_LEVEL(l)) {
244 jk_log(l, JK_LOG_DEBUG,
245 "Resetting the shared memory for child %d",
246 jk_shmem.hdr->h.data.childs);
249 jk_shmem.hdr->h.data.pos = 0;
250 jk_shmem.hdr->h.data.workers = 0;
252 JK_INIT_CS(&(jk_shmem.cs), rc);
253 if (JK_IS_DEBUG_LEVEL(l))
254 jk_log(l, JK_LOG_DEBUG,
255 "%s shared memory %s size=%u free=%u addr=%#lx",
256 attached ? "Attached" : "Initialized",
257 jk_shm_name(), jk_shmem.size,
258 jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
264 int jk_shm_attach(const char *fname, size_t sz, jk_logger_t *l)
267 if (!jk_shm_open(fname, sz, l)) {
268 if (!jk_shmem.attached) {
269 jk_shmem.attached = 1;
270 if (JK_IS_DEBUG_LEVEL(l)) {
271 jk_log(l, JK_LOG_DEBUG,
272 "Attached shared memory %s [%d] size=%u free=%u addr=%#lx",
273 jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size,
274 jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
293 CloseHandle(jk_shm_hlock);
297 --jk_shmem.hdr->h.data.childs;
298 UnmapViewOfFile(jk_shmem.hdr);
299 CloseHandle(jk_shm_map);
305 JK_DELETE_CS(&(jk_shmem.cs), rc);
308 if (jk_shmem.filename) {
309 free(jk_shmem.filename);
310 jk_shmem.filename = NULL;
319 #include <sys/stat.h>
320 #include <sys/mman.h>
324 #define MAP_FAILED (-1)
331 static int do_shm_open_lock(const char *fname, int attached, jk_logger_t *l)
341 if (attached && jk_shmem.lockname) {
342 #ifdef JK_SHM_LOCK_REOPEN
343 jk_shmem.fd_lock = open(jk_shmem.lockname, O_RDWR, 0666);
347 if (jk_shmem.fd_lock == -1) {
352 if (JK_IS_DEBUG_LEVEL(l))
353 jk_log(l, JK_LOG_DEBUG,
354 "Duplicated shared memory lock %s", jk_shmem.lockname);
359 if (!jk_shmem.lockname) {
360 #ifdef JK_SHM_LOCK_REOPEN
362 jk_shmem.fd_lock = -1;
363 mode_t mask = umask(0);
364 for (i = 0; i < 8; i++) {
365 strcpy(flkname, "/tmp/jkshmlock.XXXXXX");
366 if (mktemp(flkname)) {
367 jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0666);
368 if (jk_shmem.fd_lock >= 0)
374 strcpy(flkname, fname);
375 strcat(flkname, ".lock");
377 wptr = (char *)malloc(strlen(flkname) + 1);
378 jk_ascii2ebcdic((char *)flkname, wptr);
379 jk_shmem.fd_lock = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0666);
382 jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0666);
385 if (jk_shmem.fd_lock == -1) {
390 jk_shmem.lockname = strdup(flkname);
398 if (ftruncate(jk_shmem.fd_lock, 1)) {
400 close(jk_shmem.fd_lock);
401 jk_shmem.fd_lock = -1;
405 if (lseek(jk_shmem.fd_lock, 0, SEEK_SET) != 0) {
407 close(jk_shmem.fd_lock);
408 jk_shmem.fd_lock = -1;
411 if (JK_IS_DEBUG_LEVEL(l))
412 jk_log(l, JK_LOG_DEBUG,
413 "Opened shared memory lock %s", jk_shmem.lockname);
418 static int do_shm_open(const char *fname, int attached,
419 size_t sz, jk_logger_t *l)
430 /* Probably a call from vhost */
435 /* We should already have a header
436 * Use memory if we don't
441 jk_shmem.size = JK_SHM_ALIGN(sizeof(jk_shm_header_t) + sz);
444 /* Use plain memory in case there is no file name */
445 if (!jk_shmem.filename)
446 jk_shmem.filename = strdup("memory");
447 if (JK_IS_DEBUG_LEVEL(l))
448 jk_log(l, JK_LOG_DEBUG,
449 "Using process memory as shared memory");
454 if (!jk_shmem.filename) {
455 jk_shmem.filename = (char *)malloc(strlen(fname) + 32);
456 sprintf(jk_shmem.filename, "%s.%" JK_PID_T_FMT, fname, getpid());
460 jk_shmem.attached = 0;
462 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
463 jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
464 fd = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0666);
467 fd = open(jk_shmem.filename, O_RDWR|O_CREAT|O_TRUNC, 0666);
474 size = lseek(fd, 0, SEEK_END);
475 if (size < jk_shmem.size) {
476 size = jk_shmem.size;
477 if (ftruncate(fd, jk_shmem.size)) {
481 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
482 jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
486 unlink(jk_shmem.filename);
492 if (JK_IS_DEBUG_LEVEL(l))
493 jk_log(l, JK_LOG_DEBUG,
494 "Truncated shared memory to %u", size);
496 if (lseek(fd, 0, SEEK_SET) != 0) {
500 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
501 jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
505 unlink(jk_shmem.filename);
512 base = mmap((caddr_t)0, jk_shmem.size,
513 PROT_READ | PROT_WRITE,
514 MAP_FILE | MAP_SHARED,
516 if (base == (caddr_t)MAP_FAILED || base == (caddr_t)0) {
520 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
521 jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
525 unlink(jk_shmem.filename);
533 memset(jk_shmem.hdr, 0, jk_shmem.size);
534 memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ);
535 jk_shmem.hdr->h.data.size = sz;
536 jk_shmem.hdr->h.data.childs = 1;
537 if (JK_IS_DEBUG_LEVEL(l))
538 jk_log(l, JK_LOG_DEBUG,
539 "Initialized shared memory %s size=%u free=%u addr=%#lx",
540 jk_shm_name(), jk_shmem.size,
541 jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
546 jk_shmem.hdr->h.data.childs++;
547 jk_shmem.attached = (int)getpid();
548 nchild = jk_shmem.hdr->h.data.childs;
549 if (JK_IS_DEBUG_LEVEL(l))
550 jk_log(l, JK_LOG_DEBUG,
551 "Attached shared memory %s [%d] size=%u free=%u addr=%#lx",
552 jk_shm_name(), nchild, jk_shmem.size,
553 jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
556 * Reset the shared memory so that
557 * alloc works even for attached memory.
558 * XXX: This might break already used memory
559 * if the number of workers change between
560 * open and attach or between two attach operations.
563 if (JK_IS_DEBUG_LEVEL(l)) {
564 jk_log(l, JK_LOG_DEBUG,
565 "Resetting the shared memory for child %d",
569 jk_shmem.hdr->h.data.pos = 0;
570 jk_shmem.hdr->h.data.workers = 0;
572 JK_INIT_CS(&(jk_shmem.cs), rc);
573 if ((rc = do_shm_open_lock(jk_shmem.filename, attached, l))) {
575 munmap((void *)jk_shmem.hdr, jk_shmem.size);
578 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
579 jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
583 unlink(jk_shmem.filename);
595 int jk_shm_open(const char *fname, size_t sz, jk_logger_t *l)
597 return do_shm_open(fname, 0, sz, l);
600 int jk_shm_attach(const char *fname, size_t sz, jk_logger_t *l)
602 return do_shm_open(fname, 1, sz, l);
613 --jk_shmem.hdr->h.data.childs;
615 #ifdef JK_SHM_LOCK_REOPEN
616 if (jk_shmem.fd_lock >= 0) {
617 close(jk_shmem.fd_lock);
618 jk_shmem.fd_lock = -1;
621 JK_DELETE_CS(&(jk_shmem.cs), rc);
622 if (jk_shmem.attached) {
623 int p = (int)getpid();
624 if (p == jk_shmem.attached) {
625 /* In case this is a forked child
626 * do not close the shared memory.
627 * It will be closed by the parent.
635 if (jk_shmem.fd >= 0) {
636 munmap((void *)jk_shmem.hdr, jk_shmem.size);
639 if (jk_shmem.fd_lock >= 0)
640 close(jk_shmem.fd_lock);
641 if (jk_shmem.lockname) {
643 wptr = (char *)malloc(strlen(jk_shmem.lockname) + 1);
644 jk_ascii2ebcdic((char *)jk_shmem.lockname, wptr);
648 unlink(jk_shmem.lockname);
650 free(jk_shmem.lockname);
651 jk_shmem.lockname = NULL;
653 if (jk_shmem.filename) {
655 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
656 jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
660 unlink(jk_shmem.filename);
662 free(jk_shmem.filename);
663 jk_shmem.filename = NULL;
669 jk_shmem.fd_lock = -1;
675 void *jk_shm_alloc(jk_pool_t *p, size_t size)
680 size = JK_SHM_ALIGN(size);
681 if ((jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos) >= size) {
682 rc = &(jk_shmem.hdr->buf[jk_shmem.hdr->h.data.pos]);
683 jk_shmem.hdr->h.data.pos += size;
687 rc = jk_pool_alloc(p, size);
692 const char *jk_shm_name()
694 return jk_shmem.filename;
698 time_t jk_shm_get_workers_time()
701 return jk_shmem.hdr->h.data.modified;
703 return jk_workers_modified_time;
706 void jk_shm_set_workers_time(time_t t)
709 jk_shmem.hdr->h.data.modified = t;
711 jk_workers_modified_time = t;
712 jk_workers_access_time = t;
715 int jk_shm_is_modified()
717 time_t m = jk_shm_get_workers_time();
718 if (m != jk_workers_access_time)
724 void jk_shm_sync_access_time()
726 jk_workers_access_time = jk_shm_get_workers_time();
732 JK_ENTER_CS(&(jk_shmem.cs), rc);
734 if (rc == JK_TRUE && jk_shm_hlock != NULL) {
735 DWORD rv = WaitForSingleObject(jk_shm_hlock, INFINITE);
736 if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED)
742 if (rc == JK_TRUE && jk_shmem.fd_lock != -1) {
743 JK_ENTER_LOCK(jk_shmem.fd_lock, rc);
752 JK_LEAVE_CS(&(jk_shmem.cs), rc);
754 if (rc == JK_TRUE && jk_shm_hlock != NULL) {
755 if (!ReleaseMutex(jk_shm_hlock))
759 if (rc == JK_TRUE && jk_shmem.fd_lock != -1) {
760 JK_LEAVE_LOCK(jk_shmem.fd_lock, rc);
766 jk_shm_ajp_worker_t *jk_shm_alloc_ajp_worker(jk_pool_t *p)
768 jk_shm_ajp_worker_t *w = (jk_shm_ajp_worker_t *)jk_shm_alloc(p, JK_SHM_AJP_WORKER_SIZE);
770 memset(w, 0, JK_SHM_AJP_WORKER_SIZE);
772 jk_shmem.hdr->h.data.workers++;
773 w->h.id = jk_shmem.hdr->h.data.workers;
774 w->h.type = JK_AJP13_WORKER_TYPE;
782 jk_shm_lb_sub_worker_t *jk_shm_alloc_lb_sub_worker(jk_pool_t *p)
784 jk_shm_lb_sub_worker_t *w = (jk_shm_lb_sub_worker_t *)jk_shm_alloc(p, JK_SHM_LB_SUB_WORKER_SIZE);
786 memset(w, 0, JK_SHM_LB_SUB_WORKER_SIZE);
788 jk_shmem.hdr->h.data.workers++;
789 w->h.id = jk_shmem.hdr->h.data.workers;
790 w->h.type = JK_LB_SUB_WORKER_TYPE;
798 jk_shm_lb_worker_t *jk_shm_alloc_lb_worker(jk_pool_t *p)
800 jk_shm_lb_worker_t *w = (jk_shm_lb_worker_t *)jk_shm_alloc(p, JK_SHM_LB_WORKER_SIZE);
802 memset(w, 0, JK_SHM_LB_WORKER_SIZE);
804 jk_shmem.hdr->h.data.workers++;
805 w->h.id = jk_shmem.hdr->h.data.workers;
806 w->h.type = JK_LB_WORKER_TYPE;