~ubuntu-branches/ubuntu/utopic/pacemaker/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/Fix-lrmd-Cancel-recurring-operations-before-stop-act.patch/lib/common/mainloop.c

  • Committer: Package Import Robot
  • Author(s): Rafael David Tinoco
  • Date: 2014-09-04 09:58:36 UTC
  • Revision ID: package-import@ubuntu.com-20140904095836-cvvat3kox61c8l1y
Tags: 1.1.10+git20130802-4ubuntu3
* Fix: services: Do not allow duplicate recurring op entries - 1/3 (LP: #1353473)
* High: lrmd: Merge duplicate recurring monitor operations - 2/3 (LP: #1353473)
* Fix: lrmd: Cancel recurring operations before stop action is executed - 3/3 (LP: #1353473)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Lesser General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2.1 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public
 
15
 * License along with this library; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 */
 
18
 
 
19
#include <crm_internal.h>
 
20
 
 
21
#ifndef _GNU_SOURCE
 
22
#  define _GNU_SOURCE
 
23
#endif
 
24
 
 
25
#include <stdlib.h>
 
26
#include <signal.h>
 
27
#include <errno.h>
 
28
 
 
29
#include <sys/wait.h>
 
30
 
 
31
#include <crm/crm.h>
 
32
#include <crm/common/xml.h>
 
33
#include <crm/common/mainloop.h>
 
34
#include <crm/common/ipcs.h>
 
35
 
 
36
struct mainloop_child_s {
 
37
    pid_t pid;
 
38
    char *desc;
 
39
    unsigned timerid;
 
40
    unsigned watchid;
 
41
    gboolean timeout;
 
42
    void *privatedata;
 
43
 
 
44
    /* Called when a process dies */
 
45
    void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode);
 
46
};
 
47
 
 
48
struct trigger_s {
 
49
    GSource source;
 
50
    gboolean running;
 
51
    gboolean trigger;
 
52
    void *user_data;
 
53
    guint id;
 
54
 
 
55
};
 
56
 
 
57
static gboolean
 
58
crm_trigger_prepare(GSource * source, gint * timeout)
 
59
{
 
60
    crm_trigger_t *trig = (crm_trigger_t *) source;
 
61
 
 
62
    /* cluster-glue's FD and IPC related sources make use of
 
63
     * g_source_add_poll() but do not set a timeout in their prepare
 
64
     * functions
 
65
     *
 
66
     * This means mainloop's poll() will block until an event for one
 
67
     * of these sources occurs - any /other/ type of source, such as
 
68
     * this one or g_idle_*, that doesn't use g_source_add_poll() is
 
69
     * S-O-L and wont be processed until there is something fd-based
 
70
     * happens.
 
71
     *
 
72
     * Luckily the timeout we can set here affects all sources and
 
73
     * puts an upper limit on how long poll() can take.
 
74
     *
 
75
     * So unconditionally set a small-ish timeout, not too small that
 
76
     * we're in constant motion, which will act as an upper bound on
 
77
     * how long the signal handling might be delayed for.
 
78
     */
 
79
    *timeout = 500;             /* Timeout in ms */
 
80
 
 
81
    return trig->trigger;
 
82
}
 
83
 
 
84
static gboolean
 
85
crm_trigger_check(GSource * source)
 
86
{
 
87
    crm_trigger_t *trig = (crm_trigger_t *) source;
 
88
 
 
89
    return trig->trigger;
 
90
}
 
91
 
 
92
static gboolean
 
93
crm_trigger_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
 
94
{
 
95
    int rc = TRUE;
 
96
    crm_trigger_t *trig = (crm_trigger_t *) source;
 
97
 
 
98
    if (trig->running) {
 
99
        /* Wait until the existing job is complete before starting the next one */
 
100
        return TRUE;
 
101
    }
 
102
    trig->trigger = FALSE;
 
103
 
 
104
    if (callback) {
 
105
        rc = callback(trig->user_data);
 
106
        if (rc < 0) {
 
107
            crm_trace("Trigger handler %p not yet complete", trig);
 
108
            trig->running = TRUE;
 
109
            rc = TRUE;
 
110
        }
 
111
    }
 
112
    return rc;
 
113
}
 
114
 
 
115
static void
 
116
crm_trigger_finalize(GSource * source)
 
117
{
 
118
    crm_trace("Trigger %p destroyed", source);
 
119
}
 
120
 
 
121
#if 0
 
122
struct _GSourceCopy
 
123
{
 
124
  gpointer callback_data;
 
125
  GSourceCallbackFuncs *callback_funcs;
 
126
 
 
127
  const GSourceFuncs *source_funcs;
 
128
  guint ref_count;
 
129
 
 
130
  GMainContext *context;
 
131
 
 
132
  gint priority;
 
133
  guint flags;
 
134
  guint source_id;
 
135
 
 
136
  GSList *poll_fds;
 
137
  
 
138
  GSource *prev;
 
139
  GSource *next;
 
140
 
 
141
  char    *name;
 
142
 
 
143
  void *priv;
 
144
};
 
145
 
 
146
static int
 
147
g_source_refcount(GSource * source)
 
148
{
 
149
    /* Duplicating the contents of private header files is a necessary evil */
 
150
    if (source) {
 
151
        struct _GSourceCopy *evil = (struct _GSourceCopy*)source;
 
152
        return evil->ref_count;
 
153
    }
 
154
    return 0;
 
155
}
 
156
#else
 
157
static int g_source_refcount(GSource * source)
 
158
{
 
159
    return 0;
 
160
}
 
161
#endif
 
162
 
 
163
static GSourceFuncs crm_trigger_funcs = {
 
164
    crm_trigger_prepare,
 
165
    crm_trigger_check,
 
166
    crm_trigger_dispatch,
 
167
    crm_trigger_finalize,
 
168
};
 
169
 
 
170
static crm_trigger_t *
 
171
mainloop_setup_trigger(GSource * source, int priority, int (*dispatch) (gpointer user_data),
 
172
                       gpointer userdata)
 
173
{
 
174
    crm_trigger_t *trigger = NULL;
 
175
 
 
176
    trigger = (crm_trigger_t *) source;
 
177
 
 
178
    trigger->id = 0;
 
179
    trigger->trigger = FALSE;
 
180
    trigger->user_data = userdata;
 
181
 
 
182
    if (dispatch) {
 
183
        g_source_set_callback(source, dispatch, trigger, NULL);
 
184
    }
 
185
 
 
186
    g_source_set_priority(source, priority);
 
187
    g_source_set_can_recurse(source, FALSE);
 
188
 
 
189
    crm_trace("Setup %p with ref-count=%u", source, g_source_refcount(source));
 
190
    trigger->id = g_source_attach(source, NULL);
 
191
    crm_trace("Attached %p with ref-count=%u", source, g_source_refcount(source));
 
192
 
 
193
    return trigger;
 
194
}
 
195
 
 
196
void
 
197
mainloop_trigger_complete(crm_trigger_t * trig)
 
198
{
 
199
    crm_trace("Trigger handler %p complete", trig);
 
200
    trig->running = FALSE;
 
201
}
 
202
 
 
203
/* If dispatch returns:
 
204
 *  -1: Job running but not complete
 
205
 *   0: Remove the trigger from mainloop
 
206
 *   1: Leave the trigger in mainloop
 
207
 */
 
208
crm_trigger_t *
 
209
mainloop_add_trigger(int priority, int (*dispatch) (gpointer user_data), gpointer userdata)
 
210
{
 
211
    GSource *source = NULL;
 
212
 
 
213
    CRM_ASSERT(sizeof(crm_trigger_t) > sizeof(GSource));
 
214
    source = g_source_new(&crm_trigger_funcs, sizeof(crm_trigger_t));
 
215
    CRM_ASSERT(source != NULL);
 
216
 
 
217
    return mainloop_setup_trigger(source, priority, dispatch, userdata);
 
218
}
 
219
 
 
220
void
 
221
mainloop_set_trigger(crm_trigger_t * source)
 
222
{
 
223
    if(source) {
 
224
        source->trigger = TRUE;
 
225
    }
 
226
}
 
227
 
 
228
gboolean
 
229
mainloop_destroy_trigger(crm_trigger_t * source)
 
230
{
 
231
    GSource *gs = NULL;
 
232
 
 
233
    if(source == NULL) {
 
234
        return TRUE;
 
235
    }
 
236
 
 
237
    gs = (GSource *)source;
 
238
 
 
239
    if(g_source_refcount(gs) > 2) {
 
240
        crm_info("Trigger %p is still referenced %u times", gs, g_source_refcount(gs));
 
241
    }
 
242
 
 
243
    g_source_destroy(gs); /* Remove from mainloop, ref_count-- */
 
244
    g_source_unref(gs); /* The caller no longer carries a reference to source
 
245
                         *
 
246
                         * At this point the source should be free'd,
 
247
                         * unless we're currently processing said
 
248
                         * source, in which case mainloop holds an
 
249
                         * additional reference and it will be free'd
 
250
                         * once our processing completes
 
251
                         */
 
252
    return TRUE;
 
253
}
 
254
 
 
255
typedef struct signal_s {
 
256
    crm_trigger_t trigger;      /* must be first */
 
257
    void (*handler) (int sig);
 
258
    int signal;
 
259
 
 
260
} crm_signal_t;
 
261
 
 
262
static crm_signal_t *crm_signals[NSIG];
 
263
 
 
264
static gboolean
 
265
crm_signal_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
 
266
{
 
267
    crm_signal_t *sig = (crm_signal_t *) source;
 
268
 
 
269
    if(sig->signal != SIGCHLD) {
 
270
        crm_info("Invoking handler for signal %d: %s", sig->signal, strsignal(sig->signal));
 
271
    }
 
272
 
 
273
    sig->trigger.trigger = FALSE;
 
274
    if (sig->handler) {
 
275
        sig->handler(sig->signal);
 
276
    }
 
277
    return TRUE;
 
278
}
 
279
 
 
280
static void
 
281
mainloop_signal_handler(int sig)
 
282
{
 
283
    if (sig > 0 && sig < NSIG && crm_signals[sig] != NULL) {
 
284
        mainloop_set_trigger((crm_trigger_t *) crm_signals[sig]);
 
285
    }
 
286
}
 
287
 
 
288
static GSourceFuncs crm_signal_funcs = {
 
289
    crm_trigger_prepare,
 
290
    crm_trigger_check,
 
291
    crm_signal_dispatch,
 
292
    crm_trigger_finalize,
 
293
};
 
294
 
 
295
gboolean
 
296
crm_signal(int sig, void (*dispatch) (int sig))
 
297
{
 
298
    sigset_t mask;
 
299
    struct sigaction sa;
 
300
    struct sigaction old;
 
301
 
 
302
    if (sigemptyset(&mask) < 0) {
 
303
        crm_perror(LOG_ERR, "Call to sigemptyset failed");
 
304
        return FALSE;
 
305
    }
 
306
 
 
307
    memset(&sa, 0, sizeof(struct sigaction));
 
308
    sa.sa_handler = dispatch;
 
309
    sa.sa_flags = SA_RESTART;
 
310
    sa.sa_mask = mask;
 
311
 
 
312
    if (sigaction(sig, &sa, &old) < 0) {
 
313
        crm_perror(LOG_ERR, "Could not install signal handler for signal %d", sig);
 
314
        return FALSE;
 
315
    }
 
316
 
 
317
    return TRUE;
 
318
}
 
319
 
 
320
gboolean
 
321
mainloop_add_signal(int sig, void (*dispatch) (int sig))
 
322
{
 
323
    GSource *source = NULL;
 
324
    int priority = G_PRIORITY_HIGH - 1;
 
325
 
 
326
    if (sig == SIGTERM) {
 
327
        /* TERM is higher priority than other signals,
 
328
         *   signals are higher priority than other ipc.
 
329
         * Yes, minus: smaller is "higher"
 
330
         */
 
331
        priority--;
 
332
    }
 
333
 
 
334
    if (sig >= NSIG || sig < 0) {
 
335
        crm_err("Signal %d is out of range", sig);
 
336
        return FALSE;
 
337
 
 
338
    } else if (crm_signals[sig] != NULL && crm_signals[sig]->handler == dispatch) {
 
339
        crm_trace("Signal handler for %d is already installed", sig);
 
340
        return TRUE;
 
341
 
 
342
    } else if (crm_signals[sig] != NULL) {
 
343
        crm_err("Different signal handler for %d is already installed", sig);
 
344
        return FALSE;
 
345
    }
 
346
 
 
347
    CRM_ASSERT(sizeof(crm_signal_t) > sizeof(GSource));
 
348
    source = g_source_new(&crm_signal_funcs, sizeof(crm_signal_t));
 
349
 
 
350
    crm_signals[sig] = (crm_signal_t *) mainloop_setup_trigger(source, priority, NULL, NULL);
 
351
    CRM_ASSERT(crm_signals[sig] != NULL);
 
352
 
 
353
    crm_signals[sig]->handler = dispatch;
 
354
    crm_signals[sig]->signal = sig;
 
355
 
 
356
    if (crm_signal(sig, mainloop_signal_handler) == FALSE) {
 
357
        crm_signal_t *tmp = crm_signals[sig];
 
358
 
 
359
        crm_signals[sig] = NULL;
 
360
 
 
361
        mainloop_destroy_trigger((crm_trigger_t *) tmp);
 
362
        return FALSE;
 
363
    }
 
364
#if 0
 
365
    /* If we want signals to interrupt mainloop's poll(), instead of waiting for
 
366
     * the timeout, then we should call siginterrupt() below
 
367
     *
 
368
     * For now, just enforce a low timeout
 
369
     */
 
370
    if (siginterrupt(sig, 1) < 0) {
 
371
        crm_perror(LOG_INFO, "Could not enable system call interruptions for signal %d", sig);
 
372
    }
 
373
#endif
 
374
 
 
375
    return TRUE;
 
376
}
 
377
 
 
378
gboolean
 
379
mainloop_destroy_signal(int sig)
 
380
{
 
381
    crm_signal_t *tmp = NULL;
 
382
 
 
383
    if (sig >= NSIG || sig < 0) {
 
384
        crm_err("Signal %d is out of range", sig);
 
385
        return FALSE;
 
386
 
 
387
    } else if (crm_signal(sig, NULL) == FALSE) {
 
388
        crm_perror(LOG_ERR, "Could not uninstall signal handler for signal %d", sig);
 
389
        return FALSE;
 
390
 
 
391
    } else if (crm_signals[sig] == NULL) {
 
392
        return TRUE;
 
393
    }
 
394
 
 
395
    crm_trace("Destroying signal %d", sig);
 
396
    tmp = crm_signals[sig];
 
397
    crm_signals[sig] = NULL;
 
398
    mainloop_destroy_trigger((crm_trigger_t *) tmp);
 
399
    return TRUE;
 
400
}
 
401
 
 
402
static qb_array_t *gio_map = NULL;
 
403
 
 
404
void
 
405
mainloop_cleanup(void) 
 
406
{
 
407
    if(gio_map) {
 
408
        qb_array_free(gio_map);
 
409
    }
 
410
}
 
411
 
 
412
/*
 
413
 * libqb...
 
414
 */
 
415
struct gio_to_qb_poll {
 
416
    int32_t is_used;
 
417
    guint source;
 
418
    int32_t events;
 
419
    void *data;
 
420
    qb_ipcs_dispatch_fn_t fn;
 
421
    enum qb_loop_priority p;
 
422
};
 
423
 
 
424
static gboolean
 
425
gio_read_socket(GIOChannel * gio, GIOCondition condition, gpointer data)
 
426
{
 
427
    struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
 
428
    gint fd = g_io_channel_unix_get_fd(gio);
 
429
 
 
430
    crm_trace("%p.%d %d", data, fd, condition);
 
431
 
 
432
    if (condition & G_IO_NVAL) {
 
433
        crm_trace("Marking failed adaptor %p unused", adaptor);
 
434
        adaptor->is_used = QB_FALSE;
 
435
    }
 
436
 
 
437
    return (adaptor->fn(fd, condition, adaptor->data) == 0);
 
438
}
 
439
 
 
440
static void
 
441
gio_poll_destroy(gpointer data)
 
442
{
 
443
    struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
 
444
 
 
445
    adaptor->is_used = QB_FALSE;
 
446
    adaptor->source = 0;
 
447
}
 
448
 
 
449
static int32_t
 
450
gio_poll_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
 
451
                      void *data, qb_ipcs_dispatch_fn_t fn)
 
452
{
 
453
    struct gio_to_qb_poll *adaptor;
 
454
    GIOChannel *channel;
 
455
    int32_t res = 0;
 
456
 
 
457
    res = qb_array_index(gio_map, fd, (void **)&adaptor);
 
458
    if (res < 0) {
 
459
        crm_err("Array lookup failed for fd=%d: %d", fd, res);
 
460
        return res;
 
461
    }
 
462
 
 
463
    crm_trace("Adding fd=%d to mainloop as adapater %p", fd, adaptor);
 
464
    if (adaptor->is_used) {
 
465
        crm_err("Adapter for descriptor %d is still in-use", fd);
 
466
        return -EEXIST;
 
467
    }
 
468
 
 
469
    /* channel is created with ref_count = 1 */
 
470
    channel = g_io_channel_unix_new(fd);
 
471
    if (!channel) {
 
472
        crm_err("No memory left to add fd=%d", fd);
 
473
        return -ENOMEM;
 
474
    }
 
475
 
 
476
    /* Because unlike the poll() API, glib doesn't tell us about HUPs by default */
 
477
    evts |= (G_IO_HUP | G_IO_NVAL | G_IO_ERR);
 
478
 
 
479
    adaptor->fn = fn;
 
480
    adaptor->events = evts;
 
481
    adaptor->data = data;
 
482
    adaptor->p = p;
 
483
    adaptor->is_used = QB_TRUE;
 
484
    adaptor->source =
 
485
        g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, evts, gio_read_socket, adaptor,
 
486
                            gio_poll_destroy);
 
487
 
 
488
    /* Now that mainloop now holds a reference to channel,
 
489
     * thanks to g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
 
490
     *
 
491
     * This means that channel will be free'd by:
 
492
     * g_main_context_dispatch()
 
493
     *  -> g_source_destroy_internal()
 
494
     *      -> g_source_callback_unref()
 
495
     * shortly after gio_poll_destroy() completes
 
496
     */
 
497
    g_io_channel_unref(channel);
 
498
 
 
499
    crm_trace("Added to mainloop with gsource id=%d", adaptor->source);
 
500
    if (adaptor->source > 0) {
 
501
        return 0;
 
502
    }
 
503
 
 
504
    return -EINVAL;
 
505
}
 
