about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLars Hjemli <hjemli@gmail.com>2006-12-11 12:10:12 +0100
committerLars Hjemli <hjemli@gmail.com>2006-12-11 12:10:12 +0100
commit318d106300102c19d114a4ea89265b0a4060d9cb (patch)
tree3752575abec74ee0a2b544e36e3cc8f9cdfa1e66
parentLet 'make install' clear all cachefiles (diff)
downloadcgit-pink-318d106300102c19d114a4ea89265b0a4060d9cb.tar.gz
cgit-pink-318d106300102c19d114a4ea89265b0a4060d9cb.zip
Avoid infinite loops in caching layer
Add a global variable, cgit_max_lock_attemps, to avoid the possibility of
infinite loops when failing to acquire a lockfile. This could happen on
broken setups or under crazy server load.

Incidentally, this also fixes a lurking bug in cache_lock() where an
uninitialized returnvalue was used.

Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to '')
-rw-r--r--cache.c35
-rw-r--r--cgit.c9
-rw-r--r--cgit.h1
3 files changed, 31 insertions, 14 deletions
diff --git a/cache.c b/cache.c
index 0ffa502..2e1ef8c 100644
--- a/cache.c
+++ b/cache.c
@@ -61,26 +61,35 @@ int cache_create_dirs()
 	return 1;
 }
 
+int cache_refill_overdue(const char *lockfile)
+{
+	struct stat st;
+
+	if (stat(lockfile, &st))
+		return 0;
+	else
+		return (time(NULL) - st.st_mtime > cgit_cache_max_create_time);
+}
+
 int cache_lock(struct cacheitem *item)
 {
-	int ret;
+	int i = 0;
 	char *lockfile = fmt("%s.lock", item->name);
 
- top:  
-       	item->fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR|S_IWUSR);
+ top:
+	if (++i > cgit_max_lock_attempts)
+		die("cache_lock: unable to lock %s: %s",
+		    item->name, strerror(errno));
+
+       	item->fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
+
 	if (item->fd == NOLOCK && errno == ENOENT && cache_create_dirs())
 		goto top;
-	if (item->fd == NOLOCK && errno == EEXIST) {
-		struct stat st;
-		time_t t;
-		if (stat(lockfile, &st))
-			return ret;
-		t = time(NULL);
-		if (t-st.st_mtime > cgit_cache_max_create_time && 
-		    !unlink(lockfile))
+
+	if (item->fd == NOLOCK && errno == EEXIST &&
+	    cache_refill_overdue(lockfile) && !unlink(lockfile))
 			goto top;
-		return 0;
-	}
+
 	return (item->fd > 0);
 }
 
diff --git a/cgit.c b/cgit.c
index 7f14016..dc91125 100644
--- a/cgit.c
+++ b/cgit.c
@@ -31,6 +31,7 @@ char *cgit_virtual_root = NULL;
 
 char *cgit_cache_root   = "/var/cache/cgit";
 
+int cgit_max_lock_attempts     =  5;
 int cgit_cache_root_ttl        =  5;
 int cgit_cache_repo_ttl        =  5;
 int cgit_cache_dynamic_ttl     =  5;
@@ -465,11 +466,17 @@ static void cgit_fill_cache(struct cacheitem *item)
 
 static void cgit_refresh_cache(struct cacheitem *item)
 {
+	int i = 0;
+
 	cache_prepare(item);
  top:
+	if (++i > cgit_max_lock_attempts) {
+		die("cgit_refresh_cache: unable to lock %s: %s",
+		    item->name, strerror(errno));
+	}
 	if (!cache_exist(item)) {
 		if (!cache_lock(item)) {
-			sched_yield();
+			sleep(1);
 			goto top;
 		}
 		if (!cache_exist(item))
diff --git a/cgit.h b/cgit.h
index 3b0994a..7e4bfef 100644
--- a/cgit.h
+++ b/cgit.h
@@ -23,6 +23,7 @@ extern char *cgit_logo_link;
 extern char *cgit_virtual_root;
 extern char *cgit_cache_root;
 
+extern int cgit_max_lock_attempts;
 extern int cgit_cache_root_ttl;
 extern int cgit_cache_repo_ttl;
 extern int cgit_cache_dynamic_ttl;
4:11:50 -0500'>2019-02-22Reorganize UI code for the umpteenth timeJune McEnroe It's actually in a good state now, I think. 2019-02-21Replace "view" with "window"June McEnroe I think originally I didn't want to use the same word as curses WINDOW but it's really much clearer for the user if they're just called windows. UI code probably needs yet another rewrite though. Still feels messy. 2019-02-21Remove ROT13June McEnroe It's just not convenient when it can only do the whole line... 2019-02-21Clean up man pageJune McEnroe 2019-01-26Draw UI before connectingJune McEnroe Otherwise the "Traveling" message isn't visible while connecting. 2019-01-25Avoid unused variable warnings with getyxJune McEnroe 2019-01-25Add GNU/Linux build instructionsJune McEnroe