diff options
Diffstat (limited to 'src/libmdsserver')
-rw-r--r-- | src/libmdsserver/client-list.c | 197 | ||||
-rw-r--r-- | src/libmdsserver/client-list.h | 4 | ||||
-rw-r--r-- | src/libmdsserver/fd-table.c | 326 | ||||
-rw-r--r-- | src/libmdsserver/fd-table.h | 4 | ||||
-rw-r--r-- | src/libmdsserver/hash-list.h | 581 | ||||
-rw-r--r-- | src/libmdsserver/hash-table.c | 581 | ||||
-rw-r--r-- | src/libmdsserver/linked-list.c | 532 | ||||
-rw-r--r-- | src/libmdsserver/macros.h | 458 | ||||
-rw-r--r-- | src/libmdsserver/mds-message.c | 727 | ||||
-rw-r--r-- | src/libmdsserver/util.c | 867 |
10 files changed, 2124 insertions, 2153 deletions
diff --git a/src/libmdsserver/client-list.c b/src/libmdsserver/client-list.c index 19eaf5a..02d555e 100644 --- a/src/libmdsserver/client-list.c +++ b/src/libmdsserver/client-list.c @@ -27,7 +27,7 @@ * The default initial capacity */ #ifndef CLIENT_LIST_DEFAULT_INITIAL_CAPACITY -#define CLIENT_LIST_DEFAULT_INITIAL_CAPACITY 8 +# define CLIENT_LIST_DEFAULT_INITIAL_CAPACITY 8 #endif @@ -38,19 +38,19 @@ * @param value The value to be rounded up to a power of two * @return The nearest, but not smaller, power of two */ -__attribute__((const)) -static size_t to_power_of_two(size_t value) +static size_t __attribute__((const)) +to_power_of_two(size_t value) { - value -= 1; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; + value -= 1; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; #if SIZE_MAX == UINT64_MAX - value |= value >> 32; + value |= value >> 32; #endif - return value + 1; + return value + 1; } @@ -61,21 +61,22 @@ static size_t to_power_of_two(size_t value) * @param capacity The minimum initial capacity of the client list, 0 for default * @return Non-zero on error, `errno` will have been set accordingly */ -int client_list_create(client_list_t* restrict this, size_t capacity) +int +client_list_create(client_list_t *restrict this, size_t capacity) { - /* Use default capacity of zero is specified. */ - if (capacity == 0) - capacity = CLIENT_LIST_DEFAULT_INITIAL_CAPACITY; - - /* Initialise the client list. */ - this->capacity = capacity = to_power_of_two(capacity); - this->size = 0; - this->clients = NULL; - fail_if (xmalloc(this->clients, capacity, uint64_t)); - - return 0; - fail: - return -1; + /* Use default capacity of zero is specified. */ + if (!capacity) + capacity = CLIENT_LIST_DEFAULT_INITIAL_CAPACITY; + + /* Initialise the client list. */ + this->capacity = capacity = to_power_of_two(capacity); + this->size = 0; + this->clients = NULL; + fail_if (xmalloc(this->clients, capacity, uint64_t)); + + return 0; +fail: + return -1; } @@ -85,10 +86,11 @@ int client_list_create(client_list_t* restrict this, size_t capacity) * * @param this The client list */ -void client_list_destroy(client_list_t* restrict this) +void +client_list_destroy(client_list_t *restrict this) { - free(this->clients); - this->clients = NULL; + free(this->clients); + this->clients = NULL; } @@ -99,17 +101,18 @@ void client_list_destroy(client_list_t* restrict this) * @param out Memory slot in which to store the new client list * @return Non-zero on error, `errno` will have been set accordingly */ -int client_list_clone(const client_list_t* restrict this, client_list_t* restrict out) +int +client_list_clone(const client_list_t *restrict this, client_list_t *restrict out) { - fail_if (xmemdup(out->clients, this->clients, this->capacity, uint64_t)); - - out->capacity = this->capacity; - out->size = this->size; - - return 0; - - fail: - return -1; + fail_if (xmemdup(out->clients, this->clients, this->capacity, uint64_t)); + + out->capacity = this->capacity; + out->size = this->size; + + return 0; + +fail: + return -1; } @@ -120,23 +123,23 @@ int client_list_clone(const client_list_t* restrict this, client_list_t* restric * @param client The client to add * @return Non-zero on error, `errno` will be set accordingly */ -int client_list_add(client_list_t* restrict this, uint64_t client) +int +client_list_add(client_list_t *restrict this, uint64_t client) { - if (this->size == this->capacity) - { - uint64_t* old = this->clients; - if (xrealloc(old, this->capacity <<= 1, uint64_t)) - { - this->capacity >>= 1; - this->clients = old; - fail_if (1); + uint64_t* old; + if (this->size == this->capacity) { + old = this->clients; + if (xrealloc(old, this->capacity <<= 1, uint64_t)) { + this->capacity >>= 1; + this->clients = old; + fail_if (1); + } } - } - - this->clients[this->size++] = client; - return 0; - fail: - return -1; + + this->clients[this->size++] = client; + return 0; +fail: + return -1; } @@ -146,29 +149,27 @@ int client_list_add(client_list_t* restrict this, uint64_t client) * @param this The list * @param client The client to remove */ -void client_list_remove(client_list_t* restrict this, uint64_t client) +void +client_list_remove(client_list_t *restrict this, uint64_t client) { - size_t i; - for (i = 0; i < this->size; i++) - { - if (this->clients[i] == client) - { - size_t n = (--(this->size) - i) * sizeof(uint64_t); - memmove(this->clients + i, this->clients + i + 1, n); - - if (this->size << 1 <= this->capacity) - { - uint64_t* old = this->clients; - if (xrealloc(old, this->capacity >>= 1, uint64_t)) - { - this->capacity <<= 1; - this->clients = old; + size_t i, n; + uint64_t *old; + for (i = 0; i < this->size; i++) { + if (this->clients[i] == client) { + n = (--(this->size) - i) * sizeof(uint64_t); + memmove(this->clients + i, this->clients + i + 1, n); + + if (this->size << 1 <= this->capacity) { + old = this->clients; + if (xrealloc(old, this->capacity >>= 1, uint64_t)) { + this->capacity <<= 1; + this->clients = old; + } + } + + return; } - } - - return; } - } } @@ -178,9 +179,10 @@ void client_list_remove(client_list_t* restrict this, uint64_t client) * @param this The list * @return The number of bytes to allocate to the output buffer */ -size_t client_list_marshal_size(const client_list_t* restrict this) +size_t +client_list_marshal_size(const client_list_t *restrict this) { - return 2 * sizeof(size_t) + this->size * sizeof(uint64_t) + sizeof(int); + return 2 * sizeof(size_t) + this->size * sizeof(uint64_t) + sizeof(int); } @@ -190,13 +192,14 @@ size_t client_list_marshal_size(const client_list_t* restrict this) * @param this The list * @param data Output buffer for the marshalled data */ -void client_list_marshal(const client_list_t* restrict this, char* restrict data) +void +client_list_marshal(const client_list_t *restrict this, char *restrict data) { - buf_set_next(data, int, CLIENT_LIST_T_VERSION); - buf_set_next(data, size_t, this->capacity); - buf_set_next(data, size_t, this->size); - - memcpy(data, this->clients, this->size * sizeof(uint64_t)); + buf_set_next(data, int, CLIENT_LIST_T_VERSION); + buf_set_next(data, size_t, this->capacity); + buf_set_next(data, size_t, this->size); + + memcpy(data, this->clients, this->size * sizeof(uint64_t)); } @@ -208,21 +211,21 @@ void client_list_marshal(const client_list_t* restrict this, char* restrict data * @return Non-zero on error, `errno` will be set accordingly. * Destroy the list on error. */ -int client_list_unmarshal(client_list_t* restrict this, char* restrict data) +int +client_list_unmarshal(client_list_t *restrict this, char *restrict data) { - /* buf_get(data, int, 0, CLIENT_LIST_T_VERSION); */ - buf_next(data, int, 1); - - this->clients = NULL; - - buf_get_next(data, size_t, this->capacity); - buf_get_next(data, size_t, this->size); - - fail_if (xmalloc(this->clients, this->capacity, uint64_t)); - memcpy(this->clients, data, this->size * sizeof(uint64_t)); - - return 0; - fail: - return -1; -} + /* buf_get(data, int, 0, CLIENT_LIST_T_VERSION); */ + buf_next(data, int, 1); + + this->clients = NULL; + + buf_get_next(data, size_t, this->capacity); + buf_get_next(data, size_t, this->size); + fail_if (xmalloc(this->clients, this->capacity, uint64_t)); + memcpy(this->clients, data, this->size * sizeof(uint64_t)); + + return 0; +fail: + return -1; +} diff --git a/src/libmdsserver/client-list.h b/src/libmdsserver/client-list.h index 4d2bfa7..ffe828a 100644 --- a/src/libmdsserver/client-list.h +++ b/src/libmdsserver/client-list.h @@ -30,8 +30,7 @@ /** * Dynamic array of client ID:s */ -typedef struct client_list -{ +typedef struct client_list { /** * The size of the array */ @@ -46,7 +45,6 @@ typedef struct client_list * Stored client ID:s */ uint64_t *clients; - } client_list_t; diff --git a/src/libmdsserver/fd-table.c b/src/libmdsserver/fd-table.c index 1db2d87..fafaa65 100644 --- a/src/libmdsserver/fd-table.c +++ b/src/libmdsserver/fd-table.c @@ -31,29 +31,30 @@ * @param initial_capacity The initial capacity of the table * @return Non-zero on error, `errno` will have been set accordingly */ -int fd_table_create_tuned(fd_table_t* restrict this, size_t initial_capacity) +int +fd_table_create_tuned(fd_table_t *restrict this, size_t initial_capacity) { - size_t bitcap; - - this->capacity = initial_capacity ? initial_capacity : 1; - this->size = 0; - - this->values = NULL; - this->used = NULL; - this->value_comparator = NULL; - - /* It is important that both allocations are done with calloc: - `this->used` must set all keys as unused at the initial state, - `this->values` must be initialised for marshaling and it helps - the time overhead of `fd_table_contains_value`. */ - - bitcap = (this->capacity + 63) / 64; - fail_if (xcalloc(this->used, bitcap, size_t)); - fail_if (xcalloc(this->values, this->capacity, size_t)); - - return 0; - fail: - return -1; + size_t bitcap; + + this->capacity = initial_capacity ? initial_capacity : 1; + this->size = 0; + + this->values = NULL; + this->used = NULL; + this->value_comparator = NULL; + + /* It is important that both allocations are done with calloc: + `this->used` must set all keys as unused at the initial state, + `this->values` must be initialised for marshaling and it helps + the time overhead of `fd_table_contains_value`. */ + + bitcap = (this->capacity + 63) / 64; + fail_if (xcalloc(this->used, bitcap, size_t)); + fail_if (xcalloc(this->values, this->capacity, size_t)); + + return 0; +fail: + return -1; } @@ -65,20 +66,20 @@ int fd_table_create_tuned(fd_table_t* restrict this, size_t initial_capacity) * @param keys_freer Function that frees a key, `NULL` if keys should not be freed * @param values_freer Function that frees a value, `NULL` if value should not be freed */ -void fd_table_destroy(fd_table_t* restrict this, free_func* key_freer, free_func* value_freer) +void +fd_table_destroy(fd_table_t *restrict this, free_func *key_freer, free_func *value_freer) { - if (((key_freer != NULL) || (value_freer != NULL)) && (this->used != NULL) && (this->values != NULL)) - { - size_t i; - for (i = 0; i < this->capacity; i++) - if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) - { - if (key_freer != NULL) key_freer(i); - if (value_freer != NULL) value_freer(this->values[i]); - } - } - free(this->values); - free(this->used); + size_t i; + if ((key_freer || value_freer) && this->used && this->values) { + for (i = 0; i < this->capacity; i++) { + if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) { + if (key_freer) key_freer(i); + if (value_freer) value_freer(this->values[i]); + } + } + } + free(this->values); + free(this->used); } @@ -89,24 +90,22 @@ void fd_table_destroy(fd_table_t* restrict this, free_func* key_freer, free_func * @param value The value * @return Whether the value is stored in the table */ -int fd_table_contains_value(const fd_table_t* restrict this, size_t value) +int +fd_table_contains_value(const fd_table_t *restrict this, size_t value) { - size_t i; - if (this->value_comparator == NULL) - { - for (i = 0; i < this->capacity; i++) - if (this->values[i] == value) - if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) - return 1; - } - else - { - for (i = 0; i < this->capacity; i++) - if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) - if (this->value_comparator(this->values[i], value)) - return 1; - } - return 0; + size_t i; + if (!this->value_comparator) { + for (i = 0; i < this->capacity; i++) + if (this->values[i] == value) + if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) + return 1; + } else { + for (i = 0; i < this->capacity; i++) + if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) + if (this->value_comparator(this->values[i], value)) + return 1; + } + return 0; } @@ -117,9 +116,10 @@ int fd_table_contains_value(const fd_table_t* restrict this, size_t value) * @param key The key * @return Whether the key is used */ -int fd_table_contains_key(const fd_table_t* restrict this, int key) +int +fd_table_contains_key(const fd_table_t *restrict this, int key) { - return ((size_t)key < this->capacity) && (this->used[key / 64] & ((uint64_t)1 << (key % 64))); + return (size_t)key < this->capacity && (this->used[key / 64] & ((uint64_t)1 << (key % 64))); } @@ -130,11 +130,10 @@ int fd_table_contains_key(const fd_table_t* restrict this, int key) * @param key The key associated with the value * @return The value associated with the key, 0 if the key was not used */ -size_t fd_table_get(const fd_table_t* restrict this, int key) +size_t +fd_table_get(const fd_table_t *restrict this, int key) { - if (fd_table_contains_key(this, key) == 0) - return 0; - return this->values[key]; + return fd_table_contains_key(this, key) ? this->values[key] : 0; } @@ -147,55 +146,53 @@ size_t fd_table_get(const fd_table_t* restrict this, int key) * @return The previous value associated with the key, 0 if the key was not used. * 0 will also be returned on error, check the `errno` variable. */ -size_t fd_table_put(fd_table_t* restrict this, int key, size_t value) +size_t +fd_table_put(fd_table_t *restrict this, int key, size_t value) { - /* Override current value if the key is already used. */ - if (fd_table_contains_key(this, key)) - { - size_t rc = fd_table_get(this, key); - this->values[key] = value; - return rc; - } - - /* Grow the table if it is too small. */ - errno = 0; - if ((size_t)key >= this->capacity) - { - size_t* old_values = this->values; - size_t old_bitcap, new_bitcap; - if (xrealloc(this->values, this->capacity << 1, size_t)) - { - this->values = old_values; - fail_if (1); + size_t rc, old_bitcap, new_bitcap, *old_values; + uint64_t *old_used; + + /* Override current value if the key is already used. */ + if (fd_table_contains_key(this, key)) { + rc = fd_table_get(this, key); + this->values[key] = value; + return rc; } + + /* Grow the table if it is too small. */ + errno = 0; + if ((size_t)key >= this->capacity) { + old_values = this->values; + if (xrealloc(this->values, this->capacity << 1, size_t)) { + this->values = old_values; + fail_if (1); + } + + memset(this->values + this->capacity, 0, this->capacity * sizeof(size_t)); - memset(this->values + this->capacity, 0, this->capacity * sizeof(size_t)); - - old_bitcap = (this->capacity + 63) / 64; - this->capacity <<= 1; - new_bitcap = (this->capacity + 63) / 64; - - if (new_bitcap > old_bitcap) - { - uint64_t* old_used = this->used; - if (xrealloc(this->used, new_bitcap, size_t)) - { - this->used = old_used; - this->capacity >>= 1; - fail_if (1); - } - - memset(this->used + old_bitcap, 0, (new_bitcap - old_bitcap) * sizeof(uint64_t)); + old_bitcap = (this->capacity + 63) / 64; + this->capacity <<= 1; + new_bitcap = (this->capacity + 63) / 64; + + if (new_bitcap > old_bitcap) { + old_used = this->used; + if (xrealloc(this->used, new_bitcap, size_t)) { + this->used = old_used; + this->capacity >>= 1; + fail_if (1); + } + + memset(this->used + old_bitcap, 0, (new_bitcap - old_bitcap) * sizeof(uint64_t)); + } } - } - - /* Store the entry. */ - this->used[key / 64] |= (uint64_t)1 << (key % 64); - this->values[key] = value; - this->size++; - return 0; - fail: - return 0; + + /* Store the entry. */ + this->used[key / 64] |= (uint64_t)1 << (key % 64); + this->values[key] = value; + this->size++; + return 0; +fail: + return 0; } @@ -206,15 +203,15 @@ size_t fd_table_put(fd_table_t* restrict this, int key, size_t value) * @param key The key of the entry to remove * @return The previous value associated with the key, 0 if the key was not used */ -size_t fd_table_remove(fd_table_t* restrict this, int key) +size_t +fd_table_remove(fd_table_t *restrict this, int key) { - size_t rc = fd_table_get(this, key); - if (rc && fd_table_contains_key(this, key)) - { - this->used[key / 64] &= ~((uint64_t)1 << (key % 64)); - this->size--; - } - return rc; + size_t rc = fd_table_get(this, key); + if (rc && fd_table_contains_key(this, key)) { + this->used[key / 64] &= ~((uint64_t)1 << (key % 64)); + this->size--; + } + return rc; } @@ -223,12 +220,13 @@ size_t fd_table_remove(fd_table_t* restrict this, int key) * * @param this The fd table */ -void fd_table_clear(fd_table_t* restrict this) +void +fd_table_clear(fd_table_t *restrict this) { - size_t bitcap; - this->size = 0; - bitcap = (this->capacity + 63) / 64; - memset(this->used, 0, bitcap * sizeof(uint64_t)); + size_t bitcap; + this->size = 0; + bitcap = (this->capacity + 63) / 64; + memset(this->used, 0, bitcap * sizeof(uint64_t)); } @@ -238,10 +236,11 @@ void fd_table_clear(fd_table_t* restrict this) * @param this The fd table * @return The number of bytes to allocate to the output buffer */ -size_t fd_table_marshal_size(const fd_table_t* restrict this) +size_t +fd_table_marshal_size(const fd_table_t *restrict this) { - size_t bitcap = (this->capacity + 63) / 64; - return (this->capacity + 2) * sizeof(size_t) + bitcap * sizeof(uint64_t) + sizeof(int); + size_t bitcap = (this->capacity + 63) / 64; + return (this->capacity + 2) * sizeof(size_t) + bitcap * sizeof(uint64_t) + sizeof(int); } @@ -251,18 +250,19 @@ size_t fd_table_marshal_size(const fd_table_t* restrict this) * @param this The fd table * @param data Output buffer for the marshalled data */ -void fd_table_marshal(const fd_table_t* restrict this, char* restrict data) +void +fd_table_marshal(const fd_table_t *restrict this, char *restrict data) { - size_t bitcap = (this->capacity + 63) / 64; - - buf_set_next(data, int, FD_TABLE_T_VERSION); - buf_set_next(data, size_t, this->capacity); - buf_set_next(data, size_t, this->size); - - memcpy(data, this->values, this->capacity * sizeof(size_t)); - buf_next(data, size_t, this->capacity); - - memcpy(data, this->used, bitcap * sizeof(uint64_t)); + size_t bitcap = (this->capacity + 63) / 64; + + buf_set_next(data, int, FD_TABLE_T_VERSION); + buf_set_next(data, size_t, this->capacity); + buf_set_next(data, size_t, this->size); + + memcpy(data, this->values, this->capacity * sizeof(size_t)); + buf_next(data, size_t, this->capacity); + + memcpy(data, this->used, bitcap * sizeof(uint64_t)); } @@ -275,38 +275,38 @@ void fd_table_marshal(const fd_table_t* restrict this, char* restrict data) * @return Non-zero on error, `errno` will be set accordingly. * Destroy the table on error. */ -int fd_table_unmarshal(fd_table_t* restrict this, char* restrict data, remap_func* remapper) +int +fd_table_unmarshal(fd_table_t *restrict this, char *restrict data, remap_func *remapper) { - size_t bitcap; - size_t i; - - /* buf_get(data, int, 0, FD_TABLE_T_VERSION) */ - buf_next(data, int, 1); - - buf_get_next(data, size_t, this->capacity); - buf_get_next(data, size_t, this->size); - - this->values = NULL; - this->used = NULL; - this->value_comparator = NULL; - - fail_if (xmalloc(this->values, this->capacity, size_t)); - - bitcap = (this->capacity + 63) / 64; - fail_if (xmalloc(this->used, bitcap, size_t)); - - memcpy(this->values, data, this->capacity * sizeof(size_t)); - buf_next(data, size_t, this->capacity); - - memcpy(this->used, data, bitcap * sizeof(uint64_t)); - - if (remapper != NULL) - for (i = 0; i < this->capacity; i++) - if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) - this->values[i] = remapper(this->values[i]); - - return 0; - fail: - return -1; -} + size_t bitcap; + size_t i; + + /* buf_get(data, int, 0, FD_TABLE_T_VERSION) */ + buf_next(data, int, 1); + + buf_get_next(data, size_t, this->capacity); + buf_get_next(data, size_t, this->size); + this->values = NULL; + this->used = NULL; + this->value_comparator = NULL; + + fail_if (xmalloc(this->values, this->capacity, size_t)); + + bitcap = (this->capacity + 63) / 64; + fail_if (xmalloc(this->used, bitcap, size_t)); + + memcpy(this->values, data, this->capacity * sizeof(size_t)); + buf_next(data, size_t, this->capacity); + + memcpy(this->used, data, bitcap * sizeof(uint64_t)); + + if (remapper) + for (i = 0; i < this->capacity; i++) + if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) + this->values[i] = remapper(this->values[i]); + + return 0; +fail: + return -1; +} diff --git a/src/libmdsserver/fd-table.h b/src/libmdsserver/fd-table.h index e0b3a09..e484937 100644 --- a/src/libmdsserver/fd-table.h +++ b/src/libmdsserver/fd-table.h @@ -30,8 +30,7 @@ /** * Value lookup table optimised for file descriptors as keys */ -typedef struct fd_table -{ +typedef struct fd_table { /** * The table's capacity, i.e. how many entries that can be stored, * in total, before its internal table needs to grow @@ -61,7 +60,6 @@ typedef struct fd_table * Be aware, this variable cannot be marshalled */ compare_func *value_comparator; - } fd_table_t; diff --git a/src/libmdsserver/hash-list.h b/src/libmdsserver/hash-list.h index abcbb74..2087bce 100644 --- a/src/libmdsserver/hash-list.h +++ b/src/libmdsserver/hash-list.h @@ -34,7 +34,7 @@ * The default initial capacity */ #ifndef HASH_LIST_DEFAULT_INITIAL_CAPACITY -# define HASH_LIST_DEFAULT_INITIAL_CAPACITY 128 +# define HASH_LIST_DEFAULT_INITIAL_CAPACITY 128 #endif /** @@ -61,15 +61,15 @@ * that is, have the value `__VA_ARGS__`. */ #ifndef HASH_LIST_EXPECTED -# define HASH_LIST_EXPECTED(...) __builtin_expect((__VA_ARGS__), 1) +# define HASH_LIST_EXPECTED(...) __builtin_expect((__VA_ARGS__), 1) #endif -#define HASH_LIST_HASH(key) (this->hasher != NULL ? this->hasher(key) : (size_t)key) +#define HASH_LIST_HASH(key) (this->hasher ? this->hasher(key) : (size_t)key) -#define HASH_LIST_T_VERSION 0 +#define HASH_LIST_T_VERSION 0 /** @@ -105,7 +105,7 @@ typedef VALUE_T T##_value_t;\ * * @param entry The entry, will never be `NULL`, any only used entries will be passed */\ -typedef void T##_entry_free_func(struct T##_entry* entry);\ +typedef void T##_entry_free_func(struct T##_entry *entry);\ \ /** * Function-type for the function responsible for hashing keys @@ -134,7 +134,7 @@ static inline int T##_key_comparer(CKEY_T key_a, CKEY_T key_b);\ * @return The marshal-size of the entry's key and value */\ __attribute__((pure, nonnull))\ -static inline size_t T##_submarshal_size(const struct T##_entry* entry);\ +static inline size_t T##_submarshal_size(const struct T##_entry *entry);\ \ /** * Marshal an entry's key and value @@ -144,7 +144,7 @@ static inline size_t T##_submarshal_size(const struct T##_entry* entry);\ * @return The marshal-size of the entry's key and value */\ __attribute__((pure, nonnull))\ -static inline size_t T##_submarshal(const struct T##_entry* entry, char* restrict data);\ +static inline size_t T##_submarshal(const struct T##_entry *entry, char *restrict data);\ \ /** * Unmarshal an entry's key and value @@ -154,7 +154,7 @@ static inline size_t T##_submarshal(const struct T##_entry* entry, char* restric * @return The number of read bytes, zero on error */\ __attribute__((pure, nonnull))\ -static inline size_t T##_subunmarshal(struct T##_entry* entry, char* restrict data);\ +static inline size_t T##_subunmarshal(struct T##_entry *entry, char *restrict data);\ \ \ \ @@ -163,21 +163,21 @@ static inline size_t T##_subunmarshal(struct T##_entry* entry, char* restrict da */\ typedef struct T##_entry\ {\ - /** - * The key of the entry, `NULL` if the slot is unused - */\ - KEY_T key;\ - \ - /** - * Hash of `key`, undefined but initialised if the slot is unused - */\ - size_t key_hash;\ - \ - /** - * The value of the entry - */\ - T##_value_t value;\ - \ + /** + * The key of the entry, `NULL` if the slot is unused + */\ + KEY_T key;\ + \ + /** + * Hash of `key`, undefined but initialised if the slot is unused + */\ + size_t key_hash;\ + \ + /** + * The value of the entry + */\ + T##_value_t value;\ + \ } T##_entry_t;\ \ \ @@ -186,55 +186,55 @@ typedef struct T##_entry\ */\ typedef struct T\ {\ - /** - * The number of allocated slots - */\ - size_t allocated;\ - \ - /** - * The number of unused slot that - * has previously be used - */\ - size_t unused;\ - \ - /** - * The number of slots that have - * been used, even if no longer used - */\ - size_t used;\ - \ - /** - * This variable is used for optimisation, any - * time `hash_list_get` finds an element, its - * will be stored, and it will be the first - * inspected element by `hash_list_put` and - * `hash_list_remove` - */\ - size_t last;\ - \ - /** - * The slots - */\ - T##_entry_t* slots;\ - \ - /** - * Function used to free keys and values of entries - * - * The freeing is not used if this function pointer is `NULL` - * - * Be aware, this variable cannot be marshalled - */\ - T##_entry_free_func* freer;\ - \ - /** - * Function used to calculate the hash of a key - * - * If this function pointer is `NULL`, the identity hash is used - * - * Be aware, this variable cannot be marshalled - */\ - T##_key_hash_func* hasher;\ - \ + /** + * The number of allocated slots + */\ + size_t allocated;\ + \ + /** + * The number of unused slot that + * has previously be used + */\ + size_t unused;\ + \ + /** + * The number of slots that have + * been used, even if no longer used + */\ + size_t used;\ + \ + /** + * This variable is used for optimisation, any + * time `hash_list_get` finds an element, its + * will be stored, and it will be the first + * inspected element by `hash_list_put` and + * `hash_list_remove` + */\ + size_t last;\ + \ + /** + * The slots + */\ + T##_entry_t *slots;\ + \ + /** + * Function used to free keys and values of entries + * + * The freeing is not used if this function pointer is `NULL` + * + * Be aware, this variable cannot be marshalled + */\ + T##_entry_free_func *freer;\ + \ + /** + * Function used to calculate the hash of a key + * + * If this function pointer is `NULL`, the identity hash is used + * + * Be aware, this variable cannot be marshalled + */\ + T##_key_hash_func *hasher;\ + \ } T##_t;\ \ \ @@ -247,24 +247,24 @@ typedef struct T\ * @return Non-zero on error, `errno` will have been set accordingly */\ static inline int __attribute__((unused, nonnull))\ -T##_create(T##_t* restrict this, size_t capacity)\ +T##_create(T##_t *restrict this, size_t capacity)\ {\ - if (capacity == 0)\ - capacity = HASH_LIST_DEFAULT_INITIAL_CAPACITY;\ - \ - this->freer = NULL;\ - this->hasher = NULL;\ - this->allocated = 0;\ - this->unused = 0;\ - this->used = 0;\ - this->last = 0;\ - \ - this->slots = malloc(capacity * sizeof(T##_t));\ - if (this->slots == NULL)\ - return -1;\ - \ - this->allocated = capacity;\ - return 0;\ + if (!capacity)\ + capacity = HASH_LIST_DEFAULT_INITIAL_CAPACITY;\ + \ + this->freer = NULL;\ + this->hasher = NULL;\ + this->allocated = 0;\ + this->unused = 0;\ + this->used = 0;\ + this->last = 0;\ + \ + this->slots = malloc(capacity * sizeof(T##_t));\ + if (!this->slots)\ + return -1;\ + \ + this->allocated = capacity;\ + return 0;\ }\ \ \ @@ -274,19 +274,19 @@ T##_create(T##_t* restrict this, size_t capacity)\ * @param this The hash list */\ static inline void __attribute__((unused, nonnull))\ -T##_destroy(T##_t* restrict this)\ +T##_destroy(T##_t *restrict this)\ {\ - size_t i, n;\ - if (this->freer != NULL)\ - for (i = 0, n = this->used; i < n; i++)\ - if (this->slots[i].key)\ - this->freer(this->slots + i);\ - this->used = 0;\ - this->unused = 0;\ - this->allocated = 0;\ - this->last = 0;\ - free(this->slots);\ - this->slots = NULL;\ + size_t i, n;\ + if (this->freer)\ + for (i = 0, n = this->used; i < n; i++)\ + if (this->slots[i].key)\ + this->freer(this->slots + i);\ + this->used = 0;\ + this->unused = 0;\ + this->allocated = 0;\ + this->last = 0;\ + free(this->slots);\ + this->slots = NULL;\ }\ \ \ @@ -298,14 +298,14 @@ T##_destroy(T##_t* restrict this)\ * @return Non-zero on error, `errno` will have been set accordingly */\ static inline int __attribute__((unused, nonnull))\ -T##_clone(const T##_t* restrict this, T##_t* restrict out)\ +T##_clone(const T##_t *restrict this, T##_t *restrict out)\ {\ - if (T##_create(out, this->allocated) < 0)\ - return -1;\ - out->used = this->used;\ - out->unused = this->unused;\ - out->last = this->last;\ - memcpy(out->slots, this->slots, this->used * sizeof(T##_entry_t));\ + if (T##_create(out, this->allocated) < 0)\ + return -1;\ + out->used = this->used;\ + out->unused = this->unused;\ + out->last = this->last;\ + memcpy(out->slots, this->slots, this->used * sizeof(T##_entry_t));\ }\ \ \ @@ -321,32 +321,30 @@ T##_clone(const T##_t* restrict this, T##_t* restrict out)\ * been set accordingly. Errors are non-fatal. */\ static inline int __attribute__((unused, nonnull))\ -T##_pack(T##_t* restrict this)\ +T##_pack(T##_t *restrict this)\ {\ - size_t i, j, n;\ - T##_entry_t* slots = this->slots;\ - \ - if (this->unused > 0)\ - {\ - for (i = 0, j = 0, n = this->used; i < n; i++)\ - if (slots[i].key != NULL)\ - slots[j++] = slots[i];\ - \ - this->used -= this->unused;\ - this->unused = 0;\ - this->last = 0;\ - }\ - \ - if (this->used < this->allocated)\ - {\ - slots = realloc(slots, this->used * sizeof(T##_entry_t));\ - if (slots == NULL)\ - return -1;\ - this->slots = slots;\ - this->allocated = this->used;\ - }\ - \ - return 0;\ + size_t i, j, n;\ + T##_entry_t *slots = this->slots;\ + \ + if (this->unused > 0) {\ + for (i = 0, j = 0, n = this->used; i < n; i++)\ + if (slots[i].key)\ + slots[j++] = slots[i];\ + \ + this->used -= this->unused;\ + this->unused = 0;\ + this->last = 0;\ + }\ + \ + if (this->used < this->allocated) {\ + slots = realloc(slots, this->used * sizeof(T##_entry_t));\ + if (!slots)\ + return -1;\ + this->slots = slots;\ + this->allocated = this->used;\ + }\ + \ + return 0;\ }\ \ \ @@ -359,14 +357,14 @@ T##_pack(T##_t* restrict this)\ * @return Whether the key was found, error is impossible */\ static inline int __attribute__((unused, nonnull))\ -T##_get(T##_t* restrict this, CKEY_T key, T##_value_t* restrict value)\ +T##_get(T##_t *restrict this, CKEY_T key, T##_value_t *restrict value)\ {\ - size_t i, n, hash = HASH_LIST_HASH(key);\ - for (i = 0, n = this->used; i < n; i++)\ - if ((this->slots[i].key_hash == hash) && this->slots[i].key)\ - if (T##_key_comparer(this->slots[i].key, key))\ - return *value = this->slots[this->last = i].value, 1;\ - return this->last = 0, 0;\ + size_t i, n, hash = HASH_LIST_HASH(key);\ + for (i = 0, n = this->used; i < n; i++)\ + if (this->slots[i].key_hash == hash && this->slots[i].key)\ + if (T##_key_comparer(this->slots[i].key, key))\ + return *value = this->slots[this->last = i].value, 1;\ + return this->last = 0, 0;\ }\ \ \ @@ -377,39 +375,39 @@ T##_get(T##_t* restrict this, CKEY_T key, T##_value_t* restrict value)\ * @param key The key of the entry to remove, must not be `NULL` */\ static inline void __attribute__((unused, nonnull))\ -T##_remove(T##_t* restrict this, CKEY_T key)\ +T##_remove(T##_t *restrict this, CKEY_T key)\ {\ - size_t i = this->last, n, hash = HASH_LIST_HASH(key);\ - T##_entry_t* slots = this->slots;\ - \ - /* First, try cached index. */\ - if (HASH_LIST_EXPECTED(i && (slots[i].key_hash == hash) && (slots[i].key != NULL)))\ - if (HASH_LIST_EXPECTED(T##_key_comparer(slots[i].key, key)))\ - goto do_remove;\ - /* It is discouraged to use put or remove without - * doing a get before it, otherwise you do not know - * what is happening. So we do not expect to get - * get to the next line. However, if do not expect to - * run get before put or remove, you should modify the - * `HASH_LIST_EXPECTED` macro. However, this is single - * case where will will get to the next line, when the - * index of the item is zero. */\ - \ - /* Then, search. */\ - for (i = 0, n = this->used; i < n; i++)\ - if ((slots[i].key_hash == hash) && (slots[i].key != NULL))\ - if (T##_key_comparer(slots[i].key, key))\ - goto do_remove;\ - \ - return;\ - do_remove:\ - if (this->freer != NULL)\ - this->freer(slots + i);\ - slots[i].key = NULL;\ - this->unused++;\ - if ((this->unused >> 1) >= this->used)\ - T##_pack(this);\ - this->last = 0;\ + size_t i = this->last, n, hash = HASH_LIST_HASH(key);\ + T##_entry_t *slots = this->slots;\ + \ + /* First, try cached index. */\ + if (HASH_LIST_EXPECTED(i && slots[i].key_hash == hash && slots[i].key))\ + if (HASH_LIST_EXPECTED(T##_key_comparer(slots[i].key, key)))\ + goto do_remove;\ + /* It is discouraged to use put or remove without + * doing a get before it, otherwise you do not know + * what is happening. So we do not expect to get + * get to the next line. However, if do not expect to + * run get before put or remove, you should modify the + * `HASH_LIST_EXPECTED` macro. However, this is single + * case where will will get to the next line, when the + * index of the item is zero. */\ + \ + /* Then, search. */\ + for (i = 0, n = this->used; i < n; i++)\ + if (slots[i].key_hash == hash && slots[i].key)\ + if (T##_key_comparer(slots[i].key, key))\ + goto do_remove;\ + \ + return;\ +do_remove:\ + if (this->freer)\ + this->freer(slots + i);\ + slots[i].key = NULL;\ + this->unused++;\ + if (this->unused >> 1 >= this->used)\ + T##_pack(this);\ + this->last = 0;\ }\ \ \ @@ -423,66 +421,66 @@ T##_remove(T##_t* restrict this, CKEY_T key)\ * @return Non-zero on error, `errno` will have been set accordingly */\ static inline int __attribute__((unused, nonnull(1, 2)))\ -T##_put(T##_t* restrict this, KEY_T key, const T##_value_t* restrict value)\ +T##_put(T##_t *restrict this, KEY_T key, const T##_value_t *restrict value)\ {\ - size_t i = this->last, n, empty = this->used, hash;\ - T##_entry_t* slots = this->slots;\ - \ - /* Remove entry if no value is passed. */\ - if (value == NULL)\ - {\ - T##_remove(this, key);\ - return 0;\ - }\ - \ - /* Hash the input key. */\ - hash = HASH_LIST_HASH(key);\ - \ - /* Try cached index. */\ - if (HASH_LIST_EXPECTED(i && (slots[i].key != NULL)))\ - if (HASH_LIST_EXPECTED(slots[i].key_hash == hash))\ - if (HASH_LIST_EXPECTED(T##_key_comparer(slots[i].key, key)))\ - goto put;\ - /* It is discouraged to use put or remove without - * doing a get before it, otherwise you do not know - * what is happening. So we do not expect to get - * get to the next line. However, if do not expect to - * run get before put or remove, you should modify the - * `HASH_LIST_EXPECTED` macro. However, this is single - * case where will will get to the next line, when the - * index of the item is zero. */\ - \ - /* Find an unused slot or the current slot. */\ - for (i = 0, n = this->used; i < n; i++)\ - if (slots[i].key == NULL)\ - empty = i;\ - else if (slots[i].key_hash == hash)\ - if (T##_key_comparer(slots[i].key, key))\ - goto put;\ - \ - /* Grow slot allocation is required. */\ - if (empty == this->allocated)\ - {\ - if (empty >= SIZE_MAX >> 1)\ - return errno = ENOMEM, -1;\ - slots = realloc(slots, (empty << 1) * sizeof(T##_entry_t));\ - if (slots == NULL)\ - return -1;\ - this->slots = slots;\ - this->allocated <<= 1;\ - }\ - \ - /* Store entry. */\ - i = empty;\ - goto put_no_free;\ - put:\ - if (this->freer != NULL)\ - this->freer(slots + i);\ - put_no_free:\ - slots[i].key = key;\ - slots[i].key_hash = hash;\ - slots[i].value = *value;\ - return 0;\ + size_t i = this->last, n, empty = this->used, hash;\ + T##_entry_t* slots = this->slots;\ + \ + /* Remove entry if no value is passed. */\ + if (!value) {\ + T##_remove(this, key);\ + return 0;\ + }\ + \ + /* Hash the input key. */\ + hash = HASH_LIST_HASH(key);\ + \ + /* Try cached index. */\ + if (HASH_LIST_EXPECTED(i && slots[i].key))\ + if (HASH_LIST_EXPECTED(slots[i].key_hash == hash))\ + if (HASH_LIST_EXPECTED(T##_key_comparer(slots[i].key, key)))\ + goto put;\ + /* It is discouraged to use put or remove without + * doing a get before it, otherwise you do not know + * what is happening. So we do not expect to get + * get to the next line. However, if do not expect to + * run get before put or remove, you should modify the + * `HASH_LIST_EXPECTED` macro. However, this is single + * case where will will get to the next line, when the + * index of the item is zero. */\ + \ + /* Find an unused slot or the current slot. */\ + for (i = 0, n = this->used; i < n; i++) {\ + if (!slots[i].key) {\ + empty = i;\ + } else if (slots[i].key_hash == hash) {\ + if (T##_key_comparer(slots[i].key, key))\ + goto put;\ + }\ + }\ + \ + /* Grow slot allocation is required. */\ + if (empty == this->allocated) {\ + if (empty >= SIZE_MAX >> 1)\ + return errno = ENOMEM, -1;\ + slots = realloc(slots, (empty << 1) * sizeof(T##_entry_t));\ + if (!slots)\ + return -1;\ + this->slots = slots;\ + this->allocated <<= 1;\ + }\ + \ + /* Store entry. */\ + i = empty;\ + goto put_no_free;\ +put:\ + if (this->freer)\ + this->freer(slots + i);\ +put_no_free:\ + slots[i].key = key;\ + slots[i].key_hash = hash;\ + slots[i].value = *value;\ + return 0;\ }\ \ \ @@ -493,14 +491,14 @@ T##_put(T##_t* restrict this, KEY_T key, const T##_value_t* restrict value)\ * @return The number of bytes to allocate to the output buffer */\ static inline size_t __attribute__((unused, pure, nonnull))\ -T##_marshal_size(const T##_t* restrict this)\ +T##_marshal_size(const T##_t *restrict this)\ {\ - size_t i, n = this->used;\ - size_t rc = sizeof(int) + 4 * sizeof(size_t);\ - for (i = 0; i < n; i++)\ - if (this->slots[i].key != NULL)\ - rc += T##_submarshal_size(this->slots + i);\ - return rc + n * sizeof(char) + (n - this->unused) * sizeof(size_t);\ + size_t i, n = this->used;\ + size_t rc = sizeof(int) + 4 * sizeof(size_t);\ + for (i = 0; i < n; i++)\ + if (this->slots[i].key)\ + rc += T##_submarshal_size(this->slots + i);\ + return rc + n * sizeof(char) + (n - this->unused) * sizeof(size_t);\ }\ \ \ @@ -511,26 +509,26 @@ T##_marshal_size(const T##_t* restrict this)\ * @param data Output buffer for the marshalled data */\ static inline void __attribute__((unused, nonnull))\ -T##_marshal(const T##_t* restrict this, char* restrict data)\ +T##_marshal(const T##_t *restrict this, char *restrict data)\ {\ - size_t wrote, i, n = this->used;\ - \ - buf_set_next(data, int, HASH_LIST_T_VERSION);\ - buf_set_next(data, size_t, this->allocated);\ - buf_set_next(data, size_t, this->unused);\ - buf_set_next(data, size_t, this->used);\ - buf_set_next(data, size_t, this->last);\ - \ - for (i = 0; i < n; i++)\ - if (this->slots[i].key != NULL)\ - {\ - buf_set_next(data, char, 1);\ - buf_set_next(data, size_t, this->slots[i].key_hash);\ - wrote = T##_submarshal(this->slots + i, data);\ - data += wrote / sizeof(char);\ - }\ - else\ - buf_set_next(data, char, 0);\ + size_t wrote, i, n = this->used;\ + \ + buf_set_next(data, int, HASH_LIST_T_VERSION);\ + buf_set_next(data, size_t, this->allocated);\ + buf_set_next(data, size_t, this->unused);\ + buf_set_next(data, size_t, this->used);\ + buf_set_next(data, size_t, this->last);\ + \ + for (i = 0; i < n; i++) {\ + if (this->slots[i].key) {\ + buf_set_next(data, char, 1);\ + buf_set_next(data, size_t, this->slots[i].key_hash);\ + wrote = T##_submarshal(this->slots + i, data);\ + data += wrote / sizeof(char);\ + } else {\ + buf_set_next(data, char, 0);\ + }\ + }\ }\ \ \ @@ -543,39 +541,38 @@ T##_marshal(const T##_t* restrict this, char* restrict data)\ * Destroy the table on error. */\ static inline int __attribute__((unused, nonnull))\ -T##_unmarshal(T##_t* restrict this, char* restrict data)\ +T##_unmarshal(T##_t *restrict this, char *restrict data)\ {\ - size_t i, n, got;\ - char used;\ - \ - this->freer = NULL;\ - this->hasher = NULL;\ - \ - /* buf_get(data, int, 0, HASH_LIST_T_VERSION); */\ - buf_next(data, int, 1);\ - \ - buf_get_next(data, size_t, this->allocated);\ - buf_get_next(data, size_t, this->unused);\ - buf_get_next(data, size_t, this->used);\ - buf_get_next(data, size_t, this->last);\ - \ - this->slots = calloc(this->allocated, sizeof(T##_entry_t));\ - if (this->slots == NULL)\ - return -1;\ - \ - for (i = 0, n = this->used; i < n; i++)\ - {\ - buf_get_next(data, char, used);\ - if (used == 0)\ - continue;\ - buf_set_next(data, size_t, this->slots[i].key_hash);\ - got = T##_subunmarshal(this->slots + i, data);\ - if (got == 0)\ - return -1;\ - data += got / sizeof(char);\ - }\ - \ - return 0;\ + size_t i, n, got;\ + char used;\ + \ + this->freer = NULL;\ + this->hasher = NULL;\ + \ + /* buf_get(data, int, 0, HASH_LIST_T_VERSION); */\ + buf_next(data, int, 1);\ + \ + buf_get_next(data, size_t, this->allocated);\ + buf_get_next(data, size_t, this->unused);\ + buf_get_next(data, size_t, this->used);\ + buf_get_next(data, size_t, this->last);\ + \ + this->slots = calloc(this->allocated, sizeof(T##_entry_t));\ + if (!this->slots)\ + return -1;\ + \ + for (i = 0, n = this->used; i < n; i++) {\ + buf_get_next(data, char, used);\ + if (!used)\ + continue;\ + buf_set_next(data, size_t, this->slots[i].key_hash);\ + got = T##_subunmarshal(this->slots + i, data);\ + if (!got)\ + return -1;\ + data += got / sizeof(char);\ + }\ + \ + return 0;\ } @@ -586,9 +583,9 @@ T##_unmarshal(T##_t* restrict this, char* restrict data)\ * @param i:size_t The variable to store the buckey index in at each iteration * @param entry:hash_list_enty_t* The variable to store the entry in at each iteration */ -#define foreach_hash_list_entry(this, i, entry) \ - for (i = 0; i < (this).used; i++) \ - if (entry = (this).slots, entry->key != NULL) +#define foreach_hash_list_entry(this, i, entry)\ + for (i = 0; i < (this).used; i++)\ + if ((entry = (this).slots)->key) #endif diff --git a/src/libmdsserver/hash-table.c b/src/libmdsserver/hash-table.c index 000bd20..2a7bc3c 100644 --- a/src/libmdsserver/hash-table.c +++ b/src/libmdsserver/hash-table.c @@ -31,8 +31,8 @@ * @param K The key * @param H The hash of the key */ -#define TEST_KEY(T, B, K, H) \ - ((B->key == K) || (T->key_comparator && (B->hash == H) && T->key_comparator(B->key, K))) +#define TEST_KEY(T, B, K, H)\ + ((B)->key == (K) || ((T)->key_comparator && (B)->hash == (H) && (T)->key_comparator((B)->key, (K)))) /** @@ -42,10 +42,10 @@ * @param key The key to hash * @return The hash of the key */ -__attribute__((pure, nonnull)) -static inline size_t hash(const hash_table_t* restrict this, size_t key) +static inline size_t __attribute__((pure, nonnull)) +hash(const hash_table_t *restrict this, size_t key) { - return this->hasher ? this->hasher(key) : key; + return this->hasher ? this->hasher(key) : key; } @@ -56,10 +56,10 @@ static inline size_t hash(const hash_table_t* restrict this, size_t key) * @param key The key to hash * @return A non-negative value less the the table's capacity */ -__attribute__((pure, nonnull)) -static inline size_t truncate_hash(const hash_table_t* restrict this, size_t hash) +static inline size_t __attribute__((pure, nonnull)) +truncate_hash(const hash_table_t *restrict this, size_t hash) { - return hash % this->capacity; + return hash % this->capacity; } @@ -69,49 +69,42 @@ static inline size_t truncate_hash(const hash_table_t* restrict this, size_t has * @param this The hash table * @return Non-zero on error, `errno` will be set accordingly */ -__attribute__((nonnull)) -static int rehash(hash_table_t* restrict this) +static int __attribute__((nonnull)) +rehash(hash_table_t *restrict this) { - hash_entry_t** old_buckets = this->buckets; - size_t old_capacity = this->capacity; - size_t i = old_capacity, index; - hash_entry_t* bucket; - hash_entry_t* destination; - hash_entry_t* next; - - fail_if (xcalloc(this->buckets, old_capacity * 2 + 1, hash_entry_t*)); - this->capacity = old_capacity * 2 + 1; - this->threshold = (size_t)((float)(this->capacity) * this->load_factor); - - while (i) - { - bucket = this->buckets[--i]; - while (bucket) - { - index = truncate_hash(this, bucket->hash); - if ((destination = this->buckets[index])) - { - next = destination->next; - while (next) - { - destination = next; - next = destination->next; + hash_entry_t **old_buckets = this->buckets; + size_t old_capacity = this->capacity; + size_t i = old_capacity, index; + hash_entry_t *bucket; + hash_entry_t *destination; + hash_entry_t *next; + + fail_if (xcalloc(this->buckets, old_capacity * 2 + 1, hash_entry_t*)); + this->capacity = old_capacity * 2 + 1; + this->threshold = (size_t)((float)(this->capacity) * this->load_factor); + + while (i--) { + bucket = this->buckets[i]; + while (bucket) { + index = truncate_hash(this, bucket->hash); + if ((destination = this->buckets[index])) { + while ((next = destination->next)) + destination = next; + destination->next = bucket; + } else { + this->buckets[index] = bucket; + } + + next = bucket->next; + bucket->next = NULL; + bucket = next; } - destination->next = bucket; - } - else - this->buckets[index] = bucket; - - next = bucket->next; - bucket->next = NULL; - bucket = next; } - } - - free(old_buckets); - return 0; - fail: - return -1; + + free(old_buckets); + return 0; +fail: + return -1; } @@ -123,22 +116,23 @@ static int rehash(hash_table_t* restrict this) * @param load_factor The load factor of the table, i.e. when to grow the table * @return Non-zero on error, `errno` will have been set accordingly */ -int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_capacity, float load_factor) +int +hash_table_create_fine_tuned(hash_table_t *restrict this, size_t initial_capacity, float load_factor) { - this->buckets = NULL; - - this->capacity = initial_capacity ? initial_capacity : 1; - fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*)); - this->load_factor = load_factor; - this->threshold = (size_t)((float)(this->capacity) * load_factor); - this->size = 0; - this->value_comparator = NULL; - this->key_comparator = NULL; - this->hasher = NULL; - - return 0; - fail: - return -1; + this->buckets = NULL; + + this->capacity = initial_capacity ? initial_capacity : 1; + fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*)); + this->load_factor = load_factor; + this->threshold = (size_t)((float)(this->capacity) * load_factor); + this->size = 0; + this->value_comparator = NULL; + this->key_comparator = NULL; + this->hasher = NULL; + + return 0; +fail: + return -1; } @@ -150,27 +144,24 @@ int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_cap * @param keys_freer Function that frees a key, `NULL` if keys should not be freed * @param values_freer Function that frees a value, `NULL` if value should not be freed */ -void hash_table_destroy(hash_table_t* restrict this, free_func* key_freer, free_func* value_freer) +void +hash_table_destroy(hash_table_t *restrict this, free_func *key_freer, free_func *value_freer) { - size_t i = this->capacity; - hash_entry_t* bucket; - hash_entry_t* last; - - if (this->buckets != NULL) - { - while (i) - { - bucket = this->buckets[--i]; - while (bucket) - { - if (key_freer != NULL) key_freer(bucket->key); - if (value_freer != NULL) value_freer(bucket->value); - bucket = (last = bucket)->next; - free(last); - } + size_t i = this->capacity; + hash_entry_t *bucket, *last; + + if (this->buckets) { + while (i) { + bucket = this->buckets[--i]; + while (bucket) { + if (key_freer) key_freer(bucket->key); + if (value_freer) value_freer(bucket->value); + bucket = (last = bucket)->next; + free(last); + } + } + free(this->buckets); } - free(this->buckets); - } } @@ -181,25 +172,24 @@ void hash_table_destroy(hash_table_t* restrict this, free_func* key_freer, free_ * @param value The value * @return Whether the value is stored in the table */ -int hash_table_contains_value(const hash_table_t* restrict this, size_t value) +int +hash_table_contains_value(const hash_table_t *restrict this, size_t value) { - size_t i = this->capacity; - hash_entry_t* restrict bucket; - - while (i) - { - bucket = this->buckets[--i]; - while (bucket != NULL) - { - if (bucket->value == value) - return 1; - if (this->value_comparator && this->value_comparator(bucket->value, value)) - return 1; - bucket = bucket->next; + size_t i = this->capacity; + hash_entry_t *restrict bucket; + + while (i--) { + bucket = this->buckets[i]; + while (bucket) { + if (bucket->value == value) + return 1; + if (this->value_comparator && this->value_comparator(bucket->value, value)) + return 1; + bucket = bucket->next; + } } - } - - return 0; + + return 0; } @@ -210,20 +200,20 @@ int hash_table_contains_value(const hash_table_t* restrict this, size_t value) * @param key The key * @return Whether the key is used */ -int hash_table_contains_key(const hash_table_t* restrict this, size_t key) +int +hash_table_contains_key(const hash_table_t *restrict this, size_t key) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* restrict bucket = this->buckets[index]; - - while (bucket) - { - if (TEST_KEY(this, bucket, key, key_hash)) - return 1; - bucket = bucket->next; - } - - return 0; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *restrict bucket = this->buckets[index]; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) + return 1; + bucket = bucket->next; + } + + return 0; } @@ -234,20 +224,20 @@ int hash_table_contains_key(const hash_table_t* restrict this, size_t key) * @param key The key associated with the value * @return The value associated with the key, 0 if the key was not used */ -size_t hash_table_get(const hash_table_t* restrict this, size_t key) +size_t +hash_table_get(const hash_table_t *restrict this, size_t key) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* restrict bucket = this->buckets[index]; - - while (bucket) - { - if (TEST_KEY(this, bucket, key, key_hash)) - return bucket->value; - bucket = bucket->next; - } - - return 0; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *restrict bucket = this->buckets[index]; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) + return bucket->value; + bucket = bucket->next; + } + + return 0; } @@ -258,20 +248,20 @@ size_t hash_table_get(const hash_table_t* restrict this, size_t key) * @param key The key associated with the value * @return The entry associated with the key, `NULL` if the key was not used */ -hash_entry_t* hash_table_get_entry(const hash_table_t* restrict this, size_t key) +hash_entry_t * +hash_table_get_entry(const hash_table_t *restrict this, size_t key) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* restrict bucket = this->buckets[index]; - - while (bucket) - { - if (TEST_KEY(this, bucket, key, key_hash)) - return bucket; - bucket = bucket->next; - } - - return NULL; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *restrict bucket = this->buckets[index]; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) + return bucket; + bucket = bucket->next; + } + + return NULL; } @@ -284,41 +274,41 @@ hash_entry_t* hash_table_get_entry(const hash_table_t* restrict this, size_t key * @return The previous value associated with the key, 0 if the key was not used. * 0 will also be returned on error, check the `errno` variable. */ -size_t hash_table_put(hash_table_t* restrict this, size_t key, size_t value) +size_t +hash_table_put(hash_table_t *restrict this, size_t key, size_t value) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* restrict bucket = this->buckets[index]; - size_t rc; - - while (bucket) - if (TEST_KEY(this, bucket, key, key_hash)) - { - rc = bucket->value; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *restrict bucket = this->buckets[index]; + size_t rc; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) { + rc = bucket->value; + bucket->value = value; + return rc; + } else { + bucket = bucket->next; + } + } + + if (++(this->size) > this->threshold) { + errno = 0; + fail_if (rehash(this)); + index = truncate_hash(this, key_hash); + } + + errno = 0; + fail_if (xmalloc(bucket, 1, hash_entry_t)); bucket->value = value; - return rc; - } - else - bucket = bucket->next; - - if (++(this->size) > this->threshold) - { - errno = 0; - fail_if (rehash(this)); - index = truncate_hash(this, key_hash); - } - - errno = 0; - fail_if (xmalloc(bucket, 1, hash_entry_t)); - bucket->value = value; - bucket->key = key; - bucket->hash = key_hash; - bucket->next = this->buckets[index]; - this->buckets[index] = bucket; - - return 0; - fail: - return 0; + bucket->key = key; + bucket->hash = key_hash; + bucket->next = this->buckets[index]; + this->buckets[index] = bucket; + + return 0; +fail: + return 0; } @@ -329,32 +319,31 @@ size_t hash_table_put(hash_table_t* restrict this, size_t key, size_t value) * @param key The key of the entry to remove * @return The previous value associated with the key, 0 if the key was not used */ -size_t hash_table_remove(hash_table_t* restrict this, size_t key) +size_t +hash_table_remove(hash_table_t *restrict this, size_t key) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* bucket = this->buckets[index]; - hash_entry_t* last = NULL; - size_t rc; - - while (bucket) - { - if (TEST_KEY(this, bucket, key, key_hash)) - { - if (last == NULL) - this->buckets[index] = bucket->next; - else - last->next = bucket->next; - this->size--; - rc = bucket->value; - free(bucket); - return rc; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *bucket = this->buckets[index]; + hash_entry_t *last = NULL; + size_t rc; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) { + if (!last) + this->buckets[index] = bucket->next; + else + last->next = bucket->next; + this->size--; + rc = bucket->value; + free(bucket); + return rc; + } + last = bucket; + bucket = bucket->next; } - last = bucket; - bucket = bucket->next; - } - - return 0; + + return 0; } @@ -363,32 +352,29 @@ size_t hash_table_remove(hash_table_t* restrict this, size_t key) * * @param this The hash table */ -void hash_table_clear(hash_table_t* restrict this) +void +hash_table_clear(hash_table_t *restrict this) { - hash_entry_t** buf; - hash_entry_t* bucket; - size_t i, ptr; - - if (this->size) - { - buf = alloca((this->size + 1) * sizeof(hash_entry_t*)); - i = this->capacity; - while (i) - { - bucket = this->buckets[--i]; - ptr = 0; - buf[ptr++] = bucket; - while (bucket) - { - bucket = bucket->next; - buf[ptr++] = bucket; - } - while (ptr) - free(buf[--ptr]); - this->buckets[i] = NULL; + hash_entry_t **buf, *bucket; + size_t i, ptr; + + if (this->size) { + buf = alloca((this->size + 1) * sizeof(hash_entry_t*)); + i = this->capacity; + while (i--) { + bucket = this->buckets[i]; + ptr = 0; + buf[ptr++] = bucket; + while (bucket) { + bucket = bucket->next; + buf[ptr++] = bucket; + } + while (ptr) + free(buf[--ptr]); + this->buckets[i] = NULL; + } + this->size = 0; } - this->size = 0; - } } @@ -398,23 +384,23 @@ void hash_table_clear(hash_table_t* restrict this) * @param this The hash table * @return The number of bytes to allocate to the output buffer */ -size_t hash_table_marshal_size(const hash_table_t* restrict this) +size_t +hash_table_marshal_size(const hash_table_t *restrict this) { - size_t n = this->capacity; - size_t rc = 3 * sizeof(size_t) + sizeof(float) + n * sizeof(size_t); - size_t i, m = 0; - - for (i = 0; i < n; i++) - { - hash_entry_t* restrict bucket = this->buckets[i]; - while (bucket != NULL) - { - bucket = bucket->next; - m++; + size_t n = this->capacity; + size_t rc = 3 * sizeof(size_t) + sizeof(float) + n * sizeof(size_t); + size_t i, m = 0; + hash_entry_t *restrict bucket; + + for (i = 0; i < n; i++) { + bucket = this->buckets[i]; + while (bucket) { + bucket = bucket->next; + m++; + } } - } - - return rc + m * 3 * sizeof(size_t) + sizeof(int); + + return rc + m * 3 * sizeof(size_t) + sizeof(int); } @@ -424,31 +410,31 @@ size_t hash_table_marshal_size(const hash_table_t* restrict this) * @param this The hash table * @param data Output buffer for the marshalled data */ -void hash_table_marshal(const hash_table_t* restrict this, char* restrict data) +void +hash_table_marshal(const hash_table_t *restrict this, char *restrict data) { - size_t i, n = this->capacity; - - buf_set_next(data, int, HASH_TABLE_T_VERSION); - buf_set_next(data, size_t, this->capacity); - buf_set_next(data, float, this->load_factor); - buf_set_next(data, size_t, this->threshold); - buf_set_next(data, size_t, this->size); - - for (i = 0; i < n; i++) - { - hash_entry_t* restrict bucket = this->buckets[i]; - size_t m = 0; - while (bucket != NULL) - { - buf_set(data, size_t, 1 + m * 3 + 0, bucket->key); - buf_set(data, size_t, 1 + m * 3 + 1, bucket->value); - buf_set(data, size_t, 1 + m * 3 + 2, bucket->hash); - bucket = bucket->next; - m++; + size_t i, n = this->capacity, m; + hash_entry_t *restrict bucket; + + buf_set_next(data, int, HASH_TABLE_T_VERSION); + buf_set_next(data, size_t, this->capacity); + buf_set_next(data, float, this->load_factor); + buf_set_next(data, size_t, this->threshold); + buf_set_next(data, size_t, this->size); + + for (i = 0; i < n; i++) { + bucket = this->buckets[i]; + m = 0; + while (bucket) { + buf_set(data, size_t, 1 + m * 3 + 0, bucket->key); + buf_set(data, size_t, 1 + m * 3 + 1, bucket->value); + buf_set(data, size_t, 1 + m * 3 + 2, bucket->hash); + bucket = bucket->next; + m++; + } + buf_set(data, size_t, 0, m); + buf_next(data, size_t, 1 + m * 3); } - buf_set(data, size_t, 0, m); - buf_next(data, size_t, 1 + m * 3); - } } @@ -461,48 +447,45 @@ void hash_table_marshal(const hash_table_t* restrict this, char* restrict data) * @return Non-zero on error, `errno` will be set accordingly. * Destroy the table on error. */ -int hash_table_unmarshal(hash_table_t* restrict this, char* restrict data, remap_func* remapper) +int +hash_table_unmarshal(hash_table_t *restrict this, char *restrict data, remap_func *remapper) { - size_t i, n; - - /* buf_get(data, int, 0, HASH_TABLE_T_VERSION); */ - buf_next(data, int, 1); - - this->value_comparator = NULL; - this->key_comparator = NULL; - this->hasher = NULL; - - buf_get_next(data, size_t, this->capacity = n); - buf_get_next(data, float, this->load_factor); - buf_get_next(data, size_t, this->threshold); - buf_get_next(data, size_t, this->size); - - fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*)); - - for (i = 0; i < n; i++) - { - size_t m; - hash_entry_t* restrict bucket; - buf_get_next(data, size_t, m); - - fail_if (xmalloc(this->buckets[i] = bucket, 1, hash_entry_t)); - - while (m--) - { - if (m == 0) - bucket->next = NULL; - else - fail_if (xmalloc(bucket->next, 1, hash_entry_t)); - buf_get_next(data, size_t, bucket->key); - buf_get_next(data, size_t, bucket->value); - if (remapper != NULL) - bucket->value = remapper(bucket->value); - buf_get_next(data, size_t, bucket->hash); + size_t i, n, m; + hash_entry_t *restrict bucket; + + /* buf_get(data, int, 0, HASH_TABLE_T_VERSION); */ + buf_next(data, int, 1); + + this->value_comparator = NULL; + this->key_comparator = NULL; + this->hasher = NULL; + + buf_get_next(data, size_t, this->capacity = n); + buf_get_next(data, float, this->load_factor); + buf_get_next(data, size_t, this->threshold); + buf_get_next(data, size_t, this->size); + + fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*)); + + for (i = 0; i < n; i++) { + buf_get_next(data, size_t, m); + + fail_if (xmalloc(this->buckets[i] = bucket, 1, hash_entry_t)); + + while (m--) { + if (!m) + bucket->next = NULL; + else + fail_if (xmalloc(bucket->next, 1, hash_entry_t)); + buf_get_next(data, size_t, bucket->key); + buf_get_next(data, size_t, bucket->value); + if (remapper) + bucket->value = remapper(bucket->value); + buf_get_next(data, size_t, bucket->hash); + } } - } - - return 0; - fail: - return -1; -} + return 0; +fail: + return -1; +} diff --git a/src/libmdsserver/linked-list.c b/src/libmdsserver/linked-list.c index 401a726..954c6fe 100644 --- a/src/libmdsserver/linked-list.c +++ b/src/libmdsserver/linked-list.c @@ -27,7 +27,7 @@ * The default initial capacity */ #ifndef LINKED_LIST_DEFAULT_INITIAL_CAPACITY -# define LINKED_LIST_DEFAULT_INITIAL_CAPACITY 128 +# define LINKED_LIST_DEFAULT_INITIAL_CAPACITY 128 #endif @@ -38,19 +38,19 @@ * @param value The value to be rounded up to a power of two * @return The nearest, but not smaller, power of two */ -__attribute__((const)) -static size_t to_power_of_two(size_t value) +static size_t __attribute__((const)) +to_power_of_two(size_t value) { - value -= 1; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; + value -= 1; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; #if SIZE_MAX == UINT64_MAX - value |= value >> 32; + value |= value >> 32; #endif - return value + 1; + return value + 1; } @@ -61,32 +61,33 @@ static size_t to_power_of_two(size_t value) * @param capacity The minimum initial capacity of the linked list, 0 for default * @return Non-zero on error, `errno` will have been set accordingly */ -int linked_list_create(linked_list_t* restrict this, size_t capacity) +int +linked_list_create(linked_list_t *restrict this, size_t capacity) { - /* Use default capacity of zero is specified. */ - if (capacity == 0) - capacity = LINKED_LIST_DEFAULT_INITIAL_CAPACITY; - - /* Initialise the linked list. */ - this->capacity = capacity = to_power_of_two(capacity); - this->edge = 0; - this->end = 1; - this->reuse_head = 0; - this->reusable = NULL; - this->values = NULL; - this->next = NULL; - this->previous = NULL; - fail_if (xmalloc(this->reusable, capacity, ssize_t)); - fail_if (xmalloc(this->values, capacity, size_t)); - fail_if (xmalloc(this->next, capacity, ssize_t)); - fail_if (xmalloc(this->previous, capacity, ssize_t)); - this->values[this->edge] = 0; - this->next[this->edge] = this->edge; - this->previous[this->edge] = this->edge; - - return 0; - fail: - return -1; + /* Use default capacity of zero is specified. */ + if (!capacity) + capacity = LINKED_LIST_DEFAULT_INITIAL_CAPACITY; + + /* Initialise the linked list. */ + this->capacity = capacity = to_power_of_two(capacity); + this->edge = 0; + this->end = 1; + this->reuse_head = 0; + this->reusable = NULL; + this->values = NULL; + this->next = NULL; + this->previous = NULL; + fail_if (xmalloc(this->reusable, capacity, ssize_t)); + fail_if (xmalloc(this->values, capacity, size_t)); + fail_if (xmalloc(this->next, capacity, ssize_t)); + fail_if (xmalloc(this->previous, capacity, ssize_t)); + this->values[this->edge] = 0; + this->next[this->edge] = this->edge; + this->previous[this->edge] = this->edge; + + return 0; +fail: + return -1; } @@ -96,12 +97,13 @@ int linked_list_create(linked_list_t* restrict this, size_t capacity) * * @param this The linked list */ -void linked_list_destroy(linked_list_t* restrict this) +void +linked_list_destroy(linked_list_t *restrict this) { - free(this->reusable), this->reusable = NULL; - free(this->values), this->values = NULL; - free(this->next), this->next = NULL; - free(this->previous), this->previous = NULL; + free(this->reusable), this->reusable = NULL; + free(this->values), this->values = NULL; + free(this->next), this->next = NULL; + free(this->previous), this->previous = NULL; } @@ -112,22 +114,23 @@ void linked_list_destroy(linked_list_t* restrict this) * @param out Memory slot in which to store the new linked list * @return Non-zero on error, `errno` will have been set accordingly */ -int linked_list_clone(const linked_list_t* restrict this, linked_list_t* restrict out) +int +linked_list_clone(const linked_list_t *restrict this, linked_list_t *restrict out) { - fail_if (xmemdup(out->values, this->values, this->capacity, size_t)); - fail_if (xmemdup(out->next, this->next, this->capacity, ssize_t)); - fail_if (xmemdup(out->previous, this->previous, this->capacity, ssize_t)); - fail_if (xmemdup(out->reusable, this->reusable, this->capacity, ssize_t)); - - out->capacity = this->capacity; - out->end = this->end; - out->reuse_head = this->reuse_head; - out->edge = this->edge; - - return 0; - - fail: - return -1; + fail_if (xmemdup(out->values, this->values, this->capacity, size_t)); + fail_if (xmemdup(out->next, this->next, this->capacity, ssize_t)); + fail_if (xmemdup(out->previous, this->previous, this->capacity, ssize_t)); + fail_if (xmemdup(out->reusable, this->reusable, this->capacity, ssize_t)); + + out->capacity = this->capacity; + out->end = this->end; + out->reuse_head = this->reuse_head; + out->edge = this->edge; + + return 0; + +fail: + return -1; } @@ -145,64 +148,64 @@ int linked_list_clone(const linked_list_t* restrict this, linked_list_t* restric * @param this The list * @return Non-zero on error, `errno` will have been set accordingly */ -int linked_list_pack(linked_list_t* restrict this) +int +linked_list_pack(linked_list_t *restrict this) { - ssize_t* restrict new_next = NULL; - ssize_t* restrict new_previous = NULL; - ssize_t* restrict new_reusable = NULL; - size_t size = this->end - this->reuse_head; - size_t cap = to_power_of_two(size); - ssize_t head = 0; - size_t i = 0; - ssize_t node; - size_t* restrict vals; - int saved_errno; - - fail_if (xmalloc(vals, cap, size_t)); - while (((size_t)head != this->end) && (this->next[head] == LINKED_LIST_UNUSED)) - head++; - if ((size_t)head != this->end) - for (node = head; (node != head) || (i == 0); i++) - { - vals[i] = this->values[node]; - node = this->next[node]; - } - - if (cap != this->capacity) - { - fail_if (xmalloc(new_next, cap, ssize_t)); - fail_if (xmalloc(new_previous, cap, ssize_t)); - fail_if (xmalloc(new_reusable, cap, ssize_t)); - - free(this->next); - free(this->previous); - free(this->reusable); - - this->next = new_next; - this->previous = new_previous; - this->reusable = new_reusable; - } - - for (i = 0; i < size; i++) - this->next[i] = (ssize_t)(i + 1); - this->next[size - 1] = 0; - - for (i = 1; i < size; i++) - this->previous[i] = (ssize_t)(i - 1); - this->previous[0] = (ssize_t)(size - 1); - - this->values = vals; - this->end = size; - this->reuse_head = 0; - - return 0; - - fail: - saved_errno = errno; - free(vals); - free(new_next); - free(new_previous); - return errno = saved_errno, -1; + ssize_t *restrict new_next = NULL; + ssize_t *restrict new_previous = NULL; + ssize_t *restrict new_reusable = NULL; + size_t size = this->end - this->reuse_head; + size_t cap = to_power_of_two(size); + ssize_t head = 0; + size_t i = 0; + ssize_t node; + size_t *restrict vals; + int saved_errno; + + fail_if (xmalloc(vals, cap, size_t)); + while ((size_t)head != this->end && this->next[head] == LINKED_LIST_UNUSED) + head++; + if ((size_t)head != this->end) { + for (node = head; (node != head) || (i == 0); i++) { + vals[i] = this->values[node]; + node = this->next[node]; + } + } + + if (cap != this->capacity) { + fail_if (xmalloc(new_next, cap, ssize_t)); + fail_if (xmalloc(new_previous, cap, ssize_t)); + fail_if (xmalloc(new_reusable, cap, ssize_t)); + + free(this->next); + free(this->previous); + free(this->reusable); + + this->next = new_next; + this->previous = new_previous; + this->reusable = new_reusable; + } + + for (i = 0; i < size; i++) + this->next[i] = (ssize_t)(i + 1); + this->next[size - 1] = 0; + + for (i = 1; i < size; i++) + this->previous[i] = (ssize_t)(i - 1); + this->previous[0] = (ssize_t)(size - 1); + + this->values = vals; + this->end = size; + this->reuse_head = 0; + + return 0; + +fail: + saved_errno = errno; + free(vals); + free(new_next); + free(new_previous); + return errno = saved_errno, -1; } @@ -215,29 +218,28 @@ int linked_list_pack(linked_list_t* restrict this) * @return The next free position, * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ -__attribute__((nonnull)) -static ssize_t linked_list_get_next(linked_list_t* restrict this) +static ssize_t __attribute__((nonnull)) +linked_list_get_next(linked_list_t *restrict this) { - size_t* tmp_values; - ssize_t* tmp; - - if (this->reuse_head > 0) - return this->reusable[--(this->reuse_head)]; - if (this->end == this->capacity) - { - if ((ssize_t)(this->end) < 0) - fail_if ((errno = ENOMEM)); - - this->capacity <<= 1; - - fail_if (yrealloc(tmp_values, this->values, this->capacity, size_t)); - fail_if (yrealloc(tmp, this->next, this->capacity, ssize_t)); - fail_if (yrealloc(tmp, this->previous, this->capacity, ssize_t)); - fail_if (yrealloc(tmp, this->reusable, this->capacity, ssize_t)); - } - return (ssize_t)(this->end++); - fail: - return LINKED_LIST_UNUSED; + size_t *tmp_values; + ssize_t *tmp; + + if (this->reuse_head > 0) + return this->reusable[--(this->reuse_head)]; + if (this->end == this->capacity) { + if ((ssize_t)(this->end) < 0) + fail_if ((errno = ENOMEM)); + + this->capacity <<= 1; + + fail_if (yrealloc(tmp_values, this->values, this->capacity, size_t)); + fail_if (yrealloc(tmp, this->next, this->capacity, ssize_t)); + fail_if (yrealloc(tmp, this->previous, this->capacity, ssize_t)); + fail_if (yrealloc(tmp, this->reusable, this->capacity, ssize_t)); + } + return (ssize_t)(this->end++); +fail: + return LINKED_LIST_UNUSED; } @@ -248,15 +250,15 @@ static ssize_t linked_list_get_next(linked_list_t* restrict this) * @param node The position * @return The position */ -__attribute__((nonnull)) -static ssize_t linked_list_unuse(linked_list_t* restrict this, ssize_t node) +static ssize_t __attribute__((nonnull)) +linked_list_unuse(linked_list_t *restrict this, ssize_t node) { - if (node < 0) - return node; - this->reusable[this->reuse_head++] = node; - this->next[node] = LINKED_LIST_UNUSED; - this->previous[node] = LINKED_LIST_UNUSED; - return node; + if (node < 0) + return node; + this->reusable[this->reuse_head++] = node; + this->next[node] = LINKED_LIST_UNUSED; + this->previous[node] = LINKED_LIST_UNUSED; + return node; } @@ -269,18 +271,19 @@ static ssize_t linked_list_unuse(linked_list_t* restrict this, ssize_t node) * @return The node that has been created and inserted, * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ -ssize_t linked_list_insert_after(linked_list_t* this, size_t value, ssize_t predecessor) +ssize_t +linked_list_insert_after(linked_list_t *this, size_t value, ssize_t predecessor) { - ssize_t node = linked_list_get_next(this); - fail_if (node == LINKED_LIST_UNUSED); - this->values[node] = value; - this->next[node] = this->next[predecessor]; - this->next[predecessor] = node; - this->previous[node] = predecessor; - this->previous[this->next[node]] = node; - return node; - fail: - return LINKED_LIST_UNUSED; + ssize_t node = linked_list_get_next(this); + fail_if (node == LINKED_LIST_UNUSED); + this->values[node] = value; + this->next[node] = this->next[predecessor]; + this->next[predecessor] = node; + this->previous[node] = predecessor; + this->previous[this->next[node]] = node; + return node; +fail: + return LINKED_LIST_UNUSED; } @@ -291,12 +294,13 @@ ssize_t linked_list_insert_after(linked_list_t* this, size_t value, ssize_t pred * @param predecessor The reference node * @return The node that has been removed */ -ssize_t linked_list_remove_after(linked_list_t* restrict this, ssize_t predecessor) +ssize_t +linked_list_remove_after(linked_list_t *restrict this, ssize_t predecessor) { - ssize_t node = this->next[predecessor]; - this->next[predecessor] = this->next[node]; - this->previous[this->next[node]] = predecessor; - return linked_list_unuse(this, node); + ssize_t node = this->next[predecessor]; + this->next[predecessor] = this->next[node]; + this->previous[this->next[node]] = predecessor; + return linked_list_unuse(this, node); } @@ -309,18 +313,19 @@ ssize_t linked_list_remove_after(linked_list_t* restrict this, ssize_t predecess * @return The node that has been created and inserted, * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ -ssize_t linked_list_insert_before(linked_list_t* restrict this, size_t value, ssize_t successor) +ssize_t +linked_list_insert_before(linked_list_t *restrict this, size_t value, ssize_t successor) { - ssize_t node = linked_list_get_next(this); - fail_if (node == LINKED_LIST_UNUSED); - this->values[node] = value; - this->previous[node] = this->previous[successor]; - this->previous[successor] = node; - this->next[node] = successor; - this->next[this->previous[node]] = node; - return node; - fail: - return LINKED_LIST_UNUSED; + ssize_t node = linked_list_get_next(this); + fail_if (node == LINKED_LIST_UNUSED); + this->values[node] = value; + this->previous[node] = this->previous[successor]; + this->previous[successor] = node; + this->next[node] = successor; + this->next[this->previous[node]] = node; + return node; +fail: + return LINKED_LIST_UNUSED; } @@ -331,12 +336,13 @@ ssize_t linked_list_insert_before(linked_list_t* restrict this, size_t value, ss * @param successor The reference node * @return The node that has been removed */ -ssize_t linked_list_remove_before(linked_list_t* restrict this, ssize_t successor) +ssize_t +linked_list_remove_before(linked_list_t *restrict this, ssize_t successor) { - ssize_t node = this->previous[successor]; - this->previous[successor] = this->previous[node]; - this->next[this->previous[node]] = successor; - return linked_list_unuse(this, node); + ssize_t node = this->previous[successor]; + this->previous[successor] = this->previous[node]; + this->next[this->previous[node]] = successor; + return linked_list_unuse(this, node); } @@ -346,11 +352,12 @@ ssize_t linked_list_remove_before(linked_list_t* restrict this, ssize_t successo * @param this The list * @param node The node to remove */ -void linked_list_remove(linked_list_t* restrict this, ssize_t node) +void +linked_list_remove(linked_list_t *restrict this, ssize_t node) { - this->next[this->previous[node]] = this->next[node]; - this->previous[this->next[node]] = this->previous[node]; - linked_list_unuse(this, node); + this->next[this->previous[node]] = this->next[node]; + this->previous[this->next[node]] = this->previous[node]; + linked_list_unuse(this, node); } @@ -360,9 +367,10 @@ void linked_list_remove(linked_list_t* restrict this, ssize_t node) * @param this The list * @return The number of bytes to allocate to the output buffer */ -size_t linked_list_marshal_size(const linked_list_t* restrict this) +size_t +linked_list_marshal_size(const linked_list_t *restrict this) { - return sizeof(size_t) * (4 + this->reuse_head + 3 * this->end) + sizeof(int); + return sizeof(size_t) * (4 + this->reuse_head + 3 * this->end) + sizeof(int); } @@ -372,27 +380,28 @@ size_t linked_list_marshal_size(const linked_list_t* restrict this) * @param this The list * @param data Output buffer for the marshalled data */ -void linked_list_marshal(const linked_list_t* restrict this, char* restrict data) +void +linked_list_marshal(const linked_list_t *restrict this, char *restrict data) { - buf_set(data, int, 0, LINKED_LIST_T_VERSION); - buf_next(data, int, 1); - - buf_set(data, size_t, 0, this->capacity); - buf_set(data, size_t, 1, this->end); - buf_set(data, size_t, 2, this->reuse_head); - buf_set(data, ssize_t, 3, this->edge); - buf_next(data, size_t, 4); - - memcpy(data, this->reusable, this->reuse_head * sizeof(ssize_t)); - buf_next(data, ssize_t, this->reuse_head); - - memcpy(data, this->values, this->end * sizeof(size_t)); - buf_next(data, size_t, this->end); - - memcpy(data, this->next, this->end * sizeof(ssize_t)); - buf_next(data, ssize_t, this->end); - - memcpy(data, this->previous, this->end * sizeof(ssize_t)); + buf_set(data, int, 0, LINKED_LIST_T_VERSION); + buf_next(data, int, 1); + + buf_set(data, size_t, 0, this->capacity); + buf_set(data, size_t, 1, this->end); + buf_set(data, size_t, 2, this->reuse_head); + buf_set(data, ssize_t, 3, this->edge); + buf_next(data, size_t, 4); + + memcpy(data, this->reusable, this->reuse_head * sizeof(ssize_t)); + buf_next(data, ssize_t, this->reuse_head); + + memcpy(data, this->values, this->end * sizeof(size_t)); + buf_next(data, size_t, this->end); + + memcpy(data, this->next, this->end * sizeof(ssize_t)); + buf_next(data, ssize_t, this->end); + + memcpy(data, this->previous, this->end * sizeof(ssize_t)); } @@ -404,41 +413,42 @@ void linked_list_marshal(const linked_list_t* restrict this, char* restrict data * @return Non-zero on error, `errno` will be set accordingly. * Destroy the list on error. */ -int linked_list_unmarshal(linked_list_t* restrict this, char* restrict data) +int +linked_list_unmarshal(linked_list_t *restrict this, char *restrict data) { - /* buf_get(data, int, 0, LINKED_LIST_T_VERSION); */ - buf_next(data, int, 1); - - this->reusable = NULL; - this->values = NULL; - this->next = NULL; - this->previous = NULL; - - buf_get(data, size_t, 0, this->capacity); - buf_get(data, size_t, 1, this->end); - buf_get(data, size_t, 2, this->reuse_head); - buf_get(data, ssize_t, 3, this->edge); - buf_next(data, size_t, 4); - - fail_if (xmalloc(this->reusable, this->capacity, size_t)); - fail_if (xmalloc(this->values, this->capacity, size_t)); - fail_if (xmalloc(this->next, this->capacity, size_t)); - fail_if (xmalloc(this->previous, this->capacity, size_t)); - - memcpy(this->reusable, data, this->reuse_head * sizeof(ssize_t)); - buf_next(data, ssize_t, this->reuse_head); - - memcpy(this->values, data, this->end * sizeof(size_t)); - buf_next(data, size_t, this->end); - - memcpy(this->next, data, this->end * sizeof(ssize_t)); - buf_next(data, ssize_t, this->end); - - memcpy(this->previous, data, this->end * sizeof(ssize_t)); - - return 0; - fail: - return -1; + /* buf_get(data, int, 0, LINKED_LIST_T_VERSION); */ + buf_next(data, int, 1); + + this->reusable = NULL; + this->values = NULL; + this->next = NULL; + this->previous = NULL; + + buf_get(data, size_t, 0, this->capacity); + buf_get(data, size_t, 1, this->end); + buf_get(data, size_t, 2, this->reuse_head); + buf_get(data, ssize_t, 3, this->edge); + buf_next(data, size_t, 4); + + fail_if (xmalloc(this->reusable, this->capacity, size_t)); + fail_if (xmalloc(this->values, this->capacity, size_t)); + fail_if (xmalloc(this->next, this->capacity, size_t)); + fail_if (xmalloc(this->previous, this->capacity, size_t)); + + memcpy(this->reusable, data, this->reuse_head * sizeof(ssize_t)); + buf_next(data, ssize_t, this->reuse_head); + + memcpy(this->values, data, this->end * sizeof(size_t)); + buf_next(data, size_t, this->end); + + memcpy(this->next, data, this->end * sizeof(ssize_t)); + buf_next(data, ssize_t, this->end); + + memcpy(this->previous, data, this->end * sizeof(ssize_t)); + + return 0; +fail: + return -1; } @@ -448,31 +458,31 @@ int linked_list_unmarshal(linked_list_t* restrict this, char* restrict data) * @param this The list * @param output Output file */ -void linked_list_dump(linked_list_t* restrict this, FILE* restrict output) +void +linked_list_dump(linked_list_t *restrict this, FILE *restrict output) { - ssize_t i; - size_t j; - fprintf(output, "======= LINKED LIST DUMP =======\n"); - fprintf(output, "Capacity: %zu\n", this->capacity); - fprintf(output, "End: %zu\n", this->end); - fprintf(output, "Reuse head: %zu\n", this->reuse_head); - fprintf(output, "Edge: %zi\n", this->edge); - fprintf(output, "--------------------------------\n"); - fprintf(output, "Node table (Next, Prev, Value):\n"); - i = this->edge; - fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); - foreach_linked_list_node((*this), i) - fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); - i = this->edge; - fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); - fprintf(output, "--------------------------------\n"); - fprintf(output, "Raw node table:\n"); - for (j = 0; j < this->end; j++) - fprintf(output, " %zu: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); - fprintf(output, "--------------------------------\n"); - fprintf(output, "Reuse stack:\n"); - for (j = 0; j < this->reuse_head; j++) - fprintf(output, " %zu: %zi\n", j, this->reusable[j]); - fprintf(output, "================================\n"); + ssize_t i; + size_t j; + fprintf(output, "======= LINKED LIST DUMP =======\n"); + fprintf(output, "Capacity: %zu\n", this->capacity); + fprintf(output, "End: %zu\n", this->end); + fprintf(output, "Reuse head: %zu\n", this->reuse_head); + fprintf(output, "Edge: %zi\n", this->edge); + fprintf(output, "--------------------------------\n"); + fprintf(output, "Node table (Next, Prev, Value):\n"); + i = this->edge; + fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); + foreach_linked_list_node((*this), i) + fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); + i = this->edge; + fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); + fprintf(output, "--------------------------------\n"); + fprintf(output, "Raw node table:\n"); + for (j = 0; j < this->end; j++) + fprintf(output, " %zu: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); + fprintf(output, "--------------------------------\n"); + fprintf(output, "Reuse stack:\n"); + for (j = 0; j < this->reuse_head; j++) + fprintf(output, " %zu: %zi\n", j, this->reusable[j]); + fprintf(output, "================================\n"); } - diff --git a/src/libmdsserver/macros.h b/src/libmdsserver/macros.h index d4d588c..45412b9 100644 --- a/src/libmdsserver/macros.h +++ b/src/libmdsserver/macros.h @@ -44,24 +44,22 @@ /* CLOCK_MONOTONIC_RAW is a Linux-specific bug-fix */ #ifndef CLOCK_MONOTONIC_RAW -# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC +# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC #endif /* Define TEMP_FAILURE_RETRY if not defined, however * this version does not return a value, it will hoever * clear `errno` if no error occurs. */ #ifndef TEMP_FAILURE_RETRY -# define TEMP_FAILURE_RETRY(expression) \ - do \ - { \ - ssize_t __result; \ - do \ - __result = (ssize_t)(expression); \ - while ((__result < 0) && (errno == EINTR)); \ - if (__result >= 0) \ - errno = 0; \ - } \ - while (0) +# define TEMP_FAILURE_RETRY(expression)\ + do {\ + ssize_t __result;\ + do\ + __result = (ssize_t)(expression);\ + while (__result < 0 && errno == EINTR);\ + if (__result >= 0)\ + errno = 0;\ + } while (0) # define MDS_LIBMDSSERVER_MACROS_DEFINED_TEMP_FAILURE_RETRY #endif @@ -118,16 +116,16 @@ * @param ...:const char*, ... The format string and arguments * @return :int Zero on success, -1 on error */ -#define xasprintf(VAR, ...) \ - (asprintf(&(VAR), __VA_ARGS__) < 0 ? (VAR = NULL, -1) : 0) +#define xasprintf(VAR, ...)\ + (asprintf(&(VAR), __VA_ARGS__) < 0 ? (VAR = NULL, -1) : 0) /* -#define xasprintf(VAR, ...) \ - ({ \ - int _x_rc = (asprintf(&(VAR), __VA_ARGS__) < 0 ? (VAR = NULL, -1) : 0); \ - fprintf(stderr, "xasprintf(%s, %s)(=%zu) @ %s:%i\n", \ - #VAR, #__VA_ARGS__, _x_rc ? 0 : (strlen(VAR) + 1), __FILE__, __LINE__); \ - _x_rc; \ - }) +#define xasprintf(VAR, ...)\ + ({\ + int _x_rc = (asprintf(&(VAR), __VA_ARGS__) < 0 ? (VAR = NULL, -1) : 0);\ + fprintf(stderr, "xasprintf(%s, %s)(=%zu) @ %s:%i\n",\ + #VAR, #__VA_ARGS__, _x_rc ? 0 : (strlen(VAR) + 1), __FILE__, __LINE__);\ + _x_rc;\ + }) */ @@ -138,8 +136,8 @@ * @param ...:const char*, ... The format string and arguments * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define xsnprintf(buffer, ...) \ - snprintf(buffer, sizeof(buffer) / sizeof(char), __VA_ARGS__) +#define xsnprintf(buffer, ...)\ + snprintf(buffer, sizeof(buffer) / sizeof(char), __VA_ARGS__) /** @@ -149,8 +147,8 @@ * @param format:const char* The format * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define eprint(format) \ - fprintf(stderr, "%s: " format "\n", *argv) +#define eprint(format)\ + fprintf(stderr, "%s: " format "\n", *argv) /** @@ -161,8 +159,8 @@ * @param ... The arguments * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define eprintf(format, ...) \ - fprintf(stderr, "%s: " format "\n", *argv, __VA_ARGS__) +#define eprintf(format, ...)\ + fprintf(stderr, "%s: " format "\n", *argv, __VA_ARGS__) /** @@ -174,8 +172,8 @@ * @param format:const char* The format * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define iprint(format) \ - fprintf(stderr, "%s: info: " format "\n", *argv) +#define iprint(format)\ + fprintf(stderr, "%s: info: " format "\n", *argv) /** @@ -188,8 +186,8 @@ * @param ... The arguments * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define iprintf(format, ...) \ - fprintf(stderr, "%s: info: " format "\n", *argv, __VA_ARGS__) +#define iprintf(format, ...)\ + fprintf(stderr, "%s: info: " format "\n", *argv, __VA_ARGS__) /** @@ -198,18 +196,14 @@ * @param mutex:pthread_mutex_t The mutex * @param instructions The instructions to run while the mutex is locked */ -#define with_mutex(mutex, instructions) \ - do \ - { \ - errno = pthread_mutex_lock(&(mutex)); \ - do \ - { \ - instructions ; \ - } \ - while (0); \ - errno = pthread_mutex_unlock(&(mutex)); \ - } \ - while (0) +#define with_mutex(mutex, instructions)\ + do {\ + errno = pthread_mutex_lock(&mutex);\ + do {\ + instructions;\ + } while (0);\ + errno = pthread_mutex_unlock(&mutex);\ + } while (0) /** * Wrapper for `pthread_mutex_lock` and `pthread_mutex_unlock` with an embedded if-statement @@ -218,19 +212,14 @@ * @parma condition The condition to test * @param instructions The instructions to run while the mutex is locked */ -#define with_mutex_if(mutex, condition, instructions) \ - do \ - { \ - errno = pthread_mutex_lock(&(mutex)); \ - if (condition) \ - do \ - { \ - instructions ; \ - } \ - while (0); \ - errno = pthread_mutex_unlock(&(mutex)); \ - } \ - while (0) +#define with_mutex_if(mutex, condition, instructions)\ + do {\ + errno = pthread_mutex_lock(&mutex);\ + if (condition) {\ + instructions;\ + }\ + errno = pthread_mutex_unlock(&mutex);\ + } while (0) /** @@ -240,8 +229,8 @@ * @param b The other one of the values * @return The maximum value */ -#define max(a, b) \ - (a < b ? b : a) +#define max(a, b)\ + ((a) < (b) ? (b) : (a)) /** @@ -251,8 +240,8 @@ * @param b The other one of the values * @return The minimum value */ -#define min(a, b) \ - (a < b ? a : b) +#define min(a, b)\ + ((a) < (b) ? (a) : (b)) /** @@ -263,8 +252,8 @@ * @param index:size_t The index of the element to address * @return [type] A slot that can be set or get */ -#define buf_cast(buffer, type, index) \ - (((type*)(buffer))[index]) +#define buf_cast(buffer, type, index)\ + (((type *)(buffer))[index]) /** @@ -276,8 +265,8 @@ * @param variable:type The new value of the element * @return variable: The new value of the element */ -#define buf_set(buffer, type, index, variable) \ - (((type*)(buffer))[index] = (variable)) +#define buf_set(buffer, type, index, variable)\ + (((type *)(buffer))[index] = (variable)) /** @@ -289,8 +278,8 @@ * @param variable:type Slot to set with the value of the element * @return variable: The value of the element */ -#define buf_get(buffer, type, index, variable) \ - (variable = ((const type*)(buffer))[index]) +#define buf_get(buffer, type, index, variable)\ + (variable = ((const type*)(buffer))[index]) /** @@ -301,8 +290,8 @@ * @param count:size_t The number elements of the data type `type` to increase the pointer with * @return buffer: The buffer */ -#define buf_next(buffer, type, count) \ - (buffer += (count) * sizeof(type) / sizeof(char)) +#define buf_next(buffer, type, count)\ + (buffer += (count) * sizeof(type) / sizeof(char)) /** @@ -313,8 +302,8 @@ * @param count:size_t The number elements of the data type `type` to decrease the pointer with * @return buffer: The buffer */ -#define buf_prev(buffer, type, count) \ - (buffer -= (count) * sizeof(type) / sizeof(char)) +#define buf_prev(buffer, type, count)\ + (buffer -= (count) * sizeof(type) / sizeof(char)) /** @@ -326,9 +315,9 @@ * @param variable:type The new value of the element * @return variable: The new value of the element */ -#define buf_set_next(buffer, type, variable) \ - (buf_set(buffer, type, 0, variable), \ - buf_next(buffer, type, 1)) +#define buf_set_next(buffer, type, variable)\ + (buf_set(buffer, type, 0, variable),\ + buf_next(buffer, type, 1)) /** @@ -340,9 +329,9 @@ * @param variable:type Slot to set with the value of the element * @return variable: The value of the element */ -#define buf_get_next(buffer, type, variable) \ - (buf_get(buffer, type, 0, variable), \ - buf_next(buffer, type, 1)) +#define buf_get_next(buffer, type, variable)\ + (buf_get(buffer, type, 0, variable),\ + buf_next(buffer, type, 1)) /** @@ -352,8 +341,8 @@ * @param b:const char* The other of the strings * @return :int Whether the strings are equal */ -#define strequals(a, b) \ - (strcmp(a, b) == 0) +#define strequals(a, b)\ + (!strcmp(a, b)) /** @@ -363,8 +352,8 @@ * @param needle:const char* The string `haystack` should start with * @return :int Whether `haystack` starts with `needle` */ -#define startswith(haystack, needle) \ - (strstr(haystack, needle) == haystack) +#define startswith(haystack, needle)\ + (strstr(haystack, needle) == haystack) /** @@ -374,9 +363,9 @@ * * @return :int Non-zero on error */ -#define drop_privileges() \ - ((getegid() == getgid() ? 0 : setegid(getgid())) || \ - (geteuid() == getuid() ? 0 : seteuid(getuid()))) +#define drop_privileges()\ + ((getegid() == getgid() ? 0 : setegid(getgid())) ||\ + (geteuid() == getuid() ? 0 : seteuid(getuid()))) /** @@ -386,8 +375,8 @@ * @param time_slot:struct timespec* Pointer to the variable in which to store the time * @return :int Zero on success, -1 on error */ -#define monotone(time_slot) \ - clock_gettime(CLOCK_MONOTONIC_RAW, time_slot) +#define monotone(time_slot)\ + clock_gettime(CLOCK_MONOTONIC_RAW, time_slot) /** @@ -397,15 +386,15 @@ * @param fd:int The file descriptor */ #if 1 /* For kernels that ensure that close(2) always closes valid file descriptors. */ -# define xclose(fd) \ - close(fd) +# define xclose(fd)\ + close(fd) #else /* For kernels that ensure that close(2) never closes valid file descriptors on interruption. */ # ifdef MDS_LIBMDSSERVER_MACROS_DEFINED_TEMP_FAILURE_RETRY -# define xclose(fd) \ - TEMP_FAILURE_RETRY(close(fd)) +# define xclose(fd)\ + TEMP_FAILURE_RETRY(close(fd)) # else -# define xclose(fd) \ - (TEMP_FAILURE_RETRY(close(fd)) < 0 ? 0 : (errno = 0)) +# define xclose(fd)\ + (TEMP_FAILURE_RETRY(close(fd)) < 0 ? 0 : (errno = 0)) # endif #endif @@ -417,15 +406,15 @@ * @param f:FILE* The stream */ #if 1 /* For kernels that ensure that close(2) always closes valid file descriptors. */ -# define xfclose(f) \ - fclose(f) +# define xfclose(f)\ + fclose(f) #else /* For kernels that ensure that close(2) never closes valid file descriptors on interruption. */ # ifdef MDS_LIBMDSSERVER_MACROS_DEFINED_TEMP_FAILURE_RETRY -# define xfclose(f) \ - TEMP_FAILURE_RETRY(fclose(f)) +# define xfclose(f)\ + TEMP_FAILURE_RETRY(fclose(f)) # else -# define xfclose(f) \ - (TEMP_FAILURE_RETRY(fclose(f)) < 0 ? 0 : (errno = 0)) +# define xfclose(f)\ + (TEMP_FAILURE_RETRY(fclose(f)) < 0 ? 0 : (errno = 0)) # endif #endif @@ -435,29 +424,27 @@ * * @param condition The condition, it should evaluate the variable `fd` */ -#define close_files(condition) \ - do \ - { \ - DIR* dir = opendir(SELF_FD); \ - struct dirent* file; \ - \ - if (dir == NULL) \ - perror(*argv); /* Well, that is just unfortunate, but we cannot really do anything. */ \ - else \ - { \ - int dfd = dirfd(dir); \ - while ((file = readdir(dir)) != NULL) \ - if (strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) \ - { \ - int fd = atoi(file->d_name); \ - if (fd != dfd) \ - if (condition) \ - xclose(fd); \ - } \ - closedir(dir); \ - } \ - } \ - while (0) +#define close_files(condition)\ + do {\ + DIR *dir = opendir(SELF_FD);\ + struct dirent *file;\ + int dfd, fd;\ + \ + if (!dir) {\ + perror(*argv); /* Well, that is just unfortunate, but we cannot really do anything. */\ + } else {\ + dfd = dirfd(dir);\ + while ((file = readdir(dir))) {\ + if (strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {\ + fd = atoi(file->d_name);\ + if (fd != dfd)\ + if (condition)\ + xclose(fd);\ + }\ + }\ + closedir(dir);\ + }\ + } while (0) /** @@ -467,14 +454,13 @@ * @param elements:size_t The number of elements, in the array, to free * @scope i:size_t The variable `i` must be declared as `size_t` and avaiable for use */ -#define xfree(array, elements) \ - do \ - { \ - for (i = 0; i < (elements); i++) \ - free((array)[i]); \ - free(array), (array) = NULL; \ - } \ - while (0) +#define xfree(array, elements)\ + do {\ + for (i = 0; i < (elements); i++)\ + free((array)[i]);\ + free(array);\ + (array) = NULL;\ + } while (0) /** @@ -485,17 +471,17 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define xmalloc(var, elements, type) \ - ((var = malloc((elements) * sizeof(type))) == NULL) +#define xmalloc(var, elements, type)\ + (!(var = malloc((elements) * sizeof(type)))) /* -#define xmalloc(var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xmalloc(%s, %zu, %s)(=%zu) @ %s:%i\n", \ - #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - ((var = malloc(_x_size)) == NULL); \ - }) +#define xmalloc(var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xmalloc(%s, %zu, %s)(=%zu) @ %s:%i\n",\ + #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + (!(var = malloc(_x_size)));\ + }) */ @@ -506,16 +492,16 @@ * @param bytes:size_t The number of bytes to allocate * @return :int Evaluates to true if an only if the allocation failed */ -#define xbmalloc(var, bytes) \ - ((var = malloc(bytes)) == NULL) +#define xbmalloc(var, bytes) \ + (!(var = malloc(bytes))) /* -#define xbmalloc(var, bytes) \ - ({ \ - size_t _x_bytes = (bytes); \ - fprintf(stderr, "xbmalloc(%s, %zu) @ %s:%i\n", \ - #var, _x_bytes, __FILE__, __LINE__); \ - ((var = malloc(_x_bytes)) == NULL); \ - }) +#define xbmalloc(var, bytes)\ + ({\ + size_t _x_bytes = (bytes);\ + fprintf(stderr, "xbmalloc(%s, %zu) @ %s:%i\n",\ + #var, _x_bytes, __FILE__, __LINE__);\ + (!(var = malloc(_x_bytes)));\ + }) */ @@ -527,17 +513,17 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define xcalloc(var, elements, type) \ - ((var = calloc(elements, sizeof(type))) == NULL) +#define xcalloc(var, elements, type)\ + (!(var = calloc(elements, sizeof(type)))) /* -#define xcalloc(var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xcalloc(%s, %zu, %s)(=%zu) @ %s:%i\n", \ - #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - ((var = calloc(_x_elements, sizeof(type))) == NULL); \ - }) +#define xcalloc(var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xcalloc(%s, %zu, %s)(=%zu) @ %s:%i\n",\ + #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + (!(var = calloc(_x_elements, sizeof(type))));\ + }) */ @@ -548,16 +534,16 @@ * @param bytes:size_t The number of bytes to allocate * @return :int Evaluates to true if an only if the allocation failed */ -#define xbcalloc(var, bytes) \ - ((var = calloc(bytes, sizeof(char))) == NULL) +#define xbcalloc(var, bytes)\ + (!(var = calloc(bytes, sizeof(char)))) /* -#define xbcalloc(var, bytes) \ - ({ \ - size_t _x_bytes = (bytes); \ - fprintf(stderr, "xbcalloc(%s, %zu) @ %s:%i\n", \ - #var, _x_bytes, __FILE__, __LINE__); \ - ((var = calloc(_x_bytes, sizeof(char))) == NULL); \ - }) +#define xbcalloc(var, bytes)\ + ({\ + size_t _x_bytes = (bytes);\ + fprintf(stderr, "xbcalloc(%s, %zu) @ %s:%i\n",\ + #var, _x_bytes, __FILE__, __LINE__);\ + (!(var = calloc(_x_bytes, sizeof(char))));\ + }) */ @@ -570,16 +556,16 @@ * @return :int Evaluates to true if an only if the allocation failed */ #define xrealloc(var, elements, type) \ - ((var = realloc(var, (elements) * sizeof(type))) == NULL) + (!(var = realloc(var, (elements) * sizeof(type)))) /* -#define xrealloc(var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xrealloc(%s, %zu, %s)(=%zu) @ %s:%i\n", \ - #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - ((var = realloc(var, _x_size)) == NULL); \ - }) +#define xrealloc(var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xrealloc(%s, %zu, %s)(=%zu) @ %s:%i\n",\ + #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + (!(var = realloc(var, _x_size)));\ + }) */ @@ -593,17 +579,17 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define xxrealloc(old, var, elements, type) \ - (old = var, (((var = realloc(var, (elements) * sizeof(type))) == NULL) ? 1 : (old = NULL, 0))) +#define xxrealloc(old, var, elements, type)\ + (old = var, ((!(var = realloc(var, (elements) * sizeof(type)))) ? 1 : (old = NULL, 0))) /* -#define xxrealloc(old, var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xxrealloc(%s, %s, %zu, %s)(=%zu) @ %s:%i\n", \ - #old, #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - (old = var, (((var = realloc(var, _x_size)) == NULL) ? 1 : (old = NULL, 0))); \ - }) +#define xxrealloc(old, var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xxrealloc(%s, %s, %zu, %s)(=%zu) @ %s:%i\n",\ + #old, #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + (old = var, ((!(var = realloc(var, _x_size))) ? 1 : (old = NULL, 0)));\ + }) */ @@ -616,19 +602,19 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define yrealloc(tmp, var, elements, type) \ - ((tmp = var, (var = realloc(var, (elements) * sizeof(type))) == NULL) \ - ? (var = tmp, tmp = NULL, 1) : (tmp = NULL, 0)) +#define yrealloc(tmp, var, elements, type)\ + ((tmp = var, !(var = realloc(var, (elements) * sizeof(type))))\ + ? (var = tmp, tmp = NULL, 1) : (tmp = NULL, 0)) /* -#define yrealloc(tmp, var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "yrealloc(%s, %s, %zu, %s)(=%zu) @ %s:%i\n", \ - #tmp, #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - ((tmp = var, (var = realloc(var, _x_size)) == NULL) \ - ? (var = tmp, tmp = NULL, 1) : (tmp = NULL, 0)); \ - }) +#define yrealloc(tmp, var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "yrealloc(%s, %s, %zu, %s)(=%zu) @ %s:%i\n",\ + #tmp, #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + ((tmp = var, !(var = realloc(var, _x_size)))\ + ? (var = tmp, tmp = NULL, 1) : (tmp = NULL, 0));\ + }) */ @@ -641,17 +627,17 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define growalloc(old, var, elements, type) \ - (old = var, xrealloc(var, (elements) <<= 1, type) ? (var = old, (elements) >>= 1, 1) : 0) +#define growalloc(old, var, elements, type) \ + (old = var, xrealloc(var, (elements) <<= 1, type) ? (var = old, (elements) >>= 1, 1) : 0) /* -#define growalloc(old, var, elements, type) \ - ({ \ - size_t _x_elements_ = (elements); \ - size_t _x_size_ = _x_elements_ * sizeof(type); \ - fprintf(stderr, "growalloc(%s, %s, %zu, %s)(=%zu)\n--> ", \ - #old, #var, _x_elements_, #type, _x_size_, __FILE__, __LINE__); \ - (old = var, xrealloc(var, (elements) <<= 1, type) ? (var = old, (elements) >>= 1, 1) : 0); \ - }) +#define growalloc(old, var, elements, type)\ + ({\ + size_t _x_elements_ = (elements);\ + size_t _x_size_ = _x_elements_ * sizeof(type);\ + fprintf(stderr, "growalloc(%s, %s, %zu, %s)(=%zu)\n--> ",\ + #old, #var, _x_elements_, #type, _x_size_, __FILE__, __LINE__);\ + (old = var, xrealloc(var, (elements) <<= 1, type) ? (var = old, (elements) >>= 1, 1) : 0);\ + }) */ @@ -662,16 +648,16 @@ * @param original:const char* The string to duplicate, may be `NULL` * @return :int Evaluates to true if an only if the allocation failed */ -#define xstrdup(var, original) \ - (original ? ((var = strdup(original)) == NULL) : (var = NULL, 0)) +#define xstrdup(var, original)\ + (original ? !(var = strdup(original)) : (var = NULL, 0)) /* -#define xstrdup(var, original) \ - ({ \ - size_t _x_size = original ? strlen(original) : 0; \ - fprintf(stderr, "xstrdup(%s, %s(“%s”=%zu))(=%zu) @ %s:%i\n", \ - #var, #original, original, _x_size, _x_size + !!_x_size, __FILE__, __LINE__); \ - (original ? ((var = strdup(original)) == NULL) : (var = NULL, 0)); \ - }) +#define xstrdup(var, original)\ + ({\ + size_t _x_size = original ? strlen(original) : 0;\ + fprintf(stderr, "xstrdup(%s, %s(“%s”=%zu))(=%zu) @ %s:%i\n",\ + #var, #original, original, _x_size, _x_size + !!_x_size, __FILE__, __LINE__);\ + (original ? ((var = strdup(original)) == NULL) : (var = NULL, 0));\ + }) */ @@ -685,16 +671,16 @@ * @param original:const char* The string to duplicate, must not be `NULL` * @return :int Evaluates to true if an only if the allocation failed */ -#define xstrdup_nn(var, original) \ - ((var = strdup(original)) == NULL) +#define xstrdup_nn(var, original)\ + (!(var = strdup(original))) /* -#define xstrdup_nn(var, original) \ - ({ \ - size_t _x_size = strlen(original); \ - fprintf(stderr, "xstrdup_nn(%s, %s(“%s”=%zu))(=%zu) @ %s:%i\n", \ - #var, #original, original, _x_size, _x_size + !!_x_size, __FILE__, __LINE__); \ - (var = strdup(original)) == NULL; \ - }) +#define xstrdup_nn(var, original)\ + ({\ + size_t _x_size = strlen(original);\ + fprintf(stderr, "xstrdup_nn(%s, %s(“%s”=%zu))(=%zu) @ %s:%i\n",\ + #var, #original, original, _x_size, _x_size + !!_x_size, __FILE__, __LINE__);\ + !(var = strdup(original));\ + }) */ @@ -708,18 +694,18 @@ * @param type The data type of the elements to duplicate * @return :int Evaluates to true if an only if the allocation failed */ -#define xmemdup(var, original, elements, type) \ - (((var = malloc((elements) * sizeof(type))) == NULL) ? 1 : \ - (memcpy(var, original, (elements) * sizeof(type)), 0)) +#define xmemdup(var, original, elements, type)\ + (!(var = malloc((elements) * sizeof(type))) ? 1 :\ + (memcpy(var, original, (elements) * sizeof(type)), 0)) /* -#define xmemdup(var, original, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xmemdup(%s, %s, %zu, %s)(=%zu) @ %s:%i\n", \ - #var, #original, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - (((var = malloc(_x_size)) == NULL) ? 1 : (memcpy(var, original, _x_size), 0)); \ - }) +#define xmemdup(var, original, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xmemdup(%s, %s, %zu, %s)(=%zu) @ %s:%i\n",\ + #var, #original, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + !(var = malloc(_x_size)) ? 1 : (memcpy(var, original, _x_size), 0);\ + }) */ diff --git a/src/libmdsserver/mds-message.c b/src/libmdsserver/mds-message.c index 4ec8142..c3d968f 100644 --- a/src/libmdsserver/mds-message.c +++ b/src/libmdsserver/mds-message.c @@ -27,7 +27,7 @@ #include <sys/socket.h> -#define try(INSTRUCTION) if ((r = INSTRUCTION) < 0) return r +#define try(INSTRUCTION) do { if ((r = INSTRUCTION) < 0) return r; } while (0) /** @@ -38,20 +38,21 @@ * @return Non-zero on error, `errno` will be set accordingly. * Destroy the message on error. */ -int mds_message_initialise(mds_message_t* restrict this) +int +mds_message_initialise(mds_message_t *restrict this) { - this->headers = NULL; - this->header_count = 0; - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; - this->buffer_size = 128; - this->buffer_ptr = 0; - this->stage = 0; - fail_if (xmalloc(this->buffer, this->buffer_size, char)); - return 0; - fail: - return -1; + this->headers = NULL; + this->header_count = 0; + this->payload = NULL; + this->payload_size = 0; + this->payload_ptr = 0; + this->buffer_size = 128; + this->buffer_ptr = 0; + this->stage = 0; + fail_if (xmalloc(this->buffer, this->buffer_size, char)); + return 0; +fail: + return -1; } @@ -60,17 +61,18 @@ int mds_message_initialise(mds_message_t* restrict this) * * @param this Memory slot in which to store the new message */ -void mds_message_zero_initialise(mds_message_t* restrict this) +void +mds_message_zero_initialise(mds_message_t *restrict this) { - this->headers = NULL; - this->header_count = 0; - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; - this->buffer = NULL; - this->buffer_size = 0; - this->buffer_ptr = 0; - this->stage = 0; + this->headers = NULL; + this->header_count = 0; + this->payload = NULL; + this->payload_size = 0; + this->payload_ptr = 0; + this->buffer = NULL; + this->buffer_size = 0; + this->buffer_ptr = 0; + this->stage = 0; } @@ -80,14 +82,15 @@ void mds_message_zero_initialise(mds_message_t* restrict this) * * @param this The message */ -void mds_message_destroy(mds_message_t* restrict this) +void +mds_message_destroy(mds_message_t *restrict this) { - size_t i; - if (this->headers != NULL) - xfree(this->headers, this->header_count); - - free(this->payload), this->payload = NULL; - free(this->buffer), this->buffer = NULL; + size_t i; + if (this->headers) + xfree(this->headers, this->header_count); + + free(this->payload), this->payload = NULL; + free(this->buffer), this->buffer = NULL; } @@ -98,14 +101,15 @@ void mds_message_destroy(mds_message_t* restrict this) * @param extent The number of additional entries * @return Zero on success, -1 on error */ -int mds_message_extend_headers(mds_message_t* restrict this, size_t extent) +int +mds_message_extend_headers(mds_message_t *restrict this, size_t extent) { - char** new_headers = this->headers; - fail_if (xrealloc(new_headers, this->header_count + extent, char*)); - this->headers = new_headers; - return 0; - fail: - return -1; + char **new_headers = this->headers; + fail_if (xrealloc(new_headers, this->header_count + extent, char*)); + this->headers = new_headers; + return 0; +fail: + return -1; } @@ -115,16 +119,16 @@ int mds_message_extend_headers(mds_message_t* restrict this, size_t extent) * @param this The message * @return Zero on success, -1 on error */ -__attribute__((nonnull)) -static int mds_message_extend_buffer(mds_message_t* restrict this) +static int __attribute__((nonnull)) +mds_message_extend_buffer(mds_message_t *restrict this) { - char* new_buf = this->buffer; - fail_if (xrealloc(new_buf, this->buffer_size << 1, char)); - this->buffer = new_buf; - this->buffer_size <<= 1; - return 0; - fail: - return -1; + char *new_buf = this->buffer; + fail_if (xrealloc(new_buf, this->buffer_size << 1, char)); + this->buffer = new_buf; + this->buffer_size <<= 1; + return 0; +fail: + return -1; } @@ -133,18 +137,18 @@ static int mds_message_extend_buffer(mds_message_t* restrict this) * * @param this The message */ -__attribute__((nonnull)) -static void reset_message(mds_message_t* restrict this) +static void __attribute__((nonnull)) +reset_message(mds_message_t *restrict this) { - size_t i; - if (this->headers != NULL) - xfree(this->headers, this->header_count); - this->header_count = 0; - - free(this->payload); - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; + size_t i; + if (this->headers) + xfree(this->headers, this->header_count); + this->header_count = 0; + + free(this->payload); + this->payload = NULL; + this->payload_size = 0; + this->payload_ptr = 0; } @@ -154,29 +158,29 @@ static void reset_message(mds_message_t* restrict this) * @param this The message * @return Zero on success, negative on error (malformated message: unrecoverable state) */ -__attribute__((pure, nonnull)) -static int get_payload_length(mds_message_t* restrict this) +static int __attribute__((pure, nonnull)) +get_payload_length(mds_message_t *restrict this) { - char* header; - size_t i; - - for (i = 0; i < this->header_count; i++) - if (strstr(this->headers[i], "Length: ") == this->headers[i]) - { - /* Store the message length. */ - header = this->headers[i] + strlen("Length: "); - this->payload_size = atoz(header); - - /* Do not except a length that is not correctly formated. */ - for (; *header; header++) - if ((*header < '0') || ('9' < *header)) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Stop searching for the ‘Length’ header, we have found and parsed it. */ - break; - } - - return 0; + char *header; + size_t i; + + for (i = 0; i < this->header_count; i++) { + if (strstr(this->headers[i], "Length: ") == this->headers[i]) { + /* Store the message length. */ + header = this->headers[i] + strlen("Length: "); + this->payload_size = atoz(header); + + /* Do not except a length that is not correctly formated. */ + for (; *header; header++) + if (*header < '0' || '9' < *header) + return -2; /* Malformated value, enters unrecoverable state. */ + + /* Stop searching for the ‘Length’ header, we have found and parsed it. */ + break; + } + } + + return 0; } @@ -187,21 +191,21 @@ static int get_payload_length(mds_message_t* restrict this) * @param length The length of the header * @return Zero if valid, negative if invalid (malformated message: unrecoverable state) */ -__attribute__((pure, nonnull)) -static int validate_header(const char* header, size_t length) +static int __attribute__((pure, nonnull)) +validate_header(const char *header, size_t length) { - char* p = memchr(header, ':', length * sizeof(char)); - - if (verify_utf8(header, 0) < 0) - /* Either the string is not UTF-8, or your are under an UTF-8 attack, - let's just call this unrecoverable because the client will not correct. */ - return -2; - - if ((p == NULL) || /* Buck you, rawmemchr should not segfault the program. */ - (p[1] != ' ')) /* Also an invalid format. ' ' is mandated after the ':'. */ - return -2; - - return 0; + char *p = memchr(header, ':', length * sizeof(char)); + + if (verify_utf8(header, 0) < 0) + /* Either the string is not UTF-8, or your are under an UTF-8 attack, + let's just call this unrecoverable because the client will not correct. */ + return -2; + + if (!p || /* Buck you, rawmemchr should not segfault the program. */ + p[1] != ' ') /* Also an invalid format. ' ' is mandated after the ':'. */ + return -2; + + return 0; } @@ -212,12 +216,12 @@ static int validate_header(const char* header, size_t length) * @param length The number of characters to remove * @param update_ptr Whether to update the buffer pointer */ -__attribute__((nonnull)) -static void unbuffer_beginning(mds_message_t* restrict this, size_t length, int update_ptr) +static void __attribute__((nonnull)) +unbuffer_beginning(mds_message_t *restrict this, size_t length, int update_ptr) { - memmove(this->buffer, this->buffer + length, (this->buffer_ptr - length) * sizeof(char)); - if (update_ptr) - this->buffer_ptr -= length; + memmove(this->buffer, this->buffer + length, (this->buffer_ptr - length) * sizeof(char)); + if (update_ptr) + this->buffer_ptr -= length; } @@ -228,23 +232,23 @@ static void unbuffer_beginning(mds_message_t* restrict this, size_t length, int * @param this The message * @return The return value follows the rules of `mds_message_read` */ -__attribute__((nonnull)) -static int initialise_payload(mds_message_t* restrict this) +static int __attribute__((nonnull)) +initialise_payload(mds_message_t *restrict this) { - /* Remove the \n (end of empty line) we found from the buffer. */ - unbuffer_beginning(this, 1, 1); - - /* Get the length of the payload. */ - if (get_payload_length(this) < 0) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Allocate the payload buffer. */ - if (this->payload_size > 0) - fail_if (xmalloc(this->payload, this->payload_size, char)); - - return 0; - fail: - return -1; + /* Remove the \n (end of empty line) we found from the buffer. */ + unbuffer_beginning(this, 1, 1); + + /* Get the length of the payload. */ + if (get_payload_length(this) < 0) + return -2; /* Malformated value, enters unrecoverable state. */ + + /* Allocate the payload buffer. */ + if (this->payload_size > 0) + fail_if (xmalloc(this->payload, this->payload_size, char)); + + return 0; +fail: + return -1; } @@ -255,35 +259,34 @@ static int initialise_payload(mds_message_t* restrict this) * @param length The length of the header, including LF-termination * @return The return value follows the rules of `mds_message_read` */ -__attribute__((nonnull)) -static int store_header(mds_message_t* restrict this, size_t length) +static int __attribute__((nonnull)) +store_header(mds_message_t *restrict this, size_t length) { - char* header; - - /* Allocate the header. */ - fail_if (xmalloc(header, length, char)); /* Last char is a LF, which is substituted with NUL. */ - /* Copy the header data into the allocated header, */ - memcpy(header, this->buffer, length * sizeof(char)); - /* and NUL-terminate it. */ - header[length - 1] = '\0'; - - /* Remove the header data from the read buffer. */ - unbuffer_beginning(this, length, 1); - - /* Make sure the the header syntax is correct so that - the program does not need to care about it. */ - if (validate_header(header, length)) - { - free(header); - return -2; - } - - /* Store the header in the header list. */ - this->headers[this->header_count++] = header; - - return 0; - fail: - return -1; + char *header; + + /* Allocate the header. */ + fail_if (xmalloc(header, length, char)); /* Last char is a LF, which is substituted with NUL. */ + /* Copy the header data into the allocated header, */ + memcpy(header, this->buffer, length * sizeof(char)); + /* and NUL-terminate it. */ + header[length - 1] = '\0'; + + /* Remove the header data from the read buffer. */ + unbuffer_beginning(this, length, 1); + + /* Make sure the the header syntax is correct so that + the program does not need to care about it. */ + if (validate_header(header, length)) { + free(header); + return -2; + } + + /* Store the header in the header list. */ + this->headers[this->header_count++] = header; + + return 0; +fail: + return -1; } @@ -294,37 +297,36 @@ static int store_header(mds_message_t* restrict this, size_t length) * @param fd The file descriptor of the socket * @return The return value follows the rules of `mds_message_read` */ -__attribute__((nonnull)) -static int continue_read(mds_message_t* restrict this, int fd) +static int __attribute__((nonnull)) +continue_read(mds_message_t *restrict this, int fd) { - size_t n; - ssize_t got; - int r; - - /* Figure out how much space we have left in the read buffer. */ - n = this->buffer_size - this->buffer_ptr; - - /* If we do not have too much left, */ - if (n < 128) - { - /* grow the buffer, */ - try (mds_message_extend_buffer(this)); - - /* and recalculate how much space we have left. */ - n = this->buffer_size - this->buffer_ptr; - } - - /* Then read from the socket. */ - errno = 0; - got = recv(fd, this->buffer + this->buffer_ptr, n, 0); - this->buffer_ptr += (size_t)(got < 0 ? 0 : got); - fail_if (errno); - if (got == 0) - fail_if ((errno = ECONNRESET)); - - return 0; - fail: - return -1; + size_t n; + ssize_t got; + int r; + + /* Figure out how much space we have left in the read buffer. */ + n = this->buffer_size - this->buffer_ptr; + + /* If we do not have too much left, */ + if (n < 128) { + /* grow the buffer, */ + try (mds_message_extend_buffer(this)); + + /* and recalculate how much space we have left. */ + n = this->buffer_size - this->buffer_ptr; + } + + /* Then read from the socket. */ + errno = 0; + got = recv(fd, this->buffer + this->buffer_ptr, n, 0); + this->buffer_ptr += (size_t)(got < 0 ? 0 : got); + fail_if (errno); + if (!got) + fail_if ((errno = ECONNRESET)); + + return 0; +fail: + return -1; } @@ -341,86 +343,78 @@ static int continue_read(mds_message_t* restrict this, int fd) * -2 indicates that the message is malformated, * which is a state that cannot be recovered from. */ -int mds_message_read(mds_message_t* restrict this, int fd) +int +mds_message_read(mds_message_t *restrict this, int fd) { - size_t header_commit_buffer = 0; - int r; - - /* If we are at stage 2, we are done and it is time to start over. - This is important because the function could have been interrupted. */ - if (this->stage == 2) - { - reset_message(this); - this->stage = 0; - } - - /* Read from file descriptor until we have a full message. */ - for (;;) - { - char* p; - size_t length; - - /* Stage 0: headers. */ - /* Read all headers that we have stored into the read buffer. */ - while ((this->stage == 0) && - ((p = memchr(this->buffer, '\n', this->buffer_ptr * sizeof(char))) != NULL)) - if ((length = (size_t)(p - this->buffer))) - { - /* We have found a header. */ - - /* On every eighth header found with this function call, - we prepare the header list for eight more headers so - that it does not need to be reallocated again and again. */ - if (header_commit_buffer == 0) - try (mds_message_extend_headers(this, header_commit_buffer = 8)); - - /* Create and store header. */ - try (store_header(this, length + 1)); - header_commit_buffer -= 1; - } - else - { - /* We have found an empty line, i.e. the end of the headers. */ - - /* Remove the header–payload delimiter from the buffer, - get the payload's size and allocate the payload. */ - try (initialise_payload(this)); - - /* Mark end of stage, next stage is getting the payload. */ - this->stage = 1; - } - - - /* Stage 1: payload. */ - if ((this->stage == 1) && (this->payload_size > 0)) - { - /* How much of the payload that has not yet been filled. */ - size_t need = this->payload_size - this->payload_ptr; - /* How much we have of that what is needed. */ - size_t move = min(this->buffer_ptr, need); - - /* Copy what we have, and remove it from the the read buffer. */ - memcpy(this->payload + this->payload_ptr, this->buffer, move * sizeof(char)); - unbuffer_beginning(this, move, 1); - - /* Keep track of how much we have read. */ - this->payload_ptr += move; + size_t header_commit_buffer = 0, length, need, move; + int r; + char *p; + + /* If we are at stage 2, we are done and it is time to start over. + This is important because the function could have been interrupted. */ + if (this->stage == 2) { + reset_message(this); + this->stage = 0; } - if ((this->stage == 1) && (this->payload_ptr == this->payload_size)) - { - /* If we have filled the payload (or there was no payload), - mark the end of this stage, i.e. that the message is - complete, and return with success. */ - this->stage = 2; - return 0; + + /* Read from file descriptor until we have a full message. */ + for (;;) { + /* Stage 0: headers. */ + /* Read all headers that we have stored into the read buffer. */ + while (!this->stage && ((p = memchr(this->buffer, '\n', this->buffer_ptr * sizeof(char))))) { + if ((length = (size_t)(p - this->buffer))) { + /* We have found a header. */ + + /* On every eighth header found with this function call, + we prepare the header list for eight more headers so + that it does not need to be reallocated again and again. */ + if (!header_commit_buffer) + try (mds_message_extend_headers(this, header_commit_buffer = 8)); + + /* Create and store header. */ + try (store_header(this, length + 1)); + header_commit_buffer -= 1; + } else { + /* We have found an empty line, i.e. the end of the headers. */ + + /* Remove the header–payload delimiter from the buffer, + get the payload's size and allocate the payload. */ + try (initialise_payload(this)); + + /* Mark end of stage, next stage is getting the payload. */ + this->stage = 1; + } + } + + + /* Stage 1: payload. */ + if (this->stage == 1 && this->payload_size > 0) { + /* How much of the payload that has not yet been filled. */ + need = this->payload_size - this->payload_ptr; + /* How much we have of that what is needed. */ + move = min(this->buffer_ptr, need); + + /* Copy what we have, and remove it from the the read buffer. */ + memcpy(this->payload + this->payload_ptr, this->buffer, move * sizeof(char)); + unbuffer_beginning(this, move, 1); + + /* Keep track of how much we have read. */ + this->payload_ptr += move; + } + if (this->stage == 1 && this->payload_ptr == this->payload_size) { + /* If we have filled the payload (or there was no payload), + mark the end of this stage, i.e. that the message is + complete, and return with success. */ + this->stage = 2; + return 0; + } + + + /* If stage 1 was not completed. */ + + /* Continue reading from the socket into the buffer. */ + try (continue_read(this, fd)); } - - - /* If stage 1 was not completed. */ - - /* Continue reading from the socket into the buffer. */ - try (continue_read(this, fd)); - } } @@ -431,15 +425,15 @@ int mds_message_read(mds_message_t* restrict this, int fd) * @param this The message * @return The size of the message when marshalled */ -size_t mds_message_marshal_size(const mds_message_t* restrict this) +size_t +mds_message_marshal_size(const mds_message_t *restrict this) { - size_t rc = this->header_count + this->payload_size; - size_t i; - for (i = 0; i < this->header_count; i++) - rc += strlen(this->headers[i]); - rc *= sizeof(char); - rc += 4 * sizeof(size_t) + 2 * sizeof(int); - return rc; + size_t i, rc = this->header_count + this->payload_size; + for (i = 0; i < this->header_count; i++) + rc += strlen(this->headers[i]); + rc *= sizeof(char); + rc += 4 * sizeof(size_t) + 2 * sizeof(int); + return rc; } @@ -449,29 +443,29 @@ size_t mds_message_marshal_size(const mds_message_t* restrict this) * @param this The message * @param data Output buffer for the marshalled data */ -void mds_message_marshal(const mds_message_t* restrict this, char* restrict data) +void +mds_message_marshal(const mds_message_t *restrict this, char *restrict data) { - size_t i, n; - - buf_set_next(data, int, MDS_MESSAGE_T_VERSION); - - buf_set_next(data, size_t, this->header_count); - buf_set_next(data, size_t, this->payload_size); - buf_set_next(data, size_t, this->payload_ptr); - buf_set_next(data, size_t, this->buffer_ptr); - buf_set_next(data, int, this->stage); - - for (i = 0; i < this->header_count; i++) - { - n = strlen(this->headers[i]) + 1; - memcpy(data, this->headers[i], n * sizeof(char)); - buf_next(data, char, n); - } - - memcpy(data, this->payload, this->payload_ptr * sizeof(char)); - buf_next(data, char, this->payload_ptr); - - memcpy(data, this->buffer, this->buffer_ptr * sizeof(char)); + size_t i, n; + + buf_set_next(data, int, MDS_MESSAGE_T_VERSION); + + buf_set_next(data, size_t, this->header_count); + buf_set_next(data, size_t, this->payload_size); + buf_set_next(data, size_t, this->payload_ptr); + buf_set_next(data, size_t, this->buffer_ptr); + buf_set_next(data, int, this->stage); + + for (i = 0; i < this->header_count; i++) { + n = strlen(this->headers[i]) + 1; + memcpy(data, this->headers[i], n * sizeof(char)); + buf_next(data, char, n); + } + + memcpy(data, this->payload, this->payload_ptr * sizeof(char)); + buf_next(data, char, this->payload_ptr); + + memcpy(data, this->buffer, this->buffer_ptr * sizeof(char)); } @@ -483,75 +477,74 @@ void mds_message_marshal(const mds_message_t* restrict this, char* restrict data * @return Non-zero on error, `errno` will be set accordingly. * Destroy the message on error. */ -int mds_message_unmarshal(mds_message_t* restrict this, char* restrict data) +int +mds_message_unmarshal(mds_message_t *restrict this, char *restrict data) { - size_t i, n, header_count; - - /* buf_get(data, int, 0, MDS_MESSAGE_T_VERSION); */ - buf_next(data, int, 1); - - this->header_count = 0; - buf_get_next(data, size_t, header_count); - buf_get_next(data, size_t, this->payload_size); - buf_get_next(data, size_t, this->payload_ptr); - buf_get_next(data, size_t, this->buffer_size = this->buffer_ptr); - buf_get_next(data, int, this->stage); - - /* Make sure that the pointers are NULL so that they are - not freed without being allocated when the message is - destroyed if this function fails. */ - this->headers = NULL; - this->payload = NULL; - this->buffer = NULL; - - /* To 2-power-multiple of 128 bytes. */ - this->buffer_size >>= 7; - if (this->buffer_size == 0) - this->buffer_size = 1; - else - { - this->buffer_size -= 1; - this->buffer_size |= this->buffer_size >> 1; - this->buffer_size |= this->buffer_size >> 2; - this->buffer_size |= this->buffer_size >> 4; - this->buffer_size |= this->buffer_size >> 8; - this->buffer_size |= this->buffer_size >> 16; + size_t i, n, header_count; + + /* buf_get(data, int, 0, MDS_MESSAGE_T_VERSION); */ + buf_next(data, int, 1); + + this->header_count = 0; + buf_get_next(data, size_t, header_count); + buf_get_next(data, size_t, this->payload_size); + buf_get_next(data, size_t, this->payload_ptr); + buf_get_next(data, size_t, this->buffer_size = this->buffer_ptr); + buf_get_next(data, int, this->stage); + + /* Make sure that the pointers are NULL so that they are + not freed without being allocated when the message is + destroyed if this function fails. */ + this->headers = NULL; + this->payload = NULL; + this->buffer = NULL; + + /* To 2-power-multiple of 128 bytes. */ + this->buffer_size >>= 7; + if (!this->buffer_size) { + this->buffer_size = 1; + } else { + this->buffer_size -= 1; + this->buffer_size |= this->buffer_size >> 1; + this->buffer_size |= this->buffer_size >> 2; + this->buffer_size |= this->buffer_size >> 4; + this->buffer_size |= this->buffer_size >> 8; + this->buffer_size |= this->buffer_size >> 16; #if SIZE_MAX == UINT64_MAX - this->buffer_size |= this->buffer_size >> 32; + this->buffer_size |= this->buffer_size >> 32; #endif - this->buffer_size += 1; - } - this->buffer_size <<= 7; - - /* Allocate header list, payload and read buffer. */ - - if (header_count > 0) - fail_if (xmalloc(this->headers, header_count, char*)); - - if (this->payload_size > 0) - fail_if (xmalloc(this->payload, this->payload_size, char)); - - fail_if (xmalloc(this->buffer, this->buffer_size, char)); - - /* Fill the header list, payload and read buffer. */ - - for (i = 0; i < header_count; i++) - { - n = strlen(data) + 1; - fail_if (xmemdup(this->headers[i], data, n, char)); - buf_next(data, char, n); - this->header_count++; - } - - memcpy(this->payload, data, this->payload_ptr * sizeof(char)); - buf_next(data, char, this->payload_ptr); - - memcpy(this->buffer, data, this->buffer_ptr * sizeof(char)); - - return 0; - - fail: - return -1; + this->buffer_size += 1; + } + this->buffer_size <<= 7; + + /* Allocate header list, payload and read buffer. */ + + if (header_count > 0) + fail_if (xmalloc(this->headers, header_count, char*)); + + if (this->payload_size > 0) + fail_if (xmalloc(this->payload, this->payload_size, char)); + + fail_if (xmalloc(this->buffer, this->buffer_size, char)); + + /* Fill the header list, payload and read buffer. */ + + for (i = 0; i < header_count; i++) { + n = strlen(data) + 1; + fail_if (xmemdup(this->headers[i], data, n, char)); + buf_next(data, char, n); + this->header_count++; + } + + memcpy(this->payload, data, this->payload_ptr * sizeof(char)); + buf_next(data, char, this->payload_ptr); + + memcpy(this->buffer, data, this->buffer_ptr * sizeof(char)); + + return 0; + +fail: + return -1; } @@ -562,13 +555,14 @@ int mds_message_unmarshal(mds_message_t* restrict this, char* restrict data) * @param this The message * @return The size of the message when marshalled */ -size_t mds_message_compose_size(const mds_message_t* restrict this) +size_t +mds_message_compose_size(const mds_message_t *restrict this) { - size_t rc = 1 + this->payload_size; - size_t i; - for (i = 0; i < this->header_count; i++) - rc += strlen(this->headers[i]) + 1; - return rc * sizeof(char); + size_t rc = 1 + this->payload_size; + size_t i; + for (i = 0; i < this->header_count; i++) + rc += strlen(this->headers[i]) + 1; + return rc * sizeof(char); } @@ -578,23 +572,22 @@ size_t mds_message_compose_size(const mds_message_t* restrict this) * @param this The message * @param data Output buffer for the marshalled data */ -void mds_message_compose(const mds_message_t* restrict this, char* restrict data) +void +mds_message_compose(const mds_message_t *restrict this, char *restrict data) { - size_t i, n; - - for (i = 0; i < this->header_count; i++) - { - n = strlen(this->headers[i]); - memcpy(data, this->headers[i], n * sizeof(char)); - data += n; - buf_set_next(data, char, '\n'); - } - buf_set_next(data, char, '\n'); - - if (this->payload_size > 0) - memcpy(data, this->payload, this->payload_size * sizeof(char)); + size_t i, n; + + for (i = 0; i < this->header_count; i++) { + n = strlen(this->headers[i]); + memcpy(data, this->headers[i], n * sizeof(char)); + data += n; + buf_set_next(data, char, '\n'); + } + buf_set_next(data, char, '\n'); + + if (this->payload_size > 0) + memcpy(data, this->payload, this->payload_size * sizeof(char)); } #undef try - diff --git a/src/libmdsserver/util.c b/src/libmdsserver/util.c index cac30ad..09d996a 100644 --- a/src/libmdsserver/util.c +++ b/src/libmdsserver/util.c @@ -49,20 +49,21 @@ static char self_exe[PATH_MAX] = {0}; * @param str The client ID string * @return The client ID integer */ -uint64_t parse_client_id(const char* str) +uint64_t +parse_client_id(const char *str) { - char client_words[22]; - char* client_high; - char* client_low; - uint64_t client; - - strcpy(client_high = client_words, str); - client_low = rawmemchr(client_words, ':'); - *client_low++ = '\0'; - client = atou64(client_high) << 32; - client |= atou64(client_low); - - return client; + char client_words[22]; + char *client_high; + char *client_low; + uint64_t client; + + strcpy(client_high = client_words, str); + client_low = rawmemchr(client_words, ':'); + *client_low++ = '\0'; + client = atou64(client_high) << 32; + client |= atou64(client_low); + + return client; } @@ -72,12 +73,11 @@ uint64_t parse_client_id(const char* str) * @param var The environment variable's name * @return The environment variable's value, `NULL` if empty or not defined */ -char* getenv_nonempty(const char* var) +char * +getenv_nonempty(const char *var) { - char* rc = getenv(var); - if ((rc == NULL) || (*rc == '\0')) - return NULL; - return rc; + char *rc = getenv(var); + return (rc && *rc) ? rc : NULL; } @@ -97,20 +97,21 @@ char* getenv_nonempty(const char* var) * * @return Zero on success, -1 on error */ -int prepare_reexec(void) +int +prepare_reexec(void) { - ssize_t len; - len = readlink(SELF_EXE, self_exe, (sizeof(self_exe) / sizeof(char)) - 1); - fail_if (len < 0); - /* ‘readlink() does not append a null byte to buf.’ */ - self_exe[len] = '\0'; - /* Handle possible race condition: file was removed. */ - if (access(self_exe, F_OK) < 0) - if (!strcmp(self_exe + (len - 10), " (deleted)")) - self_exe[len - 10] = '\0'; - return 0; - fail: - return -1; + ssize_t len; + len = readlink(SELF_EXE, self_exe, (sizeof(self_exe) / sizeof(char)) - 1); + fail_if (len < 0); + /* ‘readlink() does not append a null byte to buf.’ */ + self_exe[len] = '\0'; + /* Handle possible race condition: file was removed. */ + if (access(self_exe, F_OK) < 0) + if (!strcmp(self_exe + (len - 10), " (deleted)")) + self_exe[len - 10] = '\0'; + return 0; +fail: + return -1; } @@ -125,30 +126,30 @@ int prepare_reexec(void) * @param argv The command line arguments * @param reexeced Whether the server has previously been re-exec:ed */ -void reexec_server(int argc, char** argv, int reexeced) +void +reexec_server(int argc, char **argv, int reexeced) { - char** reexec_args; - char** reexec_args_; - int i; - - /* Re-exec the server. */ - reexec_args = alloca(((size_t)argc + 2) * sizeof(char*)); - reexec_args_ = reexec_args; - if (reexeced == 0) - { - *reexec_args_++ = *argv; - fail_if (xstrdup(*reexec_args_, "--re-exec")); - for (i = 1; i < argc; i++) - reexec_args_[i] = argv[i]; - } - else /* Don't let the --re-exec:s accumulate. */ - *reexec_args_ = *argv; - for (i = 1; i < argc; i++) - reexec_args_[i] = argv[i]; - reexec_args_[argc] = NULL; - execv(self_exe[0] ? self_exe : argv[0], reexec_args); - fail: - return; + char **reexec_args; + char **reexec_args_; + int i; + + /* Re-exec the server. */ + reexec_args = alloca(((size_t)argc + 2) * sizeof(char*)); + reexec_args_ = reexec_args; + if (!reexeced) { + *reexec_args_++ = *argv; + fail_if (xstrdup(*reexec_args_, "--re-exec")); + for (i = 1; i < argc; i++) + reexec_args_[i] = argv[i]; + } else { /* Don't let the --re-exec:s accumulate. */ + *reexec_args_ = *argv; + } + for (i = 1; i < argc; i++) + reexec_args_[i] = argv[i]; + reexec_args_[argc] = NULL; + execv(self_exe[0] ? self_exe : argv[0], reexec_args); +fail: + return; } @@ -164,17 +165,18 @@ void reexec_server(int argc, char** argv, int reexeced) * @param function The function to run when the signal is caught * @return Zero on success, -1 on error */ -int xsigaction(int signo, void (*function)(int signo)) +int +xsigaction(int signo, void (*function)(int signo)) { - struct sigaction action; - sigset_t sigset; - - sigemptyset(&sigset); - action.sa_handler = function; - action.sa_mask = sigset; - action.sa_flags = 0; - - return sigaction(signo, &action, NULL); + struct sigaction action; + sigset_t sigset; + + sigemptyset(&sigset); + action.sa_handler = function; + action.sa_mask = sigset; + action.sa_flags = 0; + + return sigaction(signo, &action, NULL); } @@ -186,34 +188,32 @@ int xsigaction(int signo, void (*function)(int signo)) * @param length The length of the message * @return The number of bytes that have been sent (even on error) */ -size_t send_message(int socket, const char* message, size_t length) +size_t +send_message(int socket, const char *message, size_t length) { - size_t block_size = length; - size_t sent = 0; - ssize_t just_sent; - - errno = 0; - while (length > 0) - if ((just_sent = send(socket, message + sent, min(block_size, length), MSG_NOSIGNAL)) < 0) - { - if (errno == EPIPE) - errno = ECONNRESET; - if (errno == EMSGSIZE) - { - block_size >>= 1; - if (block_size == 0) - return sent; - } - else - return sent; - } - else - { - sent += (size_t)just_sent; - length -= (size_t)just_sent; - } - - return sent; + size_t block_size = length; + size_t sent = 0; + ssize_t just_sent; + + errno = 0; + while (length > 0) { + if ((just_sent = send(socket, message + sent, min(block_size, length), MSG_NOSIGNAL)) < 0) { + if (errno == EPIPE) + errno = ECONNRESET; + if (errno == EMSGSIZE) { + block_size >>= 1; + if (!block_size) + return sent; + } else { + return sent; + } + } else { + sent += (size_t)just_sent; + length -= (size_t)just_sent; + } + } + + return sent; } @@ -226,20 +226,21 @@ size_t send_message(int socket, const char* message, size_t length) * @param max The maximum accepted value * @return Zero on success, -1 on syntax error */ -int strict_atoi(const char* str, int* value, int min, int max) +int +strict_atoi(const char *str, int *value, int min, int max) { - long long int r; - char* endptr; - - r = strtoll(str, &endptr, 10); - if ((*str == '\0') || isspace(*str) || - (endptr - str != (ssize_t)strlen(str)) || - (r < (long long int)min) || - (r > (long long int)max)) - return -1; - - *value = (int)r; - return 0; + long long int r; + char *endptr; + + r = strtoll(str, &endptr, 10); + if (!*str || isspace(*str) || + endptr - str != (ssize_t)strlen(str) || + r < (long long int)min || + r > (long long int)max) + return -1; + + *value = (int)r; + return 0; } @@ -252,51 +253,50 @@ int strict_atoi(const char* str, int* value, int min, int max) * @param max The maximum accepted value * @return Zero on success, -1 on syntax error */ -int strict_atoj(const char* str, intmax_t* value, intmax_t min, intmax_t max) +int +strict_atoj(const char *str, intmax_t *value, intmax_t min, intmax_t max) { - static char minstr[3 * sizeof(intmax_t) + 2] = { '\0' }; - intmax_t r = 0; - char c; - int neg = 0; - - if (*str == '-') - { - if (*minstr == '\0') - sprintf(minstr, "%j", INTMAX_MIN); - if (!strcmp(str, minstr)) - { - r = INTMAX_MIN; - goto done; + static char minstr[3 * sizeof(intmax_t) + 2] = { '\0' }; + intmax_t r = 0; + char c; + int neg = 0; + + if (*str == '-') { + if (!*minstr) + sprintf(minstr, "%j", INTMAX_MIN); + if (!strcmp(str, minstr)) { + r = INTMAX_MIN; + goto done; + } + neg = 1, str++; } - neg = 1, str++; - } - - if (*str == '\0') - return -1; - - while ((c = *str)) - if (('0' <= c) && (c <= '9')) - { - if (r > INTMAX_MAX / 10) - return -1; - else if (r == INTMAX_MAX / 10) - if ((c & 15) > INTMAX_MAX % 10) - return -1; - r = r * 10 + (c & 15); - } - else - return -1; - - if (neg) - r = -r; - - done: - - if ((r < min) || (r > max)) - return -1; - - *value = r; - return 0; + + if (!*str) + return -1; + + while ((c = *str)) { + if ('0' <= c && c <= '9') { + if (r > INTMAX_MAX / 10) { + return -1; + } else if (r == INTMAX_MAX / 10) { + if ((c & 15) > INTMAX_MAX % 10) + return -1; + } + r = r * 10 + (c & 15); + } else { + return -1; + } + } + + if (neg) + r = -r; + +done: + if (r < min || r > max) + return -1; + + *value = r; + return 0; } @@ -316,50 +316,53 @@ int strict_atoj(const char* str, intmax_t* value, intmax_t min, intmax_t max) * @param max The maximum accepted value * @return Zero on success, -1 on syntax error */ -int strict_atouj(const char* str, uintmax_t* value, uintmax_t min, uintmax_t max) +int +strict_atouj(const char *str, uintmax_t *value, uintmax_t min, uintmax_t max) { - uintmax_t r = 0; - char c; - - if (*str == '\0') - return -1; - - while ((c = *str)) - if (('0' <= c) && (c <= '9')) - { - if (r > INTMAX_MAX / 10) - return -1; - else if (r == INTMAX_MAX / 10) - if ((c & 15) > INTMAX_MAX % 10) - return -1; - r = r * 10 + (c & 15); - } - else - return -1; - - if ((r < min) || (r > max)) - return -1; - - *value = r; - return 0; + uintmax_t r = 0; + char c; + + if (!*str) + return -1; + + while ((c = *str)) { + if ('0' <= c && c <= '9') { + if (r > INTMAX_MAX / 10) { + return -1; + } else if (r == INTMAX_MAX / 10) { + if ((c & 15) > INTMAX_MAX % 10) + return -1; + } + r = r * 10 + (c & 15); + } else { + return -1; + } + } + + if (r < min || r > max) + return -1; + + *value = r; + return 0; } #if defined(__GNUC__) # pragma GCC diagnostic pop #endif -#define __strict_y(Y, TYPE, PARA_TYPE, HYPER_Y, HYPER_TYPE) \ - int strict_##Y(const char* str, TYPE* value, PARA_TYPE min, PARA_TYPE max) \ - { \ - HYPER_TYPE intermediate_value; \ - if (strict_##HYPER_Y(str, &intermediate_value, (HYPER_TYPE)min, (HYPER_TYPE)max) < 0) \ - return -1; \ - return *value = (TYPE)intermediate_value, 0; \ - } +#define __strict_y(Y, TYPE, PARA_TYPE, HYPER_Y, HYPER_TYPE)\ + int\ + strict_##Y(const char *str, TYPE *value, PARA_TYPE min, PARA_TYPE max)\ + {\ + HYPER_TYPE intermediate_value;\ + if (strict_##HYPER_Y(str, &intermediate_value, (HYPER_TYPE)min, (HYPER_TYPE)max) < 0)\ + return -1;\ + return *value = (TYPE)intermediate_value, 0;\ + } -#define __strict_x(X, TYPE, HYPER_X, HYPER_TYPE) \ - __strict_y(X, TYPE, TYPE, HYPER_X, HYPER_TYPE) +#define __strict_x(X, TYPE, HYPER_X, HYPER_TYPE)\ + __strict_y(X, TYPE, TYPE, HYPER_X, HYPER_TYPE) /** @@ -577,20 +580,20 @@ __strict_x(atou64, uint64_t, atouj, uintmax_t) * @param length The length of the buffer * @return Zero on success, -1 on error */ -int full_write(int fd, const char* buffer, size_t length) +int +full_write(int fd, const char *buffer, size_t length) { - ssize_t wrote; - while (length > 0) - { - errno = 0; - wrote = write(fd, buffer, length); - fail_if (errno && (errno != EINTR)); - length -= (size_t)max(wrote, 0); - buffer += (size_t)max(wrote, 0); - } - return 0; - fail: - return -1; + ssize_t wrote; + while (length > 0) { + errno = 0; + wrote = write(fd, buffer, length); + fail_if (errno && errno != EINTR); + length -= (size_t)max(wrote, 0); + buffer += (size_t)max(wrote, 0); + } + return 0; +fail: + return -1; } @@ -601,44 +604,44 @@ int full_write(int fd, const char* buffer, size_t length) * @param length Output parameter for the length of the file, may be `NULL` * @return The content of the file, you will need to free it. `NULL` on error. */ -char* full_read(int fd, size_t* length) +char * +full_read(int fd, size_t *length) { - char* old_buf = NULL; - size_t buffer_size = 8 << 10; - size_t buffer_ptr = 0; - char* buffer; - ssize_t got; - int saved_errno; - - if (length != NULL) - *length = 0; - - /* Allocate buffer for data. */ - fail_if (xmalloc(buffer, buffer_size, char)); - - /* Read the file. */ - for (;;) - { - /* Grow buffer if it is too small. */ - if (buffer_size == buffer_ptr) - fail_if (xxrealloc(old_buf, buffer, buffer_size <<= 1, char)); - - /* Read from the file into the buffer. */ - got = read(fd, buffer + buffer_ptr, buffer_size - buffer_ptr); - fail_if ((got < 0) && (errno != EINTR)); - if (got == 0) - break; - buffer_ptr += (size_t)got; - } - - if (length != NULL) - *length = buffer_ptr; - return buffer; - fail: - saved_errno = errno; - free(old_buf); - free(buffer); - return errno = saved_errno, NULL; + char *old_buf = NULL; + size_t buffer_size = 8 << 10; + size_t buffer_ptr = 0; + char *buffer; + ssize_t got; + int saved_errno; + + if (length) + *length = 0; + + /* Allocate buffer for data. */ + fail_if (xmalloc(buffer, buffer_size, char)); + + /* Read the file. */ + for (;;) { + /* Grow buffer if it is too small. */ + if (buffer_size == buffer_ptr) + fail_if (xxrealloc(old_buf, buffer, buffer_size <<= 1, char)); + + /* Read from the file into the buffer. */ + got = read(fd, buffer + buffer_ptr, buffer_size - buffer_ptr); + fail_if (got < 0 && errno != EINTR); + if (!got) + break; + buffer_ptr += (size_t)got; + } + + if (length) + *length = buffer_ptr; + return buffer; +fail: + saved_errno = errno; + free(old_buf); + free(buffer); + return errno = saved_errno, NULL; } @@ -650,20 +653,20 @@ char* full_read(int fd, size_t* length) * @param length The length of the message * @return Zero on success, -1 on error */ -int full_send(int socket, const char* message, size_t length) +int +full_send(int socket, const char *message, size_t length) { - size_t sent; + size_t sent; - while (length > 0) - { - sent = send_message(socket, message, length); - fail_if ((sent < length) && (errno != EINTR)); - message += sent; - length -= sent; - } - return 0; - fail: - return -1; + while (length > 0) { + sent = send_message(socket, message, length); + fail_if (sent < length && errno != EINTR); + message += sent; + length -= sent; + } + return 0; +fail: + return -1; } @@ -677,17 +680,18 @@ int full_send(int socket, const char* message, size_t length) * @param needle_n The length of `needle` * @return Whether the `haystack` begins with `needle` */ -int startswith_n(const char* haystack, const char* needle, size_t haystack_n, size_t needle_n) +int +startswith_n(const char *haystack, const char *needle, size_t haystack_n, size_t needle_n) { - size_t i; - if (haystack_n < needle_n) - return 0; - - for (i = 0; i < needle_n; i++) - if (haystack[i] != needle[i]) - return 0; - - return 1; + size_t i; + if (haystack_n < needle_n) + return 0; + + for (i = 0; i < needle_n; i++) + if (haystack[i] != needle[i]) + return 0; + + return 1; } @@ -700,30 +704,30 @@ int startswith_n(const char* haystack, const char* needle, size_t haystack_n, si * @param options See description of `options` in the documentation for `waitpid` * @return See the documentation for `waitpid` */ -pid_t uninterruptable_waitpid(pid_t pid, int* restrict status, int options) +pid_t +uninterruptable_waitpid(pid_t pid, int *restrict status, int options) { - struct timespec time_start; - struct timespec time_intr; - int intr_count = 0, have_time; - pid_t rc; - - have_time = (monotone(&time_start) >= 0); - - rewait: - rc = waitpid(pid, status, options); - if (rc == (pid_t)-1) - { - fail_if (errno != EINTR); - if (have_time && (monotone(&time_intr) >= 0)) - if (time_start.tv_sec != time_intr.tv_sec) - intr_count = 0; - if (intr_count++ < 100) - goto rewait; - /* Don't let the CPU catch fire! */ - errno = EINTR; - } - fail: - return rc; + struct timespec time_start; + struct timespec time_intr; + int intr_count = 0, have_time; + pid_t rc; + + have_time = (monotone(&time_start) >= 0); + +rewait: + rc = waitpid(pid, status, options); + if (rc == (pid_t)-1) { + fail_if (errno != EINTR); + if (have_time && monotone(&time_intr) >= 0) + if (time_start.tv_sec != time_intr.tv_sec) + intr_count = 0; + if (intr_count++ < 100) + goto rewait; + /* Don't let the CPU catch fire! */ + errno = EINTR; + } +fail: + return rc; } @@ -734,72 +738,71 @@ pid_t uninterruptable_waitpid(pid_t pid, int* restrict status, int options) * @param allow_modified_nul Whether Modified UTF-8 is allowed, which allows a two-byte encoding for NUL * @return Zero if good, -1 on encoding error */ -int verify_utf8(const char* string, int allow_modified_nul) +int +verify_utf8(const char *string, int allow_modified_nul) { - static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37}; - static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31}; - long bytes = 0, read_bytes = 0, bits = 0, c, character; - - /* min bits max bits - 0....... 0 7 - 110..... 10...... 8 11 - 1110.... 10...... 10...... 12 16 - 11110... 10...... 10...... 10...... 17 21 - 111110.. 10...... 10...... 10...... 10...... 22 26 - 1111110. 10...... 10...... 10...... 10...... 10...... 27 31 - */ - - while ((c = (long)(*string++))) - if (read_bytes == 0) - { - /* First byte of the character. */ - - if ((c & 0x80) == 0x00) - /* Single-byte character. */ - continue; - - if ((c & 0xC0) == 0x80) - /* Single-byte character marked as multibyte, or - a non-first byte in a multibyte character. */ - return -1; - - /* Multibyte character. */ - while ((c & 0x80)) - bytes++, c <<= 1; - read_bytes = 1; - character = c & 0x7F; - if (bytes > 6) - /* 31-bit characters can be encoded with 6-bytes, - and UTF-8 does not cover higher code points. */ - return -1; - } - else - { - /* Not first byte of the character. */ - - if ((c & 0xC0) != 0x80) - /* Beginning of new character before a - multibyte character has ended. */ - return -1; - - character = (character << 6) | (c & 0x7F); - - if (++read_bytes < bytes) - /* Not at last byte yet. */ - continue; - - /* Check that the character is not unnecessarily long. */ - while (character) - character >>= 1, bits++; - bits = ((bits == 0) && (bytes == 2) && allow_modified_nul) ? 8 : bits; - if ((bits < BYTES_TO_MIN_BITS[bytes]) || (BYTES_TO_MAX_BITS[bytes] < bits)) - return -1; - - read_bytes = bytes = bits = 0; - } - - /* Make sure we did not stop at the middle of a multibyte character. */ - return read_bytes == 0 ? 0 : -1; + static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37}; + static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31}; + long bytes = 0, read_bytes = 0, bits = 0, c, character; + + /* min bits max bits + 0....... 0 7 + 110..... 10...... 8 11 + 1110.... 10...... 10...... 12 16 + 11110... 10...... 10...... 10...... 17 21 + 111110.. 10...... 10...... 10...... 10...... 22 26 + 1111110. 10...... 10...... 10...... 10...... 10...... 27 31 + */ + + while ((c = (long)(*string++))) { + if (read_bytes == 0) { + /* First byte of the character. */ + + if (!(c & 0x80)) + /* Single-byte character. */ + continue; + + if ((c & 0xC0) == 0x80) + /* Single-byte character marked as multibyte, or + a non-first byte in a multibyte character. */ + return -1; + + /* Multibyte character. */ + while ((c & 0x80)) + bytes++, c <<= 1; + read_bytes = 1; + character = c & 0x7F; + if (bytes > 6) + /* 31-bit characters can be encoded with 6-bytes, + and UTF-8 does not cover higher code points. */ + return -1; + } else { + /* Not first byte of the character. */ + + if ((c & 0xC0) != 0x80) + /* Beginning of new character before a + multibyte character has ended. */ + return -1; + + character = (character << 6) | (c & 0x7F); + + if (++read_bytes < bytes) + /* Not at last byte yet. */ + continue; + + /* Check that the character is not unnecessarily long. */ + while (character) + character >>= 1, bits++; + bits = ((bits == 0) && (bytes == 2) && allow_modified_nul) ? 8 : bits; + if ((bits < BYTES_TO_MIN_BITS[bytes]) || (BYTES_TO_MAX_BITS[bytes] < bits)) + return -1; + + read_bytes = bytes = bits = 0; + } + } + + /* Make sure we did not stop at the middle of a multibyte character. */ + return read_bytes == 0 ? 0 : -1; } @@ -828,85 +831,85 @@ int verify_utf8(const char* string, int allow_modified_nul) * @param message_id The message ID of this message * @return The length of the message, zero on error */ -size_t construct_error_message(const char* restrict recv_client_id, const char* restrict recv_message_id, - const char* restrict recv_command, int custom, int errnum, - const char* restrict message, char** restrict send_buffer, - size_t* restrict send_buffer_size, uint32_t message_id) +size_t +construct_error_message(const char *restrict recv_client_id, const char *restrict recv_message_id, + const char *restrict recv_command, int custom, int errnum, + const char *restrict message, char **restrict send_buffer, + size_t *restrict send_buffer_size, uint32_t message_id) { - ssize_t part_length; - size_t length; - char* temp; - - /* Measure the maximum length of message, including NUL-termination.. */ - length = sizeof("Command: error\n" - "To: 4294967296:4294967296\n" - "In response to: 4294967296\n" - "Origin command: \n" - "Message ID: 4294967296\n" - "Error: custom \n" - "Length: \n" - "\n") / sizeof(char) + 3 * (sizeof(int)) + strlen(recv_command); - if (message != NULL) - length += (sizeof("Length: \n") / sizeof(char) - 1) + 3 * sizeof(char) + strlen(message) + 1; - - /* Ensure that the send buffer is large enough. */ - if (length > *send_buffer_size) - { - fail_if (yrealloc(temp, *send_buffer, length, char)); - *send_buffer_size = length; - } - - /* Reset `length` to indicate that the currently written - message has zero in length. */ - length = 0; - - /* Start writting the error message, begin with required - headers, but exclude the error number. */ - sprintf((*send_buffer) + length, - "Command: error\n" - "To: %s\n" - "In response to: %s\n" - "Origin command: %s\n" - "Message ID: %"PRIu32"\n" - "Error: %s%zn", - recv_client_id, recv_message_id, recv_command, - message_id, custom ? "custom" : "", - &part_length), - length += (size_t)part_length; - - /* If the error is custom and has a number we need - blank space before we write the error number. */ - if (custom && (errnum >= 0)) - (*send_buffer)[length++] = ' '; - - /* Add the error number of there is one. */ - if (errnum >= 0) - sprintf((*send_buffer) + length, "%i%zn", errnum, &part_length), - length += (size_t)part_length; - - /* End the `Error`-header line. */ - (*send_buffer)[length++] = '\n'; - - /* Add the `Length`-header if there is a description. */ - if (message != NULL) - sprintf((*send_buffer) + length, "Length: %zu\n%zn", - strlen(message) + 1, &part_length), - length += (size_t)part_length + strlen(message) + 1; - - /* Add an empty line to mark the end of headers. */ - (*send_buffer)[length++] = '\n'; - - /* Write the description if there is one. */ - if (message) - { - memcpy((*send_buffer) + length, message, strlen(message) * sizeof(char)); - length += strlen(message); - (*send_buffer)[length++] = '\n'; - } - - return length; - fail: - return 0; + ssize_t part_length; + size_t length; + char *temp; + + /* Measure the maximum length of message, including NUL-termination.. */ + length = sizeof("Command: error\n" + "To: 4294967296:4294967296\n" + "In response to: 4294967296\n" + "Origin command: \n" + "Message ID: 4294967296\n" + "Error: custom \n" + "Length: \n" + "\n") / sizeof(char) + 3 * (sizeof(int)) + strlen(recv_command); + if (message) + length += (sizeof("Length: \n") / sizeof(char) - 1) + 3 * sizeof(char) + strlen(message) + 1; + + /* Ensure that the send buffer is large enough. */ + if (length > *send_buffer_size) { + fail_if (yrealloc(temp, *send_buffer, length, char)); + *send_buffer_size = length; + } + + /* Reset `length` to indicate that the currently written + message has zero in length. */ + length = 0; + + /* Start writting the error message, begin with required + headers, but exclude the error number. */ + sprintf((*send_buffer) + length, + "Command: error\n" + "To: %s\n" + "In response to: %s\n" + "Origin command: %s\n" + "Message ID: %"PRIu32"\n" + "Error: %s%zn", + recv_client_id, recv_message_id, recv_command, + message_id, custom ? "custom" : "", + &part_length); + length += (size_t)part_length; + + /* If the error is custom and has a number we need + blank space before we write the error number. */ + if (custom && errnum >= 0) + (*send_buffer)[length++] = ' '; + + /* Add the error number of there is one. */ + if (errnum >= 0) + sprintf((*send_buffer) + length, "%i%zn", errnum, &part_length), + length += (size_t)part_length; + + /* End the `Error`-header line. */ + (*send_buffer)[length++] = '\n'; + + /* Add the `Length`-header if there is a description. */ + if (message) { + sprintf((*send_buffer) + length, "Length: %zu\n%zn", + strlen(message) + 1, &part_length); + length += (size_t)part_length + strlen(message) + 1; + } + + /* Add an empty line to mark the end of headers. */ + (*send_buffer)[length++] = '\n'; + + /* Write the description if there is one. */ + if (message) { + memcpy((*send_buffer) + length, message, strlen(message) * sizeof(char)); + length += strlen(message); + (*send_buffer)[length++] = '\n'; + } + + return length; +fail: + return 0; } @@ -936,17 +939,17 @@ size_t construct_error_message(const char* restrict recv_client_id, const char* * @param message_id The message ID of this message * @return Zero on success, -1 on error */ -int send_error(const char* restrict recv_client_id, const char* restrict recv_message_id, - const char* restrict recv_command, int custom, int errnum, const char* restrict message, - char** restrict send_buffer, size_t* restrict send_buffer_size, uint32_t message_id, - int socket_fd) +int +send_error(const char *restrict recv_client_id, const char *restrict recv_message_id, + const char *restrict recv_command, int custom, int errnum, const char *restrict message, + char **restrict send_buffer, size_t *restrict send_buffer_size, uint32_t message_id, + int socket_fd) { - size_t length; - fail_if ((length = construct_error_message(recv_client_id, recv_message_id, recv_command, custom, errnum, - message, send_buffer, send_buffer_size, message_id)) == 0); - fail_if (full_send(socket_fd, *send_buffer, length)); - return 0; - fail: - return -1; + size_t length; + fail_if (!(length = construct_error_message(recv_client_id, recv_message_id, recv_command, custom, errnum, + message, send_buffer, send_buffer_size, message_id))); + fail_if (full_send(socket_fd, *send_buffer, length)); + return 0; +fail: + return -1; } - |