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)
|
|
|
|
{
|
2014-09-09 09:03:06 +00:00
|
|
|
int lag;
|
2014-06-05 09:34:29 +00:00
|
|
|
struct path *p = (struct path *) arg;
|
2014-07-18 16:05:44 +00:00
|
|
|
struct msg *m = malloc(sizeof(struct msg));
|
|
|
|
|
|
|
|
if (!m)
|
2014-09-11 14:40:54 +00:00
|
|
|
error("Failed to allocate memory for message!");
|
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-09-09 09:03:06 +00:00
|
|
|
|
2014-09-09 13:42:36 +00:00
|
|
|
/* Check sequence number */
|
|
|
|
if (m->sequence == 0) {
|
|
|
|
path_stats(p);
|
|
|
|
info("Simulation started");
|
|
|
|
|
2014-09-10 12:24:49 +00:00
|
|
|
/* Reset counters */
|
2014-09-09 13:42:36 +00:00
|
|
|
p->sent = 0;
|
|
|
|
p->received = 0;
|
|
|
|
p->invalid = 0;
|
|
|
|
p->skipped = 0;
|
|
|
|
p->dropped = 0;
|
2014-09-10 12:24:49 +00:00
|
|
|
|
|
|
|
/* Reset sequence no tracking */
|
|
|
|
p->sequence = -1;
|
|
|
|
memset(p->histogram, 0, sizeof(p->histogram));
|
|
|
|
|
2014-09-09 13:42:36 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 09:03:06 +00:00
|
|
|
lag = m->sequence - p->sequence;
|
|
|
|
|
2014-07-04 15:58:10 +00:00
|
|
|
p->received++;
|
2014-06-05 09:35:08 +00:00
|
|
|
|
2014-09-09 09:23:19 +00:00
|
|
|
if (HIST_SEQ/2 + lag < HIST_SEQ && HIST_SEQ/2 + lag >= 0)
|
2014-09-09 09:03:11 +00:00
|
|
|
p->histogram[HIST_SEQ/2 + lag]++;
|
|
|
|
|
2014-09-09 13:42:36 +00:00
|
|
|
/* Check header fields */
|
2014-09-09 09:03:06 +00:00
|
|
|
if (m->version != MSG_VERSION ||
|
|
|
|
m->type != MSG_TYPE_DATA) {
|
2014-07-04 15:58:11 +00:00
|
|
|
p->invalid++;
|
|
|
|
continue;
|
|
|
|
}
|
2014-09-09 09:03:06 +00:00
|
|
|
|
|
|
|
/* Sequence no. is lower than expected */
|
|
|
|
if (lag <= 0) {
|
|
|
|
p->dropped++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->hook && p->hook(m, p)) {
|
|
|
|
p->skipped++;
|
2014-07-04 15:58:11 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-09-09 09:03:06 +00:00
|
|
|
/* Update last known sequence number */
|
2014-09-08 14:45:46 +00:00
|
|
|
p->sequence = m->sequence;
|
2014-09-09 09:03:06 +00:00
|
|
|
p->last = m;
|
2014-09-08 14:45:46 +00:00
|
|
|
|
2014-06-25 17:50:30 +00:00
|
|
|
/* At fixed rate mode, messages are send by another thread */
|
2014-09-09 09:03:06 +00:00
|
|
|
if (!p->rate) {
|
2014-07-18 16:05:44 +00:00
|
|
|
msg_send(m, p->out);
|
2014-09-04 13:30:38 +00:00
|
|
|
p->sent++;
|
2014-09-09 09:03:06 +00:00
|
|
|
}
|
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-09-09 09:03:11 +00:00
|
|
|
if (p->received) {
|
|
|
|
path_stats(p);
|
2014-09-09 11:11:29 +00:00
|
|
|
hist_plot(p->histogram, HIST_SEQ);
|
2014-09-09 09:03:11 +00:00
|
|
|
hist_dump(p->histogram, HIST_SEQ);
|
|
|
|
}
|
|
|
|
|
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-09-09 09:03:06 +00:00
|
|
|
p->sent, p->received, p->dropped, p->skipped, p->invalid
|
2014-07-04 15:58:10 +00:00
|
|
|
);
|
2014-07-04 09:47:28 +00:00
|
|
|
}
|