diff options
Diffstat (limited to 'include/util')
| -rw-r--r-- | include/util/array.h | 79 | ||||
| -rw-r--r-- | include/util/hash_table.h | 92 | ||||
| -rw-r--r-- | include/util/mempool.h | 31 | ||||
| -rw-r--r-- | include/util/rbtree.h | 74 | ||||
| -rw-r--r-- | include/util/str_table.h | 63 | ||||
| -rw-r--r-- | include/util/threadpool.h | 125 | ||||
| -rw-r--r-- | include/util/util.h | 38 | ||||
| -rw-r--r-- | include/util/w32threadwrap.h | 105 | 
8 files changed, 607 insertions, 0 deletions
| diff --git a/include/util/array.h b/include/util/array.h new file mode 100644 index 0000000..cbac7c2 --- /dev/null +++ b/include/util/array.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * array.h + * + * Copyright (C) 2021 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef ARRAY_H +#define ARRAY_H + +#include "sqfs/predef.h" +#include "sqfs/error.h" + +#include <stddef.h> +#include <string.h> +#include <stdlib.h> + +typedef struct { +	/* sizeof a single element */ +	size_t size; + +	/* total number of elements available */ +	size_t count; + +	/* actually used number of elements available */ +	size_t used; + +	void *data; +} array_t; + +static SQFS_INLINE void *array_get(array_t *array, size_t index) +{ +	if (index >= array->used) +		return NULL; + +	return (char *)array->data + array->size * index; +} + +static SQFS_INLINE int array_set(array_t *array, size_t index, const void *data) +{ +	if (index >= array->used) +		return SQFS_ERROR_OUT_OF_BOUNDS; + +	memcpy((char *)array->data + array->size * index, data, array->size); +	return 0; +} + +static SQFS_INLINE void array_sort_range(array_t *array, size_t start, +					 size_t count, +					 int (*compare_fun)(const void *a, +							    const void *b)) +{ +	if (start < array->used) { +		if (count > (array->used - start)) +			count = array->used - start; + +		qsort((char *)array->data + array->size * start, count, +		      array->size, compare_fun); +	} +} + +#ifdef __cplusplus +extern "C" { +#endif + +SQFS_INTERNAL int array_init(array_t *array, size_t size, size_t capacity); + +SQFS_INTERNAL int array_init_copy(array_t *array, const array_t *src); + +SQFS_INTERNAL void array_cleanup(array_t *array); + +SQFS_INTERNAL int array_append(array_t *array, const void *data); + +SQFS_INTERNAL int array_set_capacity(array_t *array, size_t capacity); + +#ifdef __cplusplus +} +#endif + +#endif /* ARRAY_H */ diff --git a/include/util/hash_table.h b/include/util/hash_table.h new file mode 100644 index 0000000..813e059 --- /dev/null +++ b/include/util/hash_table.h @@ -0,0 +1,92 @@ +/* + * Copyright © 2009,2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + *    Eric Anholt <eric@anholt.net> + * + */ + +#ifndef _HASH_TABLE_H +#define _HASH_TABLE_H + +#include <stdlib.h> +#include <inttypes.h> +#include <stdbool.h> + +#include "sqfs/predef.h" + +struct hash_entry { +   sqfs_u32 hash; +   const void *key; +   void *data; +}; + +struct hash_table { +   struct hash_entry *table; +   sqfs_u32 (*key_hash_function)(void *user, const void *key); +   bool (*key_equals_function)(void *user, const void *a, const void *b); +   const void *deleted_key; +   void *user; +   sqfs_u32 size; +   sqfs_u32 rehash; +   sqfs_u64 size_magic; +   sqfs_u64 rehash_magic; +   sqfs_u32 max_entries; +   sqfs_u32 size_index; +   sqfs_u32 entries; +   sqfs_u32 deleted_entries; +}; + +SQFS_INTERNAL struct hash_table * +hash_table_create(sqfs_u32 (*key_hash_function)(void *user, const void *key), +                  bool (*key_equals_function)(void *user, const void *a, +                                              const void *b)); + +SQFS_INTERNAL struct hash_table * +hash_table_clone(struct hash_table *src); + +SQFS_INTERNAL void +hash_table_destroy(struct hash_table *ht, +		   void (*delete_function)(struct hash_entry *entry)); + +SQFS_INTERNAL struct hash_entry * +hash_table_insert_pre_hashed(struct hash_table *ht, sqfs_u32 hash, +                             const void *key, void *data); + +SQFS_INTERNAL struct hash_entry * +hash_table_search_pre_hashed(struct hash_table *ht, sqfs_u32 hash, +                             const void *key); + +SQFS_INTERNAL struct hash_entry *hash_table_next_entry(struct hash_table *ht, +						       struct hash_entry *entry); + +/** + * This foreach function is safe against deletion (which just replaces + * an entry's data with the deleted marker), but not against insertion + * (which may rehash the table, making entry a dangling pointer). + */ +#define hash_table_foreach(ht, entry)                                      \ +   for (struct hash_entry *entry = hash_table_next_entry(ht, NULL);  \ +        entry != NULL;                                                     \ +        entry = hash_table_next_entry(ht, entry)) + +#endif /* _HASH_TABLE_H */ diff --git a/include/util/mempool.h b/include/util/mempool.h new file mode 100644 index 0000000..c946c31 --- /dev/null +++ b/include/util/mempool.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * mempool.h + * + * Copyright (C) 2021 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#include "compat.h" +#include "sqfs/predef.h" + +typedef struct mem_pool_t mem_pool_t; + +#ifdef __cplusplus +extern "C" { +#endif + +SQFS_INTERNAL mem_pool_t *mem_pool_create(size_t obj_size); + +SQFS_INTERNAL void mem_pool_destroy(mem_pool_t *mem); + +SQFS_INTERNAL void *mem_pool_allocate(mem_pool_t *mem); + +SQFS_INTERNAL void mem_pool_free(mem_pool_t *mem, void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* MEMPOOL_H */ diff --git a/include/util/rbtree.h b/include/util/rbtree.h new file mode 100644 index 0000000..aac175b --- /dev/null +++ b/include/util/rbtree.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * rbtree.h + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef SQFS_RBTREE_H +#define SQFS_RBTREE_H + +#include "config.h" +#include "sqfs/predef.h" +#include "mempool.h" +#include "compat.h" + +#include <stddef.h> + +typedef struct rbtree_node_t { +	struct rbtree_node_t *left; +	struct rbtree_node_t *right; +	sqfs_u32 value_offset; +	sqfs_u32 is_red : 1; +	sqfs_u32 pad0 : 31; + +	sqfs_u8 data[]; +} rbtree_node_t; + +typedef struct rbtree_t { +	rbtree_node_t *root; + +#ifndef NO_CUSTOM_ALLOC +	mem_pool_t *pool; +#endif + +	int (*key_compare)(const void *ctx, +			   const void *lhs, const void *hrs); + +	size_t key_size; +	size_t key_size_padded; + +	size_t value_size; + +	void *key_context; +} rbtree_t; + +static SQFS_INLINE void *rbtree_node_key(rbtree_node_t *n) +{ +	return n->data; +} + +static SQFS_INLINE void *rbtree_node_value(rbtree_node_t *n) +{ +	return n->data + n->value_offset; +} + +SQFS_INTERNAL int rbtree_init(rbtree_t *tree, size_t keysize, size_t valuesize, +			      int(*key_compare)(const void *, const void *, +						const void *)); + +SQFS_INTERNAL void rbtree_cleanup(rbtree_t *tree); + +SQFS_INTERNAL int rbtree_copy(const rbtree_t *tree, rbtree_t *out); + +SQFS_INTERNAL int rbtree_insert(rbtree_t *tree, const void *key, +				const void *value); + +SQFS_INTERNAL rbtree_node_t *rbtree_lookup(const rbtree_t *tree, +					   const void *key); + +#ifdef __cplusplus +} +#endif + +#endif /* TOOLS_RBTREE_H */ + diff --git a/include/util/str_table.h b/include/util/str_table.h new file mode 100644 index 0000000..206fa3a --- /dev/null +++ b/include/util/str_table.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * str_table.h + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef STR_TABLE_H +#define STR_TABLE_H + +#include "sqfs/predef.h" +#include "array.h" +#include "hash_table.h" + +typedef struct { +	size_t index; +	size_t refcount; +	char string[]; +} str_bucket_t; + +/* Stores strings in a hash table and assigns an incremental, unique ID to +   each string. Subsequent additions return the existing ID. The ID can be +   used for (hopefully) constant time lookup of the original string. */ +typedef struct { +	/* an array that resolves index to bucket pointer */ +	array_t bucket_ptrs; + +	/* hash table with the string buckets attached */ +	struct hash_table *ht; + +	/* the next ID we are going to allocate */ +	size_t next_index; +} str_table_t; + +/* the number of strings currently stored in the table */ +static SQFS_INLINE size_t str_table_count(const str_table_t *table) +{ +	return table->next_index; +} + +/* `size` is the number of hash table buckets to use internally. */ +SQFS_INTERNAL int str_table_init(str_table_t *table); + +SQFS_INTERNAL void str_table_cleanup(str_table_t *table); + +SQFS_INTERNAL int str_table_copy(str_table_t *dst, const str_table_t *src); + +/* Resolve a string to an incremental, unique ID. */ +SQFS_INTERNAL +int str_table_get_index(str_table_t *table, const char *str, size_t *idx); + +/* Resolve a unique ID to the string it represents. +   Returns NULL if the ID is unknown, i.e. out of bounds. */ +SQFS_INTERNAL +const char *str_table_get_string(const str_table_t *table, size_t index); + +SQFS_INTERNAL void str_table_add_ref(str_table_t *table, size_t index); + +SQFS_INTERNAL void str_table_del_ref(str_table_t *table, size_t index); + +SQFS_INTERNAL +size_t str_table_get_ref_count(const str_table_t *table, size_t index); + +#endif /* STR_TABLE_H */ diff --git a/include/util/threadpool.h b/include/util/threadpool.h new file mode 100644 index 0000000..f25c497 --- /dev/null +++ b/include/util/threadpool.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * threadpool.h + * + * Copyright (C) 2021 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef THREADPOOL_H +#define THREADPOOL_H + +#include "sqfs/predef.h" + +typedef int (*thread_pool_worker_t)(void *user, void *work_item); + +/** + * @struct thread_pool_t + * + * @brief A thread pool with a ticket number based work item ordering. + * + * While the order in which items are non-deterministic, the thread pool + * implementation internally uses a ticket system to ensure the completed + * items are deqeueued in the same order that they were enqueued. + */ +typedef struct thread_pool_t { +	/** +	 * @brief Shutdown and destroy a thread pool. +	 * +	 * @param pool A pointer to a pool returned by thread_pool_create +	 */ +	void (*destroy)(struct thread_pool_t *pool); + +	/** +	 * @brief Get the actual number of worker threads available. +	 * +	 * @return A number greater or equal to 1. +	 */ +	size_t (*get_worker_count)(struct thread_pool_t *pool); + +	/** +	 * @brief Change the user data pointer for a thread pool worker +	 *        by index. +	 * +	 * @param idx A zero-based index into the worker list. +	 * @param ptr A user pointer that this specific worker thread should +	 *            pass to the worker callback. +	 */ +	void (*set_worker_ptr)(struct thread_pool_t *pool, size_t idx, +			       void *ptr); + +	/** +	 * @brief Submit a work item to a thread pool. +	 * +	 * This function will fail on allocation failure or if the internal +	 * error state is set was set by one of the workers. +	 * +	 * @param ptr A pointer to a work object to enqueue. +	 * +	 * @return Zero on success. +	 */ +	int (*submit)(struct thread_pool_t *pool, void *ptr); + +	/** +	 * @brief Wait for a work item to be completed. +	 * +	 * This function dequeues a single completed work item. It may block +	 * until one of the worker threads signals completion of an additional +	 * item. +	 * +	 * This function guarantees to return the items in the same order as +	 * they were submitted, so the function can actually block longer than +	 * necessary, because it has to wait until the next item in sequence +	 * is finished. +	 * +	 * @return A pointer to a new work item or NULL if there are none +	 *         in the pipeline. +	 */ +	void *(*dequeue)(struct thread_pool_t *pool); + +	/** +	 * @brief Get the internal worker return status value. +	 * +	 * If the worker functions returns a non-zero exit status in one of the +	 * worker threads, the thread pool stors the value internally and shuts +	 * down. This function can be used to retrieve the value. +	 * +	 * @return A non-zero value returned by the worker callback or zero if +	 *         everything is A-OK. +	 */ +	int (*get_status)(struct thread_pool_t *pool); +} thread_pool_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Create a thread pool instance. + * + * @param num_jobs The number of worker threads to launch. + * @param worker A function to call from the worker threads to process + *               the work items. + * + * @return A pointer to a thread pool on success, NULL on failure. + */ +SQFS_INTERNAL thread_pool_t *thread_pool_create(size_t num_jobs, +						thread_pool_worker_t worker); + +/** + * @brief Create a serial mockup thread pool implementation. + * + * This returns a @ref thread_pool_t implementation that, instead of running a + * thread pool actually does the work in-situ when dequeueing. + * + * @param worker A function to call from the worker threads to process + *               the work items. + * + * @return A pointer to a thread pool on success, NULL on failure. + */ +SQFS_INTERNAL +thread_pool_t *thread_pool_create_serial(thread_pool_worker_t worker); + +#ifdef __cplusplus +} +#endif + +#endif /* THREADPOOL_H */ diff --git a/include/util/util.h b/include/util/util.h new file mode 100644 index 0000000..4b05340 --- /dev/null +++ b/include/util/util.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * util.h + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef SQFS_UTIL_H +#define SQFS_UTIL_H + +#include "config.h" +#include "sqfs/predef.h" +#include "compat.h" + +#include <stddef.h> + +/* +  Helper for allocating data structures with flexible array members. + +  'base_size' is the size of the struct itself, 'item_size' the size of a +  single array element and 'nmemb' the number of elements. + +  Iternally checks for arithmetic overflows when allocating the combined thing. + */ +SQFS_INTERNAL +void *alloc_flex(size_t base_size, size_t item_size, size_t nmemb); + +/* Basically the same as calloc, but *ALWAYS* does overflow checking */ +SQFS_INTERNAL +void *alloc_array(size_t item_size, size_t nmemb); + +SQFS_INTERNAL sqfs_u32 xxh32(const void *input, const size_t len); + +/* +  Returns true if the given region of memory is filled with zero-bytes only. + */ +SQFS_INTERNAL bool is_memory_zero(const void *blob, size_t size); + +#endif /* SQFS_UTIL_H */ diff --git a/include/util/w32threadwrap.h b/include/util/w32threadwrap.h new file mode 100644 index 0000000..6b7344c --- /dev/null +++ b/include/util/w32threadwrap.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * w32threadwrap.h + * + * Copyright (C) 2021 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef W32THREADWRAP_H +#define W32THREADWRAP_H + +#include "sqfs/predef.h" + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN +#include <windows.h> + +typedef unsigned int sigset_t; +typedef HANDLE pthread_t; +typedef CRITICAL_SECTION pthread_mutex_t; +typedef CONDITION_VARIABLE pthread_cond_t; + +static inline int pthread_create(pthread_t *thread, const void *attr, +				 LPTHREAD_START_ROUTINE proc, LPVOID arg) +{ +	HANDLE hnd = CreateThread(NULL, 0, proc, arg, 0, 0); +	(void)attr; + +	if (hnd == NULL) +		return -1; + +	*thread = hnd; +	return 0; +} + +static int pthread_join(pthread_t thread, void **retval) +{ +	WaitForSingleObject(thread, INFINITE); +	CloseHandle(thread); +	if (retval != NULL) +		*retval = NULL; +	return 0; +} + +static inline int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr) +{ +	(void)attr; +	InitializeCriticalSection(mutex); +	return 0; +} + +static inline int pthread_mutex_lock(pthread_mutex_t *mutex) +{ +	EnterCriticalSection(mutex); +	return 0; +} + +static inline int pthread_mutex_unlock(pthread_mutex_t *mutex) +{ +	LeaveCriticalSection(mutex); +	return 0; +} + +static inline void pthread_mutex_destroy(pthread_mutex_t *mutex) +{ +	DeleteCriticalSection(mutex); +} + +static inline int pthread_cond_init(pthread_cond_t *cond, const void *attr) +{ +	(void)attr; +	InitializeConditionVariable(cond); +	return 0; +} + +static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mtx) +{ +	return SleepConditionVariableCS(cond, mtx, INFINITE) != 0; +} + +static inline int pthread_cond_broadcast(pthread_cond_t *cond) +{ +	WakeAllConditionVariable(cond); +	return 0; +} + +static inline void pthread_cond_destroy(pthread_cond_t *cond) +{ +	(void)cond; +} + +#define SIG_SETMASK (0) + +static inline int sigfillset(sigset_t *set) +{ +	*set = 0xFFFFFFFF; +	return 0; +} + +static inline int pthread_sigmask(int how, const sigset_t *set, +				  const sigset_t *old) +{ +	(void)how; (void)set; (void)old; +	return 0; +} + +#endif /* W32THREADWRAP_H */ | 
