[PATCH v4 3/4] windows.media.speech: Implement concurrency in IAsyncOperation.

Bernhard Kölbl besentv at gmail.com
Wed Apr 20 11:29:03 CDT 2022


Am Di., 19. Apr. 2022 um 15:08 Uhr schrieb Rémi Bernon
<rbernon at codeweavers.com>:
>
> On 4/18/22 23:42, Bernhard Kölbl wrote:
> > Signed-off-by: Bernhard Kölbl <besentv at gmail.com>
> > ---
> >   dlls/windows.media.speech/async.c        | 123 ++++++++++++++++++++++-
> >   dlls/windows.media.speech/private.h      |   4 +-
> >   dlls/windows.media.speech/recognizer.c   |   7 +-
> >   dlls/windows.media.speech/tests/speech.c |  22 ++--
> >   4 files changed, 141 insertions(+), 15 deletions(-)
> >
> > diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c
> > index cf0da23e493..66cba46d85b 100644
> > --- a/dlls/windows.media.speech/async.c
> > +++ b/dlls/windows.media.speech/async.c
> > @@ -40,7 +40,13 @@ struct async_operation
> >       LONG ref;
> >
> >       IAsyncOperationCompletedHandler_IInspectable *handler;
> > +    IInspectable *result;
> >
> > +    async_operation_worker worker;
>
>
> IMHO "callback" is more commonly used and more appropriate name than
> "worker".
>

Sure. I used "worker" because the threadpool callback is already named
like that, so a possbile confusion would be eliminated.

>
> > +    TP_WORK *async_run_work;
> > +    IInspectable *invoker;
> > +
> > +    CRITICAL_SECTION cs;
> >       AsyncStatus status;
> >       HRESULT hr;
> >   };
>
>
>
> > @@ -299,7 +345,65 @@ static const struct IAsyncInfoVtbl async_operation_info_vtbl =
> >       async_operation_info_Close
> >   };
> >
> > -HRESULT async_operation_create( const GUID *iid, IAsyncOperation_IInspectable **out )
> > +static void CALLBACK async_run_cb(TP_CALLBACK_INSTANCE *instance, void *data, TP_WORK *work)
> > +{
> > +    IAsyncOperation_IInspectable *operation = data;
> > +    struct async_operation *impl = impl_from_IAsyncOperation_IInspectable(operation);
> > +    IInspectable *result = NULL, *invoker = NULL;
> > +    async_operation_worker worker;
> > +    HRESULT hr;
> > +
> > +    EnterCriticalSection(&impl->cs);
> > +    if (impl->status == Canceled)
> > +        goto abort;
> > +
> > +    impl->status = Started;
>
>
> Should it really ignore and overwrite the Closed status here?
>
> Or perhaps instead treat it as cancellation, as it means the client
> probably doesn't care about the result anymore?

Right, I use Closed as the default/init state, that's why it is
overwritten here.
So not sure if it needs a change?

>
> > +
> > +    invoker = impl->invoker;
> > +    worker = impl->worker;
> > +    LeaveCriticalSection(&impl->cs);
> > +
> > +    hr = worker(invoker, &result);
> > +
> > +    EnterCriticalSection(&impl->cs);
> > +    if (FAILED(hr))
> > +        impl->status = Error;
> > +    else
> > +        impl->status = Completed;
> > +
> > +    impl->result = result;
> > +    impl->hr = hr;
> > +
> > +    if (impl->status == Canceled)
> > +        goto abort;
>
>
> This condition will never be true as you just wrote the status above. I
> think you can consider that if the callback had been called it's too
> late for it to be cancelled.
>

The idea is to cancel the invoication of the handler, i.e. leaving the
thread asap.
The condition can be true if you call cancel during the call to worker/callback.

>
> > +
> > +    if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET)
> > +    {
> > +        IAsyncOperationCompletedHandler_IInspectable *handler = impl->handler;
> > +        AsyncStatus status = impl->status;
> > +
> > +        IAsyncOperation_IInspectable_AddRef(operation);
> > +        IAsyncOperationCompletedHandler_IInspectable_AddRef(handler);
> > +        LeaveCriticalSection(&impl->cs);
> > +
> > +        IAsyncOperationCompletedHandler_IInspectable_Invoke(handler, operation, status);
> > +
> > +        IAsyncOperationCompletedHandler_IInspectable_Release(handler);
> > +        IAsyncOperation_IInspectable_Release(operation);
>
>
> I don't think you need to add all these references here, you already
> hold one on the operation and on the handler.

Yeah.

>
>
> > +    }
> > +    else
> > +        LeaveCriticalSection(&impl->cs);
> > +
> > +    IAsyncOperation_IInspectable_Release(operation);
> > +    return;
> > +
> > +abort:
> > +    impl->hr = E_FAIL;
> > +    LeaveCriticalSection(&impl->cs);
> > +    IAsyncOperation_IInspectable_Release(operation);
> > +}
> > +
>
>
> It will be hard to check, but I think you need to invoke the handler
> even in the Cancel case, as MSDN suggests:
>
> > If you're implementing IAsyncOperation<TResult>, then the set
> > implementation of Completed should store the handler, and the
> > surrounding logic should invoke it when Close is called. The
> > implementation should set the asyncStatus parameter of invoked
> > callbacks appropriately if there is a Cancel call, Status is not
> > Completed, errors occurred, and so on.
>

Yeah, seems odd but I can change it.

Bernhard



More information about the wine-devel mailing list