Re: rt_task_unblock() POSIX alternative

Petr Červenka grugh at centrum.cz
Thu Apr 9 17:00:09 CEST 2020


> BTW:
> Why do you think nothing can interrupt a read() from a timerfd?
> If read() blocks on a timerfd the calling thread will be put into
> interruptable sleep.
 
"I" was not able to send a signal to the task and interrupt it.
Here is an example. Please let me know, how to improve it to interrupt the read() before its timeout:
 
#include <math.h>
#include <pthread.h>
#include <stdint.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/timerfd.h>
#include <unistd.h>

#define AUTO_KILL

#define SECOND  1000000000l     // ns
#define PERIOD  (5 * SECOND)    // ns
#define SLEEP   (1 * SECOND)    // ns

using namespace std;

static pid_t mainTask_pid;
static pthread_t task;
static int timer_fd;
static bool end = false;

void signalHandler(int signal) {
    int err;
    printf("Signal handler: %d\n", signal);
    end = true;
    err = pthread_kill(task, SIGINT);
    if (err != 0) {
        printf("pthread_kill failed: %d (%s)\n", err, strerror(-err));
    }
    printf("Signal handler end\n");
}

void timediff (struct timespec *result, const struct timespec *t1, const struct timespec *t2) {
    result->tv_sec = t2->tv_sec - t1->tv_sec;
    result->tv_nsec = t2->tv_nsec - t1->tv_nsec;
    if (result->tv_nsec >= SECOND) {
        result->tv_nsec -= SECOND;
        result->tv_sec++;
    }
    if (result->tv_nsec < 0) {
        result->tv_nsec += SECOND;
        result->tv_sec--;
    }
}

static void *taskHandler(void *cookie) {
    int err;

    printf("Task started\n");

    signal(SIGINT, signalHandler);
    signal(SIGTERM, signalHandler);

    // Get current time
    struct timespec start;
    clock_gettime(CLOCK_MONOTONIC, &start);

    // Set task period
    timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
    struct itimerspec timer_conf;
    timer_conf.it_value.tv_sec      = start.tv_sec;
    timer_conf.it_value.tv_nsec     = start.tv_nsec;
    timer_conf.it_interval.tv_sec   = PERIOD / SECOND;
    timer_conf.it_interval.tv_nsec  = PERIOD % SECOND;
    printf("Set period: %.3gs\n", timer_conf.it_interval.tv_sec + (double) timer_conf.it_interval.tv_nsec / SECOND);
    err = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &timer_conf, NULL);
    if (err != 0) {
        printf("timerfd_settime failed: %d (%s)\n", err, strerror(-err));
        return NULL;
    }

    // Main cycle
    while (!end) {
        // Wait next period
        uint64_t ticks;
        ::read(timer_fd, &ticks, sizeof (ticks));

        // Get current time
        struct timespec now, result;
        clock_gettime(CLOCK_MONOTONIC, &now);

        // Printf wait time
        timediff(&result, &start, &now);
        printf("Task livind: %.3gs\n", result.tv_sec + (double) result.tv_nsec / SECOND);
        start = now;
    }

    ::close(timer_fd);
    printf("Task ended\n");
}

/*
 * 
 */
int main(int argc, char** argv) {
    unsigned long overruns;
    int err;

    mlockall(MCL_CURRENT | MCL_FUTURE);

    // Setup signal handler
    signal(SIGINT, signalHandler);
    signal(SIGTERM, signalHandler);

    // Get current process ID
    mainTask_pid = getpid();

    // Make main task real-time (prio 1)
    sched_param param;
    memset(&param, 0, sizeof(param));
    param.sched_priority = 1;
    err = sched_setscheduler(mainTask_pid, SCHED_FIFO, &param);
    if (err != 0) {
        printf("sched_setscheduler failed: %d (%s)\n", err, strerror(-err));
        goto sched_setscheduler_err;
    }

    // Create new task (prio 2)
    pthread_attr_t tattr;
    pthread_attr_init(&tattr);
    pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setschedpolicy(&tattr, SCHED_FIFO);
    memset(&param, 0, sizeof (param));
    param.sched_priority = 2;
    pthread_attr_setschedparam(&tattr, &param);
    err = pthread_create(&task, &tattr, taskHandler, NULL);
    if (err != 0) {
        printf("pthread_create failed: %d (%s)\n", err, strerror(-err));
        goto pthread_create_err;
    }

#ifndef AUTO_KILL
    printf("Press ^C to stop!\n");
    do {
        pause();
    } while(!end);
#else
    usleep(SLEEP / 1000);

    // Call of signal handler
    err = kill(0, SIGINT);  // THE ONLY ONE WHICH WORKS !!!
    //err = kill(getpid(), SIGINT);
    //err = kill(mainTask_pid, SIGINT);
    //err = pthread_kill(pthread_self(), SIGINT);
    //err = pthread_kill(task, SIGINT);
    if (err != 0) {
        printf("pthread_kill failed: %d (%s)\n", err, strerror(-err));
    }
#endif

    printf("Waiting for join\n");
    //pthread_cancel(task);
    pthread_join(task, NULL);
pthread_create_err:
sched_setaffinity_err:
sched_setscheduler_err:
    return 0;
}



More information about the Xenomai mailing list