Merge "Fix <sys/resource.h>."
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index d0fa528..6e10daa 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -62,12 +62,21 @@
 int     tgkill(pid_t tgid, pid_t tid, int sig)  all
 int     __ptrace:ptrace(int request, int pid, void* addr, void* data)  all
 int     __set_thread_area:set_thread_area(void*  user_desc)  mips,x86
-int     __getpriority:getpriority(int, int)  all
-int     setpriority(int, int, int)   all
-int     setrlimit(int resource, const struct rlimit* rlp)  all
-int     getrlimit:ugetrlimit(int resource, struct rlimit* rlp)  arm,x86
-int     getrlimit:getrlimit(int resource, struct rlimit* rlp)  aarch64,mips,x86_64
-int     getrusage(int who, struct rusage*  r_usage)  all
+
+# <sys/resource.h>
+int getrusage(int, struct rusage*)  all
+int __getpriority:getpriority(int, int)  all
+int setpriority(int, int, int)   all
+# On LP64, rlimit and rlimit64 are the same.
+# On 32-bit systems we use prlimit64 to implement the rlimit64 functions.
+int getrlimit:ugetrlimit(int, struct rlimit*)  arm,x86
+int getrlimit(int, struct rlimit*)  mips
+int getrlimit|getrlimit64(int, struct rlimit*)  aarch64,x86_64
+int setrlimit(int, const struct rlimit*)  arm,mips,x86
+int setrlimit|setrlimit64(int, const struct rlimit*)  aarch64,x86_64
+int prlimit64|prlimit(pid_t, int, struct rlimit64*, const struct rlimit64*)  aarch64,x86_64
+int prlimit64(pid_t, int, struct rlimit64*, const struct rlimit64*)  arm,mips,x86
+
 int     setgroups:setgroups32(int, const gid_t*)   arm,x86
 int     setgroups:setgroups(int, const gid_t*)     aarch64,mips,x86_64
 int     setpgid(pid_t, pid_t)  all
diff --git a/libc/arch-aarch64/syscalls.mk b/libc/arch-aarch64/syscalls.mk
index 3e5d191..653ef70 100644
--- a/libc/arch-aarch64/syscalls.mk
+++ b/libc/arch-aarch64/syscalls.mk
@@ -123,6 +123,7 @@
 syscall_src += arch-aarch64/syscalls/pipe2.S
 syscall_src += arch-aarch64/syscalls/prctl.S
 syscall_src += arch-aarch64/syscalls/pread64.S
+syscall_src += arch-aarch64/syscalls/prlimit64.S
 syscall_src += arch-aarch64/syscalls/pwrite64.S
 syscall_src += arch-aarch64/syscalls/read.S
 syscall_src += arch-aarch64/syscalls/readahead.S
diff --git a/libc/arch-aarch64/syscalls/getrlimit.S b/libc/arch-aarch64/syscalls/getrlimit.S
index 8b6548f..21b471e 100644
--- a/libc/arch-aarch64/syscalls/getrlimit.S
+++ b/libc/arch-aarch64/syscalls/getrlimit.S
@@ -19,3 +19,6 @@
 
     ret
 END(getrlimit)
