Unverified Commit a5cb2cc9 by Edward Thomson Committed by GitHub

Merge pull request #5720 from libgit2/ethomson/tlsdata

Thread-local storage: a generic internal library (with no allocations)
parents 1adb8410 20ce17f0
......@@ -960,7 +960,7 @@ int git_attr_session__init(git_attr_session *session, git_repository *repo)
GIT_ASSERT_ARG(repo);
memset(session, 0, sizeof(*session));
session->key = git_atomic_inc(&repo->attr_session_key);
session->key = git_atomic32_inc(&repo->attr_session_key);
return 0;
}
......
......@@ -108,7 +108,7 @@ static int attr_cache_upsert(git_attr_cache *cache, git_attr_file *file)
* Replace the existing value if another thread has
* created it in the meantime.
*/
old = git__swap(entry->file[file->source], file);
old = git_atomic_swap(entry->file[file->source], file);
if (old) {
GIT_REFCOUNT_OWN(old, NULL);
......@@ -132,7 +132,7 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
return error;
if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
old = git__compare_and_swap(&entry->file[file->source], file, NULL);
old = git_atomic_compare_and_swap(&entry->file[file->source], file, NULL);
attr_cache_unlock(cache);
......@@ -321,7 +321,7 @@ static void attr_cache__free(git_attr_cache *cache)
git_strmap_foreach_value(cache->files, entry, {
for (i = 0; i < GIT_ATTR_FILE_NUM_SOURCES; ++i) {
if ((file = git__swap(entry->file[i], NULL)) != NULL) {
if ((file = git_atomic_swap(entry->file[i], NULL)) != NULL) {
GIT_REFCOUNT_OWN(file, NULL);
git_attr_file__free(file);
}
......@@ -395,7 +395,7 @@ int git_attr_cache__init(git_repository *repo)
(ret = git_pool_init(&cache->pool, 1)) < 0)
goto cancel;
cache = git__compare_and_swap(&repo->attrcache, NULL, cache);
cache = git_atomic_compare_and_swap(&repo->attrcache, NULL, cache);
if (cache)
goto cancel; /* raced with another thread, free this but no error */
......@@ -417,7 +417,7 @@ int git_attr_cache_flush(git_repository *repo)
/* this could be done less expensively, but for now, we'll just free
* the entire attrcache and let the next use reinitialize it...
*/
if (repo && (cache = git__swap(repo->attrcache, NULL)) != NULL)
if (repo && (cache = git_atomic_swap(repo->attrcache, NULL)) != NULL)
attr_cache__free(cache);
return 0;
......
......@@ -9,7 +9,7 @@
#include "repository.h"
#include "commit.h"
#include "thread-utils.h"
#include "thread.h"
#include "util.h"
#include "odb.h"
#include "object.h"
......@@ -235,7 +235,7 @@ void git_cached_obj_decref(void *_obj)
{
git_cached_obj *obj = _obj;
if (git_atomic_dec(&obj->refcount) == 0) {
if (git_atomic32_dec(&obj->refcount) == 0) {
switch (obj->flags) {
case GIT_CACHE_STORE_RAW:
git_odb_object__free(_obj);
......
......@@ -13,7 +13,7 @@
#include "git2/oid.h"
#include "git2/odb.h"
#include "thread-utils.h"
#include "thread.h"
#include "oidmap.h"
enum {
......@@ -23,11 +23,11 @@ enum {
};
typedef struct {
git_oid oid;
int16_t type; /* git_object_t value */
uint16_t flags; /* GIT_CACHE_STORE value */
size_t size;
git_atomic refcount;
git_oid oid;
int16_t type; /* git_object_t value */
uint16_t flags; /* GIT_CACHE_STORE value */
size_t size;
git_atomic32 refcount;
} git_cached_obj;
typedef struct {
......@@ -61,7 +61,7 @@ GIT_INLINE(size_t) git_cache_size(git_cache *cache)
GIT_INLINE(void) git_cached_obj_incref(void *_obj)
{
git_cached_obj *obj = _obj;
git_atomic_inc(&obj->refcount);
git_atomic32_inc(&obj->refcount);
}
void git_cached_obj_decref(void *_obj);
......
......@@ -63,7 +63,9 @@
# include <pthread.h>
# include <sched.h>
# endif
#define GIT_STDLIB_CALL
#define GIT_LIBGIT2_CALL
#define GIT_SYSTEM_CALL
#ifdef GIT_USE_STAT_ATIMESPEC
# define st_atim st_atimespec
......@@ -78,7 +80,7 @@
#include "git2/types.h"
#include "git2/errors.h"
#include "errors.h"
#include "thread-utils.h"
#include "thread.h"
#include "integer.h"
#include "assert_safe.h"
......
......@@ -111,7 +111,7 @@ int git_config__configmap_lookup(int *out, git_config *config, git_configmap_ite
int git_repository__configmap_lookup(int *out, git_repository *repo, git_configmap_item item)
{
*out = (int)(intptr_t)git__load(repo->configmap_cache[(int)item]);
*out = (int)(intptr_t)git_atomic_load(repo->configmap_cache[(int)item]);
if (*out == GIT_CONFIGMAP_NOT_CACHED) {
int error;
......@@ -122,7 +122,7 @@ int git_repository__configmap_lookup(int *out, git_repository *repo, git_configm
(error = git_config__configmap_lookup(out, config, item)) < 0)
return error;
git__compare_and_swap(&repo->configmap_cache[(int)item], &oldval, out);
git_atomic_compare_and_swap(&repo->configmap_cache[(int)item], &oldval, out);
}
return 0;
......
......@@ -144,7 +144,7 @@ static git_diff_driver_registry *git_repository_driver_registry(
{
if (!repo->diff_drivers) {
git_diff_driver_registry *reg = git_diff_driver_registry_new();
reg = git__compare_and_swap(&repo->diff_drivers, NULL, reg);
reg = git_atomic_compare_and_swap(&repo->diff_drivers, NULL, reg);
if (reg != NULL) /* if we race, free losing allocation */
git_diff_driver_registry_free(reg);
......
......@@ -461,7 +461,7 @@ static void index_free(git_index *index)
/* index iterators increment the refcount of the index, so if we
* get here then there should be no outstanding iterators.
*/
if (git_atomic_get(&index->readers))
if (git_atomic32_get(&index->readers))
return;
git_index_clear(index);
......@@ -488,14 +488,14 @@ void git_index_free(git_index *index)
/* call with locked index */
static void index_free_deleted(git_index *index)
{
int readers = (int)git_atomic_get(&index->readers);
int readers = (int)git_atomic32_get(&index->readers);
size_t i;
if (readers > 0 || !index->deleted.length)
return;
for (i = 0; i < index->deleted.length; ++i) {
git_index_entry *ie = git__swap(index->deleted.contents[i], NULL);
git_index_entry *ie = git_atomic_swap(index->deleted.contents[i], NULL);
index_entry_free(ie);
}
......@@ -516,7 +516,7 @@ static int index_remove_entry(git_index *index, size_t pos)
error = git_vector_remove(&index->entries, pos);
if (!error) {
if (git_atomic_get(&index->readers) > 0) {
if (git_atomic32_get(&index->readers) > 0) {
error = git_vector_insert(&index->deleted, entry);
} else {
index_entry_free(entry);
......@@ -2295,7 +2295,7 @@ int git_index_reuc_clear(git_index *index)
GIT_ASSERT_ARG(index);
for (i = 0; i < index->reuc.length; ++i)
index_entry_reuc_free(git__swap(index->reuc.contents[i], NULL));
index_entry_reuc_free(git_atomic_swap(index->reuc.contents[i], NULL));
git_vector_clear(&index->reuc);
......@@ -3197,7 +3197,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
/* well, this isn't good */;
} else {
git_vector_swap(&entries, &index->entries);
entries_map = git__swap(index->entries_map, entries_map);
entries_map = git_atomic_swap(index->entries_map, entries_map);
}
index->dirty = 1;
......@@ -3331,7 +3331,7 @@ static int git_index_read_iterator(
goto done;
git_vector_swap(&new_entries, &index->entries);
new_entries_map = git__swap(index->entries_map, new_entries_map);
new_entries_map = git_atomic_swap(index->entries_map, new_entries_map);
git_vector_foreach(&remove_entries, i, entry) {
if (index->tree)
......@@ -3637,7 +3637,7 @@ int git_index_snapshot_new(git_vector *snap, git_index *index)
GIT_REFCOUNT_INC(index);
git_atomic_inc(&index->readers);
git_atomic32_inc(&index->readers);
git_vector_sort(&index->entries);
error = git_vector_dup(snap, &index->entries, index->entries._cmp);
......@@ -3652,7 +3652,7 @@ void git_index_snapshot_release(git_vector *snap, git_index *index)
{
git_vector_free(snap);
git_atomic_dec(&index->readers);
git_atomic32_dec(&index->readers);
git_index_free(index);
}
......
......@@ -33,7 +33,7 @@ struct git_index {
git_idxmap *entries_map;
git_vector deleted; /* deleted entries if readers > 0 */
git_atomic readers; /* number of active iterators */
git_atomic32 readers; /* number of active iterators */
unsigned int on_disk:1;
unsigned int ignore_case:1;
......
......@@ -22,7 +22,7 @@
#include "refs.h"
#include "runtime.h"
#include "sysdir.h"
#include "thread-utils.h"
#include "thread.h"
#include "threadstate.h"
#include "git2/global.h"
#include "streams/registry.h"
......
......@@ -79,7 +79,7 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
git__free(packname);
if (pack != NULL) {
git_atomic_inc(&pack->refcount);
git_atomic32_inc(&pack->refcount);
git_mutex_unlock(&git__mwindow_mutex);
*out = pack;
return 0;
......@@ -91,7 +91,7 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path)
return error;
}
git_atomic_inc(&pack->refcount);
git_atomic32_inc(&pack->refcount);
error = git_strmap_set(git__pack_cache, pack->pack_name, pack);
git_mutex_unlock(&git__mwindow_mutex);
......@@ -118,7 +118,7 @@ int git_mwindow_put_pack(struct git_pack_file *pack)
/* if we cannot find it, the state is corrupted */
GIT_ASSERT(git_strmap_exists(git__pack_cache, pack->pack_name));
count = git_atomic_dec(&pack->refcount);
count = git_atomic32_dec(&pack->refcount);
if (count == 0) {
git_strmap_delete(git__pack_cache, pack->pack_name);
pack_to_delete = pack;
......
......@@ -12,7 +12,7 @@
#include "iterator.h"
#include "netops.h"
#include "pack.h"
#include "thread-utils.h"
#include "thread.h"
#include "tree.h"
#include "util.h"
#include "revwalk.h"
......@@ -1158,7 +1158,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
int ret, active_threads = 0;
if (!pb->nr_threads)
pb->nr_threads = git_online_cpus();
pb->nr_threads = git__online_cpus();
if (pb->nr_threads <= 1) {
find_deltas(pb, list, &list_size, window, depth);
......
......@@ -57,7 +57,7 @@ static git_pack_cache_entry *new_cache_object(git_rawobj *source)
if (!e)
return NULL;
git_atomic_inc(&e->refcount);
git_atomic32_inc(&e->refcount);
memcpy(&e->raw, source, sizeof(git_rawobj));
return e;
......@@ -114,7 +114,7 @@ static git_pack_cache_entry *cache_get(git_pack_cache *cache, off64_t offset)
return NULL;
if ((entry = git_offmap_get(cache->entries, offset)) != NULL) {
git_atomic_inc(&entry->refcount);
git_atomic32_inc(&entry->refcount);
entry->last_usage = cache->use_ctr++;
}
git_mutex_unlock(&cache->lock);
......@@ -129,7 +129,7 @@ static void free_lowest_entry(git_pack_cache *cache)
git_pack_cache_entry *entry;
git_offmap_foreach(cache->entries, offset, entry, {
if (entry && git_atomic_get(&entry->refcount) == 0) {
if (entry && git_atomic32_get(&entry->refcount) == 0) {
cache->memory_used -= entry->raw.len;
git_offmap_delete(cache->entries, offset);
free_cache_object(entry);
......@@ -759,7 +759,7 @@ int git_packfile_unpack(
GIT_ERROR_CHECK_ALLOC(obj->data);
memcpy(obj->data, data, obj->len + 1);
git_atomic_dec(&cached->refcount);
git_atomic32_dec(&cached->refcount);
goto cleanup;
}
......@@ -807,7 +807,7 @@ int git_packfile_unpack(
}
if (cached) {
git_atomic_dec(&cached->refcount);
git_atomic32_dec(&cached->refcount);
cached = NULL;
}
......@@ -821,7 +821,7 @@ cleanup:
if (error < 0) {
git__free(obj->data);
if (cached)
git_atomic_dec(&cached->refcount);
git_atomic32_dec(&cached->refcount);
}
if (elem)
......
......@@ -58,7 +58,7 @@ struct git_pack_idx_header {
typedef struct git_pack_cache_entry {
size_t last_usage; /* enough? */
git_atomic refcount;
git_atomic32 refcount;
git_rawobj raw;
} git_pack_cache_entry;
......@@ -86,7 +86,7 @@ struct git_pack_file {
git_mwindow_file mwf;
git_map index_map;
git_mutex lock; /* protect updates to index_map */
git_atomic refcount;
git_atomic32 refcount;
uint32_t num_objects;
uint32_t num_bad_objects;
......
......@@ -93,7 +93,7 @@ static void set_odb(git_repository *repo, git_odb *odb)
GIT_REFCOUNT_INC(odb);
}
if ((odb = git__swap(repo->_odb, odb)) != NULL) {
if ((odb = git_atomic_swap(repo->_odb, odb)) != NULL) {
GIT_REFCOUNT_OWN(odb, NULL);
git_odb_free(odb);
}
......@@ -106,7 +106,7 @@ static void set_refdb(git_repository *repo, git_refdb *refdb)
GIT_REFCOUNT_INC(refdb);
}
if ((refdb = git__swap(repo->_refdb, refdb)) != NULL) {
if ((refdb = git_atomic_swap(repo->_refdb, refdb)) != NULL) {
GIT_REFCOUNT_OWN(refdb, NULL);
git_refdb_free(refdb);
}
......@@ -119,7 +119,7 @@ static void set_config(git_repository *repo, git_config *config)
GIT_REFCOUNT_INC(config);
}
if ((config = git__swap(repo->_config, config)) != NULL) {
if ((config = git_atomic_swap(repo->_config, config)) != NULL) {
GIT_REFCOUNT_OWN(config, NULL);
git_config_free(config);
}
......@@ -134,7 +134,7 @@ static void set_index(git_repository *repo, git_index *index)
GIT_REFCOUNT_INC(index);
}
if ((index = git__swap(repo->_index, index)) != NULL) {
if ((index = git_atomic_swap(repo->_index, index)) != NULL) {
GIT_REFCOUNT_OWN(index, NULL);
git_index_free(index);
}
......@@ -1054,7 +1054,7 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo)
if (!error) {
GIT_REFCOUNT_OWN(config, repo);
config = git__compare_and_swap(&repo->_config, NULL, config);
config = git_atomic_compare_and_swap(&repo->_config, NULL, config);
if (config != NULL) {
GIT_REFCOUNT_OWN(config, NULL);
git_config_free(config);
......@@ -1107,7 +1107,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
GIT_ASSERT_ARG(repo);
GIT_ASSERT_ARG(out);
*out = git__load(repo->_odb);
*out = git_atomic_load(repo->_odb);
if (*out == NULL) {
git_buf odb_path = GIT_BUF_INIT;
git_odb *odb;
......@@ -1125,14 +1125,14 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
return error;
}
odb = git__compare_and_swap(&repo->_odb, NULL, odb);
odb = git_atomic_compare_and_swap(&repo->_odb, NULL, odb);
if (odb != NULL) {
GIT_REFCOUNT_OWN(odb, NULL);
git_odb_free(odb);
}
git_buf_dispose(&odb_path);
*out = git__load(repo->_odb);
*out = git_atomic_load(repo->_odb);
}
return error;
......@@ -1170,7 +1170,7 @@ int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
if (!error) {
GIT_REFCOUNT_OWN(refdb, repo);
refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb);
refdb = git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb);
if (refdb != NULL) {
GIT_REFCOUNT_OWN(refdb, NULL);
git_refdb_free(refdb);
......@@ -1218,7 +1218,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
if (!error) {
GIT_REFCOUNT_OWN(index, repo);
index = git__compare_and_swap(&repo->_index, NULL, index);
index = git_atomic_compare_and_swap(&repo->_index, NULL, index);
if (index != NULL) {
GIT_REFCOUNT_OWN(index, NULL);
git_index_free(index);
......@@ -3044,8 +3044,8 @@ int git_repository_set_ident(git_repository *repo, const char *name, const char
GIT_ERROR_CHECK_ALLOC(tmp_email);
}
tmp_name = git__swap(repo->ident_name, tmp_name);
tmp_email = git__swap(repo->ident_email, tmp_email);
tmp_name = git_atomic_swap(repo->ident_name, tmp_name);
tmp_email = git_atomic_swap(repo->ident_email, tmp_email);
git__free(tmp_name);
git__free(tmp_email);
......
......@@ -152,7 +152,7 @@ struct git_repository {
unsigned int lru_counter;
git_atomic attr_session_key;
git_atomic32 attr_session_key;
git_configmap_value configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
git_strmap *submodule_cache;
......
......@@ -9,9 +9,9 @@
#include "runtime.h"
static git_runtime_shutdown_fn shutdown_callback[32];
static git_atomic shutdown_callback_count;
static git_atomic32 shutdown_callback_count;
static git_atomic init_count;
static git_atomic32 init_count;
static int init_common(git_runtime_init_fn init_fns[], size_t cnt)
{
......@@ -34,10 +34,10 @@ static void shutdown_common(void)
git_runtime_shutdown_fn cb;
int pos;
for (pos = git_atomic_get(&shutdown_callback_count);
for (pos = git_atomic32_get(&shutdown_callback_count);
pos > 0;
pos = git_atomic_dec(&shutdown_callback_count)) {
cb = git__swap(shutdown_callback[pos - 1], NULL);
pos = git_atomic32_dec(&shutdown_callback_count)) {
cb = git_atomic_swap(shutdown_callback[pos - 1], NULL);
if (cb != NULL)
cb();
......@@ -46,12 +46,12 @@ static void shutdown_common(void)
int git_runtime_shutdown_register(git_runtime_shutdown_fn callback)
{
int count = git_atomic_inc(&shutdown_callback_count);
int count = git_atomic32_inc(&shutdown_callback_count);
if (count > (int)ARRAY_SIZE(shutdown_callback) || count == 0) {
git_error_set(GIT_ERROR_INVALID,
"too many shutdown callbacks registered");
git_atomic_dec(&shutdown_callback_count);
git_atomic32_dec(&shutdown_callback_count);
return -1;
}
......@@ -116,7 +116,7 @@ int git_runtime_init(git_runtime_init_fn init_fns[], size_t cnt)
return -1;
/* Only do work on a 0 -> 1 transition of the refcount */
if ((ret = git_atomic_inc(&init_count)) == 1) {
if ((ret = git_atomic32_inc(&init_count)) == 1) {
if (init_common(init_fns, cnt) < 0)
ret = -1;
}
......@@ -136,7 +136,7 @@ int git_runtime_shutdown(void)
return -1;
/* Only do work on a 1 -> 0 transition of the refcount */
if ((ret = git_atomic_dec(&init_count)) == 0)
if ((ret = git_atomic32_dec(&init_count)) == 0)
shutdown_common();
/* Exit the lock */
......
......@@ -12,7 +12,7 @@
#include "util.h"
#include "futils.h"
#include "vector.h"
#include "thread-utils.h"
#include "thread.h"
#include "pool.h"
#include "strmap.h"
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "common.h"
#include "thread-utils.h"
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
# include <windows.h>
#elif defined(hpux) || defined(__hpux) || defined(_hpux)
# include <sys/pstat.h>
#endif
/*
* By doing this in two steps we can at least get
* the function to be somewhat coherent, even
* with this disgusting nest of #ifdefs.
*/
#ifndef _SC_NPROCESSORS_ONLN
# ifdef _SC_NPROC_ONLN
# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
# elif defined _SC_CRAY_NCPU
# define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU
# endif
#endif
int git_online_cpus(void)
{
#ifdef _SC_NPROCESSORS_ONLN
long ncpus;
#endif
#ifdef _WIN32
SYSTEM_INFO info;
GetSystemInfo(&info);
if ((int)info.dwNumberOfProcessors > 0)
return (int)info.dwNumberOfProcessors;
#elif defined(hpux) || defined(__hpux) || defined(_hpux)
struct pst_dynamic psd;
if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0))
return (int)psd.psd_proc_cnt;
#endif
#ifdef _SC_NPROCESSORS_ONLN
if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0)
return (int)ncpus;
#endif
return 1;
}
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "common.h"
#if !defined(GIT_THREADS)
#define TLSDATA_MAX 16
typedef struct {
void *value;
void (GIT_SYSTEM_CALL *destroy_fn)(void *);
} tlsdata_value;
static tlsdata_value tlsdata_values[TLSDATA_MAX];
static int tlsdata_cnt = 0;
int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
{
if (tlsdata_cnt >= TLSDATA_MAX)
return -1;
tlsdata_values[tlsdata_cnt].value = NULL;
tlsdata_values[tlsdata_cnt].destroy_fn = destroy_fn;
*key = tlsdata_cnt;
tlsdata_cnt++;
return 0;
}
int git_tlsdata_set(git_tlsdata_key key, void *value)
{
if (key < 0 || key > tlsdata_cnt)
return -1;
tlsdata_values[key].value = value;
return 0;
}
void *git_tlsdata_get(git_tlsdata_key key)
{
if (key < 0 || key > tlsdata_cnt)
return NULL;
return tlsdata_values[key].value;
}
int git_tlsdata_dispose(git_tlsdata_key key)
{
void *value;
void (*destroy_fn)(void *) = NULL;
if (key < 0 || key > tlsdata_cnt)
return -1;
value = tlsdata_values[key].value;
destroy_fn = tlsdata_values[key].destroy_fn;
tlsdata_values[key].value = NULL;
tlsdata_values[key].destroy_fn = NULL;
if (value && destroy_fn)
destroy_fn(value);
return 0;
}
#elif defined(GIT_WIN32)
int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
{
DWORD fls_index = FlsAlloc(destroy_fn);
if (fls_index == FLS_OUT_OF_INDEXES)
return -1;
*key = fls_index;
return 0;
}
int git_tlsdata_set(git_tlsdata_key key, void *value)
{
if (!FlsSetValue(key, value))
return -1;
return 0;
}
void *git_tlsdata_get(git_tlsdata_key key)
{
return FlsGetValue(key);
}
int git_tlsdata_dispose(git_tlsdata_key key)
{
if (!FlsFree(key))
return -1;
return 0;
}
#elif defined(_POSIX_THREADS)
int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *))
{
if (pthread_key_create(key, destroy_fn) != 0)
return -1;
return 0;
}
int git_tlsdata_set(git_tlsdata_key key, void *value)
{
if (pthread_setspecific(key, value) != 0)
return -1;
return 0;
}
void *git_tlsdata_get(git_tlsdata_key key)
{
return pthread_getspecific(key);
}
int git_tlsdata_dispose(git_tlsdata_key key)
{
if (pthread_key_delete(key) != 0)
return -1;
return 0;
}
#else
# error unknown threading model
#endif
......@@ -4,8 +4,8 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_thread_utils_h__
#define INCLUDE_thread_utils_h__
#ifndef INCLUDE_thread_h__
#define INCLUDE_thread_h__
#if defined(GIT_THREADS)
......@@ -38,7 +38,7 @@ typedef struct {
#else
volatile int val;
#endif
} git_atomic;
} git_atomic32;
#ifdef GIT_ARCH_64
......@@ -58,11 +58,11 @@ typedef git_atomic64 git_atomic_ssize;
#else
typedef git_atomic git_atomic_ssize;
typedef git_atomic32 git_atomic_ssize;
#define git_atomic_ssize_set git_atomic_set
#define git_atomic_ssize_add git_atomic_add
#define git_atomic_ssize_get git_atomic_get
#define git_atomic_ssize_set git_atomic32_set
#define git_atomic_ssize_add git_atomic32_add
#define git_atomic_ssize_get git_atomic32_get
#endif
......@@ -74,7 +74,7 @@ typedef git_atomic git_atomic_ssize;
# include "unix/pthread.h"
#endif
GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
{
#if defined(GIT_WIN32)
InterlockedExchange(&a->val, (LONG)val);
......@@ -87,7 +87,7 @@ GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
#endif
}
GIT_INLINE(int) git_atomic_inc(git_atomic *a)
GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
{
#if defined(GIT_WIN32)
return InterlockedIncrement(&a->val);
......@@ -100,7 +100,7 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a)
#endif
}
GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
{
#if defined(GIT_WIN32)
return InterlockedExchangeAdd(&a->val, addend);
......@@ -113,7 +113,7 @@ GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
#endif
}
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
{
#if defined(GIT_WIN32)
return InterlockedDecrement(&a->val);
......@@ -126,7 +126,7 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a)
#endif
}
GIT_INLINE(int) git_atomic_get(git_atomic *a)
GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
{
#if defined(GIT_WIN32)
return (int)InterlockedCompareExchange(&a->val, 0, 0);
......@@ -139,7 +139,7 @@ GIT_INLINE(int) git_atomic_get(git_atomic *a)
#endif
}
GIT_INLINE(void *) git___compare_and_swap(
GIT_INLINE(void *) git_atomic__compare_and_swap(
void * volatile *ptr, void *oldval, void *newval)
{
#if defined(GIT_WIN32)
......@@ -158,7 +158,7 @@ GIT_INLINE(void *) git___compare_and_swap(
#endif
}
GIT_INLINE(volatile void *) git___swap(
GIT_INLINE(volatile void *) git_atomic__swap(
void * volatile *ptr, void *newval)
{
#if defined(GIT_WIN32)
......@@ -174,7 +174,7 @@ GIT_INLINE(volatile void *) git___swap(
#endif
}
GIT_INLINE(volatile void *) git___load(void * volatile *ptr)
GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
{
#if defined(GIT_WIN32)
void *newval = NULL, *oldval = NULL;
......@@ -268,33 +268,33 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
#define GIT_RWLOCK_STATIC_INIT 0
GIT_INLINE(void) git_atomic_set(git_atomic *a, int val)
GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
{
a->val = val;
}
GIT_INLINE(int) git_atomic_inc(git_atomic *a)
GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
{
return ++a->val;
}
GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend)
GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
{
a->val += addend;
return a->val;
}
GIT_INLINE(int) git_atomic_dec(git_atomic *a)
GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
{
return --a->val;
}
GIT_INLINE(int) git_atomic_get(git_atomic *a)
GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
{
return (int)a->val;
}
GIT_INLINE(void *) git___compare_and_swap(
GIT_INLINE(void *) git_atomic__compare_and_swap(
void * volatile *ptr, void *oldval, void *newval)
{
if (*ptr == oldval)
......@@ -304,7 +304,7 @@ GIT_INLINE(void *) git___compare_and_swap(
return oldval;
}
GIT_INLINE(volatile void *) git___swap(
GIT_INLINE(volatile void *) git_atomic__swap(
void * volatile *ptr, void *newval)
{
volatile void *old = *ptr;
......@@ -312,7 +312,7 @@ GIT_INLINE(volatile void *) git___swap(
return old;
}
GIT_INLINE(volatile void *) git___load(void * volatile *ptr)
GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
{
return *ptr;
}
......@@ -342,14 +342,14 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
/* Atomically replace oldval with newval
* @return oldval if it was replaced or newval if it was not
*/
#define git__compare_and_swap(P,O,N) \
git___compare_and_swap((void * volatile *)P, O, N)
#define git_atomic_compare_and_swap(P,O,N) \
git_atomic__compare_and_swap((void * volatile *)P, O, N)
#define git__swap(ptr, val) (void *)git___swap((void * volatile *)&ptr, val)
#define git_atomic_swap(ptr, val) \
(void *)git_atomic__swap((void * volatile *)&ptr, val)
#define git__load(ptr) (void *)git___load((void * volatile *)&ptr)
extern int git_online_cpus(void);
#define git_atomic_load(ptr) \
(void *)git_atomic__load((void * volatile *)&ptr)
#if defined(GIT_THREADS)
......@@ -367,4 +367,56 @@ extern int git_online_cpus(void);
#endif
/* Thread-local data */
#if !defined(GIT_THREADS)
# define git_tlsdata_key int
#elif defined(GIT_WIN32)
# define git_tlsdata_key DWORD
#elif defined(_POSIX_THREADS)
# define git_tlsdata_key pthread_key_t
#else
# error unknown threading model
#endif
/**
* Create a thread-local data key. The destroy function will be
* called upon thread exit. On some platforms, it may be called
* when all threads have deleted their keys.
*
* Note that the tlsdata functions do not set an error message on
* failure; this is because the error handling in libgit2 is itself
* handled by thread-local data storage.
*
* @param key the tlsdata key
* @param destroy_fn function pointer called upon thread exit
* @return 0 on success, non-zero on failure
*/
int git_tlsdata_init(git_tlsdata_key *key, void (GIT_SYSTEM_CALL *destroy_fn)(void *));
/**
* Set a the thread-local value for the given key.
*
* @param key the tlsdata key to store data on
* @param value the pointer to store
* @return 0 on success, non-zero on failure
*/
int git_tlsdata_set(git_tlsdata_key key, void *value);
/**
* Get the thread-local value for the given key.
*
* @param key the tlsdata key to retrieve the value of
* @return the pointer stored with git_tlsdata_set
*/
void *git_tlsdata_get(git_tlsdata_key key);
/**
* Delete the given thread-local key.
*
* @param key the tlsdata key to dispose
* @return 0 on success, non-zero on failure
*/
int git_tlsdata_dispose(git_tlsdata_key key);
#endif
......@@ -8,8 +8,6 @@
#include "threadstate.h"
#include "runtime.h"
static void threadstate_dispose(git_threadstate *threadstate);
/**
* Handle the thread-local state
*
......@@ -17,8 +15,7 @@ static void threadstate_dispose(git_threadstate *threadstate);
* of `git_libgit2_init` (which itself must be called
* before calling any other function in the library).
*
* This function allocates a TLS index (using pthreads
* or fiber-local storage in Win32) to store the per-
* This function allocates a TLS index to store the per-
* thread state.
*
* Any internal method that requires thread-local state
......@@ -30,77 +27,41 @@ static void threadstate_dispose(git_threadstate *threadstate);
* (`git_threadstate_global_shutdown`) which will free the
* TLS index. This shutdown handler will be called by
* `git_libgit2_shutdown`.
*
* If libgit2 is built without threading support, the
* `git_threadstate_get()` call returns a pointer to a single,
* statically allocated global state. The `git_thread_`
* functions are not available in that case.
*/
#if defined(GIT_THREADS) && defined(GIT_WIN32)
static git_tlsdata_key tls_key;
static DWORD fls_index;
static void git_threadstate_global_shutdown(void)
static void threadstate_dispose(git_threadstate *threadstate)
{
FlsFree(fls_index);
if (!threadstate)
return;
git__free(threadstate->error_t.message);
threadstate->error_t.message = NULL;
}
static void WINAPI fls_free(void *threadstate)
static void GIT_SYSTEM_CALL threadstate_free(void *threadstate)
{
threadstate_dispose(threadstate);
git__free(threadstate);
}
int git_threadstate_global_init(void)
{
if ((fls_index = FlsAlloc(fls_free)) == FLS_OUT_OF_INDEXES)
return -1;
return git_runtime_shutdown_register(git_threadstate_global_shutdown);
}
git_threadstate *git_threadstate_get(void)
{
git_threadstate *threadstate;
if ((threadstate = FlsGetValue(fls_index)) != NULL)
return threadstate;
if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL ||
git_buf_init(&threadstate->error_buf, 0) < 0)
return NULL;
FlsSetValue(fls_index, threadstate);
return threadstate;
}
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
static pthread_key_t tls_key;
static void git_threadstate_global_shutdown(void)
{
git_threadstate *threadstate;
threadstate = pthread_getspecific(tls_key);
pthread_setspecific(tls_key, NULL);
threadstate = git_tlsdata_get(tls_key);
git_tlsdata_set(tls_key, NULL);
threadstate_dispose(threadstate);
git__free(threadstate);
pthread_key_delete(tls_key);
}
static void tls_free(void *threadstate)
{
threadstate_dispose(threadstate);
git__free(threadstate);
git_tlsdata_dispose(tls_key);
}
int git_threadstate_global_init(void)
{
if (pthread_key_create(&tls_key, &tls_free) != 0)
if (git_tlsdata_init(&tls_key, &threadstate_free) != 0)
return -1;
return git_runtime_shutdown_register(git_threadstate_global_shutdown);
......@@ -110,46 +71,13 @@ git_threadstate *git_threadstate_get(void)
{
git_threadstate *threadstate;
if ((threadstate = pthread_getspecific(tls_key)) != NULL)
if ((threadstate = git_tlsdata_get(tls_key)) != NULL)
return threadstate;
if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL ||
git_buf_init(&threadstate->error_buf, 0) < 0)
return NULL;
pthread_setspecific(tls_key, threadstate);
git_tlsdata_set(tls_key, threadstate);
return threadstate;
}
#elif defined(GIT_THREADS)
# error unknown threading model
#else
static git_threadstate threadstate;
static void git_threadstate_global_shutdown(void)
{
threadstate_dispose(&threadstate);
memset(&threadstate, 0, sizeof(git_threadstate));
}
int git_threadstate_global_init(void)
{
return git_runtime_shutdown_register(git_threadstate_global_shutdown);
}
git_threadstate *git_threadstate_get(void)
{
return &threadstate;
}
#endif
static void threadstate_dispose(git_threadstate *threadstate)
{
if (!threadstate)
return;
git__free(threadstate->error_t.message);
threadstate->error_t.message = NULL;
}
......@@ -36,7 +36,7 @@ typedef struct {
char *url;
int direction;
int flags;
git_atomic cancelled;
git_atomic32 cancelled;
git_repository *repo;
git_transport_message_cb progress_cb;
git_transport_message_cb error_cb;
......@@ -671,7 +671,7 @@ static void local_cancel(git_transport *transport)
{
transport_local *t = (transport_local *)transport;
git_atomic_set(&t->cancelled, 1);
git_atomic32_set(&t->cancelled, 1);
}
static int local_close(git_transport *transport)
......
......@@ -30,7 +30,7 @@ static int git_smart__recv_cb(gitno_buffer *buf)
if (t->packetsize_cb && !t->cancelled.val) {
error = t->packetsize_cb(bytes_read, t->packetsize_payload);
if (error) {
git_atomic_set(&t->cancelled, 1);
git_atomic32_set(&t->cancelled, 1);
return GIT_EUSER;
}
}
......@@ -389,7 +389,7 @@ static void git_smart__cancel(git_transport *transport)
{
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
git_atomic_set(&t->cancelled, 1);
git_atomic32_set(&t->cancelled, 1);
}
static int git_smart__is_connected(git_transport *transport)
......
......@@ -153,7 +153,7 @@ typedef struct {
git_vector refs;
git_vector heads;
git_vector common;
git_atomic cancelled;
git_atomic32 cancelled;
packetsize_cb packetsize_cb;
void *packetsize_payload;
unsigned rpc : 1,
......
......@@ -535,7 +535,7 @@ int git_smart__download_pack(
/* We might have something in the buffer already from negotiate_fetch */
if (t->buffer.offset > 0 && !t->cancelled.val)
if (t->packetsize_cb(t->buffer.offset, t->packetsize_payload))
git_atomic_set(&t->cancelled, 1);
git_atomic32_set(&t->cancelled, 1);
}
if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
......
......@@ -13,6 +13,11 @@
# include "win32/utf-conv.h"
# include "win32/w32_buffer.h"
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
# ifdef HAVE_QSORT_S
# include <search.h>
# endif
......@@ -22,6 +27,10 @@
# include <Shlwapi.h>
#endif
#if defined(hpux) || defined(__hpux) || defined(_hpux)
# include <sys/pstat.h>
#endif
int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const char **endptr, int base)
{
const char *p;
......@@ -678,7 +687,7 @@ typedef struct {
void *payload;
} git__qsort_r_glue;
static int GIT_STDLIB_CALL git__qsort_r_glue_cmp(
static int GIT_LIBGIT2_CALL git__qsort_r_glue_cmp(
void *payload, const void *a, const void *b)
{
git__qsort_r_glue *glue = payload;
......@@ -893,3 +902,43 @@ int git__getenv(git_buf *out, const char *name)
return git_buf_puts(out, val);
}
#endif
/*
* By doing this in two steps we can at least get
* the function to be somewhat coherent, even
* with this disgusting nest of #ifdefs.
*/
#ifndef _SC_NPROCESSORS_ONLN
# ifdef _SC_NPROC_ONLN
# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
# elif defined _SC_CRAY_NCPU
# define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU
# endif
#endif
int git__online_cpus(void)
{
#ifdef _SC_NPROCESSORS_ONLN
long ncpus;
#endif
#ifdef _WIN32
SYSTEM_INFO info;
GetSystemInfo(&info);
if ((int)info.dwNumberOfProcessors > 0)
return (int)info.dwNumberOfProcessors;
#elif defined(hpux) || defined(__hpux) || defined(_hpux)
struct pst_dynamic psd;
if (!pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0))
return (int)psd.psd_proc_cnt;
#endif
#ifdef _SC_NPROCESSORS_ONLN
if ((ncpus = (long)sysconf(_SC_NPROCESSORS_ONLN)) > 0)
return (int)ncpus;
#endif
return 1;
}
......@@ -18,7 +18,7 @@
#include "buffer.h"
#include "common.h"
#include "strnlen.h"
#include "thread-utils.h"
#include "thread.h"
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
......@@ -169,29 +169,29 @@ extern int git__strncasecmp(const char *a, const char *b, size_t sz);
extern int git__strcasesort_cmp(const char *a, const char *b);
typedef struct {
git_atomic refcount;
git_atomic32 refcount;
void *owner;
} git_refcount;
typedef void (*git_refcount_freeptr)(void *r);
#define GIT_REFCOUNT_INC(r) { \
git_atomic_inc(&(r)->rc.refcount); \
git_atomic32_inc(&(r)->rc.refcount); \
}
#define GIT_REFCOUNT_DEC(_r, do_free) { \
git_refcount *r = &(_r)->rc; \
int val = git_atomic_dec(&r->refcount); \
int val = git_atomic32_dec(&r->refcount); \
if (val <= 0 && r->owner == NULL) { do_free(_r); } \
}
#define GIT_REFCOUNT_OWN(r, o) { \
(void)git__swap((r)->rc.owner, o); \
(void)git_atomic_swap((r)->rc.owner, o); \
}
#define GIT_REFCOUNT_OWNER(r) git__load((r)->rc.owner)
#define GIT_REFCOUNT_OWNER(r) git_atomic_load((r)->rc.owner)
#define GIT_REFCOUNT_VAL(r) git_atomic_get((r)->rc.refcount)
#define GIT_REFCOUNT_VAL(r) git_atomic32_get((r)->rc.refcount)
static signed char from_hex[] = {
......@@ -414,6 +414,8 @@ GIT_INLINE(double) git__timer(void)
extern int git__getenv(git_buf *out, const char *name);
extern int git__online_cpus(void);
GIT_INLINE(int) git__noop(void) { return 0; }
#include "alloc.h"
......
......@@ -23,6 +23,14 @@ typedef SSIZE_T ssize_t;
#endif
#define GIT_STDLIB_CALL __cdecl
/*
* Offer GIT_LIBGIT2_CALL for our calling conventions (__cdecl, always).
* This is useful for providing callbacks to userspace code.
*
* Offer GIT_SYSTEM_CALL for the system calling conventions (__stdcall on
* Win32). Useful for providing callbacks to system libraries.
*/
#define GIT_LIBGIT2_CALL __cdecl
#define GIT_SYSTEM_CALL NTAPI
#endif
......@@ -17,7 +17,7 @@
static git_repository *_repo;
static git_tree *_a, *_b;
static git_atomic _counts[4];
static git_atomic32 _counts[4];
static int _check_counts;
#ifdef GIT_WIN32
static int _retries;
......@@ -66,10 +66,10 @@ static void free_trees(void)
git_tree_free(_b); _b = NULL;
if (_check_counts) {
cl_assert_equal_i(288, git_atomic_get(&_counts[0]));
cl_assert_equal_i(112, git_atomic_get(&_counts[1]));
cl_assert_equal_i( 80, git_atomic_get(&_counts[2]));
cl_assert_equal_i( 96, git_atomic_get(&_counts[3]));
cl_assert_equal_i(288, git_atomic32_get(&_counts[0]));
cl_assert_equal_i(112, git_atomic32_get(&_counts[1]));
cl_assert_equal_i( 80, git_atomic32_get(&_counts[2]));
cl_assert_equal_i( 96, git_atomic32_get(&_counts[3]));
}
}
......@@ -107,14 +107,14 @@ static void *run_index_diffs(void *arg)
/* keep some diff stats to make sure results are as expected */
i = git_diff_num_deltas(diff);
git_atomic_add(&_counts[0], (int32_t)i);
git_atomic32_add(&_counts[0], (int32_t)i);
exp[0] = (int)i;
while (i > 0) {
switch (git_diff_get_delta(diff, --i)->status) {
case GIT_DELTA_MODIFIED: exp[1]++; git_atomic_inc(&_counts[1]); break;
case GIT_DELTA_ADDED: exp[2]++; git_atomic_inc(&_counts[2]); break;
case GIT_DELTA_DELETED: exp[3]++; git_atomic_inc(&_counts[3]); break;
case GIT_DELTA_MODIFIED: exp[1]++; git_atomic32_inc(&_counts[1]); break;
case GIT_DELTA_ADDED: exp[2]++; git_atomic32_inc(&_counts[2]); break;
case GIT_DELTA_DELETED: exp[3]++; git_atomic32_inc(&_counts[3]); break;
default: break;
}
}
......
#include "thread-utils.h"
#include "thread.h"
void run_in_parallel(
int repeats,
......
#include "clar_libgit2.h"
#include "thread_helpers.h"
void test_threads_tlsdata__can_set_and_get(void)
{
git_tlsdata_key key_one, key_two, key_three;
cl_git_pass(git_tlsdata_init(&key_one, NULL));
cl_git_pass(git_tlsdata_init(&key_two, NULL));
cl_git_pass(git_tlsdata_init(&key_three, NULL));
cl_git_pass(git_tlsdata_set(key_one, (void *)(size_t)42424242));
cl_git_pass(git_tlsdata_set(key_two, (void *)(size_t)0xdeadbeef));
cl_git_pass(git_tlsdata_set(key_three, (void *)(size_t)98761234));
cl_assert_equal_sz((size_t)42424242, git_tlsdata_get(key_one));
cl_assert_equal_sz((size_t)0xdeadbeef, git_tlsdata_get(key_two));
cl_assert_equal_sz((size_t)98761234, git_tlsdata_get(key_three));
cl_git_pass(git_tlsdata_dispose(key_one));
cl_git_pass(git_tlsdata_dispose(key_two));
cl_git_pass(git_tlsdata_dispose(key_three));
}
#ifdef GIT_THREADS
static void *set_and_get(void *param)
{
git_tlsdata_key *tlsdata_key = (git_tlsdata_key *)param;
int val;
if (git_tlsdata_set(*tlsdata_key, &val) != 0 ||
git_tlsdata_get(*tlsdata_key) != &val)
return (void *)0;
return (void *)1;
}
#endif
#define THREAD_COUNT 10
void test_threads_tlsdata__threads(void)
{
#ifdef GIT_THREADS
git_thread thread[THREAD_COUNT];
git_tlsdata_key tlsdata;
int i;
cl_git_pass(git_tlsdata_init(&tlsdata, NULL));
for (i = 0; i < THREAD_COUNT; i++)
cl_git_pass(git_thread_create(&thread[i], set_and_get, &tlsdata));
for (i = 0; i < THREAD_COUNT; i++) {
void *result;
cl_git_pass(git_thread_join(&thread[i], &result));
cl_assert_equal_sz(1, (size_t)result);
}
cl_git_pass(git_tlsdata_dispose(tlsdata));
#endif
}
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