506
 
 
507
static int32_t
 
508
gio_poll_dispatch_mod(enum qb_loop_priority p, int32_t fd, int32_t evts,
 
509
                      void *data, qb_ipcs_dispatch_fn_t fn)
 
510
{
 
511
    return 0;
 
512
}
 
513
 
 
514
static int32_t
 
515
gio_poll_dispatch_del(int32_t fd)
 
516
{
 
517
    struct gio_to_qb_poll *adaptor;
 
518
 
 
519
    crm_trace("Looking for fd=%d", fd);
 
520
    if (qb_array_index(gio_map, fd, (void **)&adaptor) == 0) {
 
521
        crm_trace("Marking adaptor %p unused", adaptor);
 
522
        if (adaptor->source) {
 
523
            g_source_remove(adaptor->source);
 
524
            adaptor->source = 0;
 
525
        }
 
526
        adaptor->is_used = QB_FALSE;
 
527
    }
 
528
    return 0;
 
529
}
 
530
 
 
531
struct qb_ipcs_poll_handlers gio_poll_funcs = {
 
532
    .job_add = NULL,
 
533
    .dispatch_add = gio_poll_dispatch_add,
 
534
    .dispatch_mod = gio_poll_dispatch_mod,
 
535
    .dispatch_del = gio_poll_dispatch_del,
 
536
};
 
