1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* $Id: task.h,v 1.8 2020/02/25 05:00:43 jsg Exp $ */ 18 19 #ifndef ISC_TASK_H 20 #define ISC_TASK_H 1 21 22 /***** 23 ***** Module Info 24 *****/ 25 26 /*! \file isc/task.h 27 * \brief The task system provides a lightweight execution context, which is 28 * basically an event queue. 29 30 * When a task's event queue is non-empty, the 31 * task is runnable. A small work crew of threads, typically one per CPU, 32 * execute runnable tasks by dispatching the events on the tasks' event 33 * queues. Context switching between tasks is fast. 34 * 35 * \li MP: 36 * The module ensures appropriate synchronization of data structures it 37 * creates and manipulates. 38 * The caller must ensure that isc_taskmgr_destroy() is called only 39 * once for a given manager. 40 * 41 * \li Reliability: 42 * No anticipated impact. 43 * 44 * \li Resources: 45 * TBS 46 * 47 * \li Security: 48 * No anticipated impact. 49 * 50 * \li Standards: 51 * None. 52 * 53 * \section purge Purging and Unsending 54 * 55 * Events which have been queued for a task but not delivered may be removed 56 * from the task's event queue by purging or unsending. 57 * 58 * With both types, the caller specifies a matching pattern that selects 59 * events based upon their sender, type, and tag. 60 * 61 * Purging calls isc_event_free() on the matching events. 62 * 63 * Unsending returns a list of events that matched the pattern. 64 * The caller is then responsible for them. 65 * 66 * Consumers of events should purge, not unsend. 67 * 68 * Producers of events often want to remove events when the caller indicates 69 * it is no longer interested in the object, e.g. by canceling a timer. 70 * Sometimes this can be done by purging, but for some event types, the 71 * calls to isc_event_free() cause deadlock because the event free routine 72 * wants to acquire a lock the caller is already holding. Unsending instead 73 * of purging solves this problem. As a general rule, producers should only 74 * unsend events which they have sent. 75 */ 76 77 /*** 78 *** Imports. 79 ***/ 80 81 #include <isc/eventclass.h> 82 #include <isc/types.h> 83 84 #define ISC_TASKEVENT_FIRSTEVENT (ISC_EVENTCLASS_TASK + 0) 85 #define ISC_TASKEVENT_SHUTDOWN (ISC_EVENTCLASS_TASK + 1) 86 #define ISC_TASKEVENT_TEST (ISC_EVENTCLASS_TASK + 1) 87 #define ISC_TASKEVENT_LASTEVENT (ISC_EVENTCLASS_TASK + 65535) 88 89 /***** 90 ***** Tasks. 91 *****/ 92 93 /*** 94 *** Types 95 ***/ 96 97 typedef enum { 98 isc_taskmgrmode_normal = 0, 99 isc_taskmgrmode_privileged 100 } isc_taskmgrmode_t; 101 102 isc_result_t 103 isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, 104 isc_task_t **taskp); 105 /*%< 106 * Create a task. 107 * 108 * Notes: 109 * 110 *\li If 'quantum' is non-zero, then only that many events can be dispatched 111 * before the task must yield to other tasks waiting to execute. If 112 * quantum is zero, then the default quantum of the task manager will 113 * be used. 114 * 115 *\li The 'quantum' option may be removed from isc_task_create() in the 116 * future. If this happens, isc_task_getquantum() and 117 * isc_task_setquantum() will be provided. 118 * 119 * Requires: 120 * 121 *\li 'manager' is a valid task manager. 122 * 123 *\li taskp != NULL && *taskp == NULL 124 * 125 * Ensures: 126 * 127 *\li On success, '*taskp' is bound to the new task. 128 * 129 * Returns: 130 * 131 *\li #ISC_R_SUCCESS 132 *\li #ISC_R_NOMEMORY 133 *\li #ISC_R_UNEXPECTED 134 *\li #ISC_R_SHUTTINGDOWN 135 */ 136 137 void 138 isc_task_attach(isc_task_t *source, isc_task_t **targetp); 139 /*%< 140 * Attach *targetp to source. 141 * 142 * Requires: 143 * 144 *\li 'source' is a valid task. 145 * 146 *\li 'targetp' points to a NULL isc_task_t *. 147 * 148 * Ensures: 149 * 150 *\li *targetp is attached to source. 151 */ 152 153 void 154 isc_task_detach(isc_task_t **taskp); 155 /*%< 156 * Detach *taskp from its task. 157 * 158 * Requires: 159 * 160 *\li '*taskp' is a valid task. 161 * 162 * Ensures: 163 * 164 *\li *taskp is NULL. 165 * 166 *\li If '*taskp' is the last reference to the task, the task is idle (has 167 * an empty event queue), and has not been shutdown, the task will be 168 * shutdown. 169 * 170 *\li If '*taskp' is the last reference to the task and 171 * the task has been shutdown, 172 * all resources used by the task will be freed. 173 */ 174 175 void 176 isc_task_send(isc_task_t *task, isc_event_t **eventp); 177 /*%< 178 * Send '*event' to 'task'. 179 * 180 * Requires: 181 * 182 *\li 'task' is a valid task. 183 *\li eventp != NULL && *eventp != NULL. 184 * 185 * Ensures: 186 * 187 *\li *eventp == NULL. 188 */ 189 190 void 191 isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp); 192 /*%< 193 * Send '*event' to '*taskp' and then detach '*taskp' from its 194 * task. 195 * 196 * Requires: 197 * 198 *\li '*taskp' is a valid task. 199 *\li eventp != NULL && *eventp != NULL. 200 * 201 * Ensures: 202 * 203 *\li *eventp == NULL. 204 * 205 *\li *taskp == NULL. 206 * 207 *\li If '*taskp' is the last reference to the task, the task is 208 * idle (has an empty event queue), and has not been shutdown, 209 * the task will be shutdown. 210 * 211 *\li If '*taskp' is the last reference to the task and 212 * the task has been shutdown, 213 * all resources used by the task will be freed. 214 */ 215 216 unsigned int 217 isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first, 218 isc_eventtype_t last, void *tag); 219 /*%< 220 * Purge events from a task's event queue. 221 * 222 * Requires: 223 * 224 *\li 'task' is a valid task. 225 * 226 *\li last >= first 227 * 228 * Ensures: 229 * 230 *\li Events in the event queue of 'task' whose sender is 'sender', whose 231 * type is >= first and <= last, and whose tag is 'tag' will be purged, 232 * unless they are marked as unpurgable. 233 * 234 *\li A sender of NULL will match any sender. A NULL tag matches any 235 * tag. 236 * 237 * Returns: 238 * 239 *\li The number of events purged. 240 */ 241 242 void 243 isc_task_setname(isc_task_t *task, const char *name, void *tag); 244 /*%< 245 * Name 'task'. 246 * 247 * Notes: 248 * 249 *\li Only the first 15 characters of 'name' will be copied. 250 * 251 *\li Naming a task is currently only useful for debugging purposes. 252 * 253 * Requires: 254 * 255 *\li 'task' is a valid task. 256 */ 257 258 /***** 259 ***** Task Manager. 260 *****/ 261 262 isc_result_t 263 isc_taskmgr_create(unsigned int workers, 264 unsigned int default_quantum, isc_taskmgr_t **managerp); 265 /*%< 266 * Create a new task manager. isc_taskmgr_createinctx() also associates 267 * the new manager with the specified application context. 268 * 269 * Notes: 270 * 271 *\li 'workers' in the number of worker threads to create. In general, 272 * the value should be close to the number of processors in the system. 273 * The 'workers' value is advisory only. An attempt will be made to 274 * create 'workers' threads, but if at least one thread creation 275 * succeeds, isc_taskmgr_create() may return ISC_R_SUCCESS. 276 * 277 *\li If 'default_quantum' is non-zero, then it will be used as the default 278 * quantum value when tasks are created. If zero, then an implementation 279 * defined default quantum will be used. 280 * 281 * Requires: 282 * 283 *\li 'mctx' is a valid memory context. 284 * 285 *\li workers > 0 286 * 287 *\li managerp != NULL && *managerp == NULL 288 * 289 *\li 'actx' is a valid application context (for createinctx()). 290 * 291 * Ensures: 292 * 293 *\li On success, '*managerp' will be attached to the newly created task 294 * manager. 295 * 296 * Returns: 297 * 298 *\li #ISC_R_SUCCESS 299 *\li #ISC_R_NOMEMORY 300 *\li #ISC_R_NOTHREADS No threads could be created. 301 *\li #ISC_R_UNEXPECTED An unexpected error occurred. 302 *\li #ISC_R_SHUTTINGDOWN The non-threaded, shared, task 303 * manager shutting down. 304 */ 305 306 void 307 isc_taskmgr_destroy(isc_taskmgr_t **managerp); 308 /*%< 309 * Destroy '*managerp'. 310 * 311 * Notes: 312 * 313 *\li Calling isc_taskmgr_destroy() will shutdown all tasks managed by 314 * *managerp that haven't already been shutdown. The call will block 315 * until all tasks have entered the done state. 316 * 317 *\li isc_taskmgr_destroy() must not be called by a task event action, 318 * because it would block forever waiting for the event action to 319 * complete. An event action that wants to cause task manager shutdown 320 * should request some non-event action thread of execution to do the 321 * shutdown, e.g. by signaling a condition variable or using 322 * isc_app_shutdown(). 323 * 324 *\li Task manager references are not reference counted, so the caller 325 * must ensure that no attempt will be made to use the manager after 326 * isc_taskmgr_destroy() returns. 327 * 328 * Requires: 329 * 330 *\li '*managerp' is a valid task manager. 331 * 332 *\li isc_taskmgr_destroy() has not be called previously on '*managerp'. 333 * 334 * Ensures: 335 * 336 *\li All resources used by the task manager, and any tasks it managed, 337 * have been freed. 338 */ 339 340 /*%< 341 * See isc_taskmgr_create() above. 342 */ 343 typedef isc_result_t 344 (*isc_taskmgrcreatefunc_t)(unsigned int workers, 345 unsigned int default_quantum, 346 isc_taskmgr_t **managerp); 347 348 #endif /* ISC_TASK_H */ 349