svn commit: [25788] trunk/busybox: include libbb

vda at busybox.net vda at busybox.net
Mon Mar 23 06:33:37 UTC 2009


Author: vda
Date: 2009-03-23 06:33:37 +0000 (Mon, 23 Mar 2009)
New Revision: 25788

Log:
libbb: revent previous version of "concurrent history updating"
and replace it with one which does not "snoop" history written
by others. (1) it is what bug 185 needs, and (2) it is less bloaty:

function                                             old     new   delta
load_history                                           -     252    +252
read_line_input                                     3155    3287    +132
next_token                                           914     918      +4
qrealloc                                              36      33      -3
getoptscmd                                           713     708      -5
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/2 up/down: 388/-8)            Total: 380 bytes



Modified:
   trunk/busybox/include/libbb.h
   trunk/busybox/libbb/lineedit.c


Changeset:
Modified: trunk/busybox/include/libbb.h
===================================================================
--- trunk/busybox/include/libbb.h	2009-03-22 22:48:41 UTC (rev 25787)
+++ trunk/busybox/include/libbb.h	2009-03-23 06:33:37 UTC (rev 25788)
@@ -1199,7 +1199,6 @@
 	int cur_history;
 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
 	unsigned cnt_history_in_file;
-	off_t last_history_end;
 	const char *hist_file;
 #endif
 	char *history[MAX_HISTORY + 1];
@@ -1215,6 +1214,7 @@
 	FOR_SHELL = DO_HISTORY | SAVE_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION,
 };
 line_input_t *new_line_input_t(int flags) FAST_FUNC;
+/* so far static: void free_line_input_t(line_input_t *n) FAST_FUNC; */
 /* Returns:
  * -1 on read errors or EOF, or on bare Ctrl-D,
  * 0  on ctrl-C (the line entered is still returned in 'command'),

Modified: trunk/busybox/libbb/lineedit.c
===================================================================
--- trunk/busybox/libbb/lineedit.c	2009-03-22 22:48:41 UTC (rev 25787)
+++ trunk/busybox/libbb/lineedit.c	2009-03-23 06:33:37 UTC (rev 25788)
@@ -954,6 +954,14 @@
 #endif  /* FEATURE_COMMAND_TAB_COMPLETION */
 
 
+line_input_t* FAST_FUNC new_line_input_t(int flags)
+{
+	line_input_t *n = xzalloc(sizeof(*n));
+	n->flags = flags;
+	return n;
+}
+
+
 #if MAX_HISTORY > 0
 
 static void save_command_ps_at_cur_history(void)
@@ -991,16 +999,23 @@
 
 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
 /* We try to ensure that concurrent additions to the history
- * do not overwrite each other, and that additions to the history
- * by one user are noticed by others.
+ * do not overwrite each other.
  * Otherwise shell users get unhappy.
  *
  * History file is trimmed lazily, when it grows several times longer
  * than configured MAX_HISTORY lines.
  */
 
+static void free_line_input_t(line_input_t *n)
+{
+	int i = n->cnt_history;
+	while (i > 0)
+		free(n->history[--i]);
+	free(n);
+}
+
 /* state->flags is already checked to be nonzero */
