Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b45219f
Implement custom thread local storage for user of library
implausible Mar 29, 2021
7a76a33
checkout: cleanup duplication in checkout_create_the_new
implausible Aug 12, 2020
07493cc
thread checkout: move checkout buffers to tls
implausible Mar 29, 2021
e1a1eaa
thread checkout: add locks around shared state
implausible Aug 12, 2020
dc4e588
thread checkout: add locks around non thread-safe actions
implausible Apr 9, 2021
0739689
thread checkout: stub indirection for threading
implausible Aug 12, 2020
27f3c80
thread checkout: add threading to checkout_create_the_new
implausible Mar 29, 2021
37caa8d
meta: show build status for v1.3 branch
ethomson Feb 26, 2022
6b12762
online: test with https instead of git protocol
ethomson Jan 11, 2022
670415a
clone: update bitbucket tests
ethomson Mar 23, 2022
973d959
path: refactor ownership checks into current user and system
ethomson Apr 10, 2022
62d492d
repo: ensure that repo dir is owned by current user
ethomson Apr 11, 2022
e4eabb0
fs_path: mock ownership checks
ethomson Apr 12, 2022
caee92e
repo: test configuration ownership validation
ethomson Apr 11, 2022
f683806
repo: refactor global config loader function
ethomson Apr 11, 2022
eb8c3e5
repo: honor safe.directory during ownership checks
ethomson Apr 11, 2022
b58e905
repo: make ownership checks optional
ethomson Apr 12, 2022
a9eac6a
Merge pull request #6268 from libgit2/ethomson/ownership_13
ethomson Apr 12, 2022
1f39aac
meta: update version numbers for v1.3.1
ethomson Apr 12, 2022
23c24f8
meta: changelog for v1.3.1
ethomson Apr 12, 2022
1f5e7f9
Merge pull request #6271 from libgit2/ethomson/v1.3.1
ethomson Apr 12, 2022
6da6a10
Merge remote-tracking branch 'zawata/feature/custom-tls-for-external-…
zawata Apr 13, 2022
30d5c08
Merge remote-tracking branch 'zawata/multithread/checkout_create_the_…
zawata Apr 13, 2022
4b193b1
New checkout option: disabled_filters
julianmesa-gitkraken May 6, 2022
fe44f25
Merge branch 'disabled-filters-checkout' into libgit-next
ianhattendorf May 7, 2022
e78ee33
Fix degraded performance using GIT_USE_NSEC on repos cloned with GIT_…
julianmesa-gitkraken May 18, 2022
013d416
Merge pull request #7 from julianmesa-gitkraken/fix-nanoseconds-on-no…
ianhattendorf May 18, 2022
3ad710a
Fix the GIT_USE_NSEC performance fix
julianmesa-gitkraken May 26, 2022
4c98283
Merge pull request #8 from julianmesa-gitkraken/fix-nsecs-fix
ianhattendorf May 26, 2022
8254d2e
Do not add the .gitignore file if it not existing
julianmesa-gitkraken Jun 20, 2022
45f0e26
iterator: don't stat directories
julianmesa-gitkraken Jun 20, 2022
a4c112d
path: use fstatat instead of lstat
julianmesa-gitkraken Jun 20, 2022
110e29c
iterator: replace O(N) skip-to-start with O(log N)
julianmesa-gitkraken Jun 20, 2022
8bbbfab
push ignore frames lazily
julianmesa-gitkraken Jun 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Implement custom thread local storage for user of library
  • Loading branch information
implausible authored and zawata committed Jan 26, 2022
commit b45219f179f4c00189e069425e31ce42547e423b
66 changes: 66 additions & 0 deletions include/git2/sys/custom_tls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.
*/
#ifndef INCLUDE_sys_custom_tls_h__
#define INCLUDE_sys_custom_tls_h__

#include "git2/common.h"

GIT_BEGIN_DECL

/**
* Used to retrieve a pointer from a user of the library to pass to a newly
* created internal libgit2 thread. This should allow users of the library to
* establish a context that spans an internally threaded operation. This can
* useful for libraries that leverage callbacks used in an internally threaded
* routine.
*/
typedef void *GIT_CALLBACK(git_retrieve_tls_for_internal_thread_cb)(void);

/**
* This callback will be called when a thread is exiting so that a user
* of the library can clean up their thread local storage.
*/
typedef void GIT_CALLBACK(git_set_tls_on_internal_thread_cb)(void *payload);

/**
* This callback will be called when a thread is exiting so that a user
* of the library can clean up their thread local storage.
*/
typedef void GIT_CALLBACK(git_teardown_tls_on_internal_thread_cb)(void);

