1

I want to use a single thread to process socket incoming data and do some actions when the semaphore gets unlocked. According to this thread

Can we obtain a file descriptor for a semaphore or condition variable?

I can't use the select system call for this. Now I'm trying something like this using signals instead of select(). But I can't get rid of possible race conditions.

static int         dataReady;  // Socket data ready flag
static int         fd;         // Socket file descriptor
static int32*      pldSemId;   // Semaphore identifier

void sigioHandler(int /* sig */){
    dataReady = 1;
}

void tryReceiveData(){
    disableSignals();
    int  len;
    char buf[8192];

    struct sockaddr_nl sourceaddr;
    struct iovec iov = { buf, sizeof(buf) };
    struct msghdr msg;
    struct nlmsghdr *nh;

    if (!dataReady){
        enableSignals();
        return;
    }

    msg = { &sourceaddr, sizeof(sourceaddr), &iov, 1, NULL, 0, 0 };
    len = recvmsg(fd, &msg, MSG_DONTWAIT);
    ...        

    dataReady = 0;
    enableSignals();
}

void doSemaphoreActions(){
    int r;
    sops.sem_num = 0;
    sops.sem_op = -1;
    sops.sem_flg = 0; // wait and blocked

    if (semop(*pldSemId, &sops, 1) == -1) {
        if (errno == EINTR){
            return;
        }
        // Process other possible errors
        ...
    }

    // Do something useful
    ...
}

int main(){
    // Open and configure the socket
    fd = socket(...);
    ...
    // Configure the signal handler
    signal(SIGIO, sigioHandler);
    fcntl(fd, F_SETOWN, getpid());
    fcntl(fd, F_SETFL, O_ASYNC);

    // Configure the semaphore
    ...

    while (true){
        tryReceiveData();
        // SIGIO signal may be received here so we won't
        // process socket data until the next SIGIO arrives
        // or the semaphore gets unlocked
        doSemaphoreActions();
    }
}

Is there a way to disable signal handlers when the thread is in the "running" state? Or maybe there is a better solution?

valentin
  • 175
  • 3
  • 7

0 Answers0