Add documentation, expand error handling, implement file and buffer io

This commit is contained in:
2024-06-03 22:11:05 +03:00
parent fdbabab0e0
commit 79874622a2
37 changed files with 5531 additions and 986 deletions

View File

@@ -23,8 +23,9 @@ include(CTest)
enable_testing()
# Set library code
set(BHLIB_SOURCE
set(BH_SOURCE
src/algo.c
src/buffer.c
src/hashmap.c
src/queue.c
src/thread.c
@@ -32,9 +33,10 @@ set(BHLIB_SOURCE
src/deflate.c
)
set(BHLIB_HEADER
set(BH_HEADER
include/bh/bh.h
include/bh/platform.h
include/bh/buffer.h
include/bh/algo.h
include/bh/hashmap.h
include/bh/queue.h
@@ -43,7 +45,7 @@ set(BHLIB_HEADER
include/bh/deflate.h
)
set(BHLIB_INCLUDE_DIRS
set(BH_INCLUDE_DIRS
include
${PROJECT_BINARY_DIR}/include
)
@@ -52,45 +54,58 @@ set(BHLIB_INCLUDE_DIRS
# Determine platform
if(WIN32)
message(STATUS "Platform - Win32")
set(BH_PLATFORM_WIN TRUE)
# Add platform dependent files
list(APPEND BH_SOURCE
src/file_win.c
)
# Check multithreading support
check_symbol_exists(_beginthread process.h BHLIB_USE_WINTHREAD)
if(BHLIB_USE_WINTHREAD)
check_symbol_exists(_beginthread process.h BH_USE_WINTHREAD)
if(BH_USE_WINTHREAD)
message(STATUS "Multithreading enabled")
list(APPEND BHLIB_SOURCE
list(APPEND BH_SOURCE
src/thread_win.c
)
else()
message(STATUS "Multithreading disabled")
list(APPEND BHLIB_SOURCE
list(APPEND BH_SOURCE
src/thread_null.c
)
endif()
if(BHLIB_NO_WINXP)
if(BH_NO_WINXP)
add_definitions(-D_WIN32_WINNT=_WIN32_WINNT_VISTA -DWINVER=_WIN32_WINNT_VISTA)
endif()
elseif(UNIX)
message(STATUS "Platform: Unix (Linux/BSD/MacOS X)")
set(BH_PLATFORM_POSIX TRUE)
# Add platform dependent files
list(APPEND BH_SOURCE
src/file_posix.c
)
# Check multithreading support
check_include_file(pthread.h BHLIB_USE_PTHREAD)
if(BHLIB_USE_PTHREAD)
check_include_file(pthread.h BH_USE_PTHREAD)
if(BH_USE_PTHREAD)
message(STATUS "Multithreading enabled")
list(APPEND BHLIB_SOURCE
list(APPEND BH_SOURCE
src/thread_posix.c
)
else()
message(STATUS "Multithreading disabled")
list(APPEND BHLIB_SOURCE
list(APPEND BH_SOURCE
src/thread_null.c
)
endif()
else()
message(STATUS "Platform: Unknown")
message(STATUS "Multithreading disabled")
list(APPEND BHLIB_SOURCE
list(APPEND BH_SOURCE
src/thread_null.c
src/file_null.c
)
endif()
@@ -98,8 +113,8 @@ endif()
configure_file(include/bh/config.in include/bh/config.h)
# Library
add_library(bhlib STATIC ${BHLIB_SOURCE} ${BHLIB_HEADER})
target_include_directories(bhlib PUBLIC ${BHLIB_INCLUDE_DIRS})
add_library(bhlib STATIC ${BH_SOURCE} ${BH_HEADER})
target_include_directories(bhlib PUBLIC ${BH_INCLUDE_DIRS})
# Runtime definition
add_executable(main

2737
docs/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,154 +1,63 @@
#ifndef BHLIB_ALGO_H
#define BHLIB_ALGO_H
#ifndef BH_ALGO_H
#define BH_ALGO_H
#include "bh.h"
/**
* @brief Swap two elements.
*
* @param lhs Pointer to the first element
* @param rhs Pointer to the second element
* @param size Element size
*/
void bh_swap(void *lhs,
void *rhs,
void bh_swap(void *dest,
void *src,
size_t size);
/**
* @brief Partition the array.
*
* @param pivot Pointer to the pivot element
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*
* @return The return value is the pointer to the first element of the second
* partition.
*
* @warning Pivot element can be a part of the partitioned array.
*/
void *bh_partition(void *pivot,
void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
/**
* @brief Sort the array.
*
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*/
void bh_sort(void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
/**
* @brief Sort the array using insert sort.
*
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*/
void bh_sort_insert(void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
/**
* @brief Sort the array using shell sort.
*
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*/
void bh_sort_shell(void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
/**
* @brief Sort the array using intro sort.
*
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*/
void bh_sort_intro(void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
/**
* @brief Sort the array using heap sort.
*
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*/
void bh_sort_heap(void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
/**
* @brief Make heap from the array.
*
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*
* @sa bh_heap_remove, bh_heap_insert
*/
void bh_heap_make(void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
/**
* @brief Remove element from the heap.
*
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*
* @warning Removed element is placed at the end of the array
*
* @sa bh_heap_make, bh_heap_remove
*/
void bh_heap_remove(void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
/**
* @brief Insert element to the heap.
*
* @param value Pointer to the inserted value (optional)
* @param array Pointer to the array
* @param size Array size
* @param element Element size
* @param equal Equal/compare function
*
* @warning If value is not passed, function assumes inserted element
* is already placed at the end of the array.
*
* @sa bh_heap_make, bh_heap_remove
*/
void bh_heap_insert(void *value,
void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
#endif /* BHLIB_ALGO_H */
void bh_heap_replace(void *value,
void *array,
size_t size,
size_t element,
bh_equal_cb_t equal);
#endif /* BH_ALGO_H */

View File

@@ -1,5 +1,5 @@
#ifndef BHLIB_H
#define BHLIB_H
#ifndef BH_H
#define BH_H
#include <bh/config.h>
#include <stddef.h>
@@ -18,8 +18,17 @@
#define BH_PTR_TO_UINT(x) \
((bh_uintptr_t)(x))
#define BH_OK 0x0000
#define BH_ERROR 0x0001
#define BH_OOM 0x0002
#define BH_INVALID 0x0003
#define BH_NO_IMPL 0x0004
#define BH_FOUND 0x0005
#define BH_NOT_FOUND 0x0006
#define BH_TIMEOUT 0x0007
typedef int (*bh_equal_cb_t)(const void *, const void *);
typedef size_t (*bh_hash_cb_t)(const void *);
#endif /* BHLIB_H */
#endif /* BH_H */

91
include/bh/buffer.h Normal file
View File

@@ -0,0 +1,91 @@
#ifndef BH_BUFFER_H
#define BH_BUFFER_H
#include "io.h"
typedef struct bh_buffer_s bh_buffer_t;
bh_buffer_t *bh_buffer_new(void);
void bh_buffer_free(bh_buffer_t *buffer);
const char *bh_buffer_data(bh_buffer_t *buffer);
void bh_buffer_set_data(bh_buffer_t *buffer,
const char *data,
size_t size);
size_t bh_buffer_capacity(bh_buffer_t *buffer);
int bh_buffer_reserve(bh_buffer_t *buffer,
size_t size);
int bh_buffer_open_base(bh_buffer_t *buffer,
int mode);
void bh_buffer_close_base(bh_buffer_t *buffer);
int bh_buffer_is_open_base(bh_buffer_t *buffer);
size_t bh_buffer_read_base(bh_buffer_t *buffer,
char *data,
size_t size);
size_t bh_buffer_write_base(bh_buffer_t *buffer,
const char *data,
size_t size);
void bh_buffer_flush_base(bh_buffer_t *buffer);
int bh_buffer_seek_base(bh_buffer_t *buffer,
bh_off_t pos,
int dir);
bh_off_t bh_buffer_size_base(bh_buffer_t *buffer);
bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer);
bh_off_t bh_buffer_available_base(bh_buffer_t *buffer);
void bh_buffer_clear_base(bh_buffer_t *buffer);
#define bh_buffer_open(buffer, mode) \
bh_io_open((bh_io_t *)(buffer), (mode))
#define bh_buffer_close(buffer) \
bh_io_close((bh_io_t *)(buffer))
#define bh_buffer_is_open(buffer) \
bh_io_is_open((bh_io_t *)(buffer))
#define bh_buffer_read(buffer, data, size) \
bh_io_read((bh_io_t *)(buffer), (data), (size))
#define bh_buffer_write(buffer, data, size) \
bh_io_write((bh_io_t *)(buffer), (data), (size))
#define bh_buffer_flush(buffer) \
bh_io_flush((bh_io_t *)(buffer))
#define bh_buffer_seek(buffer, pos, dir) \
bh_io_seek((bh_io_t *)(buffer), (pos), (dir))
#define bh_buffer_size(buffer) \
bh_io_size((bh_io_t *)(buffer))
#define bh_buffer_tell(buffer) \
bh_io_tell((bh_io_t *)(buffer))
#define bh_buffer_available(buffer) \
bh_io_available((bh_io_t *)(buffer))
#define bh_buffer_clear(buffer) \
bh_io_clear((bh_io_t *)(buffer))
#define bh_buffer_error(buffer) \
bh_io_error((bh_io_t *)(buffer))
#define bh_buffer_eof(buffer) \
bh_io_eof((bh_io_t *)(buffer))
#endif /* BH_BUFFER_H */

View File

@@ -1,8 +1,10 @@
#ifndef BHLIB_CONFIG_H
#define BHLIB_CONFIG_H
#ifndef BH_CONFIG_H
#define BH_CONFIG_H
#cmakedefine BHLIB_USE_WINTHREAD
#cmakedefine BHLIB_USE_PTHREAD
#cmakedefine BHLIB_NO_WINXP
#cmakedefine BH_USE_WINTHREAD
#cmakedefine BH_USE_PTHREAD
#cmakedefine BH_NO_WINXP
#cmakedefine BH_PLATFORM_POSIX
#cmakedefine BH_PLATFORM_WIN
#endif /* BHLIB_CONFIG_H */
#endif /* BH_CONFIG_H */

View File

@@ -1,5 +1,5 @@
#ifndef BHLIB_DEFLATE_H
#define BHLIB_DEFLATE_H
#ifndef BH_DEFLATE_H
#define BH_DEFLATE_H
#endif /* BHLIB_DEFLATE_H */
#endif /* BH_DEFLATE_H */

View File

@@ -1,37 +1,80 @@
#ifndef BHLIB_FILE_H
#define BHLIB_FILE_H
#ifndef BH_FILE_H
#define BH_FILE_H
#include "io.h"
typedef struct bh_file_s bh_file_t;
bh_file_t *bh_file_new(const char *path,
const char *mode);
bh_file_t *bh_file_new(const char *path);
void bh_file_free(bh_file_t *file);
size_t bh_file_read(bh_file_t *file,
char *buffer,
int bh_file_open_base(bh_file_t *file,
int mode);
void bh_file_close_base(bh_file_t *file);
int bh_file_is_open_base(bh_file_t *file);
size_t bh_file_read_base(bh_file_t *file,
char *data,
size_t size);
size_t bh_file_write(bh_file_t *file,
const char *buffer,
size_t bh_file_write_base(bh_file_t *file,
const char *data,
size_t size);
void bh_file_flush(bh_file_t *file);
void bh_file_flush_base(bh_file_t *file);
void bh_file_seek(bh_file_t *file,
int bh_file_seek_base(bh_file_t *file,
bh_off_t pos,
int dir);
bh_off_t bh_file_tell(bh_file_t *file);
bh_off_t bh_file_size_base(bh_file_t *file);
bh_off_t bh_file_available(bh_file_t *file);
bh_off_t bh_file_tell_base(bh_file_t *file);
int bh_file_error(bh_file_t *file);
bh_off_t bh_file_available_base(bh_file_t *file);
int bh_file_eof(bh_file_t *file);
void bh_file_clear_base(bh_file_t *file);
void bh_file_clear(bh_file_t *file);
#define bh_file_open(file, mode) \
bh_io_open((bh_io_t *)(file), (mode))
#endif /* BHLIB_FILE_H */
#define bh_file_close(file) \
bh_io_close((bh_io_t *)(file))
#define bh_file_is_open(file) \
bh_io_is_open((bh_io_t *)(file))
#define bh_file_read(file, data, size) \
bh_io_read((bh_io_t *)(file), (data), (size))
#define bh_file_write(file, data, size) \
bh_io_write((bh_io_t *)(file), (data), (size))
#define bh_file_flush(file) \
bh_io_flush((bh_io_t *)(file))
#define bh_file_seek(file, pos, dir) \
bh_io_seek((bh_io_t *)(file), (pos), (dir))
#define bh_file_size(file) \
bh_io_size((bh_io_t *)(file))
#define bh_file_tell(file) \
bh_io_tell((bh_io_t *)(file))
#define bh_file_available(file) \
bh_io_available((bh_io_t *)(file))
#define bh_file_clear(file) \
bh_io_clear((bh_io_t *)(file))
#define bh_file_error(file) \
bh_io_error((bh_io_t *)(file))
#define bh_file_eof(file) \
bh_io_eof((bh_io_t *)(file))
#endif /* BH_FILE_H */

View File

@@ -1,231 +1,53 @@
#ifndef BHLIB_HASHMAP_H
#define BHLIB_HASHMAP_H
#ifndef BH_HASHMAP_H
#define BH_HASHMAP_H
#include "bh.h"
typedef struct bh_hashmap_s bh_hashmap_t;
/**
* @brief Create new hashmap object.
*
* @param equal Function used for comparing keys
* @param hash Function used to calculate hash value of the key
*
* @return If the function succeeds, the return value is a pointer to the new
* hashmap object.
* @return If the function fails, the return value is NULL.
*
* @sa bh_hashmap_free, bh_hashmap_reserve, bh_hashmap_insert
*/
bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal,
bh_hash_cb_t hash);
/**
* @brief Free hashmap object.
*
* @param hashmap Valid pointer to the hashmap object.
*
* @sa bh_hashmap_clear
*/
void bh_hashmap_free(bh_hashmap_t *hashmap);
/**
* @brief Clear the hashmap.
*
* @param hashmap Valid pointer to the hashmap object.
*
* @warning Calling this function will invalidate iterators.
*
* @sa bh_hashmap_remove
*/
void bh_hashmap_clear(bh_hashmap_t *hashmap);
/**
* @brief Reserve space for the specified amount of elements.
*
* @param hashmap Valid pointer to the hashmap object.
* @param size The amount of elements.
*
* @return If the function succeeds, the return value is zero.
* @return If the function fails, the return value is non-zero.
*
* @warning Calling this function will invalidate iterators.
*
* @sa bh_hashmap_capacity, bh_hashmap_insert
*/
int bh_hashmap_reserve(bh_hashmap_t *hashmap,
size_t size);
/**
* @brief Insert key/value into the hashmap.
*
* @param hashmap Valid pointer to the hashmap object.
* @param key Key
* @param value Value
*
* @return If the function succeeds, the return value is zero.
* @return If the function fails, the return value is non-zero.
*
* @warning Inserted element is owned by the caller of the function.
* @warning Calling this function will invalidate iterators.
*
* @sa bh_hashmap_remove, bh_hashmap_at
*/
int bh_hashmap_insert(bh_hashmap_t *hashmap,
void *key,
void *value);
/**
* @brief Remove element from the hashmap.
*
* @param hashmap Valid pointer to the hashmap object.
* @param key Key.
*
* @warning Calling this function will invalidate iterators.
*
* @sa bh_hashmap_insert, bh_hashmap_at
*/
void bh_hashmap_remove(bh_hashmap_t *hashmap,
void *key);
/**
* @brief Return element value by the key from the hashmap.
*
* @param hashmap Valid pointer to the hashmap.
* @param key Key.
* @param exists Optional pointer to the exists flag.
*
* @return If the function succeeds, the return value is a valid pointer to
* the element value.
* @return If the function fails, the return value is NULL.
*
* @sa bh_hashmap_empty, bh_hashmap_insert
*/
void *bh_hashmap_at(bh_hashmap_t *hashmap,
void *key,
int *exists);
/**
* @brief Check if the hashmap is empty.
*
* @param hashmap Valid pointer to the hashmap object.
*
* @return The return value is non-zero if the hashmap is empty, otherwise
* zero.
*
* @sa bh_hashmap_size
*/
int bh_hashmap_empty(bh_hashmap_t *hashmap);
/**
* @brief Return hashmap size.
*
* @param hashmap Valid pointer to the hashmap object.
*
* @return The return value is current hashmap size.
*
* @sa bh_hashmap_empty, bh_hashmap_capacity
*/
size_t bh_hashmap_size(bh_hashmap_t *hashmap);
/**
* @brief Return hashmap capacity.
*
* @param hashmap Valid pointer to the hashmap object.
*
* @return The return value is current hashmap capacity.
*
* @sa bh_hashmap_reserve, bh_hashmap_size
*/
size_t bh_hashmap_capacity(bh_hashmap_t *hashmap);
/**
* @brief Return hashmap load factor.
*
* @param hashmap Valid pointer to the hashmap object.
*
* @return The return value is current hashmap load factor.
*
* @sa bh_hashmap_set_factor, bh_hashmap_capacity
*/
float bh_hashmap_factor(bh_hashmap_t *hashmap);
/**
* @brief Set hashmap load factor.
*
* @param hashmap Valid pointer to the hashmap object.
* @param factor Load factor.
*
* @sa bh_hashmap_factor
*/
void bh_hashmap_set_factor(bh_hashmap_t *hashmap,
float factor);
/**
* @brief Return iterator for the element by the key.
*
* @param hashmap Valid pointer to the hashmap object.
* @param key Key
*
* @return The return value is the valid iterator for the element in the
* hashmap.
* @return The return value is the NULL iterator if there is no element with
* specified key.
*
* @sa bh_hashmap_iter_key, bh_hashmap_iter_value
*/
void *bh_hashmap_iter_at(bh_hashmap_t *hashmap,
void *key);
/**
* @brief Return iterator for the next element in the hashmap.
*
* @param hashmap Valid pointer to the hashmap object.
* @param iter Valid or NULL iterator.
*
* @return The return value is the valid iterator for the next element in the
* hashmap.
* @return The return value is the NULL iterator if there is no more elements
* in the hashmap.
*
* @sa bh_hashmap_iter_key, bh_hashmap_iter_value
*/
void *bh_hashmap_iter_next(bh_hashmap_t *hashmap,
void *iter);
/**
* @brief Remove element from the hashmap by the iterator.
*
* @param hashmap Valid pointer to the hashmap object.
* @param key Valid iterator.
*
* @warning Calling this function will invalidate iterators.
*
* @sa bh_hashmap_insert, bh_hashmap_at
*/
void bh_hashmap_iter_remove(bh_hashmap_t *hashmap,
void *iter);
/**
* @brief Return pointer to the element's key.
*
* @param iter Valid iterator.
*
* @return The return value is the stored element key.
*
* @sa bh_hashmap_iter_value, bh_hashmap_iter_next
*/
void *bh_hashmap_iter_key(void *iter);
/**
* @brief Return pointer to the element's value.
*
* @param iter Valid iterator.
*
* @return The return value is the stored element value.
*
* @sa bh_hashmap_iter_key, bh_hashmap_iter_next
*/
void *bh_hashmap_iter_value(void *iter);
#endif /* BHLIB_HASHMAP_H */
#endif /* BH_HASHMAP_H */

View File

@@ -0,0 +1,20 @@
#ifndef BH_INTERNAL_BUFFER_H
#define BH_INTERNAL_BUFFER_H
#include <bh/buffer.h>
struct bh_buffer_s
{
bh_io_t base;
char *data;
size_t capacity;
size_t size;
size_t at;
int mode;
};
int bh_buffer_init(bh_buffer_t *buffer);
void bh_buffer_destroy(bh_buffer_t *buffer);
#endif /* BH_INTERNAL_BUFFER_H */

View File

@@ -0,0 +1,20 @@
#ifndef BH_INTERNAL_FILE_H
#define BH_INTERNAL_FILE_H
#include "io.h"
#include <bh/file.h>
#if defined(BH_PLATFORM_POSIX)
#include "file_posix.h"
#elif defined(BH_PLATFORM_WIN)
#include "file_win.h"
#else
#include "file_null.h"
#endif
int bh_file_init(bh_file_t *file,
const char *path);
void bh_file_destroy(bh_file_t *file);
#endif /* BH_INTERNAL_FILE_H */

View File

@@ -0,0 +1,4 @@
struct bh_file_s
{
bh_io_t base;
};

View File

@@ -0,0 +1,9 @@
#include <unistd.h>
struct bh_file_s
{
bh_io_t base;
char *path;
int mode;
int handle;
};

View File

@@ -0,0 +1,9 @@
#include <windows.h>
struct bh_file_s
{
bh_io_t base;
char *path;
int mode;
HANDLE handle;
};

View File

@@ -1,5 +1,5 @@
#ifndef BHLIB_INTERNAL_HASHMAP_H
#define BHLIB_INTERNAL_HASHMAP_H
#ifndef BH_INTERNAL_HASHMAP_H
#define BH_INTERNAL_HASHMAP_H
#include <bh/hashmap.h>
@@ -27,4 +27,4 @@ void bh_hashmap_init(bh_hashmap_t *hashmap,
void bh_hashmap_destroy(bh_hashmap_t *hashmap);
#endif /* BHLIB_INTERNAL_HASHMAP_H */
#endif /* BH_INTERNAL_HASHMAP_H */

View File

@@ -1,12 +1,12 @@
#ifndef BHLIB_INTERNAL_IO_H
#define BHLIB_INTERNAL_IO_H
#ifndef BH_INTERNAL_IO_H
#define BH_INTERNAL_IO_H
#include <bh/io.h>
void bh_io_init(bh_io_t *io,
bh_io_table_t *table);
const bh_io_table_t *table);
void bh_io_destroy(bh_io_t *io);
#endif /* BHLIB_INTERNAL_IO_H */
#endif /* BH_INTERNAL_IO_H */

View File

@@ -1,5 +1,5 @@
#ifndef BHLIB_INTERNAL_QUEUE_H
#define BHLIB_INTERNAL_QUEUE_H
#ifndef BH_INTERNAL_QUEUE_H
#define BH_INTERNAL_QUEUE_H
#include <bh/queue.h>
@@ -12,24 +12,8 @@ struct bh_queue_s
size_t capacity;
};
/**
* @internal
* @brief Initialize embedded queue object.
*
* @param queue Valid pointer to the queue object.
*
* @sa bh_queue_destroy
*/
void bh_queue_init(bh_queue_t *queue);
/**
* @internal
* @brief Destroy embedded queue object.
*
* @param queue Valid pointer to the queue object.
*
* @sa bh_queue_init
*/
void bh_queue_destroy(bh_queue_t *queue);
#endif /* BHLIB_INTERNAL_QUEUE_H */
#endif /* BH_INTERNAL_QUEUE_H */

View File

@@ -1,14 +1,14 @@
#ifndef BHLIB_INTERNAL_THREAD_H
#define BHLIB_INTERNAL_THREAD_H
#ifndef BH_INTERNAL_THREAD_H
#define BH_INTERNAL_THREAD_H
#include <bh/thread.h>
#include "queue.h"
#define BH_THREAD_DONE (1 << 8)
#define BH_THREAD_DONE 0x0100
#if defined(BHLIB_USE_PTHREAD)
#if defined(BH_USE_PTHREAD)
#include "thread_posix.h"
#elif defined(BHLIB_USE_WINTHREAD)
#elif defined(BH_USE_WINTHREAD)
#include "thread_win.h"
#else
#include "thread_null.h"
@@ -42,4 +42,4 @@ void bh_task_destroy(bh_task_t *task);
void bh_thread_pool_worker(void *arg);
#endif /* BHLIB_INTERNAL_THREAD_H */
#endif /* BH_INTERNAL_THREAD_H */

View File

@@ -1,10 +1,24 @@
#ifndef BHLIB_IO_H
#define BHLIB_IO_H
#ifndef BH_IO_H
#define BH_IO_H
#include "bh.h"
#define BH_IO_ERROR (1 << 0)
#define BH_IO_EOF (1 << 1)
#define BH_IO_ERROR 0x0001
#define BH_IO_EOF 0x0002
#define BH_IO_READ 0x0001
#define BH_IO_WRITE 0x0002
#define BH_IO_READ_WRITE (BH_IO_READ | BH_IO_WRITE)
#define BH_IO_OPEN 0x0000
#define BH_IO_CREATE 0x0100
#define BH_IO_APPEND 0x0200
#define BH_IO_TRUNCATE 0x0300
#define BH_IO_MASK 0xFF00
#define BH_IO_SET 0x0000
#define BH_IO_CURRENT 0x0001
#define BH_IO_END 0x0002
#define BH_IO_CAST(x) \
((bh_io_t *)(x))
@@ -13,6 +27,13 @@ struct bh_io_s;
typedef struct bh_io_table_s
{
int (*open)(struct bh_io_s *io,
int mode);
void (*close)(struct bh_io_s *io);
int (*is_open)(struct bh_io_s *io);
size_t (*read)(struct bh_io_s *io,
char *data,
size_t size);
@@ -23,10 +44,12 @@ typedef struct bh_io_table_s
void (*flush)(struct bh_io_s *io);
void (*seek)(struct bh_io_s *io,
int (*seek)(struct bh_io_s *io,
bh_off_t offset,
int dir);
bh_off_t (*size)(struct bh_io_s *io);
bh_off_t (*tell)(struct bh_io_s *io);
bh_off_t (*available)(struct bh_io_s *io);
@@ -38,145 +61,49 @@ typedef struct bh_io_table_s
typedef struct bh_io_s
{
bh_io_table_t *table;
const bh_io_table_t *table;
int flags;
} bh_io_t;
/**
* @brief Create new IO object.
*
* @param table Valid pointer to the IO table.
* @param size Size of the IO object.
*
* @return If the function succeeds, the return value is a pointer to the
* new, semi-initalized, IO object.
* @return If the function fails, the return value is NULL.
*
* @warning This function should be used in context of implementing child
* IO objects (files, sockets, streaming compression, etc).
*
* @sa bh_io_free
*/
bh_io_t *bh_io_new(bh_io_table_t *table,
size_t size);
/**
* @brief Free IO object.
*
* @param io Valid pointer to the IO object.
*/
void bh_io_free(bh_io_t *io);
/**
* @brief Read data from IO.
*
* @param io Valid pointer to the IO object.
* @param data Valid pointer to the buffer.
* @param size Size of the buffer.
*
* @return If the function succeeds, the return value is the amount
* of bytes read from the IO object.
* @return If the function fails, the return value is zero and error
* flag is set.
*
* @sa bh_io_write, bh_io_eof, bh_io_error
*/
int bh_io_open(bh_io_t *io,
int mode);
void bh_io_close(bh_io_t *io);
int bh_io_is_open(bh_io_t *io);
size_t bh_io_read(bh_io_t *io,
char *data,
size_t size);
/**
* @brief Write data to IO.
*
* @param io Valid pointer to the IO object.
* @param data Valid pointer to the buffer.
* @param size Size of the buffer.
*
* @return If the function succeeds, the return value is the amount
* of bytes written to the IO object.
* @return If the function fails, the return value is zero and error
* flag is set.
*
* @sa bh_io_read, bh_io_error, bh_io_flush
*/
size_t bh_io_write(bh_io_t *io,
const char* data,
size_t size);
/**
* @brief Writes any uncommited changes (if possible).
*
* @param io Valid pointer to the IO object.
*/
void bh_io_flush(bh_io_t *io);
/**
* @brief Seeks IO object to the specified position (if possible).
*
* @param io Valid pointer to the IO object.
* @param offset Position
* @param dir Direction
*
* @sa bh_io_tell
*/
void bh_io_seek(bh_io_t *io,
int bh_io_seek(bh_io_t *io,
bh_off_t offset,
int dir);
/**
* @brief Return current position in IO.
*
* @param io Valid pointer to the IO object.
*
* @return If the function succeeds, the return value is current
* position in the IO.
* @return If the function fails, the return value is -1.
*
* @sa bh_io_seek
*/
bh_off_t bh_io_size(bh_io_t *io);
bh_off_t bh_io_tell(bh_io_t *io);
/**
* @brief Return available bytes in the IO.
*
* @param io Valid pointer to the IO object.
*
* @return If the function succeeds, the return value is the amount
* of the available bytes for reading.
* @return If the function fails, the return value is zero.
*/
bh_off_t bh_io_available(bh_io_t *io);
/**
* @brief Return error flag of the IO.
*
* @param io Valid pointer to the IO object.
*
* @return The return value is error flag.
*
* @sa bh_io_eof, bh_io_clear
*/
int bh_io_error(bh_io_t *io);
/**
* @brief Return end-of-file flag of the IO.
*
* @param io Valid pointer to the IO object.
*
* @return The return value is end-of-file flag.
*
* @sa bh_io_error, bh_io_clear
*/
int bh_io_eof(bh_io_t *io);
/**
* @brief Crear IO object state.
*
* @param io Valid pointer to the IO object.
*
* @sa bh_io_error, bh_io_eof
*/
void bh_io_clear(bh_io_t *io);
#endif /* BHLIB_IO_H */
#endif /* BH_IO_H */

View File

@@ -1,5 +1,5 @@
#ifndef BHLIB_PLATFORM_H
#define BHLIB_PLATFORM_H
#ifndef BH_PLATFORM_H
#define BH_PLATFORM_H
#include <stddef.h>
@@ -43,4 +43,4 @@ typedef unsigned __int32 bh_uintptr_t;
typedef bh_int64_t bh_off_t;
#endif /* BHLIB_PLATFORM_H */
#endif /* BH_PLATFORM_H */

View File

@@ -5,152 +5,31 @@
typedef struct bh_queue_s bh_queue_t;
/**
* @brief Create new queue object.
*
* @return If the function succeeds, the return value is a pointer to the new
* queue object.
* @return If the function fails, the return value is NULL.
*
* @sa bh_queue_free, bh_queue_reserve, bh_queue_insert
*/
bh_queue_t *bh_queue_new(void);
/**
* @brief Free queue object.
*
* @param queue Valid pointer to the queue object.
*
* @sa bh_queue_clear
*/
void bh_queue_free(bh_queue_t *queue);
/**
* @brief Clear the queue.
*
* @param queue Valid pointer to the queue object.
*
* @warning Calling this function will invalidate iterators.
*
* @sa bh_queue_remove
*/
void bh_queue_clear(bh_queue_t *queue);
/**
* @brief Reserve space for the specified amount of elements.
*
* @param queue Valid pointer to the queue object.
* @param size The amount of elements.
*
* @return If the function succeeds, the return value is zero.
* @return If the function fails, the return value is non-zero.
*
* @warning Calling this function will invalidate iterators.
*
* @sa bh_queue_capacity, bh_queue_insert
*/
int bh_queue_reserve(bh_queue_t *queue,
size_t size);
/**
* @brief Insert element at the end of the queue.
*
* @param queue Valid pointer to the queue object.
* @param value Element.
*
* @return If the function succeeds, the return value is zero.
* @return If the function fails, the return value is non-zero.
*
* @warning Inserted element is owned by the caller of the function.
* @warning Calling this function will invalidate iterators.
*
* @sa bh_queue_remove, bh_queue_front
*/
int bh_queue_insert(bh_queue_t *queue,
void *value);
/**
* @brief Remove element from the front of the queue.
*
* @param queue Valid pointer to the queue object.
*
* @warning Calling this function will invalidate iterators.
*
* @sa bh_queue_insert, bh_queue_front
*/
void bh_queue_remove(bh_queue_t *queue);
/**
* @brief Return element from the front of the queue.
*
* @param queue Valid pointer to the queue object.
*
* @return If the function succeeds, the return value is a valid pointer to
* the element.
* @return If the function fails, the return value is NULL.
*
* @sa bh_queue_empty, bh_queue_insert
*/
void *bh_queue_front(bh_queue_t *queue);
/**
* @brief Check if the queue is empty.
*
* @param queue Valid pointer to the queue object.
*
* @return The return value is non-zero if the queue is empty, otherwise zero.
*
* @sa bh_queue_size
*/
int bh_queue_empty(bh_queue_t *queue);
/**
* @brief Return queue size.
*
* @param queue Valid pointer to the queue object.
*
* @return The return value is current queue size.
*
* @sa bh_queue_empty, bh_queue_capacity
*/
size_t bh_queue_size(bh_queue_t *queue);
/**
* @brief Return queue capacity.
*
* @param queue Valid pointer to the queue object.
*
* @return The return value is current queue capacity.
*
* @sa bh_queue_reserve, bh_queue_size
*/
size_t bh_queue_capacity(bh_queue_t *queue);
/**
* @brief Return iterator for the next element in the queue.
*
* @param queue Valid pointer to the queue object.
* @param iter Valid or NULL iterator.
*
* @return The return value is the valid iterator for the next element in the
* queue.
* @return The return value is the NULL iterator if there is no more elements
* in the queue.
*
* @sa bh_queue_iter_value
*/
void *bh_queue_iter_next(bh_queue_t *queue,
void *iter);
/**
* @brief Return pointer to the element's value.
*
* @param iter Valid iterator.
*
* @return The return value is the stored element.
*
* @sa bh_queue_iter_next
*/
void *bh_queue_iter_value(void *iter);
#endif /* BH_QUEUE_H */

View File

@@ -1,9 +1,9 @@
#ifndef BHLIB_THREAD_H
#define BHLIB_THREAD_H
#ifndef BH_THREAD_H
#define BH_THREAD_H
#include "bh.h"
#define BH_THREAD_CLEANUP (1 << 0)
#define BH_THREAD_CLEANUP 0x0001
typedef void (*bh_thread_cb_t)(void *);
typedef struct bh_thread_s bh_thread_t;
@@ -13,12 +13,12 @@ typedef struct bh_cond_s bh_cond_t;
typedef struct bh_task_s bh_task_t;
typedef struct bh_thread_pool_s bh_thread_pool_t;
#if defined(BHLIB_USE_PTHREAD)
#if defined(BH_USE_PTHREAD)
bh_thread_t *bh_thread_new(bh_task_t *task);
bh_thread_pool_t *bh_thread_pool_new(size_t size);
#elif defined(BHLIB_USE_WINTHREAD)
#elif defined(BH_USE_WINTHREAD)
#include <windows.h>
#include <process.h>
@@ -47,250 +47,65 @@ bh_thread_pool_t *bh_thread_pool_new_base(size_t size,
#endif
/**
* @brief Create new task
*
* @param func Function
* @param data Function data
* @param flags Task flags
*
* @return Pointer to the new task
*
* @sa bh_task_free, bh_task_reuse, bh_task_done
*/
bh_task_t *bh_task_new(void (*func)(void *),
void *data,
int flags);
/**
* @brief Free the task.
*
* @param task Pointer to the task
*/
void bh_task_free(bh_task_t *task);
/**
* @brief Reuse task.
*
* @param task Pointer to the task
* @param func Function
* @param data Data
*
* @sa bh_task_free, bh_task_done
*/
void bh_task_reuse(bh_task_t *task,
void (*func)(void *),
void *data);
/**
* @brief Check if task is done.
*
* @param task Pointer to the task
*
* @return The return value is boolean flag, indicating if the task is done.
*/
int bh_task_done(bh_task_t *task);
/**
* @function bh_thread_new
*
* @brief Create new thread.
*
* @param task Thread task
*
* @return Pointer to thread
*
* @sa bh_thread_join, bh_thread_detach
*/
/**
* @function bh_thread_pool_new
* @brief Create new thread pool.
*
* @param pool Pointer to the thread pool
* @param size Amount of threads
*
* @return Pointer to thread pool
*
* @sa bh_thread_pool_add, bh_thread_pool_join, bh_thread_pool_free
*/
/**
* @brief Join thread.
*
* @param thread Pointer to the thread
*
* @return 0 on success, non-zero otherwise
*
* @sa bh_thread_detach
*/
int bh_thread_join(bh_thread_t *thread);
/**
* @brief Detach thread.
*
* @param thread Pointer to the thread
*
* @return 0 on success, non-zero otherwise
*
* @sa bh_thread_join
*/
int bh_thread_detach(bh_thread_t *thread);
/**
* @brief Create mutex.
*
* @return Pointer to the mutex
*
* @sa bh_mutex_lock, bh_mutex_try_lock, bh_mutex_destroy
*/
bh_mutex_t *bh_mutex_new(void);
/**
* @brief Free mutex.
*
* @param mutex Pointer ot the mutex
*/
void bh_mutex_free(bh_mutex_t *mutex);
/**
* @brief Lock mutex.
*
* @param mutex Pointer to the mutex
*
* @return 0 on success, non-zero otherwise
*
* @note Locking already locked mutex will block thread until mutex is
* released
*
* @sa bh_mutex_try_lock, bh_mutex_unlock
*/
int bh_mutex_lock(bh_mutex_t *mutex);
/**
* @brief Try to lock mutex.
*
* @param mutex Pointer to the mutex
*
* @return 0 on success, positive value if mutex is locked, negative value on
* error
*
* @sa bh_mutex_lock, bh_mutex_unlock
*/
int bh_mutex_try_lock(bh_mutex_t *mutex);
/**
* @brief Unlock mutex.
*
* @param mutex Pointer to the mutex
*
* @return 0 on success, non-zero otherwise
*
* @sa bh_mutex_lock, bh_mutex_try_lock
*/
int bh_mutex_unlock(bh_mutex_t *mutex);
bh_semaphore_t *bh_semaphore_new(int count);
void bh_semaphore_free(bh_semaphore_t *semaphore);
int bh_semaphore_post(bh_semaphore_t *semaphore);
int bh_semaphore_wait(bh_semaphore_t *semaphore);
int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
unsigned long timeout);
int bh_semaphore_try_wait(bh_semaphore_t *semaphore);
/**
* @brief Create condition variable.
*
* @return Pointer to the condition variable
*/
bh_cond_t *bh_cond_new(void);
/**
* @brief Destroy condition variable.
*
* @param cond Pointer to the conditional variable
*/
void bh_cond_free(bh_cond_t *cond);
/**
* @brief Block on conditional variable.
*
* @param cond Pointer to the condition variable
* @param mutex Pointer to the mutex
*
* @return 0 on success, non-zero otherwise
*
* @sa bh_cond_wait_for, bh_cond_signal, bh_cond_broadcast
*/
int bh_cond_wait(bh_cond_t *cond,
bh_mutex_t *mutex);
/**
* @brief Block on conditional variable for a period of the time.
*
* @param cond Pointer to the conditional variable
* @param mutex Pointer to the mutex
* @param timeout Timeout in miliseconds
*
* @return 0 on success, positive value on timeout, negative on error
*
* @sa bh_cond_wait, bh_cond_signal, bh_cond_broadcast
*/
int bh_cond_wait_for(bh_cond_t *cond,
bh_mutex_t *mutex,
unsigned long timeout);
/**
* @brief Unblock (notify) thread.
*
* @param cond Pointer to the condition variable
*
* @return 0 on success, non-zero otherwise
*
* @sa bh_cond_broadcast, bh_cond_wait, bh_cond_wait_for
*/
int bh_cond_signal(bh_cond_t *cond);
/**
* @brief Unblock all threads.
*
* @param cond Pointer to the conditional variable
*
* @return 0 on success, non-zero otherwise
*
* @sa bh_cond_signal, bh_cond_wait, bh_cond_wait_for
*/
int bh_cond_broadcast(bh_cond_t *cond);
/**
* @brief Submit task to the thread pool.
*
* @param pool Pointer to the thread pool
* @param func Task function
* @param data Task data
*
* @return 0 on success, non-zero otherwise
*
* @sa bh_thread_pool_join
*/
int bh_thread_pool_add(bh_thread_pool_t *pool,
bh_task_t *task);
/**
* @brief Wait until all tasks are finished.
*
* @param pool Pointer to the thread pool
* @return 0 on success, non-zero otherwise
*
* @sa bh_thread_pool_add
*/
int bh_thread_pool_wait(bh_thread_pool_t *pool);
/**
* @brief Destroy thread pool.
*
* @param pool Pointer to the thread pool
*/
void bh_thread_pool_free(bh_thread_pool_t *pool);
#endif /* BHLIB_THREAD_H */
#endif /* BH_THREAD_H */

149
main.c
View File

@@ -1,6 +1,8 @@
#include <bh/queue.h>
#include <bh/hashmap.h>
#include <bh/thread.h>
#include <bh/file.h>
#include <bh/buffer.h>
#include <stdio.h>
#include <stdint.h>
@@ -98,13 +100,160 @@ void bar()
//system("pause");
}
int fib(int x)
{
static int memory[128] = {0};
int result;
if (x < 128 && memory[x] != 0)
return memory[x];
if (x <= 1)
return 1;
result = fib(x - 1) + fib(x - 2);
if (x < 128)
memory[x] = result;
return result;
}
#include <string.h>
char* itoa (unsigned long long value, char str[], int radix)
{
char buf [66];
char* dest = buf + sizeof(buf);
int sign = 0;
if (value == 0) {
memcpy (str, "0", 2);
return str;
}
if (radix < 0) {
radix = -radix;
if ( (long long) value < 0) {
value = -value;
sign = 1;
}
}
*--dest = '\0';
switch (radix)
{
case 16:
while (value) {
* --dest = '0' + (value & 0xF);
if (*dest > '9') *dest += 'A' - '9' - 1;
value >>= 4;
}
break;
case 10:
while (value) {
*--dest = '0' + (value % 10);
value /= 10;
}
break;
case 8:
while (value) {
*--dest = '0' + (value & 7);
value >>= 3;
}
break;
case 2:
while (value) {
*--dest = '0' + (value & 1);
value >>= 1;
}
break;
default: // The slow version, but universal
while (value) {
*--dest = '0' + (value % radix);
if (*dest > '9') *dest += 'A' - '9' - 1;
value /= radix;
}
break;
}
if (sign) *--dest = '-';
memcpy (str, dest, buf +sizeof(buf) - dest);
return str;
}
void test_api(bh_io_t *io)
{
int i;
for (i = 0; i < 128; i++)
{
char str[65];
itoa(i, str, 10);
bh_io_write(io, str, strlen(str));
bh_io_write(io, " ", 1);
itoa(fib(i), str, 10);
bh_io_write(io, str, strlen(str));
bh_io_write(io, "\n", 1);
}
}
void test(void)
{
bh_file_t *file = bh_file_new("log.txt");
if (!file)
return;
if (bh_file_open(file, BH_IO_APPEND | BH_IO_WRITE))
{
printf("File not opened?");
bh_file_free(file);
return;
}
bh_file_write(file, "Hello, world!\n", 14);
test_api((bh_io_t *)file);
bh_file_free(file);
}
void ddump()
{
bh_buffer_t *buffer;
bh_file_t *file;
buffer = bh_buffer_new();
bh_buffer_open(buffer, BH_IO_WRITE);
bh_buffer_write(buffer, "Hello, world!", 13);
bh_buffer_close(buffer);
file = bh_file_new("debug.txt");
bh_file_open(file, BH_IO_WRITE | BH_IO_TRUNCATE);
bh_file_write(file, bh_buffer_data(buffer), bh_buffer_size(buffer));
bh_file_free(file);
bh_buffer_free(buffer);
}
int main()
{
bh_queue_t *queue;
void *iter;
size_t i, j;
ddump();
return 0;
//foo();
test();
printf("Thread?\n");
fflush(stdout);

View File

@@ -1,34 +1,72 @@
#include <bh/algo.h>
#include <string.h>
#include <stdio.h>
void bh_swap(void *lhs,
void *rhs,
/**
* \defgroup algo Algorithms
*
* Common algorithms (search, swap, heap, etc)
* \{
*/
/**
* Swaps \a size bytes between the object pointed to by \a src and object
* pointed to by \a dest.
*
* If the objects overlap, the behavior is undefined.
*
* If either \a src or \a dest is an invalid or null pointer, the behavior is
* undefined.
*
* \param dest Pointer to the memory location to swap to
* \param src Pointer to the memory location to swap from
* \param size Number of bytes to swap
*/
void bh_swap(void *dest,
void *src,
size_t size)
{
int tmp;
/* Swap values in int sized chunks */
/* Swap bytes in int-sized chunks */
while (size >= sizeof(tmp))
{
memmove(&tmp, lhs, sizeof(tmp));
memmove(lhs, rhs, sizeof(tmp));
memmove(rhs, &tmp, sizeof(tmp));
memmove(&tmp, dest, sizeof(tmp));
memmove(dest, src, sizeof(tmp));
memmove(src, &tmp, sizeof(tmp));
lhs = (char *)lhs + sizeof(tmp);
rhs = (char *)rhs + sizeof(tmp);
dest = (char *)dest + sizeof(tmp);
src = (char *)src + sizeof(tmp);
size -= sizeof(tmp);
}
/* Swap the rest */
/* Swap the remaining size */
if (size)
{
memmove(&tmp, lhs, size);
memmove(lhs, rhs, size);
memmove(rhs, &tmp, size);
memmove(&tmp, dest, size);
memmove(dest, src, size);
memmove(src, &tmp, size);
}
}
/**
* Partitions the \a array of \a size elements of \a element bytes, relative to
* the specified \a pivot element. Function pointed by \a equal is used for
* comparison.
*
* If the \a pivot element is part of the partitioned \a array, function will
* behaive the same way, as if \a pivot element wasn't part of the array.
*
* If \a equal indicates two elements as equivalent, their order in the
* resulting partitioned array is unspecified.
*
* \param pivot Pointer to the pivot element
* \param array Pointer to the array to partition
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparision function
*
* \return Pointer to the first element of the second partition.
*/
void *bh_partition(void *pivot,
void *array,
size_t size,
@@ -74,6 +112,17 @@ void *bh_partition(void *pivot,
return j + element;
}
/**
* Sorts the \a array of \a size elements of \a element bytes. Function pointed
* by \a equal is used for comparision.
*
* This sorting does not make any gurantees about time or space complexity.
*
* \param array Pointer to the array to sort
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparision function
*/
void bh_sort(void *array,
size_t size,
size_t element,
@@ -83,6 +132,23 @@ void bh_sort(void *array,
bh_sort_intro(array, size, element, equal);
}
/**
* Sorts the \a array of \a size elements of \a element bytes with insertion
* sort. Function pointed by \a equal is used for comparision.
*
* This sorting has following time complexity:
* - best case O(n)
* - average case O(n^2)
* - worst case O(n^2)
*
* This sorting has O(1) space complexity.
*
* \param array Pointer to the array to sort
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparision function
*/
void bh_sort_insert(void *array,
size_t size,
size_t element,
@@ -109,6 +175,20 @@ void bh_sort_insert(void *array,
}
/**
* Sorts the \a array of \a size elements of \a element bytes with shell sort.
* Function pointed by \a equal is used for comparision.
*
* This sorting has the O(n log n) best cast time complexity. Average and worst
* cases are implementation dependant.
*
* This sorting has O(1) space complexity.
*
* \param array Pointer to the array to sort
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparision function
*/
void bh_sort_shell(void *array,
size_t size,
size_t element,
@@ -201,6 +281,22 @@ static void bh_sort_intro_r(void *array,
}
}
/**
* Sorts the \a array of \a size elements of \a element bytes with insertion
* sort. Function pointed by \a equal is used for comparision.
*
* This sorting has following time complexity:
* - best case O(n log n)
* - average case O(n log n)
* - worst case O(n log n)
*
* This sorting has O(log n) space complexity.
*
* \param array Pointer to the array to sort
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparision function
*/
void bh_sort_intro(void *array,
size_t size,
size_t element,
@@ -221,6 +317,22 @@ void bh_sort_intro(void *array,
bh_sort_intro_r(array, size, element, equal, depth);
}
/**
* Sorts the \a array of \a size elements of \a element bytes with insertion
* sort. Function pointed by \a equal is used for comparision.
*
* This sorting has following time complexity:
* - best case O(n)
* - average case O(n log n)
* - worst case O(n log n)
*
* This sorting has O(1) space complexity.
*
* \param array Pointer to the array to sort
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparision function
*/
void bh_sort_heap(void *array,
size_t size,
size_t element,
@@ -232,7 +344,15 @@ void bh_sort_heap(void *array,
bh_heap_remove(array, size--, element, equal);
}
/**
* Heapifes the \a array of \a size elements of \a element bytes. Function
* pointed by \a equal is used for comparision.
*
* \param array Pointer to the array to heapify
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparision function
*/
void bh_heap_make(void *array,
size_t size,
size_t element,
@@ -279,6 +399,15 @@ void bh_heap_make(void *array,
}
}
/**
* Removes top element from heapified \a array of \a size elements of \a
* elements bytes. Function pointed by \a equal is used for comparasion.
*
* \param array Pointer to the array to remove element from
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparasion function
*/
void bh_heap_remove(void *array,
size_t size,
size_t element,
@@ -323,6 +452,16 @@ void bh_heap_remove(void *array,
}
}
/**
* Inserts new element into heapified \a array of \a size elements of \a
* elements bytes. Function pointed by \a equal is used for comparasion.
*
* \param value Pointer to the value to be inserted
* \param array Pointer to the array to remove element from
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparasion function
*/
void bh_heap_insert(void *value,
void *array,
size_t size,
@@ -358,3 +497,64 @@ void bh_heap_insert(void *value,
break;
}
}
/**
* Replaces top element of the heapified \a array of \a size elements of \a
* elements bytes. Function pointed by \a equal is used for comparasion.
*
* This function is equal to two consecutive operations of remove and insert.
*
* \param value Pointer to the value to be inserted
* \param array Pointer to the array to remove element from
* \param size Number of elements in the array
* \param element Size of each element in the array in bytes
* \param equal Comparasion function
*/
void bh_heap_replace(void *value,
void *array,
size_t size,
size_t element,
bh_equal_cb_t equal)
{
char *start, *end, *current, *left, *right;
if (size <= 1)
return;
/* Calculate start, end and children pointers */
start = (char *)array;
end = start + size * element;
current = start;
left = start + (current - start) * 2 + element;
right = left + element;
/* Copy supplied element to the first (top) position */
memmove(current, value, element);
/* Iterate until we reach the end */
while (left < end)
{
char *biggest;
/* Determine biggest child */
biggest = left;
if (right < end && equal(left, right) < 0)
biggest = right;
/* Compare biggest child with current */
if (equal(current, biggest) < 0)
{
/* Swap content and recalculate children pointers */
bh_swap(current, biggest, element);
current = biggest;
left = start + (current - start) * 2 + element;
right = left + element;
}
else
break;
}
}
/**
* \}
*/

278
src/buffer.c Normal file
View File

@@ -0,0 +1,278 @@
#include <bh/internal/buffer.h>
#include <stdlib.h>
#include <string.h>
static const bh_io_table_t bh_buffer_table = {
(int (*)(struct bh_io_s *, int)) bh_buffer_open_base,
(void (*)(struct bh_io_s *)) bh_buffer_close_base,
(int (*)(struct bh_io_s *)) bh_buffer_is_open_base,
(size_t (*)(struct bh_io_s *, char *, size_t)) bh_buffer_read_base,
(size_t (*)(struct bh_io_s *, const char *, size_t)) bh_buffer_write_base,
(void (*)(struct bh_io_s *)) bh_buffer_flush_base,
(int (*)(struct bh_io_s *, bh_off_t, int)) bh_buffer_seek_base,
(bh_off_t (*)(struct bh_io_s *)) bh_buffer_size_base,
(bh_off_t (*)(struct bh_io_s *)) bh_buffer_tell_base,
(bh_off_t (*)(struct bh_io_s *)) bh_buffer_available_base,
(void (*)(struct bh_io_s *)) bh_buffer_clear_base,
(void (*)(struct bh_io_s *)) bh_buffer_destroy
};
bh_buffer_t *bh_buffer_new(void)
{
bh_buffer_t *result;
/* Allocate and initialize buffer structure */
result = malloc(sizeof(*result));
if (result && bh_buffer_init(result))
{
/* Something went wrong - free allocated memory */
free(result);
result = NULL;
}
return result;
}
void bh_buffer_free(bh_buffer_t *buffer)
{
bh_buffer_destroy(buffer);
free(buffer);
}
int bh_buffer_init(bh_buffer_t *buffer)
{
bh_io_init(&buffer->base, &bh_buffer_table);
buffer->data = NULL;
buffer->capacity = 0;
buffer->size = 0;
buffer->at = 0;
buffer->mode = 0;
return BH_OK;
}
void bh_buffer_destroy(bh_buffer_t *buffer)
{
bh_buffer_close(buffer);
if (buffer->data)
free(buffer->data);
}
const char *bh_buffer_data(bh_buffer_t *buffer)
{
return buffer->data;
}
void bh_buffer_set_data(bh_buffer_t *buffer,
const char *data,
size_t size)
{
buffer->size = 0;
bh_buffer_write_base(buffer, data, size);
}
size_t bh_buffer_capacity(bh_buffer_t *buffer)
{
return buffer->capacity;
}
int bh_buffer_reserve(bh_buffer_t *buffer,
size_t size)
{
char *data = NULL;
/* New capacity can't be less then current buffer size */
if (size < buffer->size)
size = buffer->size;
/* Prevent same size reallocation */
if (buffer->capacity == size)
return BH_OK;
/* Allocate new memory for the buffer */
if (size)
{
data = malloc(size);
if (!data)
return BH_OOM;
/* Copy data */
if (buffer->size)
memmove(data, buffer->data, buffer->size);
}
/* Free previosly allocated memory */
if (buffer->data)
free(buffer->data);
/* Update buffer fields */
buffer->data = data;
buffer->capacity = size;
return BH_OK;
}
int bh_buffer_open_base(bh_buffer_t *buffer,
int mode)
{
/* Check if buffer is already open */
if (buffer->mode != 0)
return BH_OK;
/* Update buffer mode field */
buffer->mode = mode;
/* Determine open mode */
switch (mode & BH_IO_MASK)
{
case BH_IO_OPEN:
case BH_IO_CREATE:
case BH_IO_APPEND:
break;
case BH_IO_TRUNCATE:
buffer->size = 0;
break;
default:
return BH_NO_IMPL;
}
return BH_OK;
}
void bh_buffer_close_base(bh_buffer_t *buffer)
{
buffer->mode = 0;
}
int bh_buffer_is_open_base(bh_buffer_t *buffer)
{
return buffer->mode != 0;
}
size_t bh_buffer_read_base(bh_buffer_t *buffer,
char *data,
size_t size)
{
/* Check if buffer openned in read mode */
if (!(buffer->mode & BH_IO_READ))
{
buffer->base.flags |= BH_IO_ERROR;
return 0;
}
/* Calculate maximum available size for reading */
if (size > buffer->size - buffer->at)
size = buffer->size - buffer->at;
/* Perform reading */
if (size)
{
memmove(data, buffer->data + buffer->at, size);
buffer->at += size;
}
/* Check for end of file */
if (!size)
buffer->base.flags |= BH_IO_EOF;
else
buffer->base.flags &= ~BH_IO_EOF;
return size;
}
size_t bh_buffer_write_base(bh_buffer_t *buffer,
const char *data,
size_t size)
{
size_t capacity = 0;
/* Check if buffer is openned in write mode */
if (!(buffer->mode & BH_IO_WRITE))
{
buffer->base.flags |= BH_IO_ERROR;
return 0;
}
/* Adjust at position */
if ((buffer->mode & BH_IO_MASK) == BH_IO_APPEND)
buffer->at = buffer->size;
/* Calculate required capacity and check for overflow */
capacity = buffer->at + size;
if (capacity < size)
{
buffer->base.flags |= BH_IO_ERROR;
return 0;
}
/* Try to grow buffer */
if (buffer->capacity < capacity)
bh_buffer_reserve(buffer, capacity);
/* Calculate maximum write size */
if (size > buffer->capacity - buffer->at)
size = buffer->capacity - buffer->at;
/* Perform writing */
if (size)
{
memmove(buffer->data + buffer->at, data, size);
buffer->at += size;
buffer->size += size;
}
/* Check for end of file */
if (!size)
buffer->base.flags |= BH_IO_EOF;
else
buffer->base.flags &= ~BH_IO_EOF;
return size;
}
void bh_buffer_flush_base(bh_buffer_t *buffer)
{
(void)buffer;
}
int bh_buffer_seek_base(bh_buffer_t *buffer,
bh_off_t pos,
int dir)
{
switch (dir)
{
case BH_IO_SET: buffer->at = pos; break;
case BH_IO_CURRENT: buffer->at += pos; break;
case BH_IO_END: buffer->at = buffer->size - pos; break;
default: return BH_NO_IMPL;
}
if (buffer->at > buffer->size)
buffer->at = buffer->size;
return BH_OK;
}
bh_off_t bh_buffer_size_base(bh_buffer_t *buffer)
{
return buffer->size;
}
bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer)
{
return buffer->at;
}
bh_off_t bh_buffer_available_base(bh_buffer_t *buffer)
{
return buffer->size - buffer->at;
}
void bh_buffer_clear_base(bh_buffer_t *buffer)
{
buffer->base.flags &= ~BH_IO_ERROR;
}

275
src/file_null.c Normal file
View File

@@ -0,0 +1,275 @@
#include <bh/internal/file.h>
/**
* \defgroup file File IO
*
* File input/output API
* \{
*/
/**
* Creates new file object with specified \a path to file.
*
* \param path Path to the file
*
* \return On success, returns new file object.
* \return On failure, returns null pointer.
*/
bh_file_t *bh_file_new(const char *path)
{
(void)path;
return NULL;
}
/**
* Frees the \a file object.
*
* Before freeing the file object, this function ensures that underlying file
* was closed.
*
* \param file Pointer to the file object
*/
void bh_file_free(bh_file_t *file)
{
(void)file;
}
/**
* Initializes the \a file object with specified \a path to file.
*
* \param file Pointer to the file object
* \param path Path to the file
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_file_init(bh_file_t *file,
const char *path)
{
(void)file;
(void)path;
return BH_NO_IMPL;
}
/**
* Destroyes the \a file object.
*
* Before destroying the file object, this function ensures that underlying
* file was closed.
*
* \param file Pointer to the file object
*/
void bh_file_destroy(bh_file_t *file)
{
(void)file;
}
/**
* Opens the \a file object for specified \a mode of operation.
*
* \param file Pointer to the file object
* \param mode Bitmask determining access mode
*
* \return On success, returns zero.
* \return On failure, returns error code.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
int bh_file_open_base(bh_file_t *file,
int mode)
{
(void)file;
(void)mode;
return BH_NO_IMPL;
}
/**
* Closes the \a file object.
*
* \param file Pointer to the file object
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
void bh_file_close_base(bh_file_t *file)
{
(void)file;
}
/**
* Checks if the \a file is open.
*
* \param file Pointer to the file object
*
* \return If file object is open - returns non-zero.
* \return If file object is closed - returns zero.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
int bh_file_is_open_base(bh_file_t *file)
{
(void)file;
return 0;
}
/**
* Reads up to \a size amount of bytes from the \a file object into memory
* buffer pointed by \a data pointer.
*
* \param file Pointer to the file object
* \param data Pointer to the memory buffer
* \param size Maximum number of bytes to be read
*
* \return On success, returns number of bytes successfuly read.
* \return On failure, returns zero.
*
* \note To check for end-of-file or error see bh_io_eof and bh_io_error.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
size_t bh_file_read_base(bh_file_t *file,
char *data,
size_t size)
{
(void)file;
(void)data;
(void)size;
return 0;
}
/**
* Writes up to \a size amount of bytes to the \a file object from memory
* buffer pointed by \a data pointer.
*
* \param file Pointer to the file object
* \param data Pointer to the memory buffer
* \param size Maximum number of bytes to be read
*
* \return On success, returns number of bytes successfuly written.
* \return On failure, returns zero.
*
* \note To check for error see bh_io_error.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
size_t bh_file_write_base(bh_file_t *file,
const char *data,
size_t size)
{
(void)file;
(void)data;
(void)size;
return 0;
}
/**
* Synchronizes the \a file object (if possible).
*
* In most cases, this function causes any unwritten/buffered data to be
* written.
*
* \param file Pointer to the file object
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
void bh_file_flush_base(bh_file_t *file)
{
(void)file;
}
/**
* Seeks the \a file object in the specified direction \a dir and \a offset
* (if possible).
*
* \param file Pointer to the file object
* \param offset Number of bytes to seek in specified direciton
* \param dir Seeking direction
*
* \return On success, returns zero.
* \return On failure, returns error code.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
int bh_file_seek_base(bh_file_t *file,
bh_off_t off,
int dir)
{
(void)file;
(void)off;
(void)dir;
return BH_NO_IMPL;
}
/**
* Returns total size of the \a file object (if possible)
*
* \param file Pointer to the file object
*
* \return On success, returns total size of the file object.
* \return On failure, returns -1.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
bh_off_t bh_file_size_base(bh_file_t *file)
{
(void)file;
return -1;
}
/**
* Returns current position in the \a file object (if possible).
*
* \param file Pointer to the io object
*
* \return On success, returns current position in the file object.
* \return On failure, returns -1.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
bh_off_t bh_file_tell_base(bh_file_t *file)
{
(void)file;
return -1;
}
/**
* Returns available number of bytes to be read from the \a file object.
*
* \param file Pointer to the file object
*
* \return On success, returns number of available bytes to be read.
* \return On failure, returns zero.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
bh_off_t bh_file_available_base(bh_file_t *file)
{
(void)file;
return 0;
}
/**
* Clears error of the \a file object.
*
* \param file Pointer to the file object
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
void bh_file_clear_base(bh_file_t *file)
{
(void)file;
}
/**
* \}
*/

View File

@@ -0,0 +1,253 @@
#include <bh/internal/file.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
static const bh_io_table_t bh_file_table = {
(int (*)(struct bh_io_s *, int)) bh_file_open_base,
(void (*)(struct bh_io_s *)) bh_file_close_base,
(int (*)(struct bh_io_s *)) bh_file_is_open_base,
(size_t (*)(struct bh_io_s *, char *, size_t)) bh_file_read_base,
(size_t (*)(struct bh_io_s *, const char *, size_t)) bh_file_write_base,
(void (*)(struct bh_io_s *)) bh_file_flush_base,
(int (*)(struct bh_io_s *, bh_off_t, int)) bh_file_seek_base,
(bh_off_t (*)(struct bh_io_s *)) bh_file_size_base,
(bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base,
(bh_off_t (*)(struct bh_io_s *)) bh_file_available_base,
(void (*)(struct bh_io_s *)) bh_file_clear_base,
(void (*)(struct bh_io_s *)) bh_file_destroy
};
bh_file_t *bh_file_new(const char *path)
{
bh_file_t *result;
/* Allocate and initialize file structure */
result = malloc(sizeof(*result));
if (result && bh_file_init(result, path))
{
/* Something went wrong - free allocated memory */
free(result);
result = NULL;
}
return result;
}
void bh_file_free(bh_file_t *file)
{
bh_file_destroy(file);
free(file);
}
int bh_file_init(bh_file_t *file,
const char *path)
{
/* Ensure that path is not empty */
if (!path)
return BH_INVALID;
/* Initialize base io object */
bh_io_init(&file->base, &bh_file_table);
/* Initialize file io object */
file->handle = -1;
file->mode = 0;
file->path = strdup(path);
return BH_OK;
}
void bh_file_destroy(bh_file_t *file)
{
/* Close the file */
bh_file_close(file);
free(file->path);
}
int bh_file_open_base(bh_file_t *file,
int mode)
{
/* Set open mode for 0666 permisions */
mode_t open_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
int open_flags = 0;
/* Check if file is already opened */
if (file->handle != -1)
return BH_OK;
/* Determine read/write flags */
if (mode & BH_IO_READ_WRITE)
open_flags |= O_RDWR;
else if (mode & BH_IO_READ)
open_flags |= O_RDONLY;
else if (mode & BH_IO_WRITE)
open_flags |= O_WRONLY;
else
return BH_INVALID;
/* Determine open mode */
switch (mode & BH_IO_MASK)
{
case BH_IO_OPEN: break;
case BH_IO_CREATE: open_flags |= O_CREAT | O_EXCL; break;
case BH_IO_APPEND: open_flags |= O_CREAT | O_APPEND; break;
case BH_IO_TRUNCATE: open_flags |= O_CREAT | O_TRUNC; break;
default:
return BH_NO_IMPL;
}
/* Open file */
file->handle = open(file->path, open_flags, open_mode);
/* Check for errors */
if (file->handle == -1)
return BH_ERROR;
return BH_OK;
}
void bh_file_close_base(bh_file_t *file)
{
/* Close file if it's open */
if (file->handle != -1)
close(file->handle);
/* Set handle to invalid value */
file->handle = -1;
}
int bh_file_is_open_base(bh_file_t *file)
{
/* If handle is not -1 - then file is open */
return file->handle != -1;
}
size_t bh_file_read_base(bh_file_t *file,
char *data,
size_t size)
{
ssize_t readed;
/* Check if file is open */
if (file->handle == -1)
{
/* Error occured - set error bit */
file->base.flags |= BH_IO_ERROR;
return 0;
}
/* Read data from file */
readed = read(file->handle, data, size);
if (readed < 0)
{
/* Error occured - set error bit */
file->base.flags |= BH_IO_ERROR;
return 0;
}
/* Check for end of file */
if (!readed)
file->base.flags |= BH_IO_EOF;
else
file->base.flags &= ~BH_IO_EOF;
/* Return number of readed bytes */
return readed;
}
size_t bh_file_write_base(bh_file_t *file,
const char *data,
size_t size)
{
ssize_t written;
/* Check if file is open */
if (file->handle == -1)
{
/* Error occured - set error bit */
file->base.flags |= BH_IO_ERROR;
return 0;
}
/* Write data to file */
written = write(file->handle, data, size);
if (written < 0)
{
/* Error occured - set error bit */
file->base.flags |= BH_IO_ERROR;
return 0;
}
/* Check for end of file */
if (!written)
file->base.flags |= BH_IO_EOF;
else
file->base.flags &= ~BH_IO_EOF;
/* Return number of written bytes */
return written;
}
void bh_file_flush_base(bh_file_t *file)
{
/* Check if file is open */
if (file->handle == -1)
return;
/* Signal OS to flush data from the internal buffers */
fsync(file->handle);
}
int bh_file_seek_base(bh_file_t *file,
bh_off_t pos,
int dir)
{
/* Check if file is open */
if (file->handle == -1)
return BH_ERROR;
/* Seek to desired location */
if (lseek(file->handle, pos, dir) == -1);
return BH_ERROR;
return BH_OK;
}
bh_off_t bh_file_size_base(bh_file_t *file)
{
struct stat sb;
/* Check if file is open */
if (file->handle == -1)
return -1;
/* Get file size from the OS */
if (fstat(file->handle, &sb))
return -1;
return sb.st_size;
}
bh_off_t bh_file_tell_base(bh_file_t *file)
{
/* Check if file is open */
if (file->handle == -1)
return -1;
/* Get current file position */
return lseek(file->handle, 0, SEEK_CUR);
}
bh_off_t bh_file_available_base(bh_file_t *file)
{
/* Get available bytes for reading */
return bh_file_size_base(file) - bh_file_tell_base(file);
}
void bh_file_clear_base(bh_file_t *file)
{
file->base.flags &= ~BH_IO_ERROR;
}

View File

@@ -0,0 +1,195 @@
#include <bh/internal/file.h>
static const bh_io_table_t bh_file_table = {
(int (*)(struct bh_io_s *, int)) bh_file_open_base,
(void (*)(struct bh_io_s *)) bh_file_close_base,
(int (*)(struct bh_io_s *)) bh_file_is_open_base,
(size_t (*)(struct bh_io_s *, char *, size_t)) bh_file_read_base,
(size_t (*)(struct bh_io_s *, const char *, size_t)) bh_file_write_base,
(void (*)(struct bh_io_s *)) bh_file_flush_base,
(int (*)(struct bh_io_s *, bh_off_t, int)) bh_file_seek_base,
(bh_off_t (*)(struct bh_io_s *)) bh_file_size_base,
(bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base,
(bh_off_t (*)(struct bh_io_s *)) bh_file_available_base,
(void (*)(struct bh_io_s *)) bh_file_clear_base,
(void (*)(struct bh_io_s *)) bh_file_destroy
};
bh_file_t *bh_file_new(const char *path)
{
bh_file_t *result;
result = malloc(sizeof(*result));
if (result && bh_file_init(result, path))
{
free(result);
result = NULL;
}
return result;
}
void bh_file_free(bh_file_t *file)
{
bh_file_destroy(file);
free(file);
}
int bh_file_init(bh_file_t *file,
const char *path)
{
if (!path)
return BH_INVALID;
file->handle = INVALID_HANDLE_VALUE;
file->mode = 0;
file->path = strdup(path);
file->base.table = &bh_file_table;
return BH_OK;
}
int bh_file_open_base(bh_file_t *file,
int mode)
{
DWORD access = 0, how = 0;
if (mode & BH_IO_READ)
access |= GENERIC_READ;
if (mode & BH_IO_WRITE)
access |= GENERIC_WRITE;
switch (mode & BH_IO_MASK)
{
case BH_IO_OPEN: how = OPEN_EXISTING; break;
case BH_IO_CREATE: how = CREATE_ALWAYS; break;
case BH_IO_APPEND: how = OPEN_ALWAYS; break;
default:
case BH_IO_TRUNCATE:
return BH_NO_IMPL;
}
file->mode = mode;
file->handle = CreateFileA(file->path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL);
if (file->handle == INVALID_HANDLE_VALUE)
{
/* Error handling */
switch (GetLastError())
{
case ERROR_FILE_EXISTS: return BH_FOUND;
case ERROR_FILE_NOT_FOUND: return BH_NOT_FOUND;
default: return BH_ERROR;
}
}
return BH_OK;
}
void bh_file_close_base(bh_file_t *file)
{
if (file->handle != INVALID_HANDLE_VALUE)
CloseHandle(file->handle);
file->handle = INVALID_HANDLE_VALUE;
}
int bh_file_is_open_base(bh_file_t *file)
{
return file->handle != INVALID_HANDLE_VALUE;
}
void bh_file_destroy(bh_file_t *file)
{
bh_file_close(file);
free(file->path);
}
size_t bh_file_read_base(bh_file_t *file,
char *data,
size_t size)
{
DWORD readed;
if (!ReadFile(file->handle, data, (DWORD)size, &readed, NULL))
{
file->base.flags |= BH_IO_ERROR;
return 0;
}
if (!readed)
file->base.flags |= BH_IO_EOF;
else
file->base.flags &= ~BH_IO_EOF;
return readed;
}
size_t bh_file_write_base(bh_file_t *file,
const char *data,
size_t size)
{
DWORD written;
if ((file->mode & BH_IO_MASK) == BH_IO_APPEND)
bh_file_seek(file, 0, BH_IO_END);
if (!WriteFile(file->handle, data, (DWORD)size, &written, NULL))
{
file->base.flags |= BH_IO_ERROR;
return 0;
}
if (!written)
file->base.flags |= BH_IO_EOF;
else
file->base.flags &= ~BH_IO_EOF;
return written;
}
void bh_file_flush_base(bh_file_t *file)
{
FlushFileBuffers(file->handle);
}
int bh_file_seek_base(bh_file_t *file,
bh_off_t pos,
int dir)
{
LARGE_INTEGER position;
position.QuadPart = pos;
if (SetFilePointerEx(file->handle, position, NULL, dir))
return BH_OK;
return BH_ERROR;
}
bh_off_t bh_file_size_base(bh_file_t *file)
{
return -1;
}
bh_off_t bh_file_tell_base(bh_file_t *file)
{
LARGE_INTEGER dummy, position;
dummy.QuadPart = 0;
if (SetFilePointerEx(file->handle, dummy, &position, BH_IO_CURRENT))
return position.QuadPart;
return -1;
}
bh_off_t bh_file_available_base(bh_file_t *file)
{
return 0;
}
void bh_file_clear_base(bh_file_t *file)
{
file->base.flags &= ~BH_IO_ERROR;
}

View File

@@ -2,6 +2,22 @@
#include <stdlib.h>
#include <string.h>
/**
* \defgroup hashmap Hashmap
*
* Data stucture for storing pointers in the hashmap.
* \{
*/
/**
* Creates the new hashmap object.
*
* \param equal Comparision function
* \param hash Key hash function
*
* \return On success, returns the pointer to the new hashmap object.
* \return On failure, returns a null pointer.
*/
bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal,
bh_hash_cb_t hash)
{
@@ -14,12 +30,26 @@ bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal,
return result;
}
/**
* Frees the \a hashmap object.
*
* \param hashmap Pointer to the hashmap object to be freed
*/
void bh_hashmap_free(bh_hashmap_t *hashmap)
{
bh_hashmap_destroy(hashmap);
free(hashmap);
}
/**
* Initializes the \a hashmap object.
*
* \warning This is an internal function.
*
* \param hashmap Pointer to the hashmap object to be initialized
* \param equal Comparision function
* \param hash Key hash function
*/
void bh_hashmap_init(bh_hashmap_t *hashmap,
bh_equal_cb_t equal,
bh_hash_cb_t hash)
@@ -30,6 +60,13 @@ void bh_hashmap_init(bh_hashmap_t *hashmap,
hashmap->hash = hash;
}
/**
* Destroys the \a hashmap object.
*
* \warning This is an internal function.
*
* \param hashmap Pointer to the hashmap object to be destroied
*/
void bh_hashmap_destroy(bh_hashmap_t *hashmap)
{
if (hashmap->capacity)
@@ -39,6 +76,11 @@ void bh_hashmap_destroy(bh_hashmap_t *hashmap)
}
}
/**
* Clears the \a hashmap object.
*
* \param hashmap Pointer to the hashmap object to be cleared
*/
void bh_hashmap_clear(bh_hashmap_t *hashmap)
{
if (hashmap->capacity)
@@ -46,6 +88,22 @@ void bh_hashmap_clear(bh_hashmap_t *hashmap)
hashmap->size = 0;
}
/**
* Reserves the space for \a size elements in the \a hashmap.
*
* This function can both expand and shrink the available space in \a hashmap.
* This function takes into account current hashmap load factor.
*
* \param hashmap Pointer to the hashmap object to be resized in terms of
* capacity
* \param size New capacity of the hashmap
*
* \note Calling this function will invalidate iterators.
* \note Actual hashmap capacity can be bigger then requested.
*
* \return On success, returns zero value.
* \return On failure, returns error code.
*/
int bh_hashmap_reserve(bh_hashmap_t *hashmap,
size_t size)
{
@@ -78,7 +136,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
/* Capacity can't be bigger than max capacity and overflow */
if (capacity > max_capacity || capacity < 16)
return -1;
return BH_OOM;
}
}
else
@@ -93,7 +151,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
/* Prevent same size reallocation */
if (capacity == hashmap->capacity)
return 0;
return BH_OK;
/* Initialize new hashmap */
bh_hashmap_init(&other, hashmap->equal, hashmap->hash);
@@ -105,7 +163,6 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
/* Allocate new memory for the hashmap */
other.data = malloc(sizeof(*other.data) * capacity);
other.psls = malloc(sizeof(size_t) * capacity);
other.threshold = threshold;
other.capacity = capacity;
@@ -117,7 +174,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
free(other.data);
if (other.psls)
free(other.psls);
return -1;
return BH_OOM;
}
/* Reset probe sequence lengths */
@@ -140,9 +197,22 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
/* Swap hashmaps */
bh_hashmap_destroy(hashmap);
*hashmap = other;
return 0;
return BH_OK;
}
/**
* Inserts the pair of \a key and \a value into the \a hashmap. This function
* allows duplicates to be inserted.
*
* \param hashmap Pointer to the hashmap object
* \param key Key to be inserted
* \param value Value to be inserted
*
* \note Calling this function will invalidate iterators.
*
* \return On success, returns zero value.
* \return On failure, returns error code.
*/
int bh_hashmap_insert(bh_hashmap_t *hashmap,
void *key,
void *value)
@@ -154,7 +224,7 @@ int bh_hashmap_insert(bh_hashmap_t *hashmap,
if (hashmap->size + 1 > hashmap->threshold)
if (bh_hashmap_reserve(hashmap, hashmap->size + 1))
if (hashmap->size >= hashmap->capacity)
return -1;
return BH_OOM;
/* Prepare inserted data and set PSL to 1 */
item.key = key;
@@ -187,9 +257,19 @@ int bh_hashmap_insert(bh_hashmap_t *hashmap,
hashmap->psls[bucket] = psl;
hashmap->size++;
return 0;
return BH_OK;
}
/**
* Removes value from the \a hashmap by \a key.
*
* \param hashmap Pointer to the hashmap object
* \param key Key value
*
* \note Calling this function will invalidate iterators.
* \note If hashmap contains several key-value pairs with the same key, only
* one pair will be removed.
*/
void bh_hashmap_remove(bh_hashmap_t *hashmap,
void *key)
{
@@ -200,6 +280,19 @@ void bh_hashmap_remove(bh_hashmap_t *hashmap,
bh_hashmap_iter_remove(hashmap, iter);
}
/**
* Returns the value from the \a hashmap by the specified \a key.
*
* If the \a exists is not null pointer, the value will be stored to indicated,
* whether the \a key exists in the hashmap or not.
*
* \param hashmap Pointer to the hashmap object
* \param key Key value
* \param exists Pointer to the exists flag variable (optional)
*
* \return On success, returns value.
* \return On failure, return null pointer.
*/
void *bh_hashmap_at(bh_hashmap_t *hashmap,
void *key,
int *exists)
@@ -221,36 +314,87 @@ void *bh_hashmap_at(bh_hashmap_t *hashmap,
return NULL;
}
/**
* Checks if the \a hashmap is empty.
*
* \param hashmap Pointer to the hashmap object
*
* \return If hashmap is empty, returns non-zero value
* \return If hashmap is not empty, returns zero value
*/
int bh_hashmap_empty(bh_hashmap_t *hashmap)
{
return !hashmap->size;
}
/**
* Returns the size of the \a hashmap.
*
* \param hashmap Pointer to the hashmap object
*
* \return Returns the size of the hashmap.
*/
size_t bh_hashmap_size(bh_hashmap_t *hashmap)
{
return hashmap->size;
}
/**
* Returns the capacity of the \a hashmap.
*
* \param hashmap Pointer to the hashmap object
*
* \return Returns the capacity of the hashmap.
*/
size_t bh_hashmap_capacity(bh_hashmap_t *hashmap)
{
return hashmap->capacity;
}
/**
* Returns the load factor of the \a hashmap.
*
* \param hashmap Pointer to the hashmap object
*
* \return Returns the load factor of the hashmap.
*/
float bh_hashmap_factor(bh_hashmap_t *hashmap)
{
return hashmap->factor;
}
/**
* Sets the load \a factor of the \a hashmap.
*
* \param hashmap Pointer to the hashmap object
* \param factor Load factor value
*
* \note New load factor will be applied on the next reserve/insert operation.
*/
void bh_hashmap_set_factor(bh_hashmap_t *hashmap,
float factor)
{
/* Limit the factor value to [0.15, 1.0] */
factor = (factor > 1.0f) ? (1.0f) : (factor);
factor = (factor < 0.15f) ? (0.15f) : (factor);
/* Calculate new threshold value */
hashmap->factor = factor;
hashmap->threshold = hashmap->capacity * factor;
}
/**
* Returns the iterator to the element in the \a hashmap with specified \a key.
*
* \param hashmap Pointer to the hashmap object
* \param iter Opaque iterator value
*
* \return On success, returns iterator value.
* \return On failure, returns null pointer.
*
* \note If hashmap contains several key-value pairs with the same key, only
* iterator to the one of the pairs will returned.
*/
void *bh_hashmap_iter_at(bh_hashmap_t *hashmap,
void *key)
{
@@ -278,6 +422,19 @@ void *bh_hashmap_iter_at(bh_hashmap_t *hashmap,
return NULL;
}
/**
* Returns the iterator to the next element in the \a hashmap.
*
* \param hashmap Pointer to the hashmap object
* \param iter Opaque iterator value
*
* \return If the \a iter doesn't point to the last element of the hashmap,
* returns next iterator value.
* \return If the \a iter point to the last element of the hashmap, returns
* null pointer.
* \return If the \a iter is the null pointer, returns iterator to the
* first element of the hashmap.
*/
void *bh_hashmap_iter_next(bh_hashmap_t *hashmap,
void *iter)
{
@@ -302,6 +459,14 @@ void *bh_hashmap_iter_next(bh_hashmap_t *hashmap,
}
}
/**
* Removes value from the \a hashmap by iterator \a iter.
*
* \param hashmap Pointer to the hashmap object
* \param iter Iterator value
*
* \note Calling this function will invalidate iterators.
*/
void bh_hashmap_iter_remove(bh_hashmap_t *hashmap,
void *iter)
{
@@ -332,12 +497,30 @@ void bh_hashmap_iter_remove(bh_hashmap_t *hashmap,
hashmap->psls[bucket] = 0;
}
/**
* Returns the key, pointed by the hashmap iterator \a iter.
*
* \param iter Opaque iterator value
*
* \return Returns key, pointed by iterator.
*/
void *bh_hashmap_iter_key(void *iter)
{
return ((bh_hashmap_node_t *)iter)->key;
}
/**
* Returns the value, pointed by the hashmap iterator \a iter.
*
* \param iter Opaque iterator value
*
* \return Returns value, pointed by iterator.
*/
void *bh_hashmap_iter_value(void *iter)
{
return ((bh_hashmap_node_t *)iter)->value;
}
/**
* \}
*/

182
src/io.c
View File

@@ -1,6 +1,25 @@
#include <bh/internal/io.h>
#include <stdlib.h>
/**
* \defgroup io Input/Output
*
* Input/output device abstraction layer.
* \{
*/
/**
* Creates the new io object with specified \a table and \a size.
*
* \param table Pointer to the io table
* \param size Size of the io object
*
* \return On success, returns new semi-initialized io object.
* \return On failure, returns null pointer.
*
* \warning This function should be used in context of implementing child
* io objects (files, sockets, streaming compression, etc).
*/
bh_io_t *bh_io_new(bh_io_table_t *table,
size_t size)
{
@@ -13,24 +32,91 @@ bh_io_t *bh_io_new(bh_io_table_t *table,
return result;
}
/**
* Frees the \a io object.
*
* \param io Pointer to the io object to be freed
*/
void bh_io_free(bh_io_t *io)
{
bh_io_destroy(io);
free(io);
}
/**
* Initializes the \a io object with specified \a table.
*
* \param io Pointer to the io object to be initialized
* \param table Pointer to the io table
*/
void bh_io_init(bh_io_t *io,
bh_io_table_t *table)
const bh_io_table_t *table)
{
io->table = table;
io->flags = 0;
}
/**
* Destroys the \a io object.
*
* \param io Pointer to the io object to be destroyed
*/
void bh_io_destroy(bh_io_t *io)
{
io->table->destroy(io);
}
/**
* Opens the \a io object for specified \a mode of operation.
*
* \param io Pointer to the io object
* \param mode Bitmask determining access mode
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_io_open(bh_io_t *io,
int mode)
{
return io->table->open(io, mode);
}
/**
* Closes the \a io object.
*
* \param io Pointer to the io object
*/
void bh_io_close(bh_io_t *io)
{
io->table->close(io);
}
/**
* Checks if the \a io is open.
*
* \param io Pointer to the io object
*
* \return If io object is open - returns non-zero.
* \return If io object is closed - returns zero.
*/
int bh_io_is_open(bh_io_t *io)
{
return io->table->is_open(io);
}
/**
* Reads up to \a size amount of bytes from the \a io object into memory buffer
* pointed by \a data pointer.
*
* \param io Pointer to the io object
* \param data Pointer to the memory buffer
* \param size Maximum number of bytes to be read
*
* \return On success, returns number of bytes successfuly read.
* \return On failure, returns zero.
*
* \note To check for end-of-file or error see bh_io_eof and bh_io_error.
*/
size_t bh_io_read(bh_io_t *io,
char *data,
size_t size)
@@ -38,6 +124,19 @@ size_t bh_io_read(bh_io_t *io,
return io->table->read(io, data, size);
}
/**
* Writes up to \a size amount of bytes to the \a io object from memory buffer
* pointed by \a data pointer.
*
* \param io Pointer to the io object
* \param data Pointer to the memory buffer
* \param size Maximum number of bytes to be read
*
* \return On success, returns number of bytes successfuly written.
* \return On failure, returns zero.
*
* \note To check for error see bh_io_error.
*/
size_t bh_io_write(bh_io_t *io,
const char* data,
size_t size)
@@ -45,39 +144,112 @@ size_t bh_io_write(bh_io_t *io,
return io->table->write(io, data, size);
}
/**
* Synchronizes the \a io object (if possible).
*
* In most cases, this function causes any unwritten/buffered data to be
* written.
*
* \param io Pointer to the io object
*/
void bh_io_flush(bh_io_t *io)
{
io->table->flush(io);
}
void bh_io_seek(bh_io_t *io,
/**
* Seeks the \a io object in the specified direction \a dir and \a offset (if
* possible).
*
* \param io Pointer to the io object
* \param offset Number of bytes to seek in specified direciton
* \param dir Seeking direction
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_io_seek(bh_io_t *io,
bh_off_t offset,
int dir)
{
io->table->seek(io, offset, dir);
return io->table->seek(io, offset, dir);
}
/**
* Returns total size of the \a io object (if possible)
*
* \param io Pointer to the io object
*
* \return On success, returns total size of the io object.
* \return On failure, returns -1.
*/
bh_off_t bh_io_size(bh_io_t *io)
{
return io->table->size(io);
}
/**
* Returns current position in the \a io object (if possible).
*
* \param io Pointer to the io object
*
* \return On success, returns current position in the io object.
* \return On failure, returns -1.
*/
bh_off_t bh_io_tell(bh_io_t *io)
{
return io->table->tell(io);
}
/**
* Returns available number of bytes to be read from the \a io object.
*
* \param io Pointer to the io object
*
* \return On success, returns number of available bytes to be read.
* \return On failure, returns zero.
*/
bh_off_t bh_io_available(bh_io_t *io)
{
return io->table->available(io);
}
/**
* Checks error flag of the \a io object.
*
* \param io Pointer to the io object
*
* \return If error flag is set, returns non-zero.
* \return If error flag is not set, returns zero.
*/
int bh_io_error(bh_io_t *io)
{
return (io->flags & BH_IO_ERROR) > 0;
return (io->flags & BH_IO_ERROR) != 0;
}
/**
* Checks end-of-file flag of the \a io object.
*
* \param io Pointer to the io object
*
* \return If end-of-file flag is set, returns non-zero.
* \return If end-of-file flag is not set, returns zero.
*/
int bh_io_eof(bh_io_t *io)
{
return (io->flags & BH_IO_EOF) > 0;
return (io->flags & BH_IO_EOF) != 0;
}
/**
* Clears error of the \a io object.
*
* \param io Pointer to the io object
*/
void bh_io_clear(bh_io_t *io)
{
io->table->clear(io);
}
/**
* \}
*/

View File

@@ -2,6 +2,19 @@
#include <stdlib.h>
#include <string.h>
/**
* \defgroup queue Queue
*
* Data stucture for storing pointers in queue.
* \{
*/
/**
* Creates the new queue object.
*
* \return On success, returns the pointer to the new queue object.
* \return On failure, returns a null pointer.
*/
bh_queue_t *bh_queue_new(void)
{
bh_queue_t *result;
@@ -13,23 +26,47 @@ bh_queue_t *bh_queue_new(void)
return result;
}
/**
* Frees the \a queue object.
*
* \param queue Pointer to the queue object to be freed
*/
void bh_queue_free(bh_queue_t *queue)
{
bh_queue_destroy(queue);
free(queue);
}
/**
* Initializes the \a queue object.
*
* \warning This is an internal function.
*
* \param queue Pointer to the queue object to be initialized
*/
void bh_queue_init(bh_queue_t *queue)
{
memset(queue, 0, sizeof(*queue));
}
/**
* Destroys the \a queue object.
*
* \warning This is an internal function.
*
* \param queue Pointer to the queue object to be destroyed
*/
void bh_queue_destroy(bh_queue_t *queue)
{
if (queue->capacity)
free(queue->data);
}
/**
* Clears the \a queue object.
*
* \param queue Pointer to the queue object to be cleared
*/
void bh_queue_clear(bh_queue_t *queue)
{
queue->head = 0;
@@ -37,6 +74,20 @@ void bh_queue_clear(bh_queue_t *queue)
queue->size = 0;
}
/**
* Reserves the space for \a size elements in the \a queue.
*
* This function can both expand and shrink the available space in \a queue.
*
* \param queue Pointer to the queue object to be resized in terms of capacity
* \param size New capacity of the queue
*
* \note Calling this function will invalidate iterators.
* \note Actual hashmap capacity can be bigger then requested.
*
* \return On success, returns zero value.
* \return On failure, returns error code.
*/
int bh_queue_reserve(bh_queue_t *queue,
size_t size)
{
@@ -48,11 +99,11 @@ int bh_queue_reserve(bh_queue_t *queue,
/* New capacity should not exceed maximum capacity */
if (size > ((size_t)-1) / sizeof(void *))
return -1;
return BH_OOM;
/* Prevent same size memory reallocation */
if (size == queue->capacity)
return 0;
return BH_OK;
/* Prepare new empty queue */
bh_queue_init(&other);
@@ -64,7 +115,7 @@ int bh_queue_reserve(bh_queue_t *queue,
other.data = malloc(size * sizeof(void *));
other.capacity = size;
if (!other.data)
return -1;
return BH_OOM;
/* Iterate over old queue and insert data into new queue */
iter = bh_queue_iter_next(queue, NULL);
@@ -81,9 +132,20 @@ int bh_queue_reserve(bh_queue_t *queue,
/* Copy queue information */
*queue = other;
return 0;
return BH_OK;
}
/**
* Inserts the \a value into the \a queue.
*
* \param queue Pointer to the queue object
* \param value Value to be inserted
*
* \note Calling this function will invalidate iterators.
*
* \return On success, returns zero value.
* \return On failure, returns error code.
*/
int bh_queue_insert(bh_queue_t *queue,
void *value)
{
@@ -95,7 +157,7 @@ int bh_queue_insert(bh_queue_t *queue,
/* Check potential size overflow and reserve capacity */
capacity = (queue->capacity) ? (queue->capacity * 2) : (16);
if (capacity < queue->capacity || bh_queue_reserve(queue, capacity))
return -1;
return BH_OOM;
}
/* Increase queue size and advance tail index */
@@ -104,9 +166,16 @@ int bh_queue_insert(bh_queue_t *queue,
if (++queue->tail >= queue->capacity)
queue->tail = 0;
return 0;
return BH_OK;
}
/**
* Removes front value from the \a queue.
*
* \param queue Pointer to the queue object
*
* \note Calling this function will invalidate iterators.
*/
void bh_queue_remove(bh_queue_t *queue)
{
/* Do nothing if queue is empty */
@@ -119,6 +188,14 @@ void bh_queue_remove(bh_queue_t *queue)
queue->head = 0;
}
/**
* Returns front value from the \a queue.
*
* \param queue Pointer to the queue object
*
* \return On success, returns front value from the queue.
* \return On failure, returns null pointer.
*/
void *bh_queue_front(bh_queue_t *queue)
{
/* Do nothing if queue is empty */
@@ -129,21 +206,56 @@ void *bh_queue_front(bh_queue_t *queue)
return queue->data[queue->head];
}
/**
* Checks if the \a queue is empty.
*
* \param queue Pointer to the queue object
*
* \return If queue is empty, returns non-zero value
* \return If queue is not empty, returns zero value
*/
int bh_queue_empty(bh_queue_t *queue)
{
return !queue->size;
}
/**
* Returns the size of the \a queue.
*
* \param queue Pointer to the queue object
*
* \return Returns the size of the queue.
*/
size_t bh_queue_size(bh_queue_t *queue)
{
return queue->size;
}
/**
* Returns the capacity of the \a queue.
*
* \param queue Pointer to the queue object
*
* \return Returns the capacity of the queue.
*/
size_t bh_queue_capacity(bh_queue_t *queue)
{
return queue->capacity;
}
/**
* Returns the iterator to the next element in the \a queue.
*
* \param queue Pointer to the queue object
* \param iter Opaque iterator value
*
* \return If the \a iter doesn't point to the last element of the queue,
* returns next iterator value.
* \return If the \a iter point to the last element of the queue, returns
* null pointer.
* \return If the \a iter is the null pointer, returns iterator to the
* first element of the queue.
*/
void *bh_queue_iter_next(bh_queue_t *queue,
void *iter)
{
@@ -170,7 +282,18 @@ void *bh_queue_iter_next(bh_queue_t *queue,
return element;
}
/**
* Returns the value, pointed by the queue iterator \a iter.
*
* \param iter Opaque iterator value
*
* \return Returns value, pointed by iterator.
*/
void *bh_queue_iter_value(void *iter)
{
return *(void **)iter;
}
/**
* \}
*/

View File

@@ -1,6 +1,27 @@
#include <bh/internal/thread.h>
#include <stdlib.h>
/**
* \defgroup thread Multithreading
*
* Multithreading API
* \{
*/
/**
* Creates new task object with specified function \a func, \a data and \a
* flags.
*
* If the \a flags contain BH_THREAD_CLEANUP, upon successful completion task
* will be automaticly destroyed.
*
* \param func Task's function
* \param data Task's data
* \param flags Task's flags
*
* \return On success, returns new task object.
* \return On failure, returns null pointer.
*/
bh_task_t *bh_task_new(void (*func)(void *),
void *data,
int flags)
@@ -14,12 +35,31 @@ bh_task_t *bh_task_new(void (*func)(void *),
return result;
}
/**
* Frees the \a task object.
*
* \param task Pointer to the task object.
*/
void bh_task_free(bh_task_t *task)
{
bh_task_destroy(task);
free(task);
}
/**
* Initializes the \a task object with specified function \a func, \a data and
* \a flags.
*
* If the \a flags contain BH_THREAD_CLEANUP, upon successful completion task
* will be automaticly destroyed.
*
* \warning This is an internal function.
*
* \param task Pointer to the task object
* \param func Task's function
* \param data Task's data
* \param flags Task's flags
*/
void bh_task_init(bh_task_t *task,
void (*func)(void *),
void *data,
@@ -30,24 +70,53 @@ void bh_task_init(bh_task_t *task,
task->flags = flags;
}
/**
* Destroyes the \a task object.
*
* \warning This is an internal function.
*
* \param task Pointer to the task object
*/
void bh_task_destroy(bh_task_t *task)
{
(void)task;
}
/**
* Reuses the \a task object for different purpose.
*
* \param task Pointer to the task object
* \param func New task's function
* \param data New task's data
*/
void bh_task_reuse(bh_task_t *task,
void (*func)(void *),
void *data)
{
/* If the task is done - reinitilize it with new data */
if (task->flags & BH_THREAD_DONE)
bh_task_init(task, func, data, task->flags & ~(BH_THREAD_DONE));
}
/**
* Checks if the \a task is done.
*
* \param task Pointer to the task object
*
* \return If the task is done, returns non-zero.
* \return If the task is not done, returns zero.
*/
int bh_task_done(bh_task_t *task)
{
return (task->flags & BH_THREAD_DONE) != 0;
}
/**
* Creates the mutex object.
*
* \return On success, returns new mutex object.
* \return On failure, returns null pointer.
*/
bh_mutex_t *bh_mutex_new(void)
{
bh_mutex_t *result;
@@ -62,12 +131,27 @@ bh_mutex_t *bh_mutex_new(void)
return result;
}
/**
* Frees the \a mutex object.
*
* \param mutex Pointer to the mutex object
*/
void bh_mutex_free(bh_mutex_t *mutex)
{
bh_mutex_destroy(mutex);
free(mutex);
}
/**
* Creates the semaphore object with initial \a count value.
*
* \param count Initial semaphore value
*
* \return On success, returns new semaphore object.
* \return On failure, returns null pointer.
*
* \note Guranteed maximum \a count value is 32767.
*/
bh_semaphore_t *bh_semaphore_new(int count)
{
bh_semaphore_t *result;
@@ -82,12 +166,23 @@ bh_semaphore_t *bh_semaphore_new(int count)
return result;
}
/**
* Frees the \a semaphore object.
*
* \param semaphore Pointer to the semaphore object
*/
void bh_semaphore_free(bh_semaphore_t *semaphore)
{
bh_semaphore_destroy(semaphore);
free(semaphore);
}
/**
* Creates the condition variable object.
*
* \return On success, returns new condition variable object.
* \return On failure, returns null pointer.
*/
bh_cond_t *bh_cond_new(void)
{
bh_cond_t *result;
@@ -102,12 +197,26 @@ bh_cond_t *bh_cond_new(void)
return result;
}
/**
* Frees the condition variable object \a cond.
*
* \param cond Pointer to the condition variable object
*/
void bh_cond_free(bh_cond_t *cond)
{
bh_cond_destroy(cond);
free(cond);
}
/**
* Adds \a task to the thread \a pool.
*
* \param pool Pointer to the thread pool object
* \param task Pointer to the task object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_thread_pool_add(bh_thread_pool_t *pool,
bh_task_t *task)
{
@@ -119,16 +228,24 @@ int bh_thread_pool_add(bh_thread_pool_t *pool,
if (bh_queue_insert(&pool->tasks, task))
{
bh_mutex_unlock(&pool->lock);
return -1;
return BH_ERROR;
}
/* Signal new job */
bh_mutex_unlock(&pool->lock);
bh_cond_signal(&pool->new_task);
return 0;
return BH_OK;
}
/**
* Waits unitl all task in thread \a pool are complete.
*
* \param pool Pointer to the thread pool.
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_thread_pool_wait(bh_thread_pool_t *pool)
{
/* Lock and check if there is jobs in the queue */
@@ -160,9 +277,16 @@ int bh_thread_pool_wait(bh_thread_pool_t *pool)
/* Unlock */
bh_mutex_unlock(&pool->lock);
return 0;
return BH_OK;
}
/**
* Destroyes the thread \a pool object.
*
* \warning This is an internal function.
*
* \param pool Pointer to the thread pool object
*/
void bh_thread_pool_destroy(bh_thread_pool_t *pool)
{
size_t i;
@@ -195,12 +319,21 @@ void bh_thread_pool_destroy(bh_thread_pool_t *pool)
bh_mutex_destroy(&pool->lock);
}
/**
* Frees the thread \a pool object.
*
* \param pool Pointer to the thread pool object
*/
void bh_thread_pool_free(bh_thread_pool_t *pool)
{
bh_thread_pool_destroy(pool);
free(pool);
}
/**
* \warning This is an internal function.
* \warning Do not use this function directly!
*/
void bh_thread_pool_worker(void *arg)
{
bh_thread_pool_t *pool;
@@ -210,26 +343,31 @@ void bh_thread_pool_worker(void *arg)
{
bh_task_t *task;
/* Wait unitl there is a task or shutdown signal */
bh_mutex_lock(&pool->lock);
while (!pool->shutdown && bh_queue_empty(&pool->tasks))
bh_cond_wait(&pool->new_task, &pool->lock);
/* If its shutdown signal - exit the loop */
if (pool->shutdown)
{
bh_mutex_unlock(&pool->lock);
break;
}
/* Fetch task from the front of the queue, increase active counter */
task = bh_queue_front(&pool->tasks);
bh_queue_remove(&pool->tasks);
pool->active++;
bh_mutex_unlock(&pool->lock);
/* Do the task, mark as done, and if required - free it */
task->func(task->data);
task->flags |= BH_THREAD_DONE;
if (task->flags & BH_THREAD_CLEANUP)
bh_task_free(task);
/* Decrease active counter and broadcast that we are done */
bh_mutex_lock(&pool->lock);
pool->active--;
@@ -237,3 +375,7 @@ void bh_thread_pool_worker(void *arg)
bh_cond_broadcast(&pool->done_task);
}
}
/**
* \}
*/

View File

@@ -1,116 +1,300 @@
#include <bh/internal/thread.h>
int bh_thread_init(bh_thread_t *thread,
bh_task_t *task)
{
(void)thread;
(void)task;
return -1;
}
/**
* \ingroup thread
* \{
*/
/**
* Creates the thread object with the given \a task.
*
* \warning This function can be implemented either as a macro or as a function.
*
* \param task Pointer to the task object
*
* \return On success, returns the pointer to the new queue object.
* \return On failure, returns a null pointer.
*/
bh_thread_t *bh_thread_new(bh_task_t *task)
{
(void)task;
return NULL;
}
/**
* Initializes the \a thread object with the given \a task.
*
* \warning This is an internal function.
* \warning This function can be implemented either as a macro or as a function.
*
* \param thread Pointer to the thread object
* \param task Pointer to the task object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_thread_init(bh_thread_t *thread,
bh_task_t *task)
{
(void)thread;
(void)task;
return BH_NO_IMPL;
}
/**
* Joins the \a thread.
*
* If thread was created with bh_thread_new, this function also frees the \a
* thread object.
*
* \param thread Pointer to the thread object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_thread_join(bh_thread_t *thread)
{
(void)thread;
return -1;
return BH_NO_IMPL;
}
/**
* Detaches the \a thread.
*
* If thread was created with bh_thread_new, this function also frees the \a
* thread object.
*
* \param thread Pointer to the thread object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_thread_detach(bh_thread_t *thread)
{
(void)thread;
return -1;
return BH_NO_IMPL;
}
/**
* Initializes the \a mutex object.
*
* \warning This is an internal function.
*
* \param mutex Pointer to the mutex object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_mutex_init(bh_mutex_t *mutex)
{
(void)mutex;
return -1;
return BH_NO_IMPL;
}
/**
* Destroyes the \a mutex object.
*
* \param mutex Pointer to the mutex object
*
* \warning This is an internal function.
*/
void bh_mutex_destroy(bh_mutex_t *mutex)
{
(void)mutex;
}
/**
* Locks the \a mutex object.
*
* \param mutex Pointer to the mutex object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_mutex_lock(bh_mutex_t *mutex)
{
(void)mutex;
return -1;
return BH_NO_IMPL;
}
/**
* Tries to lock the \a mutex object.
*
* \param mutex Pointer to the mutex object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_mutex_try_lock(bh_mutex_t *mutex)
{
(void)mutex;
return -1;
return BH_NO_IMPL;
}
/**
* Unlocks the \a mutex object.
*
* \param mutex Pointer to the mutex object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_mutex_unlock(bh_mutex_t *mutex)
{
(void)mutex;
return -1;
return BH_NO_IMPL;
}
/**
* Initilizes the \a semaphore object with specified \a count value.
*
* \warning This is an internal function.
*
* \param semaphore Pointer to the semaphore object
* \param count Initial semaphore value
*
* \return On success, returns zero.
* \return On failure, returns error code.
*
* \note Guranteed maximum \a count value is 32767.
*/
int bh_semaphore_init(bh_semaphore_t *semaphore, int count)
{
(void)semaphore;
(void)count;
return -1;
return BH_NO_IMPL;
}
/**
* Destroyes the \a semaphore object.
*
* \warning This is an internal function.
*
* \param semaphore Pointer to the semaphore object
*/
void bh_semaphore_destroy(bh_semaphore_t *semaphore)
{
(void)semaphore;
}
/**
* Posts (increases value of) the \a semaphore.
*
* \param semaphore Pointer to the semaphore object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_semaphore_post(bh_semaphore_t *semaphore)
{
(void)semaphore;
return -1;
return BH_NO_IMPL;
}
/**
* Waits (decreases value of) the \a semaphore.
*
* \param semaphore Pointer to the semaphore object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_semaphore_wait(bh_semaphore_t *semaphore)
{
(void)semaphore;
return -1;
return BH_NO_IMPL;
}
/**
* Waits (decreases value of) the \a semaphore for the specified \a timeout
* amount of milliseconds.
*
* \param semaphore Pointer to the semaphore object
* \param timeout Number of milliseconds to wait for
*
* \return On success, returns zero.
* \return On failure or timeout, returns error code.
*/
int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
unsigned long timeout)
{
(void)semaphore;
return -1;
return BH_NO_IMPL;
}
/**
* Tries to waits (decrease value of) the \a semaphore.
*
* \param semaphore Pointer to the semaphore object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_semaphore_try_wait(bh_semaphore_t *semaphore)
{
(void)semaphore;
return -1;
return BH_NO_IMPL;
}
/**
* Initializes the condition variable object \a cond.
*
* \warning This is an internal function.
*
* \param cond Pointer to the condition variable
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_cond_init(bh_cond_t *cond)
{
(void)cond;
return -1;
return BH_NO_IMPL;
}
/**
* Destroyes the condition variable object \a cond.
*
* \param cond Pointer to the condition variable object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*
* \warning This is an internal function.
*/
void bh_cond_destroy(bh_cond_t *cond)
{
(void)cond;
}
/**
* Waits on the condition variable \a cond with specified \a mutex.
*
* \param cond Pointer to the condition variable object
* \param mutex Pointer to the mutex object
*
* \return On success, returns zero.
* \return ON failure, returns error code.
*/
int bh_cond_wait(bh_cond_t *cond,
bh_mutex_t *mutex)
{
(void)cond;
(void)mutex;
return -1;
return BH_NO_IMPL;
}
/**
* Waits on the condition variable \a cond with specified \a mutex for the
* specified \a timeout amount of milliseconds.
*
* \param cond Pointer to the condition variable object
* \param mutex Pointer to the mutex object
* \param timeout Number of milliseconds to wait for
*
* \return On success, returns zero.
* \return On failure or timeout, returns error code.
*/
int bh_cond_wait_for(bh_cond_t *cond,
bh_mutex_t *mutex,
unsigned long timeout)
@@ -118,33 +302,71 @@ int bh_cond_wait_for(bh_cond_t *cond,
(void)cond;
(void)mutex;
(void)timeout;
return -1;
return BH_NO_IMPL;
}
/**
* Signals (notifies) one waiting thread on the condition variable \a cond.
*
* \param cond Pointer to the condition variable object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_cond_signal(bh_cond_t *cond)
{
(void)cond;
return -1;
return BH_NO_IMPL;
}
/**
* Signals (notifies) all waiting threads on the condition variable \a cond.
*
* \param cond Pointer to the condition variable object
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_cond_broadcast(bh_cond_t *cond)
{
(void)cond;
return -1;
}
int bh_thread_pool_init(bh_thread_pool_t *pool,
size_t size)
{
(void)pool;
(void)size;
return -1;
return BH_NO_IMPL;
}
/**
* Creates the thread pool object with specified \a size amount of threads.
*
* \param size Number of threads in the thread pool
*
* \return On success, returns pointer to the new thread pool object.
* \return On failure, returns null pointer.
*/
bh_thread_pool_t *bh_thread_pool_new(size_t size)
{
(void)size;
return NULL;
}
/**
* Initilizes the thread \a pool object with specified \a size amount of
* threads.
*
* \warning This is an internal function.
*
* \param pool Pointer to the thread pool object
* \param size Number of threads in the thread pool
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int bh_thread_pool_init(bh_thread_pool_t *pool,
size_t size)
{
(void)pool;
(void)size;
return BH_NO_IMPL;
}
/**
* \}
*/

View File

@@ -5,9 +5,9 @@
static void *bh_thread_run(void *arg)
{
bh_task_t *task;
task = (bh_task_t *)arg;
/* Do the task, mark as done, and if required free it */
task->func(task->data);
task->flags |= BH_THREAD_DONE;
@@ -21,21 +21,25 @@ int bh_thread_init(bh_thread_t *thread,
bh_task_t *task)
{
thread->allocated = 0;
return pthread_create(&thread->handle, NULL, bh_thread_run, task);
if (pthread_create(&thread->handle, NULL, bh_thread_run, task))
return BH_ERROR;
return BH_OK;
}
bh_thread_t *bh_thread_new(bh_task_t *task)
{
bh_thread_t *result;
/* Allocate thread object */
result = malloc(sizeof(*result));
if (result && bh_thread_init(result, task))
{
free(result);
result = NULL;
}
/* Mark thread as allocated for deallocation in join/detach */
if (result)
result->allocated = 1;
@@ -44,27 +48,35 @@ bh_thread_t *bh_thread_new(bh_task_t *task)
int bh_thread_join(bh_thread_t *thread)
{
int result = pthread_join(thread->handle, NULL);
/* Join the thread */
if (pthread_join(thread->handle, NULL))
return BH_ERROR;
/* If thread is allocated, deallocate it */
if (thread->allocated)
free(thread);
return result;
return BH_OK;
}
int bh_thread_detach(bh_thread_t *thread)
{
int result = pthread_detach(thread->handle);
/* Detach the thread */
if (pthread_detach(thread->handle))
return BH_ERROR;
/* If thread is allocated, deallocate it */
if (thread->allocated)
free(thread);
return result;
return BH_OK;
}
int bh_mutex_init(bh_mutex_t *mutex)
{
return pthread_mutex_init(&mutex->handle, NULL);
if (pthread_mutex_init(&mutex->handle, NULL))
return BH_ERROR;
return BH_OK;
}
void bh_mutex_destroy(bh_mutex_t *mutex)
@@ -74,22 +86,30 @@ void bh_mutex_destroy(bh_mutex_t *mutex)
int bh_mutex_lock(bh_mutex_t *mutex)
{
return pthread_mutex_lock(&mutex->handle);
if (pthread_mutex_lock(&mutex->handle))
return BH_ERROR;
return BH_OK;
}
int bh_mutex_try_lock(bh_mutex_t *mutex)
{
return pthread_mutex_trylock(&mutex->handle);
if (pthread_mutex_trylock(&mutex->handle))
return BH_ERROR;
return BH_OK;
}
int bh_mutex_unlock(bh_mutex_t *mutex)
{
return pthread_mutex_unlock(&mutex->handle);
if (pthread_mutex_unlock(&mutex->handle))
return BH_ERROR;
return BH_OK;
}
int bh_semaphore_init(bh_semaphore_t *semaphore, int count)
{
return sem_init(&semaphore->handle, 0, count);
if (sem_init(&semaphore->handle, 0, count))
return BH_ERROR;
return BH_OK;
}
void bh_semaphore_destroy(bh_semaphore_t *semaphore)
@@ -99,12 +119,16 @@ void bh_semaphore_destroy(bh_semaphore_t *semaphore)
int bh_semaphore_post(bh_semaphore_t *semaphore)
{
return sem_post(&semaphore->handle);
if (sem_post(&semaphore->handle))
return BH_ERROR;
return BH_OK;
}
int bh_semaphore_wait(bh_semaphore_t *semaphore)
{
return sem_wait(&semaphore->handle);
if (sem_wait(&semaphore->handle))
return BH_ERROR;
return BH_OK;
}
int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
@@ -115,17 +139,23 @@ int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout - ts.tv_sec * 1000) * 1000000;
return sem_timedwait(&semaphore->handle, &ts);
if (sem_timedwait(&semaphore->handle, &ts))
return BH_TIMEOUT;
return BH_OK;
}
int bh_semaphore_try_wait(bh_semaphore_t *semaphore)
{
return sem_trywait(&semaphore->handle);
if (sem_trywait(&semaphore->handle))
return BH_ERROR;
return BH_OK;
}
int bh_cond_init(bh_cond_t *cond)
{
return pthread_cond_init(&cond->handle, NULL);
if (pthread_cond_init(&cond->handle, NULL))
return BH_ERROR;
return BH_OK;
}
void bh_cond_destroy(bh_cond_t *cond)
@@ -136,7 +166,9 @@ void bh_cond_destroy(bh_cond_t *cond)
int bh_cond_wait(bh_cond_t *cond,
bh_mutex_t *mutex)
{
return pthread_cond_wait(&cond->handle, &mutex->handle);
if (pthread_cond_wait(&cond->handle, &mutex->handle))
return BH_ERROR;
return BH_OK;
}
int bh_cond_wait_for(bh_cond_t *cond,
@@ -148,17 +180,23 @@ int bh_cond_wait_for(bh_cond_t *cond,
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout - ts.tv_sec * 1000) * 1000000;
return pthread_cond_timedwait(&cond->handle, &mutex->handle, &ts);
if (pthread_cond_timedwait(&cond->handle, &mutex->handle, &ts))
return BH_TIMEOUT;
return BH_OK;
}
int bh_cond_signal(bh_cond_t *cond)
{
return pthread_cond_signal(&cond->handle);
if (pthread_cond_signal(&cond->handle))
return BH_ERROR;
return BH_OK;
}
int bh_cond_broadcast(bh_cond_t *cond)
{
return pthread_cond_broadcast(&cond->handle);
if (pthread_cond_broadcast(&cond->handle))
return BH_ERROR;
return BH_OK;
}
int bh_thread_pool_init(bh_thread_pool_t *pool,
@@ -215,7 +253,7 @@ int bh_thread_pool_init(bh_thread_pool_t *pool,
}
}
return 0;
return BH_OK;
queue_fail:
free(pool->threads);
@@ -230,7 +268,7 @@ task_fail:
bh_mutex_destroy(&pool->lock);
lock_fail:
return -1;
return BH_ERROR;
}
bh_thread_pool_t *bh_thread_pool_new(size_t size)

View File

@@ -4,15 +4,18 @@ static unsigned __stdcall bh_thread_run(void *arg)
{
bh_thread_data_t data;
/* Fetch thread data, store it on stack and free from heap */
data = *(bh_thread_data_t *)arg;
free(arg);
/* Do the task, mark as done, and if required free it */
data.task->func(data.task->data);
data.task->flags |= BH_THREAD_DONE;
if (data.task->flags & BH_THREAD_CLEANUP)
bh_task_free(data.task);
/* Call thread specific end function (deallocate TLS) */
data.end(0);
return 0;
}
@@ -24,23 +27,27 @@ int bh_thread_init_base(bh_thread_t *thread,
{
bh_thread_data_t *data;
/* Allocate thread specific data */
data = malloc(sizeof(*data));
if (!data)
return -1;
return BH_OOM;
/* Setup thread specific data */
data->task = task;
data->end = end;
/* Create and setup thread (relative to the callers libc) */
thread->allocated = 0;
thread->handle = (HANDLE)_beginthreadex(NULL, 0, bh_thread_run, data, 0, NULL);
/* Check for errors */
if (!thread->handle)
{
free(data);
return -1;
return BH_ERROR;
}
return 0;
return BH_OK;
}
bh_thread_t *bh_thread_new_base(bh_task_t *task,
@@ -49,6 +56,7 @@ bh_thread_t *bh_thread_new_base(bh_task_t *task,
{
bh_thread_t *result;
/* Allocate thread object */
result = malloc(sizeof(*result));
if (result && !bh_thread_init_base(result, task, begin, end))
{
@@ -56,6 +64,7 @@ bh_thread_t *bh_thread_new_base(bh_task_t *task,
result = NULL;
}
/* Mark thread as allocated for deallocation in join/detach */
if (result)
result->allocated = 1;
@@ -64,30 +73,35 @@ bh_thread_t *bh_thread_new_base(bh_task_t *task,
int bh_thread_join(bh_thread_t *thread)
{
/* Join the thread */
WaitForSingleObject(thread->handle, INFINITE);
CloseHandle(thread->handle);
/* If thread is allocated, deallocate it */
if (thread->allocated)
free(thread);
return 0;
return BH_OK;
}
int bh_thread_detach(bh_thread_t *thread)
{
/* Detach from thread */
CloseHandle(thread->handle);
/* If thread is allocated, deallocate it */
if (thread->allocated)
free(thread);
return 0;
return BH_OK;
}
int bh_mutex_init(bh_mutex_t *mutex)
{
/* TODO: Is this spincount needed or sane? */
if (!InitializeCriticalSectionAndSpinCount(&mutex->handle, 0x400))
return -1;
return 0;
return BH_ERROR;
return BH_OK;
}
void bh_mutex_destroy(bh_mutex_t *mutex)
@@ -98,29 +112,30 @@ void bh_mutex_destroy(bh_mutex_t *mutex)
int bh_mutex_lock(bh_mutex_t *mutex)
{
EnterCriticalSection(&mutex->handle);
return 0;
return BH_OK;
}
int bh_mutex_try_lock(bh_mutex_t *mutex)
{
if (!TryEnterCriticalSection(&mutex->handle))
return -1;
return 0;
return BH_ERROR;
return BH_OK;
}
int bh_mutex_unlock(bh_mutex_t *mutex)
{
LeaveCriticalSection(&mutex->handle);
return 0;
return BH_OK;
}
int bh_semaphore_init(bh_semaphore_t *semaphore, int count)
{
/* Create semaphore with max value of 32767 (to match POSIX) */
semaphore->handle = CreateSemaphore(NULL, count, 0x7FFF, NULL);
if (!semaphore->handle)
return -1;
return BH_ERROR;
return 0;
return BH_OK;
}
void bh_semaphore_destroy(bh_semaphore_t *semaphore)
@@ -131,37 +146,38 @@ void bh_semaphore_destroy(bh_semaphore_t *semaphore)
int bh_semaphore_post(bh_semaphore_t *semaphore)
{
if (!ReleaseSemaphore(semaphore->handle, 1, NULL))
return -1;
return 0;
return BH_ERROR;
return BH_OK;
}
int bh_semaphore_wait(bh_semaphore_t *semaphore)
{
if (WaitForSingleObject(semaphore->handle, INFINITE))
return -1;
return 0;
return BH_ERROR;
return BH_OK;
}
int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
unsigned long timeout)
{
/* FIXME: Check if we timed out or errored out */
if (WaitForSingleObject(semaphore->handle, timeout))
return -1;
return 0;
return BH_TIMEOUT;
return BH_ERROR;
}
int bh_semaphore_try_wait(bh_semaphore_t *semaphore)
{
if (WaitForSingleObject(semaphore->handle, 0))
return -1;
return 0;
return BH_ERROR;
return BH_OK;
}
#if WINVER >= _WIN32_WINNT_VISTA
int bh_cond_init(bh_cond_t *cond)
{
InitializeConditionVariable(&cond->handle);
return 0;
return BH_OK;
}
void bh_cond_destroy(bh_cond_t *cond)
@@ -179,43 +195,46 @@ int bh_cond_wait_for(bh_cond_t *cond,
bh_mutex_t *mutex,
unsigned long timeout)
{
/* FIXME: Check if we timed out or errored out */
if (!SleepConditionVariableCS(&cond->handle, &mutex->handle, timeout))
return -1;
return 0;
return BH_TIMEOUT;
return BH_OK;
}
int bh_cond_signal(bh_cond_t *cond)
{
WakeConditionVariable(&cond->handle);
return 0;
return BH_OK;
}
int bh_cond_broadcast(bh_cond_t *cond)
{
WakeAllConditionVariable(&cond->handle);
return 0;
return BH_OK;
}
#else
/* Condition variable implementation based on BeOS article
* http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html
*
* Slow, but correct implementation of CVs.
*/
int bh_cond_init(bh_cond_t *cond)
{
if (bh_mutex_init(&cond->lock))
return -1;
return BH_ERROR;
if (bh_semaphore_init(&cond->wait, 0))
{
bh_mutex_destroy(&cond->lock);
return -1;
return BH_ERROR;
}
if (bh_semaphore_init(&cond->done, 0))
{
bh_semaphore_destroy(&cond->wait);
bh_mutex_destroy(&cond->lock);
return -1;
return BH_ERROR;
}
cond->waiting = 0;
cond->signals = 0;
@@ -302,7 +321,7 @@ int bh_cond_signal(bh_cond_t *cond)
else
bh_mutex_unlock(&cond->lock);
return 0;
return BH_OK;
}
int bh_cond_broadcast(bh_cond_t *cond)
@@ -326,7 +345,7 @@ int bh_cond_broadcast(bh_cond_t *cond)
else
bh_mutex_unlock(&cond->lock);
return 0;
return BH_OK;
}
#endif
@@ -386,7 +405,7 @@ int bh_thread_pool_init_base(bh_thread_pool_t *pool,
}
}
return 0;
return BH_OK;
queue_fail:
free(pool->threads);
@@ -401,7 +420,7 @@ task_fail:
bh_mutex_destroy(&pool->lock);
lock_fail:
return -1;
return BH_ERROR;
}
bh_thread_pool_t *bh_thread_pool_new_base(size_t size,
@@ -409,6 +428,7 @@ bh_thread_pool_t *bh_thread_pool_new_base(size_t size,
bh_thread_end_cb_t end)
{
bh_thread_pool_t *result;
result = malloc(sizeof(*result));
if (result && bh_thread_pool_init_base(result, size, begin, end))
{

View File

@@ -1,5 +1,5 @@
#ifndef BHLIB_UNIT_H
#define BHLIB_UNIT_H
#ifndef BH_UNIT_H
#define BH_UNIT_H
#include <stdio.h>
@@ -21,4 +21,4 @@ typedef int (*bh_unit_cb_t)(void);
void bh_unit_add(const char *name, bh_unit_cb_t func);
int bh_unit_run(void);
#endif /* BHLIB_UNIT_H */
#endif /* BH_UNIT_H */