Skip to content

Commit

Permalink
Don't flush write buffer for ftell
Browse files Browse the repository at this point in the history
[BZ #5298]
Use write pointer state along with the file offset and/or the read
pointers to get the current file position.
  • Loading branch information
Siddhesh Poyarekar committed Sep 28, 2012
1 parent 4573c6b commit adb26fa
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 31 deletions.
7 changes: 7 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
2012-09-28 Siddhesh Poyarekar <siddhesh@redhat.com>

[BZ #5298]
* libio/fileops.c (_IO_new_file_seekoff): Don't flush buffer
for ftell. Compute offsets from write pointers instead.
* libio/wfileops.c (_IO_wfile_seekoff): Likewise.

2012-09-28 Siddhesh Poyarekar <siddhesh@redhat.com>

[BZ #14543]
Expand Down
13 changes: 7 additions & 6 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ Version 2.17

* The following bugs are resolved with this release:

1349, 3479, 5044, 5400, 6778, 6808, 9685, 9914, 10014, 10038, 11607,
13412, 13542, 13629, 13679, 13696, 13717, 13741, 13939, 13966, 14042,
14090, 14150, 14151, 14154, 14157, 14166, 14173, 14195, 14237, 14252,
14283, 14298, 14303, 14307, 14328, 14331, 14336, 14337, 14347, 14349,
14376, 14459, 14476, 14505, 14510, 14516, 14518, 14519, 14530, 14532,
14538, 14543, 14544, 14545, 14562, 14576, 14579, 14583, 14587, 14621.
1349, 3479, 5044, 5298, 5400, 6778, 6808, 9685, 9914, 10014, 10038,
11607, 13412, 13542, 13629, 13679, 13696, 13717, 13741, 13939, 13966,
14042, 14090, 14150, 14151, 14154, 14157, 14166, 14173, 14195, 14237,
14252, 14283, 14298, 14303, 14307, 14328, 14331, 14336, 14337, 14347,
14349, 14376, 14459, 14476, 14505, 14510, 14516, 14518, 14519, 14530,
14532, 14538, 14543, 14544, 14545, 14562, 14576, 14579, 14583, 14587,
14621.

* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
Optimized versions of memcpy, memset, and memcmp added for System z10 and
Expand Down
21 changes: 16 additions & 5 deletions libio/fileops.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,9 @@ _IO_new_file_seekoff (fp, offset, dir, mode)
int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
&& fp->_IO_write_base == fp->_IO_write_ptr);

bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
|| _IO_in_put_mode (fp));

if (mode == 0)
dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */

Expand All @@ -988,10 +991,8 @@ _IO_new_file_seekoff (fp, offset, dir, mode)
which assumes file_ptr() is eGptr. Anyway, since we probably
end up flushing when we close(), it doesn't make much difference.)
FIXME: simulate mem-mapped files. */

if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp))
if (_IO_switch_to_get_mode (fp))
return EOF;
else if (was_writing && _IO_switch_to_get_mode (fp))
return EOF;

