xref: /aosp_15_r20/external/libwebsockets/READMEs/README.lws_sequencer.md (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker# `struct lws_sequencer` introduction
2*1c60b9acSAndroid Build Coastguard Worker
3*1c60b9acSAndroid Build Coastguard WorkerOften a single network action like a client GET is just part of a
4*1c60b9acSAndroid Build Coastguard Workerlarger series of actions, perhaps involving different connections.
5*1c60b9acSAndroid Build Coastguard Worker
6*1c60b9acSAndroid Build Coastguard WorkerSince lws operates inside an event loop, if the outer sequencing
7*1c60b9acSAndroid Build Coastguard Workerdoesn't, it can be awkward to synchronize these steps with what's
8*1c60b9acSAndroid Build Coastguard Workerhappening on the network with a particular connection on the event
9*1c60b9acSAndroid Build Coastguard Workerloop thread.
10*1c60b9acSAndroid Build Coastguard Worker
11*1c60b9acSAndroid Build Coastguard Worker![lws_sequencer](/doc-assets/lws_sequencer.svg)
12*1c60b9acSAndroid Build Coastguard Worker
13*1c60b9acSAndroid Build Coastguard Worker`struct lws_sequencer` provides a generic way to stage multi-step
14*1c60b9acSAndroid Build Coastguard Workeroperations from inside the event loop.  Because it participates
15*1c60b9acSAndroid Build Coastguard Workerin the event loop similar to a wsi, it always operates from the
16*1c60b9acSAndroid Build Coastguard Workerservice thread context and can access structures that share the
17*1c60b9acSAndroid Build Coastguard Workerservice thread without locking.  It can also provide its own
18*1c60b9acSAndroid Build Coastguard Workerhigher-level timeout handling.
19*1c60b9acSAndroid Build Coastguard Worker
20*1c60b9acSAndroid Build Coastguard WorkerNaturally you can have many of them running in the same event
21*1c60b9acSAndroid Build Coastguard Workerloop operating independently.
22*1c60b9acSAndroid Build Coastguard Worker
23*1c60b9acSAndroid Build Coastguard WorkerSequencers themselves bind to a pt (per-thread) service thread,
24*1c60b9acSAndroid Build Coastguard Workerby default there's only one of these and it's the same as saying
25*1c60b9acSAndroid Build Coastguard Workerthey bind to an `lws_context`.  The sequencer callback may create
26*1c60b9acSAndroid Build Coastguard Workerwsi which in turn are bound to a vhost, but the sequencer itself
27*1c60b9acSAndroid Build Coastguard Workeris above all that.
28*1c60b9acSAndroid Build Coastguard Worker
29*1c60b9acSAndroid Build Coastguard Worker## Sequencer timeouts
30*1c60b9acSAndroid Build Coastguard Worker
31*1c60b9acSAndroid Build Coastguard WorkerThe sequencer additionally maintains its own second-resolution timeout
32*1c60b9acSAndroid Build Coastguard Workerchecked by lws for the step being sequenced... this is independent of
33*1c60b9acSAndroid Build Coastguard Workerany lws wsi timeouts which tend to be set and reset for very short-term
34*1c60b9acSAndroid Build Coastguard Workertimeout protection inside one transaction.
35*1c60b9acSAndroid Build Coastguard Worker
36*1c60b9acSAndroid Build Coastguard WorkerThe sequencer timeout operates separately and above any wsi timeout, and
37*1c60b9acSAndroid Build Coastguard Workeris typically only reset by the sequencer callback when it receives an
38*1c60b9acSAndroid Build Coastguard Workerevent indicating a step completed or failed, or it sets up the next sequence
39*1c60b9acSAndroid Build Coastguard Workerstep.
40*1c60b9acSAndroid Build Coastguard Worker
41*1c60b9acSAndroid Build Coastguard WorkerIf the sequencer timeout expires, then the sequencer receives a queued
42*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_TIMED_OUT` message informing it, and it can take corrective action
43*1c60b9acSAndroid Build Coastguard Workeror schedule a retry of the step.  This message is queued and sent normally
44*1c60b9acSAndroid Build Coastguard Workerunder the service thread context and in order of receipt.
45*1c60b9acSAndroid Build Coastguard Worker
46*1c60b9acSAndroid Build Coastguard WorkerUnlike lws timeouts which force the wsi to close, the sequencer timeout
47*1c60b9acSAndroid Build Coastguard Workeronly sends the message.  This allows the timeout to be used to, eg, wait
48*1c60b9acSAndroid Build Coastguard Workerout a retry cooloff period and then start the retry when the
49*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_TIMED_OUT` is received, according to the state of the sequencer.
50*1c60b9acSAndroid Build Coastguard Worker
51*1c60b9acSAndroid Build Coastguard Worker## Creating an `struct lws_sequencer`
52*1c60b9acSAndroid Build Coastguard Worker
53*1c60b9acSAndroid Build Coastguard Worker```
54*1c60b9acSAndroid Build Coastguard Workertypedef struct lws_seq_info {
55*1c60b9acSAndroid Build Coastguard Worker	struct lws_context		*context;   /* lws_context for seq */
56*1c60b9acSAndroid Build Coastguard Worker	int				tsi;	    /* thread service idx */
57*1c60b9acSAndroid Build Coastguard Worker	size_t				user_size;  /* size of user alloc */
58*1c60b9acSAndroid Build Coastguard Worker	void				**puser;    /* place ptr to user */
59*1c60b9acSAndroid Build Coastguard Worker	lws_seq_event_cb		cb;	    /* seq callback */
60*1c60b9acSAndroid Build Coastguard Worker	const char			*name;	    /* seq name */
61*1c60b9acSAndroid Build Coastguard Worker	const lws_retry_bo_t		*retry;	    /* retry policy */
62*1c60b9acSAndroid Build Coastguard Worker} lws_seq_info_t;
63*1c60b9acSAndroid Build Coastguard Worker```
64*1c60b9acSAndroid Build Coastguard Worker
65*1c60b9acSAndroid Build Coastguard Worker```
66*1c60b9acSAndroid Build Coastguard Workerstruct lws_sequencer *
67*1c60b9acSAndroid Build Coastguard Workerlws_sequencer_create(lws_seq_info_t *info);
68*1c60b9acSAndroid Build Coastguard Worker```
69*1c60b9acSAndroid Build Coastguard Worker
70*1c60b9acSAndroid Build Coastguard WorkerWhen created, in lws the sequencer objects are bound to a 'per-thread',
71*1c60b9acSAndroid Build Coastguard Workerwhich is by default the same as to say bound to the `lws_context`.  You
72*1c60b9acSAndroid Build Coastguard Workercan tag them with an opaque user data pointer, and they are also bound to
73*1c60b9acSAndroid Build Coastguard Workera user-specified callback which handles sequencer events
74*1c60b9acSAndroid Build Coastguard Worker
75*1c60b9acSAndroid Build Coastguard Worker```
76*1c60b9acSAndroid Build Coastguard Workertypedef int (*lws_seq_event_cb)(struct lws_sequencer *seq, void *user_data,
77*1c60b9acSAndroid Build Coastguard Worker				lws_seq_events_t event, void *data);
78*1c60b9acSAndroid Build Coastguard Worker```
79*1c60b9acSAndroid Build Coastguard Worker
80*1c60b9acSAndroid Build Coastguard Worker`struct lws_sequencer` objects are private to lws and opaque to the user.  A small
81*1c60b9acSAndroid Build Coastguard Workerset of apis lets you perform operations on the pointer returned by the
82*1c60b9acSAndroid Build Coastguard Workercreate api.
83*1c60b9acSAndroid Build Coastguard Worker
84*1c60b9acSAndroid Build Coastguard Worker## Queueing events on a sequencer
85*1c60b9acSAndroid Build Coastguard Worker
86*1c60b9acSAndroid Build Coastguard WorkerEach sequencer object can be passed "events", which are held on a per-sequencer
87*1c60b9acSAndroid Build Coastguard Workerqueue and handled strictly in the order they arrived on subsequent event loops.
88*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_CREATED` and `LWSSEQ_DESTROYED` events are produced by lws reflecting
89*1c60b9acSAndroid Build Coastguard Workerthe sequencer's lifecycle, but otherwise the event indexes have a user-defined
90*1c60b9acSAndroid Build Coastguard Workermeaning and are queued on the sequencer by user code for eventual consumption
91*1c60b9acSAndroid Build Coastguard Workerby user code in the sequencer callback.
92*1c60b9acSAndroid Build Coastguard Worker
93*1c60b9acSAndroid Build Coastguard WorkerPending events are removed from the sequencer queues and sent to the sequencer
94*1c60b9acSAndroid Build Coastguard Workercallback from inside the event loop at a rate of one per event loop wait.
95*1c60b9acSAndroid Build Coastguard Worker
96*1c60b9acSAndroid Build Coastguard Worker## Destroying sequencers
97*1c60b9acSAndroid Build Coastguard Worker
98*1c60b9acSAndroid Build Coastguard Worker`struct lws_sequencer` objects are cleaned up during context destruction if they are
99*1c60b9acSAndroid Build Coastguard Workerstill around.
100*1c60b9acSAndroid Build Coastguard Worker
101*1c60b9acSAndroid Build Coastguard WorkerNormally the sequencer callback receives a queued message that
102*1c60b9acSAndroid Build Coastguard Workerinforms it that it's either failed at the current step, or succeeded and that
103*1c60b9acSAndroid Build Coastguard Workerwas the last step, and requests that it should be destroyed by returning
104*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_RET_DESTROY` from the sequencer callback.
105*1c60b9acSAndroid Build Coastguard Worker
106*1c60b9acSAndroid Build Coastguard Worker## Lifecycle considerations
107*1c60b9acSAndroid Build Coastguard Worker
108*1c60b9acSAndroid Build Coastguard WorkerSequencers may spawn additional assets like client wsi as part of the sequenced
109*1c60b9acSAndroid Build Coastguard Workeractions... the lifecycle of the sequencer and the assets overlap but do not
110*1c60b9acSAndroid Build Coastguard Workernecessarily depend on each other... that is a wsi created by the sequencer may
111*1c60b9acSAndroid Build Coastguard Workeroutlive the sequencer.
112*1c60b9acSAndroid Build Coastguard Worker
113*1c60b9acSAndroid Build Coastguard WorkerIt's important therefore to detach assets from the sequencer and the sequencer
114*1c60b9acSAndroid Build Coastguard Workerfrom the assets when each step is over and the asset is "out of scope" for the
115*1c60b9acSAndroid Build Coastguard Workersequencer.  It doesn't necessarily mean closing the assets, just making sure
116*1c60b9acSAndroid Build Coastguard Workerpointers are invalidated.  For example, if a client wsi held a pointer to the
117*1c60b9acSAndroid Build Coastguard Workersequencer as its `.user_data`, when the wsi is out of scope for the sequencer
118*1c60b9acSAndroid Build Coastguard Workerit can set it to NULL, eg, `lws_set_wsi_user(wsi, NULL);`.
119*1c60b9acSAndroid Build Coastguard Worker
120*1c60b9acSAndroid Build Coastguard WorkerUnder some conditions wsi may want to hang around a bit to see if there is a
121*1c60b9acSAndroid Build Coastguard Workersubsequent client wsi transaction they can be reused on.  They will clean
122*1c60b9acSAndroid Build Coastguard Workerthemselves up when they time out.
123*1c60b9acSAndroid Build Coastguard Worker
124*1c60b9acSAndroid Build Coastguard Worker## Watching wsi lifecycle from a sequencer
125*1c60b9acSAndroid Build Coastguard Worker
126*1c60b9acSAndroid Build Coastguard WorkerWhen a sequencer is creating a wsi as part of its sequence, it will be very
127*1c60b9acSAndroid Build Coastguard Workerinterested in lifecycle events.  At client wsi creation time, the sequencer
128*1c60b9acSAndroid Build Coastguard Workercallback can set info->seq to itself in order to receive lifecycle messages
129*1c60b9acSAndroid Build Coastguard Workerabout its wsi.
130*1c60b9acSAndroid Build Coastguard Worker
131*1c60b9acSAndroid Build Coastguard Worker|message|meaning|
132*1c60b9acSAndroid Build Coastguard Worker|---|---|
133*1c60b9acSAndroid Build Coastguard Worker|`LWSSEQ_WSI_CONNECTED`|The wsi has become connected|
134*1c60b9acSAndroid Build Coastguard Worker|`LWSSEQ_WSI_CONN_FAIL`|The wsi has failed to connect|
135*1c60b9acSAndroid Build Coastguard Worker|`LWSSEQ_WSI_CONN_CLOSE`|The wsi had been connected, but has now closed|
136*1c60b9acSAndroid Build Coastguard Worker
137*1c60b9acSAndroid Build Coastguard WorkerBy receiving these, the sequencer can understand when it should attempt
138*1c60b9acSAndroid Build Coastguard Workerreconnections or that it cannot progress the sequence.
139*1c60b9acSAndroid Build Coastguard Worker
140*1c60b9acSAndroid Build Coastguard WorkerWhen dealing with wsi that were created by the sequencer, they may close at
141*1c60b9acSAndroid Build Coastguard Workerany time, eg, be closed by the remote peer or an intermediary.  The
142*1c60b9acSAndroid Build Coastguard Worker`LWSSEQ_WSI_CONN_CLOSE` message may have been queued but since they are
143*1c60b9acSAndroid Build Coastguard Workerstrictly handled in the order they arrived, before it was
144*1c60b9acSAndroid Build Coastguard Workerhandled an earlier message may want to cause some api to be called on
145*1c60b9acSAndroid Build Coastguard Workerthe now-free()-d wsi.  To detect this situation safely, there is a
146*1c60b9acSAndroid Build Coastguard Workersequencer api `lws_sequencer_check_wsi()` which peeks the message
147*1c60b9acSAndroid Build Coastguard Workerbuffer and returns nonzero if it later contains an `LWSSEQ_WSI_CONN_CLOSE`
148*1c60b9acSAndroid Build Coastguard Workeralready.
149*1c60b9acSAndroid Build Coastguard Worker
150