537
 
 
538
static enum qb_ipc_type
 
539
pick_ipc_type(enum qb_ipc_type requested)
 
540
{
 
541
    const char *env = getenv("PCMK_ipc_type");
 
542
 
 
543
    if (env && strcmp("shared-mem", env) == 0) {
 
544
        return QB_IPC_SHM;
 
545
    } else if (env && strcmp("socket", env) == 0) {
 
546
        return QB_IPC_SOCKET;
 
547
    } else if (env && strcmp("posix", env) == 0) {
 
548
        return QB_IPC_POSIX_MQ;
 
549
    } else if (env && strcmp("sysv", env) == 0) {
 
550
        return QB_IPC_SYSV_MQ;
 
551
    } else if (requested == QB_IPC_NATIVE) {
 
552
        /* We prefer shared memory because the server never blocks on
 
553
         * send.  If part of a message fits into the socket, libqb
 
554
         * needs to block until the remainder can be sent also.
 
555
         * Otherwise the client will wait forever for the remaining
 
556
         * bytes.
 
557
         */
 
558
        return QB_IPC_SHM;
 
559
    }
 
560
    return requested;
 
561
}
 
562
 
 
563
qb_ipcs_service_t *
 
564
mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
 
565
                        struct qb_ipcs_service_handlers * callbacks)
 
