changeset 5106:81394e71f92a HEAD

Added istream->blocking setting. It's now used to assert-crash early if a blocking stream unexpectedly returns "need more data".
author Timo Sirainen <tss@iki.fi>
date Tue, 06 Feb 2007 12:40:15 +0200
parents 342429974bf5
children ddbc89221c26
files src/lib-mail/istream-header-filter.c src/lib-storage/index/mbox/istream-raw-mbox.c src/lib/istream-data.c src/lib/istream-file.c src/lib/istream-limit.c src/lib/istream-mmap.c src/lib/istream.c src/lib/istream.h src/plugins/zlib/istream-zlib.c
diffstat 9 files changed, 58 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-mail/istream-header-filter.c	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/lib-mail/istream-header-filter.c	Tue Feb 06 12:40:15 2007 +0200
@@ -351,6 +351,7 @@
 	mstream->istream.sync = _sync;
 	mstream->istream.stat = _stat;
 
+	mstream->istream.istream.blocking = input->blocking;
 	mstream->istream.istream.seekable = input->seekable;
 	return _i_stream_create(&mstream->istream, pool, -1, 0);
 }
--- a/src/lib-storage/index/mbox/istream-raw-mbox.c	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/lib-storage/index/mbox/istream-raw-mbox.c	Tue Feb 06 12:40:15 2007 +0200
@@ -367,6 +367,8 @@
 	rstream->istream.sync = _sync;
 	rstream->istream.stat = _stat;
 
+	rstream->istream.istream.blocking = input->blocking;
+	rstream->istream.istream.seekable = input->seekable;
 	return _i_stream_create(&rstream->istream, pool, -1,
 				input->real_stream->abs_start_offset);
 }
--- a/src/lib/istream-data.c	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/lib/istream-data.c	Tue Feb 06 12:40:15 2007 +0200
@@ -53,6 +53,7 @@
 	stream->seek = _seek;
 	stream->stat = _stat;
 
+	stream->istream.blocking = TRUE;
 	stream->istream.seekable = TRUE;
 	return _i_stream_create(stream, pool, -1, 0);
 }
--- a/src/lib/istream-file.c	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/lib/istream-file.c	Tue Feb 06 12:40:15 2007 +0200
@@ -114,15 +114,17 @@
 
 	ret = -1;
 
-	if (fstream->file) {
-		do {
+	do {
+		if (fstream->file) {
 			ret = pread(stream->fd, stream->w_buffer + stream->pos,
 				    size, stream->istream.v_offset +
 				    (stream->pos - stream->skip));
-		} while (ret < 0 && errno == EINTR);
-	} else {
-		ret = read(stream->fd, stream->w_buffer + stream->pos, size);
-	}
+		} else {
+			ret = read(stream->fd, stream->w_buffer + stream->pos,
+				   size);
+		}
+	} while (ret < 0 && errno == EINTR && stream->istream.blocking);
+
 	if (ret == 0) {
 		/* EOF */
 		stream->istream.eof = TRUE;
@@ -130,9 +132,10 @@
 	}
 
 	if (ret < 0) {
-		if (errno == EINTR || errno == EAGAIN)
+		if (errno == EINTR || errno == EAGAIN) {
+			i_assert(!stream->istream.blocking);
 			ret = 0;
-		else {
+		} else {
 			stream->istream.eof = TRUE;
 			stream->istream.stream_errno = errno;
 			return -1;
@@ -238,9 +241,10 @@
 	fstream->istream.sync = _sync;
 	fstream->istream.stat = _stat;
 
-	/* get size of fd if it's a file */
+	/* if it's a file, set the flags properly */
 	if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
 		fstream->file = TRUE;
+		fstream->istream.istream.blocking = TRUE;
 		fstream->istream.istream.seekable = TRUE;
 	}
 
--- a/src/lib/istream-limit.c	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/lib/istream-limit.c	Tue Feb 06 12:40:15 2007 +0200
@@ -132,6 +132,7 @@
 	lstream->istream.seek = _seek;
 	lstream->istream.stat = _stat;
 
+	lstream->istream.istream.blocking = input->blocking;
 	lstream->istream.istream.seekable = input->seekable;
 	return _i_stream_create(&lstream->istream, pool, i_stream_get_fd(input),
 				input->real_stream->abs_start_offset +
--- a/src/lib/istream-mmap.c	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/lib/istream-mmap.c	Tue Feb 06 12:40:15 2007 +0200
@@ -234,6 +234,7 @@
 
 	istream = _i_stream_create(&mstream->istream, pool, fd, start_offset);
 	istream->mmaped = TRUE;
+	istream->blocking = TRUE;
 	istream->seekable = TRUE;
 	return istream;
 }
--- a/src/lib/istream.c	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/lib/istream.c	Tue Feb 06 12:40:15 2007 +0200
@@ -208,42 +208,42 @@
 	return line;
 }
 
-const unsigned char *i_stream_get_data(struct istream *stream, size_t *size)
+const unsigned char *i_stream_get_data(struct istream *stream, size_t *size_r)
 {
 	struct _istream *_stream = stream->real_stream;
 
 	if (_stream->skip >= _stream->pos) {
-		*size = 0;
+		*size_r = 0;
 		return NULL;
 	}
 
-        *size = _stream->pos - _stream->skip;
+        *size_r = _stream->pos - _stream->skip;
         return _stream->buffer + _stream->skip;
 }
 
 unsigned char *i_stream_get_modifiable_data(struct istream *stream,
-					    size_t *size)
+					    size_t *size_r)
 {
 	struct _istream *_stream = stream->real_stream;
 
 	if (_stream->skip >= _stream->pos || _stream->w_buffer == NULL) {
-		*size = 0;
+		*size_r = 0;
 		return NULL;
 	}
 
-        *size = _stream->pos - _stream->skip;
+        *size_r = _stream->pos - _stream->skip;
         return _stream->w_buffer + _stream->skip;
 }
 
