From 1bd65bf8d56e462fcd8300a109896d9f4e231c28 Mon Sep 17 00:00:00 2001 From: Arjen Baart Date: Sat, 25 Jul 2020 13:59:34 +0200 Subject: [PATCH] Sleep is interrupted by signals other then message reception --- doc/design.xml | 39 ++++++++++++++++++++++++++++++++++++--- src/Tachyon.cpp | 38 +++++++++++++++++++++++++++++++------- src/Tachyon.h | 1 + test/Makefile.am | 13 +++++++------ test/accellerate_signal | 29 +++++++++++++++++++++++++++++ test/sleep_signal.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 16 deletions(-) create mode 100755 test/accellerate_signal create mode 100644 test/sleep_signal.cpp diff --git a/doc/design.xml b/doc/design.xml index eb12e28..385350f 100644 --- a/doc/design.xml +++ b/doc/design.xml @@ -120,10 +120,36 @@ The nanosleep method calculates the virtual time at which the sleep ends and cal the actual sleep by suspending the process. Interruptions of the sleep are handled by recalculating the sleep period from the possibly changed parameters and resuming the sleep if needed. +The nanosleep(2) system call is used to perform the actual sleep. +This system call may return for either one of four reasons. + + + +The sleep period ended normally. Return value = 0. + + + +The sleep is interrupted by the reception of a message. Return value = -1 and errno = EINTR. +Internally, message notification is handled by the signal SIGUSR1. +The virtual time is recalculated and the sleep resumes if the virtual end time has not passed yet. + + + +The sleep is interrupted by a signal which is handled by a signal handler. Return value = -1 and errno = EINTR. +This is not caused by receiving a message. +The sleep in virtual time is interrupted and control is returned to the calling process. + + + +An error occured. Return value = -1 and errno = EFAULT or errnno = EINVAL. + + + -To control the virtual time from an external process, a form of inter process communication (IPC) is used. The external process, usually a test program, can find the Tachyon object to control through a name which is assigned for that Tachyon object. Two or more Tachyon objects may exist, one of which holds the virtual time used by the time dependent software. The other Tachyon object(s) are used to control the virtual timebase and send the timebase parameters through a form of IPC. +To control the virtual time from an external process, a form of inter process communication (IPC) is used. +The external process, usually a test program, can find the Tachyon object to control through a name which is assigned for that Tachyon object. Two or more Tachyon objects may exist, one of which holds the virtual time used by the time dependent software. The other Tachyon object(s) are used to control the virtual timebase and send the timebase parameters through a form of IPC. @@ -174,8 +200,15 @@ The time is specified with nanosecond precision in the struct timespec -Suspend execution until the time in req is passed. That time is divided by the accelleration set in the Tachyon object. So, if a waiting time of 60 seconds is requested and the accelleration is 10, execution will be actually be suspended for 6 seconds. -The time is specified with nanosecond precision in a floating point number. +Suspend execution until the the number of seconds in req is passed. +That time is divided by the accelleration set in the Tachyon object. +So, if a waiting time of 60 seconds is requested and the accelleration is 10, execution will be actually be suspended for 6 seconds. +The time in seconds is specified with nanosecond precision in a floating point number. + + + +Suspend execution until the virtual time in end_time has passed. +If, during the sleep, the accelleration or the offset is changed, these changes are taken into account. diff --git a/src/Tachyon.cpp b/src/Tachyon.cpp index b9adaa4..bd50f66 100644 --- a/src/Tachyon.cpp +++ b/src/Tachyon.cpp @@ -90,6 +90,7 @@ bool operator < (timespec a, timespec b) static void message_notification(int signum, siginfo_t *si, void *notused) { Tachyon *tp = (Tachyon *) si->si_value.sival_ptr; + //printf("Tachyon: Caught signal %d\n", signum); tp->receive_message(); tp->expect_message(); } @@ -102,6 +103,8 @@ Tachyon::Tachyon() accelleration = 1.0; + msg_sequence = 0; + struct mq_attr queue_attributes; struct sigevent sev; struct sigaction act; @@ -124,6 +127,8 @@ Tachyon::Tachyon(const char *name) accelleration = 1.0; + msg_sequence = 0; + queue_name[0] = '\0'; msg_queue = mq_open(name, O_WRONLY); } @@ -168,7 +173,11 @@ void Tachyon::receive_message(void) int message_size; //printf("Receiving message.\n"); + message_size = mq_receive(msg_queue, message, MAX_MESSAGE_SIZE, NULL); + msg_sequence++; + + //printf("Message size = %d\n", message_size); message[message_size] = '\0'; //printf("The message is %s.\n", message); @@ -205,7 +214,7 @@ timespec Tachyon::gettime(void) // Tvirtual = T0 + acc * (Tactual - T0) + offset - difference = timespec_subtract(actual_time, T0); + difference = actual_time - T0; //printf(" Ta - T0 = %d,%d\n", difference.tv_sec, difference.tv_nsec); seconds = difference.tv_sec * accelleration; @@ -218,8 +227,7 @@ timespec Tachyon::gettime(void) difference.tv_nsec = trunc(nanoseconds); //printf(" a * (Ta - T0) = %d,%d\n", difference.tv_sec, difference.tv_nsec); - virtual_time = timespec_add(T0, difference); - virtual_time = timespec_add(virtual_time, offset); + virtual_time = T0 + difference + offset; return virtual_time; } @@ -234,7 +242,7 @@ int Tachyon::nanosleep(struct timespec req) virt_time = gettime(); - return sleep_until(timespec_add(virt_time, req)); + return sleep_until(virt_time + req); } int Tachyon::nanosleep(float req) @@ -262,13 +270,16 @@ int Tachyon::sleep_until(timespec ends_at) double seconds; double nanoseconds; int sleep_return; - bool error; + int last_msg_sequence; timespec virt_time; timespec remaining; + last_msg_sequence = msg_sequence; + sleep_return = 0; + virt_time = gettime(); - while (!error && virt_time < ends_at) + while (sleep_return == 0 && virt_time < ends_at) { timespec period; @@ -287,7 +298,20 @@ int Tachyon::sleep_until(timespec ends_at) sleep_return = ::nanosleep(&period, &remaining); //printf("nanosleep returns %d, error = %s\n", sleep_return, strerror(errno)); - error = sleep_return == -1 && errno != EINTR; + // If a sleep interruption is caused by receiving a message, the sleep is resumed. + if (sleep_return == -1 && errno == EINTR) + { + if (msg_sequence != last_msg_sequence) + { + sleep_return = 0; + last_msg_sequence = msg_sequence; + } + else + { + sleep_return = -2; // Interrupted by a different signal + } + } + virt_time = gettime(); } diff --git a/src/Tachyon.h b/src/Tachyon.h index c073506..93f65f6 100644 --- a/src/Tachyon.h +++ b/src/Tachyon.h @@ -9,6 +9,7 @@ class Tachyon { char queue_name[255]; mqd_t msg_queue; + int msg_sequence; timespec offset; timespec T0; diff --git a/test/Makefile.am b/test/Makefile.am index 6801cf9..0a8505a 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,15 +1,16 @@ -TESTS = create timespec sleep accellerate accellerate_multi sleep_float accellerate_float +TESTS = create timespec sleep accellerate accellerate_multi sleep_float accellerate_float accellerate_signal AM_CPPFLAGS = -I../src LDADD = ../src/.libs/libTachyon.la -lrt -lm -check_PROGRAMS = create timespec sleep sleep_float +check_PROGRAMS = create timespec sleep sleep_float sleep_signal -create_SOURCES = create.cpp -timespec_SOURCES = timespec.cpp -sleep_SOURCES = sleep.cpp -sleep_float_SOURCES = sleep_float.cpp +create_SOURCES = create.cpp +timespec_SOURCES = timespec.cpp +sleep_SOURCES = sleep.cpp +sleep_float_SOURCES = sleep_float.cpp +sleep_signal_SOURCES = sleep_signal.cpp clean-local: rm -f sleep.tmp diff --git a/test/accellerate_signal b/test/accellerate_signal new file mode 100755 index 0000000..bb091b6 --- /dev/null +++ b/test/accellerate_signal @@ -0,0 +1,29 @@ +#!/bin/bash + +set -m + +PATH=../src:$PATH + +START_TIME=`date +%s` +./sleep_signal >sleep.tmp & +sleep 1 +read a b PID +#include +#include + +#include +#include "Tachyon.h" + +/* + * Test the sleep function with signal handling + * By default, sleep 4 times 6 seconds. + * The sleep can be interrupted by a HUP signal, which is caught by a signal handler. + */ + + +// Signal handler for SIGHUP + +void sighup_handler(int sig) +{ + std::cout << "Caught signal " << sig << "\n"; +} + +int main() +{ + + Tachyon timebase; + float interval; + + interval = 6.0; + + signal(SIGHUP, sighup_handler); + + std::cout << "PID = " << getpid() << "\n"; + std::cout << "Tachyon name is " << timebase.name() << "\n"; + std::cout.flush(); + for (int i = 0; i < 4; i++) + { + timebase.nanosleep(interval); + std::cout << "6 seconds.\n"; + } +} -- 2.11.0