1 /* 2 * Copyright (C) 2010-2020 Red Hat, Inc. 3 * 4 * Author: Angus Salkeld <asalkeld@redhat.com> 5 * 6 * This file is part of libqb. 7 * 8 * libqb is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 2.1 of the License, or 11 * (at your option) any later version. 12 * 13 * libqb is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with libqb. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 #ifndef QB_LOOP_H_DEFINED 22 #define QB_LOOP_H_DEFINED 23 24 /* *INDENT-OFF* */ 25 #ifdef __cplusplus 26 extern "C" { 27 #endif 28 /* *INDENT-ON* */ 29 30 #include <signal.h> 31 #include <stdint.h> 32 #include <poll.h> /* make POLLIN etc. readily available */ 33 34 /** 35 * @file qbloop.h 36 * 37 * Main loop manages timers, jobs and polling sockets. 38 * 39 * Only a weaker sense of priorities is implemented, alluding to distinct 40 * set of pros and cons compared to the stronger, strict approach to them 41 * as widely applied in this problem space (since the latter gives the 42 * application more control as the effect of the former can still be 43 * achieved with some reductions, whereas it is not straightforward the 44 * other way around; cf. static priority task scheduling vs. relative 45 * fine-tuning within a single priority domain with nice(2)): 46 * 47 * + implicit mitigation for deadlock-prone priority arrangements 48 * 49 * - less predictable (proportional probability based, we can talk 50 * about an advisory effect of the priorities) responses to the arrival 51 * of the high-ranked events (i.e. in the process of the picking the next 52 * event to handle from the priority queue when at least two different 53 * priorities are eligible at the moment) 54 * 55 * One practical application for this module of libqb is in combination with 56 * IPC servers based on qbipcs.h published one (the #qb_ipcs_poll_handlers 57 * structure maps fittingly to the control functions published here). 58 * 59 * @example tcpserver.c 60 */ 61 62 63 /** 64 * Priorites for jobs, timers & poll 65 */ 66 enum qb_loop_priority { 67 QB_LOOP_LOW = 0, 68 QB_LOOP_MED = 1, 69 QB_LOOP_HIGH = 2, 70 }; 71 72 /** 73 * An opaque data type representing the main loop. 74 */ 75 typedef struct qb_loop qb_loop_t; 76 77 typedef uint64_t qb_loop_timer_handle; 78 79 typedef void *qb_loop_signal_handle; 80 81 typedef int32_t (*qb_loop_poll_dispatch_fn) (int32_t fd, int32_t revents, void *data); 82 typedef void (*qb_loop_job_dispatch_fn)(void *data); 83 typedef void (*qb_loop_timer_dispatch_fn)(void *data); 84 typedef int32_t (*qb_loop_signal_dispatch_fn)(int32_t rsignal, void *data); 85 86 typedef void (*qb_loop_poll_low_fds_event_fn) (int32_t not_enough, int32_t fds_available); 87 88 /** 89 * Create a new main loop. 90 * 91 * @return loop instance. 92 */ 93 qb_loop_t * qb_loop_create(void); 94 95 /** 96 * 97 */ 98 void qb_loop_destroy(struct qb_loop * l); 99 100 /** 101 * Stop the main loop. 102 * @param l pointer to the loop instance 103 */ 104 void qb_loop_stop(qb_loop_t *l); 105 106 /** 107 * Run the main loop. 108 * 109 * @param l pointer to the loop instance 110 */ 111 void qb_loop_run(qb_loop_t *l); 112 113 114 /** 115 * Add a job to the mainloop. 116 * 117 * This is run in the next cycle of the loop. 118 * @note it is a one-shot job. 119 * 120 * @param l pointer to the loop instance 121 * @param p the priority 122 * @param data user data passed into the dispatch function 123 * @param dispatch_fn callback function 124 * @return status (0 == ok, -errno == failure) 125 */ 126 int32_t qb_loop_job_add(qb_loop_t *l, 127 enum qb_loop_priority p, 128 void *data, 129 qb_loop_job_dispatch_fn dispatch_fn); 130 131 132 /** 133 * Delete a job from the mainloop. 134 * 135 * This will try to delete the job if it hasn't run yet. 136 * 137 * @note this will remove the first job that matches the 138 * parameters (priority, data, dispatch_fn). 139 * 140 * @param l pointer to the loop instance 141 * @param p the priority 142 * @param data user data passed into the dispatch function 143 * @param dispatch_fn callback function 144 * @return status (0 == ok, -errno == failure) 145 */ 146 int32_t qb_loop_job_del(struct qb_loop *l, 147 enum qb_loop_priority p, 148 void *data, 149 qb_loop_job_dispatch_fn dispatch_fn); 150 151 /** 152 * Add a timer to the mainloop. 153 * @note it is a one-shot job. 154 * 155 * @param l pointer to the loop instance 156 * @param p the priority 157 * @param nsec_duration nano-secs in the future to run the dispatch. 158 * @param data user data passed into the dispatch function 159 * @param dispatch_fn callback function 160 * @param timer_handle_out handle to delete the timer if needed. 161 * @return status (0 == ok, -errno == failure) 162 */ 163 int32_t qb_loop_timer_add(qb_loop_t *l, 164 enum qb_loop_priority p, 165 uint64_t nsec_duration, 166 void *data, 167 qb_loop_timer_dispatch_fn dispatch_fn, 168 qb_loop_timer_handle * timer_handle_out); 169 170 /** 171 * Delete a timer that is still outstanding. 172 * 173 * @param l pointer to the loop instance 174 * @param th handle to delete the timer if needed. 175 * @return status (0 == ok, -errno == failure) 176 */ 177 int32_t qb_loop_timer_del(qb_loop_t *l, qb_loop_timer_handle th); 178 179 /** 180 * Check to see if a timer that is still outstanding. 181 * 182 * @param l pointer to the loop instance 183 * @param th handle to delete the timer if needed. 184 * @retval QB_TRUE yes this timer is outstanding 185 * @retval QB_FALSE this timer does not exist or has expired 186 */ 187 int32_t qb_loop_timer_is_running(qb_loop_t *l, qb_loop_timer_handle th); 188 189 /** 190 * Get the expiration time of the timer, as set when the timer was created 191 * 192 * @note if the timer has already expired it will return 0 193 * 194 * @param l pointer to the loop instance 195 * @param th timer handle. 196 * @return nano seconds at which the timer will expire 197 */ 198 uint64_t qb_loop_timer_expire_time_get(struct qb_loop *l, qb_loop_timer_handle th); 199 200 /** 201 * Get the time remaining before the timer expires 202 * 203 * @note if the timer has already expired it will return 0 204 * 205 * @param l pointer to the loop instance 206 * @param th timer handle. 207 * @return nano seconds remaining until the timer expires 208 */ 209 uint64_t qb_loop_timer_expire_time_remaining(struct qb_loop *l, qb_loop_timer_handle th); 210 211 /** 212 * Set a callback to receive events on file descriptors 213 * getting low. 214 * @param l pointer to the loop instance 215 * @param fn callback function. 216 * @return status (0 == ok, -errno == failure) 217 */ 218 int32_t qb_loop_poll_low_fds_event_set(qb_loop_t *l, 219 qb_loop_poll_low_fds_event_fn fn); 220 221 /** 222 * Add a poll job to the mainloop. 223 * @note it is a re-occurring job. 224 * 225 * @param l pointer to the loop instance 226 * @param p the priority 227 * @param fd file descriptor. 228 * @param events (POLLIN|POLLOUT) etc .... 229 * @param data user data passed into the dispatch function 230 * @param dispatch_fn callback function 231 * @return status (0 == ok, -errno == failure) 232 */ 233 int32_t qb_loop_poll_add(qb_loop_t *l, 234 enum qb_loop_priority p, 235 int32_t fd, 236 int32_t events, 237 void *data, 238 qb_loop_poll_dispatch_fn dispatch_fn); 239 240 /** 241 * Modify a poll job. 242 * 243 * @param l pointer to the loop instance 244 * @param p the priority 245 * @param fd file descriptor. 246 * @param events (POLLIN|POLLOUT) etc .... 247 * @param data user data passed into the dispatch function 248 * @param dispatch_fn callback function 249 * @return status (0 == ok, -errno == failure) 250 */ 251 int32_t qb_loop_poll_mod(qb_loop_t *l, 252 enum qb_loop_priority p, 253 int32_t fd, 254 int32_t events, 255 void *data, 256 qb_loop_poll_dispatch_fn dispatch_fn); 257 258 /** 259 * Delete a poll job. 260 * 261 * @param l pointer to the loop instance 262 * @param fd file descriptor. 263 * @return status (0 == ok, -errno == failure) 264 */ 265 int32_t qb_loop_poll_del(qb_loop_t *l, int32_t fd); 266 267 /** 268 * Add a signal job. 269 * 270 * Get a callback on this signal (not in the context of the signal). 271 * 272 * @param l pointer to the loop instance 273 * @param p the priority 274 * @param sig (SIGHUP or SIGINT) etc .... 275 * @param data user data passed into the dispatch function 276 * @param dispatch_fn callback function 277 * @param handle (out) a reference to the signal job 278 * @return status (0 == ok, -errno == failure) 279 */ 280 int32_t qb_loop_signal_add(qb_loop_t *l, 281 enum qb_loop_priority p, 282 int32_t sig, 283 void *data, 284 qb_loop_signal_dispatch_fn dispatch_fn, 285 qb_loop_signal_handle *handle); 286 287 /** 288 * Modify the signal job 289 * 290 * @param l pointer to the loop instance 291 * @param p the priority 292 * @param sig (SIGHUP or SIGINT) etc .... 293 * @param data user data passed into the dispatch function 294 * @param dispatch_fn callback function 295 * @param handle (in) a reference to the signal job 296 * @return status (0 == ok, -errno == failure) 297 */ 298 int32_t qb_loop_signal_mod(qb_loop_t *l, 299 enum qb_loop_priority p, 300 int32_t sig, 301 void *data, 302 qb_loop_signal_dispatch_fn dispatch_fn, 303 qb_loop_signal_handle handle); 304 305 /** 306 * Delete the signal job. 307 * 308 * @param l pointer to the loop instance 309 * @param handle (in) a reference to the signal job 310 * @return status (0 == ok, -errno == failure) 311 */ 312 int32_t qb_loop_signal_del(qb_loop_t *l, 313 qb_loop_signal_handle handle); 314 315 /* *INDENT-OFF* */ 316 #ifdef __cplusplus 317 } 318 #endif /* __cplusplus */ 319 /* *INDENT-ON* */ 320 #endif /* QB_LOOP_H_DEFINED */ 321 322