Whenever the value T_BUFFER_MAX changes, the tracers had to be recompiled. The only reason why it was needed is because we used some fixed size buffers to read events. This commit removes this restriction. Also, with the basic simulator, this value T_BUFFER_MAX now comes with an #ifdef which would have required some special hackish-level tricks in the tracers, which is not good. Let's just allocate memory when needed.
202 lines
5.5 KiB
C
202 lines
5.5 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include "database.h"
|
|
#include "event.h"
|
|
#include "handler.h"
|
|
#include "logger/logger.h"
|
|
#include "view/view.h"
|
|
#include "gui/gui.h"
|
|
#include "utils.h"
|
|
#include "event_selector.h"
|
|
#include "config.h"
|
|
|
|
typedef struct {
|
|
int socket;
|
|
int *is_on;
|
|
int nevents;
|
|
pthread_mutex_t lock;
|
|
} vcd_data;
|
|
|
|
void is_on_changed(void *_d)
|
|
{
|
|
vcd_data *d = _d;
|
|
char t;
|
|
|
|
if (pthread_mutex_lock(&d->lock)) abort();
|
|
|
|
if (d->socket == -1) goto no_connection;
|
|
|
|
t = 1;
|
|
if (socket_send(d->socket, &t, 1) == -1 ||
|
|
socket_send(d->socket, &d->nevents, sizeof(int)) == -1 ||
|
|
socket_send(d->socket, d->is_on, d->nevents * sizeof(int)) == -1)
|
|
abort();
|
|
|
|
no_connection:
|
|
if (pthread_mutex_unlock(&d->lock)) abort();
|
|
}
|
|
|
|
void usage(void)
|
|
{
|
|
printf(
|
|
"options:\n"
|
|
" -d <database file> this option is mandatory\n"
|
|
" -on <GROUP or ID> turn log ON for given GROUP or ID\n"
|
|
" -off <GROUP or ID> turn log OFF for given GROUP or ID\n"
|
|
" -ON turn all logs ON\n"
|
|
" -OFF turn all logs OFF\n"
|
|
" note: you may pass several -on/-off/-ON/-OFF,\n"
|
|
" they will be processed in order\n"
|
|
" by default, all is off\n"
|
|
" -ip <host> connect to given IP address (default %s)\n"
|
|
" -p <port> connect to given port (default %d)\n"
|
|
" -debug-gui activate GUI debug logs\n",
|
|
DEFAULT_REMOTE_IP,
|
|
DEFAULT_REMOTE_PORT
|
|
);
|
|
exit(1);
|
|
}
|
|
|
|
static void *gui_thread(void *_g)
|
|
{
|
|
gui *g = _g;
|
|
gui_loop(g);
|
|
return NULL;
|
|
}
|
|
|
|
static void vcd_main_gui(gui *g, event_handler *h, void *database)
|
|
{
|
|
int i, j;
|
|
int n;
|
|
int nb_functions = 0;
|
|
char **ids;
|
|
widget *win;
|
|
widget *container;
|
|
widget *w;
|
|
view *timeview;
|
|
view *subview;
|
|
logger *timelog;
|
|
|
|
/* get number of vcd functions - look for all events VCD_FUNCTION_xxx */
|
|
n = database_get_ids(database, &ids);
|
|
for (i = 0; i < n; i++) {
|
|
if (strncmp(ids[i], "VCD_FUNCTION_", 13) != 0) continue;
|
|
nb_functions++;
|
|
}
|
|
|
|
win = new_toplevel_window(g, 1000, 5 * nb_functions, "VCD tracer");
|
|
container = new_container(g, VERTICAL);
|
|
widget_add_child(g, win, container, -1);
|
|
|
|
w = new_timeline(g, 1000, nb_functions, 5);
|
|
widget_add_child(g, container, w, -1);
|
|
for (i = 0; i < nb_functions; i++)
|
|
timeline_set_subline_background_color(g, w, i,
|
|
new_color(g, i & 1 ? "#ddd" : "#eee"));
|
|
timeview = new_view_time(3600, 10, g, w);
|
|
i = 0;
|
|
for (j = 0; j < n; j++) {
|
|
if (strncmp(ids[j], "VCD_FUNCTION_", 13) != 0) continue;
|
|
timelog = new_timelog(h, database, ids[j]);
|
|
subview = new_subview_time(timeview, i, FOREGROUND_COLOR, 3600*1000);
|
|
logger_add_view(timelog, subview);
|
|
i++;
|
|
}
|
|
|
|
free(ids);
|
|
}
|
|
|
|
int main(int n, char **v)
|
|
{
|
|
extern int volatile gui_logd;
|
|
char *database_filename = NULL;
|
|
void *database;
|
|
char *ip = DEFAULT_REMOTE_IP;
|
|
int port = DEFAULT_REMOTE_PORT;
|
|
char **on_off_name;
|
|
int *on_off_action;
|
|
int on_off_n = 0;
|
|
int *is_on;
|
|
int number_of_events;
|
|
int i;
|
|
event_handler *h;
|
|
gui *g;
|
|
vcd_data vcd_data;
|
|
|
|
/* write on a socket fails if the other end is closed and we get SIGPIPE */
|
|
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort();
|
|
|
|
on_off_name = malloc(n * sizeof(char *)); if (on_off_name == NULL) abort();
|
|
on_off_action = malloc(n * sizeof(int)); if (on_off_action == NULL) abort();
|
|
|
|
for (i = 1; i < n; i++) {
|
|
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
|
|
if (!strcmp(v[i], "-d"))
|
|
{ if (i > n-2) usage(); database_filename = v[++i]; continue; }
|
|
if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; }
|
|
if (!strcmp(v[i], "-p"))
|
|
{ if (i > n-2) usage(); port = atoi(v[++i]); continue; }
|
|
if (!strcmp(v[i], "-on")) { if (i > n-2) usage();
|
|
on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=1; continue; }
|
|
if (!strcmp(v[i], "-off")) { if (i > n-2) usage();
|
|
on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=0; continue; }
|
|
if (!strcmp(v[i], "-ON"))
|
|
{ on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; }
|
|
if (!strcmp(v[i], "-OFF"))
|
|
{ on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; }
|
|
if (!strcmp(v[i], "-debug-gui")) { gui_logd = 1; continue; }
|
|
usage();
|
|
}
|
|
|
|
if (database_filename == NULL) {
|
|
printf("ERROR: provide a database file (-d)\n");
|
|
exit(1);
|
|
}
|
|
|
|
database = parse_database(database_filename);
|
|
|
|
load_config_file(database_filename);
|
|
|
|
number_of_events = number_of_ids(database);
|
|
is_on = calloc(number_of_events, sizeof(int));
|
|
if (is_on == NULL) abort();
|
|
|
|
h = new_handler(database);
|
|
|
|
g = gui_init();
|
|
new_thread(gui_thread, g);
|
|
|
|
vcd_main_gui(g, h, database);
|
|
|
|
on_off(database, "VCD_FUNCTION", is_on, 1);
|
|
|
|
for (i = 0; i < on_off_n; i++)
|
|
on_off(database, on_off_name[i], is_on, on_off_action[i]);
|
|
|
|
vcd_data.socket = -1;
|
|
vcd_data.is_on = is_on;
|
|
vcd_data.nevents = number_of_events;
|
|
if (pthread_mutex_init(&vcd_data.lock, NULL)) abort();
|
|
setup_event_selector(g, database, is_on, is_on_changed, &vcd_data);
|
|
|
|
vcd_data.socket = connect_to(ip, port);
|
|
|
|
/* send the first message - activate selected traces */
|
|
is_on_changed(&vcd_data);
|
|
|
|
OBUF ebuf = { osize: 0, omaxsize: 0, obuf: NULL };
|
|
|
|
/* read messages */
|
|
while (1) {
|
|
event e;
|
|
e = get_event(vcd_data.socket, &ebuf, database);
|
|
if (e.type == -1) abort();
|
|
handle_event(h, e);
|
|
}
|
|
|
|
return 0;
|
|
}
|