libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

asyncresponses.inc (19104B)


      1 The previous chapter left one question open.  A content reader that
      2 has no data ready may return @code{0}, but doing so turns the daemon
      3 into a busy loop, and the honest answer---suspend the connection---was
      4 only sketched there.  This chapter builds the thing itself: a server
      5 whose slow work happens in threads of its own, whose connections are
      6 parked while that work is under way, and which is driven by an
      7 external @code{select()} loop so that the application stays in charge
      8 of its own event handling.
      9 
     10 The combination is a common one.  Most requests are cheap and can be
     11 answered on the spot; a few of them start a report, a backup or a
     12 query that runs for seconds.  Handling the slow ones inline would
     13 block every other client for as long as they take.  Giving every
     14 connection its own thread---@code{MHD_USE_THREAD_PER_CONNECTION}---is
     15 no answer either, both because it scales badly and because suspending
     16 is not available in that mode at all.  What is wanted is a single
     17 event loop that never blocks, plus a worker per slow job.
     18 
     19 
     20 @heading Who may call what
     21 
     22 Almost every difficulty in this design comes from one rule, so it is
     23 worth stating before any code:
     24 
     25 @table @asis
     26 @item @code{MHD_queue_response()}
     27 Must be called from the thread that runs the daemon, from inside the
     28 access handler.  A worker thread must never queue a response.
     29 
     30 @item @code{MHD_suspend_connection()}
     31 May only be called from the access handler or from a content reader
     32 callback---that is, from @emph{MHD}'s own thread, while @emph{MHD} is
     33 calling into the application.
     34 
     35 @item @code{MHD_resume_connection()}
     36 May be called from any thread at any time, and this is the exception
     37 that makes the whole design work.  It is the only @emph{MHD} function
     38 a worker thread ever needs.
     39 @end table
     40 
     41 @noindent
     42 So the split is: the worker computes and, when it has something,
     43 resumes.  Everything that touches the connection or the response
     44 happens on the daemon's thread, where @emph{MHD} calls the application
     45 back.  The worker and the daemon share exactly one object, a
     46 per-request context, and the only thing the worker does with the
     47 connection handle it holds is pass it to
     48 @code{MHD_resume_connection()}.
     49 
     50 The daemon has to be started with @code{MHD_ALLOW_SUSPEND_RESUME}; both
     51 suspend and resume call @code{MHD_PANIC()} and abort the process
     52 otherwise.  Note also that suspending does not work with a thread pool:
     53 @code{MHD_resume_connection()} asserts that the daemon has none.
     54 
     55 
     56 @heading The event loop
     57 
     58 Leaving out @code{MHD_USE_INTERNAL_POLLING_THREAD} puts @emph{MHD}
     59 into external polling mode: it starts no thread of its own and does
     60 nothing until the application asks it to.  The loop is the usual one,
     61 and the example adds its own descriptor to the very same sets---there
     62 is nothing special about @emph{MHD}'s:
     63 
     64 @verbatim
     65   FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es);
     66   max = 0;
     67   if (MHD_YES != MHD_get_fdset (daemon, &rs, &ws, &es, &max))
     68     break;                      /* fatal internal error */
     69   FD_SET (wake_pipe[0], &rs);   /* our own wakeup pipe */
     70   if (max < wake_pipe[0])
     71     max = wake_pipe[0];
     72 
     73   if (MHD_YES == MHD_get_timeout64 (daemon, &mhd_timeout))
     74     { ...fill tv...; tvp = &tv; }
     75   else
     76     tvp = NULL;                 /* nothing to wait for */
     77 
     78   select ((int) max + 1, &rs, &ws, &es, tvp);
     79   MHD_run_from_select (daemon, &rs, &ws, &es);
     80 @end verbatim
     81 @noindent
     82 
     83 The interesting branch is the one that sets @code{tvp} to @code{NULL}.
     84 @code{MHD_get_timeout64()} returns @code{MHD_NO} when @emph{MHD} has
     85 nothing whatsoever to wait for, and with every connection suspended
     86 that is precisely the situation: suspended connections do not time
     87 out, so there is no deadline to wake up for.  The loop then blocks in
     88 @code{select()} indefinitely.  Whether the server works at all depends
     89 on something waking it up.
     90 
     91 
     92 @heading Waking the loop up
     93 
     94 That something is @emph{MHD}'s inter-thread communication channel.
     95 @code{MHD_ALLOW_SUSPEND_RESUME} is defined as
     96 @code{8192 | MHD_USE_ITC}, so requesting suspend support requests the
     97 ITC as well; @code{MHD_get_fdset()} puts the reading end of that
     98 channel into the read set, ahead of everything else; and
     99 @code{MHD_resume_connection()} writes a byte to it.  A worker thread
    100 that resumes a connection therefore breaks the main thread out of
    101 @code{select()}, even though the two share nothing but the daemon
    102 handle.
    103 
    104 This deserves emphasis because the header file is misleading about it:
    105 the comment on @code{MHD_USE_ITC} says the flag is ignored with
    106 external polling.  That is true for the flag in isolation, but not for
    107 the channel: @code{MHD_ALLOW_SUSPEND_RESUME} creates it regardless of
    108 the polling mode, and in external mode it is the application's own
    109 @code{select()} that watches it.  Without that, a resumed connection
    110 would sit untouched until some unrelated event happened to wake the
    111 loop.
    112 
    113 There is no race to guard against here.  If the worker resumes in the
    114 window between @code{MHD_get_fdset()} and @code{select()}, the byte is
    115 already in the channel when @code{select()} is entered, and
    116 @code{select()} returns immediately---the channel is level triggered,
    117 so a wakeup cannot be missed.  The same property makes it safe for a
    118 worker to resume a connection that has not finished suspending yet:
    119 @emph{MHD} remembers the request and cancels the pending suspension
    120 instead of parking the connection.  Neither side needs to know what
    121 the other is doing.
    122 
    123 
    124 @heading Answering in one piece
    125 
    126 The simplest of the two patterns is for an answer that is only useful
    127 as a whole---a generated report, the result of a query.  Nothing can be
    128 sent before it is finished, so the connection is suspended in the
    129 access handler and the response is queued when @emph{MHD} comes back:
    130 
    131 @verbatim
    132 static enum MHD_Result
    133 handle_slow (struct MHD_Connection *connection, void **req_cls)
    134 {
    135   struct Job *job = *req_cls;
    136 
    137   if (NULL == job)
    138     {
    139       /* First call for this request: start the work and ask MHD to
    140          come back to us. */
    141       job = job_create (connection, 0);
    142       if (NULL == job)
    143         return MHD_NO;
    144       if (MHD_NO == job_start (job))
    145         { job_unref (job); job_unref (job); return MHD_NO; }
    146       *req_cls = job;
    147       return MHD_YES;
    148     }
    149   pthread_mutex_lock (&job->lock);
    150   if (0 == job->finished)
    151     {
    152       job->suspended = 1;
    153       MHD_suspend_connection (connection);
    154       pthread_mutex_unlock (&job->lock);
    155       return MHD_YES;
    156     }
    157   ...copy the result out from under the lock...
    158   pthread_mutex_unlock (&job->lock);
    159   ...MHD_create_response_from_buffer_copy() and MHD_queue_response()...
    160 }
    161 @end verbatim
    162 @noindent
    163 
    164 The control flow is worth following, because it is not obvious that it
    165 terminates.  @emph{MHD} calls the access handler for a request more
    166 than once; the first call is the one where @code{*req_cls} is still
    167 @code{NULL}, and returning @code{MHD_YES} without queueing anything
    168 tells @emph{MHD} to carry on.  On the second call the worker is
    169 running but not finished, so the connection is suspended and the
    170 handler returns again.  When the worker resumes the connection,
    171 @emph{MHD} calls the handler a third time---on its own thread, with
    172 the same @code{*req_cls}---and this time @code{finished} is set and the
    173 response is queued.
    174 
    175 That third call is the answer to the question this pattern exists for.
    176 The worker never queues anything; it merely makes the daemon call the
    177 application back at a moment when the answer is ready.
    178 
    179 
    180 @heading Answering as it is produced
    181 
    182 The second pattern is the more useful one when the answer is long, and
    183 it is what makes a browser show results as they appear rather than
    184 after a long blank pause.  Here the response is queued
    185 @emph{immediately}, with a content reader and an unknown size, so the
    186 headers go out at once and the body follows as the worker fills it in:
    187 
    188 @verbatim
    189   job = job_create (connection, 1);
    190   response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
    191                                                 IO_BLOCK_SIZE,
    192                                                 &stream_reader,
    193                                                 job,
    194                                                 &stream_done);
    195   ...
    196   MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE,
    197                            "text/event-stream");
    198   ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    199   MHD_destroy_response (response);
    200 @end verbatim
    201 @noindent
    202 
    203 Because the size is unknown, @emph{MHD} uses chunked transfer encoding,
    204 and every piece the content reader hands back is framed as its own
    205 chunk and goes out on the wire straight away.  The content reader is
    206 where suspending happens:
    207 
    208 @verbatim
    209 static ssize_t
    210 stream_reader (void *cls, uint64_t pos, char *buf, size_t max)
    211 {
    212   struct Job *job = cls;
    213   size_t ready;
    214 
    215   pthread_mutex_lock (&job->lock);
    216   if (job->off == job->fill)
    217     {
    218       job->off = 0;
    219       job->fill = 0;
    220       if (0 != job->finished)
    221         {
    222           pthread_mutex_unlock (&job->lock);
    223           return MHD_CONTENT_READER_END_OF_STREAM;
    224         }
    225       /* Nothing to send yet.  Take the connection out of the event
    226          loop; the worker will put it back in. */
    227       job->suspended = 1;
    228       MHD_suspend_connection (job->connection);
    229       pthread_mutex_unlock (&job->lock);
    230       return 0;
    231     }
    232   ready = job->fill - job->off;
    233   if (ready > max)
    234     ready = max;
    235   memcpy (buf, &job->payload[job->off], ready);
    236   job->off += ready;
    237   pthread_mutex_unlock (&job->lock);
    238   return (ssize_t) ready;
    239 }
    240 @end verbatim
    241 @noindent
    242 
    243 The return value is still @code{0}, exactly as in the busy-waiting
    244 version the previous chapter warned about.  The difference is the line
    245 above it.  Suspending removes the connection from the event loop, so
    246 @emph{MHD} has no reason to come back until the worker says so, and
    247 the process goes to sleep.  The example ships with a test that measures
    248 this: streaming a document that takes one second to produce costs the
    249 server no measurable CPU time at all while the connection is suspended,
    250 and very nearly a full second---one core, saturated---when the
    251 @code{MHD_suspend_connection()} call is removed and only the
    252 @code{return 0} is left.  The bytes that arrive are identical in both
    253 cases, which is what makes this such an easy mistake to keep.
    254 
    255 
    256 @heading The shared state
    257 
    258 Everything the two threads share sits in one structure per request:
    259 
    260 @verbatim
    261 struct Job
    262 {
    263   pthread_mutex_t lock;
    264   pthread_cond_t cond;
    265   struct MHD_Connection *connection;
    266   char payload[MAX_PAYLOAD];
    267   size_t fill;
    268   size_t off;
    269   unsigned int rc;
    270   int finished;
    271   int suspended;
    272   int abandoned;
    273   ...
    274 };
    275 @end verbatim
    276 @noindent
    277 
    278 There is no registry of pending requests involved in answering them,
    279 and no lookup: the pointer travels in @code{*req_cls} for the first
    280 pattern and in the content reader's @code{crc_cls} for the second, and
    281 both the daemon and the worker are handed it directly.  A shared list
    282 of all jobs is still useful, but only for shutting down in an orderly
    283 fashion, and it is protected by a lock of its own that is always taken
    284 before any job's lock, never after.
    285 
    286 The structure is reference counted, with one reference held by
    287 @emph{MHD} and one by the worker.  The @emph{MHD} side lets go in the
    288 free callback of the response for a streamed answer, and in the
    289 @code{MHD_OPTION_NOTIFY_COMPLETED} callback for the other pattern; the
    290 worker lets go when it returns.  Dropping the last reference does not
    291 free the job, though, because the worker still has to be joined and
    292 only the main thread may do that.  The main loop therefore ends with a
    293 sweep that joins and frees whatever has no references left.
    294 
    295 
    296 @heading When the client goes away
    297 
    298 This is the part that is easy to get wrong, because it does not happen
    299 during development and does happen constantly in production.  A client
    300 that closes the connection halfway through a download leaves a worker
    301 running with a pointer to a connection @emph{MHD} is about to free.
    302 
    303 The two callbacks that tell the application a request is over---the
    304 response's free callback and @code{MHD_OPTION_NOTIFY_COMPLETED}---are
    305 therefore where the worker is cut loose:
    306 
    307 @verbatim
    308 static void
    309 job_detach (struct Job *job)
    310 {
    311   pthread_mutex_lock (&job->lock);
    312   job->abandoned = 1;
    313   job->connection = NULL;
    314   pthread_cond_signal (&job->cond);
    315   pthread_mutex_unlock (&job->lock);
    316   job_unref (job);
    317 }
    318 @end verbatim
    319 @noindent
    320 
    321 and the worker checks that flag before every resume:
    322 
    323 @verbatim
    324 static void
    325 job_resume_locked (struct Job *job)
    326 {
    327   if ( (0 == job->suspended) || (0 != job->abandoned) )
    328     return;
    329   job->suspended = 0;
    330   MHD_resume_connection (job->connection);
    331 }
    332 @end verbatim
    333 @noindent
    334 
    335 Note that this function is called with the job's lock @emph{held}, and
    336 calls into @emph{MHD} without releasing it.  That is deliberate and it
    337 is what makes the pattern safe.  @emph{MHD} destroys the connection
    338 only after the completion callback has returned, and that callback
    339 cannot run while the worker holds the lock; so for as long as the
    340 worker is inside @code{MHD_resume_connection()}, the connection it
    341 passes is guaranteed to still exist.  Dropping the lock first and
    342 resuming afterwards would open exactly the window this is meant to
    343 close.
    344 
    345 The reverse order never occurs: @emph{MHD} invokes the free and
    346 completion callbacks without holding the internal locks that
    347 @code{MHD_resume_connection()} acquires, so there is no way for the
    348 two to deadlock.
    349 
    350 The condition variable in the same function is a convenience rather
    351 than a necessity.  Signalling it wakes a worker that is asleep between
    352 steps, so that the work stops within microseconds of the client
    353 disappearing instead of running to completion for nobody.
    354 
    355 
    356 @heading Shutting down
    357 
    358 Stopping a daemon that still has suspended connections is an API
    359 violation, and a suspended connection is one that only a worker can
    360 release.  The order is therefore fixed:
    361 
    362 @enumerate
    363 @item
    364 Stop handing out new jobs.
    365 
    366 @item
    367 Tell every worker to give up, and @emph{join} them.  After this point
    368 no connection can be suspended any more: the workers resume before
    369 they exit, and the content reader only ever suspends while a worker is
    370 running.
    371 
    372 @item
    373 Keep running the event loop until the connections have drained, so
    374 that the last bytes actually reach the clients.
    375 
    376 @item
    377 @code{MHD_stop_daemon()}.
    378 @end enumerate
    379 
    380 @noindent
    381 Skipping the join in step two is the tempting shortcut, and it is the
    382 one that leaves a connection parked forever with nothing left alive to
    383 wake it.
    384 
    385 
    386 @heading Example code
    387 
    388 The complete program is available as @code{asyncresponse.c}.  It runs
    389 one external @code{select()} loop and serves four URLs:
    390 
    391 @table @code
    392 @item /
    393 A small page whose JavaScript opens the stream below and appends a row
    394 for every event as it arrives.  The rows visibly trickle in, one per
    395 step, which is the most direct demonstration of what the chapter is
    396 about.
    397 
    398 @item /events
    399 The stream: a response is queued at once, and the content reader
    400 suspends between steps.  The body is a sequence of server-sent events,
    401 which needs no library on the browser side.
    402 
    403 @item /slow
    404 The other pattern: the connection is suspended in the access handler
    405 and a complete answer is queued once the worker is done.
    406 
    407 @item /fast
    408 Answered on the spot.  The page has a button that requests it and
    409 reports the round trip time; it stays in the low milliseconds while
    410 jobs are running, which is the point of suspending rather than
    411 blocking.
    412 @end table
    413 
    414 @noindent
    415 The program takes the port, the duration of a step in milliseconds and
    416 the number of steps on the command line.  Passing @code{0} as the port
    417 makes the operating system choose a free one, which the program then
    418 reports via @code{MHD_DAEMON_INFO_BIND_PORT}:
    419 
    420 @verbatim
    421 $ ./asyncresponse 0 250 20
    422 Listening on port 44321
    423 @end verbatim
    424 @noindent
    425 
    426 The accompanying @code{test_asyncresponse.c} starts exactly that
    427 binary and checks over HTTP that @code{/slow} waits for its worker,
    428 that the body of @code{/events} really arrives in pieces spread over
    429 the lifetime of the request rather than in one burst at the end, that
    430 @code{/fast} is still served promptly while jobs are parked, that a
    431 client which hangs up in the middle takes neither the server nor the
    432 worker with it, and that the process exits cleanly when it is signalled
    433 while a connection is suspended.  It also compares the server's CPU
    434 time against the wall clock time of a transfer, which is the only one
    435 of those checks that notices the difference between a suspended
    436 connection and a busy-waiting one.
    437 
    438 
    439 @heading Remarks
    440 
    441 @emph{MHD} does not detect that a client has disconnected while a
    442 connection is suspended, and the connection timeout does not run
    443 either.  A suspended connection stays suspended until somebody resumes
    444 it, without exception.  Any timeout on the work itself is therefore the
    445 application's responsibility.
    446 
    447 Suspended connections still count against the connection limits, both
    448 the global one and the per-IP one.  A server that parks connections for
    449 minutes needs its limits sized for the number of jobs it expects to
    450 have in flight, not for the number it expects to be transmitting.
    451 
    452 If the client vanishes in the middle of a chunked response, the next
    453 write fails and @emph{MHD} logs it---with
    454 @code{MHD_USE_ERROR_LOG} enabled the example prints @code{Failed to
    455 send the chunked response body ... The socket is no longer available
    456 for sending}.  That is the normal course of events for an aborted
    457 download and not a sign of a problem.
    458 
    459 Finally, none of this is specific to @code{select()}.  The same
    460 argument holds for @code{poll()} and for @code{epoll}, where the
    461 daemon's descriptor can be obtained with
    462 @code{MHD_DAEMON_INFO_EPOLL_FD} and added to an epoll set of the
    463 application's own; @code{suspend_resume_epoll.c} among the
    464 distribution's examples shows that variant.
    465 
    466 
    467 @heading Exercises
    468 
    469 @itemize @bullet
    470 
    471 @item
    472 Give the jobs a deadline.  Since a suspended connection never times
    473 out on its own, add a check to the main loop that resumes---and
    474 answers with @code{503}---any job that has been running for too long,
    475 and confirm with a step duration long enough to trigger it.
    476 
    477 @item
    478 Remove the @code{MHD_suspend_connection()} call from the content
    479 reader, leaving only the @code{return 0}, and watch the server process
    480 with @code{top} while a single client downloads the stream.  Then put
    481 it back and watch again.  Both servers send the same bytes.
    482 
    483 @item
    484 Take the resume out of the worker's final block, so that a finished job
    485 leaves its connection parked, and then stop the server while a job is
    486 in flight.  Watch what the shutdown does---and what @code{valgrind}
    487 has to say about it---and work out which of the four steps above was
    488 violated.
    489 
    490 @item
    491 Replace the per-request thread with a fixed pool of worker threads and
    492 a queue of pending jobs.  The reference counting and the
    493 @code{abandoned} flag should not need to change at all; if they do, the
    494 ownership rules were not as clean as they looked.
    495 
    496 @item
    497 Serve the stream to two browser windows at once and confirm from the
    498 timestamps that the two jobs run concurrently and are interleaved by a
    499 single-threaded event loop.
    500 
    501 @end itemize