Commit a1d34bc0 by Shawn O. Pearce

Support building on Mac OS X by using pthread_getspecific for TLS

The Mach-O format does not permit gcc to implement the __thread
TLS specification, so we must instead emulate it using a single
int cell allocated from memory and stored inside of the thread
specific data associated with the current pthread.

What makes this tricky is git_errno must be a valid lvalue, so
we really need to return a pointer to the caller and deference it
as part of the git_errno macro.

The GCC-specific __attribute__((constructor)) extension is used
to ensure the pthread_key_t is allocated before any Git functions
are executed in the library, as this is necessary to access our
thread specific storage.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
parent d7467949
......@@ -5,6 +5,9 @@
#include "util.h"
#include "errors.h"
#ifdef GIT_HAS_PTHREAD
# include <pthread.h>
#endif
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
......
#include "common.h"
#include "thread-utils.h" /* for GIT_TLS */
#if defined(GIT_TLS)
/* compile-time constant initialization required */
GIT_TLS int git_errno = 0;
#elif defined(GIT_HAS_PTHREAD)
static pthread_key_t errno_key;
static void init_errno(void) __attribute__((constructor));
static void init_errno(void)
{
pthread_key_create(&errno_key, free);
}
int *git__errno_storage(void)
{
int *e = pthread_getspecific(errno_key);
if (!e) {
e = calloc(1, sizeof(*e));
pthread_setspecific(errno_key, e);
}
return e;
}
#endif
static struct {
int num;
const char *str;
......
......@@ -13,8 +13,15 @@
GIT_BEGIN_DECL
/** The git errno. */
#if defined(GIT_TLS)
GIT_EXTERN(int) GIT_TLS git_errno;
#elif defined(GIT_HAS_PTHREAD)
# define git_errno (*git__errno_storage())
GIT_EXTERN(int *) git__errno_storage(void);
#endif
/**
* strerror() for the Git library
* @param num The error code to explain
......
......@@ -9,8 +9,15 @@
#define GIT_HAS_TLS 1
#if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || \
defined(__xlc__) || defined(__xlC__)
#if defined(__APPLE__) && defined(__MACH__)
# undef GIT_TLS
# define GIT_HAS_PTHREAD
#elif defined(__GNUC__) || \
defined(__SUNPRO_C) || \
defined(__SUNPRO_CC) || \
defined(__xlc__) || \
defined(__xlC__)
# define GIT_TLS __thread
#elif defined(__INTEL_COMPILER)
......@@ -20,7 +27,9 @@
# define GIT_TLS __thread
# endif
#elif defined(_WIN32) || defined(_WIN32_CE) || defined(__BORLANDC__)
#elif defined(_WIN32) || \
defined(_WIN32_CE) || \
defined(__BORLANDC__)
# define GIT_TLS __declspec(thread)
#else
......
#include "test_lib.h"
#include "errors.h"
#include <string.h>
BEGIN_TEST(errno_zero_on_init)
must_be_true(git_errno == 0);
END_TEST
BEGIN_TEST(set_ENOTOID)
must_be_true(GIT_ENOTOID != 0);
git_errno = GIT_ENOTOID;
must_be_true(git_errno == GIT_ENOTOID);
must_pass(strcmp(git_strerror(git_errno), "Not a git oid"));
END_TEST
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment