This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Using signals to unblock calls to msgrcv() in a multi-threaded process (Cygwin v1.7.33)


I have a multi-threaded process running under Cygwin that receives messages from several IPC message queues (built using Cygwin's gcc, version 4.8.3).  The listener for each queue runs in its own thread, each of which is created from the main thread.  Each listener is using a blocking call to msgrcv().  I want the main thread to be able to use pthread_kill() to send a SIGUSR1 signal to each listening thread to cause it to abandon its call to msgrcv() and then exit.  

My approach has been to create a signal mask containing just SIGUSR1 and associate this with a signal handler (although the signal handler contains no functionality, since all I need is for the blocking call to msgrcv() to be abandoned).  I initially set the signal mask to block in the main thread, which should then be inherited by each of the created listening threads.  I only unblock the signal mask around the call to msgrcv() in each listening thread.

I have included a simplified version of my code below.  I usually don't see any evidence of the SIGUSR1 signal being received by either of the listener threads.  Occasionally the first thread unblocks as expected but I have never seen both threads unblock.  If I change my code so that there is only a single listener thread, then everything works correctly every time.  Changing the msgrcv() call to a sleep call also allows unblocking to occur correctly.  Note that this simplified code does not include removal of the created queues (since it never manages to exit anyway) so I manually remove these after each run using the ipcrm command.

Example output:

Running thread 2 with queue Id = 1441792
Running thread 1 with queue Id = 1179649
About to kill thread 1

Is there an issue with the Cygwin implementation of signal handling, or is there a problem with my code?  Any help would be much appreciated.


#include <iostream>
#include <stdexcept>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>

using namespace std;

void SigHandler(int signal)
{
}

struct message {long id;} msg;

static void* threadMain(void* lpParam)
{
    int threadNumber = *(int*)lpParam;

    // Set a signal mask for this thread with just SIGUSR1 set
    sigset_t signalMaskUsr;
    sigemptyset(&signalMaskUsr);
    sigaddset(&signalMaskUsr, SIGUSR1);

    try
    {
        // Create an IPC message queue
        key_t key = ftok("/tmp", threadNumber);
        int id = msgget(key, IPC_CREAT|IPC_EXCL);
        if (id == -1)
            throw runtime_error("Failed to create message queue");

        cout << "Running thread " << threadNumber << " with queue Id = " 
             << id << endl;

        // Unblock the signal mask while in the msgrcv() call
        if (pthread_sigmask(SIG_UNBLOCK, &signalMaskUsr, NULL) != 0)
            throw runtime_error("Failed to unblock SIGUSR1 message queue");

        if (msgrcv(id, (void *)&msg, sizeof(msg), 0, MSG_NOERROR) == -1)
            throw runtime_error("Failed to receive data on message queue");

        if (pthread_sigmask(SIG_BLOCK, &signalMaskUsr, NULL) != 0)
            throw runtime_error("Failed to block SIGUSR1 message queue");

        cout << "Exiting thread (thread number = " << threadNumber 
             << ", queue id = " << id << ")" << endl;
    }
    catch (runtime_error& e)
    {
        cout << "Error: " << e.what() << endl;
    }

    return NULL;
}


int main()
{
    // Create a signal mask for the main thread with just SIGUSR1 set
    sigset_t sigMask;
    sigemptyset(&sigMask);
    sigaddset(&sigMask, SIGUSR1);

    // Initially block the SIGUSR1 signal
    if (pthread_sigmask(SIG_BLOCK, &sigMask, NULL) != 0)
        throw runtime_error("Failed to initialise signal mask");

    // Setup the Signal Handler for the signal mask
    struct sigaction actionStruct;
    actionStruct.sa_flags = 0;
    actionStruct.sa_mask = sigMask;
    actionStruct.sa_handler = SigHandler;
    sigaction(SIGUSR1, &actionStruct, NULL);

    try
    {
        // Create two new threads, passing in parameters of '1' and '2'
        pthread_t h1;
        pthread_t h2;
        int t1 = 1;
        int t2 = 2;

        if (pthread_create(&h1, NULL, threadMain, (void*)&t1) != 0)
            throw runtime_error("Failed to create Thread 1");

        if (pthread_create(&h2, NULL, threadMain, (void*)&t2) != 0)
            throw runtime_error("Failed to create Thread 2");

        // Allow time for thread creation to have completed
        sleep(1);

        cout << "About to kill thread 1" << endl;
        if (pthread_kill(h1, SIGUSR1) != 0)
            throw runtime_error("Failed to kill Thread 1");

        if (pthread_join(h1, NULL) != 0)
            throw runtime_error("Failed to join Thread 1");

        cout << "About to kill thread 2" << endl;
        if (pthread_kill(h2, SIGUSR1) != 0)
            throw runtime_error("Failed to kill Thread 2");

        if (pthread_join(h2, NULL) != 0)
            throw runtime_error("Failed to join Thread 2");
    }
    catch (runtime_error& e)
    {
        cout << "Error: " << e.what() << endl;
    }

    return 0;
}

Attachment: cygcheck.out
Description: cygcheck.out

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]