#include <sys/types.h>
#include <unistd.h>
+#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
+#include <errno.h>
#include "Tachyon.h"
const int MAX_MESSAGE_SIZE=100;
-static void message_notification(union sigval note)
+/*
+ Functions to calculate timespec structures
+*/
+
+// Calculate a + b
+timespec timespec_add(timespec a, timespec b)
+{
+ timespec sum;
+
+ sum.tv_sec = a.tv_sec + b.tv_sec;
+ sum.tv_nsec = a.tv_nsec + b.tv_nsec;
+
+ if (sum.tv_nsec >= 1000000000)
+ {
+ sum.tv_sec++;
+ sum.tv_nsec -= 1000000000;
+ }
+
+ return sum;
+}
+
+timespec operator + (timespec a, timespec b)
+{
+ return timespec_add(a, b);
+}
+
+// Calculate a - b
+timespec timespec_subtract(timespec a, timespec b)
{
- Tachyon *tp = (Tachyon *) note.sival_ptr;
+ timespec dif;
+
+ dif.tv_sec = a.tv_sec - b.tv_sec;
+ dif.tv_nsec = a.tv_nsec - b.tv_nsec;
+ if (dif.tv_nsec < 0 && dif.tv_sec > 0)
+ {
+ dif.tv_sec--;
+ dif.tv_nsec += 1000000000;
+ }
+ if (dif.tv_nsec > 0 && dif.tv_sec < 0)
+ {
+ dif.tv_sec++;
+ dif.tv_nsec -= 1000000000;
+ }
+
+ return dif;
+}
+
+timespec operator - (timespec a, timespec b)
+{
+ return timespec_subtract(a, b);
+}
+
+// Compare a and b. Return < 0 if a < b
+int timespec_compare(timespec a, timespec b)
+{
+ int cmp = 0;
+
+ if (a.tv_sec == b.tv_sec)
+ {
+ cmp = a.tv_nsec - b.tv_nsec;
+ }
+ else
+ {
+ cmp = a.tv_sec - b.tv_sec;
+ }
+
+ return cmp;
+}
+
+bool operator < (timespec a, timespec b)
+{
+ return timespec_compare(a, b) < 0;
+}
+
+static void message_notification(int signum, siginfo_t *si, void *notused)
+{
+ Tachyon *tp = (Tachyon *) si->si_value.sival_ptr;
tp->receive_message();
+ tp->expect_message();
}
Tachyon::Tachyon()
{
- offset = 0;
- T0 = 0;
+ offset.tv_sec = 0;
+ offset.tv_nsec = 0;
+ clock_gettime(CLOCK_REALTIME, &T0);
accelleration = 1.0;
struct mq_attr queue_attributes;
struct sigevent sev;
+ struct sigaction act;
sprintf(queue_name, "/Tachyon.%d", getpid());
queue_attributes.mq_maxmsg = 2;
msg_queue = mq_open(queue_name, O_CREAT | O_RDONLY, S_IRWXU, &queue_attributes);
- sev.sigev_notify = SIGEV_THREAD;
- sev.sigev_notify_function = message_notification;
- sev.sigev_notify_attributes = NULL;
- sev.sigev_value.sival_ptr = this;
- mq_notify(msg_queue, &sev);
+ // Setup the signal handler for message arrival
+ expect_message();
}
Tachyon::Tachyon(const char *name)
{
- offset = 0;
- T0 = 0;
+ offset.tv_sec = 0;
+ offset.tv_nsec = 0;
+ clock_gettime(CLOCK_REALTIME, &T0);
accelleration = 1.0;
return queue_name;
}
+// Prepare notification and signal handling for ther next message
+
+void Tachyon::expect_message(void)
+{
+ struct sigevent sev;
+ struct sigaction act;
+
+ // Setup the signal handler for message arrival
+
+ act.sa_sigaction = message_notification;
+ act.sa_flags = SA_SIGINFO;
+ sigaction(SIGUSR1, &act, NULL);
+
+ sev.sigev_notify = SIGEV_SIGNAL;
+ sev.sigev_signo = SIGUSR1;
+ sev.sigev_notify_attributes = NULL;
+ sev.sigev_value.sival_ptr = this;
+ mq_notify(msg_queue, &sev);
+}
+
void Tachyon::receive_message(void)
{
char message[MAX_MESSAGE_SIZE];
{
}
+// calculate the currect virtual time
+
+timespec Tachyon::gettime(void)
+{
+ timespec actual_time;
+ timespec virtual_time;
+ timespec difference;
+
+ double seconds;
+ double nanoseconds;
+ double overflow;
+
+ clock_gettime(CLOCK_REALTIME, &actual_time);
+ //printf(" Actual time: %d,%d, T0 = %d,%d\n", actual_time.tv_sec, actual_time.tv_nsec, T0.tv_sec, T0.tv_nsec);
+
+ // Tvirtual = T0 + acc * (Tactual - T0) + offset
+
+ difference = timespec_subtract(actual_time, T0);
+ //printf(" Ta - T0 = %d,%d\n", difference.tv_sec, difference.tv_nsec);
+
+ seconds = difference.tv_sec * accelleration;
+ nanoseconds = difference.tv_nsec * accelleration;
+ overflow = trunc(nanoseconds * 1.0e-9);
+ seconds += overflow;
+ nanoseconds -= overflow * 1.0e9;
+
+ difference.tv_sec = trunc(seconds);
+ 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);
+
+ return virtual_time;
+}
+
int Tachyon::nanosleep(struct timespec req)
{
double seconds;
double nanoseconds;
+ int sleep_return;
- seconds = req.tv_sec / accelleration;
- nanoseconds = req.tv_nsec / accelleration;
- nanoseconds += (seconds - trunc(seconds)) * 1.0e9;
- req.tv_sec = trunc(seconds);
- req.tv_nsec = trunc(nanoseconds);
+ timespec virt_time;
- ::nanosleep(&req, NULL);
+ virt_time = gettime();
+
+ return sleep_until(timespec_add(virt_time, req));
}
int Tachyon::nanosleep(float req)
double seconds;
double nanoseconds;
struct timespec req_t;
+ int sleep_return;
+
+ timespec virt_time;
+
+ virt_time = gettime();
seconds = req / accelleration;
nanoseconds = (seconds - trunc(seconds)) * 1.0e9;
req_t.tv_sec = trunc(seconds);
req_t.tv_nsec = trunc(nanoseconds);
- ::nanosleep(&req_t, NULL);
+ return sleep_until(virt_time + req_t);
+}
+
+int Tachyon::sleep_until(timespec ends_at)
+{
+ double seconds;
+ double nanoseconds;
+ int sleep_return;
+ bool error;
+
+ timespec virt_time;
+ timespec remaining;
+
+ virt_time = gettime();
+ while (!error && virt_time < ends_at)
+ {
+ timespec period;
+
+ period = ends_at - virt_time;
+ //printf("Tv = %d,%d. sleep end at %d,%d\n", virt_time.tv_sec, virt_time.tv_nsec, ends_at.tv_sec, ends_at.tv_nsec);
+ //printf("Virtual period = %d,%d\n", period.tv_sec, period.tv_nsec);
+
+ seconds = period.tv_sec / accelleration;
+ nanoseconds = period.tv_nsec / accelleration;
+ nanoseconds += (seconds - trunc(seconds)) * 1.0e9;
+ period.tv_sec = trunc(seconds);
+ period.tv_nsec = trunc(nanoseconds);
+
+ //printf("Sleeping for : %d,%d\n", period.tv_sec, period.tv_nsec);
+ errno = 0;
+ sleep_return = ::nanosleep(&period, &remaining);
+ //printf("nanosleep returns %d, error = %s\n", sleep_return, strerror(errno));
+
+ error = sleep_return == -1 && errno != EINTR;
+ virt_time = gettime();
+ }
+
+ return sleep_return;
}
void Tachyon::settime(time_t sec)
void Tachyon::accellerate(double factor)
{
+ timespec actual_time, virtual_time;
+
+ clock_gettime(CLOCK_REALTIME, &actual_time);
+ virtual_time = gettime();
+
+ T0 = actual_time;
+ offset = virtual_time - actual_time;
+
accelleration = factor;
// send to the Tachyon object in another process.