Darshan Shah
Darshan Shah

Reputation: 3

System V msgrcv blocking in thread

I have an application which has signal handler and created a thread to handle message queue. Below is signal Handler,

   /*! \Register handle on SIGINT. */
   signal(SIGINT, CloseHandler);

VOID CloseHandler(INT32 sig)
{
if(sig == SIGINT)
gAppExitFlag = 1;
return;
}

I have created a joinable thread to receive message queue,

      /* Initialize and set thread detached attribute */
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  if(0 != (count = pthread_create(&ModemDetectionHandel, &attr, &ModemDetectionOperation, (void *)&gAppContext)))
  {
     DS3_ERROR(DS3_TELEMETRY_APP, "Error in creating thread ModemDetectionOperation");
  }

In thread, I have created a message queue and call msgrcv with msgflg 0. So it will block until any message receive. Now when I send SIGINT to process but msgrcv don't come back and thread block in msgrcv.

My application get stuck in joining thread.

As per msgrcv man page " * The calling process catches a signal. In this case the system call fails with errno set to EINTR. (msgrcv() is never automatically restarted after being interrupted by a signal handler, regardless of the setting of the SA_RESTART flag when establishing a signal handler.)"

Why thread/msgrcv don't get signal? If I make thread as a main loop then it comes back and application exit successfully.

Upvotes: 0

Views: 916

Answers (1)

Florian Weimer
Florian Weimer

Reputation: 33704

If a signal is sent to a process, one thread which has not blocked it will handle it, but it is unspecified which thread this will be. You said that you have not blocked SIGINT on all the other threads. So the most likely explanation for the behavior you see is that the signal is handled by the main thread, and not the thread which calls msgrcv.

To fix this, you could block SIGINT on all threads except the thread that calls msgrcv. This will ensure that the signal is handled by that thread.

If you have multiple threads which need to be interrupted, this won't work. In this case, you will probably need to block SIGINT for all threads, and use sigwait in a special interrupt-handling thread to receive the SIGINT signal. This thread then can send another signal (perhaps SIGUSR1) to all threads which need to be interrupted, with one pthread_kill for each such thread. Or maybe you can use pthread_cancel as well, depending on what your needs are.

Upvotes: 1

Related Questions