566
{
 
567
    int rc = 0;
 
568
    qb_ipcs_service_t *server = NULL;
 
569
 
 
570
    if (gio_map == NULL) {
 
571
        gio_map = qb_array_create_2(64, sizeof(struct gio_to_qb_poll), 1);
 
572
    }
 
573
 
 
574
    crm_client_init();
 
575
    server = qb_ipcs_create(name, 0, pick_ipc_type(type), callbacks);
 
576
    qb_ipcs_poll_handlers_set(server, &gio_poll_funcs);
 
577
 
 
578
    rc = qb_ipcs_run(server);
 
579
    if (rc < 0) {
 
580
        crm_err("Could not start %s IPC server: %s (%d)", name, pcmk_strerror(rc), rc);
 
581
        return NULL;
 
582
    }
 
583
 
 
584
    return server;
 
585
}
 
586
 
 
587
void
 
588
mainloop_del_ipc_server(qb_ipcs_service_t * server)
 
589
{
 
590
    if (server) {
 
591
        qb_ipcs_destroy(server);
 
592
    }
 
593
}
 
594
 
 
595
struct mainloop_io_s {
 
596
    char *name;
 
597
    void *userdata;
 
598
 
 
599
    int fd;
 
600
    guint source;
 
601
    crm_ipc_t *ipc;
 
602
    GIOChannel *channel;
 
603
 
 
604
    int (*dispatch_fn_ipc) (const char *buffer, ssize_t length, gpointer userdata);
 
605
    int (*dispatch_fn_io) (gpointer userdata);
 
606
    void (*destroy_fn) (gpointer userdata);
 
607
 
 
608
};
 
