]> git.proxmox.com Git - libgit2.git/commitdiff
Make the memory-window conrol structures global
authorCarlos Martín Nieto <carlos@cmartin.tk>
Sat, 18 Aug 2012 20:11:49 +0000 (22:11 +0200)
committerCarlos Martín Nieto <cmn@elego.de>
Mon, 20 Aug 2012 10:02:52 +0000 (12:02 +0200)
Up to now, the idea was that the user would do all the operations for
one repository in the same thread. Thus we could have the
memory-mapped window information thread-local and avoid any locking.

This is not practical in a few environments, such as Apple's GCD which
allocates threads arbitrarily or the .NET CLR, where the OS-level
thread can change at any moment.

Make the control structure global and protect it with a mutex so we
don't depend on the thread currently executing the code.

src/global.c
src/global.h
src/mwindow.c
src/mwindow.h

index 368c6c664331ff824366d9d2ee72a772a3442fdd..691f0d4f6897ed5c781b1ada0a2e653ed9546357 100644 (file)
@@ -9,6 +9,9 @@
 #include "git2/threads.h" 
 #include "thread-utils.h"
 
+
+git_mutex git__mwindow_mutex;
+
 /**
  * Handle the global state with TLS
  *
@@ -47,12 +50,14 @@ void git_threads_init(void)
 
        _tls_index = TlsAlloc();
        _tls_init = 1;
+       git_mutex_init(&git__mwindow_mutex);
 }
 
 void git_threads_shutdown(void)
 {
        TlsFree(_tls_index);
        _tls_init = 0;
+       git_mutex_free(&git__mwindow_mutex);
 }
 
 git_global_st *git__global_state(void)
index 6e7373fa3d5b6bd8213a955adc3c7304a51fad92..0ad41ee63e58a3444b8acfc3f000d4ab0e21115f 100644 (file)
 typedef struct {
        git_error *last_error;
        git_error error_t;
-
-       git_mwindow_ctl mem_ctl;
 } git_global_st;
 
 git_global_st *git__global_state(void);
 
+extern git_mutex git__mwindow_mutex;
+
 #define GIT_GLOBAL (git__global_state())
 
 #endif
index 1a5446b9ccd25c830d55192a0c8d12ffcf648820..4da5badb626143194823f65254c9ef02a0c61e9c 100644 (file)
@@ -32,14 +32,20 @@ static struct {
        DEFAULT_MAPPED_LIMIT,
 };
 
+/* Whenever you want to read or modify this, grab git__mwindow_mutex */
+static git_mwindow_ctl mem_ctl;
+
 /*
  * Free all the windows in a sequence, typically because we're done
  * with the file
  */
 void git_mwindow_free_all(git_mwindow_file *mwf)
 {
-       git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
+       git_mwindow_ctl *ctl = &mem_ctl;
        unsigned int i;
+
+       git_mutex_lock(&git__mwindow_mutex);
+
        /*
         * Remove these windows from the global list
         */
@@ -67,6 +73,8 @@ void git_mwindow_free_all(git_mwindow_file *mwf)
                mwf->windows = w->next;
                git__free(w);
        }
+
+       git_mutex_unlock(&git__mwindow_mutex);
 }
 
 /*
@@ -82,7 +90,7 @@ int git_mwindow_contains(git_mwindow *win, git_off_t offset)
 /*
  * Find the least-recently-used window in a file
  */