+
+    .globl _C_LABEL(getrlimit64)
+    .equ _C_LABEL(getrlimit64), _C_LABEL(getrlimit)
diff --git a/libc/arch-aarch64/syscalls/prlimit64.S b/libc/arch-aarch64/syscalls/prlimit64.S
new file mode 100644
index 0000000..439e355
--- /dev/null
+++ b/libc/arch-aarch64/syscalls/prlimit64.S
@@ -0,0 +1,24 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(prlimit64)
+    stp     x29, x30, [sp, #-16]!
+    mov     x29,  sp
+    str     x8,       [sp, #-16]!
+
+    mov     x8, __NR_prlimit64
+    svc     #0
+
+    ldr     x8,       [sp], #16
+    ldp     x29, x30, [sp], #16
+
+    cmn     x0, #(MAX_ERRNO + 1)
+    cneg    x0, x0, hi
+    b.hi    __set_errno
+
+    ret
+END(prlimit64)
+
+    .globl _C_LABEL(prlimit)
+    .equ _C_LABEL(prlimit), _C_LABEL(prlimit64)
diff --git a/libc/arch-aarch64/syscalls/setrlimit.S b/libc/arch-aarch64/syscalls/setrlimit.S
index 3591a84..e723806 100644
--- a/libc/arch-aarch64/syscalls/setrlimit.S
+++ b/libc/arch-aarch64/syscalls/setrlimit.S
@@ -19,3 +19,6 @@
 
     ret
 END(setrlimit)
+
+    .globl _C_LABEL(setrlimit64)
+    .equ _C_LABEL(setrlimit64), _C_LABEL(setrlimit)
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index f1763ef..83e6a97 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -129,6 +129,7 @@
 syscall_src += arch-arm/syscalls/pipe2.S
 syscall_src += arch-arm/syscalls/prctl.S
 syscall_src += arch-arm/syscalls/pread64.S
+syscall_src += arch-arm/syscalls/prlimit64.S
 syscall_src += arch-arm/syscalls/pwrite64.S
 syscall_src += arch-arm/syscalls/read.S
 syscall_src += arch-arm/syscalls/readahead.S
diff --git a/libc/arch-arm/syscalls/prlimit64.S b/libc/arch-arm/syscalls/prlimit64.S
new file mode 100644
index 0000000..8d9c4ff
--- /dev/null
+++ b/libc/arch-arm/syscalls/prlimit64.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(prlimit64)
+    mov     ip, r7
+    ldr     r7, =__NR_prlimit64
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(prlimit64)
diff --git a/libc/arch-mips/syscalls.mk b/libc/arch-mips/syscalls.mk
index cc7e557..8d87b29 100644
--- a/libc/arch-mips/syscalls.mk
+++ b/libc/arch-mips/syscalls.mk
@@ -129,6 +129,7 @@
 syscall_src += arch-mips/syscalls/pipe2.S
 syscall_src += arch-mips/syscalls/prctl.S
 syscall_src += arch-mips/syscalls/pread64.S
+syscall_src += arch-mips/syscalls/prlimit64.S
 syscall_src += arch-mips/syscalls/pwrite64.S
 syscall_src += arch-mips/syscalls/read.S
 syscall_src += arch-mips/syscalls/readahead.S
diff --git a/libc/arch-mips/syscalls/prlimit64.S b/libc/arch-mips/syscalls/prlimit64.S
new file mode 100644
index 0000000..17e9157
--- /dev/null
+++ b/libc/arch-mips/syscalls/prlimit64.S
@@ -0,0 +1,23 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <asm/unistd.h>
+    .text
+    .globl prlimit64
+    .align 4
+    .ent prlimit64
+
+prlimit64:
+    .set noreorder
+    .cpload $t9
+    li $v0, __NR_prlimit64
+    syscall
+    bnez $a3, 1f
+    move $a0, $v0
+    j $ra
+    nop
+1:
+    la $t9,__set_errno
+    j $t9
+    nop
+    .set reorder
+    .end prlimit64
diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk
index 0699d09..b7d1e08 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -128,6 +128,7 @@
 syscall_src += arch-x86/syscalls/pipe2.S
 syscall_src += arch-x86/syscalls/prctl.S
 syscall_src += arch-x86/syscalls/pread64.S
+syscall_src += arch-x86/syscalls/prlimit64.S
 syscall_src += arch-x86/syscalls/pwrite64.S
 syscall_src += arch-x86/syscalls/read.S
 syscall_src += arch-x86/syscalls/readahead.S
diff --git a/libc/arch-x86/syscalls/prlimit64.S b/libc/arch-x86/syscalls/prlimit64.S
new file mode 100644
index 0000000..2256425
--- /dev/null
+++ b/libc/arch-x86/syscalls/prlimit64.S
@@ -0,0 +1,34 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(prlimit64)
+    pushl   %ebx
+    pushl   %ecx
+    pushl   %edx
+    pushl   %esi
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset ebx, 0
+    .cfi_rel_offset ecx, 4
+    .cfi_rel_offset edx, 8
+    .cfi_rel_offset esi, 12
+    mov     20(%esp), %ebx
+    mov     24(%esp), %ecx
+    mov     28(%esp), %edx
+    mov     32(%esp), %esi
+    movl    $__NR_prlimit64, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+    orl     $-1, %eax
+1:
+    popl    %esi
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(prlimit64)
diff --git a/libc/arch-x86_64/syscalls.mk b/libc/arch-x86_64/syscalls.mk
index cac7423..ec09e77 100644
--- a/libc/arch-x86_64/syscalls.mk
+++ b/libc/arch-x86_64/syscalls.mk
@@ -124,6 +124,7 @@
 syscall_src += arch-x86_64/syscalls/pipe2.S
 syscall_src += arch-x86_64/syscalls/prctl.S
 syscall_src += arch-x86_64/syscalls/pread64.S
+syscall_src += arch-x86_64/syscalls/prlimit64.S
 syscall_src += arch-x86_64/syscalls/pwrite64.S
 syscall_src += arch-x86_64/syscalls/read.S
 syscall_src += arch-x86_64/syscalls/readahead.S
diff --git a/libc/arch-x86_64/syscalls/getrlimit.S b/libc/arch-x86_64/syscalls/getrlimit.S
index 1417b28..0b3536c 100644
--- a/libc/arch-x86_64/syscalls/getrlimit.S
+++ b/libc/arch-x86_64/syscalls/getrlimit.S
@@ -14,3 +14,6 @@
 1:
     ret
 END(getrlimit)
+
+    .globl _C_LABEL(getrlimit64)
+    .equ _C_LABEL(getrlimit64), _C_LABEL(getrlimit)
diff --git a/libc/arch-x86_64/syscalls/prlimit64.S b/libc/arch-x86_64/syscalls/prlimit64.S
new file mode 100644
index 0000000..b451e8f
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/prlimit64.S
@@ -0,0 +1,20 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(prlimit64)
+    movq    %rcx, %r10
+    movl    $__NR_prlimit64, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno
+    orq     $-1, %rax
+1:
+    ret
+END(prlimit64)
+
+    .globl _C_LABEL(prlimit)
+    .equ _C_LABEL(prlimit), _C_LABEL(prlimit64)
diff --git a/libc/arch-x86_64/syscalls/setrlimit.S b/libc/arch-x86_64/syscalls/setrlimit.S
index de5b3b7..e445ec0 100644
--- a/libc/arch-x86_64/syscalls/setrlimit.S
+++ b/libc/arch-x86_64/syscalls/setrlimit.S
@@ -14,3 +14,6 @@
 1:
     ret
 END(setrlimit)
+
+    .globl _C_LABEL(setrlimit64)
+    .equ _C_LABEL(setrlimit64), _C_LABEL(setrlimit)
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index 884dd8b..d7ccdb9 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -28,10 +28,9 @@
 
 #include <errno.h>
 #include <stdarg.h>
+#include <sys/resource.h>
 #include <sys/types.h>
 #include <sys/vfs.h>
-#include <sys/vfs.h>
-#include <unistd.h>
 #include <unistd.h>
 
 #if __LP64__
@@ -86,3 +85,13 @@
 ssize_t pwrite(int fd, const void* buf, size_t byte_count, off_t offset) {
   return pwrite64(fd, buf, byte_count, static_cast<off64_t>(offset));
 }
+
+// There is no getrlimit64 system call, so we need to use prlimit64.
+int getrlimit64(int resource, rlimit64* limits64) {
+  return prlimit64(0, resource, NULL, limits64);
+}
+
+// There is no setrlimit64 system call, so we need to use prlimit64.
+int setrlimit64(int resource, const rlimit64* limits64) {
+  return prlimit64(0, resource, limits64, NULL);
+}
diff --git a/libc/include/sys/resource.h b/libc/include/sys/resource.h
index ef325c7..a91fa53 100644
--- a/libc/include/sys/resource.h
+++ b/libc/include/sys/resource.h
@@ -25,30 +25,35 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #ifndef _SYS_RESOURCE_H_
 #define _SYS_RESOURCE_H_
 
 #include <sys/cdefs.h>
-#include <sys/types.h>     /* MUST be included before linux/resource.h */
+#include <sys/types.h>
 
-/* TRICK AHEAD: <linux/resource.h> defines a getrusage function with
- *              a non-standard signature. this is surprising because the
- *              syscall seems to use the standard one instead.
- *              once again, creative macro usage saves the days
- */
-#define  getrusage   __kernel_getrusage
 #include <linux/resource.h>
-#undef   getrusage
-
-typedef unsigned long rlim_t;
 
 __BEGIN_DECLS
 
+typedef unsigned long rlim_t;
+
+extern int getrlimit(int, struct rlimit*);
+extern int setrlimit(int, const struct rlimit*);
+
+extern int getrlimit64(int, struct rlimit64*);
+extern int setrlimit64(int, const struct rlimit64*);
+
 extern int getpriority(int, int);
 extern int setpriority(int, int, int);
-extern int getrlimit(int resource, struct rlimit *rlp);
-extern int setrlimit(int resource, const struct rlimit *rlp);
-extern int getrusage(int  who, struct rusage*  r_usage);
+
+extern int getrusage(int, struct rusage*);
+
+#if __LP64__
+/* Implementing prlimit for 32-bit isn't worth the effort. */
+extern int prlimit(pid_t, int, const struct rlimit*, struct rlimit*);
+#endif
+extern int prlimit64(pid_t, int, const struct rlimit64*, struct rlimit64*);
 
 __END_DECLS
 
diff --git a/tests/Android.mk b/tests/Android.mk
index 916d0b2..0540400 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -61,6 +61,7 @@
     strings_test.cpp \
     stubs_test.cpp \
     sys_epoll_test.cpp \
+    sys_resource_test.cpp \
     sys_select_test.cpp \
     sys_sendfile_test.cpp \
     sys_stat_test.cpp \
diff --git a/tests/sys_resource_test.cpp b/tests/sys_resource_test.cpp
new file mode 100644
index 0000000..bd974cb
--- /dev/null
+++ b/tests/sys_resource_test.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/resource.h>
+
+#if __GLIBC__
+/* The host glibc we're currently building with doesn't have prlimit64 yet. */
+static int prlimit64(pid_t, int resource, const struct rlimit64* new_limit, struct rlimit64* old_limit) {
+  if (new_limit != NULL) {
+    return setrlimit64(resource, new_limit);
+  } else {
+    return getrlimit64(resource, old_limit);
+  }
+}
+#endif
+
+TEST(sys_resource, smoke) {
+#if __LP64__ || __GLIBC__
+  ASSERT_EQ(sizeof(rlimit), sizeof(rlimit64));
+  ASSERT_EQ(8U, sizeof(rlim_t));
+#else
+  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);
+  }
+
+  // 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);
+
+  // 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);
+
+  // 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);
+}