/**
* Sets the callbacks for custom thread local storage used by internally
* created libgit2 threads. This allows users of the library an opportunity
* to set thread local storage for internal threads based on the creating
* thread.
*
* @param retrieve_storage_for_internal_thread Used to retrieve a pointer on
* a thread before spawning child
* threads. This pointer will be
* passed to set_storage_on_thread
* in the newly spawned threads.
* @param set_storage_on_thread When a thread is spawned internally in libgit2,
* whatever pointer was retrieved in the calling
* thread by retrieve_storage_for_internal_thread
* will be passed to this callback in the newly
* spawned thread.
* @param teardown_storage_on_thread Before an internally spawned thread exits,
* this method will be called allowing a user
* of the library an opportunity to clean up
* any thread local storage they set up on
* the internal thread.
* @return 0 on success, or an error code. (use git_error_last for information
* about the error)
*/
GIT_EXTERN(int) git_custom_tls_set_callbacks(
git_retrieve_tls_for_internal_thread_cb retrieve_storage_for_internal_thread,
git_set_tls_on_internal_thread_cb set_storage_on_thread,
git_teardown_tls_on_internal_thread_cb teardown_storage_on_thread);

GIT_END_DECL

#endif
124 changes: 124 additions & 0 deletions src/custom_tls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* 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 "custom_tls.h"
#include "runtime.h"

#ifdef GIT_THREADS

#ifdef GIT_WIN32
# include "win32/thread.h"
#else
# include "unix/pthread.h"
#endif

struct git_custom_tls_callbacks {
git_retrieve_tls_for_internal_thread_cb retrieve_storage_for_internal_thread;

git_set_tls_on_internal_thread_cb set_storage_on_thread;

git_teardown_tls_on_internal_thread_cb teardown_storage_on_thread;

git_rwlock lock;
};

struct git_custom_tls_callbacks git__custom_tls = { 0, 0, 0 };

static void git_custom_tls_global_shutdown(void)
{
if (git_rwlock_wrlock(&git__custom_tls.lock) < 0)
return;

git__custom_tls.retrieve_storage_for_internal_thread = 0;
git__custom_tls.set_storage_on_thread = 0;
git__custom_tls.teardown_storage_on_thread = 0;

git_rwlock_wrunlock(&git__custom_tls.lock);
git_rwlock_free(&git__custom_tls.lock);
}

int git_custom_tls__global_init(void)
{
if (git_rwlock_init(&git__custom_tls.lock) < 0)
return -1;

return git_runtime_shutdown_register(git_custom_tls_global_shutdown);
}

int git_custom_tls_set_callbacks(
git_retrieve_tls_for_internal_thread_cb retrieve_storage_for_internal_thread,
git_set_tls_on_internal_thread_cb set_storage_on_thread,
git_teardown_tls_on_internal_thread_cb teardown_storage_on_thread)
{
/* We want to ensure that all callbacks are set or not set in totality.
* It does not make sense to have a subset of callbacks set.
*/
assert((retrieve_storage_for_internal_thread && set_storage_on_thread &&
teardown_storage_on_thread) || !(retrieve_storage_for_internal_thread &&
set_storage_on_thread && teardown_storage_on_thread));

if (git_rwlock_wrlock(&git__custom_tls.lock) < 0) {
git_error_set(GIT_ERROR_OS, "failed to lock custom thread local storage");
return -1;
}

git__custom_tls.retrieve_storage_for_internal_thread =
retrieve_storage_for_internal_thread;
git__custom_tls.set_storage_on_thread =
set_storage_on_thread;
git__custom_tls.teardown_storage_on_thread =
teardown_storage_on_thread;

git_rwlock_wrunlock(&git__custom_tls.lock);
return 0;
}

int git_custom_tls__init(git_custom_tls *tls)
{
if (git_rwlock_rdlock(&git__custom_tls.lock) < 0) {
git_error_set(GIT_ERROR_OS, "failed to lock custom thread local storage");
return -1;
}

/* We try to ensure that all 3 callbacks must be set or not set.
* It would not make sense to have a subset of the callbacks set.
*/
if (!git__custom_tls.retrieve_storage_for_internal_thread) {
tls->set_storage_on_thread = NULL;
tls->teardown_storage_on_thread = NULL;
tls->payload = NULL;
} else {
/* We set these on a struct so that if for whatever reason the opts are changed
* at least the opts will remain consistent for any given thread already in
* motion.
*/
tls->set_storage_on_thread = git__custom_tls.set_storage_on_thread;
tls->teardown_storage_on_thread = git__custom_tls.teardown_storage_on_thread;
tls->payload = git__custom_tls.retrieve_storage_for_internal_thread();
}

git_rwlock_rdunlock(&git__custom_tls.lock);
return 0;
}

#else

int git_custom_tls__global_init(void)
{
return 0;
}

int git_custom_tls_set_callbacks(
git_retrieve_tls_for_internal_thread_cb retrieve_storage_for_internal_thread,
git_set_tls_on_internal_thread_cb set_storage_on_thread,
git_teardown_tls_on_internal_thread_cb teardown_storage_on_thread)
{
return 0;
}

#endif
33 changes: 33 additions & 0 deletions src/custom_tls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef INCLUDE_custom_tls_h__
#define INCLUDE_custom_tls_h__

