istream-mmap.c revision 03f5c621d06d6b6d77a145196c9633a7aa64dc78
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch istream-mmap.c : Input stream handling for mmap()ed files
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch Copyright (c) 2002 Timo Sirainen
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch Permission is hereby granted, free of charge, to any person obtaining
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch a copy of this software and associated documentation files (the
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch "Software"), to deal in the Software without restriction, including
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch without limitation the rights to use, copy, modify, merge, publish,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch distribute, sublicense, and/or sell copies of the Software, and to
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch permit persons to whom the Software is furnished to do so, subject to
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch the following conditions:
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch The above copyright notice and this permission notice shall be
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch included in all copies or substantial portions of the Software.
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch struct mmap_istream *mstream = (struct mmap_istream *) stream;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (mstream->autoclose_fd && mstream->fd != -1) {
e9228a3918aa0243eff4aae1ff5462bd3198417fTimo Sirainenstatic void i_stream_munmap(struct mmap_istream *mstream)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (munmap(mstream->mmap_base, _stream->buffer_size) < 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch struct mmap_istream *mstream = (struct mmap_istream *) stream;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch struct mmap_istream *mstream = (struct mmap_istream *) stream;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* allow only full page sizes */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch max_size += mmap_pagesize - (max_size % mmap_pagesize);
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Boschstatic void _set_blocking(struct _iostream *stream __attr_unused__,
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch /* we never block */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Boschstatic ssize_t io_stream_set_mmaped_pos(struct _istream *stream)
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch struct mmap_istream *mstream = (struct mmap_istream *) stream;
9f8cef4cbc49797053c343209ea13022fdbc5a63Stephan Bosch stream->istream.start_offset + stream->istream.v_limit);
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen top = stream->istream.start_offset + stream->istream.v_limit -
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen stream->pos = I_MIN(top, stream->buffer_size);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch struct mmap_istream *mstream = (struct mmap_istream *) stream;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (stream->istream.start_offset + stream->istream.v_limit <=
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch /* end of file */
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch /* more bytes available without needing to mmap() */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch if (aligned_skip == 0 && mstream->mmap_base != NULL) {
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch /* didn't skip enough bytes */
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch if (munmap(mstream->mmap_base, stream->buffer_size) < 0)
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch i_error("io_stream_read_mmaped(): munmap() failed: %m");
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch top = stream->istream.start_offset + stream->istream.v_size -
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch stream->buffer_size = I_MIN(top, mstream->mmap_block_size);
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch i_assert((uoff_t)mstream->mmap_offset + stream->buffer_size <=
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch stream->istream.start_offset + stream->istream.v_size);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mstream->mmap_base = mmap(NULL, stream->buffer_size,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* madvise() only if non-limited mmap()ed buffer area larger than
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch limit_size = stream->istream.start_offset + stream->istream.v_limit -
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Boschstatic void _seek(struct _istream *stream, uoff_t v_offset)
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch struct mmap_istream *mstream = (struct mmap_istream *) stream;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch abs_offset = stream->istream.start_offset + v_offset;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch (uoff_t)mstream->mmap_offset + stream->buffer_size > abs_offset) {
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* already mmaped */
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch stream->skip = stream->pos = abs_offset - mstream->mmap_offset;
564e117d86ce5b659f9b9570edddc566f9ebb5dfStephan Bosch /* force reading next time */
93ed69606237a08623f8294c060fa148880058f8Timo Sirainenstatic void _skip(struct _istream *stream, uoff_t count)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch _seek(stream, stream->istream.v_offset + count);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstruct istream *i_stream_create_mmap(int fd, pool_t pool, size_t block_size,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_error("i_stream_create_mmap(): fstat() failed: %m");
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mstream = p_new(pool, struct mmap_istream, 1);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch _set_max_buffer_size(&mstream->istream.iostream, block_size);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch mstream->istream.iostream.set_blocking = _set_blocking;