none
Possible Race Condition? RRS feed

  • Question

  • Hello,

    I have this snipped of code, that is supposed to asynchronously connect to a Bluetooth LE device:

    extern "C" void async_connect_impl(
        connect_callback    connect_cb,
        void*               context,
        const void*         plattform_specific_identification )
    {
        std::uint64_t remote_addr = *static_cast< const uint64_t* >( plattform_specific_identification );
    
        ComPtr< IBluetoothDeviceStatics > statics;
        check( GetActivationFactory( HString::MakeReference( RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice ).Get(), &statics ) );
    
        ComPtr< IAsyncOperation< BluetoothDevice* > > completion;
        statics->FromBluetoothAddressAsync( remote_addr, &completion );
    
        check( completion->put_Completed(
            Callback< IAsyncOperationCompletedHandler< BluetoothDevice* > >(
            [ connect_cb, context ]( IAsyncOperation< BluetoothDevice* >* op, AsyncStatus status ) -> HRESULT
            {
                if ( status == Completed )
                {
                    ComPtr< IBluetoothDevice > device;
                    check( op->GetResults( &device ) );
                    handle_connect( device, connect_cb, context );
                }
    
                return S_OK;
            }).Get()
        ) );
    }
    

    According to the documentation, FromBluetoothAddressAsync() initiates a connection. Now the order is: first, initiate a connection; second: add a callback to be called, when the connection is established.

    In general, I would say that this order can lead to race conditions, in cases, where the connection is initiated _and_ established, before the callback is added. Unfortunately, I can not see, how I could change the order.

    I there a way to first create the asynchronous operation (and add the callback) and then start the connection establishment? Or if this code is safe and free of race conditions: why?

    Thanks in advance and kind regards,

    Torsten

    Wednesday, October 4, 2017 12:42 PM

All replies

  • Hi again Torsten,

    You may recall from a previous message to you on another thread I state, "Construction of that object doesn't necessarily create a connection." There is no way to have an application directly participate in the connection establishment by design. The platform decided when to connect and disconnect. Perhaps if you can share more about what you are trying to achieve I can help.

    You're code does have a race condition. You need to construct the callback before passing it in the method. We don't have a public C++ sample to reference on this sorry. I'll see if I can extract some test code and reply later today.

    Wednesday, October 4, 2017 6:04 PM
  • Hi Frank,

    sorry, I've mixed BluetoothDevice and BluetoothLEDevice. Both have a static FromBluetoothAddressAsync() member function. The LE version states, that it initiates a connection (Returns a BluetoothLEDevice object for the given BluetoothAddress and initiates a connection.).

    Does my question makes more sense with this correction?

    In general, I try to write a tiny abstraction, that allow me to write C++ code and to think in Bluetooth LE procedures (as defined by the BT core spec), that runs the same code on Windows, OS/X, and Linux.

    My current task at hand is to write a client that connects to a BLE Bootloader to see what bandwidth I can archive with Windows as a client to evaluate a product idea (a BLE SWD/JTAG Debug Adapter). That Bootloader doesn't support Pairing nor Binding, as firmware updates are already encrypted and signed, so there is simply no point in pairing.

    Currently, I'm stuck with the call to BluetoothLEDevice::FromBluetoothAddressAsynch() from C++, because I'm unable to create a IBluetoothLEDeviceStatics (see other thread).

    Again, thank you very much,

    Torsten

     

    Wednesday, October 4, 2017 6:26 PM