609
 
 
610
static gboolean
 
611
mainloop_gio_callback(GIOChannel * gio, GIOCondition condition, gpointer data)
 
612
{
 
613
    gboolean keep = TRUE;
 
614
    mainloop_io_t *client = data;
 
615
 
 
616
    CRM_ASSERT(client->fd == g_io_channel_unix_get_fd(gio));
 
617
 
 
618
    if (condition & G_IO_IN) {
 
619
        if (client->ipc) {
 
620
            long rc = 0;
 
621
            int max = 10;
 
622
 
 
623
            do {
 
624
                rc = crm_ipc_read(client->ipc);
 
625
                if (rc <= 0) {
 
626
                    crm_trace("Message acquisition from %s[%p] failed: %s (%ld)",
 
627
                              client->name, client, pcmk_strerror(rc), rc);
 
628
 
 
629
                } else if (client->dispatch_fn_ipc) {
 
630
                    const char *buffer = crm_ipc_buffer(client->ipc);
 
631
 
 
632
                    crm_trace("New message from %s[%p] = %d", client->name, client, rc, condition);
 
633
                    if (client->dispatch_fn_ipc(buffer, rc, client->userdata) < 0) {
 
634
                        crm_trace("Connection to %s no longer required", client->name);
 
635
                        keep = FALSE;
 
636
                    }
 
637
                }
 
638
 
 
639
            } while (keep && rc > 0 && --max > 0);
 
640
 
 
641
        } else {
 
642
            crm_trace("New message from %s[%p] %u", client->name, client, condition);
 
643
            if (client->dispatch_fn_io) {
 
644
                if (client->dispatch_fn_io(client->userdata) < 0) {
 
645
                    crm_trace("Connection to %s no longer required", client->name);
 
646
                    keep = FALSE;
 
647
                }
 
648
            }
 
649
        }
 
650
    }
 
651
 
 
652
    if (client->ipc && crm_ipc_connected(client->ipc) == FALSE) {
 
653
        crm_err("Connection to %s[%p] closed (I/O condition=%d)", client->name, client, condition);
 
654
        keep = FALSE;
 
655
 
 
656
    } else if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR)) {
 
657
        crm_trace("The connection %s[%p] has been closed (I/O condition=%d)",
 
658
                  client->name, client, condition);
 
659
        keep = FALSE;
 
660
 
 
661
    } else if ((condition & G_IO_IN) == 0) {
 
662
        /*
 
663
           #define      GLIB_SYSDEF_POLLIN     =1
 
664
           #define      GLIB_SYSDEF_POLLPRI    =2
 
665
           #define      GLIB_SYSDEF_POLLOUT    =4
 
666
           #define      GLIB_SYSDEF_POLLERR    =8
 
667
           #define      GLIB_SYSDEF_POLLHUP    =16
 
668
           #define      GLIB_SYSDEF_POLLNVAL   =32
 
669
 
 
670
           typedef enum
 
671
           {
 
672
           G_IO_IN      GLIB_SYSDEF_POLLIN,
 
673
           G_IO_OUT     GLIB_SYSDEF_POLLOUT,
 
674
           G_IO_PRI     GLIB_SYSDEF_POLLPRI,
 
675
           G_IO_ERR     GLIB_SYSDEF_POLLERR,
 
676
           G_IO_HUP     GLIB_SYSDEF_POLLHUP,
 
677
           G_IO_NVAL    GLIB_SYSDEF_POLLNVAL
 
678
           } GIOCondition;
 
679
 
 
680
           A bitwise combination representing a condition to watch for on an event source.
 
681
 
 
682
           G_IO_IN      There is data to read.
 
683
           G_IO_OUT     Data can be written (without blocking).
 
684
           G_IO_PRI     There is urgent data to read.
 
685
           G_IO_ERR     Error condition.
 
686
           G_IO_HUP     Hung up (the connection has been broken, usually for pipes and sockets).
 
687
           G_IO_NVAL    Invalid request. The file descriptor is not open.
 
688
         */
 
689
        crm_err("Strange condition: %d", condition);
 
690
    }
 
