On 1/23/22 11:29, Jinoh Kang wrote:
+static int async_add_queue( struct object *obj, struct wait_queue_entry *entry ) +{
- struct async *async = (struct async *)obj;
- assert( obj->ops == &async_ops );
- if (!async->pending && async->terminated && async->alerted)
- {
/* The client has failed to complete synchronously (e.g. EWOULDBLOCK).
* Restart the async as fully fledged asynchronous I/O, where
* the completion port notification and APC call will be triggered
* appropriately. */
async->pending = 1;
/* Unset the signaled flag if the client wants to block on this async. */
if (async->blocking) async->signaled = 0;
async_set_result( obj, STATUS_PENDING, 0 ); /* kick it off */
- }
- return add_queue( obj, entry );
+}
I'll admit, this kind of thing is why I didn't really want to have to try to optimize 3 server calls into 2. Asyncs are already really complicated, in terms of the many paths they can take, and it seems like no matter what we do they're going to get worse.
Still, I have a potential idea.
What we need to do here is similar to the infrastructure that already exists for device asyncs, namely "unknown_status" etc. It would be nice to use that instead of reinventing it, and although I haven't tried, it seems possible.
async_add_queue() as it is above is not great. I'm not sure that code actually works in every case; it definitely increases the mental burden even if it does. (Consider for instance that it would be triggered for *every* async).
Instead what I'd suggest is to use the request introduced here in every case, even if the initial status was pending. This introduces a new server call, but it only does so in cases where we already have to wait.
The end result would be not unlike get_next_device_request, which is essentially that request combined with some other things (and it doesn't deal in async object handles).