On 1/27/22 06:02, Jacek Caban wrote:
On 1/27/22 00:52, Zebediah Figura (she/her) wrote:
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.
Did you consider moving whole sock_send() and try_send() to server? We could then have a proper and reliable queue in server socket object and client could just do a regular generic server ioctl. (I didn't really follow closely the conversation, so sorry if I missed something).
That's actually a good point, thanks for making it. I think I actually did consider this when first moving things around, but decided against it on the grounds of keeping stuff out of the server...
Note that we do have to deal with scatter/gather, and the control and address in recvmsg, so it can't quite do a generic ioctl, we'd still need to use a special async I/O proc on the ntdll side. But it does obviate the need to change the async infrastructure at all.
One possible concern is that we'd end up doing a lot of large copies over the server request sockets. It's not clear to me if that's anything to worry about.