-int i_stream_read_data(struct istream *stream, const unsigned char **data,
-		       size_t *size, size_t threshold)
+int i_stream_read_data(struct istream *stream, const unsigned char **data_r,
+		       size_t *size_r, size_t threshold)
 {
 	ssize_t ret = 0;
 	bool read_more = FALSE;
 
 	do {
-		*data = i_stream_get_data(stream, size);
-		if (*size > threshold)
+		*data_r = i_stream_get_data(stream, size_r);
+		if (*size_r > threshold)
 			return 1;
 
 		/* we need more data */
@@ -252,9 +252,15 @@
 			read_more = TRUE;
 	} while (ret > 0);
 
-	*data = i_stream_get_data(stream, size);
-	return ret == -2 ? -2 :
-		(read_more || ret == 0 ? 0 : -1);
+	*data_r = i_stream_get_data(stream, size_r);
+	if (ret == -2)
+		return -2;
+
+	if (read_more || ret == 0) {
+		i_assert(!stream->blocking || stream->eof);
+		return 0;
+	}
+	return -1;
 }
 
 struct istream *_i_stream_create(struct _istream *_stream, pool_t pool, int fd,
--- a/src/lib/istream.h	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/lib/istream.h	Tue Feb 06 12:40:15 2007 +0200
@@ -9,6 +9,7 @@
 
 	int stream_errno;
 	unsigned int mmaped:1; /* be careful when copying data */
+	unsigned int blocking:1; /* read() shouldn't return 0 */
 	unsigned int closed:1;
 	unsigned int seekable:1; /* we can seek() backwards */
 	unsigned int eof:1; /* read() has reached to end of file
@@ -85,16 +86,16 @@
 
 /* Returns pointer to beginning of read data, or NULL if there's no data
    buffered. */
-const unsigned char *i_stream_get_data(struct istream *stream, size_t *size);
+const unsigned char *i_stream_get_data(struct istream *stream, size_t *size_r);
 /* Like i_stream_get_data(), but returns non-const data. This only works with
    buffered streams (currently only file), others return NULL. */
 unsigned char *i_stream_get_modifiable_data(struct istream *stream,
-					    size_t *size);
+					    size_t *size_r);
 /* Like i_stream_get_data(), but read more when needed. Returns 1 if more
    than threshold bytes are available, 0 if less, -1 if error or EOF with no
    bytes read that weren't already in buffer, or -2 if stream's input buffer
    is full. */
-int i_stream_read_data(struct istream *stream, const unsigned char **data,
-		       size_t *size, size_t threshold);
+int i_stream_read_data(struct istream *stream, const unsigned char **data_r,
+		       size_t *size_r, size_t threshold);
 
 #endif
--- a/src/plugins/zlib/istream-zlib.c	Tue Feb 06 11:49:46 2007 +0200
+++ b/src/plugins/zlib/istream-zlib.c	Tue Feb 06 12:40:15 2007 +0200
@@ -124,7 +124,11 @@
 
 	i_assert(zstream->seek_offset == stream->istream.v_offset +
 		 (stream->pos - stream->skip));
-	ret = gzread(zstream->file, stream->w_buffer + stream->pos, size);
+	do {
+	       ret = gzread(zstream->file, stream->w_buffer + stream->pos,
+			    size);
+	} while (ret < 0 && errno == EINTR && stream->istream.blocking);
+
 	if (ret == 0) {
 		/* EOF */
 		stream->istream.eof = TRUE;
@@ -132,9 +136,10 @@
 	}
 
 	if (ret < 0) {
-		if (errno == EINTR || errno == EAGAIN)
+		if (errno == EAGAIN) {
+			i_assert(!stream->istream.blocking);
 			ret = 0;
-		else {
+		} else {
 			stream->istream.eof = TRUE;
 			stream->istream.stream_errno = errno;
 			return -1;
@@ -236,6 +241,7 @@
 struct istream *i_stream_create_zlib(int fd, pool_t pool)
 {
 	struct zlib_istream *zstream;
+	struct stat st;
 
 	zstream = p_new(pool, struct zlib_istream, 1);
 	zstream->fd = fd;
@@ -252,6 +258,11 @@
 	zstream->istream.stat = _stat;
 	zstream->istream.sync = _sync;
 
-	zstream->istream.istream.seekable = TRUE;
+	/* if it's a file, set the flags properly */
+	if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
+		zstream->istream.istream.blocking = TRUE;
+		zstream->istream.istream.seekable = TRUE;
+	}
+
 	return _i_stream_create(&zstream->istream, pool, fd, 0);
 }