-void git_mwindow_scan_lru(
+static void git_mwindow_scan_lru(
        git_mwindow_file *mwf,
        git_mwindow **lru_w,
        git_mwindow **lru_l)
@@ -107,11 +115,12 @@ void git_mwindow_scan_lru(
 
 /*
  * Close the least recently used window. You should check to see if
- * the file descriptors need closing from time to time.
+ * the file descriptors need closing from time to time. Called under
+ * lock from new_window.
  */
 static int git_mwindow_close_lru(git_mwindow_file *mwf)
 {
-       git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
+       git_mwindow_ctl *ctl = &mem_ctl;
        unsigned int i;
        git_mwindow *lru_w = NULL, *lru_l = NULL, **list = &mwf->windows;
 
@@ -146,13 +155,14 @@ static int git_mwindow_close_lru(git_mwindow_file *mwf)
        return 0;
 }
 
+/* This gets called under lock from git_mwindow_open */
 static git_mwindow *new_window(
        git_mwindow_file *mwf,
        git_file fd,
        git_off_t size,
        git_off_t offset)
 {
-       git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
+       git_mwindow_ctl *ctl = &mem_ctl;
        size_t walign = _mw_options.window_size / 2;
        git_off_t len;
        git_mwindow *w;
@@ -208,9 +218,10 @@ unsigned char *git_mwindow_open(
        size_t extra,
        unsigned int *left)
 {
-       git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
+       git_mwindow_ctl *ctl = &mem_ctl;
        git_mwindow *w = *cursor;
 
+       git_mutex_lock(&git__mwindow_mutex);
        if (!w || !(git_mwindow_contains(w, offset) && git_mwindow_contains(w, offset + extra))) {
                if (w) {
                        w->inuse_cnt--;
@@ -228,8 +239,10 @@ unsigned char *git_mwindow_open(
                 */
                if (!w) {
                        w = new_window(mwf, mwf->fd, mwf->size, offset);
-                       if (w == NULL)
+                       if (w == NULL) {
+                               git_mutex_unlock(&git__mwindow_mutex);
                                return NULL;
+                       }
                        w->next = mwf->windows;
                        mwf->windows = w;
                }
@@ -247,32 +260,43 @@ unsigned char *git_mwindow_open(
        if (left)
                *left = (unsigned int)(w->window_map.len - offset);
 
+       git_mutex_unlock(&git__mwindow_mutex);
        return (unsigned char *) w->window_map.data + offset;
 }
 
 int git_mwindow_file_register(git_mwindow_file *mwf)
 {
-       git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
+       git_mwindow_ctl *ctl = &mem_ctl;
+       int ret;
 
+       git_mutex_lock(&git__mwindow_mutex);
        if (ctl->windowfiles.length == 0 &&
-               git_vector_init(&ctl->windowfiles, 8, NULL) < 0)
+           git_vector_init(&ctl->windowfiles, 8, NULL) < 0) {
+               git_mutex_unlock(&git__mwindow_mutex);
                return -1;
+       }
+
+       ret = git_vector_insert(&ctl->windowfiles, mwf);
+       git_mutex_unlock(&git__mwindow_mutex);
 
-       return git_vector_insert(&ctl->windowfiles, mwf);
+       return ret;
 }
 
 int git_mwindow_file_deregister(git_mwindow_file *mwf)
 {
-       git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
+       git_mwindow_ctl *ctl = &mem_ctl;
        git_mwindow_file *cur;
        unsigned int i;
 
+       git_mutex_lock(&git__mwindow_mutex);
        git_vector_foreach(&ctl->windowfiles, i, cur) {
                if (cur == mwf) {
                        git_vector_remove(&ctl->windowfiles, i);
+                       git_mutex_unlock(&git__mwindow_mutex);
                        return 0;
                }
        }
+       git_mutex_unlock(&git__mwindow_mutex);
 
        giterr_set(GITERR_ODB, "Failed to find the memory window file to deregister");
        return -1;
@@ -282,7 +306,9 @@ void git_mwindow_close(git_mwindow **window)
 {
        git_mwindow *w = *window;
        if (w) {
+               git_mutex_lock(&git__mwindow_mutex);
                w->inuse_cnt--;
+               git_mutex_unlock(&git__mwindow_mutex);
                *window = NULL;
        }
 }
index d4fd195690513986c8210951ea19c7f7929a48f7..c5aeaf77b77b2dfd6aef7dc2e1ede41813e97313 100644 (file)
@@ -38,7 +38,6 @@ typedef struct git_mwindow_ctl {
 int git_mwindow_contains(git_mwindow *win, git_off_t offset);
 void git_mwindow_free_all(git_mwindow_file *mwf);
 unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, size_t extra, unsigned int *left);
-void git_mwindow_scan_lru(git_mwindow_file *mwf, git_mwindow **lru_w, git_mwindow **lru_l);
 int git_mwindow_file_register(git_mwindow_file *mwf);
 int git_mwindow_file_deregister(git_mwindow_file *mwf);
 void git_mwindow_close(git_mwindow **w_cursor);