1

So, according to manual, pselect can have a timeout parameter and it will wait if no file-descriptors are changing. Also, it has an option to be interrupted by a signal:

sigemptyset(&emptyset);    /* Signal mask to use during pselect() */
res = pselect(0, NULL, NULL, NULL, NULL, &emptyset);
if (errno == EINTR) printf("Interrupted by signal\n");

It is however not obvious from the manual which signals are able to interrupt pselect?

If I have threads (producers and consumers), and each (consumer)thread is using pselect, is there a way to interrupt only one (consumer)thread from another(producer) thread?

Daniel
  • 2,318
  • 2
  • 22
  • 53
  • 1
    `if (errno == EINTR)` <<-- you should only test errno if pselect() returns -1. In other cases its value is basically undefined. – wildplasser Mar 31 '20 at 09:58

2 Answers2

1

i think the issue is analyzed in https://lwn.net/Articles/176911/

For this reason, the POSIX.1g committee devised an enhanced version of select(), called pselect(). The major difference between select() and pselect() is that the latter call has a signal mask (sigset_t) as an additional argument:

int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);

pselect uses the sigmask argument to configure which signals can interrupt it

The collection of signals that are currently blocked is called the signal mask. Each process has its own signal mask. When you create a new process (see Creating a Process), it inherits its parent’s mask. You can block or unblock signals with total flexibility by modifying the signal mask.

source : https://www.gnu.org/software/libc/manual/html_node/Process-Signal-Mask.html

https://linux.die.net/man/2/pselect

https://www.linuxprogrammingblog.com/code-examples/using-pselect-to-avoid-a-signal-race

Because of your second questions there are multiple algorithms for process synchronization see i.e. https://www.geeksforgeeks.org/introduction-of-process-synchronization/ and the links down on this page or https://en.wikipedia.org/wiki/Sleeping_barber_problem and associated pages. So basically signals are only one path for IPC in linux, cf IPC using Signals on linux

ralf htp
  • 9,149
  • 4
  • 22
  • 34
  • For the first, thanks. but for second: I need something which can interrupt threadA's pselect from threadB while not interrupting threadC (or threadC's pselect). – Daniel Mar 30 '20 at 09:07
  • if it is strictly defined which processes communicate with each other you can use IPC sockets for this https://opensource.com/article/19/4/interprocess-communication-linux-networking and https://de.wikipedia.org/wiki/POSIX_local_inter-process_communication_socket – ralf htp Mar 30 '20 at 09:12
  • "signals are only one path for IPC in linux" - sure, the only reason for signals is interrupting pselect. If I could interrupt it anyhow else I prefer not using any signals – Daniel Mar 30 '20 at 09:22
  • No interrupting pselect using signals is good, however for implementing producer-consumer IPC signals are not the first choice (https://stackoverflow.com/questions/48381628/how-to-implement-producer-consumer-using-processes), so possibly mix the IPC mechanisms ? – ralf htp Mar 30 '20 at 09:24
  • yes, possibly, but I it just don't feel right. I might drop pselect for some more modern approach (libevent or libev). Thanks! – Daniel Mar 30 '20 at 09:29
1

(Ignoring all the signal's part of the question, and only answering to

If I have threads (producers and consumers), and each (consumer)thread is using pselect, is there a way to interrupt only one (consumer)thread from another(producer) thread?"

, since the title does not imply the use of signals).

The easiest way I know is for the thread to expose a file descriptor that will always included in the p/select monitored descriptors, so it always monitor at least one. If other thread writes to that, the p/select call will return:

struct thread {
    pthread_t tid;
    int wake;
    ...
}

void *thread_cb(void *t) {
    struct thread *me = t;
    t->wake = eventfd(0, 0);
    ...
    fd_set readfds;
    // Populate readfds;
    FD_SET(t->wake, &readfds);
    select(...);
}

void interrupt_thread(struct thread *t) {
    eventfd_write(t->wake, 1);
}

If no eventfd is available, you can replace it with a classic (and more verbose) pipe, or other similar communication mechanism.

eugenioperez
  • 627
  • 7
  • 15