-static void load_history(void)
+static void load_history(line_input_t *st_parm)
 {
 	char *temp_h[MAX_HISTORY];
 	char *line;
@@ -1009,18 +1024,18 @@
 
 	/* NB: do not trash old history if file can't be opened */
 
-	fp = fopen_for_read(state->hist_file);
+	fp = fopen_for_read(st_parm->hist_file);
 	if (fp) {
 		/* clean up old history */
-		for (idx = state->cnt_history; idx > 0;) {
+		for (idx = st_parm->cnt_history; idx > 0;) {
 			idx--;
-			free(state->history[idx]);
-			state->history[idx] = NULL;
+			free(st_parm->history[idx]);
+			st_parm->history[idx] = NULL;
 		}
 
 		/* fill temp_h[], retaining only last MAX_HISTORY lines */
 		memset(temp_h, 0, sizeof(temp_h));
-		state->cnt_history_in_file = idx = 0;
+		st_parm->cnt_history_in_file = idx = 0;
 		while ((line = xmalloc_fgetline(fp)) != NULL) {
 			if (line[0] == '\0') {
 				free(line);
@@ -1028,16 +1043,15 @@
 			}
 			free(temp_h[idx]);
 			temp_h[idx] = line;
-			state->cnt_history_in_file++;
+			st_parm->cnt_history_in_file++;
 			idx++;
 			if (idx == MAX_HISTORY)
 				idx = 0;
 		}
-		state->last_history_end = lseek(fileno(fp), 0, SEEK_CUR);
 		fclose(fp);
 
 		/* find first non-NULL temp_h[], if any */
-		if (state->cnt_history_in_file) {
+		if (st_parm->cnt_history_in_file) {
 			while (temp_h[idx] == NULL) {
 				idx++;
 				if (idx == MAX_HISTORY)
@@ -1045,7 +1059,7 @@
 			}
 		}
 
-		/* copy temp_h[] to state->history[] */
+		/* copy temp_h[] to st_parm->history[] */
 		for (i = 0; i < MAX_HISTORY;) {
 			line = temp_h[idx];
 			if (!line)
@@ -1056,71 +1070,60 @@
 			line_len = strlen(line);
 			if (line_len >= MAX_LINELEN)
 				line[MAX_LINELEN-1] = '\0';
-			state->history[i++] = line;
+			st_parm->history[i++] = line;
 		}
-		state->cnt_history = i;
+		st_parm->cnt_history = i;
 	}
 }
 
 /* state->flags is already checked to be nonzero */
 static void save_history(char *str)
 {
-	off_t end;
 	int fd;
-	int len;
+	int len, len2;
 
-	len = strlen(str);
- again:
 	fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0666);
 	if (fd < 0)
 		return;
-
-	end = lseek(fd, 0, SEEK_END);
-
-	if (str) {
-		str[len] = '\n';
-		full_write(fd, str, len + 1);
-		str[len] = '\0';
-		str = NULL;
-		state->cnt_history_in_file++;
-	}
+	xlseek(fd, 0, SEEK_END); /* paranoia */
+	len = strlen(str);
+	str[len] = '\n'; /* we (try to) do atomic write */
+	len2 = full_write(fd, str, len + 1);
+	str[len] = '\0';
 	close(fd);
+	if (len2 != len + 1)
+		return; /* "wtf?" */
 
-	/* if it was not a 1st write */
-	if (state->last_history_end >= 0) {
-		/* did someone else write anything there? */
-		if (state->last_history_end != end) {
-			load_history(); /* note: updates cnt_history_in_file */
-			state->last_history_end = -1;
-			goto again;
-		}
-	}
-	state->last_history_end = end + len + 1;
-
 	/* did we write so much that history file needs trimming? */
+	state->cnt_history_in_file++;
 	if (state->cnt_history_in_file > MAX_HISTORY * 4) {
 		FILE *fp;
 		char *new_name;
+		line_input_t *st_temp;
+		int i;
 
-		new_name = xasprintf("%s.new", state->hist_file);
+		/* we may have concurrently written entries from others.
+		 * load them */
+		st_temp = new_line_input_t(state->flags);
+		st_temp->hist_file = state->hist_file;
+		load_history(st_temp);
+
+		/* write out temp file and replace hist_file atomically */
+		new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid());
 		fp = fopen_for_write(new_name);
 		if (fp) {
-			int i;
-
-			for (i = 0; i < state->cnt_history; i++) {
-				fprintf(fp, "%s\n", state->history[i]);
-			}
-			state->cnt_history_in_file = i; /* == cnt_history */
-			state->last_history_end = lseek(fileno(fp), 0, SEEK_CUR);
+			for (i = 0; i < st_temp->cnt_history; i++)
+				fprintf(fp, "%s\n", st_temp->history[i]);
 			fclose(fp);
-			/* replace hist_file atomically */
-			rename(new_name, state->hist_file);
+			if (rename(new_name, state->hist_file) == 0)
+				state->cnt_history_in_file = st_temp->cnt_history;
 		}
 		free(new_name);
+		free_line_input_t(st_temp);
 	}
 }
 #else
-#define load_history()  ((void)0)
+#define load_history(a) ((void)0)
 #define save_history(a) ((void)0)
 #endif /* FEATURE_COMMAND_SAVEHISTORY */
 
@@ -1490,7 +1493,8 @@
 	state = st ? st : (line_input_t*) &const_int_0;
 #if ENABLE_FEATURE_EDITING_SAVEHISTORY
 	if ((state->flags & SAVE_HISTORY) && state->hist_file)
-		load_history();
+		if (state->cnt_history == 0)
+			load_history(state);
 #endif
 	if (state->flags & DO_HISTORY)
 		state->cur_history = state->cnt_history;
@@ -1948,14 +1952,6 @@
 	return len; /* can't return command_len, DEINIT_S() destroys it */
 }
 
-line_input_t* FAST_FUNC new_line_input_t(int flags)
-{
-	line_input_t *n = xzalloc(sizeof(*n));
-	n->flags = flags;
-	n->last_history_end = -1;
-	return n;
-}
-
 #else
 
 #undef read_line_input



More information about the busybox-cvs mailing list