mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-11-04 14:08:17 +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