summaryrefslogtreecommitdiffstats
path: root/include/crm/common/mainloop.h
blob: a55bcdf41138585092aabb942eef785d11421218 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
 * Copyright 2009-2022 the Pacemaker project contributors
 *
 * The version control history for this file may have further details.
 *
 * This source code is licensed under the GNU Lesser General Public License
 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
 */

#ifndef PCMK__CRM_COMMON_MAINLOOP__H
#  define PCMK__CRM_COMMON_MAINLOOP__H

#  include <signal.h> // sighandler_t
#  include <glib.h>
#  include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * \file
 * \brief Wrappers for and extensions to glib mainloop
 * \ingroup core
 */

enum mainloop_child_flags {
    /* don't kill pid group on timeout, only kill the pid */
    mainloop_leave_pid_group = 0x01,
};

typedef struct trigger_s crm_trigger_t;
typedef struct mainloop_io_s mainloop_io_t;
typedef struct mainloop_child_s mainloop_child_t;
typedef struct mainloop_timer_s mainloop_timer_t;

void mainloop_cleanup(void);

crm_trigger_t *mainloop_add_trigger(int priority, int (*dispatch) (gpointer user_data),
                                    gpointer userdata);

void mainloop_set_trigger(crm_trigger_t * source);

void mainloop_trigger_complete(crm_trigger_t * trig);

gboolean mainloop_destroy_trigger(crm_trigger_t * source);

#  ifndef HAVE_SIGHANDLER_T
typedef void (*sighandler_t)(int);
#  endif

sighandler_t crm_signal_handler(int sig, sighandler_t dispatch);

gboolean mainloop_add_signal(int sig, void (*dispatch) (int sig));

gboolean mainloop_destroy_signal(int sig);

bool mainloop_timer_running(mainloop_timer_t *t);

void mainloop_timer_start(mainloop_timer_t *t);

void mainloop_timer_stop(mainloop_timer_t *t);

guint mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms);

mainloop_timer_t *mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata);

void mainloop_timer_del(mainloop_timer_t *t);


#  include <crm/common/ipc.h>
#  include <qb/qbipcs.h>

struct ipc_client_callbacks {
    /*!
     * \brief Dispatch function for an IPC connection used as mainloop source
     *
     * \param[in] buffer    Message read from IPC connection
     * \param[in] length    Number of bytes in \p buffer
     * \param[in] userdata  User data passed when creating mainloop source
     *
     * \return Negative value to remove source, anything else to keep it
     */
    int (*dispatch) (const char *buffer, ssize_t length, gpointer userdata);

    /*!
     * \brief Destroy function for mainloop IPC connection client data
     *
     * \param[in,out] userdata  User data passed when creating mainloop source
     */
    void (*destroy) (gpointer userdata);
};

qb_ipcs_service_t *mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
                                           struct qb_ipcs_service_handlers *callbacks);

/*!
 * \brief Start server-side API end-point, hooked into the internal event loop
 *
 * \param[in] name    name of the IPC end-point ("address" for the client)
 * \param[in] type    selects libqb's IPC back-end (or use #QB_IPC_NATIVE)
 * \param[in] callbacks  defines libqb's IPC service-level handlers
 * \param[in] priority  priority relative to other events handled in the
 *                      abstract handling loop, use #QB_LOOP_MED when unsure
 *
 * \return libqb's opaque handle to the created service abstraction
 *
 * \note For portability concerns, do not use this function if you keep
 *       \p priority as #QB_LOOP_MED, stick with #mainloop_add_ipc_server
 *       (with exactly such semantics) instead (once you link with this new
 *       symbol employed, you can't downgrade the library freely anymore).
 *
 * \note The intended effect will only get fully reflected when run-time
 *       linked to patched libqb: https://github.com/ClusterLabs/libqb/pull/352
 */
qb_ipcs_service_t *mainloop_add_ipc_server_with_prio(const char *name,
                                                    enum qb_ipc_type type,
                                                    struct qb_ipcs_service_handlers *callbacks,
                                                    enum qb_loop_priority prio);

void mainloop_del_ipc_server(qb_ipcs_service_t * server);

mainloop_io_t *mainloop_add_ipc_client(const char *name, int priority, size_t max_size,
                                       void *userdata, struct ipc_client_callbacks *callbacks);

void mainloop_del_ipc_client(mainloop_io_t * client);

crm_ipc_t *mainloop_get_ipc_client(mainloop_io_t * client);

struct mainloop_fd_callbacks {
    /*!
     * \brief Dispatch function for mainloop file descriptor with data ready
     *
     * \param[in,out] userdata  User data passed when creating mainloop source
     *
     * \return Negative value to remove source, anything else to keep it
     */
    int (*dispatch) (gpointer userdata);

    /*!
     * \brief Destroy function for mainloop file descriptor client data
     *
     * \param[in,out] userdata  User data passed when creating mainloop source
     */
    void (*destroy) (gpointer userdata);
};

mainloop_io_t *mainloop_add_fd(const char *name, int priority, int fd, void *userdata,
                               struct mainloop_fd_callbacks *callbacks);

void mainloop_del_fd(mainloop_io_t * client);

/*
 * Create a new tracked process
 * To track a process group, use -pid
 */
void mainloop_child_add(pid_t pid,
                        int timeout,
                        const char *desc,
                        void *userdata,
                        void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode));

void mainloop_child_add_with_flags(pid_t pid,
                        int timeout,
                        const char *desc,
                        void *userdata,
                        enum mainloop_child_flags,
                        void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode));

void *mainloop_child_userdata(mainloop_child_t * child);
int mainloop_child_timeout(mainloop_child_t * child);
const char *mainloop_child_name(mainloop_child_t * child);

pid_t mainloop_child_pid(mainloop_child_t * child);
void mainloop_clear_child_userdata(mainloop_child_t * child);
gboolean mainloop_child_kill(pid_t pid);

void pcmk_quit_main_loop(GMainLoop *mloop, unsigned int n);
void pcmk_drain_main_loop(GMainLoop *mloop, guint timer_ms,
                          bool (*check)(guint));

#  define G_PRIORITY_MEDIUM (G_PRIORITY_HIGH/2)

#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
#include <crm/common/mainloop_compat.h>
#endif

#ifdef __cplusplus
}
#endif

#endif