1 /* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25 /** \defgroup threadpool Threadpool related functions 26 * ##Threadpool 27 * \ingroup lwsapi 28 * 29 * This allows you to create one or more pool of threads which can run tasks 30 * associated with a wsi. If the pool is busy, tasks wait on a queue. 31 * 32 * Tasks don't have to be atomic, if they will take more than a few tens of ms 33 * they should return back to the threadpool worker with a return of 0. This 34 * will allow them to abort cleanly. 35 */ 36 //@{ 37 38 struct lws_threadpool; 39 struct lws_threadpool_task; 40 41 enum lws_threadpool_task_status { 42 LWS_TP_STATUS_QUEUED, 43 LWS_TP_STATUS_RUNNING, 44 LWS_TP_STATUS_SYNCING, 45 LWS_TP_STATUS_STOPPING, 46 LWS_TP_STATUS_FINISHED, /* lws_threadpool_task_status() frees task */ 47 LWS_TP_STATUS_STOPPED, /* lws_threadpool_task_status() frees task */ 48 }; 49 50 enum lws_threadpool_task_return { 51 /** Still work to do, just confirming not being stopped */ 52 LWS_TP_RETURN_CHECKING_IN, 53 /** Still work to do, enter cond_wait until service thread syncs. This 54 * is used if you have filled your buffer(s) of data to the service 55 * thread and are blocked until the service thread completes sending at 56 * least one. 57 */ 58 LWS_TP_RETURN_SYNC, 59 /** No more work to do... */ 60 LWS_TP_RETURN_FINISHED, 61 /** Responding to request to stop */ 62 LWS_TP_RETURN_STOPPED, 63 64 /* OR on to indicate this task wishes to outlive its wsi */ 65 LWS_TP_RETURN_FLAG_OUTLIVE = 64 66 }; 67 68 struct lws_threadpool_create_args { 69 int threads; 70 int max_queue_depth; 71 }; 72 73 struct lws_threadpool_task_args { 74 struct lws *wsi; /**< user must set to wsi task is bound to */ 75 void *user; /**< user may set (user-private pointer) */ 76 const char *name; /**< user may set to describe task */ 77 char async_task; /**< set to allow the task to shrug off the loss 78 of the associated wsi and continue to 79 completion */ 80 enum lws_threadpool_task_return (*task)(void *user, 81 enum lws_threadpool_task_status s); 82 /**< user must set to actual task function */ 83 void (*cleanup)(struct lws *wsi, void *user); 84 /**< socket lifecycle may end while task is not stoppable, so the task 85 * must be able to detach from any wsi and clean itself up when it does 86 * stop. If NULL, no cleanup necessary, otherwise point to a user- 87 * supplied function that destroys the stuff in \p user. 88 * 89 * wsi may be NULL on entry, indicating the task got detached due to the 90 * wsi closing before. 91 */ 92 }; 93 94 /** 95 * lws_threadpool_create() - create a pool of worker threads 96 * 97 * \param context: the lws_context the threadpool will exist inside 98 * \param args: argument struct prepared by caller 99 * \param format: printf-type format for the task name 100 * \param ...: printf type args for the task name format 101 * 102 * Creates a pool of worker threads with \p threads and a queue of up to 103 * \p max_queue_depth waiting tasks if all the threads are busy. 104 * 105 * Returns NULL if OOM, or a struct lws_threadpool pointer that must be 106 * destroyed by lws_threadpool_destroy(). 107 */ 108 LWS_VISIBLE LWS_EXTERN struct lws_threadpool * 109 lws_threadpool_create(struct lws_context *context, 110 const struct lws_threadpool_create_args *args, 111 const char *format, ...) LWS_FORMAT(3); 112 113 /** 114 * lws_threadpool_finish() - Stop all pending and running tasks 115 * 116 * \param tp: the threadpool object 117 * 118 * Marks the threadpool as under destruction. Removes everything from the 119 * pending queue and completes those tasks as LWS_TP_STATUS_STOPPED. 120 * 121 * Running tasks will also get LWS_TP_STATUS_STOPPED as soon as they 122 * "resurface". 123 * 124 * This doesn't reap tasks or free the threadpool, the reaping is done by the 125 * lws_threadpool_task_status() on the done task. 126 */ 127 LWS_VISIBLE LWS_EXTERN void 128 lws_threadpool_finish(struct lws_threadpool *tp); 129 130 /** 131 * lws_threadpool_destroy() - Destroy a threadpool 132 * 133 * \param tp: the threadpool object 134 * 135 * Waits for all worker threads to stop, ends the threads and frees the tp. 136 */ 137 LWS_VISIBLE LWS_EXTERN void 138 lws_threadpool_destroy(struct lws_threadpool *tp); 139 140 /** 141 * lws_threadpool_enqueue() - Queue the task and run it on a worker thread when possible 142 * 143 * \param tp: the threadpool to queue / run on 144 * \param args: information about what to run 145 * \param format: printf-type format for the task name 146 * \param ...: printf type args for the task name format 147 * 148 * This asks for a task to run ASAP on a worker thread in threadpool \p tp. 149 * 150 * The args defines the wsi, a user-private pointer, a timeout in secs and 151 * a pointer to the task function. 152 * 153 * Returns NULL or an opaque pointer to the queued (or running, or completed) 154 * task. 155 * 156 * Once a task is created and enqueued, it can only be destroyed by calling 157 * lws_threadpool_task_status() on it after it has reached the state 158 * LWS_TP_STATUS_FINISHED or LWS_TP_STATUS_STOPPED. 159 */ 160 LWS_VISIBLE LWS_EXTERN struct lws_threadpool_task * 161 lws_threadpool_enqueue(struct lws_threadpool *tp, 162 const struct lws_threadpool_task_args *args, 163 const char *format, ...) LWS_FORMAT(3); 164 165 /** 166 * lws_threadpool_dequeue() - Dequeue or try to stop a running task 167 * 168 * \param wsi: the wsi whose current task we want to eliminate 169 * 170 * Returns 0 is the task was dequeued or already compeleted, or 1 if the task 171 * has been asked to stop asynchronously. 172 * 173 * This doesn't free the task. It only shortcuts it to state 174 * LWS_TP_STATUS_STOPPED. lws_threadpool_task_status() must be performed on 175 * the task separately once it is in LWS_TP_STATUS_STOPPED to free the task. 176 */ 177 LWS_VISIBLE LWS_EXTERN int 178 lws_threadpool_dequeue(struct lws *wsi); 179 180 /** 181 * lws_threadpool_task_status() - Dequeue or try to stop a running task 182 * 183 * \param wsi: the wsi to query the current task of 184 * \param task: receives a pointer to the opaque task 185 * \param user: receives a void * pointer to the task user data 186 * 187 * This is the equivalent of posix waitpid()... it returns the status of the 188 * task, and if the task is in state LWS_TP_STATUS_FINISHED or 189 * LWS_TP_STATUS_STOPPED, frees \p task. If in another state, the task 190 * continues to exist. 191 * 192 * This is designed to be called from the service thread. 193 * 194 * Its use is to make sure the service thread has seen the state of the task 195 * before deleting it. 196 */ 197 LWS_VISIBLE LWS_EXTERN enum lws_threadpool_task_status 198 lws_threadpool_task_status_wsi(struct lws *wsi, 199 struct lws_threadpool_task **task, void **user); 200 201 /** 202 * lws_threadpool_task_sync() - Indicate to a stalled task it may continue 203 * 204 * \param task: the task to unblock 205 * \param stop: 0 = run after unblock, 1 = when he unblocks, stop him 206 * 207 * Inform the task that the service thread has finished with the shared data 208 * and that the task, if blocked in LWS_TP_RETURN_SYNC, may continue. 209 * 210 * If the lws service context determined that the task must be aborted, it 211 * should still call this but with stop = 1, causing the task to finish. 212 */ 213 LWS_VISIBLE LWS_EXTERN void 214 lws_threadpool_task_sync(struct lws_threadpool_task *task, int stop); 215 216 /** 217 * lws_threadpool_dump() - dump the state of a threadpool to the log 218 * 219 * \param tp: The threadpool to dump 220 * 221 * This locks the threadpool and then dumps the pending queue, the worker 222 * threads and the done queue, together with time information for how long 223 * the tasks have been in their current state, how long they have occupied a 224 * thread, etc. 225 * 226 * This only does anything on lws builds with CMAKE_BUILD_TYPE=DEBUG, otherwise 227 * while it still exists, it's a NOP. 228 */ 229 230 LWS_VISIBLE LWS_EXTERN void 231 lws_threadpool_dump(struct lws_threadpool *tp); 232 //@} 233