691
 
 
692
    /* keep == FALSE results in mainloop_gio_destroy() being called
 
693
     * just before the source is removed from mainloop
 
694
     */
 
695
    return keep;
 
696
}
 
697
 
 
698
static void
 
699
mainloop_gio_destroy(gpointer c)
 
700
{
 
701
    mainloop_io_t *client = c;
 
702
    char *c_name = strdup(client->name);
 
703
 
 
704
    /* client->source is valid but about to be destroyed (ref_count == 0) in gmain.c
 
705
     * client->channel will still have ref_count > 0... should be == 1
 
706
     */
 
707
    crm_trace("Destroying client %s[%p]", c_name, c);
 
708
 
 
709
    if (client->ipc) {
 
710
        crm_ipc_close(client->ipc);
 
711
    }
 
712
 
 
713
    if (client->destroy_fn) {
 
714
        void (*destroy_fn) (gpointer userdata) = client->destroy_fn;
 
715
 
 
716
        client->destroy_fn = NULL;
 
717
        destroy_fn(client->userdata);
 
718
    }
 
719
 
 
720
    if (client->ipc) {
 
721
        crm_ipc_t *ipc = client->ipc;
 
722
 
 
723
        client->ipc = NULL;
 
724
        crm_ipc_destroy(ipc);
 
725
    }
 
726
 
 
727
    crm_trace("Destroyed client %s[%p]", c_name, c);
 
728
 
 
729
    free(client->name); client->name = NULL;
 
730
    free(client);
 
731
 
 
732
    free(c_name);
 
733
}
 
