Skip to content
Advertisement

RPi2, OpenMAX, Deadlock

Environment

  • Raspberry Pi 2 B+
  • Debian Linux
  • OpenMAX IL

Use-case

  • OpenMAX Camera Video capture
    • Camera ports are disabled
    • Renderer / Camera Tunnel is set
    • All components state is set to Idle
    • Ports are enabled

Problem description

The first port being enabled to the Camera Input port ( Port #73 ), the port is being enabled using the “OMX_CommandPortEnable” command, as with the “OMX_CommandPortDisable” command, it is expected for the camera component to fire it’s “OMX_CALLBACKTYPE::EventHandler” event handler having “eEvent == OMX_EventCmdComplete” and “nData1 == OMX_CommandPortEnable”, however, this never happen and the application infinitely wait for the port to become enabled.

Problem Analysis

I am using std::condition_variable in conjunction with std::mutex to wait for the state change to complete, hence, OMX_CALLBACKTYPE::EventHandler updates the condition variable and calls “notify_one()” while the caller thread locks std::mutex and wait for the condition variable to be set, using this approach “OMX_CALLBACKTYPE::EventHandler” is never called ( with any argument ), and the program locks forever.
NOTE: When waiting for the condition variable the mutex is verified not to be owned, this is done by verifying (0 == std::mutex::__owner).
HOWEVER, All works fine when polling the status of the port by calling usleep and OMX_GetParameter(OMX_IndexParamPortDefinition) iteratively.

Question at hand

Why is “OMX_CALLBACKTYPE::EventHandler” triggered when polling it’s value and NOT triggered when using a conditional_variable? With windows there is the notion of APC & Alertable threads, is there any equivalent in linux? One that can explain the above mentioned?

Advertisement

Answer

My experience is that enabling a port does not issue the event callback until the port is populated with buffers. That is, the sequence is:

  • Set port to enabled (OMX_SendCommand() with OMX_CommandPortEnable).
  • Populate port buffers (OMX_AllocateBuffer() or OMX_UseBuffer()).
  • Receive OMX_CommandPortEnable event callback.

If you wait for the event callback before you allocate the buffers then you will have deadlock.

When you poll by testing OMX_PARAM_PORTDEFINITIONTYPE.bEnabled, that is going to return OMX_TRUE immediately because the spec says this member is set synchronously:

The port shall immediately set bEnabled in its port definition structure when the port receives OMX_CommandPortEnable.

Here’s what I think is happening for you when things “work”:

  • Set port to enabled.
  • Poll until bEnabled is OMX_TRUE (which happens immediately).
  • Populate port buffers.
  • Receive OMX_CommandPortEnable event callback.

You may be mistakenly thinking that it happens in this order instead:

  • Set port to enabled.
  • Poll until bEnabled is OMX_TRUE (which happens immediately).
  • Receive OMX_CommandPortEnable event callback.
  • Populate port buffers.

This makes it seem that using a condition variable somehow changes OpenMAX behavior. In actuality bEnabled and the OMX_CommandPortEnable callback aren’t really reporting the same thing. I don’t believe that any synchronization is necessary (or desirable) between enabling the port and allocating its buffers.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement