2014-07-14 11:49:44 +00:00
|
|
|
/** Message paths.
|
2014-06-05 09:34:29 +00:00
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
|
|
|
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2014-06-25 17:50:30 +00:00
|
|
|
#include <unistd.h>
|
2014-06-05 09:34:36 +00:00
|
|
|
#include <errno.h>
|
2014-06-25 17:50:30 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include <sys/syscall.h>
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2014-06-05 09:34:58 +00:00
|
|
|
#include "cfg.h"
|
2014-06-05 09:34:29 +00:00
|
|
|
#include "utils.h"
|
|
|
|
#include "path.h"
|
|
|
|
|
2014-06-25 17:50:30 +00:00
|
|
|
#define sigev_notify_thread_id _sigev_un._tid
|
|
|
|
|
|
|
|
/** Send messages */
|
|
|
|
static void * path_send(void *arg)
|
|
|
|
{
|
2014-07-04 15:58:10 +00:00
|
|
|
int sig;
|
2014-06-25 17:50:30 +00:00
|
|
|
struct path *p = (struct path *) arg;
|
|
|
|
timer_t tmr;
|
|
|
|
sigset_t set;
|
|
|
|
|
|
|
|
struct sigevent sev = {
|
|
|
|
.sigev_notify = SIGEV_THREAD_ID,
|
|
|
|
.sigev_signo = SIGALRM,
|
|
|
|
.sigev_notify_thread_id = syscall(SYS_gettid)
|
|
|
|
};
|
|
|
|
|
|
|
|
struct itimerspec its = {
|
|
|
|
.it_interval = timespec_rate(p->rate),
|
|
|
|
.it_value = { 1, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, SIGALRM);
|
|
|
|
if(pthread_sigmask(SIG_BLOCK, &set, NULL))
|
|
|
|
perror("Set signal mask");
|
|
|
|
|
|
|
|
if (timer_create(CLOCK_REALTIME, &sev, &tmr))
|
|
|
|
perror("Failed to create timer");
|
|
|
|
|
|
|
|
if (timer_settime(tmr, 0, &its, NULL))
|
|
|
|
perror("Failed to start timer");
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
sigwait(&set, &sig);
|
2014-07-04 15:58:10 +00:00
|
|
|
if (p->last) {
|
|
|
|
msg_send(p->last, p->out);
|
|
|
|
p->last = NULL;
|
|
|
|
p->sent++;
|
|
|
|
}
|
2014-06-25 17:50:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Receive messages */
|
2014-06-05 09:34:29 +00:00
|
|
|
static void * path_run(void *arg)
|
|
|
|
{
|
|
|
|
struct path *p = (struct path *) arg;
|
2014-07-18 16:05:44 +00:00
|
|
|
struct msg *m = malloc(sizeof(struct msg));
|
|
|
|
|
|
|
|
if (!m)
|
|
|
|
error("Failed to allocate memory!");
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2014-06-25 17:50:30 +00:00
|
|
|
/* Main thread loop */
|
2014-06-05 09:35:04 +00:00
|
|
|
while (1) {
|
2014-07-18 16:05:44 +00:00
|
|
|
msg_recv(m, p->in); /* Receive message */
|
2014-07-04 15:58:10 +00:00
|
|
|
p->received++;
|
2014-06-05 09:35:08 +00:00
|
|
|
|
2014-07-04 15:58:11 +00:00
|
|
|
/** Check header fields */
|
2014-07-18 16:05:44 +00:00
|
|
|
if (m->version != MSG_VERSION) {
|
2014-07-04 15:58:11 +00:00
|
|
|
p->invalid++;
|
|
|
|
continue;
|
|
|
|
}
|
2014-09-04 13:30:38 +00:00
|
|
|
else if (m->type != MSG_TYPE_DATA) {
|
2014-07-04 15:58:11 +00:00
|
|
|
p->invalid++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check sequence number */
|
2014-08-31 15:26:00 +00:00
|
|
|
if (m->sequence == 0) {
|
2014-07-04 15:58:10 +00:00
|
|
|
path_stats(p);
|
2014-07-04 15:58:11 +00:00
|
|
|
info("Simulation started");
|
|
|
|
|
|
|
|
p->sequence = 0;
|
|
|
|
p->received = 1;
|
|
|
|
p->sent = 0;
|
|
|
|
p->skipped = 0;
|
|
|
|
p->delayed = 0;
|
|
|
|
p->duplicated = 0;
|
|
|
|
p->invalid = 0;
|
2014-07-04 15:58:10 +00:00
|
|
|
}
|
2014-07-18 16:05:44 +00:00
|
|
|
else if (m->sequence < p->sequence) {
|
2014-07-04 15:58:10 +00:00
|
|
|
p->delayed++;
|
2014-07-04 15:58:11 +00:00
|
|
|
continue;
|
2014-06-05 09:34:58 +00:00
|
|
|
}
|
2014-07-18 16:05:44 +00:00
|
|
|
else if (m->sequence == p->sequence) {
|
2014-06-05 09:34:58 +00:00
|
|
|
p->duplicated++;
|
2014-07-04 15:58:11 +00:00
|
|
|
continue;
|
2014-06-05 09:34:58 +00:00
|
|
|
}
|
|
|
|
|
2014-08-31 14:43:28 +00:00
|
|
|
if (p->hook && p->hook(m, p)) {
|
2014-07-04 15:58:11 +00:00
|
|
|
p->skipped++;
|
2014-06-05 09:35:08 +00:00
|
|
|
continue;
|
2014-07-04 15:58:11 +00:00
|
|
|
}
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2014-09-08 14:45:46 +00:00
|
|
|
p->sequence = m->sequence;
|
|
|
|
|
2014-06-25 17:50:30 +00:00
|
|
|
/* At fixed rate mode, messages are send by another thread */
|
2014-09-04 13:30:38 +00:00
|
|
|
// if (p->rate)
|
|
|
|
// p->last = m;
|
|
|
|
// else {
|
2014-07-18 16:05:44 +00:00
|
|
|
msg_send(m, p->out);
|
2014-09-04 13:30:38 +00:00
|
|
|
p->sent++;
|
|
|
|
// }
|
2014-06-05 09:34:29 +00:00
|
|
|
}
|
|
|
|
|
2014-07-18 16:05:44 +00:00
|
|
|
free(m);
|
|
|
|
|
2014-06-05 09:34:29 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int path_start(struct path *p)
|
|
|
|
{
|
2014-06-25 17:50:30 +00:00
|
|
|
/* At fixed rate mode, we start another thread for sending */
|
|
|
|
if (p->rate)
|
2014-09-09 09:03:01 +00:00
|
|
|
pthread_create(&p->sent_tid, NULL, &path_send, (void *) p);
|
2014-06-25 17:50:30 +00:00
|
|
|
|
2014-09-09 09:03:01 +00:00
|
|
|
return pthread_create(&p->recv_tid, NULL, &path_run, (void *) p);
|
2014-06-05 09:34:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int path_stop(struct path *p)
|
|
|
|
{
|
2014-09-09 09:03:01 +00:00
|
|
|
pthread_cancel(p->recv_tid);
|
|
|
|
pthread_join(p->recv_tid, NULL);
|
2014-06-25 17:50:30 +00:00
|
|
|
|
|
|
|
if (p->rate) {
|
2014-09-09 09:03:01 +00:00
|
|
|
pthread_cancel(p->sent_tid);
|
|
|
|
pthread_join(p->sent_tid, NULL);
|
2014-06-25 17:50:30 +00:00
|
|
|
}
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2014-06-05 09:35:04 +00:00
|
|
|
return 0;
|
2014-06-05 09:34:29 +00:00
|
|
|
}
|
2014-07-04 09:47:28 +00:00
|
|
|
|
|
|
|
void path_stats(struct path *p)
|
|
|
|
{
|
2014-07-04 15:58:10 +00:00
|
|
|
info("%12s " MAG("=>") " %-12s: %-8u %-8u %-8u %-8u %-8u",
|
2014-07-04 09:47:28 +00:00
|
|
|
p->in->name, p->out->name,
|
2014-07-04 15:58:10 +00:00
|
|
|
p->sent, p->received, p->delayed,
|
|
|
|
p->duplicated, p->invalid
|
|
|
|
);
|
2014-07-04 09:47:28 +00:00
|
|
|
}
|