mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-08 04:30:48 +00:00
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>
This commit is contained in:
parent
d746794980
commit
a1d34bc000
@ -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>
|
||||
|
23
src/errors.c
23
src/errors.c
@ -1,9 +1,32 @@
|
||||
#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
|
||||
|
14
tests/t0000-errno.c
Normal file
14
tests/t0000-errno.c
Normal file
@ -0,0 +1,14 @@
|
||||
#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
|
Loading…
Reference in New Issue
Block a user