On Mon, 5 Aug 2013, Graham Leggett wrote: > Are you seeing a specific problem?
Well, when I download a large file over a slow link, the request does not enter write completion state but rather the worker thread is still hogged for (nearly) the entire download. > The way openssl's async behaviour works, is that is the middle of a > read, openssl might need to write, and in the middle of a write, openssl > might need to read. Openssl tells you this through the codes > SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE. You receive these codes, > re-run the select or poll or whatever with the sense that openssl has > asked for, and you're done. It is that simple. AFAICT, that part is ok. But it doesn't solve the problem that one thread is hogged for every ssl connection. > Sure, httpd might do all sorts of buffering of reads and writes, but at > the end of the day it won't matter, because openssl will never attempt > to write-during read or read-during-write without asking you whether it > is ok first. > > I can see a potential problem if the core decided to buffer a write, but > in theory that could be solved by mod_ssl simply sending a flush bucket > down the stack whenever the sense changes. I don't see why the core > needs to care that the data is a file, or encrypted, or whatever, the > core should just do what the core does. Let me recap the way async works in mpm event: There is no way to interrupt and resume the handler, so the handler always must run to completion. The only way async write completion can work is if the data produced by the handler is buffered and is later sent bit by bit in an async way. However, this cannot be done unconditionally or the memory usage would grow to infinity. Therefore the core output filter has some heuristics on when to buffer data for async write completion and when to do blocking writes instead. In general, if there is more than 64k of data in memory, this is written to the network in a blocking way. Only if the buckets are backed by files (and therefore do not use significant memory before being sent to the network), more than 64k of request data is put into async write completion. This is where mod_ssl comes in. It will read the file buckets, encrypt them, and then we have encrypted data in memory that will cause the core output filters to do blocking writes. The blocking writes happen while the handler does ap_pass_brigade() and therefore before the worker thread which executes the handler is freed. An ideal solution would put the buffering/decision for blocking/non-blocking into ap_pass_brigade(). This way other filters like deflate could also be called asynchronously. But I am not too optimistic that this can be achieved without API changes.