Project homepage Mailing List  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1635257119, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"", "f":3, "items": [ { "schema":"libjg2-1", "oid":{ "oid": "b5aad92ff0cc58dd1e0abb8ed7a08399b8f47e4b", "alias": [ "refs/heads/main"]},"tree": [ { "name": "","mode": "33188", "size":8287}, { "name": "threadpool.c","mode": "33188", "size":29534}],"s":{"c":1635257119,"u": 1066}} ,{"schema":"libjg2-1", "cid":"dca0beded4c916e92cc4d962472dd56f", "oid":{ "oid": "b5aad92ff0cc58dd1e0abb8ed7a08399b8f47e4b", "alias": [ "refs/heads/main"]},"blobname": "lib/misc/threadpool/", "blob": "## Threadpool\n\n### Overview\n\n![overview](/doc-assets/threadpool.svg)\n\nAn api that lets you create a pool of worker threads, and a queue of tasks that\nare bound to a wsi. Tasks in their own thread synchronize communication to the\nlws service thread of the wsi via `LWS_CALLBACK_SERVER_WRITEABLE` and friends.\n\nTasks can produce some output, then return that they want to \u0022sync\u0022 with the\nservice thread. That causes a `LWS_CALLBACK_SERVER_WRITEABLE` in the service\nthread context, where the output can be consumed, and the task told to continue,\nor completed tasks be reaped.\n\nALL of the details related to thread synchronization and an associated wsi in\nthe lws service thread context are handled by the threadpool api, without needing\nany pthreads in user code.\n\n### Example\n\n\n\n### Lifecycle considerations\n\n#### Tasks vs wsi\n\nAlthough all tasks start out as being associated to a wsi, in fact the lifetime\nof a task and that of the wsi are not necessarily linked.\n\nYou may start a long task, eg, that runs atomically in its thread for 30s, and\nat any time the client may close the connection, eg, close a browser window.\n\nThere are arrangements that a task can \u0022check in\u0022 periodically with lws to see\nif it has been asked to stop, allowing the task lifetime to be related to the\nwsi lifetime somewhat, but some tasks are going to be atomic and longlived.\n\nFor that reason, at wsi close an ongoing task can detach from the wsi and\ncontinue until it ends or understands it has been asked to stop. To make\nthat work, the task is created with a `cleanup` callback that performs any\nfreeing independent of still having a wsi around to do it... the task takes over\nresponsibility to free the user pointer on destruction when the task is created.\n\n![Threadpool States](/doc-assets/threadpool-states.svg)\n\n#### Reaping completed tasks\n\nOnce created, although tasks may run asynchronously, the task itself does not\nget destroyed on completion but added to a \u0022done queue\u0022. Only when the lws\nservice thread context queries the task state with `lws_threadpool_task_status()`\nmay the task be reaped and memory freed.\n\nThis is analogous to unix processes and `wait()`.\n\nIf a task became detached from its wsi, then joining the done queue is enough\nto get the task reaped, since there's nobody left any more to synchronize the\nreaping with.\n\n### User interface\n\nThe api is declared at\n\n#### Threadpool creation / destruction\n\nThe threadpool should be created at program or vhost init using\n`lws_threadpool_create()` and destroyed on exit or vhost destruction using\nfirst `lws_threadpool_finish()` and then `lws_threadpool_destroy()`.\n\nThreadpools should be named, varargs are provided on the create function\nto facilite eg, naming the threadpool by the vhost it's associated with.\n\nThreadpool creation takes an args struct with the following members:\n\nMember|function\n---|---\nthreads|The maxiumum number of independent threads in the pool\nmax_queue_depth|The maximum number of tasks allowed to wait for a place in the pool\n\n#### Task creation / destruction\n\nTasks are created and queued using `lws_threadpool_enqueue()`, this takes an\nargs struct with the following members\n\nMember|function\n---|---\nwsi|The wsi the task is initially associated with\nuser|An opaque user-private pointer used for communication with the lws service thread and private state / data\ntask|A pointer to the function that will run in the pool thread\ncleanup|A pointer to a function that will clean up finished or stopped tasks (perhaps freeing user)\n\nTasks also should have a name, the creation function again provides varargs\nto simplify naming the task with string elements related to who started it\nand why.\n\n#### The task function itself\n\nThe task function receives the task user pointer and the task state. The\npossible task states are\n\nState|Meaning\n---|---\nLWS_TP_STATUS_QUEUED|Task is still waiting for a pool thread\nLWS_TP_STATUS_RUNNING|Task is supposed to do its work\nLWS_TP_STATUS_SYNCING|Task is blocked waiting for sync from lws service thread\nLWS_TP_STATUS_STOPPING|Task has been asked to stop but didn't stop yet\nLWS_TP_STATUS_FINISHED|Task has reported it has completed\nLWS_TP_STATUS_STOPPED|Task has aborted\n\nThe task function will only be told `LWS_TP_STATUS_RUNNING` or\n`LWS_TP_STATUS_STOPPING` in its status argument... RUNNING means continue with the\nuser task and STOPPING means clean up and return `LWS_TP_RETURN_STOPPED`.\n\nIf possible every 100ms or so the task should return `LWS_TP_RETURN_CHECKING_IN`\nto allow lws to inform it reasonably quickly that it has been asked to stop\n(eg, because the related wsi has closed), or if it can continue. If not\npossible, it's okay but eg exiting the application may experience delays\nuntil the running task finishes, and since the wsi may have gone, the work\nis wasted.\n\nThe task function may return one of\n\nReturn|Meaning\n---|---\nLWS_TP_RETURN_CHECKING_IN|Still wants to run, but confirming nobody asked him to stop. Will be called again immediately with `LWS_TP_STATUS_RUNNING` or `LWS_TP_STATUS_STOPPING`\nLWS_TP_RETURN_SYNC|Task wants to trigger a WRITABLE callback and block until lws service thread restarts it with `lws_threadpool_task_sync()`\nLWS_TP_RETURN_FINISHED|Task has finished, successfully as far as it goes\nLWS_TP_RETURN_STOPPED|Task has finished, aborting in response to a request to stop\n\nThe SYNC or CHECKING_IN return may also have a flag `LWS_TP_RETURN_FLAG_OUTLIVE`\napplied to it, which indicates to threadpool that this task wishes to remain\nunstopped after the wsi closes. This is useful in the case where the task\nunderstands it will take a long time to complete, and wants to return a\ncomplete status and maybe close the connection, perhaps with a token identifying\nthe task. The task can then be monitored separately by using the token.\n\n#### Synchronizing\n\nThe task can choose to \u0022SYNC\u0022 with the lws service thread, in other words\ncause a WRITABLE callback on the associated wsi in the lws service thread\ncontext and block itself until it hears back from there via\n`lws_threadpool_task_sync()` to resume the task.\n\nThis is typically used when, eg, the task has filled its buffer, or ringbuffer,\nand needs to pause operations until what's done has been sent and some buffer\nspace is open again.\n\nIn the WRITABLE callback, in lws service thread context, the buffer can be\nsent with `lws_write()` and then `lws_threadpool_task_sync()` to allow the task\nto fill another buffer and continue that way.\n\nIf the WRITABLE callback determines that the task should stop, it can just call\n`lws_threadpool_task_sync()` with the second argument as 1, to force the task\nto stop immediately after it resumes.\n\n#### The cleanup function\n\nWhen a finished task is reaped, or a task that become detached from its initial\nwsi completes or is stopped, it calls the `.cleanup` function defined in the\ntask creation args struct to free anything related to the user pointer.\n\nWith threadpool, responsibility for freeing allocations used by the task belongs\nstrictly with the task, via the `.cleanup` function, once the task has been\nenqueued. That's different from a typical non-threadpool protocol where the\nwsi lifecycle controls deallocation. This reflects the fact that the task\nmay outlive the wsi.\n\n#### Protecting against WRITABLE and / or SYNC duplication\n\nCare should be taken than data prepared by the task thread in the user priv\nmemory should only be sent once. For example, after sending data from a user\npriv buffer of a given length stored in the priv, zero down the length.\n\nTask execution and the SYNC writable callbacks are mutually exclusive, so there\nis no danger of collision between the task thread and the lws service thread if\nthe reason for the callback is a SYNC operation from the task thread.\n\n### Thread overcommit\n\nIf the tasks running on the threads are ultimately network-bound for all or some\nof their processing (via the SYNC with the WRITEABLE callback), it's possible\nto overcommit the number of threads in the pool compared to the number of\nthreads the processor has in hardware to get better occupancy in the CPU.\n","s":{"c":1635257119,"u": 576}} ],"g": 4010,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 1, "si": 0, "db":0, "di":1, "sat":0, "lfc": "0000"}