[RFC PATCH v4 1/5] server: Allow calling async_handoff() with status code STATUS_ALERTED.
Zebediah Figura
zfigura at codeweavers.com
Thu Feb 3 12:20:59 CST 2022
On 2/3/22 09:28, Jinoh Kang wrote:
> On 2/3/22 08:45, Zebediah Figura wrote:
>> On 1/29/22 01:47, Jinoh Kang wrote:
>
> ...
>
>>> diff --git a/server/async.c b/server/async.c
>>> index 7aef28355f0..e169bb23225 100644
>>> --- a/server/async.c
>>> +++ b/server/async.c
>>> @@ -338,6 +338,30 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_
>>> return async->wait_handle;
>>> }
>>> + if (!async->pending && get_error() == STATUS_ALERTED)
>>
>> Why "!async->pending"?
>
> The rationale is twofold:
>
> 1. async_handoff() can be called with "async->pending = 1".
> Notably the device manager and some sock IOCTLs call set_async_pending() before returning.
> Also, there exists another conditional statement below which explicitly tests for "async->pending".
Yes, but they don't set the last error to STATUS_ALERTED, do they?
Anything that's triggered below should only apply to asyncs whose
initial status is known. Consider that "unknown_status" not only means
the initial NTSTATUS is unknown, but it also means the initial pending
state is unknown.
>
> 2. If "async->pending && get_error() == STATUS_ALERTED", the async will be left in an inconsistent state.
>
> - There exists an established invariant that "async->unknown_status" implies "!async->pending".
> It would be invalid that "async->unknown_status && async->pending", since an async
> "even the initial state" of which "is not known yet" cannot possibly be queued as STATUS_PENDING.
>
> - Unless "async->direct_result", an APC_ASYNC_IO is required for the async to progress;
> Our code path however issues no APC calls, leaving the async in a stale, hard-to-debug state.
>
> That said, an alternative would be to simply "assert( !async->pending )" inside the new code path.
> However, I don't really see a reason to reject STATUS_ALERTED on a pending async; we can let it
> simply follow the normal path, allowing the async to be terminated with STATUS_ALERTED as usual.
> I think this best sticks to the principle of least surprise. It's entirely my own perspective, though...
If you consider the above, "async->pending" is semantically undefined if
async->unknown_status is 1. We shouldn't depend on it being one thing or
the other, and checking for that (even in an assert) I think gives the
wrong idea that we care.
>
>>
>>> + {
>>> + /* Give the client opportunity to complete synchronously.
>>> + * If it turns out that the I/O request is not actually immediately satiable,
>>> + * the client may then choose to re-queue the async (with STATUS_PENDING).
>>
>> I'd explicitly mention *how* the async should be requeued here.
>
> I worded it that way since each I/O operation can have their own way to manage their async queue
> (e.g. socket operations would use sock->read_q/write_q, device managers would use its own IRP queue,
> while others may just use fd->read_q/write_q). I chose to retain the abstractness so that the comment would't get easily stale or out of date.
>
> That said, I suppose you specifically meant mentioning how to _transition_ the async to STATUS_PENDING.
> I agree with you in that case. I'll add a mention of the new wineserver call here.
Yeah, that's what I meant :-)
>
>>
>>> + */
>>> + async->unknown_status = 1;
>>> +
>>> + /* Deactivate async so that it can be safely queued.
>>> + * Otherwise, the async will be erroneously alerted the next time
>>> + * someone calls async_wake_up() on the queue.
>>
>> Not to put too much weight on my own perspective, but I think it's clearer to explain *why* to do something, rather than why not.
>
> By "why not" did you meant the "otherwise" part?
>
>> In this case, what we're doing is mimicking a normal "alert" case, except that we're not using an APC.
>
> If I understood correctly, I should just say instead:
>> Emulate calling async_terminate() with STATUS_ALERTED (request client to complete I/O),
>> but don't actually queue APC_ASYNC_IO under any circumstances.
> Is this correct?
Something more like that, yeah. Although, to contradict my earlier
assertion, I think it'd also help to explain what's wrong with using
APC_ASYNC_IO here.
More information about the wine-devel
mailing list