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.
+
+<enumerate>
+<item>
+The sleep period ended normally. Return value = 0.
+</item>
+
+<item>
+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.
+</item>
+
+<item>
+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.
+</item>
+
+<item>
+An error occured. Return value = -1 and errno = EFAULT or errnno = EINVAL.
+</item>
+</enumerate>
+
</para>
<para>
-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.
</para>
</chapter>
</item>
<item tag='int nanosleep(float req)'>
-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.
+</item>
+
+<item tag='int sleep_until(timespec end_time)'>
+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.
</item>
<item tag='settime (time_t sec)'>
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();
}
accelleration = 1.0;
+ msg_sequence = 0;
+
struct mq_attr queue_attributes;
struct sigevent sev;
struct sigaction act;
accelleration = 1.0;
+ msg_sequence = 0;
+
queue_name[0] = '\0';
msg_queue = mq_open(name, O_WRONLY);
}
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);
// 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;
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;
}
virt_time = gettime();
- return sleep_until(timespec_add(virt_time, req));
+ return sleep_until(virt_time + req);
}
int Tachyon::nanosleep(float req)
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;
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();
}
{
char queue_name[255];
mqd_t msg_queue;
+ int msg_sequence;
timespec offset;
timespec T0;
-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
--- /dev/null
+#!/bin/bash
+
+set -m
+
+PATH=../src:$PATH
+
+START_TIME=`date +%s`
+./sleep_signal >sleep.tmp &
+sleep 1
+read a b PID <sleep.tmp
+read a b c TACHYON_NAME <sleep.tmp
+kill -1 $PID
+sleep 1
+kill -1 $PID
+sleep 1
+kill -1 $PID
+fg
+END_TIME=`date +%s`
+duration=$(($END_TIME - $START_TIME))
+echo "Elapsed time is $duration"
+cat sleep.tmp
+
+if [[ $duration -eq 9 ]] || [[ $duration -eq 10 ]]
+then
+ echo "Elapsed time within 10 seconds"
+ exit 0
+fi
+echo "Elapsed time $duration seconds is unexpected."
+exit 1
--- /dev/null
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <iostream>
+#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";
+ }
+}