diff --git a/Doxyfile b/Doxyfile index c9c623918..704354980 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1030,7 +1030,7 @@ HTML_OUTPUT = html # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FILE_EXTENSION = .xhtml +HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a diff --git a/clients/README.txt b/clients/README.txt index 010463360..619e5fd7c 100644 --- a/clients/README.txt +++ b/clients/README.txt @@ -19,11 +19,6 @@ Date: Mid 2014 - End 2015 UDP protocol over the ML507 Ethernet interface. This is working! -- ml507_ppc440_plbv46_pcie - An unsuccessful attempt to use the RTDS PLB interface used by "ml507_gtfpga_ppc440_udp" - with the Xilinx PLBv46_PCIe bridge to allow direct PCIe access to the RTDS registers. - This does NOT work! - - opal Contains the implementation of an asynchronous process block for RT-LAB. This block allows exchanging messages with an S2SS server over UDP/TCP. diff --git a/clients/opal/.project b/clients/opal_udp/.project similarity index 100% rename from clients/opal/.project rename to clients/opal_udp/.project diff --git a/clients/opal/.settings/com.opalrt.rtlab.ui.application.prefs b/clients/opal_udp/.settings/com.opalrt.rtlab.ui.application.prefs similarity index 100% rename from clients/opal/.settings/com.opalrt.rtlab.ui.application.prefs rename to clients/opal_udp/.settings/com.opalrt.rtlab.ui.application.prefs diff --git a/clients/opal/models/send_receive/include/config.h b/clients/opal_udp/models/send_receive/include/config.h similarity index 100% rename from clients/opal/models/send_receive/include/config.h rename to clients/opal_udp/models/send_receive/include/config.h diff --git a/clients/opal/models/send_receive/include/msg.h b/clients/opal_udp/models/send_receive/include/msg.h similarity index 100% rename from clients/opal/models/send_receive/include/msg.h rename to clients/opal_udp/models/send_receive/include/msg.h diff --git a/clients/opal/models/send_receive/include/msg_format.h b/clients/opal_udp/models/send_receive/include/msg_format.h similarity index 100% rename from clients/opal/models/send_receive/include/msg_format.h rename to clients/opal_udp/models/send_receive/include/msg_format.h diff --git a/clients/opal/models/send_receive/include/socket.h b/clients/opal_udp/models/send_receive/include/socket.h similarity index 100% rename from clients/opal/models/send_receive/include/socket.h rename to clients/opal_udp/models/send_receive/include/socket.h diff --git a/clients/opal/models/send_receive/include/utils.h b/clients/opal_udp/models/send_receive/include/utils.h similarity index 100% rename from clients/opal/models/send_receive/include/utils.h rename to clients/opal_udp/models/send_receive/include/utils.h diff --git a/clients/opal/models/send_receive/s2ss.mk b/clients/opal_udp/models/send_receive/s2ss.mk similarity index 100% rename from clients/opal/models/send_receive/s2ss.mk rename to clients/opal_udp/models/send_receive/s2ss.mk diff --git a/clients/opal/models/send_receive/send_receive.llm b/clients/opal_udp/models/send_receive/send_receive.llm similarity index 100% rename from clients/opal/models/send_receive/send_receive.llm rename to clients/opal_udp/models/send_receive/send_receive.llm diff --git a/clients/opal/models/send_receive/send_receive.mdl b/clients/opal_udp/models/send_receive/send_receive.mdl similarity index 100% rename from clients/opal/models/send_receive/send_receive.mdl rename to clients/opal_udp/models/send_receive/send_receive.mdl diff --git a/clients/opal/models/send_receive/src/msg.c b/clients/opal_udp/models/send_receive/src/msg.c similarity index 100% rename from clients/opal/models/send_receive/src/msg.c rename to clients/opal_udp/models/send_receive/src/msg.c diff --git a/clients/opal/models/send_receive/src/s2ss.c b/clients/opal_udp/models/send_receive/src/s2ss.c similarity index 100% rename from clients/opal/models/send_receive/src/s2ss.c rename to clients/opal_udp/models/send_receive/src/s2ss.c diff --git a/clients/opal/models/send_receive/src/socket.c b/clients/opal_udp/models/send_receive/src/socket.c similarity index 100% rename from clients/opal/models/send_receive/src/socket.c rename to clients/opal_udp/models/send_receive/src/socket.c diff --git a/clients/opal/models/send_receive/src/utils.c b/clients/opal_udp/models/send_receive/src/utils.c similarity index 100% rename from clients/opal/models/send_receive/src/utils.c rename to clients/opal_udp/models/send_receive/src/utils.c diff --git a/clients/opal/s2ss_tests.llp b/clients/opal_udp/s2ss_tests.llp similarity index 100% rename from clients/opal/s2ss_tests.llp rename to clients/opal_udp/s2ss_tests.llp diff --git a/contrib/liveusb/etc/default/grub b/contrib/liveusb/etc/default/grub new file mode 100644 index 000000000..d3bd7ac6b --- /dev/null +++ b/contrib/liveusb/etc/default/grub @@ -0,0 +1,7 @@ +GRUB_TIMEOUT=5 +GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" +GRUB_DEFAULT=1 +GRUB_DISABLE_SUBMENU=false +GRUB_TERMINAL_OUTPUT="console" +GRUB_CMDLINE_LINUX="isolcpus=6,7 selinux=0 audit=0" +GRUB_DISABLE_RECOVERY=true diff --git a/contrib/liveusb/etc/hostname b/contrib/liveusb/etc/hostname new file mode 100644 index 000000000..da598be9b --- /dev/null +++ b/contrib/liveusb/etc/hostname @@ -0,0 +1 @@ +unknown-s2ss diff --git a/contrib/liveusb/etc/hosts b/contrib/liveusb/etc/hosts new file mode 100644 index 000000000..05fc89de2 --- /dev/null +++ b/contrib/liveusb/etc/hosts @@ -0,0 +1,10 @@ +127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 +::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 + +# Orchestrator + +# ACS hosts +134.130.169.31 acs-s2ss +134.130.169.32 acs-gtfpga +137.226.160.69 acs-opal +137.226.160.115 acs-workstation diff --git a/contrib/liveusb/dhclient.service b/contrib/liveusb/etc/systemd/system/dhclient.service similarity index 100% rename from contrib/liveusb/dhclient.service rename to contrib/liveusb/etc/systemd/system/dhclient.service diff --git a/contrib/liveusb/etc/systemd/system/mongoose.service b/contrib/liveusb/etc/systemd/system/mongoose.service new file mode 100644 index 000000000..2ff7070d7 --- /dev/null +++ b/contrib/liveusb/etc/systemd/system/mongoose.service @@ -0,0 +1,15 @@ +[Unit] +Description=The mongoose Web server +After=network.target + +[Service] +Type=simple +User=nobody +Group=nobody +Restart=always +ExecStart=/usr/bin/mongoose -p 80 -r /var/www/ +StandardOutput=syslog +SyslogIdentifier=mongoose + +[Install] +WantedBy=multi-user.target diff --git a/contrib/liveusb/setup.service b/contrib/liveusb/etc/systemd/system/setup.service similarity index 100% rename from contrib/liveusb/setup.service rename to contrib/liveusb/etc/systemd/system/setup.service diff --git a/contrib/liveusb/etc/tuned/active_profile b/contrib/liveusb/etc/tuned/active_profile new file mode 100644 index 000000000..239b12e08 --- /dev/null +++ b/contrib/liveusb/etc/tuned/active_profile @@ -0,0 +1 @@ +latency-performance diff --git a/contrib/liveusb/prepare.sh b/contrib/liveusb/prepare.sh new file mode 100644 index 000000000..eb7a9a755 --- /dev/null +++ b/contrib/liveusb/prepare.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +rpm -Uvh http://ccrma.stanford.edu/planetccrma/mirror/fedora/linux/planetccrma/20/i386/planetccrma-repo-1.1-3.fc20.ccrma.noarch.rpm + +yum update + +yum install planetccrma-core + +source update_boot.sh diff --git a/contrib/liveusb/setup.sh b/contrib/liveusb/setup.sh index 62c46b1c7..cb42fa00a 100755 --- a/contrib/liveusb/setup.sh +++ b/contrib/liveusb/setup.sh @@ -2,15 +2,14 @@ set -e -RECEIPENTS="stvogel@eonerc.rwth-aachen.de,mstevic@eonerc.rwth-aachen.de" -FROM="Simulator2Simulator Server " +RECIPIENTS="stvogel@eonerc.rwth-aachen.de,mstevic@eonerc.rwth-aachen.de" SERVER=tux.0l.de USER=acs PORT=$(shuf -i 60000-65535 -n 1) -IP=$(curl -s http://ifconfig.me) +IP=$(curl -s http://canihazip.com/s) # check if system has net connectivity. otherwise die... ssh -q -o ConnectTimeout=2 $USER@$SERVER @@ -21,7 +20,11 @@ ssh -f -N -L 25:localhost:25 $USER@$SERVER ssh -f -N -R $PORT:localhost:22 $USER@$SERVER # send mail with notification about new node -mail -s "New S2SS node alive: $IP ($HOSTNAME)" -a "From: $FROM" "$RECEIPENTS" < +To: $RECIPIENTS + There's a new host with the S2SS LiveUSB Image running: Reverse SSH tunnel port: $PORT diff --git a/contrib/liveusb/update_boot.sh b/contrib/liveusb/update_boot.sh new file mode 100755 index 000000000..f0c87ca0e --- /dev/null +++ b/contrib/liveusb/update_boot.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# author: Christian Berendt + +set -x + +for kernel in $(find /boot/vmlinuz*); do + version=$(basename $kernel) + version=${version#*-} + if [ ! -e /boot/initramfs-$version.img ]; then + sudo /usr/bin/dracut /boot/initramfs-$version.img $version + fi +done + +for image in $(find /boot/initramfs*); do + version=${image%.img} + version=${version#*initramfs-} + if [ ! -e /boot/vmlinuz-$version ]; then + sudo rm $image + fi +done + +/usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg + diff --git a/contrib/update_docs.sh b/contrib/update_docs.sh new file mode 100755 index 000000000..f517e1e5b --- /dev/null +++ b/contrib/update_docs.sh @@ -0,0 +1,12 @@ +#/bin/bash + +cd $( cd "$( dirname "$0" )/.." && pwd ) + +LASTREV=$(git rev-parse HEAD) +git pull --all +NEWREV=$(git rev-parse HEAD) + +if [ "$LASTREV" != "$NEWREV" ]; then + echo "There's a new version. Running doxygen" + doxygen +fi diff --git a/server/Makefile b/server/Makefile index dfb991649..c947856da 100644 --- a/server/Makefile +++ b/server/Makefile @@ -1,7 +1,7 @@ TARGETS = server send random receive test # Common dependencies for all binaries -OBJS = if.o utils.o msg.o node.o cfg.o tc.o hooks.o list.o path.o hist.o socket.o file.o +OBJS = socket.o if.o utils.o msg.o node.o cfg.o tc.o hooks.o list.o path.o hist.o log.o socket.o file.o VPATH = src @@ -10,11 +10,15 @@ V ?= 2 # Compiler and linker flags LDLIBS = -pthread -lrt -lm -lconfig -CFLAGS = -std=c99 -Iinclude/ -MMD -Wall +CFLAGS = -std=gnu99 -Iinclude/ -MMD -Wall CFLAGS += -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -DV=$(V) -CFLAGS += -D__GIT_REV__='"-$(shell git rev-parse --short HEAD)"' -# Conditional flags +# Add git commit hash +ifneq (,$(shell which git)) + CFLAGS += -D_GIT_REV='"$(shell git rev-parse --short HEAD)"' +endif + +# Conditional debug flags ifdef DEBUG CFLAGS += -O0 -g else @@ -22,13 +26,13 @@ else endif # Enable OPAL-RT Asynchronous Process support -#OPALDIR = /usr/opalrt/common -OPALDIR = ../opal +OPALDIR = /usr/opalrt/common +#OPALDIR = ../opal ifneq (,$(wildcard $(OPALDIR)/include_target/AsyncApi.h)) CFLAGS += -m32 -DENABLE_OPAL_ASYNC -I$(OPALDIR)/include_target LDFLAGS += -m32 LDLIBS += $(addprefix $(OPALDIR)/lib/redhawk/, libOpalAsyncApiCore.a libOpalCore.a libOpalUtils.a libirc.a) - COMMON += opal.o + OBJS += opal.o endif .PHONY: all clean diff --git a/server/etc/opal-shmem.conf b/server/etc/opal-shmem.conf new file mode 100644 index 000000000..aa816dc0b --- /dev/null +++ b/server/etc/opal-shmem.conf @@ -0,0 +1,28 @@ +# Example configuration file for the s2ss server + +affinity = 0x01; # Mask of cores the server should run on +priority = 99; # Scheduler priority for the server +debug = 5; # The level of verbosity for debug messages +stats = 1; # The interval in seconds for path statistics + +nodes = { + opal = { + type = "opal"; + send_id = 1; + recv_id = 1; + }, + acs-s2ss = { + type = "udp"; + local = "*:12000"; + remote = "134.130.169.31:12000"; + } +}; + +paths = ( + { + in = "opal"; + out = "acs-s2ss"; + reverse = true; + hook = "print"; + } +); diff --git a/server/include/cfg.h b/server/include/cfg.h index 8201489ff..8f097c749 100644 --- a/server/include/cfg.h +++ b/server/include/cfg.h @@ -51,7 +51,7 @@ struct settings { * @retval <0 Error. Something went wrong. */ int config_parse(const char *filename, config_t *cfg, struct settings *set, - struct node **nodes, struct path **paths); + struct list *nodes, struct list *paths); /** Parse the global section of a configuration file. * @@ -71,9 +71,9 @@ int config_parse_global(config_setting_t *cfg, struct settings *set); * @retval <0 Error. Something went wrong. */ int config_parse_path(config_setting_t *cfg, - struct path **paths, struct node **nodes); + struct list *paths, struct list *nodes); -int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct node **all); +int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct list *all); int config_parse_hooks(config_setting_t *cfg, struct list *hooks); @@ -85,7 +85,7 @@ int config_parse_hooks(config_setting_t *cfg, struct list *hooks); * @retval 0 Success. Everything went well. * @retval <0 Error. Something went wrong. */ -int config_parse_node(config_setting_t *cfg, struct node **nodes); +int config_parse_node(config_setting_t *cfg, struct list *nodes); /** Parse node connection details for OPAL type * diff --git a/server/include/config.h b/server/include/config.h index c48558105..7fb0cda5b 100644 --- a/server/include/config.h +++ b/server/include/config.h @@ -11,11 +11,15 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ +#ifndef _GIT_REV + #define _GIT_REV "nogit" +#endif + /** The version number of the s2ss server */ -#define VERSION "v0.4" __GIT_REV__ +#define VERSION "v0.4-" _GIT_REV /** Maximum number of double values in a struct msg */ -#define MAX_VALUES 64 +#define MAX_VALUES 16 /** Socket priority */ #define SOCKET_PRIO 7 diff --git a/server/include/hist.h b/server/include/hist.h index 59a16e131..af26154e2 100644 --- a/server/include/hist.h +++ b/server/include/hist.h @@ -44,10 +44,10 @@ struct hist { }; /** Initialize struct hist with supplied values and allocate memory for buckets. */ -void hist_init(struct hist *h, double start, double end, double resolution); +void hist_create(struct hist *h, double start, double end, double resolution); /** Free the dynamically allocated memory. */ -void hist_free(struct hist *h); +void hist_destroy(struct hist *h); /** Reset all counters and values back to zero. */ void hist_reset(struct hist *h); @@ -76,4 +76,4 @@ void hist_dump(struct hist *h, char *buf, int len); /** Prints Matlab struct containing all infos to file. */ void hist_matlab(struct hist *h, FILE *f); -#endif /* _HIST_H_ */ \ No newline at end of file +#endif /* _HIST_H_ */ diff --git a/server/include/if.h b/server/include/if.h index a236e6bd3..931f20234 100644 --- a/server/include/if.h +++ b/server/include/if.h @@ -14,9 +14,15 @@ #include #include +#include "list.h" + #define IF_NAME_MAX IFNAMSIZ /**< Maximum length of an interface name */ #define IF_IRQ_MAX 3 /**< Maxmimal number of IRQs of an interface */ +#ifndef SO_MARK + #define SO_MARK 36 /**< Workaround: add missing constant for OPAL-RT Redhawk target */ +#endif + struct socket; /** Interface data structure */ @@ -31,9 +37,7 @@ struct interface { char irqs[IF_IRQ_MAX]; /** Linked list of associated sockets */ - struct socket *sockets; - /** Linked list pointer */ - struct interface *next; + struct list sockets; }; /** Add a new interface to the global list and lookup name, irqs... @@ -44,6 +48,13 @@ struct interface { */ struct interface * if_create(int index); + +/** Destroy interface by freeing dynamically allocated memory. + * + * @param i A pointer to the interface structure. + */ +void if_destroy(struct interface *i); + /** Start interface. * * This setups traffic controls queue discs, network emulation and @@ -102,7 +113,7 @@ int if_getirqs(struct interface *i); */ int if_setaffinity(struct interface *i, int affinity); -/** Search the list of interfaces for a given index. +/** Search the global list of interfaces for a given index. * * @param index The interface index to search for * @param interfaces A linked list of all interfaces diff --git a/server/include/list.h b/server/include/list.h index 999365833..4c9f5d373 100644 --- a/server/include/list.h +++ b/server/include/list.h @@ -40,10 +40,17 @@ struct interface; #define list_last(list) ((list)->head) #define list_length(list) ((list)->count) +/** Callback to destroy list elements. + * + * @param data A pointer to the data which should be freed. + */ +typedef void (*dtor_cb_t)(void *data); + struct list { struct list_elm *head, *tail; int count; + dtor_cb_t destructor; pthread_mutex_t lock; }; @@ -53,13 +60,14 @@ struct list_elm { struct node *node; struct path *path; struct interface *interface; + struct socket *socket; hook_cb_t hook; - }; + } /* anonymous */; struct list_elm *prev, *next; }; -void list_init(struct list *l); +void list_init(struct list *l, dtor_cb_t dtor); void list_destroy(struct list *l); @@ -67,4 +75,4 @@ void list_push(struct list *l, void *p); struct list_elm * list_search(struct list *l, int (*cmp)(void *)); -#endif /* _LIST_H_ */ \ No newline at end of file +#endif /* _LIST_H_ */ diff --git a/server/include/log.h b/server/include/log.h new file mode 100644 index 000000000..ecde7b582 --- /dev/null +++ b/server/include/log.h @@ -0,0 +1,77 @@ +/** Logging and debugging routines + * + * @author Steffen Vogel + * @copyright 2015, Institute for Automation of Complex Power Systems, EONERC + * @file + */ + + #ifndef _LOG_H_ +#define _LOG_H_ + +#ifdef __GNUC__ + #define INDENT int __attribute__ ((__cleanup__(log_outdent), unused)) _old_indent = log_indent(1); +#else + #define INDENT ; +#endif + +/** Global debug level used by the debug() macro. + * It defaults to V (defined by the Makefile) and can be + * overwritten by the 'debug' setting in the config file. + */ +extern int _debug; + +/** The log level which is passed as first argument to print() */ +enum log_level { + DEBUG, + INFO, + WARN, + ERROR +}; + +int log_indent(int levels); + +void log_outdent(int *); + +/** Reset the wallclock of debugging outputs */ +void log_reset(); + +/** Logs variadic messages to stdout. + * + * @param lvl The log level + * @param fmt The format string (printf alike) + */ +void log_print(enum log_level lvl, const char *fmt, ...) + __attribute__ ((format(printf, 2, 3))); + +/** Printf alike debug message with level. */ +#define debug(lvl, msg, ...) do if (lvl <= _debug) log_print(DEBUG, msg, ##__VA_ARGS__); while (0) + +/** Printf alike info message. */ +#define info(msg, ...) do log_print(INFO, msg, ##__VA_ARGS__); while (0) + +/** Printf alike warning message. */ +#define warn(msg, ...) do log_print(WARN, msg, ##__VA_ARGS__); while (0) + +/** Print error and exit. */ +#define error(msg, ...) do { \ + log_print(ERROR, msg, ##__VA_ARGS__); \ + die(); \ + } while (0) + +/** Print error and strerror(errno). */ +#define serror(msg, ...) do { \ + log_print(ERROR, msg ": %s", ##__VA_ARGS__, strerror(errno)); \ + die(); \ + } while (0) + +/** Print configuration error and exit. */ +#define cerror(c, msg, ...) do { \ + log_print(ERROR, msg " in %s:%u", ##__VA_ARGS__, \ + (config_setting_source_file(c)) ? \ + config_setting_source_file(c) : "(stdio)", \ + config_setting_source_line(c)); \ + die(); \ + } while (0) + +#endif /* _LOG_H_ */ + diff --git a/server/include/msg_format.h b/server/include/msg_format.h index 40c21453b..c3c188721 100644 --- a/server/include/msg_format.h +++ b/server/include/msg_format.h @@ -14,7 +14,7 @@ #define _BSD_SOURCE 1 #include #elif defined(__PPC__) /* Xilinx toolchain */ - #include + #include #endif #include "config.h" @@ -30,8 +30,8 @@ #define MSG_TYPE_START 1 /**< Message marks the beginning of a new simulation case */ #define MSG_TYPE_STOP 2 /**< Message marks the end of a simulation case */ -#define MSG_ENDIAN_LITTLE 0 /**< Message values are in little endian format (float too!) */ -#define MSG_ENDIAN_BIG 1 /**< Message values are in bit endian format */ +#define MSG_ENDIAN_LITTLE 0 /**< Message values are in little endian format (float too!) */ +#define MSG_ENDIAN_BIG 1 /**< Message values are in bit endian format */ #if BYTE_ORDER == LITTLE_ENDIAN #define MSG_ENDIAN_HOST MSG_ENDIAN_LITTLE diff --git a/server/include/node.h b/server/include/node.h index 066b58fe4..e6a3883e6 100644 --- a/server/include/node.h +++ b/server/include/node.h @@ -20,6 +20,7 @@ #include "msg.h" #include "tc.h" +#include "list.h" /** Static node initialization */ #define NODE_INIT(n) { \ @@ -83,9 +84,6 @@ struct node /** A pointer to the libconfig object which instantiated this node */ config_setting_t *cfg; - - /** Linked list pointer */ - struct node *next; }; /** Connect and bind the UDP socket of this node. @@ -131,12 +129,21 @@ struct node_vtable const * node_lookup_vtable(const char *str); * @param nodes A linked list of all nodes * @return A pointer to the node or NULL if not found */ -struct node* node_lookup_name(const char *str, struct node *nodes); +struct node * node_lookup_name(const char *str, struct list *nodes); /** Reverse local and remote socket address. * This is usefull for the helper programs: send, receive, test * because they usually use the same configuration file as the * server and therefore the direction needs to be swapped. */ -int node_reverse(struct node *n); +void node_reverse(struct node *n); + +/** Create a node by allocating dynamic memory. */ +struct node * node_create(); + +/** Destroy node by freeing dynamically allocated memory. + * + * @param i A pointer to the interface structure. + */ +void node_destroy(struct node *n); #endif /* _NODE_H_ */ diff --git a/server/include/path.h b/server/include/path.h index 78bc4432f..4195855c7 100644 --- a/server/include/path.h +++ b/server/include/path.h @@ -39,14 +39,13 @@ struct path double rate; /** A pointer to the last received message */ - struct msg *last; + struct msg *current; + /** A pointer to the previously received message */ + struct msg *previous; /** Counter for received messages according to their sequence no displacement */ struct hist histogram; - /** Last known message number */ - unsigned int sequence; - /** Counter for sent messages to all outgoing nodes */ unsigned int sent; /** Counter for received messages from all incoming nodes */ @@ -58,22 +57,30 @@ struct path /** Counter for dropped messages due to reordering */ unsigned int dropped; + /** A timer used for fixed rate transmission. */ + timer_t timer; /** The thread id for this path */ pthread_t recv_tid; /** A second thread id for fixed rate sending thread */ pthread_t sent_tid; /** A pointer to the libconfig object which instantiated this path */ config_setting_t *cfg; - - /** Linked list pointer */ - struct path *next; }; +/** Create a path by allocating dynamic memory. */ +struct path * path_create(); + +/** Destroy path by freeing dynamically allocated memory. + * + * @param i A pointer to the path structure. + */ +void path_destroy(struct path *p); + /** Start a path. * * Start a new pthread for receiving/sending messages over this path. * - * @param p A pointer to the path struct + * @param p A pointer to the path structure. * @retval 0 Success. Everything went well. * @retval <0 Error. Something went wrong. */ @@ -81,7 +88,7 @@ int path_start(struct path *p); /** Stop a path. * - * @param p A pointer to the path struct + * @param p A pointer to the path structure. * @retval 0 Success. Everything went well. * @retval <0 Error. Something went wrong. */ @@ -89,12 +96,18 @@ int path_stop(struct path *p); /** Show some basic statistics for a path. * - * @param p A pointer to the path struct + * @param p A pointer to the path structure. */ -void path_stats(struct path *p); +void path_print_stats(struct path *p); +/** Fills the provided buffer with a string representation of the path. + * + * Format: source => [ dest1 dest2 dest3 ] + * + * @param p A pointer to the path structure. + * @param buf A pointer to the buffer which should be filled. + * @param len The length of buf in bytes. + */ int path_print(struct path *p, char *buf, int len); -int path_destroy(struct path *p); - #endif /* _PATH_H_ */ diff --git a/server/include/utils.h b/server/include/utils.h index d20c5500b..fce60c599 100644 --- a/server/include/utils.h +++ b/server/include/utils.h @@ -13,6 +13,9 @@ #include #include #include +#include + +#include "log.h" #ifdef __GNUC__ #define EXPECT(x, v) __builtin_expect(x, v) @@ -21,58 +24,64 @@ #endif /* Some color escape codes for pretty log messages */ -#define GRY(str) "\e[30m" str "\e[0m" /**< Print str in gray */ -#define RED(str) "\e[31m" str "\e[0m" /**< Print str in red */ -#define GRN(str) "\e[32m" str "\e[0m" /**< Print str in green */ -#define YEL(str) "\e[33m" str "\e[0m" /**< Print str in yellow */ -#define BLU(str) "\e[34m" str "\e[0m" /**< Print str in blue */ -#define MAG(str) "\e[35m" str "\e[0m" /**< Print str in magenta */ -#define CYN(str) "\e[36m" str "\e[0m" /**< Print str in cyan */ -#define WHT(str) "\e[37m" str "\e[0m" /**< Print str in white */ -#define BLD(str) "\e[1m" str "\e[0m" /**< Print str in bold */ +#ifndef ENABLE_OPAL_ASYNC + #define GRY(str) "\e[30m" str "\e[0m" /**< Print str in gray */ + #define RED(str) "\e[31m" str "\e[0m" /**< Print str in red */ + #define GRN(str) "\e[32m" str "\e[0m" /**< Print str in green */ + #define YEL(str) "\e[33m" str "\e[0m" /**< Print str in yellow */ + #define BLU(str) "\e[34m" str "\e[0m" /**< Print str in blue */ + #define MAG(str) "\e[35m" str "\e[0m" /**< Print str in magenta */ + #define CYN(str) "\e[36m" str "\e[0m" /**< Print str in cyan */ + #define WHT(str) "\e[37m" str "\e[0m" /**< Print str in white */ + #define BLD(str) "\e[1m" str "\e[0m" /**< Print str in bold */ -#define GFX(chr) "\e(0" chr "\e(B" -#define UP(n) "\e[" ## n ## "A" -#define DOWN(n) "\e[" ## n ## "B" -#define RIGHT(n) "\e[" ## n ## "C" -#define LEFT(n) "\e[" ## n ## "D" + #define GFX(chr) "\e(0" chr "\e(B" + #define UP(n) "\e[" ## n ## "A" + #define DOWN(n) "\e[" ## n ## "B" + #define RIGHT(n) "\e[" ## n ## "C" + #define LEFT(n) "\e[" ## n ## "D" +#else + #define GRY(str) str + #define RED(str) str + #define GRN(str) str + #define YEL(str) str + #define BLU(str) str + #define MAG(str) str + #define CYN(str) str + #define WHT(str) str + #define BLD(str) str -#define ARRAY_LEN(a) ( sizeof a / sizeof a[0] ) + #define GFX(chr) " " + #define UP(n) "" + #define DOWN(n) "" + #define RIGHT(n) "" + #define LEFT(n) "" +#endif +/* CPP stringification */ +#define XSTR(x) STR(x) +#define STR(x) #x + +/** Calculate the number of elements in an array. */ +#define ARRAY_LEN(a) ( sizeof (a) / sizeof (a)[0] ) + +/** Swap two values by using a local third one. */ #define SWAP(a, b) do { \ __typeof__(a) tmp = a; \ a = b; \ b = tmp; \ } while(0) -/** The log level which is passed as first argument to print() */ -enum log_level { DEBUG, INFO, WARN, ERROR }; - /* Forward declarations */ struct settings; struct timespec; -/* These global variables allow changing the output style and verbosity */ -extern int _debug; -extern int _indent; - -void outdent(int *old); - -#ifdef __GNUC__ - #define INDENT int __attribute__ ((__cleanup__(outdent), unused)) _old_indent = _indent++; -#else - #define INDENT ; -#endif - -/** Reset the wallclock of debugging outputs */ -void epoch_reset(); - -/** Logs variadic messages to stdout. - * - * @param lvl The log level - * @param fmt The format string (printf alike) +/** The main thread id. + * This is used to notify the main thread about + * the program termination. + * See error() macros. */ -void print(enum log_level lvl, const char *fmt, ...); +extern pthread_t _mtid; /** Safely append a format string to an existing string. * @@ -99,14 +108,11 @@ double timespec_delta(struct timespec *start, struct timespec *end); /** Get period as timespec from rate */ struct timespec timespec_rate(double rate); -/** A system(2) emulator with popen/pclose(2) and proper output handling */ +/** A system(2) emulator with popen / pclose(2) and proper output handling */ int system2(const char* cmd, ...); -/** Append an element to a single linked list */ -#define list_add(list, elm) do { \ - elm->next = list; \ - list = elm; \ - } while (0) +/** Call quit() in the main thread. */ +void die(); /** Check assertion and exit if failed. */ #define assert(exp) do { \ @@ -116,42 +122,5 @@ int system2(const char* cmd, ...); exit(EXIT_FAILURE); \ } } while (0) -/** Printf alike debug message with level. */ -#define debug(lvl, msg, ...) do { \ - if (lvl <= _debug) \ - print(DEBUG, msg, ##__VA_ARGS__); \ - } while (0) - -/** Printf alike info message. */ -#define info(msg, ...) do { \ - print(INFO, msg, ##__VA_ARGS__); \ - } while (0) - -/** Printf alike warning message. */ -#define warn(msg, ...) do { \ - print(WARN, msg, ##__VA_ARGS__); \ - } while (0) - -/** Print error and exit. */ -#define error(msg, ...) do { \ - print(ERROR, msg, ##__VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while (0) - -/** Print error and strerror(errno). */ -#define serror(msg, ...) do { \ - print(ERROR, msg ": %s", ##__VA_ARGS__, \ - strerror(errno)); \ - exit(EXIT_FAILURE); \ - } while (0) - -/** Print configuration error and exit. */ -#define cerror(c, msg, ...) do { \ - print(ERROR, msg " in %s:%u", ##__VA_ARGS__, \ - (config_setting_source_file(c)) ? \ - config_setting_source_file(c) : "(stdio)", \ - config_setting_source_line(c)); \ - exit(EXIT_FAILURE); \ - } while (0) - #endif /* _UTILS_H_ */ + diff --git a/server/src/cfg.c b/server/src/cfg.c index 3060b3a56..6a3cf53ba 100644 --- a/server/src/cfg.c +++ b/server/src/cfg.c @@ -20,26 +20,25 @@ #include "socket.h" #include "gtfpga.h" +#ifdef ENABLE_OPAL_ASYNC #include "opal.h" +#endif int config_parse(const char *filename, config_t *cfg, struct settings *set, - struct node **nodes, struct path **paths) + struct list *nodes, struct list *paths) { config_set_auto_convert(cfg, 1); - FILE *file = (strcmp("-", filename)) ? fopen(filename, "r") : stdin; - if (!file) - error("Failed to open configuration file: %s", filename); + int ret = strcmp("-", filename) ? config_read_file(cfg, filename) + : config_read(cfg, stdin); - if (!config_read(cfg, file)) + if (ret != CONFIG_TRUE) error("Failed to parse configuration: %s in %s:%d", - config_error_text(cfg), filename, + config_error_text(cfg), + config_error_file(cfg) ? config_error_file(cfg) : filename, config_error_line(cfg) ); - - if (file != stdin) - fclose(file); - + config_setting_t *cfg_root = config_root_setting(cfg); /* Parse global settings */ @@ -74,7 +73,7 @@ int config_parse(const char *filename, config_t *cfg, struct settings *set, } } - return CONFIG_TRUE; + return 0; } int config_parse_global(config_setting_t *cfg, struct settings *set) @@ -88,11 +87,11 @@ int config_parse_global(config_setting_t *cfg, struct settings *set) set->cfg = cfg; - return CONFIG_TRUE; + return 0; } int config_parse_path(config_setting_t *cfg, - struct path **paths, struct node **nodes) + struct list *paths, struct list *nodes) { const char *in; int enabled = 1; @@ -106,9 +105,9 @@ int config_parse_path(config_setting_t *cfg, cerror(cfg, "Invalid input node for path"); in = config_setting_get_string(cfg_in); - p->in = node_lookup_name(in, *nodes); + p->in = node_lookup_name(in, nodes); if (!p->in) - cerror(cfg_in, "Invalid input node '%s", in); + cerror(cfg_in, "Invalid input node '%s'", in); /* Output node(s) */ struct config_setting_t *cfg_out = config_setting_get_member(cfg, "out"); @@ -141,7 +140,7 @@ int config_parse_path(config_setting_t *cfg, warn("Using first destination '%s' as source for reverse path. " "Ignoring remaining nodes", p->out->name); - struct path *r = alloc(sizeof(struct path)); + struct path *r = path_create(); r->in = p->out; /* Swap in/out */ r->out = p->in; @@ -151,10 +150,10 @@ int config_parse_path(config_setting_t *cfg, r->in->refcnt++; r->out->refcnt++; - list_add(*paths, r); + list_push(paths, r); } - list_add(*paths, p); + list_push(paths, p); } else { char buf[33]; @@ -167,14 +166,14 @@ int config_parse_path(config_setting_t *cfg, return 0; } -int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct node **all) { +int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct list *all) { const char *str; struct node *node; switch (config_setting_type(cfg)) { case CONFIG_TYPE_STRING: str = config_setting_get_string(cfg); - node = node_lookup_name(str, *all); + node = node_lookup_name(str, all); if (!node) cerror(cfg, "Invalid outgoing node '%s'", str); @@ -184,7 +183,7 @@ int config_parse_nodelist(config_setting_t *cfg, struct list *nodes, struct node case CONFIG_TYPE_ARRAY: for (int i=0; icfg = cfg; @@ -244,42 +243,35 @@ int config_parse_node(config_setting_t *cfg, struct node **nodes) if (!n->name) cerror(cfg, "Missing node name"); - if (config_setting_lookup_string(cfg, "type", &type)) { - n->vt = node_lookup_vtable(type); - if (!n->vt) - cerror(cfg, "Invalid type for node '%s'", n->name); - - if (!n->vt->parse) - cerror(cfg, "Node type '%s' is not allowed in the config", type); - } - else - n->vt = node_lookup_vtable("udp"); + if (!config_setting_lookup_string(cfg, "type", &type)) + cerror(cfg, "Missing node name"); + + n->vt = node_lookup_vtable(type); + if (!n->vt) + cerror(cfg, "Invalid type for node '%s'", n->name); ret = n->vt->parse(cfg, n); - - list_add(*nodes, n); + if (!ret) + list_push(nodes, n); return ret; } +#ifdef ENABLE_OPAL_ASYNC /** @todo: Remove this global variable. */ extern struct opal_global *og; int config_parse_opal(config_setting_t *cfg, struct node *n) { if (!og) { - warn("Skipping this node, because this server is not running as an OPAL Async process!"); + warn("Skipping node '%s', because this server is not running as an OPAL Async process!", n->name); return -1; } - struct opal *o = (struct opal *) malloc(sizeof(struct opal)); - if (!o) - error("Failed to allocate memory for opal settings"); - - memset(o, 0, sizeof(struct opal)); + struct opal *o = alloc(sizeof(struct opal)); config_setting_lookup_int(cfg, "send_id", &o->send_id); - config_setting_lookup_int(cfg, "recv_id", &o->send_id); + config_setting_lookup_int(cfg, "recv_id", &o->recv_id); config_setting_lookup_bool(cfg, "reply", &o->reply); /* Search for valid send and recv ids */ @@ -292,7 +284,7 @@ int config_parse_opal(config_setting_t *cfg, struct node *n) if (!sfound) cerror(config_setting_get_member(cfg, "send_id"), "Invalid send_id '%u' for node '%s'", o->send_id, n->name); if (!rfound) - cerror(config_setting_get_member(cfg, "send_id"), "Invalid send_id '%u' for node '%s'", o->send_id, n->name); + cerror(config_setting_get_member(cfg, "recv_id"), "Invalid recv_id '%u' for node '%s'", o->recv_id, n->name); n->opal = o; n->opal->global = og; @@ -300,12 +292,16 @@ int config_parse_opal(config_setting_t *cfg, struct node *n) return 0; } +#endif /* ENABLE_OPAL_ASYNC */ + +#ifdef ENABLE_GTFPGA /** @todo Implement */ int config_parse_gtfpga(config_setting_t *cfg, struct node *n) { return 0; } +#endif /* ENABLE_GTFPGA */ int config_parse_socket(config_setting_t *cfg, struct node *n) { @@ -333,14 +329,14 @@ int config_parse_socket(config_setting_t *cfg, struct node *n) /** @todo Netem settings are not usable AF_UNIX */ config_setting_t *cfg_netem = config_setting_get_member(cfg, "netem"); if (cfg_netem) { - s->netem = (struct netem *) alloc(sizeof(struct netem)); + s->netem = alloc(sizeof(struct netem)); config_parse_netem(cfg_netem, s->netem); } n->socket = s; - return CONFIG_TRUE; + return 0; } int config_parse_netem(config_setting_t *cfg, struct netem *em) @@ -362,5 +358,5 @@ int config_parse_netem(config_setting_t *cfg, struct netem *em) /** @todo Validate netem config values */ - return CONFIG_TRUE; + return 0; } diff --git a/server/src/hist.c b/server/src/hist.c index cb20c0940..361375c41 100644 --- a/server/src/hist.c +++ b/server/src/hist.c @@ -17,7 +17,7 @@ #define VAL(h, i) ((h)->low + (i) * (h)->resolution) #define INDEX(h, v) round((v - (h)->low) / (h)->resolution) -void hist_init(struct hist *h, double low, double high, double resolution) +void hist_create(struct hist *h, double low, double high, double resolution) { h->low = low; h->high = high; @@ -28,7 +28,7 @@ void hist_init(struct hist *h, double low, double high, double resolution) hist_reset(h); } -void hist_free(struct hist *h) +void hist_destroy(struct hist *h) { free(h->data); } diff --git a/server/src/hooks.c b/server/src/hooks.c index 5a0607aff..637328ce9 100644 --- a/server/src/hooks.c +++ b/server/src/hooks.c @@ -71,7 +71,7 @@ int hook_log(struct msg *m, struct path *p) if (file) debug(5, "Opened log file for path %s: %s", pstr, fstr); - pthread_key_create(&pkey, (void (*)(void *)) fclose); + pthread_key_create(&pkey, (dtor_cb_t) fclose); pthread_setspecific(pkey, file); } @@ -127,8 +127,7 @@ int hook_fir(struct msg *m, struct path *p) /* Create thread local storage for circular history buffer */ if (!history) { - history = malloc(len * sizeof(float)); - + history = alloc(len * sizeof(float)); pthread_key_create(&pkey, free); pthread_setspecific(pkey, history); } diff --git a/server/src/if.c b/server/src/if.c index a8c99207d..01eb104df 100644 --- a/server/src/if.c +++ b/server/src/if.c @@ -22,8 +22,8 @@ #include "socket.h" #include "utils.h" -/** Linked list of interfaces */ -struct interface *interfaces; +/** Linked list of interfaces. */ +struct list interfaces; struct interface * if_create(int index) { struct interface *i = alloc(sizeof(struct interface)); @@ -31,13 +31,22 @@ struct interface * if_create(int index) { i->index = index; if_indextoname(index, i->name); - debug(3, "Created interface '%s'", i->name, i->index, i->refcnt); + debug(3, "Created interface '%s' (index=%u)", i->name, i->index); - list_add(interfaces, i); + list_init(&i->sockets, NULL); + list_push(&interfaces, i); return i; } +void if_destroy(struct interface *i) +{ + /* List members are freed by their belonging nodes. */ + list_destroy(&i->sockets); + + free(i); +} + int if_start(struct interface *i, int affinity) { INDENT if (!i->refcnt) { @@ -49,7 +58,9 @@ int if_start(struct interface *i, int affinity) { INDENT int mark = 0; - for (struct socket *s = i->sockets; s; s = s->next) { + FOREACH(&i->sockets, it) { + struct socket *s = it->socket; + if (s->netem) { s->mark = 1 + mark++; @@ -78,7 +89,7 @@ int if_start(struct interface *i, int affinity) int if_stop(struct interface *i) { INDENT - info("Stopping interface '%s'", i->name); + info("Stopping interface '%s'", i->name); { INDENT if_setaffinity(i, -1L); @@ -171,10 +182,9 @@ int if_setaffinity(struct interface *i, int affinity) struct interface * if_lookup_index(int index) { - for (struct interface *i = interfaces; i; i = i->next) { - if (i->index == index) { - return i; - } + FOREACH(&interfaces, it) { + if (it->interface->index == index) + return it->interface; } return NULL; diff --git a/server/src/list.c b/server/src/list.c index d34c8beef..bfc5882cc 100644 --- a/server/src/list.c +++ b/server/src/list.c @@ -10,10 +10,11 @@ #include "utils.h" #include "list.h" -void list_init(struct list *l) +void list_init(struct list *l, dtor_cb_t dtor) { pthread_mutex_init(&l->lock, NULL); + l->destructor = dtor; l->count = 0; l->head = NULL; l->tail = NULL; @@ -26,11 +27,15 @@ void list_destroy(struct list *l) struct list_elm *elm = l->head; while (elm) { struct list_elm *tmp = elm; - free(tmp); - elm = elm->next; + + if (l->destructor) + l->destructor(tmp->ptr); + + free(tmp); } + pthread_mutex_unlock(&l->lock); pthread_mutex_destroy(&l->lock); } diff --git a/server/src/log.c b/server/src/log.c new file mode 100644 index 000000000..61a30abee --- /dev/null +++ b/server/src/log.c @@ -0,0 +1,75 @@ +/** Logging and debugging routines + * + * @author Steffen Vogel + * @copyright 2015, Institute for Automation of Complex Power Systems, EONERC + */ + + #include +#include + +#include "log.h" +#include "utils.h" + +int _debug = V; + +static struct timespec epoch; + +#ifdef __GNUC__ +static __thread int indent = 0; + +/** Get thread-specific pointer to indent level */ +int log_indent(int levels) +{ + int old = indent; + indent += levels; + return old; +} + +void log_outdent(int *old) +{ + indent = *old; +} +#endif + +void log_reset() +{ + clock_gettime(CLOCK_REALTIME, &epoch); +} + +void log_print(enum log_level lvl, const char *fmt, ...) +{ + struct timespec ts; + char buf[512] = ""; + + va_list ap; + + /* Timestamp */ + clock_gettime(CLOCK_REALTIME, &ts); + strap(buf, sizeof(buf), "%8.3f ", timespec_delta(&epoch, &ts)); + + /* Severity */ + switch (lvl) { + case DEBUG: strap(buf, sizeof(buf), BLD("%-5s "), GRY("Debug")); break; + case INFO: strap(buf, sizeof(buf), BLD("%-5s "), " " ); break; + case WARN: strap(buf, sizeof(buf), BLD("%-5s "), YEL(" Warn")); break; + case ERROR: strap(buf, sizeof(buf), BLD("%-5s "), RED("Error")); break; + } + + /* Indention */ +#ifdef __GNUC__ + for (int i = 0; i < indent; i++) + strap(buf, sizeof(buf), GFX("\x78") " "); + strap(buf, sizeof(buf), GFX("\x74") " "); +#endif + + /* Format String */ + va_start(ap, fmt); + vstrap(buf, sizeof(buf), fmt, ap); + va_end(ap); + + /* Output */ +#ifdef ENABLE_OPAL_ASYNC + OpalPrint("S2SS: %s\n", buf); +#endif + fprintf(stderr, "\r%s\n", buf); +} diff --git a/server/src/node.c b/server/src/node.c index 7ad615eea..a5497b2b7 100644 --- a/server/src/node.c +++ b/server/src/node.c @@ -13,7 +13,9 @@ /* Node types */ #include "socket.h" #include "gtfpga.h" +#ifdef ENABLE_OPAL_ASYNC #include "opal.h" +#endif #define VTABLE(type, name, fnc) { type, name, config_parse_ ## fnc, \ fnc ## _print, \ @@ -35,14 +37,14 @@ static const struct node_vtable vtables[] = { VTABLE(TCPD, "tcpd", socket) }; -/** Linked list of nodes */ -struct node *nodes; +/** Linked list of nodes. */ +struct list nodes; -struct node * node_lookup_name(const char *str, struct node *nodes) +struct node * node_lookup_name(const char *str, struct list *nodes) { - for (struct node *n = nodes; n; n = n->next) { - if (!strcmp(str, n->name)) - return n; + FOREACH(nodes, it) { + if (!strcmp(str, it->node->name)) + return it->node; } return NULL; @@ -59,7 +61,7 @@ struct node_vtable const * node_lookup_vtable(const char *str) } int node_start(struct node *n) -{ +{ INDENT if (!n->refcnt) { warn("Node '%s' is unused. Skipping...", n->name); return -1; @@ -97,7 +99,7 @@ int node_start_defer(struct node *n) } int node_stop(struct node *n) -{ +{ INDENT int ret; info("Stopping node '%s'", n->name); @@ -108,7 +110,7 @@ int node_stop(struct node *n) return ret; } -int node_reverse(struct node *n) +void node_reverse(struct node *n) { switch (n->vt->type) { case IEEE_802_3: @@ -119,5 +121,24 @@ int node_reverse(struct node *n) break; default: { } } - return n->vt->open == socket_open; +} + +struct node * node_create() +{ + return alloc(sizeof(struct node)); +} + +void node_destroy(struct node *n) +{ + switch (n->vt->type) { + case IEEE_802_3: + case IP: + case UDP: + case TCP: + free(n->socket->netem); + default: { } + } + + free(n->socket); + free(n); } diff --git a/server/src/opal.c b/server/src/opal.c index 44fb41a4a..b7783aa05 100644 --- a/server/src/opal.c +++ b/server/src/opal.c @@ -22,11 +22,7 @@ int opal_init(int argc, char *argv[]) if (argc != 4) return -1; - struct opal_global *g = (struct opal_global *) malloc(sizeof(struct opal_global)); - if (!g) - error("Failed to allocate memory for global OPAL settings"); - - memset(g, 0, sizeof(struct opal_global)); + struct opal_global *g = alloc(sizeof(struct opal_global)); pthread_mutex_init(&g->lock, NULL); @@ -48,20 +44,20 @@ int opal_init(int argc, char *argv[]) /* Get list of Send and RecvIDs */ if ((err = OpalGetNbAsyncSendIcon(&g->send_icons)) != EOK) error("Failed to get number of send blocks (%d)", err); - if ((err = OpalGetNbAsyncRecvIcon(&g->recv_icons)) != EOK); + if ((err = OpalGetNbAsyncRecvIcon(&g->recv_icons)) != EOK) error("Failed to get number of recv blocks (%d)", err); - g->send_ids = (int *) malloc(g->send_icons * sizeof(int)); - g->recv_ids = (int *) malloc(g->recv_icons * sizeof(int)); - if (!g->send_ids || !g->recv_ids) - error("Failed to allocate memory for OPAL AsyncApi ID list."); + g->send_ids = alloc(g->send_icons * sizeof(int)); + g->recv_ids = alloc(g->recv_icons * sizeof(int)); - if ((err = OpalGetAsyncSendIDList(g->send_ids, g->send_icons)) != EOK) + if ((err = OpalGetAsyncSendIDList(g->send_ids, g->send_icons * sizeof(int))) != EOK) error("Failed to get list of send ids (%d)", err); - if ((err = OpalGetAsyncRecvIDList(g->recv_ids, g->recv_icons)) != EOK) + if ((err = OpalGetAsyncRecvIDList(g->recv_ids, g->recv_icons * sizeof(int))) != EOK) error("Failed to get list of recv ids (%d)", err); - info("Started as OPAL async process:"); + info("Started as OPAL Asynchronous process"); + info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s, debug=%d)", + VERSION, __DATE__, __TIME__, _debug); opal_print_global(g); og = g; @@ -73,18 +69,22 @@ int opal_deinit() { int err; - if (og) { - if ((err = OpalCloseAsyncMem(og->async_shmem_size, og->async_shmem_name)) != EOK) - error("Failed to close shared memory area (%d)", err); - if ((err = OpalSystemCtrl_UnRegister(og->print_shmem_name)) != EOK) - error("Failed to close shared memory for system control (%d)", err); + if (!og) + return 0; + + if ((err = OpalCloseAsyncMem(og->async_shmem_size, og->async_shmem_name)) != EOK) + error("Failed to close shared memory area (%d)", err); + + debug(4, "Closing OPAL shared memory mapping"); + + if ((err = OpalSystemCtrl_UnRegister(og->print_shmem_name)) != EOK) + error("Failed to close shared memory for system control (%d)", err); - free(og->send_ids); - free(og->recv_ids); - free(og); + free(og->send_ids); + free(og->recv_ids); + free(og); - og = NULL; - } + og = NULL; return 0; } @@ -99,15 +99,15 @@ int opal_print_global(struct opal_global *g) for (int i=0; irecv_icons; i++) strap(rbuf, sizeof(rbuf), "%u ", g->recv_ids[i]); - debug(4, "Controller ID: %u", g->params.controllerID); - debug(4, "Send Blocks: %s", sbuf); - debug(4, "Receive Blocks: %s", rbuf); + debug(2, "Controller ID: %u", g->params.controllerID); + debug(2, "Send Blocks: %s", sbuf); + debug(2, "Receive Blocks: %s", rbuf); - debug(4, "Control Block Parameters:"); + debug(2, "Control Block Parameters:"); for (int i=0; iparams.FloatParam[i]); + debug(2, "FloatParam[]%u] = %f", i, g->params.FloatParam[i]); for (int i=0; iparams.StringParam[i]); + debug(2, "StringParam[%u] = %s", i, g->params.StringParam[i]); return 0; } @@ -151,9 +151,9 @@ int opal_read(struct node *n, struct msg *m) do { if ((ret = OpalWaitForAsyncSendRequest(&id)) != EOK) { state = OpalGetAsyncModelState(); - if ((state != STATE_RESET) && (state != STATE_STOP)) { - OpalSetAsyncSendIconError(ret, id); - info("OpalWaitForAsyncSendRequest(), errno %d", ret); + if ((state == STATE_RESET) || (state == STATE_STOP)) { + warn("OpalGetAsyncModelState(): Model stopped or resetted!"); + die(); } return -1; // FIXME: correct return value @@ -193,8 +193,10 @@ int opal_read(struct node *n, struct msg *m) /* Before continuing, we make sure that the real-time model * has not been stopped. If it has, we quit. */ state = OpalGetAsyncModelState(); - if ((state == STATE_RESET) || (state == STATE_STOP)) - error("OpalGetAsyncModelState(): Model stopped or resetted!"); // TODO: fixme + if ((state == STATE_RESET) || (state == STATE_STOP)) { + warn("OpalGetAsyncModelState(): Model stopped or resetted!"); + die(); + } return 0; } @@ -209,8 +211,10 @@ int opal_write(struct node *n, struct msg *m) double data[MSG_VALUES] = { NAN }; state = OpalGetAsyncModelState(); - if ((state == STATE_RESET) || (state == STATE_STOP)) - return -1; + if ((state == STATE_RESET) || (state == STATE_STOP)) { + warn("OpalGetAsyncModelState(): Model stopped or resetted!"); + die(); + } OpalSetAsyncRecvIconStatus(m->sequence, o->recv_id); /* Set the Status to the message ID */ OpalSetAsyncRecvIconError(0, o->recv_id); /* Set the Error to 0 */ diff --git a/server/src/path.c b/server/src/path.c index a697ae2a0..c08810433 100644 --- a/server/src/path.c +++ b/server/src/path.c @@ -16,17 +16,19 @@ #include "utils.h" #include "path.h" -#define sigev_notify_thread_id _sigev_un._tid +#ifndef sigev_notify_thread_id + #define sigev_notify_thread_id _sigev_un._tid +#endif -/** Linked list of paths */ -struct path *paths; +/** Linked list of paths. */ +struct list paths; /** Send messages asynchronously */ static void * path_send(void *arg) { + struct path *p = arg; + int sig; - struct path *p = (struct path *) arg; - timer_t tmr; sigset_t set; struct sigevent sev = { @@ -45,22 +47,19 @@ static void * path_send(void *arg) if(pthread_sigmask(SIG_BLOCK, &set, NULL)) serror("Set signal mask"); - if (timer_create(CLOCK_REALTIME, &sev, &tmr)) + if (timer_create(CLOCK_REALTIME, &sev, &p->timer)) serror("Failed to create timer"); - if (timer_settime(tmr, 0, &its, NULL)) + if (timer_settime(p->timer, 0, &its, NULL)) serror("Failed to start timer"); while (1) { sigwait(&set, &sig); /* blocking wait for next timer tick */ - if (p->received) { - FOREACH(&p->destinations, it) { - node_write(it->node, p->last); - } - - p->sent++; - } + FOREACH(&p->destinations, it) + node_write(it->node, p->current); + + p->sent++; } return NULL; @@ -69,43 +68,48 @@ static void * path_send(void *arg) /** Receive messages */ static void * path_run(void *arg) { - char buf[33]; struct path *p = arg; - struct msg *m = alloc(sizeof(struct msg)); - if (!m) - error("Failed to allocate memory for message!"); + + p->previous = alloc(sizeof(struct msg)); + p->current = alloc(sizeof(struct msg)); + char buf[33]; + /* Open deferred TCP connection */ node_start_defer(p->in); // FIXME: node_start_defer(p->out); + /* Main thread loop */ while (1) { - node_read(p->in, m); /* Receive message */ + node_read(p->in, p->current); /* Receive message */ p->received++; /* Check header fields */ - if (m->version != MSG_VERSION || - m->type != MSG_TYPE_DATA) { + if (p->current->version != MSG_VERSION || + p->current->type != MSG_TYPE_DATA) { p->invalid++; continue; } /* Update histogram */ - int dist = (UINT16_MAX + m->sequence - p->sequence) % UINT16_MAX; + int dist = (UINT16_MAX + p->current->sequence - p->previous->sequence) % UINT16_MAX; if (dist > UINT16_MAX / 2) dist -= UINT16_MAX; hist_put(&p->histogram, dist); /* Handle simulation restart */ - if (m->sequence == 0 && abs(dist) >= 1) { - path_print(p, buf, sizeof(buf)); - path_stats(p); - - warn("Simulation for path %s restarted (p->seq=%u, m->seq=%u, dist=%d)", - buf, p->sequence, m->sequence, dist); + if (p->current->sequence == 0 && abs(dist) >= 1) { + if (p->received) { + path_print_stats(p); + hist_print(&p->histogram); + } + + path_print(p, buf, sizeof(buf)); + warn("Simulation for path %s restarted (prev->seq=%u, current->seq=%u, dist=%d)", + buf, p->previous->sequence, p->current->sequence, dist); /* Reset counters */ p->sent = 0; @@ -114,7 +118,6 @@ static void * path_run(void *arg) p->skipped = 0; p->dropped = 0; - hist_print(&p->histogram); hist_reset(&p->histogram); } else if (dist <= 0 && p->received > 1) { @@ -124,27 +127,22 @@ static void * path_run(void *arg) /* Call hook callbacks */ FOREACH(&p->hooks, it) { - if (it->hook(m, p)) { + if (it->hook(p->current, p)) { p->skipped++; continue; } } - /* Update last known sequence number */ - p->sequence = m->sequence; - p->last = m; - /* At fixed rate mode, messages are send by another thread */ if (!p->rate) { - FOREACH(&p->destinations, it) { - node_write(it->node, m); - } - + FOREACH(&p->destinations, it) + node_write(it->node, p->current); + p->sent++; } - } - free(m); + SWAP(p->previous, p->current); + } return NULL; } @@ -156,13 +154,11 @@ int path_start(struct path *p) info("Starting path: %s", buf); - hist_init(&p->histogram, -HIST_SEQ, +HIST_SEQ, 1); - /* At fixed rate mode, we start another thread for sending */ if (p->rate) - pthread_create(&p->sent_tid, NULL, &path_send, (void *) p); + pthread_create(&p->sent_tid, NULL, &path_send, p); - return pthread_create(&p->recv_tid, NULL, &path_run, (void *) p); + return pthread_create(&p->recv_tid, NULL, &path_run, p); } int path_stop(struct path *p) @@ -178,25 +174,23 @@ int path_stop(struct path *p) if (p->rate) { pthread_cancel(p->sent_tid); pthread_join(p->sent_tid, NULL); + + timer_delete(p->timer); } - if (p->sent || p->received) { - path_stats(p); + if (p->received) hist_print(&p->histogram); - hist_free(&p->histogram); - } return 0; } -void path_stats(struct path *p) +void path_print_stats(struct path *p) { char buf[33]; path_print(p, buf, sizeof(buf)); - info("%-32s : %-8u %-8u %-8u %-8u %-8u", - buf, p->sent, p->received, p->dropped, p->skipped, p->invalid - ); + info("%-32s : %-8u %-8u %-8u %-8u %-8u", buf, + p->sent, p->received, p->dropped, p->skipped, p->invalid); } int path_print(struct path *p, char *buf, int len) @@ -215,10 +209,25 @@ int path_print(struct path *p, char *buf, int len) return 0; } -int path_destroy(struct path *p) +struct path * path_create() +{ + struct path *p = alloc(sizeof(struct path)); + + list_init(&p->destinations, NULL); + list_init(&p->hooks, NULL); + + hist_create(&p->histogram, -HIST_SEQ, +HIST_SEQ, 1); + + return p; +} + +void path_destroy(struct path *p) { list_destroy(&p->destinations); list_destroy(&p->hooks); + hist_destroy(&p->histogram); - return 0; + free(p->current); + free(p->previous); + free(p); } diff --git a/server/src/random.c b/server/src/random.c index 7e3849cd6..4d08c0844 100644 --- a/server/src/random.c +++ b/server/src/random.c @@ -22,7 +22,7 @@ void tick(int sig, siginfo_t *si, void *ptr) { - struct msg *m = (struct msg*) si->si_value.sival_ptr; + struct msg *m = (struct msg *) si->si_value.sival_ptr; msg_random(m); msg_fprint(stdout, m); @@ -37,9 +37,12 @@ int main(int argc, char *argv[]) printf("Usage: %s VALUES RATE\n", argv[0]); printf(" VALUES is the number of values a message contains\n"); printf(" RATE how many messages per second\n\n"); - printf("Simulator2Simulator Server %s (built on %s %s)\n", BLU(VERSION), MAG(__DATE__), MAG(__TIME__)); - printf(" Copyright 2014, Institute for Automation of Complex Power Systems, EONERC\n"); - printf(" Steffen Vogel \n"); + + printf("Simulator2Simulator Server %s (built on %s %s)\n", + BLU(VERSION), MAG(__DATE__), MAG(__TIME__)); + printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n"); + printf(" Steffen Vogel \n"); + exit(EXIT_FAILURE); } diff --git a/server/src/receive.c b/server/src/receive.c index 18f131c0e..378311073 100644 --- a/server/src/receive.c +++ b/server/src/receive.c @@ -24,7 +24,7 @@ static struct settings set; static struct msg msg = MSG_INIT(0); -extern struct node *nodes; +extern struct list nodes; static struct node *node; void quit(int sig, siginfo_t *si, void *ptr) @@ -35,13 +35,16 @@ void quit(int sig, siginfo_t *si, void *ptr) void usage(char *name) { - printf("Usage: %s CONFIG NODE\n", name); + printf("Usage: %s [-r] CONFIG NODE\n", name); + printf(" -r swap local / remote address of socket based nodes)\n\n"); printf(" CONFIG path to a configuration file\n"); printf(" NODE name of the node which shoud be used\n\n"); + printf("Simulator2Simulator Server %s (built on %s %s)\n", BLU(VERSION), MAG(__DATE__), MAG(__TIME__)); - printf(" Copyright 2014, Institute for Automation of Complex Power Systems, EONERC\n"); - printf(" Steffen Vogel \n"); + printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n"); + printf(" Steffen Vogel \n"); + exit(EXIT_FAILURE); } @@ -76,7 +79,7 @@ int main(int argc, char *argv[]) config_init(&config); config_parse(argv[optind], &config, &set, &nodes, NULL); - node = node_lookup_name(argv[optind+1], nodes); + node = node_lookup_name(argv[optind+1], &nodes); if (!node) error("There's no node with the name '%s'", argv[optind+1]); diff --git a/server/src/send.c b/server/src/send.c index 2dd7bae2a..a4f841e7a 100644 --- a/server/src/send.c +++ b/server/src/send.c @@ -27,7 +27,7 @@ static struct settings set; static struct msg msg = MSG_INIT(0); static struct node *node; -extern struct node *nodes; +extern struct list nodes; void quit(int sig, siginfo_t *si, void *ptr) { @@ -38,13 +38,15 @@ void quit(int sig, siginfo_t *si, void *ptr) void usage(char *name) { printf("Usage: %s [-r] CONFIG NODE\n", name); - printf(" -r swap local / remote address of socket based nodes)\n"); + printf(" -r swap local / remote address of socket based nodes)\n\n"); printf(" CONFIG path to a configuration file\n"); printf(" NODE name of the node which shoud be used\n"); + printf("Simulator2Simulator Server %s (built on %s %s)\n", BLU(VERSION), MAG(__DATE__), MAG(__TIME__)); - printf(" Copyright 2014, Institute for Automation of Complex Power Systems, EONERC\n"); - printf(" Steffen Vogel \n"); + printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n"); + printf(" Steffen Vogel \n"); + exit(EXIT_FAILURE); } @@ -79,7 +81,7 @@ int main(int argc, char *argv[]) config_init(&config); config_parse(argv[optind], &config, &set, &nodes, NULL); - node = node_lookup_name(argv[optind+1], nodes); + node = node_lookup_name(argv[optind+1], &nodes); if (!node) error("There's no node with the name '%s'", argv[optind+1]); diff --git a/server/src/server.c b/server/src/server.c index 9513ca02e..ccd1e1018 100644 --- a/server/src/server.c +++ b/server/src/server.c @@ -27,55 +27,52 @@ #endif /** Linked list of nodes */ -extern struct node *nodes; +extern struct list nodes; /** Linked list of paths */ -extern struct path *paths; +extern struct list paths; /** Linked list of interfaces */ -extern struct interface *interfaces; +extern struct list interfaces; /** The global configuration */ -struct settings settings; -config_t config; +static struct settings settings; +static config_t config; static void quit() -{ _indent = 0; +{ info("Stopping paths:"); - for (struct path *p = paths; p; p = p->next) { INDENT - path_stop(p); - path_destroy(p); - } + FOREACH(&paths, it) + path_stop(it->path); info("Stopping nodes:"); - for (struct node *n = nodes; n; n = n->next) { INDENT - node_stop(n); - } + FOREACH(&nodes, it) + node_stop(it->node); info("Stopping interfaces:"); - for (struct interface *i = interfaces; i; i = i->next) { INDENT - if_stop(i); - } + FOREACH(&interfaces, it) + if_stop(it->interface); - /** @todo Free nodes */ +#ifdef ENABLE_OPAL_ASYNC + opal_deinit(); +#endif + /* Freeing dynamically allocated memory */ + list_destroy(&paths); + list_destroy(&nodes); + list_destroy(&interfaces); config_destroy(&config); + info("Goodbye!"); + _exit(EXIT_SUCCESS); } void realtime_init() { INDENT - /* Check for realtime kernel patch */ - struct stat st; - if (stat("/sys/kernel/realtime", &st)) - warn("Use a RT-preempt patched Linux for lower latencies!"); - else - info("Server is running on a realtime patched kernel"); - - /* Use FIFO scheduler with realtime priority */ + /* Use FIFO scheduler with real time priority */ if (settings.priority) { struct sched_param param = { .sched_priority = settings.priority }; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) - serror("Failed to set realtime priority"); + serror("Failed to set real time priority"); else debug(3, "Set task priority to %u", settings.priority); } @@ -99,9 +96,9 @@ void signals_init() }; sigemptyset(&sa_quit.sa_mask); + sigaction(SIGQUIT, &sa_quit, NULL); sigaction(SIGTERM, &sa_quit, NULL); sigaction(SIGINT, &sa_quit, NULL); - atexit(&quit); } void usage(const char *name) @@ -113,14 +110,18 @@ void usage(const char *name) printf(" This type of invocation is used by OPAL-RT Asynchronous processes.\n"); printf(" See in the RT-LAB User Guide for more information.\n\n"); #endif - printf("Simulator2Simulator Server %s (built on %s, %s)\n", + printf("Simulator2Simulator Server %s (built on %s %s)\n", BLU(VERSION), MAG(__DATE__), MAG(__TIME__)); - + printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n"); + printf(" Steffen Vogel \n"); + exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { + _mtid = pthread_self(); + /* Check arguments */ #ifdef ENABLE_OPAL_ASYNC if (argc != 2 && argc != 4) @@ -128,28 +129,37 @@ int main(int argc, char *argv[]) if (argc != 2) #endif usage(argv[0]); - - epoch_reset(); - info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s)", - BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__))); - char *configfile = argv[1]; + info("This is Simulator2Simulator Server (S2SS) %s (built on %s, %s, debug=%d)", + BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__)), _debug); /* Check priviledges */ if (getuid() != 0) error("The server requires superuser privileges!"); - /* Start initialization */ + /* Initialize lists */ + list_init(&nodes, (dtor_cb_t) node_destroy); + list_init(&paths, (dtor_cb_t) path_destroy); + list_init(&interfaces, (dtor_cb_t) if_destroy); + + info("Initialize realtime system:"); realtime_init(); + info("Setup signals:"); signals_init(); + info("Parsing configuration:"); config_init(&config); #ifdef ENABLE_OPAL_ASYNC - /* Check if called as asynchronous process from RT-LAB */ + /* Check if called we are called as an asynchronous process from RT-LAB. */ opal_init(argc, argv); + + /* @todo: look in predefined locations for a file */ + char *configfile = "opal-shmem.conf"; +#else + char *configfile = argv[1]; #endif /* Parse configuration and create nodes/paths */ @@ -157,40 +167,34 @@ int main(int argc, char *argv[]) /* Connect all nodes and start one thread per path */ info("Starting nodes:"); - for (struct node *n = nodes; n; n = n->next) { INDENT - node_start(n); - } + FOREACH(&nodes, it) + node_start(it->node); info("Starting interfaces:"); - for (struct interface *i = interfaces; i; i = i->next) { INDENT - if_start(i, settings.affinity); - } + FOREACH(&interfaces, it) + if_start(it->interface, settings.affinity); - info("Starting pathes:"); - for (struct path *p = paths; p; p = p->next) { INDENT - path_start(p); - } + info("Starting paths:"); + FOREACH(&paths, it) + path_start(it->path); /* Run! */ if (settings.stats > 0) { - struct path *p = paths; - info("Runtime Statistics:"); info("%-32s : %-8s %-8s %-8s %-8s %-8s", "Source " MAG("=>") " Destination", "#Sent", "#Recv", "#Drop", "#Skip", "#Inval"); info("---------------------------------------------------------------------------"); - while (1) { + do { FOREACH(&paths, it) { usleep(settings.stats * 1e6); - path_stats(p); + path_print_stats(it->path); + } } while (1); - p = (p->next) ? p->next : paths; - } } else pause(); - /* Note: quit() is called by exit handler! */ + quit(); return 0; } diff --git a/server/src/socket.c b/server/src/socket.c index bfab7155e..3e4fc85d6 100644 --- a/server/src/socket.c +++ b/server/src/socket.c @@ -34,8 +34,8 @@ int socket_print(struct node *n, char *buf, int len) char local[INET6_ADDRSTRLEN + 16]; char remote[INET6_ADDRSTRLEN + 16]; - socket_print_addr(local, sizeof(local), (struct sockaddr*) &s->local); - socket_print_addr(remote, sizeof(remote), (struct sockaddr*) &s->remote); + socket_print_addr(local, sizeof(local), (struct sockaddr *) &s->local); + socket_print_addr(remote, sizeof(remote), (struct sockaddr *) &s->remote); return snprintf(buf, len, "local=%s, remote=%s", local, remote); } @@ -86,7 +86,7 @@ int socket_open(struct node *n) if (!i) i = if_create(index); - list_add(i->sockets, s); + list_push(&i->sockets, s); i->refcnt++; /* Set socket priority, QoS or TOS IP options */ @@ -230,7 +230,7 @@ int socket_parse_addr(const char *addr, struct sockaddr *sa, enum node_type type else { /* Format: "192.168.0.10:12001" */ struct addrinfo hint = { .ai_flags = flags, - .ai_family = AF_UNSPEC + .ai_family = AF_INET }; /* Split string */ diff --git a/server/src/test.c b/server/src/test.c index 594732f36..2deec58bf 100644 --- a/server/src/test.c +++ b/server/src/test.c @@ -26,7 +26,7 @@ static struct settings set; static struct node *node; -extern struct node *nodes; +extern struct list nodes; /* Test options */ int running = 1; @@ -48,7 +48,7 @@ double high = 2e-4; /** Histogram resolution. */ double res = 1e-5; -#define CLOCK_ID CLOCK_MONOTONIC_RAW +#define CLOCK_ID CLOCK_MONOTONIC /* Prototypes */ void test_rtt(); @@ -67,10 +67,12 @@ int main(int argc, char *argv[]) printf(" CONFIG path to a configuration file\n"); printf(" TEST the name of the test to execute: 'rtt'\n"); printf(" NODE name of the node which shoud be used\n\n"); + printf("Simulator2Simulator Server %s (built on %s %s)\n", BLU(VERSION), MAG(__DATE__), MAG(__TIME__)); - printf(" Copyright 2014, Institute for Automation of Complex Power Systems, EONERC\n"); - printf(" Steffen Vogel \n"); + printf(" Copyright 2015, Institute for Automation of Complex Power Systems, EONERC\n"); + printf(" Steffen Vogel \n"); + exit(EXIT_FAILURE); } @@ -87,7 +89,7 @@ int main(int argc, char *argv[]) config_init(&config); config_parse(argv[1], &config, &set, &nodes, NULL); - node = node_lookup_name(argv[3], nodes); + node = node_lookup_name(argv[3], &nodes); if (!node) error("There's no node with the name '%s'", argv[3]); @@ -122,9 +124,9 @@ int main(int argc, char *argv[]) error("Unknown option '-%c'.", optopt); else error("Unknown option character '\\x%x'.", optopt); - exit(1); + exit(EXIT_FAILURE); default: - abort (); + abort(); } continue; @@ -155,7 +157,7 @@ void test_rtt() { double avg = 0; struct hist histogram; - hist_init(&histogram, low, high, res); + hist_create(&histogram, low, high, res); #if 1 /* Print header */ fprintf(stdout, "%17s", "timestamp"); @@ -201,5 +203,5 @@ void test_rtt() { else error("Invalid file descriptor: %u", fd); - hist_free(&histogram); + hist_destroy(&histogram); } diff --git a/server/src/utils.c b/server/src/utils.c index cfdbf0486..d30dd2503 100644 --- a/server/src/utils.c +++ b/server/src/utils.c @@ -12,10 +12,11 @@ #include #include #include -#include #include +#include #ifdef ENABLE_OPAL_ASYNC +#define RTLAB #include #endif @@ -23,20 +24,11 @@ #include "cfg.h" #include "utils.h" -/* This global variable contains the debug level for debug() and assert() macros */ -int _debug = V; -int _indent = 0; +pthread_t _mtid; -struct timespec epoch; - -void outdent(int *old) +void die() { - _indent = *old; -} - -void epoch_reset() -{ - clock_gettime(CLOCK_REALTIME, &epoch); + pthread_kill(_mtid, SIGINT); } int strap(char *dest, size_t size, const char *fmt, ...) @@ -58,43 +50,6 @@ int vstrap(char *dest, size_t size, const char *fmt, va_list ap) return vsnprintf(dest + len, size - len, fmt, ap); } -void print(enum log_level lvl, const char *fmt, ...) -{ - struct timespec ts; - char buf[512] = ""; - - va_list ap; - - /* Timestamp */ - clock_gettime(CLOCK_REALTIME, &ts); - strap(buf, sizeof(buf), "%8.3f ", timespec_delta(&epoch, &ts)); - - /* Severity */ - switch (lvl) { - case DEBUG: strap(buf, sizeof(buf), BLD("%-5s "), GRY("Debug")); break; - case INFO: strap(buf, sizeof(buf), BLD("%-5s "), " " ); break; - case WARN: strap(buf, sizeof(buf), BLD("%-5s "), YEL(" Warn")); break; - case ERROR: strap(buf, sizeof(buf), BLD("%-5s "), RED("Error")); break; - } - - /* Indention */ - for (int i = 0; i < _indent-1; i++) - strap(buf, sizeof(buf), GFX("\x78") " "); - strap(buf, sizeof(buf), GFX("\x74") " "); - - /* Format String */ - va_start(ap, fmt); - vstrap(buf, sizeof(buf), fmt, ap); - va_end(ap); - - /* Output */ -#ifdef ENABLE_OPAL_ASYNC - OpalPrint("%s\n", buf); -#else - fprintf(stderr, "%s\n", buf); -#endif -} - cpu_set_t to_cpu_set(int set) { cpu_set_t cset;