mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 22:25:04 +00:00
threads: Fix the shared global state with TLS
See `global.c` for a description of what we're doing. When libgit2 is built with GIT_THREADS support, the threading system must be explicitly initialized with `git_threads_init()`.
This commit is contained in:
parent
b0b2dd5ecc
commit
a15c550db8
@ -11,6 +11,7 @@
|
|||||||
#include "git2/version.h"
|
#include "git2/version.h"
|
||||||
|
|
||||||
#include "git2/common.h"
|
#include "git2/common.h"
|
||||||
|
#include "git2/threads.h"
|
||||||
#include "git2/errors.h"
|
#include "git2/errors.h"
|
||||||
#include "git2/zlib.h"
|
#include "git2/zlib.h"
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#ifndef INCLUDE_git_common_h__
|
#ifndef INCLUDE_git_common_h__
|
||||||
#define INCLUDE_git_common_h__
|
#define INCLUDE_git_common_h__
|
||||||
|
|
||||||
#include "thread-utils.h"
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@ -38,18 +37,6 @@
|
|||||||
# define GIT_EXTERN(type) extern type
|
# define GIT_EXTERN(type) extern type
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Declare a public TLS symbol exported for application use. */
|
|
||||||
#if __GNUC__ >= 4
|
|
||||||
# define GIT_EXTERN_TLS(type) extern \
|
|
||||||
__attribute__((visibility("default"))) \
|
|
||||||
GIT_TLS \
|
|
||||||
type
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
# define GIT_EXTERN_TLS(type) __declspec(dllexport) GIT_TLS type
|
|
||||||
#else
|
|
||||||
# define GIT_EXTERN_TLS(type) extern GIT_TLS type
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Declare a function as always inlined. */
|
/** Declare a function as always inlined. */
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# define GIT_INLINE(type) static __inline type
|
# define GIT_INLINE(type) static __inline type
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009-2011 the libgit2 contributors
|
|
||||||
*
|
|
||||||
* 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_git_thread_utils_h__
|
|
||||||
#define INCLUDE_git_thread_utils_h__
|
|
||||||
|
|
||||||
/*
|
|
||||||
* How TLS works is compiler+platform dependant
|
|
||||||
* Sources: http://en.wikipedia.org/wiki/Thread-Specific_Storage
|
|
||||||
* http://predef.sourceforge.net/precomp.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef GIT_THREADS
|
|
||||||
# define GIT_HAS_TLS 1
|
|
||||||
|
|
||||||
/* No TLS in Cygwin */
|
|
||||||
# if defined(__CHECKER__) || defined(__CYGWIN__)
|
|
||||||
# undef GIT_HAS_TLS
|
|
||||||
# define GIT_TLS
|
|
||||||
|
|
||||||
/* No TLS in Mach binaries for Mac OS X */
|
|
||||||
# elif defined(__APPLE__) && defined(__MACH__)
|
|
||||||
# undef GIT_TLS
|
|
||||||
# define GIT_TLS
|
|
||||||
|
|
||||||
/* Normal TLS for GCC */
|
|
||||||
# elif defined(__GNUC__) || \
|
|
||||||
defined(__SUNPRO_C) || \
|
|
||||||
defined(__SUNPRO_CC) || \
|
|
||||||
defined(__xlc__) || \
|
|
||||||
defined(__xlC__)
|
|
||||||
# define GIT_TLS __thread
|
|
||||||
|
|
||||||
/* ICC may run on Windows or Linux */
|
|
||||||
# elif defined(__INTEL_COMPILER)
|
|
||||||
# if defined(_WIN32) || defined(_WIN32_CE)
|
|
||||||
# define GIT_TLS __declspec(thread)
|
|
||||||
# else
|
|
||||||
# define GIT_TLS __thread
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/* Declspec for MSVC in Win32 */
|
|
||||||
# elif defined(_WIN32) || \
|
|
||||||
defined(_WIN32_CE) || \
|
|
||||||
defined(__BORLANDC__)
|
|
||||||
# define GIT_TLS __declspec(thread)
|
|
||||||
|
|
||||||
/* Other platform; no TLS */
|
|
||||||
# else
|
|
||||||
# undef GIT_HAS_TLS
|
|
||||||
# define GIT_TLS /* nothing: tls vars are thread-global */
|
|
||||||
# endif
|
|
||||||
#else /* Disable TLS if libgit2 is not threadsafe */
|
|
||||||
# define GIT_TLS
|
|
||||||
#endif /* GIT_THREADS */
|
|
||||||
|
|
||||||
#endif /* INCLUDE_git_thread_utils_h__ */
|
|
48
include/git2/threads.h
Normal file
48
include/git2/threads.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2011 the libgit2 contributors
|
||||||
|
*
|
||||||
|
* 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_git_threads_h__
|
||||||
|
#define INCLUDE_git_threads_h__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file git2/threads.h
|
||||||
|
* @brief Library level thread functions
|
||||||
|
* @defgroup git_thread Threading functions
|
||||||
|
* @ingroup Git
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
GIT_BEGIN_DECL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init the threading system.
|
||||||
|
*
|
||||||
|
* If libgit2 has been built with GIT_THREADS
|
||||||
|
* on, this function must be called once before
|
||||||
|
* any other library functions.
|
||||||
|
*
|
||||||
|
* If libgit2 has been built without GIT_THREADS
|
||||||
|
* support, this function is a no-op.
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(void) git_threads_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown the threading system.
|
||||||
|
*
|
||||||
|
* If libgit2 has been built with GIT_THREADS
|
||||||
|
* on, this function must be called before shutting
|
||||||
|
* down the library.
|
||||||
|
*
|
||||||
|
* If libgit2 has been built without GIT_THREADS
|
||||||
|
* support, this function is a no-op.
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(void) git_threads_shutdown(void);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
GIT_END_DECL
|
||||||
|
#endif
|
||||||
|
|
@ -8,7 +8,6 @@
|
|||||||
#define INCLUDE_common_h__
|
#define INCLUDE_common_h__
|
||||||
|
|
||||||
#include "git2/common.h"
|
#include "git2/common.h"
|
||||||
#include "git2/thread-utils.h"
|
|
||||||
#include "cc-compat.h"
|
#include "cc-compat.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
32
src/errors.c
32
src/errors.c
@ -5,13 +5,9 @@
|
|||||||
* a Linking Exception. For full terms see the included COPYING file.
|
* a Linking Exception. For full terms see the included COPYING file.
|
||||||
*/
|
*/
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "git2/thread-utils.h" /* for GIT_TLS */
|
#include "global.h"
|
||||||
#include "thread-utils.h" /* for GIT_TLS */
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
static GIT_TLS char g_last_error[1024];
|
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
int num;
|
int num;
|
||||||
const char *str;
|
const char *str;
|
||||||
@ -59,19 +55,26 @@ const char *git_strerror(int num)
|
|||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ERROR_MAX_LEN 1024
|
||||||
|
|
||||||
void git___rethrow(const char *msg, ...)
|
void git___rethrow(const char *msg, ...)
|
||||||
{
|
{
|
||||||
char new_error[1024];
|
char new_error[ERROR_MAX_LEN];
|
||||||
|
char *last_error;
|
||||||
char *old_error = NULL;
|
char *old_error = NULL;
|
||||||
|
|
||||||
va_list va;
|
va_list va;
|
||||||
|
|
||||||
|
last_error = GIT_GLOBAL->error.last;
|
||||||
|
|
||||||
va_start(va, msg);
|
va_start(va, msg);
|
||||||
vsnprintf(new_error, sizeof(new_error), msg, va);
|
vsnprintf(new_error, ERROR_MAX_LEN, msg, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
old_error = git__strdup(g_last_error);
|
old_error = git__strdup(last_error);
|
||||||
snprintf(g_last_error, sizeof(g_last_error), "%s \n - %s", new_error, old_error);
|
|
||||||
|
snprintf(last_error, ERROR_MAX_LEN, "%s \n - %s", new_error, old_error);
|
||||||
|
|
||||||
git__free(old_error);
|
git__free(old_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,19 +83,22 @@ void git___throw(const char *msg, ...)
|
|||||||
va_list va;
|
va_list va;
|
||||||
|
|
||||||
va_start(va, msg);
|
va_start(va, msg);
|
||||||
vsnprintf(g_last_error, sizeof(g_last_error), msg, va);
|
vsnprintf(GIT_GLOBAL->error.last, ERROR_MAX_LEN, msg, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *git_lasterror(void)
|
const char *git_lasterror(void)
|
||||||
{
|
{
|
||||||
if (!g_last_error[0])
|
char *last_error = GIT_GLOBAL->error.last;
|
||||||
|
|
||||||
|
if (!last_error[0])
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return g_last_error;
|
return last_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void git_clearerror(void)
|
void git_clearerror(void)
|
||||||
{
|
{
|
||||||
g_last_error[0] = '\0';
|
char *last_error = GIT_GLOBAL->error.last;
|
||||||
|
last_error[0] = '\0';
|
||||||
}
|
}
|
||||||
|
134
src/global.c
Normal file
134
src/global.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2011 the libgit2 contributors
|
||||||
|
*
|
||||||
|
* 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 "global.h"
|
||||||
|
#include "git2/threads.h"
|
||||||
|
#include "thread-utils.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the global state with TLS
|
||||||
|
*
|
||||||
|
* If libgit2 is built with GIT_THREADS enabled,
|
||||||
|
* the `git_threads_init()` function must be called
|
||||||
|
* before calling any other function of the library.
|
||||||
|
*
|
||||||
|
* This function allocates a TLS index (using pthreads
|
||||||
|
* or the native Win32 API) to store the global state
|
||||||
|
* on a per-thread basis.
|
||||||
|
*
|
||||||
|
* Any internal method that requires global state will
|
||||||
|
* then call `git__global_state()` which returns a pointer
|
||||||
|
* to the global state structure; this pointer is lazily
|
||||||
|
* allocated on each thread.
|
||||||
|
*
|
||||||
|
* Before shutting down the library, the
|
||||||
|
* `git_threads_shutdown` method must be called to free
|
||||||
|
* the previously reserved TLS index.
|
||||||
|
*
|
||||||
|
* If libgit2 is built without threading support, the
|
||||||
|
* `git__global_statestate()` 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 DWORD _tls_index;
|
||||||
|
static int _tls_init = 0;
|
||||||
|
|
||||||
|
void git_threads_init(void)
|
||||||
|
{
|
||||||
|
if (_tls_init)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_tls_index = TlsAlloc();
|
||||||
|
_tls_init = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void git_threads_shutdown(void)
|
||||||
|
{
|
||||||
|
TlsFree(_tls_index);
|
||||||
|
_tls_init = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_global_st *git__global_state(void)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if ((ptr = TlsGetValue(_tls_index)) != NULL)
|
||||||
|
return ptr;
|
||||||
|
|
||||||
|
ptr = malloc(sizeof(git_global_st));
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(ptr, 0x0, sizeof(git_global_st));
|
||||||
|
TlsSetValue(_tls_index, ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
|
||||||
|
|
||||||
|
static pthread_key_t _tls_key;
|
||||||
|
static int _tls_init = 0;
|
||||||
|
|
||||||
|
static void cb__free_status(void *st)
|
||||||
|
{
|
||||||
|
free(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
void git_threads_init(void)
|
||||||
|
{
|
||||||
|
if (_tls_init)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pthread_key_create(&_tls_key, &cb__free_status);
|
||||||
|
_tls_init = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void git_threads_shutdown(void)
|
||||||
|
{
|
||||||
|
pthread_key_delete(_tls_key);
|
||||||
|
_tls_init = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_global_st *git__global_state(void)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if ((ptr = pthread_getspecific(_tls_key)) != NULL)
|
||||||
|
return ptr;
|
||||||
|
|
||||||
|
ptr = malloc(sizeof(git_global_st));
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(ptr, 0x0, sizeof(git_global_st));
|
||||||
|
pthread_setspecific(_tls_key, ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static git_global_st __state;
|
||||||
|
|
||||||
|
void git_threads_init(void)
|
||||||
|
{
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
void git_threads_shutdown(void)
|
||||||
|
{
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
git_global_st *git__global_state(void)
|
||||||
|
{
|
||||||
|
return &__state;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* GIT_THREADS */
|
24
src/global.h
Normal file
24
src/global.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2011 the libgit2 contributors
|
||||||
|
*
|
||||||
|
* 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_global_h__
|
||||||
|
#define INCLUDE_global_h__
|
||||||
|
|
||||||
|
#include "mwindow.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
char last[1024];
|
||||||
|
} error;
|
||||||
|
|
||||||
|
git_mwindow_ctl mem_ctl;
|
||||||
|
} git_global_st;
|
||||||
|
|
||||||
|
git_global_st *git__global_state(void);
|
||||||
|
|
||||||
|
#define GIT_GLOBAL (git__global_state())
|
||||||
|
|
||||||
|
#endif
|
@ -10,6 +10,7 @@
|
|||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "fileops.h"
|
#include "fileops.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
#define DEFAULT_WINDOW_SIZE \
|
#define DEFAULT_WINDOW_SIZE \
|
||||||
(sizeof(void*) >= 8 \
|
(sizeof(void*) >= 8 \
|
||||||
@ -20,21 +21,15 @@
|
|||||||
((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL))
|
((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need this because each process is only allowed a specific amount
|
* These are the global options for mmmap limits.
|
||||||
* of memory. Making it writable should generate one instance per
|
* TODO: allow the user to change these
|
||||||
* process, but we still need to set a couple of variables.
|
|
||||||
*/
|
*/
|
||||||
|
static struct {
|
||||||
static git_mwindow_ctl ctl = {
|
size_t window_size;
|
||||||
0,
|
size_t mapped_limit;
|
||||||
0,
|
} _mw_options = {
|
||||||
DEFAULT_WINDOW_SIZE,
|
DEFAULT_WINDOW_SIZE,
|
||||||
DEFAULT_MAPPED_LIMIT,
|
DEFAULT_MAPPED_LIMIT,
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
{0, 0, 0, 0, 0}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -43,28 +38,29 @@ static git_mwindow_ctl ctl = {
|
|||||||
*/
|
*/
|
||||||
void git_mwindow_free_all(git_mwindow_file *mwf)
|
void git_mwindow_free_all(git_mwindow_file *mwf)
|
||||||
{
|
{
|
||||||
|
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
/*
|
/*
|
||||||
* Remove these windows from the global list
|
* Remove these windows from the global list
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < ctl.windowfiles.length; ++i){
|
for (i = 0; i < ctl->windowfiles.length; ++i){
|
||||||
if (git_vector_get(&ctl.windowfiles, i) == mwf) {
|
if (git_vector_get(&ctl->windowfiles, i) == mwf) {
|
||||||
git_vector_remove(&ctl.windowfiles, i);
|
git_vector_remove(&ctl->windowfiles, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctl.windowfiles.length == 0) {
|
if (ctl->windowfiles.length == 0) {
|
||||||
git_vector_free(&ctl.windowfiles);
|
git_vector_free(&ctl->windowfiles);
|
||||||
ctl.windowfiles.contents = NULL;
|
ctl->windowfiles.contents = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (mwf->windows) {
|
while (mwf->windows) {
|
||||||
git_mwindow *w = mwf->windows;
|
git_mwindow *w = mwf->windows;
|
||||||
assert(w->inuse_cnt == 0);
|
assert(w->inuse_cnt == 0);
|
||||||
|
|
||||||
ctl.mapped -= w->window_map.len;
|
ctl->mapped -= w->window_map.len;
|
||||||
ctl.open_windows--;
|
ctl->open_windows--;
|
||||||
|
|
||||||
git_futils_mmap_free(&w->window_map);
|
git_futils_mmap_free(&w->window_map);
|
||||||
|
|
||||||
@ -115,6 +111,7 @@ void git_mwindow_scan_lru(
|
|||||||
*/
|
*/
|
||||||
static int git_mwindow_close_lru(git_mwindow_file *mwf)
|
static int git_mwindow_close_lru(git_mwindow_file *mwf)
|
||||||
{
|
{
|
||||||
|
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
git_mwindow *lru_w = NULL, *lru_l = NULL, **list = &mwf->windows;
|
git_mwindow *lru_w = NULL, *lru_l = NULL, **list = &mwf->windows;
|
||||||
|
|
||||||
@ -122,16 +119,16 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf)
|
|||||||
if(mwf->windows)
|
if(mwf->windows)
|
||||||
git_mwindow_scan_lru(mwf, &lru_w, &lru_l);
|
git_mwindow_scan_lru(mwf, &lru_w, &lru_l);
|
||||||
|
|
||||||
for (i = 0; i < ctl.windowfiles.length; ++i) {
|
for (i = 0; i < ctl->windowfiles.length; ++i) {
|
||||||
git_mwindow *last = lru_w;
|
git_mwindow *last = lru_w;
|
||||||
git_mwindow_file *cur = git_vector_get(&ctl.windowfiles, i);
|
git_mwindow_file *cur = git_vector_get(&ctl->windowfiles, i);
|
||||||
git_mwindow_scan_lru(cur, &lru_w, &lru_l);
|
git_mwindow_scan_lru(cur, &lru_w, &lru_l);
|
||||||
if (lru_w != last)
|
if (lru_w != last)
|
||||||
list = &cur->windows;
|
list = &cur->windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lru_w) {
|
if (lru_w) {
|
||||||
ctl.mapped -= lru_w->window_map.len;
|
ctl->mapped -= lru_w->window_map.len;
|
||||||
git_futils_mmap_free(&lru_w->window_map);
|
git_futils_mmap_free(&lru_w->window_map);
|
||||||
|
|
||||||
if (lru_l)
|
if (lru_l)
|
||||||
@ -140,7 +137,7 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf)
|
|||||||
*list = lru_w->next;
|
*list = lru_w->next;
|
||||||
|
|
||||||
git__free(lru_w);
|
git__free(lru_w);
|
||||||
ctl.open_windows--;
|
ctl->open_windows--;
|
||||||
|
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -148,9 +145,14 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf)
|
|||||||
return git__throw(GIT_ERROR, "Failed to close memory window. Couln't find LRU");
|
return git__throw(GIT_ERROR, "Failed to close memory window. Couln't find LRU");
|
||||||
}
|
}
|
||||||
|
|
||||||
static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, git_off_t size, git_off_t offset)
|
static git_mwindow *new_window(
|
||||||
|
git_mwindow_file *mwf,
|
||||||
|
git_file fd,
|
||||||
|
git_off_t size,
|
||||||
|
git_off_t offset)
|
||||||
{
|
{
|
||||||
size_t walign = ctl.window_size / 2;
|
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
|
||||||
|
size_t walign = _mw_options.window_size / 2;
|
||||||
git_off_t len;
|
git_off_t len;
|
||||||
git_mwindow *w;
|
git_mwindow *w;
|
||||||
|
|
||||||
@ -162,16 +164,16 @@ static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, git_off_t siz
|
|||||||
w->offset = (offset / walign) * walign;
|
w->offset = (offset / walign) * walign;
|
||||||
|
|
||||||
len = size - w->offset;
|
len = size - w->offset;
|
||||||
if (len > (git_off_t)ctl.window_size)
|
if (len > (git_off_t)_mw_options.window_size)
|
||||||
len = (git_off_t)ctl.window_size;
|
len = (git_off_t)_mw_options.window_size;
|
||||||
|
|
||||||
ctl.mapped += (size_t)len;
|
ctl->mapped += (size_t)len;
|
||||||
|
|
||||||
while(ctl.mapped_limit < ctl.mapped &&
|
while (_mw_options.mapped_limit < ctl->mapped &&
|
||||||
git_mwindow_close_lru(mwf) == GIT_SUCCESS) {}
|
git_mwindow_close_lru(mwf) == GIT_SUCCESS) /* nop */;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We treat ctl.mapped_limit as a soft limit. If we can't find a
|
* We treat _mw_options.mapped_limit as a soft limit. If we can't find a
|
||||||
* window to close and are above the limit, we still mmap the new
|
* window to close and are above the limit, we still mmap the new
|
||||||
* window.
|
* window.
|
||||||
*/
|
*/
|
||||||
@ -179,14 +181,14 @@ static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, git_off_t siz
|
|||||||
if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < GIT_SUCCESS)
|
if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < GIT_SUCCESS)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ctl.mmap_calls++;
|
ctl->mmap_calls++;
|
||||||
ctl.open_windows++;
|
ctl->open_windows++;
|
||||||
|
|
||||||
if (ctl.mapped > ctl.peak_mapped)
|
if (ctl->mapped > ctl->peak_mapped)
|
||||||
ctl.peak_mapped = ctl.mapped;
|
ctl->peak_mapped = ctl->mapped;
|
||||||
|
|
||||||
if (ctl.open_windows > ctl.peak_open_windows)
|
if (ctl->open_windows > ctl->peak_open_windows)
|
||||||
ctl.peak_open_windows = ctl.open_windows;
|
ctl->peak_open_windows = ctl->open_windows;
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
|
|
||||||
@ -199,9 +201,14 @@ cleanup:
|
|||||||
* Open a new window, closing the least recenty used until we have
|
* Open a new window, closing the least recenty used until we have
|
||||||
* enough space. Don't forget to add it to your list
|
* enough space. Don't forget to add it to your list
|
||||||
*/
|
*/
|
||||||
unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor,
|
unsigned char *git_mwindow_open(
|
||||||
git_off_t offset, int extra, unsigned int *left)
|
git_mwindow_file *mwf,
|
||||||
|
git_mwindow **cursor,
|
||||||
|
git_off_t offset,
|
||||||
|
int extra,
|
||||||
|
unsigned int *left)
|
||||||
{
|
{
|
||||||
|
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
|
||||||
git_mwindow *w = *cursor;
|
git_mwindow *w = *cursor;
|
||||||
|
|
||||||
if (!w || !git_mwindow_contains(w, offset + extra)) {
|
if (!w || !git_mwindow_contains(w, offset + extra)) {
|
||||||
@ -229,7 +236,7 @@ unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor,
|
|||||||
|
|
||||||
/* If we changed w, store it in the cursor */
|
/* If we changed w, store it in the cursor */
|
||||||
if (w != *cursor) {
|
if (w != *cursor) {
|
||||||
w->last_used = ctl.used_ctr++;
|
w->last_used = ctl->used_ctr++;
|
||||||
w->inuse_cnt++;
|
w->inuse_cnt++;
|
||||||
*cursor = w;
|
*cursor = w;
|
||||||
}
|
}
|
||||||
@ -245,13 +252,14 @@ unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor,
|
|||||||
|
|
||||||
int git_mwindow_file_register(git_mwindow_file *mwf)
|
int git_mwindow_file_register(git_mwindow_file *mwf)
|
||||||
{
|
{
|
||||||
|
git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (ctl.windowfiles.length == 0 &&
|
if (ctl->windowfiles.length == 0 &&
|
||||||
(error = git_vector_init(&ctl.windowfiles, 8, NULL)) < GIT_SUCCESS)
|
(error = git_vector_init(&ctl->windowfiles, 8, NULL)) < GIT_SUCCESS)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return git_vector_insert(&ctl.windowfiles, mwf);
|
return git_vector_insert(&ctl->windowfiles, mwf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void git_mwindow_close(git_mwindow **window)
|
void git_mwindow_close(git_mwindow **window)
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "fileops.h"
|
|
||||||
|
|
||||||
typedef struct git_mwindow {
|
typedef struct git_mwindow {
|
||||||
struct git_mwindow *next;
|
struct git_mwindow *next;
|
||||||
@ -29,8 +28,6 @@ typedef struct git_mwindow_file {
|
|||||||
typedef struct git_mwindow_ctl {
|
typedef struct git_mwindow_ctl {
|
||||||
size_t mapped;
|
size_t mapped;
|
||||||
unsigned int open_windows;
|
unsigned int open_windows;
|
||||||
size_t window_size; /* needs default value */
|
|
||||||
size_t mapped_limit; /* needs default value */
|
|
||||||
unsigned int mmap_calls;
|
unsigned int mmap_calls;
|
||||||
unsigned int peak_open_windows;
|
unsigned int peak_open_windows;
|
||||||
size_t peak_mapped;
|
size_t peak_mapped;
|
||||||
|
@ -5,11 +5,13 @@
|
|||||||
* a Linking Exception. For full terms see the included COPYING file.
|
* a Linking Exception. For full terms see the included COPYING file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mwindow.h"
|
#include "common.h"
|
||||||
#include "odb.h"
|
#include "odb.h"
|
||||||
#include "pack.h"
|
#include "pack.h"
|
||||||
#include "delta-apply.h"
|
#include "delta-apply.h"
|
||||||
#include "sha1_lookup.h"
|
#include "sha1_lookup.h"
|
||||||
|
#include "mwindow.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
#include "git2/oid.h"
|
#include "git2/oid.h"
|
||||||
#include "git2/zlib.h"
|
#include "git2/zlib.h"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#ifndef INCLUDE_thread_utils_h__
|
#ifndef INCLUDE_thread_utils_h__
|
||||||
#define INCLUDE_thread_utils_h__
|
#define INCLUDE_thread_utils_h__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
/* Common operations even if threading has been disabled */
|
/* Common operations even if threading has been disabled */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user