Apache HTTPD
mod_watchdog.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* Watchdog module.
18 */
19
20#include "apr.h"
21#include "mod_watchdog.h"
22#include "ap_provider.h"
23#include "ap_mpm.h"
24#include "http_core.h"
25#include "util_mutex.h"
26
27#include "apr_atomic.h"
28
29#define AP_WATCHDOG_PGROUP "watchdog"
30#define AP_WATCHDOG_PVERSION "parent"
31#define AP_WATCHDOG_CVERSION "child"
32
34
45
59
68
72static const char *wd_proc_mutex_type = "watchdog-callback";
73
75{
76 apr_status_t rv;
78
79 /* Do nothing if the thread wasn't started. */
81 return APR_SUCCESS;
82
83 if (w->is_running) {
85 while (wl) {
86 if (wl->status == APR_SUCCESS) {
87 /* Execute watchdog callback with STOPPING state */
89 (void *)wl->data, w->pool);
90 wl->status = APR_EOF;
91 }
92 wl = wl->next;
93 }
94 }
95 w->is_running = 0;
96 apr_thread_join(&rv, w->thread);
97 return rv;
98}
99
100/*--------------------------------------------------------------------------*/
101/* */
102/* Main watchdog worker thread. */
103/* For singleton workers child thread that first obtains the process */
104/* mutex is running. Threads in other child's are locked on mutex. */
105/* */
106/*--------------------------------------------------------------------------*/
107static void* APR_THREAD_FUNC wd_worker(apr_thread_t *thread, void *data)
108{
110 apr_status_t rv;
111 int locked = 0;
112 int probed = 0;
113 int inited = 0;
114 int mpmq_s = 0;
116
117 w->pool = apr_thread_pool_get(thread);
118 w->is_running = 1;
119
120 apr_atomic_set32(&w->thread_started, 1); /* thread started */
121
122 if (w->mutex) {
123 while (w->is_running) {
125 w->is_running = 0;
126 break;
127 }
128 if (mpmq_s == AP_MPMQ_STOPPING) {
129 w->is_running = 0;
130 break;
131 }
133 if (rv == APR_SUCCESS) {
134 if (probed) {
135 /* Sleep after we were locked
136 * up to 1 second. Httpd can be
137 * in the middle of shutdown, and
138 * our child didn't yet received
139 * the shutdown signal.
140 */
141 probed = 10;
142 while (w->is_running && probed > 0) {
144 probed--;
146 w->is_running = 0;
147 break;
148 }
149 if (mpmq_s == AP_MPMQ_STOPPING) {
150 w->is_running = 0;
151 break;
152 }
153 }
154 }
155 locked = 1;
156 break;
157 }
158 probed = 1;
160 }
161 }
162
164 apr_pool_tag(temp_pool, "wd_running");
165
166 if (w->is_running) {
167 watchdog_list_t *wl = w->callbacks;
169 APLOGNO(02972) "%sWatchdog (%s) running",
170 w->singleton ? "Singleton " : "", w->name);
172 if (wl) {
173 while (wl && w->is_running) {
174 /* Execute watchdog callback */
176 (void *)wl->data, temp_pool);
177 wl = wl->next;
178 }
180 }
181 else {
183 inited = 1;
184 }
185 }
186
187 /* Main execution loop */
188 while (w->is_running) {
190 watchdog_list_t *wl = w->callbacks;
191
194 w->is_running = 0;
195 }
196 if (mpmq_s == AP_MPMQ_STOPPING) {
197 w->is_running = 0;
198 }
199 if (!w->is_running) {
200 break;
201 }
203 while (wl && w->is_running) {
204 if (wl->status == APR_SUCCESS) {
205 wl->step += (apr_time_now() - curr);
206 if (wl->step >= wl->interval) {
207 wl->step = 0;
208 /* Execute watchdog callback */
210 (void *)wl->data, temp_pool);
212 w->is_running = 0;
213 }
214 if (mpmq_s == AP_MPMQ_STOPPING) {
215 w->is_running = 0;
216 }
217 }
218 }
219 wl = wl->next;
220 }
221 if (w->is_running && w->callbacks == NULL) {
222 /* This is hook mode watchdog
223 * running on WatchogInterval
224 */
225 w->step += (apr_time_now() - curr);
226 if (w->step >= wd_interval) {
227 w->step = 0;
228 /* Run watchdog step hook */
230 }
231 }
232
234 }
235
237
238 if (inited) {
239 /* Run the watchdog exit hooks.
240 * If this was singleton watchdog the init hook
241 * might never been called, so skip the exit hook
242 * in that case as well.
243 */
245 }
246 else {
247 watchdog_list_t *wl = w->callbacks;
248 while (wl) {
249 if (wl->status == APR_SUCCESS) {
250 /* Execute watchdog callback with STOPPING state */
252 (void *)wl->data, w->pool);
253 }
254 wl = wl->next;
255 }
256 }
258 APLOGNO(02973) "%sWatchdog (%s) stopping",
259 w->singleton ? "Singleton " : "", w->name);
260
261 if (locked)
264
265 return NULL;
266}
267
269{
271
273
274 if (w->singleton) {
275 /* Initialize singleton mutex in child */
278 if (rc != APR_SUCCESS)
279 return rc;
280 }
281
282 /* Start the newly created watchdog */
284 if (rc == APR_SUCCESS) {
286 }
287
288 return rc;
289}
290
292 const char *name,
293 int parent,
294 int singleton,
295 apr_pool_t *p)
296{
297 ap_watchdog_t *w;
299
301 /* Parent threads are not supported for
302 * forked mpm's
303 */
304 *watchdog = NULL;
305 return APR_ENOTIMPL;
306 }
308 if (w) {
309 *watchdog = w;
310 return APR_SUCCESS;
311 }
312 w = apr_pcalloc(p, sizeof(ap_watchdog_t));
313 w->name = name;
314 w->pool = p;
315 w->singleton = parent ? 0 : singleton;
316 *watchdog = w;
318 pver, *watchdog);
319}
320
322 apr_interval_time_t interval,
323 const void *data,
325{
328
329 while (c) {
330 if (c->data == data && c->callback_fn == callback) {
331 /* We have existing callback.
332 * Update the interval and reset status, so the
333 * callback and continue execution if stopped earlier.
334 */
335 c->interval = interval;
336 c->step = 0;
337 c->status = APR_SUCCESS;
338 rv = APR_SUCCESS;
339 break;
340 }
341 c = c->next;
342 }
343 return rv;
344}
345
347 apr_interval_time_t interval,
348 const void *data,
350{
352
353 while (c) {
354 if (c->data == data && c->callback_fn == callback) {
355 /* We have already registered callback.
356 * Do not allow callbacks that have the same
357 * function and data pointers.
358 */
359 return APR_EEXIST;
360 }
361 c = c->next;
362 }
363 c = apr_palloc(w->pool, sizeof(watchdog_list_t));
364 c->data = data;
365 c->callback_fn = callback;
366 c->interval = interval;
367 c->step = 0;
368 c->status = APR_EINIT;
369
370 c->wd = w;
371 c->next = w->callbacks;
372 w->callbacks = c;
373 w->active++;
374
375 return APR_SUCCESS;
376}
377
378/*--------------------------------------------------------------------------*/
379/* */
380/* Pre config hook. */
381/* Create default watchdogs for parent and child */
382/* Parent watchdog executes inside parent process so it doesn't need the */
383/* singleton mutex */
384/* */
385/*--------------------------------------------------------------------------*/
387 apr_pool_t *ptemp)
388{
389 apr_status_t rv;
390 ap_watchdog_t *w;
391
393 if ((rv = ap_watchdog_get_instance(&w,
395 return rv;
396 }
397 if ((rv = ap_watchdog_get_instance(&w,
399 return rv;
400 }
402 /* Create parent process watchdog for
403 * non forked mpm's only.
404 */
405 if ((rv = ap_watchdog_get_instance(&w,
407 return rv;
408 }
409 }
410
413 return rv;
414 }
415
416 return OK;
417}
418
419/*--------------------------------------------------------------------------*/
420/* */
421/* Post config hook. */
422/* Create watchdog thread in parent and initializes Watchdog module */
423/* */
424/*--------------------------------------------------------------------------*/
426 apr_pool_t *ptemp, server_rec *s)
427{
428 apr_status_t rv;
429 const char *pk = "watchdog_init_module_tag";
431 const apr_array_header_t *wl;
432
434 /* First time config phase -- skip. */
435 return OK;
436
438 if (!wd_server_conf) {
440 return APR_ENOMEM;
442 apr_pool_tag(wd_server_conf->pool, "wd_server_conf");
444 }
446 "Watchdog: Running with WatchdogInterval %"
448 wd_server_conf->s = s;
452 int i;
453
455 "Watchdog: found parent providers.");
456
458 for (i = 0; i < wl->nelts; i++) {
460 wn[i].provider_name,
463 "Watchdog: Looking for parent (%s).", wn[i].provider_name);
464 if (w) {
465 if (!w->active) {
466 int status = ap_run_watchdog_need(s, w->name, 1,
467 w->singleton);
468 if (status == OK) {
469 /* One of the modules returned OK to this watchdog.
470 * Mark it as active
471 */
472 w->active = 1;
473 }
474 }
475 if (w->active) {
476 /* We have active watchdog.
477 * Create the watchdog thread
478 */
479 if ((rv = wd_startup(w, wd_server_conf->pool)) != APR_SUCCESS) {
481 "Watchdog: Failed to create parent worker thread.");
482 return rv;
483 }
485 "Watchdog: Created parent worker thread (%s).", w->name);
487 }
488 }
489 }
490 }
493 "Spawned %d parent worker threads.",
495 }
499 int i;
501 "Watchdog: found child providers.");
502
504 for (i = 0; i < wl->nelts; i++) {
506 wn[i].provider_name,
509 "Watchdog: Looking for child (%s).", wn[i].provider_name);
510 if (w) {
511 if (!w->active) {
512 int status = ap_run_watchdog_need(s, w->name, 0,
513 w->singleton);
514 if (status == OK) {
515 /* One of the modules returned OK to this watchdog.
516 * Mark it as active
517 */
518 w->active = 1;
519 }
520 }
521 if (w->active) {
522 /* We have some callbacks registered.
523 * Create mutexes for singleton watchdogs
524 */
525 if (w->singleton) {
527 w->name, s,
528 wd_server_conf->pool, 0);
529 if (rv != APR_SUCCESS) {
531 "Watchdog: Failed to create singleton mutex.");
532 return rv;
533 }
535 "Watchdog: Created singleton mutex (%s).", w->name);
536 }
538 }
539 }
540 }
541 }
542 return OK;
543}
544
545/*--------------------------------------------------------------------------*/
546/* */
547/* Child init hook. */
548/* Create watchdog threads and initializes Mutexes in child */
549/* */
550/*--------------------------------------------------------------------------*/
552{
553 apr_status_t rv = OK;
554 const apr_array_header_t *wl;
555
557 /* We don't have anything configured, bail out.
558 */
560 "Watchdog: nothing configured?");
561 return;
562 }
566 int i;
568 for (i = 0; i < wl->nelts; i++) {
570 wn[i].provider_name,
572 if (w && w->active) {
573 /* We have some callbacks registered.
574 * Kick of the watchdog
575 */
576 if ((rv = wd_startup(w, wd_server_conf->pool)) != APR_SUCCESS) {
578 "Watchdog: Failed to create child worker thread.");
579 /* No point to continue */
580 return;
581 }
583 "Watchdog: Created child worker thread (%s).", wn[i].provider_name);
584 }
585 }
586 }
587}
588
589/*--------------------------------------------------------------------------*/
590/* */
591/* WatchdogInterval directive */
592/* */
593/*--------------------------------------------------------------------------*/
594static const char *wd_cmd_watchdog_int(cmd_parms *cmd, void *dummy,
595 const char *arg)
596{
597 apr_status_t rv;
599
600 if (errs != NULL)
601 return errs;
603
604 if (rv != APR_SUCCESS)
605 return "Unparse-able WatchdogInterval setting";
607 return apr_psprintf(cmd->pool, "Invalid WatchdogInterval: minimal value %"
609 }
610
611 return NULL;
612}
613
614/*--------------------------------------------------------------------------*/
615/* */
616/* List of directives specific to our module. */
617/* */
618/*--------------------------------------------------------------------------*/
620{
622 "WatchdogInterval", /* directive name */
623 wd_cmd_watchdog_int, /* config action routine */
624 NULL, /* argument to include in call */
625 RSRC_CONF, /* where available */
626 "Watchdog interval in seconds"
627 ),
628 {NULL}
629};
630
631/*--------------------------------------------------------------------------*/
632/* */
633/* Which functions are responsible for which hooks in the server. */
634/* */
635/*--------------------------------------------------------------------------*/
637{
638
639 /* Only the mpm_winnt has child init hook handler.
640 * Make sure that we are called after the mpm child init handler
641 * initializes.
642 */
643 static const char *const after_mpm[] = { "mpm_winnt.c", NULL};
644
645 /* Pre config handling
646 */
648 NULL,
649 NULL,
651
652 /* Post config handling
653 */
655 NULL,
656 NULL,
658
659 /* Child init hook
660 */
662 after_mpm,
663 NULL,
665
669}
670
671/*--------------------------------------------------------------------------*/
672/* */
673/* The list of callback routines and data structures that provide */
674/* the static hooks into our module from the other parts of the server. */
675/* */
676/*--------------------------------------------------------------------------*/
679 NULL, /* create per-directory config structure */
680 NULL, /* merge per-directory config structures */
681 NULL, /* create per-server config structure */
682 NULL, /* merge per-server config structures */
683 wd_directives, /* command apr_table_t */
684 wd_register_hooks /* register hooks */
685};
686
687/*--------------------------------------------------------------------------*/
688/* */
689/* The list of optional hooks that we provide */
690/* */
691/*--------------------------------------------------------------------------*/
698
700 (server_rec *s, const char *name,
701 int parent, int singleton),
702 (s, name, parent, singleton),
705 (server_rec *s, const char *name,
707 (s, name, pool),
710 (server_rec *s, const char *name,
712 (s, name, pool),
715 (server_rec *s, const char *name,
717 (s, name, pool),
Apache Multi-Processing Module library.
Apache Provider API.
APR Atomic Operations.
void apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val)
Definition atomic.c:73
apr_uint32_t apr_atomic_read32(volatile apr_uint32_t *mem)
Definition atomic.c:68
static apr_pool_t * pconf
Definition event.c:441
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
void ap_hook_child_init(ap_HOOK_child_init_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:167
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define AP_SQ_MS_CREATE_PRE_CONFIG
Definition http_core.h:1047
int ap_state_query(int query_code)
Definition core.c:5378
#define AP_SQ_MAIN_STATE
Definition http_core.h:1030
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_DEBUG
Definition http_log.h:71
apr_status_t ap_proc_mutex_create(apr_proc_mutex_t **mutex, const char **name, const char *type, const char *instance_id, server_rec *server, apr_pool_t *pool, apr_int32_t options)
Definition util_mutex.c:454
apr_status_t ap_mutex_register(apr_pool_t *pconf, const char *type, const char *default_dir, apr_lockmech_e default_mech, apr_int32_t options)
Definition util_mutex.c:254
apr_array_header_t * ap_list_provider_names(apr_pool_t *pool, const char *provider_group, const char *provider_version)
Definition provider.c:127
apr_status_t ap_register_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, const char *provider_version, const void *provider)
Definition provider.c:35
void * ap_lookup_provider(const char *provider_group, const char *provider_name, const char *provider_version)
Definition provider.c:99
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define APR_EOF
Definition apr_errno.h:461
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_EINIT
Definition apr_errno.h:474
#define APR_EEXIST
Definition apr_errno.h:648
#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(ns, link, ret, name, args_decl, args_use, decline)
Definition apr_hooks.h:267
#define APR_HOOK_FIRST
Definition apr_hooks.h:301
#define APR_HOOK_LINK(name)
Definition apr_hooks.h:139
#define APR_HOOK_LAST
Definition apr_hooks.h:305
#define APR_HOOK_STRUCT(members)
Definition apr_hooks.h:135
#define APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(ns, link, ret, name, args_decl, args_use, ok, decline)
Definition apr_hooks.h:222
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
apr_pool_t * temp_pool
#define APR_REGISTER_OPTIONAL_FN(name)
apr_redis_t * rc
Definition apr_redis.h:173
#define RSRC_CONF
int ap_run_watchdog_init(server_rec *s, const char *name, apr_pool_t *pool)
#define AP_WATCHDOG_STATE_STARTING
#define AP_WATCHDOG_STATE_STOPPING
int ap_run_watchdog_need(server_rec *s, const char *name, int parent, int singleton)
int ap_run_watchdog_step(server_rec *s, const char *name, apr_pool_t *pool)
#define AP_WATCHDOG_STATE_RUNNING
#define AP_WD_TM_INTERVAL
#define AP_WATCHDOG_SINGLETON
#define AP_WATCHDOG_DEFAULT
int ap_run_watchdog_exit(server_rec *s, const char *name, apr_pool_t *pool)
#define AP_WD_TM_SLICE
apr_status_t ap_watchdog_callback_fn_t(int state, void *data, apr_pool_t *pool)
#define STANDARD20_MODULE_STUFF
apr_status_t ap_timeout_parameter_parse(const char *timeout_parameter, apr_interval_time_t *timeout, const char *default_time_unit)
Definition util.c:2622
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void * data
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_vformatter_buff_t const char va_list ap
Definition apr_lib.h:176
apr_pool_t * parent
Definition apr_pools.h:197
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
@ APR_LOCK_DEFAULT
const char * s
Definition apr_strings.h:95
apr_cmdtype_e cmd
int int status
#define apr_time_as_msec(time)
Definition apr_time.h:72
#define APR_TIME_T_FMT
Definition apr_time.h:52
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_int64_t apr_time_t
Definition apr_time.h:45
apr_status_t ap_mpm_query(int query_code, int *result)
Definition mpm_common.c:421
#define AP_MPMQ_IS_FORKED
Definition ap_mpm.h:154
#define AP_MPMQ_MPM_STATE
Definition ap_mpm.h:174
#define AP_MPMQ_STOPPING
Definition ap_mpm.h:142
#define AP_MPMQ_NOT_SUPPORTED
Definition ap_mpm.h:125
CORE HTTP Daemon.
apr_pool_t * p
Definition md_event.c:32
static ap_watchdog_t * watchdog
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static void *APR_THREAD_FUNC wd_worker(apr_thread_t *thread, void *data)
static apr_status_t ap_watchdog_register_callback(ap_watchdog_t *w, apr_interval_time_t interval, const void *data, ap_watchdog_callback_fn_t *callback)
static int mpm_is_forked
static int wd_post_config_hook(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static apr_status_t ap_watchdog_get_instance(ap_watchdog_t **watchdog, const char *name, int parent, int singleton, apr_pool_t *p)
static const command_rec wd_directives[]
static apr_status_t ap_watchdog_set_callback_interval(ap_watchdog_t *w, apr_interval_time_t interval, const void *data, ap_watchdog_callback_fn_t *callback)
static const char * wd_cmd_watchdog_int(cmd_parms *cmd, void *dummy, const char *arg)
static const char * wd_proc_mutex_type
static void wd_child_init_hook(apr_pool_t *p, server_rec *s)
static apr_status_t wd_startup(ap_watchdog_t *w, apr_pool_t *p)
#define AP_WATCHDOG_CVERSION
static int wd_pre_config_hook(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
static apr_interval_time_t wd_interval
static wd_server_conf_t * wd_server_conf
#define AP_WATCHDOG_PGROUP
static void wd_register_hooks(apr_pool_t *p)
#define AP_WATCHDOG_PVERSION
static apr_status_t wd_worker_cleanup(void *data)
Watchdog module for Apache.
apr_status_t apr_thread_exit(apr_thread_t *thd, apr_status_t retval)
Definition thread.c:157
apr_status_t apr_thread_join(apr_status_t *retval, apr_thread_t *thd)
Definition thread.c:166
char * name
apr_proc_mutex_t * mutex
apr_pool_t * pool
apr_thread_t * thread
apr_uint32_t thread_started
const char * name
watchdog_list_t * callbacks
apr_interval_time_t step
A structure to store information for each virtual server.
Definition httpd.h:1322
ap_watchdog_t * wd
apr_interval_time_t step
ap_watchdog_callback_fn_t * callback_fn
apr_interval_time_t interval
const void * data
struct watchdog_list_t * next
apr_status_t status
server_rec * s
apr_pool_t * pool
Apache Mutex support library.