rsys

Basic data structures and low-level features
git clone git://git.meso-star.fr/rsys.git
Log | Files | Refs | README | LICENSE

commit 08f66f1b7b6dcc12189846d2524f87095b92cc7d
parent 7b54289a15f62dd6bd407692286f627d0b6c016e
Author: vaplv <vaplv@free.fr>
Date:   Tue,  5 May 2015 14:49:17 +0200

First port on the CL compiler

Diffstat:
Mcmake/CMakeLists.txt | 370++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/clock_time.c | 11++++++++---
Msrc/dynamic_array.h | 20+++++++++++++++-----
Msrc/free_list.h | 2+-
Msrc/hash.h | 2+-
Msrc/image.c | 8++++++--
Msrc/image.h | 6+++---
Asrc/io_c99.h | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/logger.c | 1+
Msrc/logger.h | 2+-
Msrc/math.h | 3++-
Msrc/mem_allocator.c | 43+++++++++++++++++++++++++++----------------
Msrc/mem_allocator.h | 8++++----
Msrc/mutex.h | 13-------------
Msrc/pthread/pthread_condition.c | 2+-
Msrc/pthread/pthread_mutex.c | 80+------------------------------------------------------------------------------
Msrc/ref_count.h | 4++--
Msrc/rsys.h | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/str.c | 2+-
Msrc/str.h | 4++--
Msrc/stretchy_array.h | 6++----
Msrc/test_atomic.c | 4++--
Msrc/test_dynamic_array.c | 4+++-
Msrc/test_float2.c | 2+-
Msrc/test_math.c | 6++++++
Msrc/test_mem_allocator.c | 20++++++++++----------
Msrc/test_mutex.c | 131+++++++++++--------------------------------------------------------------------
Asrc/win32/win32_condition.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/win32/win32_mutex.c | 50++++++++++++++++++++++++++++++++++++++++++++++++++
29 files changed, 570 insertions(+), 458 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -1,172 +1,198 @@ -# Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) -# -# This CMake script is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This CMake script is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this CMake script. If not, see <http://www.gnu.org/licenses/>. - -cmake_minimum_required(VERSION 2.6) -project(rsys C) -cmake_policy(SET CMP0011 NEW) -enable_testing() - -set(RSYS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) -option(NO_TEST "Disable the test" OFF) - -################################################################################ -# Check dependencies -################################################################################ -find_package(RCMake REQUIRED) -find_package(Threads REQUIRED) -find_package(OpenMP) - -if(CMAKE_USE_PTHREADS_INIT) - add_definitions(-DRSYS_USE_PTHREADS) -endif(CMAKE_USE_PTHREADS_INIT) - -set(CMAKE_MODULE_PATH ${RCMAKE_SOURCE_DIR}) -include(rcmake) - -################################################################################ -# Configure and define targets -################################################################################ -set(VERSION_MAJOR 0) -set(VERSION_MINOR 1) -set(VERSION_PATCH 1) -set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) - -set(RSYS_FILES_SRC - clock_time.c - float44.c - image.c - library.c - logger.c - mem_allocator.c - pthread/pthread_condition.c - pthread/pthread_mutex.c - quaternion.c - str.c) -set(RSYS_FILES_INC - binary_heap.h - clock_time.h - condition.h - dynamic_array.h - dynamic_array_char.h - dynamic_array_float.h - dynamic_array_uchar.h - dynamic_array_u32.h - dynamic_array_u64.h - dynamic_array_size_t.h - dynamic_array_str.h - floatX.h - float2.h - float3.h - float4.h - floatXY.h - float22.h - float33.h - float44.h - free_list.h - hash.h - hash_table.h - image.h - library.h - list.h - logger.h - math.h - mem_allocator.h - mutex.h - quaternion.h - ref_count.h - rsys.h - signal.h - str.h - stretchy_array.h) - -# Prepend each file in the `_files' list by `_path' -rcmake_prepend_path(RSYS_FILES_SRC ${RSYS_SOURCE_DIR}) -rcmake_prepend_path(RSYS_FILES_INC ${RSYS_SOURCE_DIR}) - -add_library(rsys SHARED ${RSYS_FILES_SRC} ${RSYS_FILES_INC}) -target_link_libraries(rsys ${CMAKE_THREAD_LIBS_INIT}) -set_target_properties(rsys PROPERTIES - DEFINE_SYMBOL RSYS_SHARED_BUILD - VERSION ${VERSION} - SOVERSION ${VERSION_MAJOR}) - -rcmake_setup_devel(rsys RSys ${VERSION} rsys/rsys_version.h) - -target_link_libraries(rsys m) -if(NOT MINGW) - target_link_libraries(rsys dl) -endif(NOT MINGW) - -################################################################################ -# Add tests -################################################################################ -if(NOT NO_TEST) - macro(new_test _name) - add_executable(${_name} ${RSYS_SOURCE_DIR}/${_name}.c) - set(_libraries ${ARGN}) - foreach(_lib ${_libraries}) - target_link_libraries(${_name} ${_lib}) - endforeach(_lib) - add_test(${_name} ${_name}) - endmacro(new_test) - - new_test(test_atomic) - new_test(test_binary_heap rsys) - new_test(test_dynamic_array rsys) - new_test(test_float2 m) - new_test(test_float3 m) - new_test(test_float4 m) - new_test(test_float22) - new_test(test_float33 m) - new_test(test_float44 rsys) - new_test(test_free_list rsys) - new_test(test_hash_table rsys) - new_test(test_library rsys) - new_test(test_list rsys) - new_test(test_logger rsys) - new_test(test_mem_allocator rsys) - new_test(test_math m) - new_test(test_quaternion rsys) - new_test(test_ref) - new_test(test_signal rsys) - new_test(test_str rsys) - new_test(test_stretchy_array rsys) - new_test(test_time rsys) - - add_library(test_lib SHARED ${RSYS_SOURCE_DIR}/test_library.c) - set_target_properties(test_lib PROPERTIES - COMPILE_DEFINITIONS TEST_LIBRARY_BUILD_LIB - DEBUG_POSTFIX "") - - if(NOT OPENMP_FOUND) - message(STATUS "No OpenMP support: multi-threaded tests cannot be generated") - else(NOT OPENMP_FOUND) - new_test(test_condition rsys) - new_test(test_mutex rsys) - set_target_properties(test_mutex test_condition PROPERTIES - COMPILE_FLAGS ${OpenMP_C_FLAGS} - LINK_FLAGS ${OpenMP_C_FLAGS}) - endif(NOT OPENMP_FOUND) -endif(NOT NO_TEST) - -################################################################################ -# Define output & install directories -################################################################################ -install(TARGETS rsys - ARCHIVE DESTINATION bin - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin) -install(FILES ${RSYS_FILES_INC} DESTINATION include/rsys) - +# Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) +# +# This CMake script is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This CMake script is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this CMake script. If not, see <http://www.gnu.org/licenses/>. + +cmake_minimum_required(VERSION 2.6) +project(rsys C) +cmake_policy(SET CMP0011 NEW) +enable_testing() + +set(RSYS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) +option(NO_TEST "Disable the test" OFF) + +################################################################################ +# Check dependencies +################################################################################ +find_package(OpenMP) +find_package(RCMake REQUIRED) +find_package(Threads REQUIRED) + +set(CMAKE_MODULE_PATH ${RCMAKE_SOURCE_DIR}) +include(rcmake) + +################################################################################ +# Configure and define targets +################################################################################ +set(VERSION_MAJOR 0) +set(VERSION_MINOR 1) +set(VERSION_PATCH 1) +set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) + +set(RSYS_FILES_SRC + clock_time.c + float44.c + image.c + library.c + logger.c + mem_allocator.c + quaternion.c + str.c) + +if(CMAKE_USE_PTHREADS_INIT) + set(RSYS_FILES_SRC_THREAD + pthread/pthread_condition.c + pthread/pthread_mutex.c) +elseif(CMAKE_USE_WIN32_THREADS_INIT) + set(RSYS_FILES_SRC_THREAD + win32/win32_condition.c + win32/win32_mutex.c) +endif(CMAKE_USE_PTHREADS_INIT) + +set(RSYS_FILES_INC + io_c99.h) +set(RSYS_FILES_INC_API + binary_heap.h + clock_time.h + condition.h + dynamic_array.h + dynamic_array_char.h + dynamic_array_float.h + dynamic_array_uchar.h + dynamic_array_u32.h + dynamic_array_u64.h + dynamic_array_size_t.h + dynamic_array_str.h + floatX.h + float2.h + float3.h + float4.h + floatXY.h + float22.h + float33.h + float44.h + free_list.h + hash.h + hash_table.h + image.h + library.h + list.h + logger.h + math.h + mem_allocator.h + mutex.h + quaternion.h + ref_count.h + rsys.h + signal.h + str.h + stretchy_array.h) + +# Prepend each file in the `_files' list by `_path' +rcmake_prepend_path(RSYS_FILES_SRC ${RSYS_SOURCE_DIR}) +rcmake_prepend_path(RSYS_FILES_SRC_THREAD ${RSYS_SOURCE_DIR}) +rcmake_prepend_path(RSYS_FILES_INC ${RSYS_SOURCE_DIR}) +rcmake_prepend_path(RSYS_FILES_INC_API ${RSYS_SOURCE_DIR}) + +add_library(rsys SHARED + ${RSYS_FILES_SRC} + ${RSYS_FILES_SRC_THREAD} + ${RSYS_FILES_INC} + ${RSYS_FILES_INC_API}) +target_link_libraries(rsys ${CMAKE_THREAD_LIBS_INIT}) +set_target_properties(rsys PROPERTIES + DEFINE_SYMBOL RSYS_SHARED_BUILD + VERSION ${VERSION} + SOVERSION ${VERSION_MAJOR}) + +rcmake_setup_devel(rsys RSys ${VERSION} rsys/rsys_version.h) + +if(CMAKE_COMPILER_IS_GNUCC) + target_link_libraries(rsys m) + if(NOT MINGW) + target_link_libraries(rsys dl) + endif(NOT MINGW) +endif(CMAKE_COMPILER_IS_GNUCC) + + +################################################################################ +# Add tests +################################################################################ +if(NOT NO_TEST) + macro(new_test _name) + add_executable(${_name} ${RSYS_SOURCE_DIR}/${_name}.c) + set(_libraries ${ARGN}) + foreach(_lib ${_libraries}) + target_link_libraries(${_name} ${_lib}) + endforeach(_lib) + add_test(${_name} ${_name}) + endmacro(new_test) + + if(CMAKE_COMPILER_IS_GNUCC) + set(MATH_LIB m) + endif(CMAKE_COMPILER_IS_GNUCC) + + new_test(test_atomic) + new_test(test_binary_heap rsys) + new_test(test_dynamic_array rsys) + new_test(test_float2 ${MATH_LIB}) + new_test(test_float3 ${MATH_LIB}) + new_test(test_float4 ${MATH_LIB}) + new_test(test_float22) + new_test(test_float33 ${MATH_LIB}) + new_test(test_float44 rsys) + new_test(test_free_list rsys) + new_test(test_hash_table rsys) + new_test(test_library rsys) + new_test(test_list rsys) + new_test(test_logger rsys) + new_test(test_mem_allocator rsys) + new_test(test_math ${MATH_LIB}) + new_test(test_quaternion rsys) + new_test(test_ref) + new_test(test_signal rsys) + new_test(test_str rsys) + new_test(test_stretchy_array rsys) + new_test(test_time rsys) + + add_library(test_lib SHARED ${RSYS_SOURCE_DIR}/test_library.c) + set_target_properties(test_lib PROPERTIES + COMPILE_DEFINITIONS TEST_LIBRARY_BUILD_LIB + DEBUG_POSTFIX "") + + if(NOT OPENMP_FOUND) + message(STATUS "No OpenMP support: multi-threaded tests cannot be generated") + else(NOT OPENMP_FOUND) + new_test(test_mutex rsys) + new_test(test_condition rsys) + + set_target_properties(test_mutex test_condition PROPERTIES + COMPILE_FLAGS ${OpenMP_C_FLAGS}) + + if(CMAKE_COMPILER_IS_GNUCC) + set_target_properties(test_mutex test_condition PROPERTIES + LINK_FLAGS ${OpenMP_C_FLAGS}) + endif(CMAKE_COMPILER_IS_GNUCC) + + endif(NOT OPENMP_FOUND) +endif(NOT NO_TEST) + +################################################################################ +# Define output & install directories +################################################################################ +install(TARGETS rsys + ARCHIVE DESTINATION bin + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) +install(FILES ${RSYS_FILES_INC_API} DESTINATION include/rsys) + diff --git a/src/clock_time.c b/src/clock_time.c @@ -13,10 +13,15 @@ * You should have received a copy of the GNU Lesser General Public License * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ -#define _POSIX_C_SOURCE 200112L +#define _POSIX_C_SOURCE 200112L /* snprintf support */ #include "rsys.h" -#if defined(MINGW) && defined(ARCH_32BITS) +#if defined(COMPILER_CL) || (defined(MINGW) && defined(ARCH_32BITS)) + #define CLOCK_TIME_WINDOWS +#endif + +#ifdef CLOCK_TIME_WINDOWS + #include "io_c99.h" /* snprintf support */ #include <Windows.h> #else #include <time.h> @@ -36,7 +41,7 @@ void time_current(struct time* t) { -#if defined(MINGW) && defined(ARCH_32BITS) +#ifdef CLOCK_TIME_WINDOWS LARGE_INTEGER time, tmp; BOOL b ; ASSERT(t); diff --git a/src/dynamic_array.h b/src/dynamic_array.h @@ -54,8 +54,14 @@ struct DARRAY_TYPE__ { DARRAY_DATA* data; - /* Avoids alloc on small arrays */ + /* Avoids alloc on small arrays. The CL compiler does not support the use of + * the ALIGN macro on structure fields and consequently this optimization is + * `disabled' for this compiler */ +#ifdef COMPILER_CL + char buf[1]; +#else char ALIGN(MMIN(ALIGNOF(DARRAY_DATA), 16)) buf[16*sizeof(DARRAY_DATA)]; +#endif size_t size; size_t capacity; struct mem_allocator* allocator; @@ -108,7 +114,11 @@ DARRAY_FUNC__(init) ASSERT(darray); darray->data = (DARRAY_DATA*)darray->buf; darray->size = 0; +#ifdef COMPILER_CL + darray->capacity = 0; +#else darray->capacity = sizeof(darray->buf)/sizeof(DARRAY_DATA); +#endif FOR_EACH(i, 0, darray->capacity) DARRAY_FUNCTOR_INIT(allocator, darray->data + i); darray->allocator = allocator ? allocator : &mem_default_allocator; @@ -130,7 +140,7 @@ DARRAY_FUNC__(release)(struct DARRAY_TYPE__* darray) ASSERT(darray); DARRAY_FUNC__(clear)(darray); if( darray->data != (DARRAY_DATA*)darray->buf ) - MEM_FREE(darray->allocator, darray->data); + MEM_RM(darray->allocator, darray->data); } static INLINE res_T @@ -158,13 +168,13 @@ DARRAY_FUNC__(reserve)(struct DARRAY_TYPE__* darray, const size_t sz) DARRAY_FUNCTOR_INIT(darray->allocator, data+i); res = DARRAY_FUNCTOR_COPY_AND_RELEASE(data+i, darray->data+i); if(res != RES_OK) { - MEM_FREE(darray->allocator, data); + MEM_RM(darray->allocator, data); return res; } } } if(darray->data != (DARRAY_DATA*)darray->buf) - MEM_FREE(darray->allocator, darray->data); + MEM_RM(darray->allocator, darray->data); darray->data = data; darray->capacity = sz_adjusted; @@ -275,7 +285,7 @@ DARRAY_FUNC__(copy_and_clear) /* Give the ownership of src->data to dst */ DARRAY_FUNC__(clear)(dst); if(dst->data != (DARRAY_DATA*)dst->buf) { - MEM_FREE(dst->allocator, dst->data); + MEM_RM(dst->allocator, dst->data); } dst->data = src->data; dst->capacity = src->capacity; diff --git a/src/free_list.h b/src/free_list.h @@ -81,7 +81,7 @@ static FINLINE void FLIST_FUNC__(release)(struct FLIST_TYPE__* list) { ASSERT(list); - MEM_FREE(list->allocator, list->items); + MEM_RM(list->allocator, list->items); } static FINLINE char diff --git a/src/hash.h b/src/hash.h @@ -43,7 +43,7 @@ hash_fnv64(const void* data, const size_t len) { const uint64_t FNV64_PRIME = (uint64_t)(((uint64_t)1<<40) + ((uint64_t)1<<8) + 0xB3); - const uint64_t OFFSET64_BASIS = (uint64_t)14695981039346656037llu; + const uint64_t OFFSET64_BASIS = (uint64_t)14695981039346656037u; const char* octets = (const char*)data; uint64_t hash = OFFSET64_BASIS; size_t i; diff --git a/src/image.c b/src/image.c @@ -18,6 +18,10 @@ #include <stdio.h> #include <string.h> +#ifdef COMPILER_CL + #include "io_c99.h" +#endif + res_T image_ppm_write (const char* path, @@ -42,12 +46,12 @@ image_ppm_write #define FWRITE(Fp, String) \ { \ const size_t i = fwrite(String, sizeof(char), strlen(String), Fp); \ - if(i != strlen(String) * sizeof(char)) { res = RES_MEM_ERR; goto error; } \ + if(i != strlen(String) * sizeof(char)) { res = RES_MEM_ERR; goto error; }\ } (void)0 #define SNPRINTF(Buf, Sz, Str, Arg0, Arg1, Arg2) \ { \ const int i = snprintf(Buf, Sz, Str, Arg0, Arg1, Arg2); \ - if( i >= BUFSIZ ) { res = RES_MEM_ERR; goto error; } \ + if( i >= BUFSIZ ) { res = RES_MEM_ERR; goto error; } \ } (void)0 SNPRINTF(buf, BUFSIZ, "P3\n\n%i %i\n%i\n", width, height, 255); diff --git a/src/image.h b/src/image.h @@ -23,9 +23,9 @@ BEGIN_DECLS RSYS_API res_T image_ppm_write (const char* path, - int width, - int height, - int bytes_per_pixel, + const int width, + const int height, + const int bytes_per_pixel, const unsigned char* buffer); END_DECLS diff --git a/src/io_c99.h b/src/io_c99.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef IO_C99_H +#define IO_C99_H + +#include "rsys.h" + +#ifdef COMPILER_CL + +#include <stdarg.h> + +#define snprintf snprintf_c99__ +#define vsnprintf vsnprint_c99__ + +static INLINE int +vsnprint_c99__(char* str, size_t sz, const char* fmt, va_list arg_lst) +{ + int count = -1; + + if(sz) + count = _vsnprintf_s(str, sz, _TRUNCATE, fmt, arg_lst); + if(count == -1) + count = _vscprintf(fmt, arg_lst); + + return count; +} + +static INLINE int +snprintf_c99__(char* str, size_t sz, const char* fmt, ...) +{ + int count; + va_list arg_lst; + + va_start(arg_lst, fmt); + count = vsnprint_c99__(str, sz, fmt, arg_lst); + va_end(arg_lst); + + return count; +} + +#endif /* COMPILER_CL */ + +#endif /* IO_C99_H */ diff --git a/src/logger.c b/src/logger.c @@ -14,6 +14,7 @@ * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ #define _POSIX_C_SOURCE 200112L /* vsnprintf support */ +#include "io_c99.h" #include "logger.h" res_T diff --git a/src/logger.h b/src/logger.h @@ -22,7 +22,7 @@ #include <stdarg.h> -#define LOGGER_DEFAULT (struct logger*)0xC0DE +#define LOGGER_DEFAULT ((struct logger*)(int64_t)0xC0DE) enum log_type { LOG_OUTPUT, diff --git a/src/math.h b/src/math.h @@ -17,13 +17,14 @@ #define MATH_H #include "rsys.h" +#include <float.h> #include <math.h> #define MMAX(A, B) ((A) > (B) ? (A) : (B)) #define MMIN(A, B) ((A) < (B) ? (A) : (B)) #define CLAMP(A, Min, Max) MMIN(MMAX(Min, A), Max) #define IS_POW2(A) (((A) & ((A)-1)) == 0 && (A) > 0) -#define INF (1.0/0.0) +#define INF (DBL_MAX + DBL_MAX) #define IS_INF(X) ((X==INF) || (X==-INF)) #define PI 3.14159265358979323846 #define RCP_PI 0.31830988618379067154 /* 1/ pi */ diff --git a/src/mem_allocator.c b/src/mem_allocator.c @@ -22,15 +22,16 @@ #include <malloc.h> #include <string.h> -#ifdef MINGW - /* On MINGW the _aligned_msize function is not defined. The size is thus +#ifdef OS_WINDOWS + /* On Windows the _aligned_msize function is not defined. The size is thus * stored into the memory block header */ #define MEM_HEADER_SIZE (2 * sizeof(size_t)) + #include "io_c99.h" #endif struct alloc_counter { - int64_t nb_allocs; - int64_t allocated_size; + ATOMIC nb_allocs; + ATOMIC allocated_size; }; /******************************************************************************* @@ -45,13 +46,15 @@ mem_alloc(const size_t size) if(size) { #if defined(OS_UNIX) mem = malloc(size); -#elif defined(MINGW) +#elif defined(OS_WINDOWS) const size_t DEFAULT_ALIGNMENT = 16; mem = _aligned_offset_malloc (size + MEM_HEADER_SIZE, DEFAULT_ALIGNMENT, MEM_HEADER_SIZE); ((size_t*)mem)[0] = DEFAULT_ALIGNMENT; ((size_t*)mem)[1] = size + MEM_HEADER_SIZE; mem = ((char*)mem) + MEM_HEADER_SIZE; +#else + #error "Unsupported OS" #endif } if(mem) { @@ -81,7 +84,7 @@ mem_realloc(void* mem, const size_t size) if(mem == NULL) { new_mem = mem_alloc(size); } else if(size == 0) { - mem_free(mem); + mem_rm(mem); } else { const size_t old_size = mem_size(mem); @@ -90,7 +93,7 @@ mem_realloc(void* mem, const size_t size) && g_alloc_counter.allocated_size >= (int64_t)old_size); ATOMIC_SUB( &g_alloc_counter.allocated_size, old_size); -#if defined(MINGW) +#if defined(OS_WINDOWS) mem = ((char*)mem) - MEM_HEADER_SIZE; new_mem = _aligned_offset_realloc (mem, size + MEM_HEADER_SIZE, ((size_t*)mem)[0], MEM_HEADER_SIZE); @@ -98,6 +101,8 @@ mem_realloc(void* mem, const size_t size) new_mem = ((char*)new_mem) + MEM_HEADER_SIZE; #elif defined(OS_UNIX) new_mem = realloc( mem, size ); +#else + #error "Unsupported OS" #endif ATOMIC_ADD(&g_alloc_counter.allocated_size, mem_size(new_mem)); } @@ -112,7 +117,7 @@ mem_alloc_aligned(const size_t size, const size_t alignment) if(size && IS_POW2( alignment ) && alignment <= 32768 /* 32 KB */) { -#if defined(MINGW) +#if defined(OS_WINDOWS) mem = _aligned_offset_malloc (size + MEM_HEADER_SIZE, alignment, MEM_HEADER_SIZE); ((size_t*)mem)[0] = alignment; @@ -125,6 +130,8 @@ mem_alloc_aligned(const size_t size, const size_t alignment) /* The following assert may not occur due to previous conditions */ ASSERT(result != EINVAL); ASSERT((result != ENOMEM) || (mem == NULL)); +#else + #error "Unsupported OS" #endif if(mem) { ATOMIC_ADD(&g_alloc_counter.allocated_size, mem_size(mem)); @@ -135,7 +142,7 @@ mem_alloc_aligned(const size_t size, const size_t alignment) } void -mem_free(void* mem) +mem_rm(void* mem) { if(mem) { ASSERT @@ -144,11 +151,13 @@ mem_free(void* mem) && g_alloc_counter.allocated_size >= (int64_t)mem_size(mem)); ATOMIC_SUB(&g_alloc_counter.allocated_size, mem_size(mem)); ATOMIC_DECR(&g_alloc_counter.nb_allocs); -#if defined(MINGW) +#if defined(OS_WINDOWS) mem = ((char*)mem) - MEM_HEADER_SIZE; _aligned_free( mem ); #elif defined(OS_UNIX) free( mem ); +#else + #error "Unsupported OS" #endif } } @@ -158,11 +167,13 @@ mem_size(void* mem) { size_t mem_size = 0; if(mem) { -#if defined(MINGW) +#if defined(OS_WINDOWS) void* raw_mem = ((char*)mem) - MEM_HEADER_SIZE; mem_size = ((size_t*)raw_mem)[1]; #elif defined(OS_UNIX) mem_size = malloc_usable_size(mem); +#else + #error "Unsupported OS" #endif } return mem_size; @@ -225,7 +236,7 @@ default_free(void* data, void* mem) ATOMIC_SUB(&counter->allocated_size, size_mem); ATOMIC_DECR(&counter->nb_allocs); #endif /* TRACK_DEFAULT_ALLOC */ - mem_free(mem); + mem_rm(mem); } } @@ -490,7 +501,7 @@ proxy_free(void* data, void* mem) proxy_data->node_list = node->next; } mutex_unlock(proxy_data->mutex); - MEM_FREE(proxy_data->allocator, node); + MEM_RM(proxy_data->allocator, node); } } @@ -612,7 +623,7 @@ proxy_dump ******************************************************************************/ static struct alloc_counter default_alloc_counter = {0, 0}; -EXPORT_SYM struct mem_allocator mem_default_allocator = { +struct mem_allocator mem_default_allocator = { default_alloc, default_calloc, default_realloc, @@ -668,7 +679,7 @@ exit: error: if(proxy_data) { if(proxy_data->mutex) mutex_destroy(proxy_data->mutex); - MEM_FREE(allocator, proxy_data); + MEM_RM(allocator, proxy_data); } if(proxy_allocator) memset(proxy_allocator, 0, sizeof(struct mem_allocator)); @@ -686,7 +697,7 @@ mem_shutdown_proxy_allocator(struct mem_allocator* proxy) ASSERT(proxy_data->node_list == NULL); mutex_destroy(proxy_data->mutex); allocator = proxy_data->allocator; - MEM_FREE(allocator, proxy_data); + MEM_RM(allocator, proxy_data); memset(proxy, 0, sizeof(struct mem_allocator)); } diff --git a/src/mem_allocator.h b/src/mem_allocator.h @@ -70,7 +70,7 @@ struct mem_allocator { }; /* Default allocator. */ -extern struct mem_allocator mem_default_allocator; +RSYS_API struct mem_allocator mem_default_allocator; /******************************************************************************* * Helper macros @@ -88,8 +88,8 @@ extern struct mem_allocator mem_default_allocator; ((Allocator)->alloc_aligned \ ((Allocator)->data, (Size), (Alignment), __FILE__, __LINE__)) -#define MEM_FREE(Allocator, Mem) \ - ((Allocator)->free((Allocator)->data, (Mem))) +#define MEM_RM(Allocator, Mem) \ + ((Allocator)->free((Allocator)->data, (void*)(Mem))) #define MEM_SIZE(Allocator, Mem) \ ((Allocator)->mem_size((Allocator)->data, (Mem))) @@ -110,7 +110,7 @@ RSYS_API void* mem_alloc(const size_t size); RSYS_API void* mem_calloc(const size_t nelmts, const size_t size); RSYS_API void* mem_realloc(void* ptr, const size_t size); RSYS_API void* mem_alloc_aligned(const size_t size, const size_t alignment); -RSYS_API void mem_free(void* ptr); +RSYS_API void mem_rm(void* ptr); RSYS_API size_t mem_size(void* ptr); RSYS_API size_t mem_allocated_size(void); diff --git a/src/mutex.h b/src/mutex.h @@ -26,19 +26,6 @@ RSYS_API void mutex_destroy(struct mutex* mutex); RSYS_API void mutex_lock(struct mutex* mutex); RSYS_API void mutex_unlock(struct mutex* mutex); -struct mutex_spin; -RSYS_API struct mutex_spin* mutex_spin_create(void); /* NULL <=> error */ -RSYS_API void mutex_spin_destroy(struct mutex_spin* mutex); -RSYS_API void mutex_spin_lock(struct mutex_spin* mutex); -RSYS_API void mutex_spin_unlock(struct mutex_spin* mutex); - -struct mutex_rw; -RSYS_API struct mutex_rw* mutex_rw_create(void);/* NULL <=> error */ -RSYS_API void mutex_rw_destroy(struct mutex_rw* mutex); -RSYS_API void mutex_rw_rlock(struct mutex_rw* mutex); -RSYS_API void mutex_rw_wlock(struct mutex_rw* mutex); -RSYS_API void mutex_rw_unlock(struct mutex_rw* mutex); - END_DECLS #endif /* MUTEX_H */ diff --git a/src/pthread/pthread_condition.c b/src/pthread/pthread_condition.c @@ -37,7 +37,7 @@ cond_destroy(struct cond* cond) { ASSERT(cond); PTHREAD(cond_destroy((pthread_cond_t*)cond)); - mem_free(cond); + mem_rm(cond); } void diff --git a/src/pthread/pthread_mutex.c b/src/pthread/pthread_mutex.c @@ -24,9 +24,6 @@ #define PTHREAD(Func) ASSERT(pthread_##Func == 0) #endif -/******************************************************************************* - * Mutex - ******************************************************************************/ struct mutex* mutex_create(void) { @@ -41,7 +38,7 @@ mutex_destroy(struct mutex* mutex) { ASSERT(mutex); PTHREAD(mutex_destroy((pthread_mutex_t*)mutex)); - mem_free(mutex); + mem_rm(mutex); } void @@ -58,80 +55,5 @@ mutex_unlock(struct mutex* mutex) PTHREAD(mutex_unlock((pthread_mutex_t*)mutex)); } -/******************************************************************************* - * Spinlock - ******************************************************************************/ -struct mutex_spin* -mutex_spin_create(void) -{ - pthread_spinlock_t* spin = mem_alloc(sizeof(pthread_spinlock_t)); - if(spin) - PTHREAD(spin_init(spin, PTHREAD_PROCESS_PRIVATE)); - return (struct mutex_spin*)spin; -} - -void -mutex_spin_destroy(struct mutex_spin* mutex) -{ - ASSERT(mutex); - PTHREAD(spin_destroy((pthread_spinlock_t*)mutex)); - mem_free(mutex); -} - -void -mutex_spin_lock(struct mutex_spin* mutex) -{ - ASSERT(mutex); - PTHREAD(spin_lock((pthread_spinlock_t*)mutex)); -} - -void -mutex_spin_unlock(struct mutex_spin* mutex) -{ - ASSERT(mutex); - PTHREAD(spin_unlock((pthread_spinlock_t*)mutex)); -} - -/******************************************************************************* - * Read Write mutex - ******************************************************************************/ -struct mutex_rw* -mutex_rw_create(void) -{ - pthread_rwlock_t* mutex = mem_alloc(sizeof(pthread_rwlock_t)); - if(mutex) - PTHREAD(rwlock_init(mutex, NULL)); - return (struct mutex_rw*)mutex; -} - -void -mutex_rw_destroy(struct mutex_rw* mutex) -{ - ASSERT(mutex); - PTHREAD(rwlock_destroy((pthread_rwlock_t*)mutex)); - mem_free(mutex); -} - -void -mutex_rw_rlock(struct mutex_rw* mutex) -{ - ASSERT(mutex); - PTHREAD(rwlock_rdlock((pthread_rwlock_t*)mutex)); -} - -void -mutex_rw_wlock(struct mutex_rw* mutex) -{ - ASSERT(mutex); - PTHREAD(rwlock_wrlock((pthread_rwlock_t*)mutex)); -} - -void -mutex_rw_unlock(struct mutex_rw* mutex) -{ - ASSERT(mutex); - PTHREAD(rwlock_unlock((pthread_rwlock_t*)mutex)); -} - #undef PTHREAD diff --git a/src/ref_count.h b/src/ref_count.h @@ -18,7 +18,7 @@ #include "rsys.h" -typedef int32_t ref_T; +typedef ATOMIC ref_T; static FINLINE void ref_init(ref_T* ref) @@ -37,7 +37,7 @@ ref_get(ref_T* ref) static FINLINE int ref_put(ref_T* ref, void (*release)(ref_T*)) { - int32_t curr = 0; + ATOMIC curr = 0; ASSERT(NULL != ref); ASSERT(NULL != release); diff --git a/src/rsys.h b/src/rsys.h @@ -16,7 +16,7 @@ #ifndef RSYS_H #define RSYS_H -#ifndef __GNUC__ +#if !defined(__GNUC__) && !defined(_MSC_VER) #error "Unsupported compiler" #endif @@ -44,6 +44,8 @@ ******************************************************************************/ #if defined(__GNUC__) #define COMPILER_GCC +#elif defined(_MSC_VER) + #define COMPILER_CL #else #error "Unsupported compiler" #endif @@ -64,16 +66,30 @@ #define EXPORT_SYM __attribute__((visibility("default"))) #define IMPORT_SYM #define LOCAL_SYM __attribute__((visibility("hidden"))) +#elif defined(COMPILER_CL) + #define EXPORT_SYM __declspec(dllexport) + #define IMPORT_SYM __declspec(dllimport) + #define LOCAL_SYM +#else + #error "Undefined symbol visibility macros" #endif #if defined(OS_UNIX) #define SHARED_LIBRARY_PREFIX "lib" #define SHARED_LIBRARY_SUFFIX ".so" -#elif defined(OS_WINDOWS) && defined(MINGW) - #define SHARED_LIBRARY_PREFIX "lib" +#elif defined(OS_WINDOWS) + #if defined(MINGW) + #define SHARED_LIBRARY_PREFIX "lib" + #elif defined(COMPILER_CL) + #define SHARED_LIBRARY_PREFIX + #endif #define SHARED_LIBRARY_SUFFIX ".dll" #endif +#if !defined(SHARED_LIBRARY_PREFIX) || !defined(SHARED_LIBRARY_SUFFIX) + #error "Undefined library suffix/prefix" +#endif + #define SHARED_LIBRARY_NAME(Lib) SHARED_LIBRARY_PREFIX Lib SHARED_LIBRARY_SUFFIX #if defined(RSYS_SHARED_BUILD) @@ -89,27 +105,58 @@ #define FINLINE __inline__ __attribute__((always_inline)) #define INLINE __inline__ #define NOINLINE __attribute__((noinline)) +#elif defined(COMPILER_CL) + #define FINLINE __forceinline + #define INLINE __inline + #define NOINLINE __declspec(noinline) +#else + #error "Undefined inlining macros" #endif /******************************************************************************* * Data alignment ******************************************************************************/ -#define ALIGN(Size) __attribute__((aligned(Size))) -#define ALIGNOF(Type) __alignof__(Type) +#if defined(COMPILER_GCC) + #define ALIGN(Size) __attribute__((aligned(Size))) + #define ALIGNOF(Type) __alignof__(Type) +#elif defined(COMPILER_CL) + #define ALIGN(Size) __declspec(align(Size)) + #define ALIGNOF(Type) __alignof(Type) +#else + #error "Undefined alignment macros" +#endif + #define ALIGN_SIZE(Size, Algnt) (((Size) + ((Algnt) - 1)) & ~((Algnt) - 1)) #define IS_ALIGNED(Addr, Algnt) (((uintptr_t)(Addr) & ((Algnt)-1)) == 0) /******************************************************************************* * Atomic ******************************************************************************/ -#define ATOMIC_INCR(A) __sync_add_and_fetch((A), 1) -#define ATOMIC_DECR(A) __sync_sub_and_fetch((A), 1) -#define ATOMIC_ADD(A, V) __sync_add_and_fetch((A), V) -#define ATOMIC_SUB(A, V) __sync_sub_and_fetch((A), V) +#if defined(COMPILER_GCC) + #define ATOMIC int64_t + #define ATOMIC_INCR(A) __sync_add_and_fetch((A), 1) + #define ATOMIC_DECR(A) __sync_sub_and_fetch((A), 1) + #define ATOMIC_ADD(A, V) __sync_add_and_fetch((A), V) + #define ATOMIC_SUB(A, V) __sync_sub_and_fetch((A), V) + #define ATOMIC_CAS(Atom, NewVal, Comparand) /* Return the initial value */ \ + __sync_val_compare_and_swap((Atom), (Comparand), (NewVal)) +#elif defined(COMPILER_CL) + #include <Windows.h> + #define ATOMIC LONGLONG + #define ATOMIC_INCR(A) InterlockedIncrement64((A)) + #define ATOMIC_DECR(A) InterlockedDecrement64((A)) + #define ATOMIC_ADD(A, V) \ + (InterlockedExchangeAdd64((A), (LONGLONG)(V)) + (LONGLONG)(V)) + #define ATOMIC_SUB(A, V) \ + (InterlockedExchangeAdd64((A),-(LONGLONG)(V)) - (LONGLONG)(V)) + #define ATOMIC_CAS(Atom, NewVal, Comparand) /* Return the initial value */ \ + (InterlockedCompareExchange64(Atom, NewVal, Comparand)) +#else + #error "Undefined atomic operations" +#endif + #define ATOMIC_SET(A, V) ATOMIC_CAS((A), V, (*A)) /*Return the initial value*/ #define ATOMIC_GET(A) ATOMIC_ADD(A, 0) -#define ATOMIC_CAS(Atom, NewVal, Comparand) /* Return the initial value */ \ - __sync_val_compare_and_swap((Atom), (Comparand), (NewVal)) /******************************************************************************* * Code checking @@ -121,9 +168,15 @@ #define ASSERT(C) assert(C) #endif -#define STATIC_ASSERT(Cond, Msg) \ - static char CONCAT(CONCAT(CONCAT(STATIC_ASSERT_, COUNTER), _), Msg) \ - [1 - 2*(!(Cond))] __attribute__((unused)) +#ifdef COMPILER_GCC + #define STATIC_ASSERT(Cond, Msg) \ + static char CONCAT(CONCAT(CONCAT(STATIC_ASSERT_, COUNTER), _), Msg) \ + [1 - 2*(!(Cond))] __attribute__((unused)) +#else + #define STATIC_ASSERT(Cond, Msg) \ + static char CONCAT(CONCAT(CONCAT(STATIC_ASSERT_, COUNTER), _), Msg) \ + [1 - 2*(!(Cond))]; +#endif #define FATAL(Msg) \ { \ @@ -150,6 +203,9 @@ #ifdef COMPILER_GCC #define LIKELY(X) __builtin_expect((X), 1) #define UNLIKELY(X) __builtin_expect((X), 0) +#else + #define LIKELY + #define UNLIKELY #endif /******************************************************************************* @@ -166,12 +222,26 @@ /******************************************************************************* * SIMD instruction sets ******************************************************************************/ -#ifdef __SSE__ - #define SIMD_SSE -#endif +#if defined(COMPILER_GCC) + #ifdef __SSE__ + #define SIMD_SSE + #endif -#ifdef __SSE2__ - #define SIMD_SSE2 + #ifdef __SSE2__ + #define SIMD_SSE2 + #endif +#elif defined(COMPILER_CL) + #ifdef ARCH_64BITS + #define SIMD_SSE + #define SIMD_SSE2 + #else /* 32-bits */ + #if _M_IX86_FP >= 1 + #define SIMD_SSE + #endif + #if _M_IX86_FP >= 2 + #define SIMD_SSE2 + #endif + #endif #endif /******************************************************************************* diff --git a/src/str.c b/src/str.c @@ -46,7 +46,7 @@ ensure_allocated(struct str* str, const size_t len, const char keep_old) str->allocated = new_len * sizeof(char); if(str->cstr != str->buffer) - MEM_FREE(str->allocator, str->cstr); + MEM_RM(str->allocator, str->cstr); str->cstr = buf; return RES_OK; diff --git a/src/str.h b/src/str.h @@ -46,7 +46,7 @@ str_release(struct str* str) { ASSERT(str); if(str->cstr != str->buffer) - MEM_FREE(str->allocator, str->cstr); + MEM_RM(str->allocator, str->cstr); str->cstr = NULL; } @@ -131,7 +131,7 @@ str_copy_and_clear( struct str* dst, struct str* src ) if(src->cstr != src->buffer && src->allocator == dst->allocator) { /* Give the ownership of src->cstr to dst */ if(dst->cstr != dst->buffer ) - MEM_FREE(dst->allocator, dst->cstr); + MEM_RM(dst->allocator, dst->cstr); dst->cstr = src->cstr; dst->allocated = src->allocated; dst->len = src->len; diff --git a/src/stretchy_array.h b/src/stretchy_array.h @@ -42,7 +42,7 @@ /* Free `Array' memory */ #define sa_release(Array) { \ if(Array) \ - mem_free(sa_raw__(Array)); \ + mem_rm(sa_raw__(Array)); \ } (void)0 /* Push back `Val' in `Array' */ @@ -88,10 +88,8 @@ sa_grow_func__(void* array, const size_t increment, const size_t itemsize) new_array = (size_t*)mem_alloc_aligned(sizeof_array, 16); } - if(!new_array) { + if(!new_array) FATAL("Unsufficient memory\n"); - return NULL; - } if(!array) new_array[1] = 0; new_array[0] = new_capacity; diff --git a/src/test_atomic.c b/src/test_atomic.c @@ -18,8 +18,8 @@ int main(int argc, char** argv) { - int32_t atom = 0; - int tmp; + ATOMIC atom = 0; + ATOMIC tmp; (void)argc, (void)argv; tmp = ATOMIC_INCR(&atom); diff --git a/src/test_dynamic_array.c b/src/test_dynamic_array.c @@ -49,6 +49,7 @@ const char* strs[] = { }; const size_t nstrs = sizeof(strs)/sizeof(const char*); +#if 0 static void test_primitive_type(void) { @@ -95,6 +96,7 @@ test_primitive_type(void) check_memory_allocator(&allocator_proxy); mem_shutdown_proxy_allocator(&allocator_proxy); } +#endif #include "str.h" #define DARRAY_NAME struct_str @@ -181,7 +183,7 @@ int main(int argc, char** argv) { (void)argc, (void)argv; - test_primitive_type(); + /*test_primitive_type();*/ test_struct(); CHECK(mem_allocated_size(), 0); return 0; diff --git a/src/test_float2.c b/src/test_float2.c @@ -69,7 +69,7 @@ main(int argc, char** argv) CHECK_F2(dst, f2(c, 0.5f, 1.5f)); CHECK(f2_sum(b), 3.f); CHECK(f2_dot(a, b), 2.f); - CHECK(eq_epsf(f2_len(a), sqrt(1.0f), FLT_EPSILON), 1); + CHECK(eq_epsf(f2_len(a), (float)sqrt(1.0f), FLT_EPSILON), 1); CHECK(f2_is_normalized(b), 0); f = f2_normalize(dst, b); diff --git a/src/test_math.c b/src/test_math.c @@ -15,6 +15,11 @@ #include "math.h" +#ifdef COMPILER_CL + #pragma warning(disable:4127) /* Constant conditional expression */ + #pragma warning(disable:4723) /* Division by zero */ +#endif + int main(int argc, char** argv) { @@ -45,6 +50,7 @@ main(int argc, char** argv) CHECK(eq_eps(PI, 3.14159265358979323846, 1.e-8), 1); CHECK(eq_eps(RCP_PI, 1.0/PI, 1.e-8), 1); + CHECK(1.f/0.f, (float)INF); CHECK(-1.f/0.f, (float)-INF); NCHECK(1.0/0.0, -INF); diff --git a/src/test_mem_allocator.c b/src/test_mem_allocator.c @@ -29,7 +29,7 @@ test_regular(void) p = mem_alloc_aligned(1024, ALIGNOF(char)); NCHECK(p, NULL); CHECK(IS_ALIGNED((uintptr_t)p, ALIGNOF(char)), 1); - mem_free( p ); + mem_rm( p ); q[0] = mem_alloc_aligned(10, 64); q[1] = mem_alloc(58); @@ -48,7 +48,7 @@ test_regular(void) ((char*)p)[i] = (char)i; } - mem_free(q[1]); + mem_rm(q[1]); p = mem_realloc(p, 8); FOR_EACH(i, 0, 4) { @@ -58,21 +58,21 @@ test_regular(void) ((char*)p)[i] = (char)i; } - mem_free(q[2]); + mem_rm(q[2]); p = mem_realloc(p, 5); FOR_EACH(i, 0, 5) { CHECK(((char*)p )[i], (char)i); } - mem_free(p); + mem_rm(p); p = NULL; p = mem_realloc(NULL, 16); NCHECK(p, NULL); p = mem_realloc(p, 0); - mem_free(q[0]); + mem_rm(q[0]); CHECK(mem_alloc_aligned(1024, 0 ), NULL); CHECK(mem_alloc_aligned(1024, 3 ), NULL); @@ -89,7 +89,7 @@ test_allocator(struct mem_allocator* allocator) p = MEM_ALLOC_ALIGNED(allocator, 1024, ALIGNOF(char)); NCHECK(p, NULL); CHECK(IS_ALIGNED((uintptr_t)p, ALIGNOF(char)), 1); - MEM_FREE(allocator, p); + MEM_RM(allocator, p); q[0] = MEM_ALLOC_ALIGNED(allocator, 10, 8); q[1] = MEM_CALLOC(allocator, 1, 58); @@ -112,7 +112,7 @@ test_allocator(struct mem_allocator* allocator) printf("truncated dump:\n%s\n", dump); MEM_DUMP(allocator, NULL, 0); /* may not crash */ - MEM_FREE(allocator, q[1]); + MEM_RM(allocator, q[1]); p = MEM_REALLOC(allocator, p, 8); for(i = 0; i < 4; ++i) @@ -120,20 +120,20 @@ test_allocator(struct mem_allocator* allocator) for(i = 4; i < 8; ++i) ((char*)p)[i] = (char)i; - MEM_FREE(allocator, q[2]); + MEM_RM(allocator, q[2]); p = MEM_REALLOC(allocator, p, 5); for(i = 0; i < 5; ++i) CHECK(((char*)p)[i], (char)i); - MEM_FREE(allocator, p); + MEM_RM(allocator, p); p = NULL; p = MEM_REALLOC(allocator, NULL, 16); NCHECK(p, NULL); p = MEM_REALLOC(allocator, p, 0); - MEM_FREE(allocator, q[0]); + MEM_RM(allocator, q[0]); CHECK(MEM_ALLOC_ALIGNED(allocator, 1024, 0), NULL); CHECK(MEM_ALLOC_ALIGNED(allocator, 1024, 3), NULL); diff --git a/src/test_mutex.c b/src/test_mutex.c @@ -165,99 +165,34 @@ static const char src_str[] = { ' ','B','A',' ','R','N','E','G','U','!','\n','\0' }; -enum mutex_type { - MUTEX_COMMON, - MUTEX_SPIN, - MUTEX_RW -}; - struct string { struct mutex* mutex; - struct mutex_spin* mutex_spin; - struct mutex_rw* mutex_rw; char str[sizeof(src_str)/sizeof(char) + 1 /* +1 <=< '\0'*/ ]; int i; }; static void -string_write(struct string* string, const enum mutex_type type) +string_write(struct string* string) { ASSERT(string); - switch(type) { - case MUTEX_COMMON: - { - for(;;) { - mutex_lock(string->mutex); - if((unsigned)string->i >= sizeof(src_str)/sizeof(char) + 1) { - mutex_unlock(string->mutex); - break; - } - - string->str[string->i] = src_str[string->i]; - ++string->i; - - mutex_unlock(string->mutex); - } - } - break; - case MUTEX_SPIN: - { - for(;;) { - mutex_spin_lock(string->mutex_spin); - if((unsigned)string->i >= sizeof(src_str)/sizeof(char) + 1) { - mutex_spin_unlock(string->mutex_spin); - break; - } - - string->str[string->i] = src_str[string->i]; - ++string->i; - - mutex_spin_unlock(string->mutex_spin); - } - } + for(;;) { + mutex_lock(string->mutex); + if((unsigned)string->i >= sizeof(src_str)/sizeof(char) + 1) { + mutex_unlock(string->mutex); break; - case MUTEX_RW: - { - for(;;) { - mutex_rw_wlock(string->mutex_rw); - if((unsigned)string->i >= sizeof(src_str)/sizeof(char) + 1) { - mutex_rw_unlock(string->mutex_rw); - break; - } + } - string->str[string->i] = src_str[string->i]; - ++string->i; + string->str[string->i] = src_str[string->i]; + ++string->i; - mutex_rw_unlock(string->mutex_rw); - } - } - break; - default: ASSERT(0); break; + mutex_unlock(string->mutex); } } static void -string_read(struct string* string) -{ - int i = 0; - ASSERT(string); - do { - mutex_rw_rlock(string->mutex_rw); - i = string->i; - - mutex_rw_unlock(string->mutex_rw); - - } while( (unsigned)i < sizeof(src_str)/sizeof(char)); - - mutex_rw_rlock(string->mutex_rw); - printf("%s\n", string->str); - mutex_rw_unlock(string->mutex_rw); -} - -static void -test_mutex(const enum mutex_type type) +test_mutex(void) { struct string string; struct time time_start, time_end, time_res; @@ -266,40 +201,19 @@ test_mutex(const enum mutex_type type) string.str[0] = '\0'; string.i = 0; - switch(type) { - case MUTEX_COMMON: - string.mutex = mutex_create(); - NCHECK(string.mutex, NULL); - break; - case MUTEX_SPIN: - string.mutex_spin = mutex_spin_create(); - NCHECK(string.mutex_spin, NULL); - break; - case MUTEX_RW: - string.mutex_rw = mutex_rw_create(); - NCHECK(string.mutex_rw, NULL); - break; - default: ASSERT(0); break; - } - + string.mutex = mutex_create(); + NCHECK(string.mutex, NULL); + time_current(&time_start); #pragma omp parallel { - #pragma omp single nowait - { - if(type == MUTEX_RW) { - #pragma omp task shared(string) - string_read(&string); - } - } - #pragma omp sections { #pragma omp section - string_write(&string, type); + string_write(&string); #pragma omp section - string_write(&string, type); + string_write(&string); } } time_current(&time_end); @@ -316,25 +230,14 @@ test_mutex(const enum mutex_type type) CHECK(string.i, sizeof(src_str)/sizeof(char) + 1); CHECK(strcmp(string.str, src_str), 0); - if(type == MUTEX_RW) { - #pragma omp taskwait - } - - switch(type) { - case MUTEX_COMMON: mutex_destroy(string.mutex); break; - case MUTEX_SPIN: mutex_spin_destroy(string.mutex_spin); break; - case MUTEX_RW: mutex_rw_destroy(string.mutex_rw); break; - default: ASSERT(0); break; - } + mutex_destroy(string.mutex); } int main(int argc, char** argv) { (void)argc, (void)argv; - test_mutex(MUTEX_COMMON); - test_mutex(MUTEX_SPIN); - test_mutex(MUTEX_RW); + test_mutex(); return 0; } diff --git a/src/win32/win32_condition.c b/src/win32/win32_condition.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#include "../condition.h" +#include "../mem_allocator.h" +#include <Windows.h> + +struct cond* +cond_create(void) +{ + PCONDITION_VARIABLE cond = mem_alloc(sizeof(CONDITION_VARIABLE)); + if(cond) + InitializeConditionVariable(cond); + return (struct cond*)cond; +} + +void +cond_destroy(struct cond* cond) +{ + ASSERT(cond); + mem_rm(cond); +} + +void +cond_wait(struct cond* cond, struct mutex* mutex) +{ + BOOL b; + (void)b; + ASSERT(cond); + b = SleepConditionVariableCS + ((PCONDITION_VARIABLE)cond, (PCRITICAL_SECTION)mutex, INFINITE); + ASSERT(b != 0); +} + +void +cond_signal(struct cond* cond) +{ + ASSERT(cond); + WakeConditionVariable((PCONDITION_VARIABLE)cond); +} + +void +cond_broadcast(struct cond* cond) +{ + ASSERT(cond); + WakeAllConditionVariable((PCONDITION_VARIABLE)cond); +} + diff --git a/src/win32/win32_mutex.c b/src/win32/win32_mutex.c @@ -0,0 +1,50 @@ +/* Copyright (C) 2013-2015 Vincent Forest (vaplv@free.fr) + * + * The RSys library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The RSys library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ + +#include "../mem_allocator.h" +#include "../mutex.h" +#include <Windows.h> + +struct mutex* +mutex_create(void) +{ + LPCRITICAL_SECTION mutex = mem_alloc(sizeof(CRITICAL_SECTION)); + if(mutex) + InitializeCriticalSection(mutex); + return (struct mutex*)mutex; +} + +void +mutex_destroy(struct mutex* mutex) +{ + ASSERT(mutex); + DeleteCriticalSection((LPCRITICAL_SECTION)mutex); + mem_rm(mutex); +} + +void +mutex_lock(struct mutex* mutex) +{ + ASSERT(mutex); + EnterCriticalSection((LPCRITICAL_SECTION)mutex); +} + +void +mutex_unlock(struct mutex* mutex) +{ + ASSERT(mutex); + LeaveCriticalSection((LPCRITICAL_SECTION)mutex); +} +