Unverified Commit c3512fe6 by Edward Thomson Committed by GitHub

Merge branch 'main' into multi-pack-index-odb-write

parents ea285904 78cd7624
{
"postCreateCommand": "bash .devcontainer/setup.sh"
}
#!/bin/sh
set -e
sudo apt-get update
sudo apt-get -y --no-install-recommends install cmake
mkdir build
cd build
cmake ..
\ No newline at end of file
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/libgit2_clar",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
\ No newline at end of file
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build",
"type": "shell",
"command": "cd build && cmake --build . --parallel",
"group": "build",
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "Run Tests",
"type": "shell",
"command": "build/libgit2_clar -v",
"group": "test",
"presentation": {
"reveal": "always",
"panel": "new"
}
}
]
}
\ No newline at end of file
...@@ -56,6 +56,7 @@ ELSE() ...@@ -56,6 +56,7 @@ ELSE()
MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}") MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend: ${USE_SHA1}")
ENDIF() ENDIF()
list(APPEND SRC_SHA1 "hash/sha1.h")
list(SORT SRC_SHA1) list(SORT SRC_SHA1)
ADD_FEATURE_INFO(SHA ON "using ${USE_SHA1}") ADD_FEATURE_INFO(SHA ON "using ${USE_SHA1}")
...@@ -41,8 +41,8 @@ ...@@ -41,8 +41,8 @@
typedef git_array_t(char) git_array_generic_t; typedef git_array_t(char) git_array_generic_t;
/* use a generic array for growth so this can return the new item */ /* use a generic array for growth, return 0 on success */
GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size) GIT_INLINE(int) git_array_grow(void *_a, size_t item_size)
{ {
volatile git_array_generic_t *a = _a; volatile git_array_generic_t *a = _a;
size_t new_size; size_t new_size;
...@@ -59,18 +59,18 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size) ...@@ -59,18 +59,18 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL) if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL)
goto on_oom; goto on_oom;
a->ptr = new_array; a->asize = new_size; a->size++; a->ptr = new_array;
return a->ptr + (a->size - 1) * item_size; a->asize = new_size;
return 0;
on_oom: on_oom:
git_array_clear(*a); git_array_clear(*a);
return NULL; return -1;
} }
#define git_array_alloc(a) \ #define git_array_alloc(a) \
(((a).size >= (a).asize) ? \ (((a).size < (a).asize || git_array_grow(&(a), sizeof(*(a).ptr)) == 0) ? \
git_array_grow(&(a), sizeof(*(a).ptr)) : \ &(a).ptr[(a).size++] : (void *)NULL)
((a).ptr ? &(a).ptr[(a).size++] : (void *)NULL))
#define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : (void *)NULL) #define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : (void *)NULL)
......
...@@ -127,7 +127,7 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file) ...@@ -127,7 +127,7 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
{ {
int error = 0; int error = 0;
git_attr_file_entry *entry; git_attr_file_entry *entry;
git_attr_file *old = NULL; git_attr_file *oldfile = NULL;
if (!file) if (!file)
return 0; return 0;
...@@ -136,13 +136,13 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file) ...@@ -136,13 +136,13 @@ static int attr_cache_remove(git_attr_cache *cache, git_attr_file *file)
return error; return error;
if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL) if ((entry = attr_cache_lookup_entry(cache, file->entry->path)) != NULL)
old = git_atomic_compare_and_swap(&entry->file[file->source.type], file, NULL); oldfile = git_atomic_compare_and_swap(&entry->file[file->source.type], file, NULL);
attr_cache_unlock(cache); attr_cache_unlock(cache);
if (old) { if (oldfile == file) {
GIT_REFCOUNT_OWN(old, NULL); GIT_REFCOUNT_OWN(file, NULL);
git_attr_file__free(old); git_attr_file__free(file);
} }
return error; return error;
...@@ -401,8 +401,7 @@ int git_attr_cache__init(git_repository *repo) ...@@ -401,8 +401,7 @@ int git_attr_cache__init(git_repository *repo)
(ret = git_pool_init(&cache->pool, 1)) < 0) (ret = git_pool_init(&cache->pool, 1)) < 0)
goto cancel; goto cancel;
cache = git_atomic_compare_and_swap(&repo->attrcache, NULL, cache); if (git_atomic_compare_and_swap(&repo->attrcache, NULL, cache) != NULL)
if (cache)
goto cancel; /* raced with another thread, free this but no error */ goto cancel; /* raced with another thread, free this but no error */
git_config_free(cfg); git_config_free(cfg);
......
...@@ -162,37 +162,6 @@ done: ...@@ -162,37 +162,6 @@ done:
return error; return error;
} }
static int update_remote_head_byname(
git_repository *repo,
const char *remote_name,
const char *tracking_branch_name,
const char *reflog_message)
{
git_buf tracking_head_name = GIT_BUF_INIT;
git_reference *remote_head = NULL;
int error;
if ((error = git_buf_printf(&tracking_head_name,
"%s%s/%s",
GIT_REFS_REMOTES_DIR,
remote_name,
GIT_HEAD_FILE)) < 0)
goto cleanup;
error = git_reference_symbolic_create(
&remote_head,
repo,
git_buf_cstr(&tracking_head_name),
tracking_branch_name,
true,
reflog_message);
cleanup:
git_reference_free(remote_head);
git_buf_dispose(&tracking_head_name);
return error;
}
static int update_remote_head( static int update_remote_head(
git_repository *repo, git_repository *repo,
git_remote *remote, git_remote *remote,
...@@ -200,7 +169,9 @@ static int update_remote_head( ...@@ -200,7 +169,9 @@ static int update_remote_head(
const char *reflog_message) const char *reflog_message)
{ {
git_refspec *refspec; git_refspec *refspec;
git_buf tracking_branch_name = GIT_BUF_INIT; git_reference *remote_head = NULL;
git_buf remote_head_name = GIT_BUF_INIT;
git_buf remote_branch_name = GIT_BUF_INIT;
int error; int error;
/* Determine the remote tracking ref name from the local branch */ /* Determine the remote tracking ref name from the local branch */
...@@ -213,19 +184,30 @@ static int update_remote_head( ...@@ -213,19 +184,30 @@ static int update_remote_head(
} }
if ((error = git_refspec_transform( if ((error = git_refspec_transform(
&tracking_branch_name, &remote_branch_name,
refspec, refspec,
git_buf_cstr(target))) < 0) git_buf_cstr(target))) < 0)
goto cleanup; goto cleanup;
error = update_remote_head_byname( if ((error = git_buf_printf(&remote_head_name,
repo, "%s%s/%s",
GIT_REFS_REMOTES_DIR,
git_remote_name(remote), git_remote_name(remote),
git_buf_cstr(&tracking_branch_name), GIT_HEAD_FILE)) < 0)
goto cleanup;
error = git_reference_symbolic_create(
&remote_head,
repo,
git_buf_cstr(&remote_head_name),
git_buf_cstr(&remote_branch_name),
true,
reflog_message); reflog_message);
cleanup: cleanup:
git_buf_dispose(&tracking_branch_name); git_reference_free(remote_head);
git_buf_dispose(&remote_branch_name);
git_buf_dispose(&remote_head_name);
return error; return error;
} }
...@@ -277,19 +259,20 @@ cleanup: ...@@ -277,19 +259,20 @@ cleanup:
static int update_head_to_branch( static int update_head_to_branch(
git_repository *repo, git_repository *repo,
const char *remote_name, git_remote *remote,
const char *branch, const char *branch,
const char *reflog_message) const char *reflog_message)
{ {
int retcode; int retcode;
git_buf remote_branch_name = GIT_BUF_INIT; git_buf remote_branch_name = GIT_BUF_INIT;
git_reference* remote_ref = NULL; git_reference* remote_ref = NULL;
git_buf default_branch = GIT_BUF_INIT;
GIT_ASSERT_ARG(remote_name); GIT_ASSERT_ARG(remote);
GIT_ASSERT_ARG(branch); GIT_ASSERT_ARG(branch);
if ((retcode = git_buf_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s", if ((retcode = git_buf_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s",
remote_name, branch)) < 0 ) git_remote_name(remote), branch)) < 0 )
goto cleanup; goto cleanup;
if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0) if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0)
...@@ -299,11 +282,18 @@ static int update_head_to_branch( ...@@ -299,11 +282,18 @@ static int update_head_to_branch(
reflog_message)) < 0) reflog_message)) < 0)
goto cleanup; goto cleanup;
retcode = update_remote_head_byname(repo, remote_name, remote_branch_name.ptr, reflog_message); if ((retcode = git_remote_default_branch(&default_branch, remote)) < 0)
goto cleanup;
if (!git_remote__matching_refspec(remote, git_buf_cstr(&default_branch)))
goto cleanup;
retcode = update_remote_head(repo, remote, &default_branch, reflog_message);
cleanup: cleanup:
git_reference_free(remote_ref); git_reference_free(remote_ref);
git_buf_dispose(&remote_branch_name); git_buf_dispose(&remote_branch_name);
git_buf_dispose(&default_branch);
return retcode; return retcode;
} }
...@@ -388,8 +378,7 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c ...@@ -388,8 +378,7 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
int error; int error;
if (branch) if (branch)
error = update_head_to_branch(repo, git_remote_name(remote), branch, error = update_head_to_branch(repo, remote, branch, reflog_message);
reflog_message);
/* Point HEAD to the same ref as the remote's head */ /* Point HEAD to the same ref as the remote's head */
else else
error = update_head_to_remote(repo, remote, reflog_message); error = update_head_to_remote(repo, remote, reflog_message);
......
...@@ -141,18 +141,23 @@ static int diff_driver_funcname(const git_config_entry *entry, void *payload) ...@@ -141,18 +141,23 @@ static int diff_driver_funcname(const git_config_entry *entry, void *payload)
static git_diff_driver_registry *git_repository_driver_registry( static git_diff_driver_registry *git_repository_driver_registry(
git_repository *repo) git_repository *repo)
{ {
if (!repo->diff_drivers) { git_diff_driver_registry *reg = git_atomic_load(repo->diff_drivers), *newreg;
git_diff_driver_registry *reg = git_diff_driver_registry_new(); if (reg)
reg = git_atomic_compare_and_swap(&repo->diff_drivers, NULL, reg); return reg;
if (reg != NULL) /* if we race, free losing allocation */ newreg = git_diff_driver_registry_new();
git_diff_driver_registry_free(reg); if (!newreg) {
}
if (!repo->diff_drivers)
git_error_set(GIT_ERROR_REPOSITORY, "unable to create diff driver registry"); git_error_set(GIT_ERROR_REPOSITORY, "unable to create diff driver registry");
return newreg;
return repo->diff_drivers; }
reg = git_atomic_compare_and_swap(&repo->diff_drivers, NULL, newreg);
if (!reg) {
reg = newreg;
} else {
/* if we race, free losing allocation */
git_diff_driver_registry_free(newreg);
}
return reg;
} }
static int diff_driver_alloc( static int diff_driver_alloc(
......
...@@ -1093,8 +1093,7 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo) ...@@ -1093,8 +1093,7 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo)
if (!error) { if (!error) {
GIT_REFCOUNT_OWN(config, repo); GIT_REFCOUNT_OWN(config, repo);
config = git_atomic_compare_and_swap(&repo->_config, NULL, config); if (git_atomic_compare_and_swap(&repo->_config, NULL, config) != NULL) {
if (config != NULL) {
GIT_REFCOUNT_OWN(config, NULL); GIT_REFCOUNT_OWN(config, NULL);
git_config_free(config); git_config_free(config);
} }
...@@ -1164,8 +1163,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) ...@@ -1164,8 +1163,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
return error; return error;
} }
odb = git_atomic_compare_and_swap(&repo->_odb, NULL, odb); if (git_atomic_compare_and_swap(&repo->_odb, NULL, odb) != NULL) {
if (odb != NULL) {
GIT_REFCOUNT_OWN(odb, NULL); GIT_REFCOUNT_OWN(odb, NULL);
git_odb_free(odb); git_odb_free(odb);
} }
...@@ -1209,8 +1207,7 @@ int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo) ...@@ -1209,8 +1207,7 @@ int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo)
if (!error) { if (!error) {
GIT_REFCOUNT_OWN(refdb, repo); GIT_REFCOUNT_OWN(refdb, repo);
refdb = git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb); if (git_atomic_compare_and_swap(&repo->_refdb, NULL, refdb) != NULL) {
if (refdb != NULL) {
GIT_REFCOUNT_OWN(refdb, NULL); GIT_REFCOUNT_OWN(refdb, NULL);
git_refdb_free(refdb); git_refdb_free(refdb);
} }
...@@ -1257,8 +1254,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) ...@@ -1257,8 +1254,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
if (!error) { if (!error) {
GIT_REFCOUNT_OWN(index, repo); GIT_REFCOUNT_OWN(index, repo);
index = git_atomic_compare_and_swap(&repo->_index, NULL, index); if (git_atomic_compare_and_swap(&repo->_index, NULL, index) != NULL) {
if (index != NULL) {
GIT_REFCOUNT_OWN(index, NULL); GIT_REFCOUNT_OWN(index, NULL);
git_index_free(index); git_index_free(index);
} }
......
...@@ -74,6 +74,9 @@ typedef git_atomic32 git_atomic_ssize; ...@@ -74,6 +74,9 @@ typedef git_atomic32 git_atomic_ssize;
# include "unix/pthread.h" # include "unix/pthread.h"
#endif #endif
/*
* Atomically sets the contents of *a to be val.
*/
GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val) GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
...@@ -87,6 +90,10 @@ GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val) ...@@ -87,6 +90,10 @@ GIT_INLINE(void) git_atomic32_set(git_atomic32 *a, int val)
#endif #endif
} }
/*
* Atomically increments the contents of *a by 1, and stores the result back into *a.
* @return the result of the operation.
*/
GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a) GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
...@@ -100,10 +107,14 @@ GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a) ...@@ -100,10 +107,14 @@ GIT_INLINE(int) git_atomic32_inc(git_atomic32 *a)
#endif #endif
} }
/*
* Atomically adds the contents of *a and addend, and stores the result back into *a.
* @return the result of the operation.
*/
GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend) GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
return InterlockedExchangeAdd(&a->val, addend); return InterlockedAdd(&a->val, addend);
#elif defined(GIT_BUILTIN_ATOMIC) #elif defined(GIT_BUILTIN_ATOMIC)
return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST); return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
#elif defined(GIT_BUILTIN_SYNC) #elif defined(GIT_BUILTIN_SYNC)
...@@ -113,6 +124,10 @@ GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend) ...@@ -113,6 +124,10 @@ GIT_INLINE(int) git_atomic32_add(git_atomic32 *a, int32_t addend)
#endif #endif
} }
/*
* Atomically decrements the contents of *a by 1, and stores the result back into *a.
* @return the result of the operation.
*/
GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a) GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
...@@ -126,6 +141,10 @@ GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a) ...@@ -126,6 +141,10 @@ GIT_INLINE(int) git_atomic32_dec(git_atomic32 *a)
#endif #endif
} }
/*
* Atomically gets the contents of *a.
* @return the contents of *a.
*/
GIT_INLINE(int) git_atomic32_get(git_atomic32 *a) GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
...@@ -143,16 +162,13 @@ GIT_INLINE(void *) git_atomic__compare_and_swap( ...@@ -143,16 +162,13 @@ GIT_INLINE(void *) git_atomic__compare_and_swap(
void * volatile *ptr, void *oldval, void *newval) void * volatile *ptr, void *oldval, void *newval)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
volatile void *foundval; return InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
return (foundval == oldval) ? oldval : newval;
#elif defined(GIT_BUILTIN_ATOMIC) #elif defined(GIT_BUILTIN_ATOMIC)
bool success = __atomic_compare_exchange(ptr, &oldval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); void *foundval = oldval;
return success ? oldval : newval; __atomic_compare_exchange(ptr, &foundval, &newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return foundval;
#elif defined(GIT_BUILTIN_SYNC) #elif defined(GIT_BUILTIN_SYNC)
volatile void *foundval; return __sync_val_compare_and_swap(ptr, oldval, newval);
foundval = __sync_val_compare_and_swap(ptr, oldval, newval);
return (foundval == oldval) ? oldval : newval;
#else #else
# error "Unsupported architecture for atomic operations" # error "Unsupported architecture for atomic operations"
#endif #endif
...@@ -164,11 +180,11 @@ GIT_INLINE(volatile void *) git_atomic__swap( ...@@ -164,11 +180,11 @@ GIT_INLINE(volatile void *) git_atomic__swap(
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
return InterlockedExchangePointer(ptr, newval); return InterlockedExchangePointer(ptr, newval);
#elif defined(GIT_BUILTIN_ATOMIC) #elif defined(GIT_BUILTIN_ATOMIC)
void * volatile foundval; void * volatile foundval = NULL;
__atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST); __atomic_exchange(ptr, &newval, &foundval, __ATOMIC_SEQ_CST);
return foundval; return foundval;
#elif defined(GIT_BUILTIN_SYNC) #elif defined(GIT_BUILTIN_SYNC)
return __sync_lock_test_and_set(ptr, newval); return (volatile void *)__sync_lock_test_and_set(ptr, newval);
#else #else
# error "Unsupported architecture for atomic operations" # error "Unsupported architecture for atomic operations"
#endif #endif
...@@ -178,9 +194,7 @@ GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr) ...@@ -178,9 +194,7 @@ GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
void *newval = NULL, *oldval = NULL; void *newval = NULL, *oldval = NULL;
volatile void *foundval = NULL; return (volatile void *)InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
foundval = InterlockedCompareExchangePointer((volatile PVOID *)ptr, newval, oldval);
return foundval;
#elif defined(GIT_BUILTIN_ATOMIC) #elif defined(GIT_BUILTIN_ATOMIC)
return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST); return (volatile void *)__atomic_load_n(ptr, __ATOMIC_SEQ_CST);
#elif defined(GIT_BUILTIN_SYNC) #elif defined(GIT_BUILTIN_SYNC)
...@@ -192,10 +206,14 @@ GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr) ...@@ -192,10 +206,14 @@ GIT_INLINE(volatile void *) git_atomic__load(void * volatile *ptr)
#ifdef GIT_ARCH_64 #ifdef GIT_ARCH_64
/*
* Atomically adds the contents of *a and addend, and stores the result back into *a.
* @return the result of the operation.
*/
GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
return InterlockedExchangeAdd64(&a->val, addend); return InterlockedAdd64(&a->val, addend);
#elif defined(GIT_BUILTIN_ATOMIC) #elif defined(GIT_BUILTIN_ATOMIC)
return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST); return __atomic_add_fetch(&a->val, addend, __ATOMIC_SEQ_CST);
#elif defined(GIT_BUILTIN_SYNC) #elif defined(GIT_BUILTIN_SYNC)
...@@ -205,6 +223,9 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) ...@@ -205,6 +223,9 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
#endif #endif
} }
/*
* Atomically sets the contents of *a to be val.
*/
GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val) GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
...@@ -218,6 +239,10 @@ GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val) ...@@ -218,6 +239,10 @@ GIT_INLINE(void) git_atomic64_set(git_atomic64 *a, int64_t val)
#endif #endif
} }
/*
* Atomically gets the contents of *a.
* @return the contents of *a.
*/
GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a) GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
{ {
#if defined(GIT_WIN32) #if defined(GIT_WIN32)
...@@ -297,11 +322,10 @@ GIT_INLINE(int) git_atomic32_get(git_atomic32 *a) ...@@ -297,11 +322,10 @@ GIT_INLINE(int) git_atomic32_get(git_atomic32 *a)
GIT_INLINE(void *) git_atomic__compare_and_swap( GIT_INLINE(void *) git_atomic__compare_and_swap(
void * volatile *ptr, void *oldval, void *newval) void * volatile *ptr, void *oldval, void *newval)
{ {
if (*ptr == oldval) void *foundval = *ptr;
if (foundval == oldval)
*ptr = newval; *ptr = newval;
else return foundval;
oldval = newval;
return oldval;
} }
GIT_INLINE(volatile void *) git_atomic__swap( GIT_INLINE(volatile void *) git_atomic__swap(
...@@ -339,17 +363,50 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a) ...@@ -339,17 +363,50 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
#endif #endif
/* Atomically replace oldval with newval /*
* @return oldval if it was replaced or newval if it was not * Atomically replace the contents of *ptr (if they are equal to oldval) with
* newval. ptr must point to a pointer or a value that is the same size as a
* pointer. This is semantically compatible with:
*
* #define git_atomic_compare_and_swap(ptr, oldval, newval) \
* ({ \
* void *foundval = *ptr; \
* if (foundval == oldval) \
* *ptr = newval; \
* foundval; \
* })
*
* @return the original contents of *ptr.
*/ */
#define git_atomic_compare_and_swap(P,O,N) \ #define git_atomic_compare_and_swap(ptr, oldval, newval) \
git_atomic__compare_and_swap((void * volatile *)P, O, N) git_atomic__compare_and_swap((void * volatile *)ptr, oldval, newval)
#define git_atomic_swap(ptr, val) \ /*
(void *)git_atomic__swap((void * volatile *)&ptr, val) * Atomically replace the contents of v with newval. v must be the same size as
* a pointer. This is semantically compatible with:
*
* #define git_atomic_swap(v, newval) \
* ({ \
* volatile void *old = v; \
* v = newval; \
* old; \
* })
*
* @return the original contents of v.
*/
#define git_atomic_swap(v, newval) \
(void *)git_atomic__swap((void * volatile *)&(v), newval)
#define git_atomic_load(ptr) \ /*
(void *)git_atomic__load((void * volatile *)&ptr) * Atomically reads the contents of v. v must be the same size as a pointer.
* This is semantically compatible with:
*
* #define git_atomic_load(v) v
*
* @return the contents of v.
*/
#define git_atomic_load(v) \
(void *)git_atomic__load((void * volatile *)&(v))
#if defined(GIT_THREADS) #if defined(GIT_THREADS)
......
...@@ -172,7 +172,7 @@ void test_clone_nonetwork__can_checkout_given_branch(void) ...@@ -172,7 +172,7 @@ void test_clone_nonetwork__can_checkout_given_branch(void)
cl_git_pass(git_reference_lookup(&remote_head, g_repo, "refs/remotes/origin/HEAD")); cl_git_pass(git_reference_lookup(&remote_head, g_repo, "refs/remotes/origin/HEAD"));
cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(remote_head)); cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(remote_head));
cl_assert_equal_s("refs/remotes/origin/test", git_reference_symbolic_target(remote_head)); cl_assert_equal_s("refs/remotes/origin/master", git_reference_symbolic_target(remote_head));
git_reference_free(remote_head); git_reference_free(remote_head);
} }
......
...@@ -964,7 +964,7 @@ void test_config_read__get_mapped(void) ...@@ -964,7 +964,7 @@ void test_config_read__get_mapped(void)
" key9 = off\n"); " key9 = off\n");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig")); cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
// check parsing bool and string /* check parsing bool and string */
cl_git_pass(git_config_get_mapped(&val, cfg, "header.key1", _test_map1, ARRAY_SIZE(_test_map1))); cl_git_pass(git_config_get_mapped(&val, cfg, "header.key1", _test_map1, ARRAY_SIZE(_test_map1)));
cl_assert_equal_i(val, MAP_TRUE); cl_assert_equal_i(val, MAP_TRUE);
cl_git_pass(git_config_get_mapped(&val, cfg, "header.key2", _test_map1, ARRAY_SIZE(_test_map1))); cl_git_pass(git_config_get_mapped(&val, cfg, "header.key2", _test_map1, ARRAY_SIZE(_test_map1)));
...@@ -986,7 +986,7 @@ void test_config_read__get_mapped(void) ...@@ -986,7 +986,7 @@ void test_config_read__get_mapped(void)
cl_git_fail(git_config_get_mapped(&val, cfg, "header.key7", _test_map1, ARRAY_SIZE(_test_map1))); cl_git_fail(git_config_get_mapped(&val, cfg, "header.key7", _test_map1, ARRAY_SIZE(_test_map1)));
// check parsing int values /* check parsing int values */
cl_git_pass(git_config_get_mapped(&val, cfg, "header.key1", _test_map2, ARRAY_SIZE(_test_map2))); cl_git_pass(git_config_get_mapped(&val, cfg, "header.key1", _test_map2, ARRAY_SIZE(_test_map2)));
cl_git_pass(git_config_get_int32(&known_good, cfg, "header.key1")); cl_git_pass(git_config_get_int32(&known_good, cfg, "header.key1"));
cl_assert_equal_i(val, known_good); cl_assert_equal_i(val, known_good);
......
...@@ -107,4 +107,4 @@ void test_pack_midx__odb_create(void) ...@@ -107,4 +107,4 @@ void test_pack_midx__odb_create(void)
git_buf_dispose(&expected_midx); git_buf_dispose(&expected_midx);
cl_git_pass(git_futils_rmdir_r("./clone.git", NULL, GIT_RMDIR_REMOVE_FILES)); cl_git_pass(git_futils_rmdir_r("./clone.git", NULL, GIT_RMDIR_REMOVE_FILES));
} }
\ No newline at end of file
...@@ -72,7 +72,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, ...@@ -72,7 +72,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id,
.strings = &refspec_strs, .strings = &refspec_strs,
}; };
// create two commits in repo 1 and a reference to them /* create two commits in repo 1 and a reference to them */
{ {
git_oid empty_tree_id; git_oid empty_tree_id;
git_tree *empty_tree; git_tree *empty_tree;
...@@ -92,7 +92,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, ...@@ -92,7 +92,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id,
git_treebuilder_free(tb); git_treebuilder_free(tb);
} }
// fetch the reference via the remote /* fetch the reference via the remote */
{ {
git_remote *remote; git_remote *remote;
...@@ -103,7 +103,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, ...@@ -103,7 +103,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id,
git_remote_free(remote); git_remote_free(remote);
} }
// assert that repo2 references the second commit /* assert that repo2 references the second commit */
{ {
const git_oid *target; const git_oid *target;
git_reference *ref; git_reference *ref;
...@@ -113,7 +113,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, ...@@ -113,7 +113,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id,
git_reference_free(ref); git_reference_free(ref);
} }
// set the reference in repo1 to point to the older commit /* set the reference in repo1 to point to the older commit */
{ {
git_reference *ref; git_reference *ref;
git_reference *ref2; git_reference *ref2;
...@@ -124,7 +124,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id, ...@@ -124,7 +124,7 @@ void do_time_travelling_fetch(git_oid *commit1id, git_oid *commit2id,
git_reference_free(ref2); git_reference_free(ref2);
} }
// fetch the reference again /* fetch the reference again */
{ {
git_remote *remote; git_remote *remote;
...@@ -144,7 +144,7 @@ void test_remote_fetch__dont_update_refs_if_not_descendant_and_not_force(void) { ...@@ -144,7 +144,7 @@ void test_remote_fetch__dont_update_refs_if_not_descendant_and_not_force(void) {
do_time_travelling_fetch(&commit1id, &commit2id, false); do_time_travelling_fetch(&commit1id, &commit2id, false);
// assert that the reference in repo2 has not changed /* assert that the reference in repo2 has not changed */
cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME)); cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME));
target = git_reference_target(ref); target = git_reference_target(ref);
cl_assert_equal_b(git_oid_cmp(target, &commit2id), 0); cl_assert_equal_b(git_oid_cmp(target, &commit2id), 0);
...@@ -160,7 +160,7 @@ void test_remote_fetch__do_update_refs_if_not_descendant_and_force(void) { ...@@ -160,7 +160,7 @@ void test_remote_fetch__do_update_refs_if_not_descendant_and_force(void) {
do_time_travelling_fetch(&commit1id, &commit2id, true); do_time_travelling_fetch(&commit1id, &commit2id, true);
// assert that the reference in repo2 has changed /* assert that the reference in repo2 has changed */
cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME)); cl_git_pass(git_reference_lookup(&ref, repo2, REPO2_REFNAME));
target = git_reference_target(ref); target = git_reference_target(ref);
cl_assert_equal_b(git_oid_cmp(target, &commit1id), 0); cl_assert_equal_b(git_oid_cmp(target, &commit1id), 0);
......
#include "clar_libgit2.h"
void test_threads_atomic__atomic32_set(void)
{
git_atomic32 v = {0};
git_atomic32_set(&v, 1);
cl_assert_equal_i(v.val, 1);
}
void test_threads_atomic__atomic32_get(void)
{
git_atomic32 v = {1};
cl_assert_equal_i(git_atomic32_get(&v), 1);
}
void test_threads_atomic__atomic32_inc(void)
{
git_atomic32 v = {0};
cl_assert_equal_i(git_atomic32_inc(&v), 1);
cl_assert_equal_i(v.val, 1);
}
void test_threads_atomic__atomic32_add(void)
{
git_atomic32 v = {0};
cl_assert_equal_i(git_atomic32_add(&v, 1), 1);
cl_assert_equal_i(v.val, 1);
}
void test_threads_atomic__atomic32_dec(void)
{
git_atomic32 v = {1};
cl_assert_equal_i(git_atomic32_dec(&v), 0);
cl_assert_equal_i(v.val, 0);
}
void test_threads_atomic__atomic64_set(void)
{
#ifndef GIT_ARCH_64
cl_skip();
#else
git_atomic64 v = {0};
git_atomic64_set(&v, 1);
cl_assert_equal_i(v.val, 1);
#endif
}
void test_threads_atomic__atomic64_get(void)
{
#ifndef GIT_ARCH_64
cl_skip();
#else
git_atomic64 v = {1};
cl_assert_equal_i(git_atomic64_get(&v), 1);
#endif
}
void test_threads_atomic__atomic64_add(void)
{
#ifndef GIT_ARCH_64
cl_skip();
#else
git_atomic64 v = {0};
cl_assert_equal_i(git_atomic64_add(&v, 1), 1);
cl_assert_equal_i(v.val, 1);
#endif
}
void test_threads_atomic__cas_pointer(void)
{
int *value = NULL;
int newvalue1 = 1, newvalue2 = 2;
/* value is updated */
cl_assert_equal_p(git_atomic_compare_and_swap(&value, NULL, &newvalue1), NULL);
cl_assert_equal_p(value, &newvalue1);
/* value is not updated */
cl_assert_equal_p(git_atomic_compare_and_swap(&value, NULL, &newvalue2), &newvalue1);
cl_assert_equal_p(value, &newvalue1);
}
void test_threads_atomic__cas_intptr(void)
{
intptr_t value = 0;
intptr_t oldvalue;
intptr_t newvalue;
/* value is updated */
oldvalue = 0;
newvalue = 1;
cl_assert_equal_i((intptr_t)git_atomic_compare_and_swap(&value, (void *)oldvalue, (void *)newvalue), 0);
cl_assert_equal_i(value, 1);
/* value is not updated */
oldvalue = 0;
newvalue = 2;
cl_assert_equal_i((intptr_t)git_atomic_compare_and_swap(&value, (void *)oldvalue, (void *)newvalue), 1);
cl_assert_equal_i(value, 1);
}
void test_threads_atomic__swap(void)
{
int *value = NULL;
int newvalue = 1;
cl_assert_equal_p(git_atomic_swap(value, &newvalue), NULL);
cl_assert_equal_p(value, &newvalue);
cl_assert_equal_p(git_atomic_swap(value, NULL), &newvalue);
cl_assert_equal_p(value, NULL);
}
void test_threads_atomic__load_ptr(void)
{
int value = 1;
int *ptr = &value;
cl_assert_equal_p(git_atomic_load(ptr), &value);
}
void test_threads_atomic__load_intptr(void)
{
intptr_t value = 1;
cl_assert_equal_i((intptr_t)git_atomic_load(value), 1);
}
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