diff options
-rw-r--r-- | libc/Android.mk | 2 | ||||
-rw-r--r-- | libc/stdio/fread.c (renamed from libc/upstream-openbsd/lib/libc/stdio/fread.c) | 18 | ||||
-rw-r--r-- | tests/stdio_test.cpp | 31 |
3 files changed, 49 insertions, 2 deletions
diff --git a/libc/Android.mk b/libc/Android.mk index 045556e..3005092 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -61,6 +61,7 @@ libc_common_src_files := \ bionic/sigsetmask.c \ bionic/system_properties_compat.c \ stdio/findfp.c \ + stdio/fread.c \ stdio/snprintf.c\ stdio/sprintf.c \ @@ -396,7 +397,6 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/fputs.c \ upstream-openbsd/lib/libc/stdio/fputwc.c \ upstream-openbsd/lib/libc/stdio/fputws.c \ - upstream-openbsd/lib/libc/stdio/fread.c \ upstream-openbsd/lib/libc/stdio/freopen.c \ upstream-openbsd/lib/libc/stdio/fscanf.c \ upstream-openbsd/lib/libc/stdio/fseek.c \ diff --git a/libc/upstream-openbsd/lib/libc/stdio/fread.c b/libc/stdio/fread.c index 8a592f6..e052128 100644 --- a/libc/upstream-openbsd/lib/libc/stdio/fread.c +++ b/libc/stdio/fread.c @@ -68,7 +68,23 @@ fread(void *buf, size_t size, size_t count, FILE *fp) fp->_r = 0; total = resid; p = buf; - while (resid > (r = fp->_r)) { + + // BEGIN android-added + // Avoid pathological behavior on unbuffered files. OpenBSD + // will loop reading one byte then memcpying one byte! + if ((fp->_flags & __SNBF) != 0) { + // We know if we're unbuffered that our buffer is empty, so + // we can just read directly. + while (resid > 0 && (r = (*fp->_read)(fp->_cookie, p, resid)) > 0) { + p += r; + resid -= r; + } + FUNLOCKFILE(fp); + return ((total - resid) / size); + } + // END android-added + + while (resid > (size_t)(r = fp->_r)) { (void)memcpy((void *)p, (void *)fp->_p, (size_t)r); fp->_p += r; /* fp->_r = 0 ... done in __srefill */ diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 6a2991f..bba744a 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -694,3 +694,34 @@ TEST(stdio, fpos_t_and_seek) { fclose(fp); } + +// https://code.google.com/p/android/issues/detail?id=81155 +// http://b/18556607 +TEST(stdio, fread_unbuffered_pathological_performance) { + FILE* fp = fopen("/dev/zero", "r"); + ASSERT_TRUE(fp != NULL); + + // Make this stream unbuffered. + setvbuf(fp, 0, _IONBF, 0); + + char buf[65*1024]; + memset(buf, 0xff, sizeof(buf)); + + time_t t0 = time(NULL); + for (size_t i = 0; i < 1024; ++i) { + fread(buf, 64*1024, 1, fp); + } + time_t t1 = time(NULL); + + fclose(fp); + + // 1024 64KiB reads should have been very quick. + ASSERT_LE(t1 - t0, 1); + + for (size_t i = 0; i < 64*1024; ++i) { + ASSERT_EQ('\0', buf[i]); + } + for (size_t i = 64*1024; i < 65*1024; ++i) { + ASSERT_EQ('\xff', buf[i]); + } +} |