Merge "Contact proper debuggerd when crashing."
diff --git a/benchmarks/benchmark_main.cpp b/benchmarks/benchmark_main.cpp
index 6d83f8a..fae09be 100644
--- a/benchmarks/benchmark_main.cpp
+++ b/benchmarks/benchmark_main.cpp
@@ -22,7 +22,7 @@
#include <time.h>
#include <string>
-#include <map>
+#include <vector>
#include <inttypes.h>
@@ -38,6 +38,41 @@
return benchmarks;
}
+// Similar to the code in art, but supporting both binary and decimal prefixes.
+static std::string PrettyInt(uint64_t count, size_t base) {
+ if (base != 2 && base != 10) abort();
+
+ // The byte thresholds at which we display amounts. A count is displayed
+ // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
+ static const uint64_t kUnitThresholds2[] = {
+ 1024*1024*1024 /* Gi */, 2*1024*1024 /* Mi */, 3*1024 /* Ki */, 0,
+ };
+ static const uint64_t kUnitThresholds10[] = {
+ 1000*1000*1000 /* G */, 2*1000*1000 /* M */, 3*1000 /* k */, 0,
+ };
+ static const uint64_t kAmountPerUnit2[] = { 1024*1024*1024, 1024*1024, 1024, 1 };
+ static const uint64_t kAmountPerUnit10[] = { 1000*1000*1000, 1000*1000, 1000, 1 };
+ static const char* const kUnitStrings2[] = { "Gi", "Mi", "Ki", "" };
+ static const char* const kUnitStrings10[] = { "G", "M", "k", "" };
+
+ // Which set are we using?
+ const uint64_t* kUnitThresholds = ((base == 2) ? kUnitThresholds2 : kUnitThresholds10);
+ const uint64_t* kAmountPerUnit = ((base == 2) ? kAmountPerUnit2 : kAmountPerUnit10);
+ const char* const* kUnitStrings = ((base == 2) ? kUnitStrings2 : kUnitStrings10);
+
+ size_t i = 0;
+ for (; kUnitThresholds[i] != 0; ++i) {
+ if (count >= kUnitThresholds[i]) {
+ break;
+ }
+ }
+ char* s = NULL;
+ asprintf(&s, "%" PRId64 "%s", count / kAmountPerUnit[i], kUnitStrings[i]);
+ std::string result(s);
+ free(s);
+ return result;
+}
+
static int Round(int n) {
int base = 1;
while (base*10 < n) {
@@ -154,27 +189,25 @@
char throughput[100];
throughput[0] = '\0';
+
if (g_benchmark_total_time_ns > 0 && g_bytes_processed > 0) {
- double mib_processed = static_cast<double>(g_bytes_processed)/1e6;
+ double gib_processed = static_cast<double>(g_bytes_processed)/1e9;
double seconds = static_cast<double>(g_benchmark_total_time_ns)/1e9;
- snprintf(throughput, sizeof(throughput), " %8.2f MiB/s", mib_processed/seconds);
+ snprintf(throughput, sizeof(throughput), " %8.3f GiB/s", gib_processed/seconds);
}
char full_name[100];
if (fn_range_ != NULL) {
- if (arg >= (1<<20)) {
- snprintf(full_name, sizeof(full_name), "%s/%dM", name_, arg/(1<<20));
- } else if (arg >= (1<<10)) {
- snprintf(full_name, sizeof(full_name), "%s/%dK", name_, arg/(1<<10));
- } else {
- snprintf(full_name, sizeof(full_name), "%s/%d", name_, arg);
- }
+ snprintf(full_name, sizeof(full_name), "%s/%s", name_, PrettyInt(arg, 2).c_str());
} else {
snprintf(full_name, sizeof(full_name), "%s", name_);
}
- printf("%-*s %10d %10" PRId64 "%s\n", g_name_column_width, full_name,
- iterations, g_benchmark_total_time_ns/iterations, throughput);
+ printf("%-*s %10s %10" PRId64 "%s\n",
+ g_name_column_width, full_name,
+ PrettyInt(iterations, 10).c_str(),
+ g_benchmark_total_time_ns/iterations,
+ throughput);
fflush(stdout);
}
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 386ea04..fe25d76 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -65,3 +65,13 @@
ReadWriteTest(iters, chunk_size, fwrite, false);
}
BENCHMARK(BM_stdio_fwrite_unbuffered)->AT_COMMON_SIZES;
+
+static void BM_stdio_fopen_fgets_fclose(int iters) {
+ char buf[1024];
+ for (int i = 0; i < iters; ++i) {
+ FILE* fp = fopen("/proc/version", "re");
+ fgets(buf, sizeof(buf), fp);
+ fclose(fp);
+ }
+}
+BENCHMARK(BM_stdio_fopen_fgets_fclose);
diff --git a/libc/Android.mk b/libc/Android.mk
index cc1585c..e96bcff 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -61,6 +61,7 @@
stdio/fread.c \
stdio/snprintf.c\
stdio/sprintf.c \
+ stdio/stdio.c \
stdio/stdio_ext.cpp \
# Fortify implementations of libc functions.
@@ -450,7 +451,6 @@
upstream-openbsd/lib/libc/stdio/setbuffer.c \
upstream-openbsd/lib/libc/stdio/setvbuf.c \
upstream-openbsd/lib/libc/stdio/sscanf.c \
- upstream-openbsd/lib/libc/stdio/stdio.c \
upstream-openbsd/lib/libc/stdio/swprintf.c \
upstream-openbsd/lib/libc/stdio/swscanf.c \
upstream-openbsd/lib/libc/stdio/tempnam.c \
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 15d04c2..c431835 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -1090,7 +1090,7 @@
XLOG("ns_parserr failed. %s\n", strerror(errno));
}
- XLOG("TTL = %d\n", result);
+ XLOG("TTL = %lu\n", result);
return result;
}
diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c
index e052128..baf62b9 100644
--- a/libc/stdio/fread.c
+++ b/libc/stdio/fread.c
@@ -35,6 +35,7 @@
#include <string.h>
#include <stdint.h>
#include <errno.h>
+#include <sys/param.h>
#include "local.h"
#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
@@ -42,13 +43,8 @@
size_t
fread(void *buf, size_t size, size_t count, FILE *fp)
{
- size_t resid;
- char *p;
- int r;
- size_t total;
-
/*
- * Extension: Catch integer overflow
+ * Extension: Catch integer overflow.
*/
if ((size >= MUL_NO_OVERFLOW || count >= MUL_NO_OVERFLOW) &&
size > 0 && SIZE_MAX / size < count) {
@@ -57,48 +53,81 @@
return (0);
}
+ const size_t desired_total = count * size;
+ size_t total = desired_total;
+
/*
* ANSI and SUSv2 require a return value of 0 if size or count are 0.
*/
- if ((resid = count * size) == 0)
+ if (total == 0) {
return (0);
+ }
+
FLOCKFILE(fp);
_SET_ORIENTATION(fp, -1);
+
+ // TODO: how can this ever happen?!
if (fp->_r < 0)
fp->_r = 0;
- total = resid;
- p = buf;
- // 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);
+ /*
+ * Ensure _bf._size is valid.
+ */
+ if (fp->_bf._base == NULL) {
+ __smakebuf(fp);
}
- // 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 */
- p += r;
- resid -= r;
+ char* dst = buf;
+
+ while (total > 0) {
+ /*
+ * Copy data out of the buffer.
+ */
+ size_t buffered_bytes = MIN((size_t) fp->_r, total);
+ memcpy(dst, fp->_p, buffered_bytes);
+ fp->_p += buffered_bytes;
+ fp->_r -= buffered_bytes;
+ dst += buffered_bytes;
+ total -= buffered_bytes;
+
+ /*
+ * Are we done?
+ */
+ if (total == 0) {
+ goto out;
+ }
+
+ /*
+ * Do we have so much more to read that we should
+ * avoid copying it through the buffer?
+ */
+ if (total > (size_t) fp->_bf._size) {
+ break;
+ }
+
+ /*
+ * Less than a buffer to go, so refill the buffer and
+ * go around the loop again.
+ */
if (__srefill(fp)) {
- /* no more input: return partial result */
- FUNLOCKFILE(fp);
- return ((total - resid) / size);
+ goto out;
}
}
- (void)memcpy((void *)p, (void *)fp->_p, resid);
- fp->_r -= resid;
- fp->_p += resid;
+
+ /*
+ * Read directly into the caller's buffer.
+ */
+ while (total > 0) {
+ ssize_t bytes_read = (*fp->_read)(fp->_cookie, dst, total);
+ if (bytes_read <= 0) {
+ fp->_flags = (fp->_r == 0) ? __SEOF : __SERR;
+ break;
+ }
+ dst += bytes_read;
+ total -= bytes_read;
+ }
+
+out:
FUNLOCKFILE(fp);
- return (count);
+ return ((desired_total - total) / size);
}
diff --git a/libc/upstream-openbsd/lib/libc/stdio/stdio.c b/libc/stdio/stdio.c
similarity index 88%
rename from libc/upstream-openbsd/lib/libc/stdio/stdio.c
rename to libc/stdio/stdio.c
index a4a27b5..13b9887 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -31,6 +31,7 @@
* SUCH DAMAGE.
*/
+#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
@@ -46,7 +47,7 @@
FILE *fp = cookie;
int ret;
- ret = read(fp->_file, buf, n);
+ ret = TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
/* if the read succeeded, update the current offset */
if (ret >= 0)
fp->_offset += ret;
@@ -61,9 +62,9 @@
FILE *fp = cookie;
if (fp->_flags & __SAPP)
- (void) lseek(fp->_file, (off_t)0, SEEK_END);
+ (void) TEMP_FAILURE_RETRY(lseek(fp->_file, (off_t)0, SEEK_END));
fp->_flags &= ~__SOFF; /* in case FAPPEND mode is set */
- return (write(fp->_file, buf, n));
+ return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
}
fpos_t
@@ -72,7 +73,7 @@
FILE *fp = cookie;
off_t ret;
- ret = lseek(fp->_file, (off_t)offset, whence);
+ ret = TEMP_FAILURE_RETRY(lseek(fp->_file, (off_t)offset, whence));
if (ret == (off_t)-1)
fp->_flags &= ~__SOFF;
else {
@@ -85,5 +86,5 @@
int
__sclose(void *cookie)
{
- return (close(((FILE *)cookie)->_file));
+ return TEMP_FAILURE_RETRY(close(((FILE *)cookie)->_file));
}
diff --git a/tests/Android.mk b/tests/Android.mk
index 38d85f8..3150655 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -212,19 +212,36 @@
include $(LOCAL_PATH)/Android.build.mk
# -----------------------------------------------------------------------------
+# Library of bionic customized gtest main function.
+# -----------------------------------------------------------------------------
+libBionicGtestMain_src_files := gtest_main.cpp
+
+libBionicGtestMain_cflags := $(test_cflags)
+
+libBionicGtestMain_cppflags := $(test_cppflags)
+
+module := libBionicGtestMain
+module_tag := optional
+build_type := target
+build_target := STATIC_TEST_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
+
+# -----------------------------------------------------------------------------
# Tests for the device using bionic's .so. Run with:
# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
# adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests64
# -----------------------------------------------------------------------------
bionic-unit-tests_whole_static_libraries := \
libBionicTests \
+ libBionicGtestMain \
bionic-unit-tests_static_libraries := \
libtinyxml2 \
liblog \
bionic-unit-tests_src_files := \
- gtest_main.cpp \
atexit_test.cpp \
dl_test.cpp \
dlext_test.cpp \
@@ -268,6 +285,7 @@
# -----------------------------------------------------------------------------
bionic-unit-tests-static_whole_static_libraries := \
libBionicTests \
+ libBionicGtestMain \
bionic-unit-tests-static_static_libraries := \
libm \
@@ -277,9 +295,6 @@
libtinyxml2 \
liblog \
-bionic-unit-tests-static_src_files := \
- gtest_main.cpp \
-
bionic-unit-tests-static_force_static_executable := true
# libc and libc++ both define std::nothrow. libc's is a private symbol, but this
@@ -302,7 +317,6 @@
ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
bionic-unit-tests-glibc_src_files := \
- gtest_main.cpp \
atexit_test.cpp \
dlfcn_test.cpp \
dl_test.cpp \
@@ -315,6 +329,7 @@
bionic-unit-tests-glibc_whole_static_libraries := \
libBionicStandardTests \
+ libBionicGtestMain \
bionic-unit-tests-glibc_ldlibs := \
-lrt -ldl -lutil \
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 6c5023b..99cd4ee 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -319,18 +319,6 @@
fflush(stdout);
}
-static void TestcaseTimePrint(const TestCase& testcase) {
- int64_t testcase_time = 0;
- for (size_t i = 0; i < testcase.TestCount(); ++i) {
- testcase_time += testcase.GetTestTime(i);
- }
- printf("%zu %s from %s (%lld ms total)\n", testcase.TestCount(),
- (testcase.TestCount() == 1) ? "test" : "tests",
- testcase.GetName().c_str(),
- testcase_time / 1000000LL);
- fflush(stdout);
-}
-
static void OnTestIterationEndPrint(const std::vector<TestCase>& testcase_list, size_t /*iteration*/,
int64_t elapsed_time) {
@@ -364,10 +352,6 @@
}
}
- for (auto const& testcase : testcase_list) {
- TestcaseTimePrint(testcase);
- }
-
ColoredPrintf(COLOR_GREEN, "[==========] ");
printf("%zu %s from %zu %s ran.", test_count, (test_count == 1) ? "test" : "tests",
testcase_count, (testcase_count == 1) ? "test case" : "test cases");
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index 3dbc485..950c7ed 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -34,7 +34,13 @@
TEST(stdio_ext, __fbufsize) {
FILE* fp = fopen("/proc/version", "r");
+ // Initially, there's no buffer in case the first thing you do is disable buffering.
+ ASSERT_EQ(0U, __fbufsize(fp));
+
+ // A read forces a buffer to be created.
char buf[128];
+ fgets(buf, sizeof(buf), fp);
+ ASSERT_EQ(1024U, __fbufsize(fp));
ASSERT_EQ(0, setvbuf(fp, buf, _IOFBF, 1));
ASSERT_EQ(1U, __fbufsize(fp));
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index de5eea3..6d7e72b 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -888,3 +888,25 @@
ASSERT_EQ('\xff', buf[i]);
}
}
+
+TEST(fread, fread_EOF) {
+ const char* digits = "0123456789";
+ FILE* fp = fmemopen((char*) digits, sizeof(digits), "r");
+
+ // Try to read too much, but little enough that it still fits in the FILE's internal buffer.
+ char buf1[4 * 4];
+ memset(buf1, 0, sizeof(buf1));
+ ASSERT_EQ(2U, fread(buf1, 4, 4, fp));
+ ASSERT_STREQ(buf1, "01234567");
+ ASSERT_TRUE(feof(fp));
+
+ rewind(fp);
+
+ char buf2[4 * 4];
+ memset(buf2, 0, sizeof(buf2));
+ ASSERT_EQ(2U, fread(buf2, 4, 4096, fp));
+ ASSERT_STREQ(buf2, "01234567");
+ ASSERT_TRUE(feof(fp));
+
+ fclose(fp);
+}
diff --git a/tests/sys_resource_test.cpp b/tests/sys_resource_test.cpp
index 91d07ab..8cefc65 100644
--- a/tests/sys_resource_test.cpp
+++ b/tests/sys_resource_test.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
#include <sys/resource.h>
-TEST(sys_resource, smoke) {
+#include <gtest/gtest.h>
+
+TEST(sys_resource, rlimit_struct_size) {
#if defined(__LP64__) || defined(__GLIBC__)
ASSERT_EQ(sizeof(rlimit), sizeof(rlimit64));
ASSERT_EQ(8U, sizeof(rlim_t));
@@ -26,51 +26,75 @@
ASSERT_NE(sizeof(rlimit), sizeof(rlimit64));
ASSERT_EQ(4U, sizeof(rlim_t));
#endif
+}
- // Read with getrlimit, getrlimit64, and prlimit64.
- // (prlimit is prlimit64 on LP64 and unimplemented on 32-bit.)
- rlimit l32;
- rlimit64 l64;
- rlimit64 pr_l64;
- ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
- ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
- ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
- ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
- ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
- ASSERT_EQ(l64.rlim_max, pr_l64.rlim_max);
- if (l64.rlim_max == RLIM64_INFINITY) {
- ASSERT_EQ(RLIM_INFINITY, l32.rlim_max);
- } else {
- ASSERT_EQ(l64.rlim_max, l32.rlim_max);
+class SysResourceTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
+ ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
+ ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
}
- // Write with setrlimit and read back with everything.
- l32.rlim_cur = 123;
- ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &l32));
- ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
- ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
- ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
- ASSERT_EQ(123U, l32.rlim_cur);
- ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
- ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
+ void CheckResourceLimits();
- // Write with setrlimit64 and read back with everything.
- l64.rlim_cur = 456;
- ASSERT_EQ(0, setrlimit64(RLIMIT_CORE, &l64));
- ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
- ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
- ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
- ASSERT_EQ(456U, l32.rlim_cur);
- ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
- ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
+ protected:
+ rlimit l32_;
+ rlimit64 l64_;
+ rlimit64 pr_l64_;
+};
- // Write with prlimit64 and read back with everything.
- l64.rlim_cur = 789;
- ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &l64, NULL));
- ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
- ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
- ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
- ASSERT_EQ(789U, l32.rlim_cur);
- ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
- ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
+void SysResourceTest::CheckResourceLimits() {
+ ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
+ ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
+ ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
+ ASSERT_EQ(l64_.rlim_cur, pr_l64_.rlim_cur);
+ if (l64_.rlim_cur == RLIM64_INFINITY) {
+ ASSERT_EQ(RLIM_INFINITY, l32_.rlim_cur);
+ } else {
+ ASSERT_EQ(l64_.rlim_cur, l32_.rlim_cur);
+ }
+
+ ASSERT_EQ(l64_.rlim_max, pr_l64_.rlim_max);
+ if (l64_.rlim_max == RLIM64_INFINITY) {
+ ASSERT_EQ(RLIM_INFINITY, l32_.rlim_max);
+ } else {
+ ASSERT_EQ(l64_.rlim_max, l32_.rlim_max);
+ }
+}
+
+// Force rlim_max to be bigger than a constant so we can continue following test.
+// Change resource limit setting with "ulimit -Hc" in the shell if this test fails.
+TEST_F(SysResourceTest, RLIMIT_CORE_rlim_max_not_zero) {
+ ASSERT_TRUE(l32_.rlim_max == RLIM_INFINITY || l32_.rlim_max >= 456U) <<
+ "RLIMIT_CORE rlim_max = " << l32_.rlim_max;
+}
+
+TEST_F(SysResourceTest, get_resource_limit_equal) {
+ CheckResourceLimits();
+}
+
+TEST_F(SysResourceTest, setrlimit) {
+ l32_.rlim_cur = 123U;
+ ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &l32_));
+ CheckResourceLimits();
+ ASSERT_EQ(123U, l32_.rlim_cur);
+}
+
+TEST_F(SysResourceTest, setrlimit64) {
+ l64_.rlim_cur = 456U;
+ ASSERT_EQ(0, setrlimit64(RLIMIT_CORE, &l64_));
+ CheckResourceLimits();
+ ASSERT_EQ(456U, l64_.rlim_cur);
+}
+
+TEST_F(SysResourceTest, prlimit64) {
+ pr_l64_.rlim_cur = pr_l64_.rlim_max;
+ ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &pr_l64_, NULL));
+ CheckResourceLimits();
+ ASSERT_EQ(pr_l64_.rlim_max, pr_l64_.rlim_cur);
+}
+
+TEST_F(SysResourceTest, prlimit) {
+ // prlimit is prlimit64 on LP64 and unimplemented on 32-bit. So we only test prlimit64.
}
diff --git a/tools/bionicbb/gmail_listener.py b/tools/bionicbb/gmail_listener.py
index 6a8b9e6..f4936d6 100644
--- a/tools/bionicbb/gmail_listener.py
+++ b/tools/bionicbb/gmail_listener.py
@@ -297,6 +297,13 @@
except NotImplementedError as ex:
print ex
return False
+ except gerrit.GerritError as ex:
+ if ex.code == 404:
+ print '{}(404): {}!'.format(
+ termcolor.colored('ERROR', 'red'), ex)
+ return True
+ else:
+ return False
def main(argc, argv):