14 const int MAX_MESSAGE_SIZE=100;
17 Functions to calculate timespec structures
21 timespec timespec_add(timespec a, timespec b)
25 sum.tv_sec = a.tv_sec + b.tv_sec;
26 sum.tv_nsec = a.tv_nsec + b.tv_nsec;
28 if (sum.tv_nsec >= 1000000000)
31 sum.tv_nsec -= 1000000000;
37 timespec operator + (timespec a, timespec b)
39 return timespec_add(a, b);
43 timespec timespec_subtract(timespec a, timespec b)
47 dif.tv_sec = a.tv_sec - b.tv_sec;
48 dif.tv_nsec = a.tv_nsec - b.tv_nsec;
49 if (dif.tv_nsec < 0 && dif.tv_sec > 0)
52 dif.tv_nsec += 1000000000;
54 if (dif.tv_nsec > 0 && dif.tv_sec < 0)
57 dif.tv_nsec -= 1000000000;
63 timespec operator - (timespec a, timespec b)
65 return timespec_subtract(a, b);
68 // Compare a and b. Return < 0 if a < b
69 int timespec_compare(timespec a, timespec b)
73 if (a.tv_sec == b.tv_sec)
75 cmp = a.tv_nsec - b.tv_nsec;
79 cmp = a.tv_sec - b.tv_sec;
85 bool operator < (timespec a, timespec b)
87 return timespec_compare(a, b) < 0;
90 static void message_notification(int signum, siginfo_t *si, void *notused)
92 Tachyon *tp = (Tachyon *) si->si_value.sival_ptr;
93 tp->receive_message();
101 clock_gettime(CLOCK_REALTIME, &T0);
105 struct mq_attr queue_attributes;
107 struct sigaction act;
109 sprintf(queue_name, "/Tachyon.%d", getpid());
110 queue_attributes.mq_maxmsg = 2;
111 queue_attributes.mq_msgsize = MAX_MESSAGE_SIZE;
113 msg_queue = mq_open(queue_name, O_CREAT | O_RDONLY, S_IRWXU, &queue_attributes);
115 // Setup the signal handler for message arrival
119 Tachyon::Tachyon(const char *name)
123 clock_gettime(CLOCK_REALTIME, &T0);
127 queue_name[0] = '\0';
128 msg_queue = mq_open(name, O_WRONLY);
134 if (queue_name[0] != '\0')
136 mq_unlink(queue_name);
140 const char * Tachyon::name(void)
145 // Prepare notification and signal handling for ther next message
147 void Tachyon::expect_message(void)
150 struct sigaction act;
152 // Setup the signal handler for message arrival
154 act.sa_sigaction = message_notification;
155 act.sa_flags = SA_SIGINFO;
156 sigaction(SIGUSR1, &act, NULL);
158 sev.sigev_notify = SIGEV_SIGNAL;
159 sev.sigev_signo = SIGUSR1;
160 sev.sigev_notify_attributes = NULL;
161 sev.sigev_value.sival_ptr = this;
162 mq_notify(msg_queue, &sev);
165 void Tachyon::receive_message(void)
167 char message[MAX_MESSAGE_SIZE];
170 //printf("Receiving message.\n");
171 message_size = mq_receive(msg_queue, message, MAX_MESSAGE_SIZE, NULL);
172 message[message_size] = '\0';
174 //printf("The message is %s.\n", message);
178 accellerate(atof(message+1));
187 time_t Tachyon::time(void)
191 // calculate the currect virtual time
193 timespec Tachyon::gettime(void)
195 timespec actual_time;
196 timespec virtual_time;
203 clock_gettime(CLOCK_REALTIME, &actual_time);
204 //printf(" Actual time: %d,%d, T0 = %d,%d\n", actual_time.tv_sec, actual_time.tv_nsec, T0.tv_sec, T0.tv_nsec);
206 // Tvirtual = T0 + acc * (Tactual - T0) + offset
208 difference = timespec_subtract(actual_time, T0);
209 //printf(" Ta - T0 = %d,%d\n", difference.tv_sec, difference.tv_nsec);
211 seconds = difference.tv_sec * accelleration;
212 nanoseconds = difference.tv_nsec * accelleration;
213 overflow = trunc(nanoseconds * 1.0e-9);
215 nanoseconds -= overflow * 1.0e9;
217 difference.tv_sec = trunc(seconds);
218 difference.tv_nsec = trunc(nanoseconds);
219 //printf(" a * (Ta - T0) = %d,%d\n", difference.tv_sec, difference.tv_nsec);
221 virtual_time = timespec_add(T0, difference);
222 virtual_time = timespec_add(virtual_time, offset);
227 int Tachyon::nanosleep(struct timespec req)
235 virt_time = gettime();
237 return sleep_until(timespec_add(virt_time, req));
240 int Tachyon::nanosleep(float req)
244 struct timespec req_t;
249 virt_time = gettime();
251 seconds = req / accelleration;
252 nanoseconds = (seconds - trunc(seconds)) * 1.0e9;
254 req_t.tv_sec = trunc(seconds);
255 req_t.tv_nsec = trunc(nanoseconds);
257 return sleep_until(virt_time + req_t);
260 int Tachyon::sleep_until(timespec ends_at)
270 virt_time = gettime();
271 while (!error && virt_time < ends_at)
275 period = ends_at - virt_time;
276 //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);
277 //printf("Virtual period = %d,%d\n", period.tv_sec, period.tv_nsec);
279 seconds = period.tv_sec / accelleration;
280 nanoseconds = period.tv_nsec / accelleration;
281 nanoseconds += (seconds - trunc(seconds)) * 1.0e9;
282 period.tv_sec = trunc(seconds);
283 period.tv_nsec = trunc(nanoseconds);
285 //printf("Sleeping for : %d,%d\n", period.tv_sec, period.tv_nsec);
287 sleep_return = ::nanosleep(&period, &remaining);
288 //printf("nanosleep returns %d, error = %s\n", sleep_return, strerror(errno));
290 error = sleep_return == -1 && errno != EINTR;
291 virt_time = gettime();
297 void Tachyon::settime(time_t sec)
301 void Tachyon::accellerate(double factor)
303 timespec actual_time, virtual_time;
305 clock_gettime(CLOCK_REALTIME, &actual_time);
306 virtual_time = gettime();
309 offset = virtual_time - actual_time;
311 accelleration = factor;
313 // send to the Tachyon object in another process.
314 if (queue_name[0] == '\0')
316 char message[MAX_MESSAGE_SIZE];
318 sprintf(message, "A%f", accelleration);
319 mq_send(msg_queue, message, strlen(message), 100);