if (fp->_IO_buf_base == NULL)
{
Expand All @@ -1010,7 +1011,17 @@ _IO_new_file_seekoff (fp, offset, dir, mode)
{
case _IO_seek_cur:
/* Adjust for read-ahead (bytes is buffer). */
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
if (mode != 0 || !was_writing)
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
else
{
/* _IO_read_end coincides with fp._offset, so the actual file position
is fp._offset - (_IO_read_end - new_write_ptr). This is fine
even if fp._offset is not set, since fp->_IO_read_end is then at
_IO_buf_base and this adjustment is for unbuffered output. */
offset -= fp->_IO_read_end - fp->_IO_write_ptr;
}

if (fp->_offset == _IO_pos_BAD)
{
if (mode != 0)
Expand Down
116 changes: 96 additions & 20 deletions libio/wfileops.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,10 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
&& (fp->_wide_data->_IO_write_base
== fp->_wide_data->_IO_write_ptr));

bool was_writing = ((fp->_wide_data->_IO_write_ptr
> fp->_wide_data->_IO_write_base)
|| _IO_in_put_mode (fp));

if (mode == 0)
{
/* XXX For wide stream with backup store it is not very
Expand Down Expand Up @@ -644,11 +648,8 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
which assumes file_ptr() is eGptr. Anyway, since we probably
end up flushing when we close(), it doesn't make much difference.)
FIXME: simulate mem-mapped files. */

if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base
|| _IO_in_put_mode (fp))
if (_IO_switch_to_wget_mode (fp))
return WEOF;
else if (was_writing && _IO_switch_to_wget_mode (fp))
return WEOF;

if (fp->_wide_data->_IO_buf_base == NULL)
{
Expand Down Expand Up @@ -679,29 +680,104 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
cv = fp->_codecvt;
clen = (*cv->__codecvt_do_encoding) (cv);

if (clen > 0)
if (mode != 0 || !was_writing)
{
offset -= (fp->_wide_data->_IO_read_end
- fp->_wide_data->_IO_read_ptr) * clen;
/* Adjust by readahead in external buffer. */
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
if (clen > 0)
{
offset -= (fp->_wide_data->_IO_read_end
- fp->_wide_data->_IO_read_ptr) * clen;
/* Adjust by readahead in external buffer. */
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
}
else
{
int nread;

flushed:
delta = (fp->_wide_data->_IO_read_ptr
- fp->_wide_data->_IO_read_base);
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
nread = (*cv->__codecvt_do_length) (cv,
&fp->_wide_data->_IO_state,
fp->_IO_read_base,
fp->_IO_read_end, delta);
fp->_IO_read_ptr = fp->_IO_read_base + nread;
fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
}
}
else
{
int nread;
char *new_write_ptr = fp->_IO_write_ptr;

delta = fp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_base;
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
fp->_IO_read_base,
fp->_IO_read_end, delta);
fp->_IO_read_ptr = fp->_IO_read_base + nread;
fp->_wide_data->_IO_read_end = fp->_wide_data->_IO_read_ptr;
offset -= fp->_IO_read_end - fp->_IO_read_base - nread;
if (clen > 0)
offset += (fp->_wide_data->_IO_write_ptr
- fp->_wide_data->_IO_write_base) / clen;
else
{
enum __codecvt_result status;
delta = (fp->_wide_data->_IO_write_ptr
- fp->_wide_data->_IO_write_base);
const wchar_t *write_base = fp->_wide_data->_IO_write_base;

/* FIXME: This actually ends up in two iterations of conversion,
one here and the next when the buffer actually gets flushed.
It may be possible to optimize this in future so that
wdo_write identifies already converted content and does not
redo it. In any case, this is much better than having to
flush buffers for every ftell. */
do
{
/* Ugh, no point trying to avoid the flush. Just do it
and go back to how it was with the read mode. */
if (delta > 0 && new_write_ptr == fp->_IO_buf_end)
{
if (_IO_switch_to_wget_mode (fp))
return WEOF;
goto flushed;
}

const wchar_t *new_wbase = fp->_wide_data->_IO_write_base;
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
status = (*cv->__codecvt_do_out) (cv,
&fp->_wide_data->_IO_state,
write_base,
write_base + delta,
&new_wbase,
new_write_ptr,
fp->_IO_buf_end,
&new_write_ptr);

delta -= new_wbase - write_base;

/* If there was an error, then return WEOF.
TODO: set buffer state. */
if (__builtin_expect (status == __codecvt_error, 0))
return WEOF;
}
while (delta > 0);
}

/* _IO_read_end coincides with fp._offset, so the actual file position
is fp._offset - (_IO_read_end - new_write_ptr). This is fine
even if fp._offset is not set, since fp->_IO_read_end is then at
_IO_buf_base and this adjustment is for unbuffered output. */
offset -= fp->_IO_read_end - new_write_ptr;
}

if (fp->_offset == _IO_pos_BAD)
goto dumb;
{
if (mode != 0)
goto dumb;
else
{
result = _IO_SYSSEEK (fp, 0, dir);
if (result == EOF)
return result;
fp->_offset = result;
}
}

/* Make offset absolute, assuming current pointer is file_ptr(). */
offset += fp->_offset;

Expand Down

0 comments on commit adb26fa

Please sign in to comment.