diff --git a/include/villas/advio.h b/include/villas/advio.h index afbf3b14b..15c56ebd8 100644 --- a/include/villas/advio.h +++ b/include/villas/advio.h @@ -26,7 +26,11 @@ #include -#include "crypt.h" +#include + +#ifdef __cplusplus +extern "C"{ +#endif struct advio { CURL *curl; @@ -81,3 +85,7 @@ void arewind(AFILE *file); int adownload(AFILE *af, int resume); int aupload(AFILE *af, int resume); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/api.h b/include/villas/api.h index b56627306..6a9a1a37b 100644 --- a/include/villas/api.h +++ b/include/villas/api.h @@ -33,6 +33,10 @@ #include "api/session.h" +#ifdef __cplusplus +extern "C"{ +#endif + /* Forward declarations */ struct lws; struct super_node; @@ -81,3 +85,7 @@ int api_stop(struct api *a); int api_ws_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); int api_http_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/villas/api/session.h b/include/villas/api/session.h index 55835a8b4..65dfac659 100644 --- a/include/villas/api/session.h +++ b/include/villas/api/session.h @@ -30,6 +30,10 @@ #include #include +#ifdef __cplusplus +extern "C"{ +#endif + enum api_version { API_VERSION_UNKOWN = 0, API_VERSION_1 = 1 @@ -70,3 +74,7 @@ int api_session_destroy(struct api_session *s); int api_session_run_command(struct api_session *s, json_t *req, json_t **resp); char * api_session_name(struct api_session *s); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/atomic.h b/include/villas/atomic.h index 0eba94d48..2ae1a84be 100644 --- a/include/villas/atomic.h +++ b/include/villas/atomic.h @@ -21,7 +21,9 @@ * along with this program. If not, see . *********************************************************************************/ -#include "common.h" +#pragma once + +#include #ifdef __cplusplus @@ -37,4 +39,4 @@ typedef std::atomic atomic_state; typedef _Atomic enum state atomic_state; -#endif +#endif /* __cplusplus */ diff --git a/include/villas/bitset.h b/include/villas/bitset.h index 757774361..7e61147cd 100644 --- a/include/villas/bitset.h +++ b/include/villas/bitset.h @@ -26,6 +26,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct bitset { char *set; size_t dimension; @@ -62,4 +66,8 @@ int bitset_test(struct bitset *b, size_t bit); int bitset_cmp(struct bitset *a, struct bitset *b); /** Return an human readable representation of the bit set */ -char * bitset_dump(struct bitset *b); +char *bitset_dump(struct bitset *b); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/buffer.h b/include/villas/buffer.h index 8899f5fb0..77f679d67 100644 --- a/include/villas/buffer.h +++ b/include/villas/buffer.h @@ -29,9 +29,13 @@ #include "common.h" +#ifdef __cplusplus +extern "C" { +#endif + struct buffer { enum state state; - + char *buf; size_t len; size_t size; @@ -40,11 +44,15 @@ struct buffer { int buffer_init(struct buffer *b, size_t size); int buffer_destroy(struct buffer *b); - + void buffer_clear(struct buffer *b); int buffer_append(struct buffer *b, const char *data, size_t len); int buffer_parse_json(struct buffer *b, json_t **j); -int buffer_append_json(struct buffer *b, json_t *j); \ No newline at end of file +int buffer_append_json(struct buffer *b, json_t *j); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/villas/common.h b/include/villas/common.h index 41457b2e7..64de9bb8c 100644 --- a/include/villas/common.h +++ b/include/villas/common.h @@ -23,6 +23,10 @@ #pragma once +#ifdef __cplusplus +extern "C"{ +#endif + /* Common states for most objects in VILLASnode (paths, nodes, hooks, plugins) */ enum state { STATE_DESTROYED = 0, @@ -36,3 +40,13 @@ enum state { STATE_UNLOADED = 5, /* alias for STATE_STARTED used by struct plugin */ STATE_CLOSED = 5 /* alias for STATE_STARTED used by struct io */ }; + +/** Callback to destroy list elements. + * + * @param data A pointer to the data which should be freed. + */ +typedef int (*dtor_cb_t)(void *); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/compat.h b/include/villas/compat.h index ad574fda2..1cac42afb 100644 --- a/include/villas/compat.h +++ b/include/villas/compat.h @@ -20,8 +20,14 @@ * along with this program. If not, see . *********************************************************************************/ +#pragma once + #include +#ifdef __cplusplus +extern "C" { +#endif + #if JANSSON_VERSION_HEX < 0x020A00 size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags); #endif @@ -43,3 +49,7 @@ size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags); #define htobe32(x) OSSwapHostToBigInt32(x) #define htobe64(x) OSSwapHostToBigInt64(x) #endif /* __MACH__ */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/config.h.in b/include/villas/config.h.in index 68d56ee8c..419f0fa61 100644 --- a/include/villas/config.h.in +++ b/include/villas/config.h.in @@ -26,6 +26,10 @@ #pragma once +#ifdef __cplusplus +extern "C"{ +#endif + /* Paths */ #define PLUGIN_PATH PREFIX "/share/villas/node/plugins" #define WEB_PATH PREFIX "/share/villas/node/web" @@ -56,3 +60,7 @@ /* Required kernel version */ #define KERNEL_VERSION_MAJ 3 #define KERNEL_VERSION_MIN 6 + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/config_helper.h b/include/villas/config_helper.h index 6be9afe4b..abed550f7 100644 --- a/include/villas/config_helper.h +++ b/include/villas/config_helper.h @@ -27,14 +27,18 @@ #include "sample.h" +#ifdef __cplusplus +extern "C" { +#endif + /* Convert a libconfig object to a jansson object */ -json_t * config_to_json(config_setting_t *cfg); +json_t *config_to_json(config_setting_t *cfg); /* Convert a jansson object into a libconfig object. */ int json_to_config(json_t *json, config_setting_t *parent); /* Create a JSON object from command line parameters. */ -json_t * json_load_cli(int argc, char *argv[]); +json_t *json_load_cli(int argc, char *argv[]); int json_object_extend_str(json_t *orig, const char *str); @@ -42,3 +46,7 @@ void json_object_extend_key_value(json_t *obj, const char *key, const char *valu /* Merge two JSON objects recursively. */ int json_object_extend(json_t *orig, json_t *merge); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/crypt.h b/include/villas/crypt.h index 9b5c7843b..29b99410e 100644 --- a/include/villas/crypt.h +++ b/include/villas/crypt.h @@ -25,9 +25,17 @@ #include #include +#ifdef __cplusplus +extern "C"{ +#endif + /** Calculate SHA1 hash of complete file \p f and place it into \p sha1. * * @param sha1[out] Must be SHA_DIGEST_LENGTH (20) in size. * @retval 0 Everything was okay. */ int sha1sum(FILE *f, unsigned char *sha1); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/villas/format_type.h b/include/villas/format_type.h index 805b930a3..d1a4a7cb5 100644 --- a/include/villas/format_type.h +++ b/include/villas/format_type.h @@ -25,6 +25,10 @@ #include +#ifdef __cplusplus +extern "C"{ +#endif + /* Forward declarations */ struct sample; struct io; @@ -104,3 +108,7 @@ struct format_type { }; struct format_type * format_type_lookup(const char *name); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/villas/formats/csv.h b/include/villas/formats/csv.h index d32c93f52..f9f944131 100644 --- a/include/villas/formats/csv.h +++ b/include/villas/formats/csv.h @@ -25,6 +25,9 @@ #include +#ifdef __cplusplus +extern "C" { +#endif /* Forward declarations. */ struct sample; @@ -32,3 +35,7 @@ void csv_header(struct io *io); int csv_sscan(struct io *io, char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt); int csv_sprint(struct io *io, char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/formats/json-reserve.h b/include/villas/formats/json-reserve.h index 71280af59..f6e6c227b 100644 --- a/include/villas/formats/json-reserve.h +++ b/include/villas/formats/json-reserve.h @@ -24,6 +24,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct sample; struct io; @@ -33,3 +37,7 @@ int json_reserve_sscan(struct io *io, char *buf, size_t len, size_t *rbytes, str int json_reserve_print(struct io *io, struct sample *smps[], unsigned cnt); int json_reserve_scan(struct io *io, struct sample *smps[], unsigned cnt); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/formats/json.h b/include/villas/formats/json.h index 50fb60aee..ea73e0ff6 100644 --- a/include/villas/formats/json.h +++ b/include/villas/formats/json.h @@ -24,6 +24,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct sample; @@ -32,3 +36,7 @@ int json_sscan(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp int json_print(struct io *io, struct sample *smps[], unsigned cnt); int json_scan(struct io *io, struct sample *smps[], unsigned cnt); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/formats/msg.h b/include/villas/formats/msg.h index c10498c12..c69e21bbc 100644 --- a/include/villas/formats/msg.h +++ b/include/villas/formats/msg.h @@ -22,6 +22,10 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declaration */ struct msg; struct sample; @@ -53,3 +57,7 @@ int msg_to_sample(struct msg *msg, struct sample *smp); /** Copy fields form \p smp into \p msg. */ int msg_from_sample(struct msg *msg, struct sample *smp); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/formats/msg_format.h b/include/villas/formats/msg_format.h index 45930fae8..1dc4f87b5 100644 --- a/include/villas/formats/msg_format.h +++ b/include/villas/formats/msg_format.h @@ -25,6 +25,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** The current version number for the message format */ #define MSG_VERSION 2 @@ -90,3 +94,7 @@ struct msg uint32_t i; /**< Integer values. */ } data[]; } __attribute__((packed)); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/formats/protobuf.h b/include/villas/formats/protobuf.h index 49f171555..d6dda00dc 100644 --- a/include/villas/formats/protobuf.h +++ b/include/villas/formats/protobuf.h @@ -25,6 +25,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct sample; @@ -33,3 +37,7 @@ int protobuf_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct /** Read struct sample's from buffer \p buf into samples \p smps. */ int protobuf_sscan(struct io *io, char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/formats/raw.h b/include/villas/formats/raw.h index 7d0b1e3b9..3ee518b2f 100644 --- a/include/villas/formats/raw.h +++ b/include/villas/formats/raw.h @@ -25,6 +25,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct sample; @@ -58,3 +62,7 @@ int raw_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct samp /** Read struct sample's from buffer \p buf into samples \p smps. */ int raw_sscan(struct io *io, char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/formats/villas_binary.h b/include/villas/formats/villas_binary.h index 79dd248e4..8fd4428c3 100644 --- a/include/villas/formats/villas_binary.h +++ b/include/villas/formats/villas_binary.h @@ -25,6 +25,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations. */ struct sample; struct msg; @@ -39,3 +43,7 @@ int villas_binary_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, s /** Read struct sample's from buffer \p buf into samples \p smps. */ int villas_binary_sscan(struct io *io, char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsigned cnt); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/formats/villas_human.h b/include/villas/formats/villas_human.h index 01ced6032..c372b14ef 100644 --- a/include/villas/formats/villas_human.h +++ b/include/villas/formats/villas_human.h @@ -25,6 +25,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct io; struct sample; @@ -33,3 +37,7 @@ void villas_human_header(struct io *io); int villas_human_print(struct io *io, struct sample *smps[], unsigned cnt); int villas_human_scan(struct io *io, struct sample *smps[], unsigned cnt); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/villas/hash_table.h b/include/villas/hash_table.h new file mode 100644 index 000000000..87726184f --- /dev/null +++ b/include/villas/hash_table.h @@ -0,0 +1,85 @@ +/** A generic hash table + * + * @author Steffen Vogel + * @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#pragma once + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct hash_table_entry { + void *key; + void *data; + + struct hash_table_entry *next; +}; + +/** A thread-safe hash table using separate chaing with linked lists. */ +struct hash_table { + enum state state; + + struct hash_table_entry **table; + + size_t size; + pthread_mutex_t lock; +}; + +/** Initialize a new hash table. + * + */ +int hash_table_init(struct hash_table *ht, size_t size); + +/** Destroy a hash table. + * + * + */ +int hash_table_destroy(struct hash_table *ht, dtor_cb_t dtor, bool release); + +/** Insert a new key/value pair into the hash table. + * + */ +int hash_table_insert(struct hash_table *ht, void *key, void *data); + +/** Delete a key from the hash table. + * + * + */ +int hash_table_delete(struct hash_table *ht, void *key); + +/** Perform a lookup in the hash table. + * + * @retval != NULL The value for the given key. + * @retval NULL The given key is not stored in the hash table. + */ +void * hash_table_lookup(struct hash_table *ht, void *key); + +/** Dump the contents of the hash table in a human readable format to stdout. */ +void hash_table_dump(struct hash_table *ht); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/hist.h b/include/villas/hist.h index 935908576..477470956 100644 --- a/include/villas/hist.h +++ b/include/villas/hist.h @@ -28,6 +28,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + #define HIST_HEIGHT (LOG_WIDTH - 55) #define HIST_SEQ 17 @@ -103,3 +107,7 @@ int hist_dump_json(struct hist *h, FILE *f); /** Build a libjansson / JSON object of the histogram. */ json_t * hist_json(struct hist *h); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/hook.h b/include/villas/hook.h index eadd4c281..e80f6a46a 100644 --- a/include/villas/hook.h +++ b/include/villas/hook.h @@ -34,8 +34,12 @@ #pragma once -#include "hook_type.h" -#include "common.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* Forward declarations */ struct path; @@ -96,3 +100,7 @@ int hook_cmp_priority(const void *a, const void *b); * } */ int hook_parse_list(struct list *list, json_t *cfg, struct path *p, struct node *n); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/hook_type.h b/include/villas/hook_type.h index 6c6d7ec70..de1331a2e 100644 --- a/include/villas/hook_type.h +++ b/include/villas/hook_type.h @@ -39,6 +39,10 @@ #include +#ifdef __cplusplus +extern "C"{ +#endif + /* Forward declarations */ struct hook; struct sample; @@ -74,3 +78,6 @@ struct hook_type { struct hook_type * hook_type_lookup(const char *name); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/villas/io.h b/include/villas/io.h index d24705a61..c9e8a07a6 100644 --- a/include/villas/io.h +++ b/include/villas/io.h @@ -23,9 +23,13 @@ #pragma once -#include "advio.h" -#include "common.h" -#include "node.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* Forward declarations */ struct sample; @@ -134,3 +138,7 @@ int io_sscan(struct io *io, char *buf, size_t len, size_t *rbytes, struct sample * @retval <0 Something went wrong. */ int io_sprint(struct io *io, char *buf, size_t len, size_t *wbytes, struct sample *smps[], unsigned cnt); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/kernel/if.h b/include/villas/kernel/if.h index 4a6068ad5..1d6420098 100644 --- a/include/villas/kernel/if.h +++ b/include/villas/kernel/if.h @@ -33,6 +33,10 @@ #include +#ifdef __cplusplus +extern "C"{ +#endif + #define IF_IRQ_MAX 3 /**< Maxmimal number of IRQs of an interface */ #ifndef SO_MARK @@ -121,4 +125,8 @@ int if_get_irqs(struct interface *i); */ int if_set_affinity(struct interface *i, int affinity); + +#ifdef __cplusplus +} +#endif /** @} */ diff --git a/include/villas/kernel/kernel.h b/include/villas/kernel/kernel.h index 6b39dc40c..265e125f4 100644 --- a/include/villas/kernel/kernel.h +++ b/include/villas/kernel/kernel.h @@ -28,6 +28,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct version; @@ -85,6 +89,10 @@ int kernel_get_page_size(); int kernel_get_hugepage_size(); /** Set SMP affinity of IRQ */ -int kernel_irq_setaffinity(unsigned irq, uintmax_t new, uintmax_t *old); +int kernel_irq_setaffinity(unsigned irq, uintmax_t new , uintmax_t *old ); + +#ifdef __cplusplus +} +#endif /** @} */ diff --git a/include/villas/kernel/nl-private.h b/include/villas/kernel/nl-private.h index 968cdb209..ded3b0a97 100644 --- a/include/villas/kernel/nl-private.h +++ b/include/villas/kernel/nl-private.h @@ -1,5 +1,9 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + #define SCH_NETEM_ATTR_DIST 0x2000 struct rtnl_netem_corr @@ -43,3 +47,7 @@ struct rtnl_netem }; void *rtnl_tc_data(struct rtnl_tc *tc); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/kernel/nl.h b/include/villas/kernel/nl.h index 879312cd9..894df4f9f 100644 --- a/include/villas/kernel/nl.h +++ b/include/villas/kernel/nl.h @@ -29,6 +29,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** Get index of outgoing interface for given destination address. * * @retval >=0 Interface index of outgoing interface. @@ -37,9 +41,13 @@ int nl_get_egress(struct nl_addr *addr); /** Get or create global netlink socket. */ -struct nl_sock * nl_init(); +struct nl_sock *nl_init(); /** Close and free global netlink socket. */ void nl_shutdown(); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/kernel/rt.h b/include/villas/kernel/rt.h index f1c8b5bc6..c6c5c0e9b 100644 --- a/include/villas/kernel/rt.h +++ b/include/villas/kernel/rt.h @@ -26,6 +26,10 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + int rt_init(int priority, int affinity); int rt_set_affinity(int affinity); @@ -43,4 +47,8 @@ int rt_lock_memory(); */ int rt_is_preemptible(); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/kernel/tc.h b/include/villas/kernel/tc.h index a64439be8..0b5afbbc3 100644 --- a/include/villas/kernel/tc.h +++ b/include/villas/kernel/tc.h @@ -37,6 +37,10 @@ #include +#ifdef __cplusplus +extern "C"{ +#endif + typedef uint32_t tc_hdl_t; struct interface; @@ -72,4 +76,8 @@ int tc_prio(struct interface *i, struct rtnl_qdisc **qd, tc_hdl_t handle, tc_hdl */ int tc_mark(struct interface *i, struct rtnl_cls **cls, tc_hdl_t flowid, uint32_t mark); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/kernel/tc_netem.h b/include/villas/kernel/tc_netem.h index 78dc10951..b6d0a86c4 100644 --- a/include/villas/kernel/tc_netem.h +++ b/include/villas/kernel/tc_netem.h @@ -37,6 +37,10 @@ #include +#ifdef __cplusplus +extern "C"{ +#endif + typedef uint32_t tc_hdl_t; struct interface; @@ -70,4 +74,8 @@ int tc_netem(struct interface *i, struct rtnl_qdisc **qd, tc_hdl_t handle, tc_hd int tc_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, json_t *json); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/list.h b/include/villas/list.h index f3dd82bc8..ab79d6774 100644 --- a/include/villas/list.h +++ b/include/villas/list.h @@ -8,7 +8,22 @@ * * @file * @author Steffen Vogel - * @copyright 20177, Institute for Automation of Complex Power Systems, EONERC + * @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC +* + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . *********************************************************************************/ #pragma once @@ -17,7 +32,11 @@ #include #include -#include "common.h" +#include + +#ifdef __cplusplus +extern "C"{ +#endif #define LIST_CHUNKSIZE 16 @@ -46,12 +65,6 @@ __attribute__((destructor(105))) static void UNIQUE(__dtor)() { \ #define list_first(list) list_at(list, 0) #define list_last(list) list_at(list, (list)->length-1) -/** Callback to destroy list elements. - * - * @param data A pointer to the data which should be freed. - */ -typedef int (*dtor_cb_t)(void *); - /** Callback to search or sort a list. */ typedef int (*cmp_cb_t)(const void *, const void *); @@ -120,3 +133,7 @@ int list_set(struct list *l, int index, void *value); * @retval >=0 Entry \p value was found at returned index. */ ssize_t list_index(struct list *l, void *value); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/log_config.h b/include/villas/log_config.h index 86c2281ba..d7322fd0a 100644 --- a/include/villas/log_config.h +++ b/include/villas/log_config.h @@ -29,9 +29,18 @@ struct log; #include "log.h" +#ifdef __cplusplus +extern "C"{ +#endif + /** Parse logging configuration. */ int log_parse(struct log *l, json_t *cfg); /** Print configuration error and exit. */ void jerror(json_error_t *err, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/villas/mapping.h b/include/villas/mapping.h index 498d0e455..5bee741f6 100644 --- a/include/villas/mapping.h +++ b/include/villas/mapping.h @@ -25,9 +25,13 @@ #include -#include "stats.h" -#include "common.h" -#include "list.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* Forward declarations */ struct stats; @@ -93,3 +97,7 @@ int mapping_parse(struct mapping_entry *e, json_t *cfg, struct list *nodes); int mapping_parse_str(struct mapping_entry *e, const char *str, struct list *nodes); int mapping_parse_list(struct list *l, json_t *cfg, struct list *nodes); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/memory.h b/include/villas/memory.h index 9514d748d..616377d20 100644 --- a/include/villas/memory.h +++ b/include/villas/memory.h @@ -21,57 +21,50 @@ * along with this program. If not, see . *********************************************************************************/ -#include -#include - #pragma once -#define HUGEPAGESIZE (1 << 21) +#include +#include +#include -struct memtype; +#include -typedef void *(*memzone_allocator_t)(struct memtype *mem, size_t len, size_t alignment); -typedef int (*memzone_deallocator_t)(struct memtype *mem, void *ptr, size_t len); +#ifdef __cplusplus +extern "C" { +#endif -enum memtype_flags { - MEMORY_MMAP = (1 << 0), - MEMORY_DMA = (1 << 1), - MEMORY_HUGEPAGE = (1 << 2), - MEMORY_HEAP = (1 << 3) -}; - -struct memtype { - const char *name; - int flags; - - size_t alignment; - - memzone_allocator_t alloc; - memzone_deallocator_t free; - - void *_vd; /**0 If allocation was successful. */ -void * memory_alloc(struct memtype *m, size_t len); +void * memory_alloc(struct memory_type *m, size_t len); -void * memory_alloc_aligned(struct memtype *m, size_t len, size_t alignment); +void * memory_alloc_aligned(struct memory_type *m, size_t len, size_t alignment); -int memory_free(struct memtype *m, void *ptr, size_t len); +int memory_free(void *ptr); -struct memtype * memtype_managed_init(void *ptr, size_t len); - -extern struct memtype memtype_heap; -extern struct memtype memtype_hugepage; +#ifdef __cplusplus +} +#endif diff --git a/include/villas/memory_type.h b/include/villas/memory_type.h new file mode 100644 index 000000000..8d927cf3d --- /dev/null +++ b/include/villas/memory_type.h @@ -0,0 +1,70 @@ +/** Memory allocators. + * + * @file + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declaratio */ +struct memory_type; + +typedef struct memory_allocation * (*memory_allocator_t)(struct memory_type *mem, size_t len, size_t alignment); +typedef int (*memory_deallocator_t)(struct memory_type *mem, struct memory_allocation * ma); + +enum memory_type_flags { + MEMORY_MMAP = (1 << 0), + MEMORY_DMA = (1 << 1), + MEMORY_HUGEPAGE = (1 << 2), + MEMORY_HEAP = (1 << 3) +}; + +struct memory_type { + const char *name; + int flags; + + size_t alignment; + + memory_allocator_t alloc; + memory_deallocator_t free; + + void *_vd; /**< Virtual data for internal state */ +}; + +extern struct memory_type memory_type_heap; +extern struct memory_type memory_hugepage; + +struct ibv_mr * memory_type_ib_mr(void *ptr); + +struct node; + +struct memory_type * memory_ib(struct node *n, struct memory_type *parent); +struct memory_type * memory_managed(void *ptr, size_t len); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/node.h b/include/villas/node.h index 29c312124..b63acb2cc 100644 --- a/include/villas/node.h +++ b/include/villas/node.h @@ -32,11 +32,15 @@ #include #include -#include "node_type.h" -#include "sample.h" -#include "list.h" -#include "queue.h" -#include "common.h" +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif struct node_direction { int enabled; @@ -158,7 +162,10 @@ int node_write(struct node *n, struct sample *smps[], unsigned cnt); int node_fd(struct node *n); -struct memtype * node_memtype(struct node *n, struct memtype *parent); +struct memory_type * node_memory_type(struct node *n, struct memory_type *parent); +#ifdef __cplusplus +} +#endif /** @} */ diff --git a/include/villas/node_type.h b/include/villas/node_type.h index 6de269f52..b9026b1d3 100644 --- a/include/villas/node_type.h +++ b/include/villas/node_type.h @@ -24,6 +24,10 @@ * @{ *********************************************************************************/ +#ifdef __cplusplus +extern "C"{ +#endif + #pragma once #include @@ -85,6 +89,14 @@ struct node_type { */ int (*parse)(struct node *n, json_t *cfg); + /** Check the current node configuration for plausability and errors. + * + * @param n A pointer to the node object. + * @retval 0 Success. Node configuration is good. + * @retval <0 Error. The node configuration is bogus. + */ + int (*check)(struct node *n); + /** Parse node from command line arguments. */ int (*parse_cli)(struct node *n, int argc, char *argv[]); @@ -152,7 +164,7 @@ struct node_type { int (*fd)(struct node *n); /** */ - struct memtype * (*memtype)(struct node *n, struct memtype *parent); + struct memory_type * (*memory_type)(struct node *n, struct memory_type *parent); }; /** Initialize all registered node type subsystems. @@ -172,4 +184,8 @@ const char * node_type_name(struct node_type *vt); struct node_type * node_type_lookup(const char *name); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/amqp.h b/include/villas/nodes/amqp.h index e23154108..b343190c1 100644 --- a/include/villas/nodes/amqp.h +++ b/include/villas/nodes/amqp.h @@ -35,6 +35,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct format_type; @@ -81,4 +85,8 @@ int amqp_read(struct node *n, struct sample *smps[], unsigned cnt); /** @see node_type::write */ int amqp_write(struct node *n, struct sample *smps[], unsigned cnt); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/cbuilder.h b/include/villas/nodes/cbuilder.h index c90e73db1..2513fb94e 100644 --- a/include/villas/nodes/cbuilder.h +++ b/include/villas/nodes/cbuilder.h @@ -33,6 +33,10 @@ #include +#ifdef __cplusplus +extern "C"{ +#endif + /* Forward declaration */ struct cbuilder; @@ -65,4 +69,8 @@ struct cbuilder { int eventfd; /**< Eventfd for synchronizing cbuilder_read() / cbuilder_write() access. */ }; +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/comedi.h b/include/villas/nodes/comedi.h index 311874ca6..3aa01f5b3 100644 --- a/include/villas/nodes/comedi.h +++ b/include/villas/nodes/comedi.h @@ -35,6 +35,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + // whether to use read() or mmap() kernel interface #define COMEDI_USE_READ (1) //#define COMEDI_USE_READ (0) @@ -45,20 +49,19 @@ struct comedi_chanspec { }; struct comedi_direction { - int subdevice; ///< Comedi subdevice - int buffer_size; ///< Comedi's kernel buffer size in kB - int sample_size; ///< Size of a single measurement sample - int sample_rate_hz; ///< Sample rate in Hz - bool present; ///< Config present - bool enabled; ///< Card is started successfully - bool running; ///< Card is actively transfering samples - struct timespec started; ///< Timestamp when sampling started - struct timespec last_debug; ///< Timestamp of last debug output - size_t counter; ///< Number of villas samples transfered + int subdevice; ///< Comedi subdevice + int buffer_size; ///< Comedi's kernel buffer size in kB + int sample_size; ///< Size of a single measurement sample + int sample_rate_hz; ///< Sample rate in Hz + bool present; ///< Config present + bool enabled; ///< Card is started successfully + bool running; ///< Card is actively transfering samples + struct timespec started; ///< Timestamp when sampling started + struct timespec last_debug; ///< Timestamp of last debug output + size_t counter; ///< Number of villas samples transfered struct comedi_chanspec *chanspecs; ///< Range and maxdata config of channels - unsigned *chanlist; ///< Channel list in comedi's packed format - size_t chanlist_len; ///< Number of channels for this direction - + unsigned *chanlist; ///< Channel list in comedi's packed format + size_t chanlist_len; ///< Number of channels for this direction char* buffer; char* bufptr; @@ -70,8 +73,8 @@ struct comedi { comedi_t *dev; #if COMEDI_USE_READ - char* buf; - char* bufptr; + char *buf; + char *bufptr; #else char *map; size_t bufpos; @@ -100,3 +103,7 @@ int comedi_read(struct node *n, struct sample *smps[], unsigned cnt); int comedi_write(struct node *n, struct sample *smps[], unsigned cnt); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/nodes/file.h b/include/villas/nodes/file.h index da105b0b8..498afb0a4 100644 --- a/include/villas/nodes/file.h +++ b/include/villas/nodes/file.h @@ -33,6 +33,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define FILE_MAX_PATHLEN 512 struct file { @@ -85,3 +89,7 @@ int file_read(struct node *n, struct sample *smps[], unsigned cnt); int file_write(struct node *n, struct sample *smps[], unsigned cnt); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/nodes/iec61850.h b/include/villas/nodes/iec61850.h index 7dd31e4c2..9f7944b4b 100644 --- a/include/villas/nodes/iec61850.h +++ b/include/villas/nodes/iec61850.h @@ -38,6 +38,10 @@ #include #include +#ifdef __cplusplus +extern "C"{ +#endif + enum iec61850_type { /* According to IEC 61850-7-2 */ IEC61850_TYPE_BOOLEAN, @@ -107,4 +111,8 @@ int iec61850_receiver_stop(struct iec61850_receiver *r); int iec61850_receiver_destroy(struct iec61850_receiver *r); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/iec61850_sv.h b/include/villas/nodes/iec61850_sv.h index 8b43644e1..7213c20fb 100644 --- a/include/villas/nodes/iec61850_sv.h +++ b/include/villas/nodes/iec61850_sv.h @@ -40,6 +40,10 @@ #include #include +#ifdef __cplusplus +extern "C"{ +#endif + struct iec61850_sv { char *interface; int app_id; @@ -97,4 +101,8 @@ int iec61850_sv_write(struct node *n, struct sample *smps[], unsigned cnt); int iec61850_sv_fd(struct node *n); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/influxdb.h b/include/villas/nodes/influxdb.h index 919725b55..3abbde1f9 100644 --- a/include/villas/nodes/influxdb.h +++ b/include/villas/nodes/influxdb.h @@ -31,6 +31,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct node; struct sample; @@ -63,4 +67,8 @@ int influxdb_close(struct node *n); /** @see node_type::write */ int influxdb_write(struct node *n, struct sample *smps[], unsigned cnt); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/loopback.h b/include/villas/nodes/loopback.h index cfbb5d33a..4cff73eb6 100644 --- a/include/villas/nodes/loopback.h +++ b/include/villas/nodes/loopback.h @@ -32,6 +32,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct node; struct sample; @@ -64,4 +68,8 @@ int loopback_read(struct node *n, struct sample *smps[], unsigned cnt); /** @see node_type::write */ int loopback_write(struct node *n, struct sample *smps[], unsigned cnt); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/mqtt.h b/include/villas/nodes/mqtt.h index 22d12dd61..40713c8b2 100644 --- a/include/villas/nodes/mqtt.h +++ b/include/villas/nodes/mqtt.h @@ -34,6 +34,10 @@ #include #include +#ifdef __cplusplus +extern "C"{ +#endif + /* Forward declarations */ struct format_type; struct mosquitto; @@ -96,4 +100,8 @@ int mqtt_read(struct node *n, struct sample *smps[], unsigned cnt); /** @see node_type::write */ int mqtt_write(struct node *n, struct sample *smps[], unsigned cnt); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/nanomsg.h b/include/villas/nodes/nanomsg.h index 81feb12bf..11b5d2a3e 100644 --- a/include/villas/nodes/nanomsg.h +++ b/include/villas/nodes/nanomsg.h @@ -33,6 +33,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** The maximum length of a packet which contains stuct msg. */ #define NANOMSG_MAX_PACKET_LEN 1500 @@ -72,4 +76,8 @@ int nanomsg_read(struct node *n, struct sample *smps[], unsigned cnt); /** @see node_type::write */ int nanomsg_write(struct node *n, struct sample *smps[], unsigned cnt); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/ngsi.h b/include/villas/nodes/ngsi.h index 67c9bc766..6160907a5 100644 --- a/include/villas/nodes/ngsi.h +++ b/include/villas/nodes/ngsi.h @@ -43,6 +43,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + struct node; struct ngsi { @@ -95,3 +99,7 @@ int ngsi_read(struct node *n, struct sample *smps[], unsigned cnt); int ngsi_write(struct node *n, struct sample *smps[], unsigned cnt); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/nodes/opal.h b/include/villas/nodes/opal.h index f39668e9e..10d96e514 100644 --- a/include/villas/nodes/opal.h +++ b/include/villas/nodes/opal.h @@ -31,8 +31,8 @@ #include -#include "node.h" -#include "msg.h" +#include +#include /* Define RTLAB before including OpalPrint.h for messages to be sent * to the OpalDisplay. Otherwise stdout will be used. */ @@ -41,6 +41,10 @@ #include "AsyncApi.h" #include "OpalGenAsyncParamCtrl.h" +#ifdef __cplusplus +extern "C" { +#endif + struct opal { int reply; int mode; @@ -85,4 +89,8 @@ int opal_read(struct node *n, struct sample *smps[], unsigned cnt); /** @see node_type::write */ int opal_write(struct node *n, struct sample *smps[], unsigned cnt); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/shmem.h b/include/villas/nodes/shmem.h index dc156064f..0426645ce 100644 --- a/include/villas/nodes/shmem.h +++ b/include/villas/nodes/shmem.h @@ -36,6 +36,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** Node-type for shared memory communication. * @see node_type */ @@ -66,3 +70,7 @@ int shmem_read(struct node *n, struct sample *smps[], unsigned cnt); int shmem_write(struct node *n, struct sample *smps[], unsigned cnt); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/nodes/signal_generator.h b/include/villas/nodes/signal_generator.h index 7c669aa16..18d0c0b48 100644 --- a/include/villas/nodes/signal_generator.h +++ b/include/villas/nodes/signal_generator.h @@ -32,6 +32,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct node; struct sample; @@ -90,3 +94,7 @@ int signal_generator_read(struct node *n, struct sample *smps[], unsigned cnt); enum signal_generator_type signal_generator_lookup_type(const char *type); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/nodes/socket.h b/include/villas/nodes/socket.h index 345792823..6cccdf848 100644 --- a/include/villas/nodes/socket.h +++ b/include/villas/nodes/socket.h @@ -50,6 +50,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct format_type; @@ -155,3 +159,7 @@ int socket_parse_addr(const char *str, struct sockaddr *sa, enum socket_layer la int socket_compare_addr(struct sockaddr *x, struct sockaddr *y); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/nodes/stats.h b/include/villas/nodes/stats.h index 27caf6621..89a161656 100644 --- a/include/villas/nodes/stats.h +++ b/include/villas/nodes/stats.h @@ -33,6 +33,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct node; struct sample; @@ -51,7 +55,7 @@ struct stats_node { int stats_node_init(struct super_node *sn); /** @see node_type::print */ -char * stats_node_print(struct node *n); +char *stats_node_print(struct node *n); /** @see node_type::parse */ int stats_node_parse(struct node *n, json_t *cfg); @@ -65,4 +69,8 @@ int stats_node_stop(struct node *n); /** @see node_type::read */ int stats_node_read(struct node *n, struct sample *smps[], unsigned cnt); +#ifdef __cplusplus +} +#endif + /** @} */ diff --git a/include/villas/nodes/test_rtt.h b/include/villas/nodes/test_rtt.h index a0e14e533..20f204410 100644 --- a/include/villas/nodes/test_rtt.h +++ b/include/villas/nodes/test_rtt.h @@ -33,6 +33,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct test_rtt; struct node; @@ -81,3 +85,7 @@ int test_rtt_read(struct node *n, struct sample *smps[], unsigned cnt); int test_rtt_write(struct node *n, struct sample *smps[], unsigned cnt); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/nodes/websocket.h b/include/villas/nodes/websocket.h index 6c61053b1..0e5097a17 100644 --- a/include/villas/nodes/websocket.h +++ b/include/villas/nodes/websocket.h @@ -38,6 +38,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define DEFAULT_WEBSOCKET_QUEUELEN (DEFAULT_QUEUELEN * 64) #define DEFAULT_WEBSOCKET_SAMPLELEN DEFAULT_SAMPLELEN @@ -114,3 +118,7 @@ int websocket_read(struct node *n, struct sample *smps[], unsigned cnt); int websocket_write(struct node *n, struct sample *smps[], unsigned cnt); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/nodes/zeromq.h b/include/villas/nodes/zeromq.h index afdf4a9b7..4f31de46e 100644 --- a/include/villas/nodes/zeromq.h +++ b/include/villas/nodes/zeromq.h @@ -35,6 +35,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #if ZMQ_BUILD_DRAFT_API && (ZMQ_VERSION_MAJOR > 4 || (ZMQ_VERSION_MAJOR == 4 && ZMQ_VERSION_MINOR >= 2)) #define ZMQ_BUILD_DISH 1 #endif @@ -104,3 +108,7 @@ int zeromq_read(struct node *n, struct sample *smps[], unsigned cnt); int zeromq_write(struct node *n, struct sample *smps[], unsigned cnt); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/path.h b/include/villas/path.h index 1db52dcf4..8df955f55 100644 --- a/include/villas/path.h +++ b/include/villas/path.h @@ -32,14 +32,18 @@ #include #include -#include "list.h" -#include "queue.h" -#include "pool.h" -#include "bitset.h" -#include "common.h" -#include "hook.h" -#include "mapping.h" -#include "task.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* Forward declarations */ struct stats; @@ -169,3 +173,7 @@ int path_uses_node(struct path *p, struct node *n); int path_parse(struct path *p, json_t *cfg, struct list *nodes); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/plugin.h b/include/villas/plugin.h index 6a58b2d57..a015c2e49 100644 --- a/include/villas/plugin.h +++ b/include/villas/plugin.h @@ -31,7 +31,21 @@ #include "node_type.h" #include "format_type.h" -/** @todo This is ugly as hell and broken on OS X / Clang anyway. */ +#ifdef __cplusplus +extern "C"{ +#endif + +/** (De-)Register a plugin by adding it to the global plugin list. + * + * We make use of GCC's / Clang's constructor/destructor function + * attributes to let the following code be executed by the loader. + * This works only when we compile libvillas as a shared library! + * + * The __attribute__((constructor)) / __attribute__((destructor)) + * is currently only supported by GCC and Clang + * + * See: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes + */ #define REGISTER_PLUGIN(p) \ __attribute__((constructor(110))) static void UNIQUE(__ctor)() {\ if (plugins.state == STATE_DESTROYED) \ @@ -95,3 +109,7 @@ void plugin_dump(enum plugin_type type); /** Find registered and loaded plugin with given name and type. */ struct plugin * plugin_lookup(enum plugin_type type, const char *name); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/pool.h b/include/villas/pool.h index 15d7833db..4343c1b5a 100644 --- a/include/villas/pool.h +++ b/include/villas/pool.h @@ -28,19 +28,21 @@ #include #include -#include "queue.h" -#include "common.h" -#include "memory.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /** A thread-safe memory pool */ struct pool { off_t buffer_off; /**< Offset from the struct address to the underlying memory area */ - struct memtype *mem; enum state state; size_t len; /**< Length of the underlying memory area */ - size_t blocksz; /**< Length of a block in bytes */ size_t alignment; /**< Alignment of a block in bytes */ @@ -58,7 +60,7 @@ struct pool { * @retval 0 The pool has been successfully initialized. * @retval <>0 There was an error during the pool initialization. */ -int pool_init(struct pool *p, size_t cnt, size_t blocksz, struct memtype *mem); +int pool_init(struct pool *p, size_t cnt, size_t blocksz, struct memory_type *mem); /** Destroy and release memory used by pool. */ int pool_destroy(struct pool *p); @@ -92,3 +94,7 @@ INLINE int pool_put(struct pool *p, void *buf) { return queue_push(&p->queue, buf); } + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/queue.h b/include/villas/queue.h index ce1ab58d5..549cbed78 100644 --- a/include/villas/queue.h +++ b/include/villas/queue.h @@ -33,16 +33,19 @@ #pragma once - #include #include #include -#include "atomic.h" -#include "common.h" +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif /* Forward declarations */ -struct memtype; +struct memory_type; #define CACHELINE_SIZE 64 typedef char cacheline_pad_t[CACHELINE_SIZE]; @@ -58,7 +61,6 @@ struct queue { atomic_state state; - struct memtype *mem; size_t buffer_mask; off_t buffer_off; /**< Relative pointer to struct queue_cell[] */ @@ -74,7 +76,7 @@ struct queue { }; /** Initialize MPMC queue */ -int queue_init(struct queue *q, size_t size, struct memtype *mem); +int queue_init(struct queue *q, size_t size, struct memory_type *mem); /** Desroy MPMC queue and release memory */ int queue_destroy(struct queue *q); @@ -112,3 +114,7 @@ int queue_pull_many(struct queue *q, void *ptr[], size_t cnt); * @return -1 on failure. */ int queue_close(struct queue *q); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/queue_signalled.h b/include/villas/queue_signalled.h index 4f9e012b4..0b73e7c5b 100644 --- a/include/villas/queue_signalled.h +++ b/include/villas/queue_signalled.h @@ -27,6 +27,10 @@ #include "queue.h" +#ifdef __cplusplus +extern "C"{ +#endif + enum queue_signalled_flags { /* Mode */ QUEUE_SIGNALLED_AUTO = (0 << 0), /**< We will choose the best method available on the platform */ @@ -64,7 +68,7 @@ struct queue_signalled { #define queue_signalled_available(q) queue_available(&((q)->queue)) -int queue_signalled_init(struct queue_signalled *qs, size_t size, struct memtype *mem, int flags); +int queue_signalled_init(struct queue_signalled *qs, size_t size, struct memory_type *mem, int flags); int queue_signalled_destroy(struct queue_signalled *qs); @@ -80,3 +84,7 @@ int queue_signalled_close(struct queue_signalled *qs); /** Returns a file descriptor which can be used with poll / select to wait for new data */ int queue_signalled_fd(struct queue_signalled *qs); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/sample.h b/include/villas/sample.h index 149fcc4f5..83e4e6334 100644 --- a/include/villas/sample.h +++ b/include/villas/sample.h @@ -23,11 +23,7 @@ #pragma once -#include "atomic.h" - -#ifdef __cplusplus -extern "C" { -#endif +#include #include #include @@ -35,6 +31,10 @@ extern "C" { #include #include +#ifdef __cplusplus +extern "C"{ +#endif + /* Forward declarations */ struct pool; diff --git a/include/villas/signal.h b/include/villas/signal.h index 56502e8f3..09487bda7 100644 --- a/include/villas/signal.h +++ b/include/villas/signal.h @@ -25,6 +25,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* Forward declarations */ struct list; struct node; @@ -46,3 +50,7 @@ int signal_parse(struct signal *s, json_t *cfg); int signal_parse_list(struct list *list, json_t *cfg); int signal_get_offset(const char *str, struct node *n); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/stats.h b/include/villas/stats.h index e0e46f941..2ee375889 100644 --- a/include/villas/stats.h +++ b/include/villas/stats.h @@ -21,13 +21,16 @@ * along with this program. If not, see . *********************************************************************************/ -#ifndef _STATS_H_ -#define _STATS_H_ +#pragma once #include #include -#include "hist.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif /* Forward declarations */ struct sample; @@ -86,4 +89,6 @@ void stats_print(struct stats *s, FILE *f, enum stats_format fmt, int verbose); enum stats_id stats_lookup_id(const char *name); -#endif /* _STATS_H_ */ +#ifdef __cplusplus +} +#endif diff --git a/include/villas/super_node.h b/include/villas/super_node.h index 064c31cc9..71d172e63 100644 --- a/include/villas/super_node.h +++ b/include/villas/super_node.h @@ -23,11 +23,15 @@ #pragma once -#include "list.h" -#include "api.h" -#include "web.h" -#include "log.h" -#include "common.h" +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /** Global configuration */ struct super_node { @@ -83,3 +87,7 @@ int super_node_stop(struct super_node *sn); /** Desctroy configuration object. */ int super_node_destroy(struct super_node *sn); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/table.h b/include/villas/table.h index f11a0d5d9..18998b2c4 100644 --- a/include/villas/table.h +++ b/include/villas/table.h @@ -25,6 +25,12 @@ * @{ */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + struct table_column { int width; /**< Width of the column. */ char *title; /**< The title as shown in the table header. */ @@ -55,3 +61,7 @@ void table_row(struct table *t, ...); void table_footer(struct table *t); /** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/task.h b/include/villas/task.h index 141f2f7e2..07eadcb50 100644 --- a/include/villas/task.h +++ b/include/villas/task.h @@ -28,6 +28,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** We can choose between two periodic task implementations */ //#define PERIODIC_TASK_IMPL NANOSLEEP #define TIMERFD 1 @@ -73,3 +77,7 @@ int task_set_rate(struct task *t, double rate); * Note: currently not supported on all platforms. */ int task_fd(struct task *t); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/timing.h b/include/villas/timing.h index 1ef49e123..dad07fad1 100644 --- a/include/villas/timing.h +++ b/include/villas/timing.h @@ -28,6 +28,10 @@ #include +#ifdef __cplusplus +extern "C"{ +#endif + /** Get delta between two timespec structs */ struct timespec time_diff(const struct timespec *start, const struct timespec *end); @@ -45,3 +49,7 @@ double time_to_double(const struct timespec *ts); /** Convert double containing seconds after 1970 to timespec. */ struct timespec time_from_double(double secs); + +#ifdef __cplusplus +} +#endif diff --git a/include/villas/utils.h b/include/villas/utils.h index ac753be84..942087fbb 100644 --- a/include/villas/utils.h +++ b/include/villas/utils.h @@ -33,6 +33,11 @@ #include #include +#ifdef __cplusplus +extern "C"{ +#endif + + #ifdef __GNUC__ #define LIKELY(x) __builtin_expect((x),1) #define UNLIKELY(x) __builtin_expect((x),0) @@ -275,3 +280,8 @@ pid_t spawn(const char *name, char *const argv[]); /** Determines the string length as printed on the screen (ignores escable sequences). */ size_t strlenp(const char *str); + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/include/villas/web.h b/include/villas/web.h index a299146e4..c7b06ea95 100644 --- a/include/villas/web.h +++ b/include/villas/web.h @@ -25,7 +25,11 @@ #include -#include "common.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif /* Forward declarations */ struct api; @@ -60,3 +64,7 @@ int web_stop(struct web *w); /** Parse HTTPd and WebSocket related options */ int web_parse(struct web *w, json_t *cfg); + +#ifdef __cplusplus +} +#endif diff --git a/lib/Makefile.villas-ext.inc b/lib/Makefile.villas-ext.inc index b8558a46a..be9fbc621 100644 --- a/lib/Makefile.villas-ext.inc +++ b/lib/Makefile.villas-ext.inc @@ -26,7 +26,7 @@ LIBEXT = $(BUILDDIR)/$(LIBEXT_NAME).so.$(LIBEXT_ABI_VERSION) LIBEXT_SRCS += $(addprefix lib/, sample.c queue.c queue_signalled.c \ memory.c log.c shmem.c utils.c kernel/kernel.c list.c \ - timing.c pool.c log_helper.c \ + timing.c pool.c log_helper.c hash_table.c memory/managed.c \ ) LIBEXT_LDFLAGS = -shared diff --git a/lib/Makefile.villas.inc b/lib/Makefile.villas.inc index ff375a743..48819cb1d 100644 --- a/lib/Makefile.villas.inc +++ b/lib/Makefile.villas.inc @@ -26,11 +26,13 @@ LIB = $(BUILDDIR)/$(LIB_NAME).so.$(LIB_ABI_VERSION) # Object files for libvillas LIB_SRCS += $(addprefix lib/kernel/, kernel.c rt.c) \ + $(addprefix lib/memory/, heap.c hugepage.c managed.c) \ $(addprefix lib/, sample.c path.c node.c hook.c log.c log_config.c \ utils.c super_node.c hist.c timing.c pool.c list.c queue.c \ - queue_signalled.c memory.c memory_ib.c advio.c plugin.c node_type.c stats.c \ + queue_signalled.c memory.c advio.c plugin.c node_type.c stats.c \ mapping.c shmem.c config_helper.c crypt.c compat.c \ log_helper.c task.c buffer.c table.c bitset.c signal.c \ + hash_table.c \ ) LIB_LDFLAGS += -shared diff --git a/lib/api.c b/lib/api.c index 8ea079949..dbf31c23d 100644 --- a/lib/api.c +++ b/lib/api.c @@ -272,7 +272,7 @@ int api_init(struct api *a, struct super_node *sn) if (ret) return ret; - ret = queue_signalled_init(&a->pending, 1024, &memtype_heap, 0); + ret = queue_signalled_init(&a->pending, 1024, &memory_type_heap, 0); if (ret) return ret; diff --git a/lib/api/session.c b/lib/api/session.c index 8ad155efe..e421bff79 100644 --- a/lib/api/session.c +++ b/lib/api/session.c @@ -40,11 +40,11 @@ int api_session_init(struct api_session *s, enum api_mode m) if (ret) return ret; - ret = queue_init(&s->request.queue, 128, &memtype_heap); + ret = queue_init(&s->request.queue, 128, &memory_type_heap); if (ret) return ret; - ret = queue_init(&s->response.queue, 128, &memtype_heap); + ret = queue_init(&s->response.queue, 128, &memory_type_heap); if (ret) return ret; diff --git a/lib/hash_table.c b/lib/hash_table.c new file mode 100644 index 000000000..2fb88aa88 --- /dev/null +++ b/lib/hash_table.c @@ -0,0 +1,202 @@ +/** A generic hash table + * + * @author Steffen Vogel + * @copyright 2017-2018, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include + +#include +#include + +static int hash_table_hash(struct hash_table *ht, void *key) +{ + uintptr_t ptr = (uintptr_t) key; + + return ptr % ht->size; +} + +int hash_table_init(struct hash_table *ht, size_t size) +{ + int ret; + size_t len = sizeof(struct hash_table_entry *) * size; + + assert(ht->state == STATE_DESTROYED); + + ret = pthread_mutex_init(&ht->lock, NULL); + if (ret) + return ret; + + ht->table = alloc(len); + + memset(ht->table, 0, len); + + ht->size = size; + ht->state = STATE_INITIALIZED; + + return 0; +} + +int hash_table_destroy(struct hash_table *ht, dtor_cb_t dtor, bool release) +{ + int ret; + struct hash_table_entry *cur, *next; + + assert(ht->state == STATE_INITIALIZED); + + pthread_mutex_lock(&ht->lock); + + for (int i = 0; i < ht->size; i++) { + for (cur = ht->table[i]; cur; cur = next) { + if (dtor) + dtor(cur->data); + + if (release) + free(cur->data); + + next = cur->next; + + free(cur); + } + } + + pthread_mutex_unlock(&ht->lock); + + ret = pthread_mutex_destroy(&ht->lock); + if (ret) + return ret; + + free(ht->table); + + ht->state = STATE_DESTROYED; + + return 0; +} + +int hash_table_insert(struct hash_table *ht, void *key, void *data) +{ + int ret, ikey = hash_table_hash(ht, key); + struct hash_table_entry *hte, *cur; + + assert(ht->state == STATE_INITIALIZED); + + pthread_mutex_lock(&ht->lock); + + /* Check that the key is not already in the table */ + for (cur = ht->table[ikey]; + cur && cur->key != key; + cur = cur->next); + + if (cur) + ret = -1; + else { + hte = alloc(sizeof(struct hash_table_entry)); + if (hte) { + hte->key = key; + hte->data = data; + hte->next = NULL; + + if ((cur = ht->table[ikey])) + hte->next = ht->table[ikey]; + + ht->table[ikey] = hte; + + ret = 0; + } + else + ret = -1; + } + + pthread_mutex_unlock(&ht->lock); + + return ret; +} + +#include + +int hash_table_delete(struct hash_table *ht, void *key) +{ + int ret, ikey = hash_table_hash(ht, key); + struct hash_table_entry *cur, *prev; + + assert(ht->state == STATE_INITIALIZED); + + pthread_mutex_lock(&ht->lock); + + for (prev = NULL, + cur = ht->table[ikey]; + cur && cur->key != key; + prev = cur, + cur = cur->next); + + if (cur) { + if (prev) + prev->next = cur->next; + else + ht->table[ikey] = cur->next; + + free(cur); + + ret = 0; + } + else + ret = -1; /* not found */ + + pthread_mutex_unlock(&ht->lock); + + return ret; +} + +void * hash_table_lookup(struct hash_table *ht, void *key) +{ + int ikey = hash_table_hash(ht, key); + struct hash_table_entry *hte; + + assert(ht->state == STATE_INITIALIZED); + + pthread_mutex_lock(&ht->lock); + + for (hte = ht->table[ikey]; + hte && hte->key != key; + hte = hte->next); + + void *data = hte ? hte->data : NULL; + + pthread_mutex_unlock(&ht->lock); + + return data; +} + +void hash_table_dump(struct hash_table *ht) +{ + struct hash_table_entry *hte; + + assert(ht->state == STATE_INITIALIZED); + + pthread_mutex_lock(&ht->lock); + + for (int i = 0; i < ht->size; i++) { + printf("%i: ", i); + for (hte = ht->table[i]; hte; hte = hte->next) + printf("%p->%p ", hte->key, hte->data); + printf("\n"); + } + + pthread_mutex_unlock(&ht->lock); +} diff --git a/lib/memory.c b/lib/memory.c index 4877ee01a..4257d14aa 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -25,26 +25,29 @@ #include #include -#include #include #include -#include - -/* Required to allocate hugepages on Apple OS X */ -#ifdef __MACH__ - #include -#elif defined(__linux__) - #include -#endif #include #include #include +#include +#include + +static struct hash_table allocations = { .state = STATE_DESTROYED }; int memory_init(int hugepages) { + int ret; + + if (allocations.state == STATE_DESTROYED) { + ret = hash_table_init(&allocations, 100); + if (ret) + return ret; + } + #ifdef __linux__ - int ret, pagecnt, pagesz; + int pagecnt, pagesz; struct rlimit l; info("Initialize memory sub-system"); @@ -77,252 +80,41 @@ int memory_init(int hugepages) return 0; } -void * memory_alloc(struct memtype *m, size_t len) +void * memory_alloc(struct memory_type *m, size_t len) { - void *ptr = m->alloc(m, len, sizeof(void *)); - - debug(LOG_MEM | 5, "Allocated %#zx bytes of %s memory: %p", len, m->name, ptr); - - return ptr; + return memory_alloc_aligned(m, len, sizeof(void *)); } -void * memory_alloc_aligned(struct memtype *m, size_t len, size_t alignment) +void * memory_alloc_aligned(struct memory_type *m, size_t len, size_t alignment) { - void *ptr = m->alloc(m, len, alignment); + struct memory_allocation *ma = m->alloc(m, len, alignment); - debug(LOG_MEM | 5, "Allocated %#zx bytes of %#zx-byte-aligned %s memory: %p", len, alignment, m->name, ptr); + hash_table_insert(&allocations, ma->address, ma); - return ptr; + debug(LOG_MEM | 5, "Allocated %#zx bytes of %#zx-byte-aligned %s memory: %p", ma->length, ma->alignment, ma->type->name, ma->address); + + return ma->address; } -int memory_free(struct memtype *m, void *ptr, size_t len) +int memory_free(void *ptr) { - debug(LOG_MEM | 5, "Releasing %#zx bytes of %s memory", len, m->name); - - return m->free(m, ptr, len); -} - -static void * memory_heap_alloc(struct memtype *m, size_t len, size_t alignment) -{ - void *ptr; int ret; - if (alignment < sizeof(void *)) - alignment = sizeof(void *); + /* Find corresponding memory allocation entry */ + struct memory_allocation *ma = (struct memory_allocation *) hash_table_lookup(&allocations, ptr); + if (!ma) + return -1; - ret = posix_memalign(&ptr, alignment, len); + debug(LOG_MEM | 5, "Releasing %#zx bytes of %s memory", ma->length, ma->type->name); - return ret ? NULL : ptr; -} + ret = ma->type->free(ma->type, ma); + if (ret) + return ret; -int memory_heap_free(struct memtype *m, void *ptr, size_t len) -{ - free(ptr); + /* Remove allocation entry */ + ret = hash_table_delete(&allocations, ma->address); + if (ret) + return ret; return 0; } - -/** Allocate memory backed by hugepages with malloc() like interface */ -static void * memory_hugepage_alloc(struct memtype *m, size_t len, size_t alignment) -{ - void *ret; - int prot = PROT_READ | PROT_WRITE; - int flags = MAP_PRIVATE | MAP_ANONYMOUS; - -#ifdef __MACH__ - flags |= VM_FLAGS_SUPERPAGE_SIZE_2MB; -#elif defined(__linux__) - flags |= MAP_HUGETLB; - - if (getuid() == 0) - flags |= MAP_LOCKED; -#endif - - ret = mmap(NULL, len, prot, flags, -1, 0); - if (ret == MAP_FAILED) - return NULL; - - return ret; -} - -static int memory_hugepage_free(struct memtype *m, void *ptr, size_t len) -{ - len = ALIGN(len, HUGEPAGESIZE); /* ugly see: https://lkml.org/lkml/2015/3/27/171 */ - - return munmap(ptr, len); -} - -void* memory_managed_alloc(struct memtype *m, size_t len, size_t alignment) -{ - /* Simple first-fit allocation */ - struct memblock *first = (struct memblock *) m->_vd; - struct memblock *block; - - for (block = first; block != NULL; block = block->next) { - if (block->flags & MEMBLOCK_USED) - continue; - - char* cptr = (char *) block + sizeof(struct memblock); - size_t avail = block->len; - uintptr_t uptr = (uintptr_t) cptr; - - /* Check alignment first; leave a gap at start of block to assure - * alignment if necessary */ - uintptr_t rem = uptr % alignment; - uintptr_t gap = 0; - if (rem != 0) { - gap = alignment - rem; - if (gap > avail) - continue; /* Next aligned address isn't in this block anymore */ - - cptr += gap; - avail -= gap; - } - - if (avail >= len) { - if (gap > sizeof(struct memblock)) { - /* The alignment gap is big enough to fit another block. - * The original block descriptor is already at the correct - * position, so we just change its len and create a new block - * descriptor for the actual block we're handling. */ - block->len = gap - sizeof(struct memblock); - struct memblock *newblock = (struct memblock *) (cptr - sizeof(struct memblock)); - newblock->prev = block; - newblock->next = block->next; - block->next = newblock; - newblock->flags = 0; - newblock->len = len; - block = newblock; - } - else { - /* The gap is too small to fit another block descriptor, so we - * must account for the gap length in the block length. */ - block->len = len + gap; - } - - if (avail > len + sizeof(struct memblock)) { - /* Imperfect fit, so create another block for the remaining part */ - struct memblock *newblock = (struct memblock *) (cptr + len); - newblock->prev = block; - newblock->next = block->next; - block->next = newblock; - if (newblock->next) - newblock->next->prev = newblock; - newblock->flags = 0; - newblock->len = avail - len - sizeof(struct memblock); - } - else { - /* If this block was larger than the requested length, but only - * by less than sizeof(struct memblock), we may have wasted - * memory by previous assignments to block->len. */ - block->len = avail; - } - - block->flags |= MEMBLOCK_USED; - - return (void *) cptr; - } - } - - /* No suitable block found */ - return NULL; -} - -int memory_managed_free(struct memtype *m, void *ptr, size_t len) -{ - struct memblock *first = (struct memblock *) m->_vd; - struct memblock *block; - char *cptr = ptr; - - for (block = first; block != NULL; block = block->next) { - if (!(block->flags & MEMBLOCK_USED)) - continue; - - /* Since we may waste some memory at the start of a block to ensure - * alignment, ptr may not actually be the start of the block */ - if ((char *) block + sizeof(struct memblock) <= cptr && - cptr < (char *) block + sizeof(struct memblock) + block->len) { - /* Try to merge it with neighbouring free blocks */ - if (block->prev && !(block->prev->flags & MEMBLOCK_USED) && - block->next && !(block->next->flags & MEMBLOCK_USED)) { - /* Special case first: both previous and next block are unused */ - block->prev->len += block->len + block->next->len + 2 * sizeof(struct memblock); - block->prev->next = block->next->next; - if (block->next->next) - block->next->next->prev = block->prev; - } - else if (block->prev && !(block->prev->flags & MEMBLOCK_USED)) { - block->prev->len += block->len + sizeof(struct memblock); - block->prev->next = block->next; - if (block->next) - block->next->prev = block->prev; - } - else if (block->next && !(block->next->flags & MEMBLOCK_USED)) { - block->len += block->next->len + sizeof(struct memblock); - block->next = block->next->next; - if (block->next) - block->next->prev = block; - } - else { - /* no neighbouring free block, so just mark it as free */ - block->flags &= ~MEMBLOCK_USED; - } - - return 0; - } - } - - return -1; -} - -struct memtype * memtype_managed_init(void *ptr, size_t len) -{ - struct memtype *mt = ptr; - struct memblock *mb; - char *cptr = ptr; - - if (len < sizeof(struct memtype) + sizeof(struct memblock)) { - info("memtype_managed_init: passed region too small"); - return NULL; - } - - /* Initialize memtype */ - mt->name = "managed"; - mt->flags = 0; - mt->alloc = memory_managed_alloc; - mt->free = memory_managed_free; - mt->alignment = 1; - - cptr += ALIGN(sizeof(struct memtype), sizeof(void *)); - - /* Initialize first free memblock */ - mb = (struct memblock *) cptr; - mb->prev = NULL; - mb->next = NULL; - mb->flags = 0; - - cptr += ALIGN(sizeof(struct memblock), sizeof(void *)); - - mb->len = len - (cptr - (char *) ptr); - - mt->_vd = (void *) mb; - - return mt; -} - -/* List of available memory types */ -struct memtype memtype_heap = { - .name = "heap", - .flags = MEMORY_HEAP, - .alloc = memory_heap_alloc, - .free = memory_heap_free, - .alignment = 1 -}; - -struct memtype memtype_hugepage = { - .name = "mmap_hugepages", - .flags = MEMORY_MMAP | MEMORY_HUGEPAGE, - .alloc = memory_hugepage_alloc, - .free = memory_hugepage_free, - .alignment = 21 /* 2 MiB hugepage */ -}; diff --git a/lib/memory/heap.c b/lib/memory/heap.c new file mode 100644 index 000000000..7e054fd23 --- /dev/null +++ b/lib/memory/heap.c @@ -0,0 +1,67 @@ +/** Memory allocators. + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include + +#include +#include + +static struct memory_allocation * memory_heap_alloc(struct memory_type *m, size_t len, size_t alignment) +{ + int ret; + + struct memory_allocation *ma = alloc(sizeof(struct memory_allocation)); + if (!ma) + return NULL; + + ma->alignment = alignment; + ma->type = m; + ma->length = len; + + if (ma->alignment < sizeof(void *)) + ma->alignment = sizeof(void *); + + ret = posix_memalign(&ma->address, ma->alignment, ma->length); + if (ret) { + free(ma); + return NULL; + } + + return ma; +} + +static int memory_heap_free(struct memory_type *m, struct memory_allocation *ma) +{ + free(ma->address); + free(ma); + + return 0; +} + +/* List of available memory types */ +struct memory_type memory_type_heap = { + .name = "heap", + .flags = MEMORY_HEAP, + .alloc = memory_heap_alloc, + .free = memory_heap_free, + .alignment = 1 +}; diff --git a/lib/memory/hugepage.c b/lib/memory/hugepage.c new file mode 100644 index 000000000..6bf17719c --- /dev/null +++ b/lib/memory/hugepage.c @@ -0,0 +1,101 @@ +/** Hugepage memory allocator. + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Required to allocate hugepages on Apple OS X */ +#ifdef __MACH__ + #include +#elif defined(__linux__) + #include +#endif + +#include +#include +#include + +#define HUGEPAGESIZE (1 << 22) /* 2 MiB */ + +/** Allocate memory backed by hugepages with malloc() like interface */ +static struct memory_allocation * memory_hugepage_alloc(struct memory_type *m, size_t len, size_t alignment) +{ + int prot = PROT_READ | PROT_WRITE; + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + +#ifdef __MACH__ + flags |= VM_FLAGS_SUPERPAGE_SIZE_2MB; +#elif defined(__linux__) + flags |= MAP_HUGETLB; + + if (getuid() == 0) + flags |= MAP_LOCKED; +#endif + + struct memory_allocation *ma = alloc(sizeof(struct memory_allocation)); + if (!ma) + return NULL; + + /** We must make sure that len is a multiple of the hugepage size + * + * See: https://lkml.org/lkml/2014/10/22/925 + */ + ma->length = ALIGN(len, HUGEPAGESIZE); + ma->alignment = alignment; + ma->type = m; + + ma->address = mmap(NULL, len, prot, flags, -1, 0); + if (ma->address == MAP_FAILED) { + free(ma); + return NULL; + } + + return ma; +} + +static int memory_hugepage_free(struct memory_type *m, struct memory_allocation *ma) +{ + int ret; + + ret = munmap(ma->address, ma->length); + if (ret) + return ret; + + free(ma); + + return 0; +} + +struct memory_type memory_hugepage = { + .name = "mmap_hugepages", + .flags = MEMORY_MMAP | MEMORY_HUGEPAGE, + .alloc = memory_hugepage_alloc, + .free = memory_hugepage_free, + .alignment = 21 /* 2 MiB hugepage */ +}; diff --git a/lib/memory_ib.c b/lib/memory/ib.c similarity index 60% rename from lib/memory_ib.c rename to lib/memory/ib.c index 9a1432aaf..5679c6e6a 100644 --- a/lib/memory_ib.c +++ b/lib/memory/ib.c @@ -21,9 +21,15 @@ *********************************************************************************/ #include -#include +#include +#include #include +struct memory_ib { + struct ibv_pd *pd; + struct memory_type *parent; +}; + struct ibv_mr * memory_ib_mr(void *ptr) { struct ibv_mr *mr = (struct ibv_mr *) ptr; @@ -31,41 +37,51 @@ struct ibv_mr * memory_ib_mr(void *ptr) return (mr - 1); } -void * memory_ib_alloc(struct memtype *m, size_t len, size_t alignment) +static struct memory_allocation * memory_ib_alloc(struct memory_type *m, size_t len, size_t alignment) { struct memory_ib *mi = (struct memory_ib *) m->_vd; - struct ibv_mr **mr = memory_alloc_aligned(mi->parent, len + sizeof(struct ibv_mr *), alignment); - char *ptr = (char *) (mr + 1); + struct memory_allocation *ma = alloc(sizeof(struct memory_allocation)); + if (!ma) + return NULL; - *mr = ibv_reg_mr(mi->pd, ptr, len, IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); - if(!*mr) { - free(ptr); + ma->type = m; + ma->length = len; + ma->alignment = alignment; + + ma->parent = mi->parent->alloc(mi->parent, len + sizeof(struct ibv_mr *), alignment); + ma->address = ma->parent->address; + + ma->ib.mr = ibv_reg_mr(mi->pd, ma->address, ma->length, IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); + if(!ma->ib.mr) { + mi->parent->free(mi->parent, ma->parent); + free(ma); return NULL; } - return ptr; + return ma; } -int memory_ib_free(struct memtype *m, void *ptr, size_t len) +static int memory_ib_free(struct memory_type *m, struct memory_allocation *ma) { + int ret; struct memory_ib *mi = (struct memory_ib *) m->_vd; - struct ibv_mr *mr = memory_ib_mr(ptr); - ibv_dereg_mr(mr); + ibv_dereg_mr(ma->ib.mr); - ptr -= sizeof(struct ibv_mr *); - len += sizeof(struct ibv_mr *); + ret = mi->parent->free(mi->parent, ma->parent); + if (ret) + return ret; - memory_free(mi->parent, ptr, len); + free(ma); return 0; } -struct memtype * ib_memtype(struct node *n, struct memtype *parent) +struct memory_type * memory_ib(struct node *n, struct memory_type *parent) { struct infiniband *i = (struct infiniband *) n->_vd; - struct memtype *mt = malloc(sizeof(struct memtype)); + struct memory_type *mt = malloc(sizeof(struct memory_type)); mt->name = "ib"; mt->flags = 0; diff --git a/lib/memory/managed.c b/lib/memory/managed.c new file mode 100644 index 000000000..ab8bc4b59 --- /dev/null +++ b/lib/memory/managed.c @@ -0,0 +1,193 @@ +/** Memory allocators. + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +static struct memory_allocation * memory_managed_alloc(struct memory_type *m, size_t len, size_t alignment) +{ + /* Simple first-fit allocation */ + struct memory_block *first = (struct memory_block *) m->_vd; + struct memory_block *block; + + for (block = first; block != NULL; block = block->next) { + if (block->used) + continue; + + char* cptr = (char *) block + sizeof(struct memory_block); + size_t avail = block->length; + uintptr_t uptr = (uintptr_t) cptr; + + /* Check alignment first; leave a gap at start of block to assure + * alignment if necessary */ + uintptr_t rem = uptr % alignment; + uintptr_t gap = 0; + if (rem != 0) { + gap = alignment - rem; + if (gap > avail) + continue; /* Next aligned address isn't in this block anymore */ + + cptr += gap; + avail -= gap; + } + + if (avail >= len) { + if (gap > sizeof(struct memory_block)) { + /* The alignment gap is big enough to fit another block. + * The original block descriptor is already at the correct + * position, so we just change its len and create a new block + * descriptor for the actual block we're handling. */ + block->length = gap - sizeof(struct memory_block); + struct memory_block *newblock = (struct memory_block *) (cptr - sizeof(struct memory_block)); + newblock->prev = block; + newblock->next = block->next; + block->next = newblock; + newblock->used = false; + newblock->length = len; + block = newblock; + } + else { + /* The gap is too small to fit another block descriptor, so we + * must account for the gap length in the block length. */ + block->length = len + gap; + } + + if (avail > len + sizeof(struct memory_block)) { + /* Imperfect fit, so create another block for the remaining part */ + struct memory_block *newblock = (struct memory_block *) (cptr + len); + newblock->prev = block; + newblock->next = block->next; + block->next = newblock; + + if (newblock->next) + newblock->next->prev = newblock; + + newblock->used = false; + newblock->length = avail - len - sizeof(struct memory_block); + } + else { + /* If this block was larger than the requested length, but only + * by less than sizeof(struct memory_block), we may have wasted + * memory by previous assignments to block->length. */ + block->length = avail; + } + + block->used = true; + + struct memory_allocation *ma = alloc(sizeof(struct memory_allocation)); + if (!ma) + return NULL; + + ma->address = cptr; + ma->type = m; + ma->alignment = alignment; + ma->length = len; + ma->managed.block = block; + + return ma; + } + } + + /* No suitable block found */ + return NULL; +} + +static int memory_managed_free(struct memory_type *m, struct memory_allocation *ma) +{ + struct memory_block *block = ma->managed.block; + + /* Try to merge it with neighbouring free blocks */ + if (block->prev && !block->prev->used && + block->next && !block->next->used) { + /* Special case first: both previous and next block are unused */ + block->prev->length += block->length + block->next->length + 2 * sizeof(struct memory_block); + block->prev->next = block->next->next; + if (block->next->next) + block->next->next->prev = block->prev; + } + else if (block->prev && !block->prev->used) { + block->prev->length += block->length + sizeof(struct memory_block); + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } + else if (block->next && !block->next->used) { + block->length += block->next->length + sizeof(struct memory_block); + block->next = block->next->next; + if (block->next) + block->next->prev = block; + } + else { + /* no neighbouring free block, so just mark it as free */ + block->used = false; + } + + free(ma); + + return 0; +} + +struct memory_type * memory_managed(void *ptr, size_t len) +{ + struct memory_type *mt = ptr; + struct memory_block *mb; + char *cptr = ptr; + + if (len < sizeof(struct memory_type) + sizeof(struct memory_block)) { + info("memory_managed: passed region too small"); + return NULL; + } + + /* Initialize memory_type */ + mt->name = "managed"; + mt->flags = 0; + mt->alloc = memory_managed_alloc; + mt->free = memory_managed_free; + mt->alignment = 1; + + cptr += ALIGN(sizeof(struct memory_type), sizeof(void *)); + + /* Initialize first free memory block */ + mb = (struct memory_block *) cptr; + mb->prev = NULL; + mb->next = NULL; + mb->used = false; + + cptr += ALIGN(sizeof(struct memory_block), sizeof(void *)); + + mb->length = len - (cptr - (char *) ptr); + + mt->_vd = (void *) mb; + + return mt; +} diff --git a/lib/node.c b/lib/node.c index 866cbe576..e7c9f7a7f 100644 --- a/lib/node.c +++ b/lib/node.c @@ -309,6 +309,10 @@ int node_check(struct node *n) if (ret) return ret; + ret = n->_vt->check ? n->_vt->check(n) : 0; + if (ret) + return ret; + n->state = STATE_CHECKED; return 0; @@ -545,9 +549,9 @@ int node_fd(struct node *n) return n->_vt->fd ? n->_vt->fd(n) : -1; } -struct memtype * node_memtype(struct node *n, struct memtype *parent) +struct memory_type * node_memory_type(struct node *n, struct memory_type *parent) { - return n->_vt->memtype(n, parent) ? n->_vt->memtype(n, parent) : &memtype_hugepage; + return n->_vt->memory_type ? n->_vt->memory_type(n, parent) : &memory_hugepage; } int node_parse_list(struct list *list, json_t *cfg, struct list *all) diff --git a/lib/nodes/Makefile.inc b/lib/nodes/Makefile.inc index 47a329242..f6423c129 100644 --- a/lib/nodes/Makefile.inc +++ b/lib/nodes/Makefile.inc @@ -159,6 +159,7 @@ endif # Enable Infiniband support ifeq ($(WITH_NODE_INFINIBAND),1) LIB_SRCS += lib/nodes/infiniband.c + LIB_SRCS += lib/memory/ib.c LIB_NODES += infiniband LIB_LDLIBS += -libverbs LIB_LDLIBS += -lrdmacm diff --git a/lib/nodes/iec61850_sv.c b/lib/nodes/iec61850_sv.c index 70c91efca..82dadf238 100644 --- a/lib/nodes/iec61850_sv.c +++ b/lib/nodes/iec61850_sv.c @@ -294,11 +294,11 @@ int iec61850_sv_start(struct node *n) SVReceiver_addSubscriber(i->subscriber.receiver, i->subscriber.subscriber); /* Initialize pool and queue to pass samples between threads */ - ret = pool_init(&i->subscriber.pool, 1024, SAMPLE_LEN(n->samplelen), &memtype_hugepage); + ret = pool_init(&i->subscriber.pool, 1024, SAMPLE_LEN(n->samplelen), &memory_hugepage); if (ret) return ret; - ret = queue_signalled_init(&i->subscriber.queue, 1024, &memtype_hugepage, 0); + ret = queue_signalled_init(&i->subscriber.queue, 1024, &memory_hugepage, 0); if (ret) return ret; } diff --git a/lib/nodes/infiniband.c b/lib/nodes/infiniband.c index b1a6fe528..b5483c114 100644 --- a/lib/nodes/infiniband.c +++ b/lib/nodes/infiniband.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include @@ -239,7 +239,7 @@ static void ib_build_ibv(struct node *n) pool_init(&ib->mem.p_recv, ib->qp_init.cap.max_recv_wr, SAMPLE_DATA_LEN(DEFAULT_SAMPLELEN), - &memtype_heap); + &memory_type_heap); if(ret) { error("Failed to init recv memory pool of node %s: %s", @@ -270,7 +270,7 @@ static void ib_build_ibv(struct node *n) pool_init(&ib->mem.p_send, ib->qp_init.cap.max_send_wr, sizeof(double), - &memtype_heap); + &memory_type_heap); if(ret) { error("Failed to init send memory of node %s: %s", @@ -840,7 +840,7 @@ static struct plugin p = { .read = ib_read, .write = ib_write, .fd = ib_fd, - .memtype = ib_memtype + .memory_type = memory_ib } }; diff --git a/lib/nodes/loopback.c b/lib/nodes/loopback.c index e25efcd67..62b11519c 100644 --- a/lib/nodes/loopback.c +++ b/lib/nodes/loopback.c @@ -50,11 +50,11 @@ int loopback_open(struct node *n) int ret; struct loopback *l = (struct loopback *) n->_vd; - ret = pool_init(&l->pool, l->queuelen, SAMPLE_LEN(n->samplelen), &memtype_hugepage); + ret = pool_init(&l->pool, l->queuelen, SAMPLE_LEN(n->samplelen), &memory_hugepage); if (ret) return ret; - return queue_signalled_init(&l->queue, l->queuelen, &memtype_hugepage, QUEUE_SIGNALLED_EVENTFD); + return queue_signalled_init(&l->queue, l->queuelen, &memory_hugepage, QUEUE_SIGNALLED_EVENTFD); } int loopback_close(struct node *n) diff --git a/lib/nodes/mqtt.c b/lib/nodes/mqtt.c index bc3692f13..893d10d8d 100644 --- a/lib/nodes/mqtt.c +++ b/lib/nodes/mqtt.c @@ -301,11 +301,11 @@ int mqtt_start(struct node *n) if (ret) return ret; - ret = pool_init(&m->pool, 1024, SAMPLE_LEN(n->samplelen), &memtype_hugepage); + ret = pool_init(&m->pool, 1024, SAMPLE_LEN(n->samplelen), &memory_hugepage); if (ret) return ret; - ret = queue_signalled_init(&m->queue, 1024, &memtype_hugepage, 0); + ret = queue_signalled_init(&m->queue, 1024, &memory_hugepage, 0); if (ret) return ret; diff --git a/lib/nodes/websocket.c b/lib/nodes/websocket.c index b30926fff..a81b8b2e8 100644 --- a/lib/nodes/websocket.c +++ b/lib/nodes/websocket.c @@ -81,7 +81,7 @@ static int websocket_connection_init(struct websocket_connection *c) c->_name = NULL; - ret = queue_init(&c->queue, DEFAULT_QUEUELEN, &memtype_hugepage); + ret = queue_init(&c->queue, DEFAULT_QUEUELEN, &memory_hugepage); if (ret) return ret; @@ -400,11 +400,11 @@ int websocket_start(struct node *n) int ret; struct websocket *w = (struct websocket *) n->_vd; - ret = pool_init(&w->pool, DEFAULT_WEBSOCKET_QUEUELEN, SAMPLE_LEN(DEFAULT_WEBSOCKET_SAMPLELEN), &memtype_hugepage); + ret = pool_init(&w->pool, DEFAULT_WEBSOCKET_QUEUELEN, SAMPLE_LEN(DEFAULT_WEBSOCKET_SAMPLELEN), &memory_hugepage); if (ret) return ret; - ret = queue_signalled_init(&w->queue, DEFAULT_WEBSOCKET_QUEUELEN, &memtype_hugepage, 0); + ret = queue_signalled_init(&w->queue, DEFAULT_WEBSOCKET_QUEUELEN, &memory_hugepage, 0); if (ret) return ret; diff --git a/lib/path.c b/lib/path.c index 7763e1aa5..b3bb3d9e0 100644 --- a/lib/path.c +++ b/lib/path.c @@ -46,7 +46,7 @@ static int path_source_init(struct path_source *ps) { int ret; - ret = pool_init(&ps->pool, MAX(DEFAULT_QUEUELEN, ps->node->in.vectorize), SAMPLE_LEN(ps->node->samplelen), &memtype_hugepage); + ret = pool_init(&ps->pool, MAX(DEFAULT_QUEUELEN, ps->node->in.vectorize), SAMPLE_LEN(ps->node->samplelen), &memory_hugepage); if (ret) return ret; @@ -148,7 +148,7 @@ static int path_destination_init(struct path_destination *pd, int queuelen) { int ret; - ret = queue_init(&pd->queue, queuelen, &memtype_hugepage); + ret = queue_init(&pd->queue, queuelen, &memory_hugepage); if (ret) return ret; @@ -430,7 +430,7 @@ int path_init2(struct path *p) if (!p->samplelen) p->samplelen = DEFAULT_SAMPLELEN; - ret = pool_init(&p->pool, MAX(1, list_length(&p->destinations)) * p->queuelen, SAMPLE_LEN(p->samplelen), &memtype_hugepage); + ret = pool_init(&p->pool, MAX(1, list_length(&p->destinations)) * p->queuelen, SAMPLE_LEN(p->samplelen), &memory_hugepage); if (ret) return ret; diff --git a/lib/pool.c b/lib/pool.c index 0f77df83a..1a7ce726f 100644 --- a/lib/pool.c +++ b/lib/pool.c @@ -25,7 +25,7 @@ #include #include -int pool_init(struct pool *p, size_t cnt, size_t blocksz, struct memtype *m) +int pool_init(struct pool *p, size_t cnt, size_t blocksz, struct memory_type *m) { int ret; @@ -35,7 +35,6 @@ int pool_init(struct pool *p, size_t cnt, size_t blocksz, struct memtype *m) p->alignment = kernel_get_cacheline_size(); p->blocksz = p->alignment * CEIL(blocksz, p->alignment); p->len = cnt * p->blocksz; - p->mem = m; void *buffer = memory_alloc_aligned(m, p->len, p->alignment); if (!buffer) @@ -66,7 +65,7 @@ int pool_destroy(struct pool *p) queue_destroy(&p->queue); void *buffer = (char*) p + p->buffer_off; - ret = memory_free(p->mem, buffer, p->len); + ret = memory_free(buffer); if (ret == 0) p->state = STATE_DESTROYED; diff --git a/lib/queue.c b/lib/queue.c index af65d0bde..0b020b192 100644 --- a/lib/queue.c +++ b/lib/queue.c @@ -36,7 +36,7 @@ #include /** Initialize MPMC queue */ -int queue_init(struct queue *q, size_t size, struct memtype *mem) +int queue_init(struct queue *q, size_t size, struct memory_type *m) { assert(q->state == STATE_DESTROYED); @@ -47,9 +47,8 @@ int queue_init(struct queue *q, size_t size, struct memtype *mem) warn("A queue size was changed from %lu to %lu", old_size, size); } - q->mem = mem; q->buffer_mask = size - 1; - struct queue_cell *buffer = (struct queue_cell *) memory_alloc(q->mem, sizeof(struct queue_cell) * size); + struct queue_cell *buffer = (struct queue_cell *) memory_alloc(m, sizeof(struct queue_cell) * size); if (!buffer) return -2; @@ -74,8 +73,7 @@ int queue_destroy(struct queue *q) if (q->state == STATE_DESTROYED) return 0; - ret = memory_free(q->mem, buffer, (q->buffer_mask + 1) * sizeof(struct queue_cell)); - + ret = memory_free(buffer); if (ret == 0) q->state = STATE_DESTROYED; diff --git a/lib/queue_signalled.c b/lib/queue_signalled.c index a37caa316..bc625ecd6 100644 --- a/lib/queue_signalled.c +++ b/lib/queue_signalled.c @@ -36,7 +36,7 @@ static void queue_signalled_cleanup(void *p) pthread_mutex_unlock(&qs->pthread.mutex); } -int queue_signalled_init(struct queue_signalled *qs, size_t size, struct memtype *mem, int flags) +int queue_signalled_init(struct queue_signalled *qs, size_t size, struct memory_type *mem, int flags) { int ret; diff --git a/lib/shmem.c b/lib/shmem.c index 56020a249..294e7ae67 100644 --- a/lib/shmem.c +++ b/lib/shmem.c @@ -35,8 +35,8 @@ size_t shmem_total_size(int queuelen, int samplelen) { - /* We have the constant const of the memtype header */ - return sizeof(struct memtype) + /* We have the constant const of the memory_type header */ + return sizeof(struct memory_type) /* and the shared struct itself */ + sizeof(struct shmem_shared) /* the size of the actual queue and the queue for the pool */ @@ -44,7 +44,7 @@ size_t shmem_total_size(int queuelen, int samplelen) /* the size of the pool */ + queuelen * kernel_get_cacheline_size() * CEIL(SAMPLE_LEN(samplelen), kernel_get_cacheline_size()) /* a memblock for each allocation (1 shmem_shared, 2 queues, 1 pool) */ - + 4 * sizeof(struct memblock) + + 4 * sizeof(struct memory_block) /* and some extra buffer for alignment */ + 1024; } @@ -55,7 +55,7 @@ int shmem_int_open(const char *wname, const char* rname, struct shmem_int *shm, int fd, ret; size_t len; void *base; - struct memtype *manager; + struct memory_type *manager; struct shmem_shared *shared; struct stat stat_buf; sem_t *sem_own, *sem_other; @@ -92,7 +92,7 @@ retry: fd = shm_open(wname, O_RDWR|O_CREAT|O_EXCL, 0600); close(fd); - manager = memtype_managed_init(base, len); + manager = memory_managed(base, len); shared = memory_alloc(manager, sizeof(struct shmem_shared)); if (!shared) { errno = ENOMEM; @@ -144,7 +144,7 @@ retry: fd = shm_open(wname, O_RDWR|O_CREAT|O_EXCL, 0600); if (base == MAP_FAILED) return -10; - cptr = (char *) base + sizeof(struct memtype) + sizeof(struct memblock); + cptr = (char *) base + sizeof(struct memory_type) + sizeof(struct memory_block); shared = (struct shmem_shared *) cptr; shm->read.base = base; shm->read.name = rname; diff --git a/packaging/docker/Dockerfile.dev b/packaging/docker/Dockerfile.dev index 6f10d1736..0561bacd3 100644 --- a/packaging/docker/Dockerfile.dev +++ b/packaging/docker/Dockerfile.dev @@ -78,7 +78,7 @@ RUN dnf -y install \ libiec61850-devel \ librabbitmq-devel \ mosquitto-devel \ - comedilib-devel + comedilib-devel comedilib # IB Verbs Dependencies RUN dnf -y install \ diff --git a/packaging/rpm/villas-node.spec b/packaging/rpm/villas-node.spec index 6570b0090..71a8a3255 100644 --- a/packaging/rpm/villas-node.spec +++ b/packaging/rpm/villas-node.spec @@ -14,7 +14,7 @@ BuildRequires: gcc pkgconfig make Requires: iproute module-init-tools -BuildRequires: openssl-devel libconfig-devel libnl3-devel libcurl-devel jansson-devel libwebsockets-devel zeromq-devel nanomsg-devel libiec61850-devel librabbitmq-devel mosquitto-devel comedilib-devel +BuildRequires: openssl-devel libconfig-devel libnl3-devel libcurl-devel jansson-devel libwebsockets-devel zeromq-devel nanomsg-devel libiec61850-devel librabbitmq-devel mosquitto-devel comedilib-devel comedilib Requires: openssl libconfig libnl3 libcurl jansson libwebsockets zeromq nanomsg libiec61850 librabbitmq mosquitto comedilib %description diff --git a/src/hook.c b/src/hook.c index ecf31cf9f..1d444b458 100644 --- a/src/hook.c +++ b/src/hook.c @@ -182,7 +182,7 @@ check: if (optarg == endptr) smps = alloc(cnt * sizeof(struct sample *)); - ret = pool_init(&q, 10 * cnt, SAMPLE_LEN(DEFAULT_SAMPLELEN), &memtype_hugepage); + ret = pool_init(&q, 10 * cnt, SAMPLE_LEN(DEFAULT_SAMPLELEN), &memory_hugepage); if (ret) error("Failed to initilize memory pool"); diff --git a/src/pipe.c b/src/pipe.c index 272f4cf1b..c7558e60e 100644 --- a/src/pipe.c +++ b/src/pipe.c @@ -132,7 +132,8 @@ static void * send_loop(void *ctx) struct sample *smps[node->out.vectorize]; /* Initialize memory */ - ret = pool_init(&sendd.pool, MAX(16384, 2*LOG2_CEIL(node->out.vectorize)), SAMPLE_LEN(DEFAULT_SAMPLELEN), node_memtype(node, &memtype_heap)); + ret = pool_init(&sendd.pool, MAX(16384, 2*LOG2_CEIL(node->out.vectorize)), SAMPLE_LEN(DEFAULT_SAMPLELEN), node_memory_type(node, &memory_type_heap)); + if (ret < 0) error("Failed to allocate memory for receive pool."); @@ -196,7 +197,7 @@ static void * recv_loop(void *ctx) struct sample *smps[node->in.vectorize]; /* Initialize memory */ - ret = pool_init(&recvv.pool, MAX(16*8192, 2*LOG2_CEIL(node->in.vectorize)), SAMPLE_LEN(DEFAULT_SAMPLELEN), node_memtype(node, &memtype_heap)); + ret = pool_init(&recvv.pool, MAX(16*8192, 2*LOG2_CEIL(node->in.vectorize)), SAMPLE_LEN(DEFAULT_SAMPLELEN), node_memory_type(node, &memory_type_heap)); if (ret < 0) error("Failed to allocate memory for receive pool."); diff --git a/src/signal.c b/src/signal.c index 324f12733..31e47716c 100644 --- a/src/signal.c +++ b/src/signal.c @@ -155,7 +155,7 @@ int main(int argc, char *argv[]) if (ret) error("Failed to verify node configuration"); - ret = pool_init(&q, 16, SAMPLE_LEN(n.samplelen), &memtype_heap); + ret = pool_init(&q, 16, SAMPLE_LEN(n.samplelen), &memory_type_heap); if (ret) error("Failed to initialize pool"); diff --git a/src/test-cmp.c b/src/test-cmp.c index 0c5bad66e..52d93c5b0 100644 --- a/src/test-cmp.c +++ b/src/test-cmp.c @@ -122,7 +122,7 @@ check: if (optarg == endptr) int n = argc - optind; /* The number of files which we compare */ struct side s[n]; - ret = pool_init(&pool, n, SAMPLE_LEN(DEFAULT_SAMPLELEN), &memtype_heap); + ret = pool_init(&pool, n, SAMPLE_LEN(DEFAULT_SAMPLELEN), &memory_type_heap); if (ret) error("Failed to initialize pool"); diff --git a/tests/unit/hash_table.c b/tests/unit/hash_table.c new file mode 100644 index 000000000..362c42e69 --- /dev/null +++ b/tests/unit/hash_table.c @@ -0,0 +1,71 @@ +/** Unit tests for hash table + * + * @author Steffen Vogel + * @copyright 2018, Institute for Automation of Complex Power Systems, EONERC + * @license GNU General Public License (version 3) + * + * VILLASnode + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *********************************************************************************/ + +#include + +#include +#include + +static char *keys[] = { "able", "achieve", "acoustics", "action", "activity", "aftermath", "afternoon", "afterthought", "apparel", "appliance", "beginner", "believe", "bomb", "border", "boundary", "breakfast", "cabbage", "cable", "calculator", "calendar", "caption", "carpenter", "cemetery", "channel", "circle", "creator", "creature", "education", "faucet", "feather", "friction", "fruit", "fuel", "galley", "guide", "guitar", "health", "heart", "idea", "kitten", "laborer", "language" }; +static char *values[] = { "lawyer", "linen", "locket", "lumber", "magic", "minister", "mitten", "money", "mountain", "music", "partner", "passenger", "pickle", "picture", "plantation", "plastic", "pleasure", "pocket", "police", "pollution", "railway", "recess", "reward", "route", "scene", "scent", "squirrel", "stranger", "suit", "sweater", "temper", "territory", "texture", "thread", "treatment", "veil", "vein", "volcano", "wealth", "weather", "wilderness", "wren" }; + +Test(hash_table, hash_table_lookup) +{ + int ret; + struct hash_table ht = { .state = STATE_DESTROYED }; + + ret = hash_table_init(&ht, 20); + cr_assert(!ret); + + /* Insert */ + for (int i = 0; i < ARRAY_LEN(keys); i++) { + ret = hash_table_insert(&ht, keys[i], values[i]); + cr_assert(!ret); + } + + /* Lookup */ + for (int i = 0; i < ARRAY_LEN(keys); i++) { + char *value = hash_table_lookup(&ht, keys[i]); + cr_assert_eq(values[i], value); + } + + /* Inserting the same key twice should fail */ + ret = hash_table_insert(&ht, keys[0], values[0]); + cr_assert(ret); + + hash_table_dump(&ht); + + /* Removing an entry */ + ret = hash_table_delete(&ht, keys[0]); + cr_assert(!ret); + + /* Removing the same entry twice should fail */ + ret = hash_table_delete(&ht, keys[0]); + cr_assert(ret); + + /* After removing, we should be able to insert it again */ + ret = hash_table_insert(&ht, keys[0], values[0]); + cr_assert(!ret); + + ret = hash_table_destroy(&ht, NULL, false); + cr_assert(!ret); +} diff --git a/tests/unit/io.c b/tests/unit/io.c index 4abdc57a2..8c2338cd9 100644 --- a/tests/unit/io.c +++ b/tests/unit/io.c @@ -185,7 +185,7 @@ ParameterizedTest(char *fmt, io, lowlevel) struct sample *smps[NUM_SAMPLES]; struct sample *smpt[NUM_SAMPLES]; - ret = pool_init(&p, 2 * NUM_SAMPLES, SAMPLE_LEN(NUM_VALUES), &memtype_hugepage); + ret = pool_init(&p, 2 * NUM_SAMPLES, SAMPLE_LEN(NUM_VALUES), &memory_hugepage); cr_assert_eq(ret, 0); info("Running test for format = %s", fmt); @@ -232,7 +232,7 @@ ParameterizedTest(char *fmt, io, highlevel) info("Running test for format = %s", fmt); - ret = pool_init(&p, 2 * NUM_SAMPLES, SAMPLE_LEN(NUM_VALUES), &memtype_hugepage); + ret = pool_init(&p, 2 * NUM_SAMPLES, SAMPLE_LEN(NUM_VALUES), &memory_hugepage); cr_assert_eq(ret, 0); generate_samples(&p, smps, smpt, NUM_SAMPLES, NUM_VALUES); diff --git a/tests/unit/memory.c b/tests/unit/memory.c index 55435d45c..821795afd 100644 --- a/tests/unit/memory.c +++ b/tests/unit/memory.c @@ -28,26 +28,31 @@ #include #include +#define HUGEPAGESIZE (1 << 22) + TheoryDataPoints(memory, aligned) = { DataPoints(size_t, 1, 32, 55, 1 << 10, 1 << 20), DataPoints(size_t, 1, 8, 1 << 12), - DataPoints(struct memtype *, &memtype_heap, &memtype_hugepage) + DataPoints(struct memory_type *, &memory_type_heap, &memory_hugepage) }; -Theory((size_t len, size_t align, struct memtype *m), memory, aligned) { +Theory((size_t len, size_t align, struct memory_type *m), memory, aligned) { int ret; void *ptr; + ret = memory_init(100); + cr_assert(!ret); + ptr = memory_alloc_aligned(m, len, align); cr_assert_neq(ptr, NULL, "Failed to allocate memory"); cr_assert(IS_ALIGNED(ptr, align)); - if (m == &memtype_hugepage) { + if (m == &memory_hugepage) { cr_assert(IS_ALIGNED(ptr, HUGEPAGESIZE)); } - ret = memory_free(m, ptr, len); + ret = memory_free(ptr); cr_assert_eq(ret, 0, "Failed to release memory: ret=%d, ptr=%p, len=%zu: %s", ret, ptr, len, strerror(errno)); } @@ -57,15 +62,18 @@ Test(memory, manager) { int ret; void *p, *p1, *p2, *p3; - struct memtype *m; + struct memory_type *m; total_size = 1 << 10; - max_block = total_size - sizeof(struct memtype) - sizeof(struct memblock); + max_block = total_size - sizeof(struct memory_type) - sizeof(struct memory_block); - p = memory_alloc(&memtype_heap, total_size); + ret = memory_init(0); + cr_assert(!ret); + + p = memory_alloc(&memory_type_heap, total_size); cr_assert_not_null(p); - m = memtype_managed_init(p, total_size); + m = memory_managed(p, total_size); cr_assert_not_null(m); p1 = memory_alloc(m, 16); @@ -74,7 +82,7 @@ Test(memory, manager) { p2 = memory_alloc(m, 32); cr_assert_not_null(p2); - ret = memory_free(m, p1, 16); + ret = memory_free(p1); cr_assert(ret == 0); p1 = memory_alloc_aligned(m, 128, 128); @@ -85,21 +93,21 @@ Test(memory, manager) { cr_assert(p3); cr_assert(IS_ALIGNED(p3, 256)); - ret = memory_free(m, p2, 32); + ret = memory_free(p2); cr_assert(ret == 0); - ret = memory_free(m, p1, 128); + ret = memory_free(p1); cr_assert(ret == 0); - ret = memory_free(m, p3, 128); + ret = memory_free(p3); cr_assert(ret == 0); p1 = memory_alloc(m, max_block); cr_assert_not_null(p1); - ret = memory_free(m, p1, max_block); + ret = memory_free(p1); cr_assert(ret == 0); - ret = memory_free(&memtype_heap, p, total_size); + ret = memory_free(p); cr_assert(ret == 0); } diff --git a/tests/unit/pool.c b/tests/unit/pool.c index d2ef6160a..e2958185a 100644 --- a/tests/unit/pool.c +++ b/tests/unit/pool.c @@ -32,16 +32,16 @@ struct param { int thread_count; int pool_size; size_t block_size; - struct memtype *memtype; + struct memory_type *memory_type; }; ParameterizedTestParameters(pool, basic) { static struct param params[] = { - { 1, 4096, 150, &memtype_heap }, - { 1, 128, 8, &memtype_hugepage }, - { 1, 4, 8192, &memtype_hugepage }, - { 1, 1 << 13, 4, &memtype_heap } + { 1, 4096, 150, &memory_type_heap }, + { 1, 128, 8, &memory_hugepage }, + { 1, 4, 8192, &memory_hugepage }, + { 1, 1 << 13, 4, &memory_type_heap } }; return cr_make_param_array(struct param, params, ARRAY_LEN(params)); @@ -54,7 +54,7 @@ ParameterizedTest(struct param *p, pool, basic) void *ptr, *ptrs[p->pool_size]; - ret = pool_init(&pool, p->pool_size, p->block_size, p->memtype); + ret = pool_init(&pool, p->pool_size, p->block_size, p->memory_type); cr_assert_eq(ret, 0, "Failed to create pool"); ptr = pool_get(&pool); diff --git a/tests/unit/queue.c b/tests/unit/queue.c index fad646c11..dca93f12d 100644 --- a/tests/unit/queue.c +++ b/tests/unit/queue.c @@ -51,7 +51,7 @@ struct param { int batch_size; void * (*thread_func)(void *); struct queue queue; - const struct memtype *memtype; + const struct memory_type *memory_type; }; /** Get thread id as integer @@ -243,7 +243,7 @@ Test(queue, single_threaded) .start = 1 /* we start immeadiatly */ }; - ret = queue_init(&p.queue, p.queue_size, &memtype_heap); + ret = queue_init(&p.queue, p.queue_size, &memory_type_heap); cr_assert_eq(ret, 0, "Failed to create queue"); producer(&p); @@ -265,35 +265,35 @@ ParameterizedTestParameters(queue, multi_threaded) .thread_count = 32, .thread_func = producer_consumer_many, .batch_size = 10, - .memtype = &memtype_heap + .memory_type = &memory_type_heap }, { .iter_count = 1 << 8, .queue_size = 1 << 9, .thread_count = 4, .thread_func = producer_consumer_many, .batch_size = 100, - .memtype = &memtype_heap + .memory_type = &memory_type_heap }, { .iter_count = 1 << 16, .queue_size = 1 << 14, .thread_count = 16, .thread_func = producer_consumer_many, .batch_size = 100, - .memtype = &memtype_heap + .memory_type = &memory_type_heap }, { .iter_count = 1 << 8, .queue_size = 1 << 9, .thread_count = 4, .thread_func = producer_consumer_many, .batch_size = 10, - .memtype = &memtype_heap + .memory_type = &memory_type_heap }, { .iter_count = 1 << 16, .queue_size = 1 << 9, .thread_count = 16, .thread_func = producer_consumer, .batch_size = 10, - .memtype = &memtype_hugepage + .memory_type = &memory_hugepage } }; @@ -308,7 +308,7 @@ ParameterizedTest(struct param *p, queue, multi_threaded, .timeout = 20) p->start = 0; - ret = queue_init(&p->queue, p->queue_size, &memtype_heap); + ret = queue_init(&p->queue, p->queue_size, &memory_type_heap); cr_assert_eq(ret, 0, "Failed to create queue"); uint64_t start_tsc_time, end_tsc_time; @@ -350,7 +350,7 @@ Test(queue, init_destroy) int ret; struct queue q = { .state = STATE_DESTROYED }; - ret = queue_init(&q, 1024, &memtype_heap); + ret = queue_init(&q, 1024, &memory_type_heap); cr_assert_eq(ret, 0); /* Should succeed */ ret = queue_destroy(&q); diff --git a/tests/unit/queue_signalled.c b/tests/unit/queue_signalled.c index 0acf8d1ea..030ef9117 100644 --- a/tests/unit/queue_signalled.c +++ b/tests/unit/queue_signalled.c @@ -132,7 +132,7 @@ ParameterizedTest(struct param *param, queue_signalled, simple, .timeout = 5) pthread_t t1, t2; - ret = queue_signalled_init(&q, LOG2_CEIL(NUM_ELEM), &memtype_heap, param->flags); + ret = queue_signalled_init(&q, LOG2_CEIL(NUM_ELEM), &memory_type_heap, param->flags); cr_assert_eq(ret, 0, "Failed to initialize queue: flags=%#x, ret=%d", param->flags, ret); ret = pthread_create(&t1, NULL, producer, &q);