Devctl() block state issue with TimerTimeout

Description: Below is the functionality to detect the Video process on the network is alive or not. The functionality works fine when the video process is alive.

Whenever the Video process is killed or the network cable is disconnected, the devctl() goes into indefinite block state, which results the system hung.

What code changes do we need to do to unblock after the timer is expired? Please help.

Code Snippet Start
Main():
videoCamFileDescriptor = open(CAMERA_PROC_DNAME_NET, O_RDWR);
if (videoCamFileDescriptor < 0) {
exit(EXIT_FAILURE);
}

//Thread with 1 second timer:
uint64_t ipc_timeout = 1000000000L;
struct sigevent qevent;

vm_cmnd.id = __DIOTF(_DCMD_MISC, _DCMD_VM_HEARTBEAT_CMD , vm_cmnd_t);
qevent.sigev_notify = SIGEV_UNBLOCK;
TimerTimeout(CLOCK_REALTIME, _NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY, &qevent, &ipc_timeout, NULL);
ipc_err = devctl(videoCamFileDescriptor, vm_cmnd.id, &vm_cmnd, sizeof(vm_cmnd_t), NULL);

if (ipc_err == EOK) {
// Working OK
} else {
// Not Working
}
Code Snippet End

Thank you all.

The _DCMD_VM_HEARTBEAT_CMD is obviously coming from the remote camera process. If that process dies or you disconnect the cable, there is no way for that command to be sent back to your process so that’s why it’s hanging indefinitely in devctl.

A quick way to get around this is to put JUST the devctl call code into it’s own thread. When it returns with EOK, you increment a counter. Then in your main thread (where the TimerTimeout call is) when the timer expires you just check to see if the counter incremented and if it did, you know everything is fine.

Tim

Hi Tim,

Thank you for the response.

Below code is called in a separate thread. The videoCamFileDescriptor is only in Main where videoCamFileDescriptor initializes only one time. Sorry for the confusion.

Thread with 1 second timer:
uint64_t ipc_timeout = 1000000000L;
struct sigevent qevent;

vm_cmnd.id = __DIOTF(_DCMD_MISC, _DCMD_VM_HEARTBEAT_CMD , vm_cmnd_t);
qevent.sigev_notify = SIGEV_UNBLOCK;
TimerTimeout(CLOCK_REALTIME, _NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY, &qevent, &ipc_timeout, NULL);
ipc_err = devctl(videoCamFileDescriptor, vm_cmnd.id, &vm_cmnd, sizeof(vm_cmnd_t), NULL);

if (ipc_err == EOK) {
// Working OK
} else {
// Not Working
}

Here we thought that the TimerTimeout() will unblock the devctl after 1 second timeout. Is this correct?

Is there any other way to unblock devctl?

Thank you.

TimerTimeout is just a timer that sleeps for the amount of time you request and when it finishes, it sets values in the notification structure you provide (qevent in your code). It will not unblock devctl which it knows nothing about.

You can unblock devctl in a lot of ways. See all the DCMD ways here:
https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.devctl/topic/about.html
But figuring out which ones you need may be a bit of a pain because you are going across the network.

For simplicity, I’d code things as follows:

Global Variable
int mCameraAliveCounter = 0;

Thread 1:

int lastCameraAliveCounter = 0;
while (1)
{
    lastCameraAliveCounter = mCameraAliveCounter;
    sleep (1000);
    if (lastCameraAliveCounter == mCameraAliveCounter)
   {
       // Camera is offline for 1 second so do something.
   }
}

Thread 2:

while (1)
{
    // Query camera 5x a second (may need to be more or less if camera can't respond that often)
    sleep (200);
    vm_cmnd.id = __DIOTF(_DCMD_MISC, _DCMD_VM_HEARTBEAT_CMD , vm_cmnd_t);
    ipc_err = devctl(videoCamFileDescriptor, vm_cmnd.id, &vm_cmnd, sizeof(vm_cmnd_t), NULL);

    if (ipc_err == EOK) {
        // Update Camera Alive Counter;
        mCameraAliveCounter++; 
    } else {
      // Not Working
   }
}

Tim

1 Like