Commit 5c27da1f4844eef2b4dfbabce526b6c5f2cd310b

Vicent Martí 2012-08-20T12:10:23

Merge pull request #884 from carlosmn/global-windows Make the memory-window conrol structures global

diff --git a/src/global.c b/src/global.c
index 368c6c6..691f0d4 100644
--- a/src/global.c
+++ b/src/global.c
@@ -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)
diff --git a/src/global.h b/src/global.h
index 6e7373f..0ad41ee 100644
--- a/src/global.h
+++ b/src/global.h
@@ -12,12 +12,12 @@
 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
diff --git a/src/mwindow.c b/src/mwindow.c
index 1a5446b..4da5bad 100644
--- a/src/mwindow.c
+++ b/src/mwindow.c
@@ -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;
 	}
 }
diff --git a/src/mwindow.h b/src/mwindow.h
index d4fd195..c5aeaf7 100644
--- a/src/mwindow.h
+++ b/src/mwindow.h
@@ -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);