This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
RFC: POSIX timers and threads in a realtime context
- From: "Warlich, Christof" <christof dot warlich at siemens dot com>
- To: "libc-alpha at sourceware dot org" <libc-alpha at sourceware dot org>
- Date: Mon, 5 Oct 2015 15:04:31 +0000
- Subject: RFC: POSIX timers and threads in a realtime context
- Authentication-results: sourceware.org; auth=none
Hi,
looking at the glibc timer API, there is a Linux-specific interface to send timer events to a dedicated thread belonging to the current process:
$ man timer_create
...
SIGEV_THREAD_ID (Linux-specific)
As for SIGEV_SIGNAL, but the signal is targeted at the thread
whose ID is given in sigev_notify_thread_id, which must be a
thread in the same process as the caller. The sigev_notify_thread_id
field specifies a kernel thread ID, that is, the value returned by
clone(2) or gettid(2). This flag is intended only for use by threading
libraries.
...
But as this interface requires a Linux kernel thread id, it allows to only set up timer events being sent to the _current_ thread using the gettid() system call, because gettid() only returns the tid of the current thread. To facilitate the discussion, the example below shows some working code. You may just copy and paste it to a terminal to compile and run:
$ cat << EOF | gcc -xc - -pthread -lrt && ./a.out
#include <pthread.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/syscall.h>
int main(void) {
struct timespec period = {1, 0};
struct itimerspec itime = {period, period};
timer_t timer;
siginfo_t info;
sigset_t set;
struct sigevent event;
pid_t tid = syscall(SYS_gettid);
memset(&event, 0, sizeof(event));
event.sigev_notify = SIGEV_THREAD_ID;
event.sigev_signo = SIGRTMIN;
event._sigev_un._tid = tid;
event.sigev_value.sival_ptr = (void *) 0xdeadbeef;
assert(timer_create(CLOCK_MONOTONIC, &event, &timer) == 0);
assert(timer_settime(timer, 0, &itime, 0) == 0);
sigemptyset(&set);
sigaddset(&set, SIGRTMIN);
assert(!pthread_sigmask(SIG_BLOCK, &set, NULL));
while(1) {
assert(sigwaitinfo(&set, &info) == SIGRTMIN);
printf("Got signal %d with value %p\n", info.si_signo, info.si_ptr);
}
return 0;
}
EOF
Unfortunately, there is no interface to send timer events to _another_ dedicated POSIX thread of the current process, because there is no interface that calculates the kernel thread id for another than the current POSIX thread id.
To get around this restriction, I'd like to suggest extending the GLIBC API to support sending timer events to arbitrary POSIX threads belonging to the current process by either:
introducing a new Linux specific function that calculates the kernel thread id from a POSIX thread id along the lines
pid_t pthread_to_tid_np (pthread_t id) {
return ((struct pthread *) id)->tid;
}
or:
introducing a new Linux-specific sigev_notify value named e.g. SIGEV_PTHREAD_ID and a new member in struct sigevent, e.g. _sigev_un._pthread, allowing to directly pass a POSIX thread id to struct sigevent. Furthermore, adding something like #define sigev_notify_pthread _sigev_un._sigev_thread._pthread to siginfo.h would then be appropriate to make access to the newly defined interface look nicer.
The main reason for my suggestion is better realtime support: The suggested solution provides a rather low-latency path to send timer events to threads.
I would be more than happy to provide a GLIBC patch that implements either of the two suggested solutions, or any other solution allowing to send timer events to dedicated threads, as long as chances are that it may be acceptable for the GLIBC maintainers. Personally, I'd be in favor for the second of the presented solutions, as it would not expose kernel thread ids to application code and would more smoothly fit into the currently available interface.
Please comment.