734
 
 
735
mainloop_io_t *
 
736
mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata,
 
737
                        struct ipc_client_callbacks *callbacks)
 
738
{
 
739
    mainloop_io_t *client = NULL;
 
740
    crm_ipc_t *conn = crm_ipc_new(name, max_size);
 
741
 
 
742
    if (conn && crm_ipc_connect(conn)) {
 
743
        int32_t fd = crm_ipc_get_fd(conn);
 
744
 
 
745
        client = mainloop_add_fd(name, priority, fd, userdata, NULL);
 
746
        client->ipc = conn;
 
747
        client->destroy_fn = callbacks->destroy;
 
748
        client->dispatch_fn_ipc = callbacks->dispatch;
 
749
    }
 
750
 
 
751
    if (conn && client == NULL) {
 
752
        crm_trace("Connection to %s failed", name);
 
753
        crm_ipc_close(conn);
 
754
        crm_ipc_destroy(conn);
 
755
    }
 
756
 
 
757
    return client;
 
758
}
 
759
 
 
760
void
 
761
mainloop_del_ipc_client(mainloop_io_t * client)
 
762
{
 
763
    mainloop_del_fd(client);
 
764
}
 
765
 
 
766
crm_ipc_t *
 
767
mainloop_get_ipc_client(mainloop_io_t * client)
 
768
{
 
769
    if (client) {
 
770
        return client->ipc;
 
771
    }
 
772
    return NULL;
 
773
}
 
774
 
 
775
mainloop_io_t *
 
776
mainloop_add_fd(const char *name, int priority, int fd, void *userdata,
 
777
                struct mainloop_fd_callbacks * callbacks)
 
778
{
 
779
    mainloop_io_t *client = NULL;
 
780
 
 
781
    if (fd > 0) {
 
782
        client = calloc(1, sizeof(mainloop_io_t));
 
783
        client->name = strdup(name);
 
784
        client->userdata = userdata;
 
785
 
 
786
        if (callbacks) {
 
787
            client->destroy_fn = callbacks->destroy;
 
788
            client->dispatch_fn_io = callbacks->dispatch;
 
789
        }
 
790
 
 
791
        client->fd = fd;
 
792
        client->channel = g_io_channel_unix_new(fd);
 
793
        client->source =
 
794
            g_io_add_watch_full(client->channel, priority,
 
795
                                (G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR), mainloop_gio_callback,
 
796
                                client, mainloop_gio_destroy);
 
797
 
 
798
        /* Now that mainloop now holds a reference to channel,
 
799
         * thanks to g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
 
800
         *
 
801
         * This means that channel will be free'd by:
 
802
         * g_main_context_dispatch() or g_source_remove()
 
803
         *  -> g_source_destroy_internal()
 
804
         *      -> g_source_callback_unref()
 
805
         * shortly after mainloop_gio_destroy() completes
 
806
         */
 
807
        g_io_channel_unref(client->channel);
 
808
        crm_trace("Added connection %d for %s[%p].%d", client->source, client->name, client, fd);
 
809
    }
 
810
 
 
811
    return client;
 
812
}
 
813
 
 
814
void
 
815
mainloop_del_fd(mainloop_io_t * client)
 
816
{
 
817
    if (client != NULL) {
 
818
        crm_trace("Removing client %s[%p]", client->name, client);
 
819
        if (client->source) {
 
820
            /* Results in mainloop_gio_destroy() being called just
 
821
             * before the source is removed from mainloop
 
822
             */
 
823
            g_source_remove(client->source);
 
824
        }
 
825
    }
 
826
}
 
827
 
 
828
pid_t
 
829
mainloop_child_pid(mainloop_child_t * child)
 
830
{
 
831
    return child->pid;
 
832
}
 
833
 
 
834
const char *
 
835
mainloop_child_name(mainloop_child_t * child)
 
836
{
 
837
    return child->desc;
 
838
}
 
839
 
 
840
int
 
841
mainloop_child_timeout(mainloop_child_t * child)
 
842
{
 
843
    return child->timeout;
 
844
}
 
845
 
 
846
void *
 
847
mainloop_child_userdata(mainloop_child_t * child)
 
848
{
 
849
    return child->privatedata;
 
850
}
 
851
 
 
852
void
 
853
mainloop_clear_child_userdata(mainloop_child_t * child)
 
854
{
 
855
    child->privatedata = NULL;
 
856
}
 
857
 
 
858
static gboolean
 
859
child_timeout_callback(gpointer p)
 
