Author: dcreager Date: Sun May 20 14:24:19 2012 New Revision: 1340735 URL: http://svn.apache.org/viewvc?rev=1340735&view=rev Log: AVRO-1092. C: Thread-safe versions of error handling code.
We now provide optional thread-safe versions of the error managing code on Unix. (Only on Unix for now, because we rely on pthread's thread-local storage API.) You can ask for thread-safe versions by defining the THREADSAFE cmake variable. Contributed by Pugachev Maxim; Windows compatibility added by Vivek Nadkarni. Modified: avro/trunk/CHANGES.txt avro/trunk/lang/c/CMakeLists.txt avro/trunk/lang/c/INSTALL avro/trunk/lang/c/README.maintaining_win32.txt avro/trunk/lang/c/src/CMakeLists.txt avro/trunk/lang/c/src/errors.c Modified: avro/trunk/CHANGES.txt URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1340735&r1=1340734&r2=1340735&view=diff ============================================================================== --- avro/trunk/CHANGES.txt (original) +++ avro/trunk/CHANGES.txt Sun May 20 14:24:19 2012 @@ -104,6 +104,9 @@ Avro 1.7.0 (unreleased) AVRO-1088. C: Performance tests for arrays and schema resolution. (Vivek Nadkarni via dcreager) + AVRO-1092. C: Error management code can be defined in a thread-safe + manner. (Pugachev Maxim and Vivek Nadkarni via dcreager) + Avro 1.6.3 (5 March 2012) AVRO-1077. Missing 'inline' for union set function. (thiru) Modified: avro/trunk/lang/c/CMakeLists.txt URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/CMakeLists.txt?rev=1340735&r1=1340734&r2=1340735&view=diff ============================================================================== --- avro/trunk/lang/c/CMakeLists.txt (original) +++ avro/trunk/lang/c/CMakeLists.txt Sun May 20 14:24:19 2012 @@ -106,6 +106,20 @@ endif(WIN32) # Uncomment to allow non-atomic increment/decrement of reference count # add_definitions(-DAVRO_ALLOW_NON_ATOMIC_REFCOUNT) +# Thread support (only for *nix with pthreads) +set(THREADS_LIBRARIES) +if(UNIX AND THREADSAFE AND CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_THREAD_PREFER_PTHREAD) + find_package(Threads) + + if(NOT CMAKE_USE_PTHREADS_INIT) + message(FATAL_ERROR "pthreads not found") + endif(NOT CMAKE_USE_PTHREADS_INIT) + + add_definitions(-DTHREADSAFE -D_REENTRANT) + set(THREADS_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) +endif(UNIX AND THREADSAFE AND CMAKE_COMPILER_IS_GNUCC) + include_directories(${AvroC_SOURCE_DIR}/src) include_directories(${AvroC_SOURCE_DIR}/jansson/src) Modified: avro/trunk/lang/c/INSTALL URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/INSTALL?rev=1340735&r1=1340734&r2=1340735&view=diff ============================================================================== --- avro/trunk/lang/c/INSTALL (original) +++ avro/trunk/lang/c/INSTALL Sun May 20 14:24:19 2012 @@ -55,3 +55,9 @@ like the following: to the cmake command given above. The set of architectures that you can choose from differs depending on which version of OS X you're running; common possibilities include "i386", "x86_64", "ppc", and "ppc64". + +On Unix, you can request thread-safe versions of the Avro library's +global functions by defining the THREADSAFE cmake variable. Just add +the following to your cmake invokation: + + -DTHREADSAFE=true Modified: avro/trunk/lang/c/README.maintaining_win32.txt URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/README.maintaining_win32.txt?rev=1340735&r1=1340734&r2=1340735&view=diff ============================================================================== --- avro/trunk/lang/c/README.maintaining_win32.txt (original) +++ avro/trunk/lang/c/README.maintaining_win32.txt Sun May 20 14:24:19 2012 @@ -152,3 +152,15 @@ Instructions for Maintenance changes in st.c and st.h -- which were converted to new-style function declarations. +19. Structures cannot be initialized using the .element notation for + Win32. For example if we have a struct test_t: + typedef struct + { + int a; + int b; + } test_t; + Then we can initialize the struct using the syntax: + test_t t1 = { 0, 0 }; + But we cannot use the syntax: + test_t t2 = { .a = 0, . b = 0 }; + because Win32 does not support it. Modified: avro/trunk/lang/c/src/CMakeLists.txt URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/src/CMakeLists.txt?rev=1340735&r1=1340734&r2=1340735&view=diff ============================================================================== --- avro/trunk/lang/c/src/CMakeLists.txt (original) +++ avro/trunk/lang/c/src/CMakeLists.txt Sun May 20 14:24:19 2012 @@ -102,13 +102,13 @@ source_group(Jansson FILES ${JANSSON_SRC string(REPLACE ":" "." LIBAVRO_DOT_VERSION ${LIBAVRO_VERSION}) add_library(avro-static STATIC ${AVRO_SRC} ${JANSSON_SRC}) -target_link_libraries(avro-static ${CODEC_LIBRARIES}) +target_link_libraries(avro-static ${CODEC_LIBRARIES} ${THREADS_LIBRARIES}) set_target_properties(avro-static PROPERTIES OUTPUT_NAME avro) if (NOT WIN32) # TODO: Create Windows DLLs. See http://www.cmake.org/Wiki/BuildingWinDLL add_library(avro-shared SHARED ${AVRO_SRC} ${JANSSON_SRC}) -target_link_libraries(avro-shared ${CODEC_LIBRARIES}) +target_link_libraries(avro-shared ${CODEC_LIBRARIES} ${THREADS_LIBRARIES}) set_target_properties(avro-shared PROPERTIES OUTPUT_NAME avro SOVERSION ${LIBAVRO_DOT_VERSION}) Modified: avro/trunk/lang/c/src/errors.c URL: http://svn.apache.org/viewvc/avro/trunk/lang/c/src/errors.c?rev=1340735&r1=1340734&r2=1340735&view=diff ============================================================================== --- avro/trunk/lang/c/src/errors.c (original) +++ avro/trunk/lang/c/src/errors.c Sun May 20 14:24:19 2012 @@ -18,9 +18,21 @@ #include <stdarg.h> #include <stdio.h> #include <string.h> +#include <stdlib.h> #include "avro/errors.h" +#if defined THREADSAFE && (defined __unix__ || defined __unix) +#include <pthread.h> +static pthread_key_t error_data_key; +static pthread_once_t error_data_key_once = PTHREAD_ONCE_INIT; + +static void make_error_data_key() +{ + pthread_key_create(&error_data_key, free); +} +#endif + /* 4K should be enough, right? */ #define AVRO_ERROR_SIZE 4096 @@ -31,11 +43,46 @@ * buffer, and then swaps them. */ -static char AVRO_ERROR1[AVRO_ERROR_SIZE] = {'\0'}; -static char AVRO_ERROR2[AVRO_ERROR_SIZE] = {'\0'}; +struct avro_error_data_t { + char AVRO_ERROR1[AVRO_ERROR_SIZE]; + char AVRO_ERROR2[AVRO_ERROR_SIZE]; + + char *AVRO_CURRENT_ERROR; + char *AVRO_OTHER_ERROR; +}; + -static char *AVRO_CURRENT_ERROR = AVRO_ERROR1; -static char *AVRO_OTHER_ERROR = AVRO_ERROR2; +static struct avro_error_data_t * +avro_get_error_data(void) +{ +#if defined THREADSAFE && (defined __unix__ || defined __unix) + pthread_once(&error_data_key_once, make_error_data_key); + + struct avro_error_data_t *ERROR_DATA = + (struct avro_error_data_t*) pthread_getspecific(error_data_key); + + if (!ERROR_DATA) { + ERROR_DATA = (struct avro_error_data_t*) malloc(sizeof(struct avro_error_data_t)); + pthread_setspecific(error_data_key, ERROR_DATA); + + ERROR_DATA->AVRO_ERROR1[0] = '\0'; + ERROR_DATA->AVRO_ERROR2[0] = '\0'; + ERROR_DATA->AVRO_CURRENT_ERROR = ERROR_DATA->AVRO_ERROR1; + ERROR_DATA->AVRO_OTHER_ERROR = ERROR_DATA->AVRO_ERROR2; + } + + return ERROR_DATA; +#else + static struct avro_error_data_t ERROR_DATA = { + /* .AVRO_ERROR1 = */ {'\0'}, + /* .AVRO_ERROR2 = */ {'\0'}, + /* .AVRO_CURRENT_ERROR = */ ERROR_DATA.AVRO_ERROR1, + /* .AVRO_OTHER_ERROR = */ ERROR_DATA.AVRO_ERROR2, + }; + + return &ERROR_DATA; +#endif +} void @@ -43,7 +90,7 @@ avro_set_error(const char *fmt, ...) { va_list args; va_start(args, fmt); - vsnprintf(AVRO_CURRENT_ERROR, AVRO_ERROR_SIZE, fmt, args); + vsnprintf(avro_get_error_data()->AVRO_CURRENT_ERROR, AVRO_ERROR_SIZE, fmt, args); va_end(args); //fprintf(stderr, "--- %s\n", AVRO_CURRENT_ERROR); } @@ -52,13 +99,15 @@ avro_set_error(const char *fmt, ...) void avro_prefix_error(const char *fmt, ...) { + struct avro_error_data_t *ERROR_DATA = avro_get_error_data(); + /* * First render the prefix into OTHER_ERROR. */ va_list args; va_start(args, fmt); - int bytes_written = vsnprintf(AVRO_OTHER_ERROR, AVRO_ERROR_SIZE, fmt, args); + int bytes_written = vsnprintf(ERROR_DATA->AVRO_OTHER_ERROR, AVRO_ERROR_SIZE, fmt, args); va_end(args); /* @@ -66,9 +115,9 @@ avro_prefix_error(const char *fmt, ...) */ if (bytes_written < AVRO_ERROR_SIZE) { - strncpy(&AVRO_OTHER_ERROR[bytes_written], AVRO_CURRENT_ERROR, + strncpy(&ERROR_DATA->AVRO_OTHER_ERROR[bytes_written], ERROR_DATA->AVRO_CURRENT_ERROR, AVRO_ERROR_SIZE - bytes_written); - AVRO_OTHER_ERROR[AVRO_ERROR_SIZE-1] = '\0'; + ERROR_DATA->AVRO_OTHER_ERROR[AVRO_ERROR_SIZE-1] = '\0'; } /* @@ -76,14 +125,14 @@ avro_prefix_error(const char *fmt, ...) */ char *tmp; - tmp = AVRO_OTHER_ERROR; - AVRO_OTHER_ERROR = AVRO_CURRENT_ERROR; - AVRO_CURRENT_ERROR = tmp; + tmp = ERROR_DATA->AVRO_OTHER_ERROR; + ERROR_DATA->AVRO_OTHER_ERROR = ERROR_DATA->AVRO_CURRENT_ERROR; + ERROR_DATA->AVRO_CURRENT_ERROR = tmp; //fprintf(stderr, "+++ %s\n", AVRO_CURRENT_ERROR); } const char *avro_strerror(void) { - return AVRO_CURRENT_ERROR; + return avro_get_error_data()->AVRO_CURRENT_ERROR; }