#include "common.h"
#include "git2/sys/custom_tls.h"

int git_custom_tls__global_init(void);

#ifdef GIT_THREADS

typedef struct {
git_set_tls_on_internal_thread_cb set_storage_on_thread;

git_teardown_tls_on_internal_thread_cb teardown_storage_on_thread;

/**
* payload should be set on the thread that is spawning the child thread.
* This payload will be passed to set_storage_on_thread
*/
void *payload;
} git_custom_tls;

int git_custom_tls__init(git_custom_tls *tls);

#endif

#endif
2 changes: 2 additions & 0 deletions src/libgit2.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "transports/smart.h"
#include "transports/http.h"
#include "transports/ssh.h"
#include "custom_tls.h"

#ifdef GIT_WIN32
# include "win32/w32_leakcheck.h"
Expand Down Expand Up @@ -69,6 +70,7 @@ int git_libgit2_init(void)
git_allocator_global_init,
git_threadstate_global_init,
git_threads_global_init,
git_custom_tls__global_init,
git_hash_global_init,
git_sysdir_global_init,
git_filter_global_init,
Expand Down
73 changes: 73 additions & 0 deletions src/unix/pthread.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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 "pthread.h"
#include "thread.h"
#include "runtime.h"

git_tlsdata_key thread_handle;

static void git_threads_global_shutdown(void) {
git_tlsdata_dispose(thread_handle);
}

int git_threads_global_init(void) {
int error = git_tlsdata_init(&thread_handle, NULL);
if (error != 0) {
return error;
}

return git_runtime_shutdown_register(git_threads_global_shutdown);
}

static void *git_unix__threadproc(void *arg)
{
void *result;
int error;
git_thread *thread = arg;

error = git_tlsdata_set(thread_handle, thread);
if (error != 0) {
return NULL;
}

if (thread->tls.set_storage_on_thread) {
thread->tls.set_storage_on_thread(thread->tls.payload);
}

result = thread->proc(thread->param);

if (thread->tls.teardown_storage_on_thread) {
thread->tls.teardown_storage_on_thread();
}

return result;
}

int git_thread_create(
git_thread *thread,
void *(*start_routine)(void*),
void *arg)
{

thread->proc = start_routine;
thread->param = arg;
if (git_custom_tls__init(&thread->tls) < 0)
return -1;

return pthread_create(&thread->thread, NULL, git_unix__threadproc, thread);
}

void git_thread_exit(void *value)
{
git_thread *thread = git_tlsdata_get(thread_handle);

if (thread && thread->tls.teardown_storage_on_thread)
thread->tls.teardown_storage_on_thread();

return pthread_exit(value);
}
15 changes: 11 additions & 4 deletions src/unix/pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,25 @@
#ifndef INCLUDE_unix_pthread_h__
#define INCLUDE_unix_pthread_h__

#include "../custom_tls.h"

typedef struct {
pthread_t thread;
void *(*proc)(void *);
void *param;
git_custom_tls tls;
} git_thread;

GIT_INLINE(int) git_threads_global_init(void) { return 0; }
int git_threads_global_init(void);

#define git_thread_create(git_thread_ptr, start_routine, arg) \
pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg)
int git_thread_create(
git_thread *thread,
void *(*start_routine)(void*),
void *arg);
#define git_thread_join(git_thread_ptr, status) \
pthread_join((git_thread_ptr)->thread, status)
#define git_thread_currentid() ((size_t)(pthread_self()))
#define git_thread_exit(retval) pthread_exit(retval)
void git_thread_exit(void *value);

/* Git Mutex */
#define git_mutex pthread_mutex_t
Expand Down
17 changes: 15 additions & 2 deletions src/win32/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,19 @@ static DWORD fls_index;
static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
{
git_thread *thread = lpParameter;

/* Set the current thread for `git_thread_exit` */
FlsSetValue(fls_index, thread);

if (thread->tls.set_storage_on_thread) {
thread->tls.set_storage_on_thread(thread->tls.payload);
}

thread->result = thread->proc(thread->param);

if (thread->tls.teardown_storage_on_thread) {
thread->tls.teardown_storage_on_thread();
}

return CLEAN_THREAD_EXIT;
}

Expand Down Expand Up @@ -72,6 +79,9 @@ int git_thread_create(
thread->result = NULL;
thread->param = arg;
thread->proc = start_routine;
if (git_custom_tls__init(&thread->tls) < 0)
return -1;

thread->thread = CreateThread(
NULL, 0, git_win32__threadproc, thread, 0, NULL);

Expand Down Expand Up @@ -107,8 +117,11 @@ void git_thread_exit(void *value)
{
git_thread *thread = FlsGetValue(fls_index);

if (thread)
if (thread) {
if (thread->tls.teardown_storage_on_thread)
thread->tls.teardown_storage_on_thread();
thread->result = value;
}

ExitThread(CLEAN_THREAD_EXIT);
}
Expand Down
Loading