860
{
 
861
    mainloop_child_t *child = p;
 
862
 
 
863
    child->timerid = 0;
 
864
    if (child->timeout) {
 
865
        crm_crit("%s process (PID %d) will not die!", child->desc, (int)child->pid);
 
866
        return FALSE;
 
867
    }
 
868
 
 
869
    child->timeout = TRUE;
 
870
    crm_warn("%s process (PID %d) timed out", child->desc, (int)child->pid);
 
871
 
 
872
    if (kill(child->pid, SIGKILL) < 0) {
 
873
        if (errno == ESRCH) {
 
874
            /* Nothing left to do */
 
875
            return FALSE;
 
876
        }
 
877
        crm_perror(LOG_ERR, "kill(%d, KILL) failed", child->pid);
 
878
    }
 
879
 
 
880
    child->timerid = g_timeout_add(5000, child_timeout_callback, child);
 
881
    return FALSE;
 
882
}
 
883
 
 
884
static GListPtr child_list = NULL;
 
885
 
 
886
static void
 
887
child_death_dispatch(int signal)
 
888
{
 
889
    GListPtr iter = child_list;
 
890
 
 
891
    while(iter) {
 
892
        int rc = 0;
 
893
        int core = 0;
 
894
        int signo = 0;
 
895
        int status = 0;
 
896
        int exitcode = 0;
 
897
 
 
898
        GListPtr saved = NULL;
 
899
        mainloop_child_t *child = iter->data;
 
900
 
 
901
        rc = waitpid(child->pid, &status, WNOHANG);
 
902
        if(rc == 0) {
 
903
            iter = iter->next;
 
904
            continue;
 
905
 
 
906
        } else if(rc != child->pid) {
 
907
            signo = signal;
 
908
            exitcode = 1;
 
909
            status = 1;
 
910
            crm_perror(LOG_ERR, "Call to waitpid(%d) failed", child->pid);
 
911
 
 
912
        } else {
 
913
            crm_trace("Managed process %d exited: %p", child->pid, child);
 
914
 
 
915
            if (WIFEXITED(status)) {
 
916
                exitcode = WEXITSTATUS(status);
 
917
                crm_trace("Managed process %d (%s) exited with rc=%d", child->pid, child->desc, exitcode);
 
918
 
 
919
            } else if (WIFSIGNALED(status)) {
 
920
                signo = WTERMSIG(status);
 
921
                crm_trace("Managed process %d (%s) exited with signal=%d", child->pid, child->desc, signo);
 
922
            }
 
923
#ifdef WCOREDUMP
 
924
            if (WCOREDUMP(status)) {
 
925
                core = 1;
 
926
                crm_err("Managed process %d (%s) dumped core", child->pid, child->desc);
 
927
            }
 
928
#endif
 
929
        }
 
930
 
 
931
        if (child->callback) {
 
932
            child->callback(child, child->pid, core, signo, exitcode);
 
933
        }
 
934
 
 
935
        crm_trace("Removing process entry %p for %d", child, child->pid);
 
936
 
 
937
        saved = iter;
 
938
        iter = iter->next;
 
939
 
 
940
        child_list = g_list_remove_link(child_list, saved);
 
941
        g_list_free(saved);
 
942
 
 
943
        if (child->timerid != 0) {
 
944
            crm_trace("Removing timer %d", child->timerid);
 
945
            g_source_remove(child->timerid);
 
946
            child->timerid = 0;
 
947
        }
 
948
        free(child->desc);
 
949
        free(child);
 
950
    }
 
951
}
 
952
 
 
953
/* Create/Log a new tracked process
 
954
 * To track a process group, use -pid
 
955
 */
 
956
void
 
957
mainloop_child_add(pid_t pid, int timeout, const char *desc, void *privatedata,
 
958
                   void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode))
 
959
{
 
960
    static bool need_init = TRUE;
 
961
    mainloop_child_t *child = g_new(mainloop_child_t, 1);
 
962
 
 
963
    child->pid = pid;
 
964
    child->timerid = 0;
 
965
    child->timeout = FALSE;
 
966
    child->privatedata = privatedata;
 
967
    child->callback = callback;
 
968
 
 
969
    if(desc) {
 
970
        child->desc = strdup(desc);
 
971
    }
 
972
 
 
973
    if (timeout) {
 
974
        child->timerid = g_timeout_add(timeout, child_timeout_callback, child);
 
975
    }
 
976
 
 
977
    child_list = g_list_append(child_list, child);
 
978
 
 
979
    if(need_init) {
 
980
        need_init = FALSE;
 
981
 
 
982
        /* Do NOT use g_child_watch_add() and friends, they rely on pthreads */
 
983
        mainloop_add_signal(SIGCHLD, child_death_dispatch);
 
984
 
 
985
        /* In case they terminated before the signal handler was installed */
 
986
        child_death_dispatch(SIGCHLD);
 
987
    }
 
988
}