Don't flush write buffer for ftell

[BZ #5298]
Use write pointer state along with the file offset and/or the read
pointers to get the current file position.
This commit is contained in:
Siddhesh Poyarekar 2012-09-28 18:37:23 +05:30
parent 4573c6b098
commit adb26faefe
4 changed files with 126 additions and 31 deletions

View file

@ -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]

13
NEWS
View file

@ -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

View file

@ -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. */
@ -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)
{
@ -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)

View file

@ -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
@ -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)
{
@ -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;