1 /*
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 
18 /***************************************************************************
19  * Description: Shared Memory support                                      *
20  * Author:      Mladen Turk <mturk@jboss.com>                              *
21  * Author:      Rainer Jung <rjung@apache.org>                             *
22  ***************************************************************************/
23 
24 #include "jk_global.h"
25 #include "jk_pool.h"
26 #include "jk_util.h"
27 #include "jk_mt.h"
28 #include "jk_lb_worker.h"
29 #include "jk_ajp13_worker.h"
30 #include "jk_ajp14_worker.h"
31 #include "jk_shm.h"
32 
33 /** jk shm header core data structure
34  * This is always the first slot in shared memory.
35  */
36 struct jk_shm_header_data
37 {
38     /* Shared memory magic JK_SHM_MAGIC */
39     char         magic[JK_SHM_MAGIC_SIZ];
40     unsigned int size;
41     unsigned int pos;
42     unsigned int childs;
43     unsigned int workers;
44     unsigned int maintain_checking;
45     volatile time_t maintain_time;
46 };
47 
48 typedef struct jk_shm_header_data jk_shm_header_data_t;
49 
50 /** jk shm header record structure
51  */
52 struct jk_shm_header
53 {
54     union {
55         jk_shm_header_data_t data;
56         char alignbuf[JK_SHM_SLOT_SIZE];
57     } h;
58     char   buf[1];
59 };
60 
61 typedef struct jk_shm_header jk_shm_header_t;
62 
63 /** jk shm in memory structure.
64  */
65 struct jk_shm
66 {
67     unsigned int size;
68     unsigned int ajp_workers;
69     unsigned int lb_sub_workers;
70     unsigned int lb_workers;
71     char        *filename;
72     char        *lockname;
73     int          fd;
74     int          fd_lock;
75     int          attached;
76     jk_shm_header_t  *hdr;
77     JK_CRIT_SEC       cs;
78 };
79 
80 typedef struct jk_shm jk_shm_t;
81 
82 static const char shm_signature[] = { JK_SHM_MAGIC };
83 static jk_shm_t jk_shmem = { 0, 0, 0, 0, NULL, NULL, -1, -1, 0, NULL};
84 #if defined (WIN32)
85 static HANDLE jk_shm_map = NULL;
86 static HANDLE jk_shm_hlock = NULL;
87 #endif
88 static int jk_shm_inited_cs = 0;
89 
jk_shm_calculate_slot_size()90 static size_t jk_shm_calculate_slot_size()
91 {
92     int align = 64;
93     size_t slot_size = 0;
94     size_t this_size = 0;
95 
96     this_size = sizeof(jk_shm_header_data_t);
97     if (this_size > slot_size)
98         slot_size = this_size;
99 
100     this_size = sizeof(jk_shm_worker_header_t);
101     if (this_size > slot_size)
102         slot_size = this_size;
103 
104     this_size = sizeof(jk_shm_ajp_worker_t);
105     if (this_size > slot_size)
106         slot_size = this_size;
107 
108     this_size = sizeof(jk_shm_lb_sub_worker_t);
109     if (this_size > slot_size)
110         slot_size = this_size;
111 
112     this_size = sizeof(jk_shm_lb_worker_t);
113     if (this_size > slot_size)
114         slot_size = this_size;
115 
116     slot_size = JK_ALIGN(slot_size, align);
117     return slot_size;
118 }
119 
120 /* Calculate needed shm size */
jk_shm_calculate_size(jk_map_t * init_data,jk_logger_t * l)121 int jk_shm_calculate_size(jk_map_t *init_data, jk_logger_t *l)
122 {
123     char **worker_list;
124     size_t needed_slot_size = 0;
125     unsigned int i;
126     unsigned int num_of_workers;
127     int num_of_ajp_workers = 0;
128     int num_of_lb_sub_workers = 0;
129     int num_of_lb_workers = 0;
130 
131     JK_TRACE_ENTER(l);
132 
133     if (jk_get_worker_list(init_data, &worker_list,
134                            &num_of_workers) == JK_FALSE) {
135         jk_log(l, JK_LOG_ERROR,
136                "Could not get worker list from map");
137         JK_TRACE_EXIT(l);
138         return 0;
139     }
140     needed_slot_size = jk_shm_calculate_slot_size();
141     if (JK_IS_DEBUG_LEVEL(l))
142         jk_log(l, JK_LOG_DEBUG, "JK_SHM_SLOT_SIZE defined as %d, need at least %d",
143                JK_SHM_SLOT_SIZE , needed_slot_size);
144     if (needed_slot_size > JK_SHM_SLOT_SIZE) {
145         jk_log(l, JK_LOG_ERROR,
146                "JK_SHM_SLOT_SIZE %d is too small, need at least %d",
147                JK_SHM_SLOT_SIZE, needed_slot_size);
148         JK_TRACE_EXIT(l);
149         return 0;
150     }
151     for (i = 0; i < num_of_workers; i++) {
152         const char *type = jk_get_worker_type(init_data, worker_list[i]);
153 
154         if (!strcmp(type, JK_AJP13_WORKER_NAME) ||
155             !strcmp(type, JK_AJP14_WORKER_NAME)) {
156             num_of_ajp_workers++;
157         }
158         else if (!strcmp(type, JK_LB_WORKER_NAME)) {
159             char **member_list;
160             unsigned int num_of_members;
161             num_of_lb_workers++;
162             if (jk_get_lb_worker_list(init_data, worker_list[i],
163                                       &member_list, &num_of_members) == JK_FALSE) {
164                 jk_log(l, JK_LOG_ERROR,
165                        "Could not get member list for lb worker from map");
166             }
167             else {
168                 if (JK_IS_DEBUG_LEVEL(l))
169                     jk_log(l, JK_LOG_DEBUG, "worker %s of type %s has %u members",
170                            worker_list[i], JK_LB_WORKER_NAME, num_of_members);
171                 num_of_lb_sub_workers += num_of_members;
172             }
173         }
174     }
175     if (JK_IS_DEBUG_LEVEL(l))
176         jk_log(l, JK_LOG_DEBUG, "shared memory will contain %d ajp workers and %d lb workers with %d members",
177                num_of_ajp_workers,
178                num_of_lb_workers,
179                num_of_lb_sub_workers);
180     jk_shmem.ajp_workers = num_of_ajp_workers;
181     jk_shmem.lb_sub_workers = num_of_lb_sub_workers;
182     jk_shmem.lb_workers = num_of_lb_workers;
183     JK_TRACE_EXIT(l);
184     return (JK_SHM_SLOT_SIZE * (jk_shmem.ajp_workers +
185             jk_shmem.lb_sub_workers * 2 +
186             jk_shmem.lb_workers));
187 }
188 
189 
190 #if defined (WIN32)
191 
192 /* Use plain memory */
jk_shm_open(const char * fname,int sz,jk_logger_t * l)193 int jk_shm_open(const char *fname, int sz, jk_logger_t *l)
194 {
195     int rc = -1;
196     int attached = 0;
197     char lkname[MAX_PATH];
198     char shname[MAX_PATH] = "";
199 
200     JK_TRACE_ENTER(l);
201     if (!jk_shm_inited_cs) {
202         jk_shm_inited_cs = 1;
203         JK_INIT_CS(&jk_shmem.cs, rc);
204     }
205     JK_ENTER_CS(&jk_shmem.cs);
206     if (jk_shmem.hdr) {
207         if (JK_IS_DEBUG_LEVEL(l))
208             jk_log(l, JK_LOG_DEBUG, "Shared memory is already opened");
209         JK_TRACE_EXIT(l);
210         JK_LEAVE_CS(&jk_shmem.cs);
211         return 0;
212     }
213     if (sz < 0) {
214         jk_log(l, JK_LOG_ERROR, "Invalid shared memory size (%d)", sz);
215         JK_TRACE_EXIT(l);
216         return EINVAL;
217     }
218     jk_shmem.size = JK_SHM_ALIGN(JK_SHM_SLOT_SIZE + sz);
219 #if defined (WIN32)
220     jk_shm_map   = NULL;
221     jk_shm_hlock = NULL;
222     if (fname) {
223         int i;
224         SIZE_T shmsz = 0;
225         strcpy(shname, "Local\\");
226         strncat(shname, fname, MAX_PATH - 8);
227         for(i = 7; i < (int)strlen(shname); i++) {
228             if (!jk_isalnum(shname[i]))
229                 shname[i] = '_';
230             else
231                 shname[i] = toupper(shname[i]);
232         }
233         strcpy(lkname, shname);
234         strncat(lkname, "_MUTEX", MAX_PATH - 1);
235         jk_shm_hlock = CreateMutex(jk_get_sa_with_null_dacl(), TRUE, lkname);
236         if (jk_shm_hlock == NULL) {
237             if (GetLastError() == ERROR_ALREADY_EXISTS) {
238                 attached = 1;
239                 jk_shm_hlock = OpenMutex(MUTEX_ALL_ACCESS, FALSE, lkname);
240             }
241         }
242         else if (GetLastError() == ERROR_ALREADY_EXISTS)
243             attached = 1;
244         if (jk_shm_hlock == NULL) {
245             rc = GetLastError();
246             jk_log(l, JK_LOG_ERROR, "Failed to open shared memory mutex %s with errno=%d",
247                    lkname, rc);
248             JK_LEAVE_CS(&jk_shmem.cs);
249             JK_TRACE_EXIT(l);
250             return rc;
251         }
252         if (attached) {
253             DWORD ws = WaitForSingleObject(jk_shm_hlock, INFINITE);
254             if (ws == WAIT_FAILED) {
255                 rc = GetLastError();
256                 CloseHandle(jk_shm_hlock);
257                 jk_shm_hlock = NULL;
258                 JK_LEAVE_CS(&jk_shmem.cs);
259                 JK_TRACE_EXIT(l);
260                 return rc;
261             }
262             jk_shm_map = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, shname);
263             if (jk_shm_map == NULL) {
264                 rc = GetLastError();
265                 jk_log(l, JK_LOG_ERROR, "Failed to open shared memory %s with errno=%d",
266                        shname, rc);
267             }
268         }
269         if (jk_shm_map == NULL) {
270             shmsz = jk_shmem.size;
271             jk_shm_map = CreateFileMapping(INVALID_HANDLE_VALUE,
272                                            jk_get_sa_with_null_dacl(),
273                                            PAGE_READWRITE,
274                                            0,
275                                            (DWORD)shmsz,
276                                            shname);
277         }
278         if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE) {
279             rc = GetLastError();
280             jk_log(l, JK_LOG_ERROR, "Failed to map shared memory %s with errno=%d",
281                    fname, rc);
282             CloseHandle(jk_shm_hlock);
283             jk_shm_hlock = NULL;
284             jk_shm_map   = NULL;
285             JK_LEAVE_CS(&jk_shmem.cs);
286             JK_TRACE_EXIT(l);
287             return rc;
288         }
289         jk_shmem.hdr = (jk_shm_header_t *)MapViewOfFile(jk_shm_map,
290                                                         FILE_MAP_READ | FILE_MAP_WRITE,
291                                                         0,
292                                                         0,
293                                                         shmsz);
294     }
295     else
296 #endif
297     jk_shmem.hdr = (jk_shm_header_t *)calloc(1, jk_shmem.size);
298     if (!jk_shmem.hdr) {
299 #if defined (WIN32)
300         rc = GetLastError();
301         if (jk_shm_map) {
302             CloseHandle(jk_shm_map);
303             jk_shm_map = NULL;
304         }
305         if (jk_shm_hlock) {
306             CloseHandle(jk_shm_hlock);
307             jk_shm_hlock = NULL;
308         }
309 #endif
310         JK_LEAVE_CS(&jk_shmem.cs);
311         JK_TRACE_EXIT(l);
312         return rc;
313     }
314     if (!jk_shmem.filename) {
315         if (shname[0])
316             jk_shmem.filename = strdup(shname);
317         else
318             jk_shmem.filename = strdup("memory");
319     }
320     jk_shmem.fd       = 0;
321     jk_shmem.attached = attached;
322     if (!attached) {
323         memset(jk_shmem.hdr, 0, jk_shmem.size);
324         memcpy(jk_shmem.hdr->h.data.magic, shm_signature,
325                JK_SHM_MAGIC_SIZ);
326         jk_shmem.hdr->h.data.size = sz;
327         jk_shmem.hdr->h.data.childs = 1;
328         jk_shmem.hdr->h.data.maintain_checking = 0;
329         jk_shmem.hdr->h.data.maintain_time = time(NULL);
330     }
331     else {
332         jk_shmem.hdr->h.data.childs++;
333         /*
334          * Reset the shared memory so that
335          * alloc works even for attached memory.
336          * XXX: This might break already used memory
337          * if the number of workers change between
338          * open and attach or between two attach operations.
339          */
340 #if 0
341         if (jk_shmem.hdr->h.data.childs > 1) {
342             if (JK_IS_DEBUG_LEVEL(l)) {
343                 jk_log(l, JK_LOG_DEBUG,
344                        "Resetting the shared memory for child %d",
345                        jk_shmem.hdr->h.data.childs);
346             }
347         }
348         jk_shmem.hdr->h.data.pos     = 0;
349         jk_shmem.hdr->h.data.workers = 0;
350 #endif
351     }
352 #if defined (WIN32)
353     if (jk_shm_hlock != NULL) {
354         /* Unlock shared memory */
355         ReleaseMutex(jk_shm_hlock);
356     }
357 #endif
358     JK_LEAVE_CS(&jk_shmem.cs);
359     if (JK_IS_DEBUG_LEVEL(l))
360         jk_log(l, JK_LOG_DEBUG,
361                "%s shared memory %s [%d] size=%u workers=%d free=%u addr=%#lx",
362                attached ? "Attached" : "Initialized",
363                jk_shm_name(),
364                jk_shmem.hdr->h.data.childs,
365                jk_shmem.size, jk_shmem.hdr->h.data.workers - 1,
366                jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
367                jk_shmem.hdr);
368     JK_TRACE_EXIT(l);
369     return 0;
370 }
371 
jk_shm_attach(const char * fname,int sz,jk_logger_t * l)372 int jk_shm_attach(const char *fname, int sz, jk_logger_t *l)
373 {
374     JK_TRACE_ENTER(l);
375     if (!jk_shm_open(fname, sz, l)) {
376         if (!jk_shmem.attached) {
377             jk_shmem.attached = 1;
378             if (JK_IS_DEBUG_LEVEL(l)) {
379                 jk_log(l, JK_LOG_DEBUG,
380                    "Attached shared memory %s [%d] size=%u free=%u addr=%#lx",
381                    jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size,
382                    jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
383                    jk_shmem.hdr);
384             }
385         }
386         JK_TRACE_EXIT(l);
387         return 0;
388     }
389     else {
390         JK_TRACE_EXIT(l);
391         return -1;
392     }
393 }
394 
jk_shm_close(jk_logger_t * l)395 void jk_shm_close(jk_logger_t *l)
396 {
397     if (jk_shm_inited_cs) {
398         JK_ENTER_CS(&jk_shmem.cs);
399     }
400     if (jk_shmem.hdr) {
401         if (JK_IS_DEBUG_LEVEL(l)) {
402             jk_log(l, JK_LOG_DEBUG,
403                    "Closed shared memory %s childs=%u",
404                    jk_shm_name(), jk_shmem.hdr->h.data.childs);
405         }
406 #if defined (WIN32)
407         if (jk_shm_hlock) {
408             WaitForSingleObject(jk_shm_hlock, 60000);
409             ReleaseMutex(jk_shm_hlock);
410             CloseHandle(jk_shm_hlock);
411             jk_shm_hlock = NULL;
412         }
413         if (jk_shm_map) {
414             --jk_shmem.hdr->h.data.childs;
415             UnmapViewOfFile(jk_shmem.hdr);
416             CloseHandle(jk_shm_map);
417             jk_shm_map = NULL;
418         }
419         else
420 #endif
421         free(jk_shmem.hdr);
422     }
423     jk_shmem.hdr = NULL;
424     if (jk_shmem.filename) {
425         free(jk_shmem.filename);
426         jk_shmem.filename = NULL;
427     }
428     if (jk_shm_inited_cs) {
429         JK_LEAVE_CS(&jk_shmem.cs);
430     }
431 }
432 
433 #else
434 
435 #include <unistd.h>
436 #include <fcntl.h>
437 #include <errno.h>
438 #include <sys/stat.h>
439 #include <sys/mman.h>
440 #include <sys/uio.h>
441 
442 #ifndef MAP_FAILED
443 #define MAP_FAILED  (-1)
444 #endif
445 
446 #ifndef MAP_FILE
447 #define MAP_FILE    (0)
448 #endif
449 
do_shm_open_lock(const char * fname,int attached,jk_logger_t * l)450 static int do_shm_open_lock(const char *fname, int attached, jk_logger_t *l)
451 {
452     int rc;
453     char flkname[256];
454 #ifdef AS400_UTF8
455     char *wptr;
456 #endif
457 
458     JK_TRACE_ENTER(l);
459 
460     if (attached && jk_shmem.lockname) {
461 #ifdef JK_SHM_LOCK_REOPEN
462         jk_shmem.fd_lock = open(jk_shmem.lockname, O_RDWR, 0666);
463 #else
464         errno = EINVAL;
465 #endif
466         if (jk_shmem.fd_lock == -1) {
467             rc = errno;
468             JK_TRACE_EXIT(l);
469             return rc;
470         }
471         if (JK_IS_DEBUG_LEVEL(l))
472             jk_log(l, JK_LOG_DEBUG,
473                    "Duplicated shared memory lock %s", jk_shmem.lockname);
474         JK_TRACE_EXIT(l);
475         return 0;
476     }
477 
478     if (!jk_shmem.lockname) {
479 #ifdef JK_SHM_LOCK_REOPEN
480         int i;
481         jk_shmem.fd_lock = -1;
482         mode_t mask = umask(0);
483         for (i = 0; i < 8; i++) {
484             strcpy(flkname, "/tmp/jkshmlock.XXXXXX");
485             if (mktemp(flkname)) {
486                 jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0666);
487                 if (jk_shmem.fd_lock >= 0)
488                     break;
489             }
490         }
491         umask(mask);
492 #else
493         strcpy(flkname, fname);
494         strcat(flkname, ".lock");
495 #ifdef AS400_UTF8
496         wptr = (char *)malloc(strlen(flkname) + 1);
497         jk_ascii2ebcdic((char *)flkname, wptr);
498         jk_shmem.fd_lock = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0666);
499         free(wptr);
500 #else
501         jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0666);
502 #endif
503 #endif
504         if (jk_shmem.fd_lock == -1) {
505             rc = errno;
506             JK_TRACE_EXIT(l);
507             return rc;
508         }
509         jk_shmem.lockname = strdup(flkname);
510     }
511     else {
512         /* Nothing to do */
513         JK_TRACE_EXIT(l);
514         return 0;
515     }
516 
517     if (ftruncate(jk_shmem.fd_lock, 1)) {
518         rc = errno;
519         close(jk_shmem.fd_lock);
520         jk_shmem.fd_lock = -1;
521         JK_TRACE_EXIT(l);
522         return rc;
523     }
524     if (lseek(jk_shmem.fd_lock, 0, SEEK_SET) != 0) {
525         rc = errno;
526         close(jk_shmem.fd_lock);
527         jk_shmem.fd_lock = -1;
528         return rc;
529     }
530     if (JK_IS_DEBUG_LEVEL(l))
531         jk_log(l, JK_LOG_DEBUG,
532                "Opened shared memory lock %s", jk_shmem.lockname);
533     JK_TRACE_EXIT(l);
534     return 0;
535 }
536 
do_shm_open(const char * fname,int attached,int sz,jk_logger_t * l)537 static int do_shm_open(const char *fname, int attached,
538                        int sz, jk_logger_t *l)
539 {
540     int rc;
541     int fd;
542     void *base;
543 #ifdef AS400_UTF8
544     char *wptr;
545 #endif
546 
547     JK_TRACE_ENTER(l);
548     if (!jk_shm_inited_cs) {
549         jk_shm_inited_cs = 1;
550         JK_INIT_CS(&jk_shmem.cs, rc);
551     }
552     if (jk_shmem.hdr) {
553         /* Probably a call from vhost */
554         if (!attached)
555             attached = 1;
556     }
557     else if (attached) {
558         /* We should already have a header
559          * Use memory if we don't
560          */
561         JK_TRACE_EXIT(l);
562         return 0;
563     }
564     if (sz < 0) {
565         jk_log(l, JK_LOG_ERROR, "Invalid shared memory size (%d)", sz);
566         JK_TRACE_EXIT(l);
567         return EINVAL;
568     }
569     jk_shmem.size = JK_SHM_ALIGN(JK_SHM_SLOT_SIZE + sz);
570 
571     if (!fname) {
572         /* Use plain memory in case there is no file name */
573         if (!jk_shmem.filename)
574             jk_shmem.filename  = strdup("memory");
575         if (JK_IS_DEBUG_LEVEL(l))
576             jk_log(l, JK_LOG_DEBUG,
577                    "Using process memory as shared memory");
578         JK_TRACE_EXIT(l);
579         return 0;
580     }
581 
582     if (!jk_shmem.filename) {
583         jk_shmem.filename = (char *)malloc(strlen(fname) + 32);
584         sprintf(jk_shmem.filename, "%s.%" JK_PID_T_FMT, fname, getpid());
585     }
586     if (!attached) {
587         size_t size;
588         jk_shmem.attached = 0;
589 #ifdef AS400_UTF8
590         wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
591         jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
592         fd = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0666);
593         free(wptr);
594 #else
595         fd = open(jk_shmem.filename, O_RDWR|O_CREAT|O_TRUNC, 0666);
596 #endif
597         if (fd == -1) {
598             jk_shmem.size = 0;
599             JK_TRACE_EXIT(l);
600             return errno;
601         }
602         size = lseek(fd, 0, SEEK_END);
603         if (size < jk_shmem.size) {
604             size = jk_shmem.size;
605             if (ftruncate(fd, jk_shmem.size)) {
606                 rc = errno;
607                 close(fd);
608 #ifdef  AS400_UTF8
609                 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
610                 jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
611                 unlink(wptr);
612                 free(wptr);
613 #else
614                 unlink(jk_shmem.filename);
615 #endif
616                 jk_shmem.size = 0;
617                 JK_TRACE_EXIT(l);
618                 return rc;
619             }
620             if (JK_IS_DEBUG_LEVEL(l))
621                 jk_log(l, JK_LOG_DEBUG,
622                        "Truncated shared memory to %u", size);
623         }
624         if (lseek(fd, 0, SEEK_SET) != 0) {
625             rc = errno;
626             close(fd);
627 #ifdef  AS400_UTF8
628             wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
629             jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
630             unlink(wptr);
631             free(wptr);
632 #else
633             unlink(jk_shmem.filename);
634 #endif
635             jk_shmem.size = 0;
636             JK_TRACE_EXIT(l);
637             return rc;
638         }
639 
640         base = mmap((caddr_t)0, jk_shmem.size,
641                     PROT_READ | PROT_WRITE,
642                     MAP_FILE | MAP_SHARED,
643                     fd, 0);
644         if (base == (caddr_t)MAP_FAILED || base == (caddr_t)0) {
645             rc = errno;
646             close(fd);
647 #ifdef  AS400_UTF8
648             wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
649             jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
650             unlink(wptr);
651             free(wptr);
652 #else
653             unlink(jk_shmem.filename);
654 #endif
655             jk_shmem.size = 0;
656             JK_TRACE_EXIT(l);
657             return rc;
658         }
659         jk_shmem.hdr = base;
660         jk_shmem.fd  = fd;
661         memset(jk_shmem.hdr, 0, jk_shmem.size);
662         memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ);
663         jk_shmem.hdr->h.data.size = sz;
664         jk_shmem.hdr->h.data.childs = 1;
665         jk_shmem.hdr->h.data.maintain_checking = 0;
666         jk_shmem.hdr->h.data.maintain_time = time(NULL);
667         if (JK_IS_DEBUG_LEVEL(l))
668             jk_log(l, JK_LOG_DEBUG,
669                    "Initialized shared memory %s size=%u free=%u addr=%#lx",
670                    jk_shm_name(), jk_shmem.size,
671                    jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
672                    jk_shmem.hdr);
673     }
674     else {
675         jk_shmem.hdr->h.data.childs++;
676         jk_shmem.attached = (int)getpid();
677         if (JK_IS_DEBUG_LEVEL(l))
678             jk_log(l, JK_LOG_DEBUG,
679                    "Attached shared memory %s [%d] size=%u workers=%u free=%u addr=%#lx",
680                    jk_shm_name(),
681                    jk_shmem.hdr->h.data.childs,
682                    jk_shmem.size, jk_shmem.hdr->h.data.workers - 1,
683                    jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
684                    jk_shmem.hdr);
685 #if 0
686         /*
687          * Reset the shared memory so that
688          * alloc works even for attached memory.
689          * XXX: This might break already used memory
690          * if the number of workers change between
691          * open and attach or between two attach operations.
692          */
693         if (nchild > 1) {
694             if (JK_IS_DEBUG_LEVEL(l)) {
695                 jk_log(l, JK_LOG_DEBUG,
696                        "Resetting the shared memory for child %d",
697                        nchild);
698             }
699         }
700         jk_shmem.hdr->h.data.pos     = 0;
701         jk_shmem.hdr->h.data.workers = 0;
702 #endif
703     }
704     if ((rc = do_shm_open_lock(jk_shmem.filename, attached, l))) {
705         if (!attached) {
706             munmap((void *)jk_shmem.hdr, jk_shmem.size);
707             close(jk_shmem.fd);
708 #ifdef  AS400_UTF8
709             wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
710             jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
711             unlink(wptr);
712             free(wptr);
713 #else
714             unlink(jk_shmem.filename);
715 #endif
716         }
717         jk_shmem.hdr = NULL;
718         jk_shmem.fd  = -1;
719         JK_TRACE_EXIT(l);
720         return rc;
721     }
722     JK_TRACE_EXIT(l);
723     return 0;
724 }
725 
jk_shm_open(const char * fname,int sz,jk_logger_t * l)726 int jk_shm_open(const char *fname, int sz, jk_logger_t *l)
727 {
728     return do_shm_open(fname, 0, sz, l);
729 }
730 
jk_shm_attach(const char * fname,int sz,jk_logger_t * l)731 int jk_shm_attach(const char *fname, int sz, jk_logger_t *l)
732 {
733     return do_shm_open(fname, 1, sz, l);
734 }
735 
jk_shm_close(jk_logger_t * l)736 void jk_shm_close(jk_logger_t *l)
737 {
738 #ifdef AS400_UTF8
739     char *wptr;
740 #endif
741 
742     if (jk_shmem.hdr) {
743         if (JK_IS_DEBUG_LEVEL(l)) {
744             jk_log(l, JK_LOG_DEBUG,
745                    "Closed shared memory %s childs=%u",
746                    jk_shm_name(), jk_shmem.hdr->h.data.childs);
747         }
748         --jk_shmem.hdr->h.data.childs;
749 
750 #ifdef JK_SHM_LOCK_REOPEN
751         if (jk_shmem.fd_lock >= 0) {
752             close(jk_shmem.fd_lock);
753             jk_shmem.fd_lock = -1;
754         }
755 #endif
756         if (jk_shmem.attached) {
757             int p = (int)getpid();
758             if (p == jk_shmem.attached) {
759                 /* In case this is a forked child
760                  * do not close the shared memory.
761                  * It will be closed by the parent.
762                  */
763                 jk_shmem.size = 0;
764                 jk_shmem.hdr  = NULL;
765                 jk_shmem.fd   = -1;
766                 return;
767             }
768         }
769         if (jk_shmem.fd >= 0) {
770             munmap((void *)jk_shmem.hdr, jk_shmem.size);
771             close(jk_shmem.fd);
772         }
773         if (jk_shmem.fd_lock >= 0)
774             close(jk_shmem.fd_lock);
775         if (jk_shmem.lockname) {
776 #ifdef  AS400_UTF8
777             wptr = (char *)malloc(strlen(jk_shmem.lockname) + 1);
778             jk_ascii2ebcdic((char *)jk_shmem.lockname, wptr);
779             unlink(wptr);
780             free(wptr);
781 #else
782             unlink(jk_shmem.lockname);
783 #endif
784             free(jk_shmem.lockname);
785             jk_shmem.lockname = NULL;
786         }
787         if (jk_shmem.filename) {
788 #ifdef  AS400_UTF8
789             wptr = (char *)malloc(strlen(jk_shmem.filename) + 1);
790             jk_ascii2ebcdic((char *)jk_shmem.filename, wptr);
791             unlink(wptr);
792             free(wptr);
793 #else
794             unlink(jk_shmem.filename);
795 #endif
796             free(jk_shmem.filename);
797             jk_shmem.filename = NULL;
798         }
799     }
800     jk_shmem.size    = 0;
801     jk_shmem.hdr     = NULL;
802     jk_shmem.fd      = -1;
803     jk_shmem.fd_lock = -1;
804 }
805 
806 
807 #endif
808 
jk_shm_alloc_worker(jk_pool_t * p,int type,int parent_id,const char * name,jk_logger_t * l)809 jk_shm_worker_header_t *jk_shm_alloc_worker(jk_pool_t *p, int type,
810                                             int parent_id, const char *name,
811                                             jk_logger_t *l)
812 {
813     unsigned int i;
814     jk_shm_worker_header_t *w = 0;
815 
816     if (jk_check_attribute_length("name", name, l) == JK_FALSE) {
817         return NULL;
818     }
819 
820     if (jk_shmem.hdr) {
821         jk_shm_lock();
822         for (i = 0; i < jk_shmem.hdr->h.data.pos; i += JK_SHM_SLOT_SIZE) {
823             w = (jk_shm_worker_header_t *)(jk_shmem.hdr->buf + i);
824             if (w->type == type && w-> parent_id == parent_id &&
825                 strcmp(w->name, name) == 0) {
826                 /* We have found already created worker */
827                 jk_shm_unlock();
828                 return w;
829             }
830         }
831         /* Allocate new worker */
832         if ((jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos) >= JK_SHM_SLOT_SIZE) {
833             w = (jk_shm_worker_header_t *)(jk_shmem.hdr->buf + jk_shmem.hdr->h.data.pos);
834             memset(w, 0, JK_SHM_SLOT_SIZE);
835             strncpy(w->name, name, JK_SHM_STR_SIZ);
836             jk_shmem.hdr->h.data.workers++;
837             w->id = jk_shmem.hdr->h.data.workers;
838             w->type = type;
839             w->parent_id = parent_id;
840             jk_shmem.hdr->h.data.pos += JK_SHM_SLOT_SIZE;
841         }
842         else {
843             /* No more free memory left.
844              */
845             jk_log(l, JK_LOG_ERROR,
846                    "Could not allocate shared memory for worker %s",
847                    name);
848             w = NULL;
849         }
850         jk_shm_unlock();
851     }
852     else if (p) {
853         w = (jk_shm_worker_header_t *)jk_pool_alloc(p, JK_SHM_SLOT_SIZE);
854         if (w) {
855             memset(w, 0, JK_SHM_SLOT_SIZE);
856             strncpy(w->name, name, JK_SHM_STR_SIZ);
857             w->id = 0;
858             w->type = type;
859             w->parent_id = parent_id;
860         }
861     }
862 
863     return w;
864 }
865 
jk_shm_name()866 const char *jk_shm_name()
867 {
868     return jk_shmem.filename;
869 }
870 
jk_shm_check_maintain(time_t trigger)871 int jk_shm_check_maintain(time_t trigger)
872 {
873     int rv = JK_FALSE;
874     int maintain_checking = JK_ATOMIC_INCREMENT(&(jk_shmem.hdr->h.data.maintain_checking));
875     /* Another process (or thread) is already checking */
876     if (maintain_checking > 1) {
877         JK_ATOMIC_DECREMENT(&(jk_shmem.hdr->h.data.maintain_checking));
878         return rv;
879     }
880     if (jk_shmem.hdr->h.data.maintain_time <= trigger) {
881         jk_shmem.hdr->h.data.maintain_time = time(NULL);
882         rv = JK_TRUE;
883     }
884     JK_ATOMIC_DECREMENT(&(jk_shmem.hdr->h.data.maintain_checking));
885     return rv;
886 }
887 
jk_shm_lock()888 int jk_shm_lock()
889 {
890     int rc = JK_TRUE;
891 
892     if (!jk_shm_inited_cs)
893         return JK_FALSE;
894     JK_ENTER_CS(&jk_shmem.cs);
895 #if defined (WIN32)
896     if (jk_shm_hlock != NULL) {
897         if (WaitForSingleObject(jk_shm_hlock, INFINITE) == WAIT_FAILED)
898             rc = JK_FALSE;
899     }
900 #else
901     if (jk_shmem.fd_lock != -1) {
902         JK_ENTER_LOCK(jk_shmem.fd_lock, rc);
903     }
904 #endif
905     return rc;
906 }
907 
jk_shm_unlock()908 int jk_shm_unlock()
909 {
910     int rc = JK_TRUE;
911 
912     if (!jk_shm_inited_cs)
913         return JK_FALSE;
914 #if defined (WIN32)
915     if (jk_shm_hlock != NULL) {
916         ReleaseMutex(jk_shm_hlock);
917     }
918 #else
919     if (jk_shmem.fd_lock != -1) {
920         JK_LEAVE_LOCK(jk_shmem.fd_lock, rc);
921     }
922 #endif
923     JK_LEAVE_CS(&jk_shmem.cs);
924     return rc;
925 }
926 
jk_shm_alloc_ajp_worker(jk_pool_t * p,const char * name,jk_logger_t * l)927 jk_shm_ajp_worker_t *jk_shm_alloc_ajp_worker(jk_pool_t *p, const char *name,
928                                              jk_logger_t *l)
929 {
930     return (jk_shm_ajp_worker_t *)jk_shm_alloc_worker(p,
931                                     JK_AJP13_WORKER_TYPE, 0, name, l);
932 }
933 
jk_shm_alloc_lb_sub_worker(jk_pool_t * p,int lb_id,const char * name,jk_logger_t * l)934 jk_shm_lb_sub_worker_t *jk_shm_alloc_lb_sub_worker(jk_pool_t *p, int lb_id, const char *name,
935                                                    jk_logger_t *l)
936 {
937     return (jk_shm_lb_sub_worker_t *)jk_shm_alloc_worker(p,
938                                     JK_LB_SUB_WORKER_TYPE, lb_id, name, l);
939 }
940 
jk_shm_alloc_lb_worker(jk_pool_t * p,const char * name,jk_logger_t * l)941 jk_shm_lb_worker_t *jk_shm_alloc_lb_worker(jk_pool_t *p, const char *name,
942                                            jk_logger_t *l)
943 {
944     return (jk_shm_lb_worker_t *)jk_shm_alloc_worker(p,
945                                     JK_LB_WORKER_TYPE, 0, name, l);
946 }
947