mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-03 04:34:15 +00:00
Merge pull request #2676 from libgit2/cmn/threading
Threading and crypto libraries
This commit is contained in:
commit
7bb639911b
@ -58,6 +58,11 @@ dependencies, it can make use of a few libraries to add to it:
|
||||
- LibSSH2 to enable the SSH transport
|
||||
- iconv (OSX) to handle the HFS+ path encoding peculiarities
|
||||
|
||||
Threading
|
||||
=========
|
||||
|
||||
See [THREADING](THREADING.md) for information
|
||||
|
||||
Building libgit2 - Using CMake
|
||||
==============================
|
||||
|
||||
|
79
THREADING.md
Normal file
79
THREADING.md
Normal file
@ -0,0 +1,79 @@
|
||||
Threads in libgit2
|
||||
==================
|
||||
|
||||
You may safely use any libgit2 object from any thread, though there
|
||||
may be issues depending on the cryptographic libraries libgit2 or its
|
||||
dependencies link to (more on this later). For libgit2 itself,
|
||||
provided you take the following into consideration you won't run into
|
||||
issues:
|
||||
|
||||
Sharing objects
|
||||
---------------
|
||||
|
||||
Use an object from a single thread at a time. Most data structures do
|
||||
not guard against concurrent access themselves. This is because they
|
||||
are rarely used in isolation and it makes more sense to synchronize
|
||||
access via a larger lock or similar mechanism.
|
||||
|
||||
There are some objects which are read-only/immutable and are thus safe
|
||||
to share across threads, such as references and configuration
|
||||
snapshots.
|
||||
|
||||
Error messages
|
||||
--------------
|
||||
|
||||
The error message is thread-local. The `giterr_last()` call must
|
||||
happen on the same thread as the error in order to get the
|
||||
message. Often this will be the case regardless, but if you use
|
||||
something like the GDC on MacOS (where code is executed on an
|
||||
arbitrary thread), the code must make sure to retrieve the error code
|
||||
on the thread where the error happened.
|
||||
|
||||
Threads and cryptographic libraries
|
||||
=======================================
|
||||
|
||||
On Windows
|
||||
----------
|
||||
|
||||
When built as a native Windows DLL, libgit2 uses WinCNG and WinHTTP,
|
||||
both of which are thread-safe. You do not need to do anything special.
|
||||
|
||||
When using libssh2 which itself uses WinCNG, there are no special
|
||||
steps necessary. If you are using a MinGW or similar environment where
|
||||
libssh2 uses OpenSSL or libgcrypt, then the non-Windows case affects
|
||||
you.
|
||||
|
||||
Non-Windows
|
||||
-----------
|
||||
|
||||
On the rest of the platforms, libgit2 uses OpenSSL to be able to use
|
||||
HTTPS as a transport. This library is made to be thread-implementation
|
||||
agnostic, and the users of the library must set which locking function
|
||||
it should use. This means that libgit2 cannot know what to set as the
|
||||
user of libgit2 may use OpenSSL independently and the locking settings
|
||||
must survive libgit2 shutting down.
|
||||
|
||||
libgit2 does provide a convenience function
|
||||
`git_openssl_set_locking()` to use the platform-native mutex
|
||||
mechanisms to perform the locking, which you may rely on if you do not
|
||||
want to use OpenSSL outside of libgit2, or you know that libgit2 will
|
||||
outlive the rest of the operations. It is not safe to use OpenSSL
|
||||
multi-threaded after libgit2's shutdown function has been called.
|
||||
|
||||
See the
|
||||
[OpenSSL documentation](https://www.openssl.org/docs/crypto/threads.html)
|
||||
on threading for more details.
|
||||
|
||||
libssh2 may be linked against OpenSSL or libgcrypt. If it uses
|
||||
OpenSSL, you only need to set up threading for OpenSSL once and the
|
||||
above paragraphs are enough. If it uses libgcrypt, then you need to
|
||||
set up its locking before using it multi-threaded. libgit2 has no
|
||||
direct connection to libgcrypt and thus has not convenience functions for
|
||||
it (but libgcrypt has macros). Read libgcrypt's
|
||||
[threading documentation for more information](http://www.gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html)
|
||||
|
||||
It is your responsibility as an application author or packager to know
|
||||
what your dependencies are linked against and to take the appropriate
|
||||
steps to ensure the cryptographic libraries are thread-safe. We agree
|
||||
that this situation is far from ideal but at this time it is something
|
||||
the application authors need to deal with.
|
@ -44,6 +44,22 @@ GIT_EXTERN(int) git_threads_init(void);
|
||||
*/
|
||||
GIT_EXTERN(void) git_threads_shutdown(void);
|
||||
|
||||
/**
|
||||
* Initialize the OpenSSL locks
|
||||
*
|
||||
* OpenSSL requires the application to determine how it performs
|
||||
* locking. This is a convenience function which libgit2 provides for
|
||||
* allocating and initializing the locks as well as setting the
|
||||
* locking function to use the system's native locking functions.
|
||||
*
|
||||
* The locking function will be cleared and the memory will be freed
|
||||
* when you call git_threads_sutdown().
|
||||
*
|
||||
* @return 0 on success, -1 if there are errors or if libgit2 was not
|
||||
* built with OpenSSL and threading support.
|
||||
*/
|
||||
GIT_EXTERN(int) git_openssl_set_locking(void);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
42
src/global.c
42
src/global.c
@ -64,8 +64,9 @@ void openssl_locking_function(int mode, int n, const char *file, int line)
|
||||
}
|
||||
}
|
||||
|
||||
static void shutdown_ssl(void)
|
||||
static void shutdown_ssl_locking(void)
|
||||
{
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
git__free(openssl_locks);
|
||||
}
|
||||
#endif
|
||||
@ -96,30 +97,35 @@ static void init_ssl(void)
|
||||
SSL_CTX_free(git__ssl_ctx);
|
||||
git__ssl_ctx = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int git_openssl_set_locking(void)
|
||||
{
|
||||
#ifdef GIT_SSL
|
||||
# ifdef GIT_THREADS
|
||||
{
|
||||
int num_locks, i;
|
||||
int num_locks, i;
|
||||
|
||||
num_locks = CRYPTO_num_locks();
|
||||
openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
|
||||
if (openssl_locks == NULL) {
|
||||
SSL_CTX_free(git__ssl_ctx);
|
||||
git__ssl_ctx = NULL;
|
||||
num_locks = CRYPTO_num_locks();
|
||||
openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
|
||||
GITERR_CHECK_ALLOC(openssl_locks);
|
||||
|
||||
for (i = 0; i < num_locks; i++) {
|
||||
if (git_mutex_init(&openssl_locks[i]) != 0) {
|
||||
giterr_set(GITERR_SSL, "failed to initialize openssl locks");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_locks; i++) {
|
||||
if (git_mutex_init(&openssl_locks[i]) != 0) {
|
||||
SSL_CTX_free(git__ssl_ctx);
|
||||
git__ssl_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CRYPTO_set_locking_callback(openssl_locking_function);
|
||||
}
|
||||
|
||||
git__on_shutdown(shutdown_ssl);
|
||||
CRYPTO_set_locking_callback(openssl_locking_function);
|
||||
git__on_shutdown(shutdown_ssl_locking);
|
||||
return 0;
|
||||
# else
|
||||
giterr_set(GITERR_THREAD, "libgit2 as not built with threads");
|
||||
return -1;
|
||||
# endif
|
||||
giterr_set(GITERR_SSL, "libgit2 was not built with OpenSSL support");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user