Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1571200509, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", "f":3, "items": [ {"schema":"libjg2-1", "cid":"6e1e0191cb52fadfe7188737f866383f", "oid":{ "oid": "1cae39bb695b7201d43e8cc25eda98e625ceae2f", "alias": [ "refs/heads/master"]},"blobname": "READMEs/README.lws_sequencer.md", "blob": "# `struct lws_sequencer` introduction\n\nOften a single network action like a client GET is just part of a\nlarger series of actions, perhaps involving different connections.\n\nSince lws operates inside an event loop, if the outer sequencing\ndoesn't, it can be awkward to synchronize these steps with what's\nhappening on the network with a particular connection on the event\nloop thread.\n\n![lws_sequencer](/doc-assets/lws_sequencer.svg)\n\n`struct lws_sequencer` provides a generic way to stage multi-step\noperations from inside the event loop. Because it participates\nin the event loop similar to a wsi, it always operates from the\nservice thread context and can access structures that share the\nservice thread without locking. It can also provide its own\nhigher-level timeout handling.\n\nNaturally you can have many of them running in the same event\nloop operating independently.\n\nSequencers themselves bind to a pt (per-thread) service thread,\nby default there's only one of these and it's the same as saying\nthey bind to an `lws_context`. The sequencer callback may create\nwsi which in turn are bound to a vhost, but the sequencer itself\nis above all that.\n\n## Sequencer timeouts\n\nThe sequencer additionally maintains its own second-resolution timeout\nchecked by lws for the step being sequenced... this is independent of\nany lws wsi timeouts which tend to be set and reset for very short-term\ntimeout protection inside one transaction.\n\nThe sequencer timeout operates separately and above any wsi timeout, and\nis typically only reset by the sequencer callback when it receives an\nevent indicating a step completed or failed, or it sets up the next sequence\nstep.\n\nIf the sequencer timeout expires, then the sequencer receives a queued\n`LWSSEQ_TIMED_OUT` message informing it, and it can take corrective action\nor schedule a retry of the step. This message is queued and sent normally\nunder the service thread context and in order of receipt.\n\nUnlike lws timeouts which force the wsi to close, the sequencer timeout\nonly sends the message. This allows the timeout to be used to, eg, wait\nout a retry cooloff period and then start the retry when the\n`LWSSEQ_TIMED_OUT` is received, according to the state of the sequencer.\n\n## Creating an `struct lws_sequencer`\n\n```\ntypedef struct lws_seq_info {\n\tstruct lws_context\t\t*context; /* lws_context for seq */\n\tint\t\t\t\ttsi;\t /* thread service idx */\n\tsize_t\t\t\t\tuser_size; /* size of user alloc */\n\tvoid\t\t\t\t**puser; /* place ptr to user */\n\tlws_seq_event_cb\t\tcb;\t /* seq callback */\n\tconst char\t\t\t*name;\t /* seq name */\n\tconst lws_retry_bo_t\t\t*retry;\t /* retry policy */\n} lws_seq_info_t;\n```\n\n```\nstruct lws_sequencer *\nlws_sequencer_create(lws_seq_info_t *info);\n```\n\nWhen created, in lws the sequencer objects are bound to a 'per-thread',\nwhich is by default the same as to say bound to the `lws_context`. You\ncan tag them with an opaque user data pointer, and they are also bound to\na user-specified callback which handles sequencer events\n\n```\ntypedef int (*lws_seq_event_cb)(struct lws_sequencer *seq, void *user_data,\n\t\t\t\tlws_seq_events_t event, void *data);\n```\n\n`struct lws_sequencer` objects are private to lws and opaque to the user. A small\nset of apis lets you perform operations on the pointer returned by the\ncreate api.\n\n## Queueing events on a sequencer\n\nEach sequencer object can be passed \u0022events\u0022, which are held on a per-sequencer\nqueue and handled strictly in the order they arrived on subsequent event loops.\n`LWSSEQ_CREATED` and `LWSSEQ_DESTROYED` events are produced by lws reflecting\nthe sequencer's lifecycle, but otherwise the event indexes have a user-defined\nmeaning and are queued on the sequencer by user code for eventual consumption\nby user code in the sequencer callback.\n\nPending events are removed from the sequencer queues and sent to the sequencer\ncallback from inside the event loop at a rate of one per event loop wait.\n\n## Destroying sequencers\n\n`struct lws_sequencer` objects are cleaned up during context destruction if they are\nstill around.\n\nNormally the sequencer callback receives a queued message that\ninforms it that it's either failed at the current step, or succeeded and that\nwas the last step, and requests that it should be destroyed by returning\n`LWSSEQ_RET_DESTROY` from the sequencer callback.\n\n## Lifecycle considerations\n\nSequencers may spawn additional assets like client wsi as part of the sequenced\nactions... the lifecycle of the sequencer and the assets overlap but do not\nnecessarily depend on each other... that is a wsi created by the sequencer may\noutlive the sequencer.\n\nIt's important therefore to detach assets from the sequencer and the sequencer\nfrom the assets when each step is over and the asset is \u0022out of scope\u0022 for the\nsequencer. It doesn't necessarily mean closing the assets, just making sure\npointers are invalidated. For example, if a client wsi held a pointer to the\nsequencer as its `.user_data`, when the wsi is out of scope for the sequencer\nit can set it to NULL, eg, `lws_set_wsi_user(wsi, NULL);`.\n\nUnder some conditions wsi may want to hang around a bit to see if there is a\nsubsequent client wsi transaction they can be reused on. They will clean\nthemselves up when they time out.\n\n## Watching wsi lifecycle from a sequencer\n\nWhen a sequencer is creating a wsi as part of its sequence, it will be very\ninterested in lifecycle events. At client wsi creation time, the sequencer\ncallback can set info-\u003eseq to itself in order to receive lifecycle messages\nabout its wsi.\n\n|message|meaning|\n|---|---|\n|`LWSSEQ_WSI_CONNECTED`|The wsi has become connected|\n|`LWSSEQ_WSI_CONN_FAIL`|The wsi has failed to connect|\n|`LWSSEQ_WSI_CONN_CLOSE`|The wsi had been connected, but has now closed|\n\nBy receiving these, the sequencer can understand when it should attempt\nreconnections or that it cannot progress the sequence.\n\nWhen dealing with wsi that were created by the sequencer, they may close at\nany time, eg, be closed by the remote peer or an intermediary. The\n`LWSSEQ_WSI_CONN_CLOSE` message may have been queued but since they are\nstrictly handled in the order they arrived, before it was\nhandled an earlier message may want to cause some api to be called on\nthe now-free()-d wsi. To detect this situation safely, there is a\nsequencer api `lws_sequencer_check_wsi()` which peeks the message\nbuffer and returns nonzero if it later contains an `LWSSEQ_WSI_CONN_CLOSE`\nalready.\n\n","s":{"c":1571200509,"u": 322}} ],"g": 1668,"chitpc": 0,"ehitpc": 0, "indexed":0 }