Fix <sys/resource.h>.

The situation here is a bit confusing. On 64-bit, rlimit and rlimit64 are
the same, and so getrlimit/getrlimit64, setrlimit/setrlimit64,
and prlimit/prlimit64 are all the same. On 32-bit, rlimit and rlimit64 are
different. 32-bit architectures other than MIPS go one step further by having
an even more limited getrlimit system call, so arm and x86 need to use
ugetrlimit instead of getrlimit. Worse, the 32-bit architectures don't have
64-bit getrlimit- and setrlimit-equivalent system calls, and you have to use
prlimit64 instead. There's no 32-bit prlimit system call, so there's no
easy implementation of that --- what should we do if the result of prlimit64
won't fit in a struct rlimit? Since 32-bit survived without prlimit/prlimit64
for this long, I'm not going to bother implementing prlimit for 32-bit.

We need the rlimit64 functions to be able to build strace 4.8 out of the box.

Change-Id: I1903d913b23016a2fc3b9f452885ac730d71e001
This commit is contained in:
Elliott Hughes 2014-01-09 10:17:03 -08:00
parent 8276d2875f
commit 0f461e35f6
19 changed files with 264 additions and 21 deletions

View File

@ -62,12 +62,21 @@ int tkill(pid_t tid, int sig) all
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

View File

@ -123,6 +123,7 @@ syscall_src += arch-aarch64/syscalls/personality.S
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

View File

@ -19,3 +19,6 @@ ENTRY(getrlimit)
ret
END(getrlimit)
.globl _C_LABEL(getrlimit64)
.equ _C_LABEL(getrlimit64), _C_LABEL(getrlimit)

View File

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

View File

@ -19,3 +19,6 @@ ENTRY(setrlimit)
ret
END(setrlimit)
.globl _C_LABEL(setrlimit64)
.equ _C_LABEL(setrlimit64), _C_LABEL(setrlimit)

View File

@ -129,6 +129,7 @@ syscall_src += arch-arm/syscalls/personality.S
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

View File

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

View File

@ -129,6 +129,7 @@ syscall_src += arch-mips/syscalls/personality.S
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

View File

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

View File

@ -128,6 +128,7 @@ syscall_src += arch-x86/syscalls/personality.S
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

View File

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

View File

@ -124,6 +124,7 @@ syscall_src += arch-x86_64/syscalls/personality.S
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

View File

@ -14,3 +14,6 @@ ENTRY(getrlimit)
1:
ret
END(getrlimit)
.globl _C_LABEL(getrlimit64)
.equ _C_LABEL(getrlimit64), _C_LABEL(getrlimit)

View File

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

View File

@ -14,3 +14,6 @@ ENTRY(setrlimit)
1:
ret
END(setrlimit)
.globl _C_LABEL(setrlimit64)
.equ _C_LABEL(setrlimit64), _C_LABEL(setrlimit)

View File

@ -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 pread(int fd, void* buf, size_t byte_count, off_t offset) {
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);
}

View File

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

View File

@ -61,6 +61,7 @@ test_src_files = \
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 \

View File

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