diff options
Diffstat (limited to 'perf/thirdparty')
| -rw-r--r-- | perf/thirdparty/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | perf/thirdparty/iniparser/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | perf/thirdparty/iniparser/dictionary.c | 383 | ||||
| -rw-r--r-- | perf/thirdparty/iniparser/dictionary.h | 170 | ||||
| -rw-r--r-- | perf/thirdparty/iniparser/iniparser.c | 949 | ||||
| -rw-r--r-- | perf/thirdparty/iniparser/iniparser.h | 446 | ||||
| -rw-r--r-- | perf/thirdparty/rmind_ringbuf/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | perf/thirdparty/rmind_ringbuf/ringbuf.c | 430 | ||||
| -rw-r--r-- | perf/thirdparty/rmind_ringbuf/ringbuf.h | 29 | ||||
| -rw-r--r-- | perf/thirdparty/rmind_ringbuf/utils.h | 115 |
10 files changed, 2542 insertions, 0 deletions
diff --git a/perf/thirdparty/CMakeLists.txt b/perf/thirdparty/CMakeLists.txt new file mode 100644 index 0000000..5ad8bd4 --- /dev/null +++ b/perf/thirdparty/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.0) +project(BBQ_THIRDPARTY) + +add_subdirectory(iniparser) +add_subdirectory(rmind_ringbuf) diff --git a/perf/thirdparty/iniparser/CMakeLists.txt b/perf/thirdparty/iniparser/CMakeLists.txt new file mode 100644 index 0000000..f24e1e8 --- /dev/null +++ b/perf/thirdparty/iniparser/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.0) +project(INIPARSER) + +file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.c) #搜索当前cmake所在目录下的c文件 +set(LIBRARY_OUTPUT_PATH ${LIB_PATH}) #设置库生成目录 + +add_library(iniparser STATIC ${SRC_LIST}) #生成静态库 +# add_library(${BBQ_LIB} SHARED ${SRC_LIST}) #生成动态库
\ No newline at end of file diff --git a/perf/thirdparty/iniparser/dictionary.c b/perf/thirdparty/iniparser/dictionary.c new file mode 100644 index 0000000..85dfdc0 --- /dev/null +++ b/perf/thirdparty/iniparser/dictionary.c @@ -0,0 +1,383 @@ +/*-------------------------------------------------------------------------*/ +/** + @file dictionary.c + @author N. Devillard + @brief Implements a dictionary for string variables. + + This module implements a simple dictionary object, i.e. a list + of string/string associations. This object is useful to store e.g. + informations retrieved from a configuration file (ini files). +*/ +/*--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ +#include "dictionary.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/** Minimal allocated number of entries in a dictionary */ +#define DICTMINSZ 128 + +/*--------------------------------------------------------------------------- + Private functions + ---------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------*/ +/** + @brief Duplicate a string + @param s String to duplicate + @return Pointer to a newly allocated string, to be freed with free() + + This is a replacement for strdup(). This implementation is provided + for systems that do not have it. + */ +/*--------------------------------------------------------------------------*/ +static char * xstrdup(const char * s) +{ + char * t ; + size_t len ; + if (!s) + return NULL ; + + len = strlen(s) + 1 ; + t = (char*) malloc(len) ; + if (t) { + memcpy(t, s, len) ; + } + return t ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Double the size of the dictionary + @param d Dictionary to grow + @return This function returns non-zero in case of failure + */ +/*--------------------------------------------------------------------------*/ +static int dictionary_grow(dictionary * d) +{ + char ** new_val ; + char ** new_key ; + unsigned * new_hash ; + + new_val = (char**) calloc(d->size * 2, sizeof *d->val); + new_key = (char**) calloc(d->size * 2, sizeof *d->key); + new_hash = (unsigned*) calloc(d->size * 2, sizeof *d->hash); + if (!new_val || !new_key || !new_hash) { + /* An allocation failed, leave the dictionary unchanged */ + if (new_val) + free(new_val); + if (new_key) + free(new_key); + if (new_hash) + free(new_hash); + return -1 ; + } + /* Initialize the newly allocated space */ + memcpy(new_val, d->val, d->size * sizeof(char *)); + memcpy(new_key, d->key, d->size * sizeof(char *)); + memcpy(new_hash, d->hash, d->size * sizeof(unsigned)); + /* Delete previous data */ + free(d->val); + free(d->key); + free(d->hash); + /* Actually update the dictionary */ + d->size *= 2 ; + d->val = new_val; + d->key = new_key; + d->hash = new_hash; + return 0 ; +} + +/*--------------------------------------------------------------------------- + Function codes + ---------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +/** + @brief Compute the hash key for a string. + @param key Character string to use for key. + @return 1 unsigned int on at least 32 bits. + + This hash function has been taken from an Article in Dr Dobbs Journal. + This is normally a collision-free function, distributing keys evenly. + The key is stored anyway in the struct so that collision can be avoided + by comparing the key itself in last resort. + */ +/*--------------------------------------------------------------------------*/ +unsigned dictionary_hash(const char * key) +{ + size_t len ; + unsigned hash ; + size_t i ; + + if (!key) + return 0 ; + + len = strlen(key); + for (hash=0, i=0 ; i<len ; i++) { + hash += (unsigned)key[i] ; + hash += (hash<<10); + hash ^= (hash>>6) ; + } + hash += (hash <<3); + hash ^= (hash >>11); + hash += (hash <<15); + return hash ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Create a new dictionary object. + @param size Optional initial size of the dictionary. + @return 1 newly allocated dictionary object. + + This function allocates a new dictionary object of given size and returns + it. If you do not know in advance (roughly) the number of entries in the + dictionary, give size=0. + */ +/*-------------------------------------------------------------------------*/ +dictionary * dictionary_new(size_t size) +{ + dictionary * d ; + + /* If no size was specified, allocate space for DICTMINSZ */ + if (size<DICTMINSZ) size=DICTMINSZ ; + + d = (dictionary*) calloc(1, sizeof *d) ; + + if (d) { + d->size = size ; + d->val = (char**) calloc(size, sizeof *d->val); + d->key = (char**) calloc(size, sizeof *d->key); + d->hash = (unsigned*) calloc(size, sizeof *d->hash); + if (!d->size || !d->val || !d->hash) { + free((void *) d->size); + free((void *) d->val); + free((void *) d->hash); + free(d); + d = NULL; + } + } + return d ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a dictionary object + @param d dictionary object to deallocate. + @return void + + Deallocate a dictionary object and all memory associated to it. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_del(dictionary * d) +{ + size_t i ; + + if (d==NULL) return ; + for (i=0 ; i<d->size ; i++) { + if (d->key[i]!=NULL) + free(d->key[i]); + if (d->val[i]!=NULL) + free(d->val[i]); + } + free(d->val); + free(d->key); + free(d->hash); + free(d); + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get a value from a dictionary. + @param d dictionary object to search. + @param key Key to look for in the dictionary. + @param def Default value to return if key not found. + @return 1 pointer to internally allocated character string. + + This function locates a key in a dictionary and returns a pointer to its + value, or the passed 'def' pointer if no such key can be found in + dictionary. The returned character pointer points to data internal to the + dictionary object, you should not try to free it or modify it. + */ +/*--------------------------------------------------------------------------*/ +const char * dictionary_get(const dictionary * d, const char * key, const char * def) +{ + unsigned hash ; + size_t i ; + + if(d == NULL || key == NULL) + return def ; + + hash = dictionary_hash(key); + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + /* Compare hash */ + if (hash==d->hash[i]) { + /* Compare string, to avoid hash collisions */ + if (!strcmp(key, d->key[i])) { + return d->val[i] ; + } + } + } + return def ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Set a value in a dictionary. + @param d dictionary object to modify. + @param key Key to modify or add. + @param val Value to add. + @return int 0 if Ok, anything else otherwise + + If the given key is found in the dictionary, the associated value is + replaced by the provided one. If the key cannot be found in the + dictionary, it is added to it. + + It is Ok to provide a NULL value for val, but NULL values for the dictionary + or the key are considered as errors: the function will return immediately + in such a case. + + Notice that if you dictionary_set a variable to NULL, a call to + dictionary_get will return a NULL value: the variable will be found, and + its value (NULL) is returned. In other words, setting the variable + content to NULL is equivalent to deleting the variable from the + dictionary. It is not possible (in this implementation) to have a key in + the dictionary without value. + + This function returns non-zero in case of failure. + */ +/*--------------------------------------------------------------------------*/ +int dictionary_set(dictionary * d, const char * key, const char * val) +{ + size_t i ; + unsigned hash ; + + if (d==NULL || key==NULL) return -1 ; + + /* Compute hash for this key */ + hash = dictionary_hash(key) ; + /* Find if value is already in dictionary */ + if (d->n>0) { + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + if (hash==d->hash[i]) { /* Same hash value */ + if (!strcmp(key, d->key[i])) { /* Same key */ + /* Found a value: modify and return */ + if (d->val[i]!=NULL) + free(d->val[i]); + d->val[i] = (val ? xstrdup(val) : NULL); + /* Value has been modified: return */ + return 0 ; + } + } + } + } + /* Add a new value */ + /* See if dictionary needs to grow */ + if (d->n==d->size) { + /* Reached maximum size: reallocate dictionary */ + if (dictionary_grow(d) != 0) + return -1; + } + + /* Insert key in the first empty slot. Start at d->n and wrap at + d->size. Because d->n < d->size this will necessarily + terminate. */ + for (i=d->n ; d->key[i] ; ) { + if(++i == d->size) i = 0; + } + /* Copy key */ + d->key[i] = xstrdup(key); + d->val[i] = (val ? xstrdup(val) : NULL) ; + d->hash[i] = hash; + d->n ++ ; + return 0 ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a key in a dictionary + @param d dictionary object to modify. + @param key Key to remove. + @return void + + This function deletes a key in a dictionary. Nothing is done if the + key cannot be found. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_unset(dictionary * d, const char * key) +{ + unsigned hash ; + size_t i ; + + if (key == NULL || d == NULL) { + return; + } + + hash = dictionary_hash(key); + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + /* Compare hash */ + if (hash==d->hash[i]) { + /* Compare string, to avoid hash collisions */ + if (!strcmp(key, d->key[i])) { + /* Found key */ + break ; + } + } + } + if (i>=d->size) + /* Key not found */ + return ; + + free(d->key[i]); + d->key[i] = NULL ; + if (d->val[i]!=NULL) { + free(d->val[i]); + d->val[i] = NULL ; + } + d->hash[i] = 0 ; + d->n -- ; + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump + @param f Opened file pointer. + @return void + + Dumps a dictionary onto an opened file pointer. Key pairs are printed out + as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as + output file pointers. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_dump(const dictionary * d, FILE * out) +{ + size_t i ; + + if (d==NULL || out==NULL) return ; + if (d->n<1) { + fprintf(out, "empty dictionary\n"); + return ; + } + for (i=0 ; i<d->size ; i++) { + if (d->key[i]) { + fprintf(out, "%20s\t[%s]\n", + d->key[i], + d->val[i] ? d->val[i] : "UNDEF"); + } + } + return ; +} diff --git a/perf/thirdparty/iniparser/dictionary.h b/perf/thirdparty/iniparser/dictionary.h new file mode 100644 index 0000000..f459cfe --- /dev/null +++ b/perf/thirdparty/iniparser/dictionary.h @@ -0,0 +1,170 @@ + +/*-------------------------------------------------------------------------*/ +/** + @file dictionary.h + @author N. Devillard + @brief Implements a dictionary for string variables. + + This module implements a simple dictionary object, i.e. a list + of string/string associations. This object is useful to store e.g. + informations retrieved from a configuration file (ini files). +*/ +/*--------------------------------------------------------------------------*/ + +#ifndef _DICTIONARY_H_ +#define _DICTIONARY_H_ + +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ + +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + New types + ---------------------------------------------------------------------------*/ + + +/*-------------------------------------------------------------------------*/ +/** + @brief Dictionary object + + This object contains a list of string/string associations. Each + association is identified by a unique string key. Looking up values + in the dictionary is speeded up by the use of a (hopefully collision-free) + hash function. + */ +/*-------------------------------------------------------------------------*/ +typedef struct _dictionary_ { + unsigned n ; /** Number of entries in dictionary */ + size_t size ; /** Storage size */ + char ** val ; /** List of string values */ + char ** key ; /** List of string keys */ + unsigned * hash ; /** List of hash values for keys */ +} dictionary ; + + +/*--------------------------------------------------------------------------- + Function prototypes + ---------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------*/ +/** + @brief Compute the hash key for a string. + @param key Character string to use for key. + @return 1 unsigned int on at least 32 bits. + + This hash function has been taken from an Article in Dr Dobbs Journal. + This is normally a collision-free function, distributing keys evenly. + The key is stored anyway in the struct so that collision can be avoided + by comparing the key itself in last resort. + */ +/*--------------------------------------------------------------------------*/ +unsigned dictionary_hash(const char * key); + +/*-------------------------------------------------------------------------*/ +/** + @brief Create a new dictionary object. + @param size Optional initial size of the dictionary. + @return 1 newly allocated dictionary object. + + This function allocates a new dictionary object of given size and returns + it. If you do not know in advance (roughly) the number of entries in the + dictionary, give size=0. + */ +/*--------------------------------------------------------------------------*/ +dictionary * dictionary_new(size_t size); + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a dictionary object + @param d dictionary object to deallocate. + @return void + + Deallocate a dictionary object and all memory associated to it. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_del(dictionary * vd); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get a value from a dictionary. + @param d dictionary object to search. + @param key Key to look for in the dictionary. + @param def Default value to return if key not found. + @return 1 pointer to internally allocated character string. + + This function locates a key in a dictionary and returns a pointer to its + value, or the passed 'def' pointer if no such key can be found in + dictionary. The returned character pointer points to data internal to the + dictionary object, you should not try to free it or modify it. + */ +/*--------------------------------------------------------------------------*/ +const char * dictionary_get(const dictionary * d, const char * key, const char * def); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Set a value in a dictionary. + @param d dictionary object to modify. + @param key Key to modify or add. + @param val Value to add. + @return int 0 if Ok, anything else otherwise + + If the given key is found in the dictionary, the associated value is + replaced by the provided one. If the key cannot be found in the + dictionary, it is added to it. + + It is Ok to provide a NULL value for val, but NULL values for the dictionary + or the key are considered as errors: the function will return immediately + in such a case. + + Notice that if you dictionary_set a variable to NULL, a call to + dictionary_get will return a NULL value: the variable will be found, and + its value (NULL) is returned. In other words, setting the variable + content to NULL is equivalent to deleting the variable from the + dictionary. It is not possible (in this implementation) to have a key in + the dictionary without value. + + This function returns non-zero in case of failure. + */ +/*--------------------------------------------------------------------------*/ +int dictionary_set(dictionary * vd, const char * key, const char * val); + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete a key in a dictionary + @param d dictionary object to modify. + @param key Key to remove. + @return void + + This function deletes a key in a dictionary. Nothing is done if the + key cannot be found. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_unset(dictionary * d, const char * key); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump + @param f Opened file pointer. + @return void + + Dumps a dictionary onto an opened file pointer. Key pairs are printed out + as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as + output file pointers. + */ +/*--------------------------------------------------------------------------*/ +void dictionary_dump(const dictionary * d, FILE * out); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/perf/thirdparty/iniparser/iniparser.c b/perf/thirdparty/iniparser/iniparser.c new file mode 100644 index 0000000..4cffb96 --- /dev/null +++ b/perf/thirdparty/iniparser/iniparser.c @@ -0,0 +1,949 @@ + +/*-------------------------------------------------------------------------*/ +/** + @file iniparser.c + @author N. Devillard + @brief Parser for ini files. +*/ +/*--------------------------------------------------------------------------*/ +/*---------------------------- Includes ------------------------------------*/ +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include "iniparser.h" + +/*---------------------------- Defines -------------------------------------*/ +#define ASCIILINESZ (1024) +#define INI_INVALID_KEY ((char*)-1) + +/*--------------------------------------------------------------------------- + Private to this module + ---------------------------------------------------------------------------*/ +/** + * This enum stores the status for each parsed line (internal use only). + */ +typedef enum _line_status_ { + LINE_UNPROCESSED, + LINE_ERROR, + LINE_EMPTY, + LINE_COMMENT, + LINE_SECTION, + LINE_VALUE +} line_status ; + +/*-------------------------------------------------------------------------*/ +/** + @brief Convert a string to lowercase. + @param in String to convert. + @param out Output buffer. + @param len Size of the out buffer. + @return ptr to the out buffer or NULL if an error occured. + + This function convert a string into lowercase. + At most len - 1 elements of the input string will be converted. + */ +/*--------------------------------------------------------------------------*/ +static const char * strlwc(const char * in, char *out, unsigned len) +{ + unsigned i ; + + if (in==NULL || out == NULL || len==0) return NULL ; + i=0 ; + while (in[i] != '\0' && i < len-1) { + out[i] = (char)tolower((int)in[i]); + i++ ; + } + out[i] = '\0'; + return out ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Duplicate a string + @param s String to duplicate + @return Pointer to a newly allocated string, to be freed with free() + + This is a replacement for strdup(). This implementation is provided + for systems that do not have it. + */ +/*--------------------------------------------------------------------------*/ +static char * xstrdup(const char * s) +{ + char * t ; + size_t len ; + if (!s) + return NULL ; + + len = strlen(s) + 1 ; + t = (char*) malloc(len) ; + if (t) { + memcpy(t, s, len) ; + } + return t ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Remove blanks at the beginning and the end of a string. + @param str String to parse and alter. + @return unsigned New size of the string. + */ +/*--------------------------------------------------------------------------*/ +static unsigned strstrip(char * s) +{ + char *last = NULL ; + char *dest = s; + + if (s==NULL) return 0; + + last = s + strlen(s); + while (isspace((int)*s) && *s) s++; + while (last > s) { + if (!isspace((int)*(last-1))) + break ; + last -- ; + } + *last = (char)0; + + memmove(dest,s,last - s + 1); + return last - s; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Default error callback for iniparser: wraps `fprintf(stderr, ...)`. + */ +/*--------------------------------------------------------------------------*/ +static int default_error_callback(const char *format, ...) +{ + int ret; + va_list argptr; + va_start(argptr, format); + ret = vfprintf(stderr, format, argptr); + va_end(argptr); + return ret; +} + +static int (*iniparser_error_callback)(const char*, ...) = default_error_callback; + +/*-------------------------------------------------------------------------*/ +/** + @brief Configure a function to receive the error messages. + @param errback Function to call. + + By default, the error will be printed on stderr. If a null pointer is passed + as errback the error callback will be switched back to default. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_set_error_callback(int (*errback)(const char *, ...)) +{ + if (errback) { + iniparser_error_callback = errback; + } else { + iniparser_error_callback = default_error_callback; + } +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get number of sections in a dictionary + @param d Dictionary to examine + @return int Number of sections found in dictionary + + This function returns the number of sections found in a dictionary. + The test to recognize sections is done on the string stored in the + dictionary: a section name is given as "section" whereas a key is + stored as "section:key", thus the test looks for entries that do not + contain a colon. + + This clearly fails in the case a section name contains a colon, but + this should simply be avoided. + + This function returns -1 in case of error. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getnsec(const dictionary * d) +{ + size_t i ; + int nsec ; + + if (d==NULL) return -1 ; + nsec=0 ; + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + if (strchr(d->key[i], ':')==NULL) { + nsec ++ ; + } + } + return nsec ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get name for section n in a dictionary. + @param d Dictionary to examine + @param n Section number (from 0 to nsec-1). + @return Pointer to char string + + This function locates the n-th section in a dictionary and returns + its name as a pointer to a string statically allocated inside the + dictionary. Do not free or modify the returned string! + + This function returns NULL in case of error. + */ +/*--------------------------------------------------------------------------*/ +const char * iniparser_getsecname(const dictionary * d, int n) +{ + size_t i ; + int foundsec ; + + if (d==NULL || n<0) return NULL ; + foundsec=0 ; + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + if (strchr(d->key[i], ':')==NULL) { + foundsec++ ; + if (foundsec>n) + break ; + } + } + if (foundsec<=n) { + return NULL ; + } + return d->key[i] ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump. + @param f Opened file pointer to dump to. + @return void + + This function prints out the contents of a dictionary, one element by + line, onto the provided file pointer. It is OK to specify @c stderr + or @c stdout as output files. This function is meant for debugging + purposes mostly. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_dump(const dictionary * d, FILE * f) +{ + size_t i ; + + if (d==NULL || f==NULL) return ; + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + if (d->val[i]!=NULL) { + fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); + } else { + fprintf(f, "[%s]=UNDEF\n", d->key[i]); + } + } + return ; +} + +static void escape_value(char *escaped, char *value) { + char c; + int v = 0; + int e = 0; + + if(!escaped || !value) + return; + + while((c = value[v]) != '\0') { + if(c == '\\' || c == '"') { + escaped[e] = '\\'; + e++; + } + escaped[e] = c; + v++; + e++; + } + escaped[e] = '\0'; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary to a loadable ini file + @param d Dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given dictionary into a loadable ini file. + It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_dump_ini(const dictionary * d, FILE * f) +{ + size_t i ; + size_t nsec ; + const char * secname ; + char escaped[ASCIILINESZ+1] = ""; + + if (d==NULL || f==NULL) return ; + + nsec = iniparser_getnsec(d); + if (nsec<1) { + /* No section in file: dump all keys as they are */ + for (i=0 ; i<d->size ; i++) { + if (d->key[i]==NULL) + continue ; + escape_value(escaped, d->val[i]); + fprintf(f, "%s = \"%s\"\n", d->key[i], escaped); + } + return ; + } + for (i=0 ; i<nsec ; i++) { + secname = iniparser_getsecname(d, i) ; + iniparser_dumpsection_ini(d, secname, f); + } + fprintf(f, "\n"); + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary section to a loadable ini file + @param d Dictionary to dump + @param s Section name of dictionary to dump + @param f Opened file pointer to dump to + @return void + + This function dumps a given section of a given dictionary into a loadable ini + file. It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f) +{ + size_t j ; + char keym[ASCIILINESZ+1]; + int seclen ; + char escaped[ASCIILINESZ+1] = ""; + + if (d==NULL || f==NULL) return ; + if (! iniparser_find_entry(d, s)) return ; + + seclen = (int)strlen(s); + fprintf(f, "\n[%s]\n", s); + sprintf(keym, "%s:", s); + for (j=0 ; j<d->size ; j++) { + if (d->key[j]==NULL) + continue ; + if (!strncmp(d->key[j], keym, seclen+1)) { + escape_value(escaped, d->val[j]); + fprintf(f, "%-30s = \"%s\"\n", d->key[j]+seclen+1, escaped); + } + } + fprintf(f, "\n"); + return ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @return Number of keys in section + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getsecnkeys(const dictionary * d, const char * s) +{ + int seclen, nkeys ; + char keym[ASCIILINESZ+1]; + size_t j ; + + nkeys = 0; + + if (d==NULL) return nkeys; + if (! iniparser_find_entry(d, s)) return nkeys; + + seclen = (int)strlen(s); + strlwc(s, keym, sizeof(keym)); + keym[seclen] = ':'; + + for (j=0 ; j<d->size ; j++) { + if (d->key[j]==NULL) + continue ; + if (!strncmp(d->key[j], keym, seclen+1)) + nkeys++; + } + + return nkeys; + +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @param keys Already allocated array to store the keys in + @return The pointer passed as `keys` argument or NULL in case of error + + This function queries a dictionary and finds all keys in a given section. + The keys argument should be an array of pointers which size has been + determined by calling `iniparser_getsecnkeys` function prior to this one. + + Each pointer in the returned char pointer-to-pointer is pointing to + a string allocated in the dictionary; do not free or modify them. + */ +/*--------------------------------------------------------------------------*/ +const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys) +{ + size_t i, j, seclen ; + char keym[ASCIILINESZ+1]; + + if (d==NULL || keys==NULL) return NULL; + if (! iniparser_find_entry(d, s)) return NULL; + + seclen = strlen(s); + strlwc(s, keym, sizeof(keym)); + keym[seclen] = ':'; + + i = 0; + + for (j=0 ; j<d->size ; j++) { + if (d->key[j]==NULL) + continue ; + if (!strncmp(d->key[j], keym, seclen+1)) { + keys[i] = d->key[j]; + i++; + } + } + + return keys; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key + @param d Dictionary to search + @param key Key string to look for + @param def Default value to return if key not found. + @return pointer to statically allocated character string + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the pointer passed as 'def' is returned. + The returned char pointer is pointing to a string allocated in + the dictionary, do not free or modify it. + */ +/*--------------------------------------------------------------------------*/ +const char * iniparser_getstring(const dictionary * d, const char * key, const char * def) +{ + const char * lc_key ; + const char * sval ; + char tmp_str[ASCIILINESZ+1]; + + if (d==NULL || key==NULL) + return def ; + + lc_key = strlwc(key, tmp_str, sizeof(tmp_str)); + sval = dictionary_get(d, lc_key, def); + return sval ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an long int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return long integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + "42" -> 42 + "042" -> 34 (octal -> decimal) + "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + + Credits: Thanks to A. Becker for suggesting strtol() + */ +/*--------------------------------------------------------------------------*/ +long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound) +{ + const char * str ; + + str = iniparser_getstring(d, key, INI_INVALID_KEY); + if (str==NULL || str==INI_INVALID_KEY) return notfound ; + return strtol(str, NULL, 0); +} + +int64_t iniparser_getint64(const dictionary * d, const char * key, int64_t notfound) +{ + const char * str ; + + str = iniparser_getstring(d, key, INI_INVALID_KEY); + if (str==NULL || str==INI_INVALID_KEY) return notfound ; + return strtoimax(str, NULL, 0); +} + +uint64_t iniparser_getuint64(const dictionary * d, const char * key, uint64_t notfound) +{ + const char * str ; + + str = iniparser_getstring(d, key, INI_INVALID_KEY); + if (str==NULL || str==INI_INVALID_KEY) return notfound ; + return strtoumax(str, NULL, 0); +} + + + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + "42" -> 42 + "042" -> 34 (octal -> decimal) + "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + + Credits: Thanks to A. Becker for suggesting strtol() + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getint(const dictionary * d, const char * key, int notfound) +{ + return (int)iniparser_getlongint(d, key, notfound); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a double + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return double + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + */ +/*--------------------------------------------------------------------------*/ +double iniparser_getdouble(const dictionary * d, const char * key, double notfound) +{ + const char * str ; + + str = iniparser_getstring(d, key, INI_INVALID_KEY); + if (str==NULL || str==INI_INVALID_KEY) return notfound ; + return atof(str); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a boolean + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + A true boolean is found if one of the following is matched: + + - A string starting with 'y' + - A string starting with 'Y' + - A string starting with 't' + - A string starting with 'T' + - A string starting with '1' + + A false boolean is found if one of the following is matched: + + - A string starting with 'n' + - A string starting with 'N' + - A string starting with 'f' + - A string starting with 'F' + - A string starting with '0' + + The notfound value returned if no boolean is identified, does not + necessarily have to be 0 or 1. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getboolean(const dictionary * d, const char * key, int notfound) +{ + int ret ; + const char * c ; + + c = iniparser_getstring(d, key, INI_INVALID_KEY); + if (c==NULL || c==INI_INVALID_KEY) return notfound ; + if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { + ret = 1 ; + } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { + ret = 0 ; + } else { + ret = notfound ; + } + return ret; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Finds out if a given entry exists in a dictionary + @param ini Dictionary to search + @param entry Name of the entry to look for + @return integer 1 if entry exists, 0 otherwise + + Finds out if a given entry exists in the dictionary. Since sections + are stored as keys with NULL associated values, this is the only way + of querying for the presence of sections in a dictionary. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_find_entry(const dictionary * ini, const char * entry) +{ + int found=0 ; + if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { + found = 1 ; + } + return found ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Set an entry in a dictionary. + @param ini Dictionary to modify. + @param entry Entry to modify (entry name) + @param val New value to associate to the entry. + @return int 0 if Ok, -1 otherwise. + + If the given entry can be found in the dictionary, it is modified to + contain the provided value. If it cannot be found, the entry is created. + It is Ok to set val to NULL. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_set(dictionary * ini, const char * entry, const char * val) +{ + char tmp_str[ASCIILINESZ+1]; + return dictionary_set(ini, strlwc(entry, tmp_str, sizeof(tmp_str)), val) ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete an entry in a dictionary + @param ini Dictionary to modify + @param entry Entry to delete (entry name) + @return void + + If the given entry can be found, it is deleted from the dictionary. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_unset(dictionary * ini, const char * entry) +{ + char tmp_str[ASCIILINESZ+1]; + dictionary_unset(ini, strlwc(entry, tmp_str, sizeof(tmp_str))); +} + +static void parse_quoted_value(char *value, char quote) { + char c; + char *quoted; + int q = 0, v = 0; + int esc = 0; + + if(!value) + return; + + quoted = xstrdup(value); + + if(!quoted) { + iniparser_error_callback("iniparser: memory allocation failure\n"); + goto end_of_value; + } + + while((c = quoted[q]) != '\0') { + if(!esc) { + if(c == '\\') { + esc = 1; + q++; + continue; + } + + if(c == quote) { + goto end_of_value; + } + } + esc = 0; + value[v] = c; + v++; + q++; + } +end_of_value: + value[v] = '\0'; + free(quoted); +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Load a single line from an INI file + @param input_line Input line, may be concatenated multi-line input + @param section Output space to store section + @param key Output space to store key + @param value Output space to store value + @return line_status value + */ +/*--------------------------------------------------------------------------*/ +static line_status iniparser_line( + const char * input_line, + char * section, + char * key, + char * value) +{ + line_status sta ; + char * line = NULL; + size_t len ; + int d_quote; + + line = xstrdup(input_line); + len = strstrip(line); + + sta = LINE_UNPROCESSED ; + if (len<1) { + /* Empty line */ + sta = LINE_EMPTY ; + } else if (line[0]=='#' || line[0]==';') { + /* Comment line */ + sta = LINE_COMMENT ; + } else if (line[0]=='[' && line[len-1]==']') { + /* Section name without opening square bracket */ + sscanf(line, "[%[^\n]", section); + len = strlen(section); + /* Section name without closing square bracket */ + if(section[len-1] == ']') + { + section[len-1] = '\0'; + } + strstrip(section); + strlwc(section, section, len); + sta = LINE_SECTION ; + } else if ((d_quote = sscanf (line, "%[^=] = \"%[^\n]\"", key, value)) == 2 + || sscanf (line, "%[^=] = '%[^\n]'", key, value) == 2) { + /* Usual key=value with quotes, with or without comments */ + strstrip(key); + strlwc(key, key, len); + if(d_quote == 2) + parse_quoted_value(value, '"'); + else + parse_quoted_value(value, '\''); + /* Don't strip spaces from values surrounded with quotes */ + sta = LINE_VALUE ; + } else if (sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { + /* Usual key=value without quotes, with or without comments */ + strstrip(key); + strlwc(key, key, len); + strstrip(value); + /* + * sscanf cannot handle '' or "" as empty values + * this is done here + */ + if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { + value[0]=0 ; + } + sta = LINE_VALUE ; + } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 + || sscanf(line, "%[^=] %[=]", key, value) == 2) { + /* + * Special cases: + * key= + * key=; + * key=# + */ + strstrip(key); + strlwc(key, key, len); + value[0]=0 ; + sta = LINE_VALUE ; + } else { + /* Generate syntax error */ + sta = LINE_ERROR ; + } + + free(line); + return sta ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Parse an ini file and return an allocated dictionary object + @param in File to read. + @param ininame Name of the ini file to read (only used for nicer error messages) + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the file to be read. It returns a dictionary object that should not + be accessed directly, but through accessor functions instead. + + The returned dictionary must be freed using iniparser_freedict(). + */ +/*--------------------------------------------------------------------------*/ +dictionary * iniparser_load_file(FILE * in, const char * ininame) +{ + char line [ASCIILINESZ+1] ; + char section [ASCIILINESZ+1] ; + char key [ASCIILINESZ+1] ; + char tmp [(ASCIILINESZ * 2) + 2] ; + char val [ASCIILINESZ+1] ; + + int last=0 ; + int len ; + int lineno=0 ; + int errs=0; + int mem_err=0; + + dictionary * dict ; + + dict = dictionary_new(0) ; + if (!dict) { + return NULL ; + } + + memset(line, 0, ASCIILINESZ); + memset(section, 0, ASCIILINESZ); + memset(key, 0, ASCIILINESZ); + memset(val, 0, ASCIILINESZ); + last=0 ; + + while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { + lineno++ ; + len = (int)strlen(line)-1; + if (len<=0) + continue; + /* Safety check against buffer overflows */ + if (line[len]!='\n' && !feof(in)) { + iniparser_error_callback( + "iniparser: input line too long in %s (%d)\n", + ininame, + lineno); + dictionary_del(dict); + return NULL ; + } + /* Get rid of \n and spaces at end of line */ + while ((len>=0) && + ((line[len]=='\n') || (isspace(line[len])))) { + line[len]=0 ; + len-- ; + } + if (len < 0) { /* Line was entirely \n and/or spaces */ + len = 0; + } + /* Detect multi-line */ + if (line[len]=='\\') { + /* Multi-line value */ + last=len ; + continue ; + } else { + last=0 ; + } + switch (iniparser_line(line, section, key, val)) { + case LINE_EMPTY: + case LINE_COMMENT: + break ; + + case LINE_SECTION: + mem_err = dictionary_set(dict, section, NULL); + break ; + + case LINE_VALUE: + sprintf(tmp, "%s:%s", section, key); + mem_err = dictionary_set(dict, tmp, val); + break ; + + case LINE_ERROR: + iniparser_error_callback( + "iniparser: syntax error in %s (%d):\n-> %s\n", + ininame, + lineno, + line); + errs++ ; + break; + + default: + break ; + } + memset(line, 0, ASCIILINESZ); + last=0; + if (mem_err<0) { + iniparser_error_callback("iniparser: memory allocation failure\n"); + break ; + } + } + if (errs) { + dictionary_del(dict); + dict = NULL ; + } + return dict ; +} + +/*-------------------------------------------------------------------------*/ +/** + @brief Parse an ini file and return an allocated dictionary object + @param ininame Name of the ini file to read. + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the name of the file to be read. It returns a dictionary object that + should not be accessed directly, but through accessor functions + instead. + + The returned dictionary must be freed using iniparser_freedict(). + */ +/*--------------------------------------------------------------------------*/ +dictionary * iniparser_load(const char * ininame) +{ + FILE * in ; + dictionary * dict ; + + if ((in=fopen(ininame, "r"))==NULL) { + iniparser_error_callback("iniparser: cannot open %s\n", ininame); + return NULL ; + } + + dict = iniparser_load_file(in, ininame); + fclose(in); + + return dict ; +} + + +/*-------------------------------------------------------------------------*/ +/** + @brief Free all memory associated to an ini dictionary + @param d Dictionary to free + @return void + + Free all memory associated to an ini dictionary. + It is mandatory to call this function before the dictionary object + gets out of the current context. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_freedict(dictionary * d) +{ + dictionary_del(d); +} diff --git a/perf/thirdparty/iniparser/iniparser.h b/perf/thirdparty/iniparser/iniparser.h new file mode 100644 index 0000000..d8026a8 --- /dev/null +++ b/perf/thirdparty/iniparser/iniparser.h @@ -0,0 +1,446 @@ + +/*-------------------------------------------------------------------------*/ +/** + @file iniparser.h + @author N. Devillard + @brief Parser for ini files. +*/ +/*--------------------------------------------------------------------------*/ + +#ifndef _INIPARSER_H_ +#define _INIPARSER_H_ + +/*--------------------------------------------------------------------------- + Includes + ---------------------------------------------------------------------------*/ + +#include "dictionary.h" +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*/ +/** + @brief Configure a function to receive the error messages. + @param errback Function to call. + + By default, the error will be printed on stderr. If a null pointer is passed + as errback the error callback will be switched back to default. + */ +/*--------------------------------------------------------------------------*/ + +void iniparser_set_error_callback(int (*errback)(const char *, ...)); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get number of sections in a dictionary + @param d Dictionary to examine + @return int Number of sections found in dictionary + + This function returns the number of sections found in a dictionary. + The test to recognize sections is done on the string stored in the + dictionary: a section name is given as "section" whereas a key is + stored as "section:key", thus the test looks for entries that do not + contain a colon. + + This clearly fails in the case a section name contains a colon, but + this should simply be avoided. + + This function returns -1 in case of error. + */ +/*--------------------------------------------------------------------------*/ + +int iniparser_getnsec(const dictionary * d); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Get name for section n in a dictionary. + @param d Dictionary to examine + @param n Section number (from 0 to nsec-1). + @return Pointer to char string + + This function locates the n-th section in a dictionary and returns + its name as a pointer to a string statically allocated inside the + dictionary. Do not free or modify the returned string! + + This function returns NULL in case of error. + */ +/*--------------------------------------------------------------------------*/ + +const char * iniparser_getsecname(const dictionary * d, int n); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary to a loadable ini file + @param d Dictionary to dump + @param f Opened file pointer to dump to + + This function dumps a given dictionary into a loadable ini file. + It is Ok to specify @c stderr or @c stdout as output files. + + All values are quoted, these charecters are escaped: + + - ' : the quote character (e.g. "String with \"Quotes\"") + - \ : the backslash character (e.g. "C:\\tmp") + + */ +/*--------------------------------------------------------------------------*/ + +void iniparser_dump_ini(const dictionary * d, FILE * f); + +/*-------------------------------------------------------------------------*/ +/** + @brief Save a dictionary section to a loadable ini file + @param d Dictionary to dump + @param s Section name of dictionary to dump + @param f Opened file pointer to dump to + + This function dumps a given section of a given dictionary into a loadable ini + file. It is Ok to specify @c stderr or @c stdout as output files. + */ +/*--------------------------------------------------------------------------*/ + +void iniparser_dumpsection_ini(const dictionary * d, const char * s, FILE * f); + +/*-------------------------------------------------------------------------*/ +/** + @brief Dump a dictionary to an opened file pointer. + @param d Dictionary to dump. + @param f Opened file pointer to dump to. + + This function prints out the contents of a dictionary, one element by + line, onto the provided file pointer. It is OK to specify @c stderr + or @c stdout as output files. This function is meant for debugging + purposes mostly. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_dump(const dictionary * d, FILE * f); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @return Number of keys in section + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getsecnkeys(const dictionary * d, const char * s); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the number of keys in a section of a dictionary. + @param d Dictionary to examine + @param s Section name of dictionary to examine + @param keys Already allocated array to store the keys in + @return The pointer passed as `keys` argument or NULL in case of error + + This function queries a dictionary and finds all keys in a given section. + The keys argument should be an array of pointers which size has been + determined by calling `iniparser_getsecnkeys` function prior to this one. + + Each pointer in the returned char pointer-to-pointer is pointing to + a string allocated in the dictionary; do not free or modify them. + */ +/*--------------------------------------------------------------------------*/ +const char ** iniparser_getseckeys(const dictionary * d, const char * s, const char ** keys); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key + @param d Dictionary to search + @param key Key string to look for + @param def Default value to return if key not found. + @return pointer to statically allocated character string + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the pointer passed as 'def' is returned. + The returned char pointer is pointing to a string allocated in + the dictionary, do not free or modify it. + */ +/*--------------------------------------------------------------------------*/ +const char * iniparser_getstring(const dictionary * d, const char * key, const char * def); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + - "42" -> 42 + - "042" -> 34 (octal -> decimal) + - "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + + Credits: Thanks to A. Becker for suggesting strtol() + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getint(const dictionary * d, const char * key, int notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an long int + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + - "42" -> 42 + - "042" -> 34 (octal -> decimal) + - "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtol(), see the associated man page for overflow + handling. + */ +/*--------------------------------------------------------------------------*/ +long int iniparser_getlongint(const dictionary * d, const char * key, long int notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an int64_t + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + - "42" -> 42 + - "042" -> 34 (octal -> decimal) + - "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtoimax(), see the associated man page for overflow + handling. + + This function is usefull on 32bit architectures where `long int` is only + 32bit. + */ +/*--------------------------------------------------------------------------*/ +int64_t iniparser_getint64(const dictionary * d, const char * key, int64_t notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to an uint64_t + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + Supported values for integers include the usual C notation + so decimal, octal (starting with 0) and hexadecimal (starting with 0x) + are supported. Examples: + + - "42" -> 42 + - "042" -> 34 (octal -> decimal) + - "0x42" -> 66 (hexa -> decimal) + + Warning: the conversion may overflow in various ways. Conversion is + totally outsourced to strtoumax(), see the associated man page for overflow + handling. + + This function is usefull on 32bit architectures where `long int` is only + 32bit. + */ +/*--------------------------------------------------------------------------*/ +uint64_t iniparser_getuint64(const dictionary * d, const char * key, uint64_t notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a double + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return double + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + */ +/*--------------------------------------------------------------------------*/ +double iniparser_getdouble(const dictionary * d, const char * key, double notfound); + +/*-------------------------------------------------------------------------*/ +/** + @brief Get the string associated to a key, convert to a boolean + @param d Dictionary to search + @param key Key string to look for + @param notfound Value to return in case of error + @return integer + + This function queries a dictionary for a key. A key as read from an + ini file is given as "section:key". If the key cannot be found, + the notfound value is returned. + + A true boolean is found if one of the following is matched: + + - A string starting with 'y' + - A string starting with 'Y' + - A string starting with 't' + - A string starting with 'T' + - A string starting with '1' + + A false boolean is found if one of the following is matched: + + - A string starting with 'n' + - A string starting with 'N' + - A string starting with 'f' + - A string starting with 'F' + - A string starting with '0' + + The notfound value returned if no boolean is identified, does not + necessarily have to be 0 or 1. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_getboolean(const dictionary * d, const char * key, int notfound); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Set an entry in a dictionary. + @param ini Dictionary to modify. + @param entry Entry to modify (entry name) + @param val New value to associate to the entry. + @return int 0 if Ok, -1 otherwise. + + If the given entry can be found in the dictionary, it is modified to + contain the provided value. If it cannot be found, the entry is created. + It is Ok to set val to NULL. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_set(dictionary * ini, const char * entry, const char * val); + + +/*-------------------------------------------------------------------------*/ +/** + @brief Delete an entry in a dictionary + @param ini Dictionary to modify + @param entry Entry to delete (entry name) + + If the given entry can be found, it is deleted from the dictionary. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_unset(dictionary * ini, const char * entry); + +/*-------------------------------------------------------------------------*/ +/** + @brief Finds out if a given entry exists in a dictionary + @param ini Dictionary to search + @param entry Name of the entry to look for + @return integer 1 if entry exists, 0 otherwise + + Finds out if a given entry exists in the dictionary. Since sections + are stored as keys with NULL associated values, this is the only way + of querying for the presence of sections in a dictionary. + */ +/*--------------------------------------------------------------------------*/ +int iniparser_find_entry(const dictionary * ini, const char * entry) ; + +/*-------------------------------------------------------------------------*/ +/** + @brief Parse an ini file and return an allocated dictionary object + @param ininame Name of the ini file to read. + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the name of the file to be read. It returns a dictionary object that + should not be accessed directly, but through accessor functions + instead. + + Iff the value is a quoted string it supports some escape sequences: + + - \" or ' : the quote character + (e.g. 'String with "Quotes"' or "String with 'Quotes'") + - \ : the backslash character (e.g. "C:\tmp") + + Escape sequences always start with a backslash. Additional escape sequences + might be added in the future. Backslash characters must be escaped. Any other + sequence then those outlined above is invalid and may lead to unpredictable + results. + + The returned dictionary must be freed using iniparser_freedict(). + */ +/*--------------------------------------------------------------------------*/ +dictionary * iniparser_load(const char * ininame); + +/*-------------------------------------------------------------------------*/ +/** + @brief Parse an ini file and return an allocated dictionary object + @param in File to read. + @param ininame Name of the ini file to read (only used for nicer error messages) + @return Pointer to newly allocated dictionary + + This is the parser for ini files. This function is called, providing + the file to be read. It returns a dictionary object that should not + be accessed directly, but through accessor functions instead. + + Iff the value is a quoted string it supports some escape sequences: + + - \" or ' : the quote character + (e.g. 'String with "Quotes"' or "String with 'Quotes'") + - \ : the backslash character (e.g. "C:\tmp") + + Escape sequences always start with a backslash. Additional escape sequences + might be added in the future. Backslash characters must be escaped. Any other + sequence then those outlined above is invalid and may lead to unpredictable + results. + + The returned dictionary must be freed using iniparser_freedict(). + */ +/*--------------------------------------------------------------------------*/ +dictionary * iniparser_load_file(FILE * in, const char * ininame); + +/*-------------------------------------------------------------------------*/ +/** + @brief Free all memory associated to an ini dictionary + @param d Dictionary to free + + Free all memory associated to an ini dictionary. + It is mandatory to call this function before the dictionary object + gets out of the current context. + */ +/*--------------------------------------------------------------------------*/ +void iniparser_freedict(dictionary * d); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/perf/thirdparty/rmind_ringbuf/CMakeLists.txt b/perf/thirdparty/rmind_ringbuf/CMakeLists.txt new file mode 100644 index 0000000..7b65eaa --- /dev/null +++ b/perf/thirdparty/rmind_ringbuf/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.0) +project(RMIND_RINGBUF) + +file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.c) #搜索当前cmake所在目录下的c文件 +set(LIBRARY_OUTPUT_PATH ${LIB_PATH}) #设置库生成目录 + +add_library(rmind_ringbuf STATIC ${SRC_LIST}) #生成静态库
\ No newline at end of file diff --git a/perf/thirdparty/rmind_ringbuf/ringbuf.c b/perf/thirdparty/rmind_ringbuf/ringbuf.c new file mode 100644 index 0000000..75cfee9 --- /dev/null +++ b/perf/thirdparty/rmind_ringbuf/ringbuf.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2016-2017 Mindaugas Rasiukevicius <rmind at noxt eu> + * All rights reserved. + * + * Use is subject to license terms, as specified in the LICENSE file. + */ + +/* + * Atomic multi-producer single-consumer ring buffer, which supports + * contiguous range operations and which can be conveniently used for + * message passing. + * + * There are three offsets -- think of clock hands: + * - NEXT: marks the beginning of the available space, + * - WRITTEN: the point up to which the data is actually written. + * - Observed READY: point up to which data is ready to be written. + * + * Producers + * + * Observe and save the 'next' offset, then request N bytes from + * the ring buffer by atomically advancing the 'next' offset. Once + * the data is written into the "reserved" buffer space, the thread + * clears the saved value; these observed values are used to compute + * the 'ready' offset. + * + * Consumer + * + * Writes the data between 'written' and 'ready' offsets and updates + * the 'written' value. The consumer thread scans for the lowest + * seen value by the producers. + * + * Key invariant + * + * Producers cannot go beyond the 'written' offset; producers are + * also not allowed to catch up with the consumer. Only the consumer + * is allowed to catch up with the producer i.e. set the 'written' + * offset to be equal to the 'next' offset. + * + * Wrap-around + * + * If the producer cannot acquire the requested length due to little + * available space at the end of the buffer, then it will wraparound. + * WRAP_LOCK_BIT in 'next' offset is used to lock the 'end' offset. + * + * There is an ABA problem if one producer stalls while a pair of + * producer and consumer would both successfully wrap-around and set + * the 'next' offset to the stale value of the first producer, thus + * letting it to perform a successful CAS violating the invariant. + * A counter in the 'next' offset (masked by WRAP_COUNTER) is used + * to prevent from this problem. It is incremented on wraparounds. + * + * The same ABA problem could also cause a stale 'ready' offset, + * which could be observed by the consumer. We set WRAP_LOCK_BIT in + * the 'seen' value before advancing the 'next' and clear this bit + * after the successful advancing; this ensures that only the stable + * 'ready' is observed by the consumer. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdbool.h> +#include <inttypes.h> +#include <string.h> +#include <limits.h> +#include <errno.h> + +#include "ringbuf.h" +#include "utils.h" + +#define RBUF_OFF_MASK (0x00000000ffffffffUL) +#define WRAP_LOCK_BIT (0x8000000000000000UL) +#define RBUF_OFF_MAX (UINT64_MAX & ~WRAP_LOCK_BIT) + +#define WRAP_COUNTER (0x7fffffff00000000UL) +#define WRAP_INCR(x) (((x) + 0x100000000UL) & WRAP_COUNTER) + +typedef uint64_t ringbuf_off_t; + +struct ringbuf_worker { + volatile ringbuf_off_t seen_off; + int registered; +}; + +struct ringbuf { + /* Ring buffer space. */ + size_t space; + + /* + * The NEXT hand is atomically updated by the producer. + * WRAP_LOCK_BIT is set in case of wrap-around; in such case, + * the producer can update the 'end' offset. + */ + volatile ringbuf_off_t next; + ringbuf_off_t end; + + /* The following are updated by the consumer. */ + ringbuf_off_t written; + unsigned nworkers; + ringbuf_worker_t workers[]; +}; + +/* + * ringbuf_setup: initialise a new ring buffer of a given length. + */ +int +ringbuf_setup(ringbuf_t *rbuf, unsigned nworkers, size_t length) +{ + if (length >= RBUF_OFF_MASK) { + errno = EINVAL; + return -1; + } + memset(rbuf, 0, offsetof(ringbuf_t, workers[nworkers])); + rbuf->space = length; + rbuf->end = RBUF_OFF_MAX; + rbuf->nworkers = nworkers; + return 0; +} + +/* + * ringbuf_get_sizes: return the sizes of the ringbuf_t and ringbuf_worker_t. + */ +void +ringbuf_get_sizes(unsigned nworkers, + size_t *ringbuf_size, size_t *ringbuf_worker_size) +{ + if (ringbuf_size) + *ringbuf_size = offsetof(ringbuf_t, workers[nworkers]); + if (ringbuf_worker_size) + *ringbuf_worker_size = sizeof(ringbuf_worker_t); +} + +/* + * ringbuf_register: register the worker (thread/process) as a producer + * and pass the pointer to its local store. + */ +ringbuf_worker_t * +ringbuf_register(ringbuf_t *rbuf, unsigned i) +{ + ringbuf_worker_t *w = &rbuf->workers[i]; + + w->seen_off = RBUF_OFF_MAX; + atomic_store_explicit(&w->registered, true, memory_order_release); + return w; +} + +void +ringbuf_unregister(ringbuf_t *rbuf, ringbuf_worker_t *w) +{ + w->registered = false; + (void)rbuf; +} + +/* + * stable_nextoff: capture and return a stable value of the 'next' offset. + */ +static inline ringbuf_off_t +stable_nextoff(ringbuf_t *rbuf) +{ + unsigned count = SPINLOCK_BACKOFF_MIN; + ringbuf_off_t next; +retry: + next = atomic_load_explicit(&rbuf->next, memory_order_acquire); + if (next & WRAP_LOCK_BIT) { + SPINLOCK_BACKOFF(count); + goto retry; + } + ASSERT((next & RBUF_OFF_MASK) < rbuf->space); + return next; +} + +/* + * stable_seenoff: capture and return a stable value of the 'seen' offset. + */ +static inline ringbuf_off_t +stable_seenoff(ringbuf_worker_t *w) +{ + unsigned count = SPINLOCK_BACKOFF_MIN; + ringbuf_off_t seen_off; +retry: + seen_off = atomic_load_explicit(&w->seen_off, memory_order_acquire); + if (seen_off & WRAP_LOCK_BIT) { + SPINLOCK_BACKOFF(count); + goto retry; + } + return seen_off; +} + +/* + * ringbuf_acquire: request a space of a given length in the ring buffer. + * + * => On success: returns the offset at which the space is available. + * => On failure: returns -1. + */ +ssize_t +ringbuf_acquire(ringbuf_t *rbuf, ringbuf_worker_t *w, size_t len) +{ + ringbuf_off_t seen, next, target; + + ASSERT(len > 0 && len <= rbuf->space); + ASSERT(w->seen_off == RBUF_OFF_MAX); + + do { + ringbuf_off_t written; + + /* + * Get the stable 'next' offset. Save the observed 'next' + * value (i.e. the 'seen' offset), but mark the value as + * unstable (set WRAP_LOCK_BIT). + * + * Note: CAS will issue a memory_order_release for us and + * thus ensures that it reaches global visibility together + * with new 'next'. + */ + seen = stable_nextoff(rbuf); + next = seen & RBUF_OFF_MASK; + ASSERT(next < rbuf->space); + atomic_store_explicit(&w->seen_off, next | WRAP_LOCK_BIT, + memory_order_relaxed); + + /* + * Compute the target offset. Key invariant: we cannot + * go beyond the WRITTEN offset or catch up with it. + */ + target = next + len; + written = rbuf->written; + if (__predict_false(next < written && target >= written)) { + /* The producer must wait. */ + atomic_store_explicit(&w->seen_off, + RBUF_OFF_MAX, memory_order_release); + return -1; + } + + if (__predict_false(target >= rbuf->space)) { + const bool exceed = target > rbuf->space; + + /* + * Wrap-around and start from the beginning. + * + * If we would exceed the buffer, then attempt to + * acquire the WRAP_LOCK_BIT and use the space in + * the beginning. If we used all space exactly to + * the end, then reset to 0. + * + * Check the invariant again. + */ + target = exceed ? (WRAP_LOCK_BIT | len) : 0; + if ((target & RBUF_OFF_MASK) >= written) { + atomic_store_explicit(&w->seen_off, + RBUF_OFF_MAX, memory_order_release); + return -1; + } + /* Increment the wrap-around counter. */ + target |= WRAP_INCR(seen & WRAP_COUNTER); + } else { + /* Preserve the wrap-around counter. */ + target |= seen & WRAP_COUNTER; + } + } while (!atomic_compare_exchange_weak(&rbuf->next, &seen, target)); + + /* + * Acquired the range. Clear WRAP_LOCK_BIT in the 'seen' value + * thus indicating that it is stable now. + * + * No need for memory_order_release, since CAS issued a fence. + */ + atomic_store_explicit(&w->seen_off, w->seen_off & ~WRAP_LOCK_BIT, + memory_order_relaxed); + + /* + * If we set the WRAP_LOCK_BIT in the 'next' (because we exceed + * the remaining space and need to wrap-around), then save the + * 'end' offset and release the lock. + */ + if (__predict_false(target & WRAP_LOCK_BIT)) { + /* Cannot wrap-around again if consumer did not catch-up. */ + ASSERT(rbuf->written <= next); + ASSERT(rbuf->end == RBUF_OFF_MAX); + rbuf->end = next; + next = 0; + + /* + * Unlock: ensure the 'end' offset reaches global + * visibility before the lock is released. + */ + atomic_store_explicit(&rbuf->next, + (target & ~WRAP_LOCK_BIT), memory_order_release); + } + ASSERT((target & RBUF_OFF_MASK) <= rbuf->space); + return (ssize_t)next; +} + +/* + * ringbuf_produce: indicate the acquired range in the buffer is produced + * and is ready to be consumed. + */ +void +ringbuf_produce(ringbuf_t *rbuf, ringbuf_worker_t *w) +{ + (void)rbuf; + ASSERT(w->registered); + ASSERT(w->seen_off != RBUF_OFF_MAX); + atomic_store_explicit(&w->seen_off, RBUF_OFF_MAX, memory_order_release); +} + +/* + * ringbuf_consume: get a contiguous range which is ready to be consumed. + */ +size_t +ringbuf_consume(ringbuf_t *rbuf, size_t *offset) +{ + ringbuf_off_t written = rbuf->written, next, ready; + size_t towrite; +retry: + /* + * Get the stable 'next' offset. Note: stable_nextoff() issued + * a load memory barrier. The area between the 'written' offset + * and the 'next' offset will be the *preliminary* target buffer + * area to be consumed. + */ + next = stable_nextoff(rbuf) & RBUF_OFF_MASK; + if (written == next) { + /* If producers did not advance, then nothing to do. */ + return 0; + } + + /* + * Observe the 'ready' offset of each producer. + * + * At this point, some producer might have already triggered the + * wrap-around and some (or all) seen 'ready' values might be in + * the range between 0 and 'written'. We have to skip them. + */ + ready = RBUF_OFF_MAX; + + for (unsigned i = 0; i < rbuf->nworkers; i++) { + ringbuf_worker_t *w = &rbuf->workers[i]; + ringbuf_off_t seen_off; + + /* + * Skip if the worker has not registered. + * + * Get a stable 'seen' value. This is necessary since we + * want to discard the stale 'seen' values. + */ + if (!atomic_load_explicit(&w->registered, memory_order_relaxed)) + continue; + seen_off = stable_seenoff(w); + + /* + * Ignore the offsets after the possible wrap-around. + * We are interested in the smallest seen offset that is + * not behind the 'written' offset. + */ + if (seen_off >= written) { + ready = MIN(seen_off, ready); + } + ASSERT(ready >= written); + } + + /* + * Finally, we need to determine whether wrap-around occurred + * and deduct the safe 'ready' offset. + */ + if (next < written) { + const ringbuf_off_t end = MIN(rbuf->space, rbuf->end); + + /* + * Wrap-around case. Check for the cut off first. + * + * Reset the 'written' offset if it reached the end of + * the buffer or the 'end' offset (if set by a producer). + * However, we must check that the producer is actually + * done (the observed 'ready' offsets are clear). + */ + if (ready == RBUF_OFF_MAX && written == end) { + /* + * Clear the 'end' offset if was set. + */ + if (rbuf->end != RBUF_OFF_MAX) { + rbuf->end = RBUF_OFF_MAX; + } + + /* + * Wrap-around the consumer and start from zero. + */ + written = 0; + atomic_store_explicit(&rbuf->written, + written, memory_order_release); + goto retry; + } + + /* + * We cannot wrap-around yet; there is data to consume at + * the end. The ready range is smallest of the observed + * 'ready' or the 'end' offset. If neither is set, then + * the actual end of the buffer. + */ + ASSERT(ready > next); + ready = MIN(ready, end); + ASSERT(ready >= written); + } else { + /* + * Regular case. Up to the observed 'ready' (if set) + * or the 'next' offset. + */ + ready = MIN(ready, next); + } + towrite = ready - written; + *offset = written; + + ASSERT(ready >= written); + ASSERT(towrite <= rbuf->space); + return towrite; +} + +/* + * ringbuf_release: indicate that the consumed range can now be released. + */ +void +ringbuf_release(ringbuf_t *rbuf, size_t nbytes) +{ + const size_t nwritten = rbuf->written + nbytes; + + ASSERT(rbuf->written <= rbuf->space); + ASSERT(rbuf->written <= rbuf->end); + ASSERT(nwritten <= rbuf->space); + + rbuf->written = (nwritten == rbuf->space) ? 0 : nwritten; +} diff --git a/perf/thirdparty/rmind_ringbuf/ringbuf.h b/perf/thirdparty/rmind_ringbuf/ringbuf.h new file mode 100644 index 0000000..e8fc767 --- /dev/null +++ b/perf/thirdparty/rmind_ringbuf/ringbuf.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Mindaugas Rasiukevicius <rmind at noxt eu> + * All rights reserved. + * + * Use is subject to license terms, as specified in the LICENSE file. + */ + +#ifndef _RINGBUF_H_ +#define _RINGBUF_H_ + +__BEGIN_DECLS + +typedef struct ringbuf ringbuf_t; +typedef struct ringbuf_worker ringbuf_worker_t; + +int ringbuf_setup(ringbuf_t *, unsigned, size_t); +void ringbuf_get_sizes(unsigned, size_t *, size_t *); + +ringbuf_worker_t *ringbuf_register(ringbuf_t *, unsigned); +void ringbuf_unregister(ringbuf_t *, ringbuf_worker_t *); + +ssize_t ringbuf_acquire(ringbuf_t *, ringbuf_worker_t *, size_t); +void ringbuf_produce(ringbuf_t *, ringbuf_worker_t *); +size_t ringbuf_consume(ringbuf_t *, size_t *); +void ringbuf_release(ringbuf_t *, size_t); + +__END_DECLS + +#endif diff --git a/perf/thirdparty/rmind_ringbuf/utils.h b/perf/thirdparty/rmind_ringbuf/utils.h new file mode 100644 index 0000000..413157b --- /dev/null +++ b/perf/thirdparty/rmind_ringbuf/utils.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Berkeley Software Design, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cdefs.h 8.8 (Berkeley) 1/9/95 + */ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include <assert.h> + +/* + * A regular assert (debug/diagnostic only). + */ +#if defined(DEBUG) +#define ASSERT assert +#else +#define ASSERT(x) +#endif + +/* + * Minimum, maximum and rounding macros. + */ + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif + +/* + * Branch prediction macros. + */ +#ifndef __predict_true +#define __predict_true(x) __builtin_expect((x) != 0, 1) +#define __predict_false(x) __builtin_expect((x) != 0, 0) +#endif + +/* + * Atomic operations and memory barriers. If C11 API is not available, + * then wrap the GCC builtin routines. + * + * Note: This atomic_compare_exchange_weak does not do the C11 thing of + * filling *(expected) with the actual value, because we don't need + * that here. + */ +#ifndef atomic_compare_exchange_weak +#define atomic_compare_exchange_weak(ptr, expected, desired) \ + __sync_bool_compare_and_swap(ptr, *(expected), desired) +#endif + +#ifndef atomic_thread_fence +#define memory_order_relaxed __ATOMIC_RELAXED +#define memory_order_acquire __ATOMIC_ACQUIRE +#define memory_order_release __ATOMIC_RELEASE +#define memory_order_seq_cst __ATOMIC_SEQ_CST +#define atomic_thread_fence(m) __atomic_thread_fence(m) +#endif +#ifndef atomic_store_explicit +#define atomic_store_explicit __atomic_store_n +#endif +#ifndef atomic_load_explicit +#define atomic_load_explicit __atomic_load_n +#endif + +/* + * Exponential back-off for the spinning paths. + */ +#define SPINLOCK_BACKOFF_MIN 4 +#define SPINLOCK_BACKOFF_MAX 128 +#if defined(__x86_64__) || defined(__i386__) +#define SPINLOCK_BACKOFF_HOOK __asm volatile("pause" ::: "memory") +#else +#define SPINLOCK_BACKOFF_HOOK +#endif +#define SPINLOCK_BACKOFF(count) \ +do { \ + for (int __i = (count); __i != 0; __i--) { \ + SPINLOCK_BACKOFF_HOOK; \ + } \ + if ((count) < SPINLOCK_BACKOFF_MAX) \ + (count) += (count); \ +} while (/* CONSTCOND */ 0); + +#endif |
