diff --git a/ndk/sources/android/libportable/Android.mk b/ndk/sources/android/libportable/Android.mk index 135001273..1e0c79ae9 100644 --- a/ndk/sources/android/libportable/Android.mk +++ b/ndk/sources/android/libportable/Android.mk @@ -36,11 +36,15 @@ libportable_arch_src_files += \ arch-mips/clone.c \ arch-mips/epoll.c \ arch-mips/errno.c \ + arch-mips/eventfd.c \ arch-mips/fcntl.c \ + arch-mips/filefd.c \ + arch-mips/inotify.c \ arch-mips/ioctl.c \ arch-mips/mmap.c \ arch-mips/open.c \ arch-mips/poll.c \ + arch-mips/pipe.c \ arch-mips/pthread.c \ arch-mips/resource.c \ arch-mips/signal.c \ @@ -50,6 +54,7 @@ libportable_arch_src_files += \ arch-mips/statfs.c \ arch-mips/syscall.c \ arch-mips/timer.c \ + arch-mips/timerfd.c \ arch-mips/waitpid.c endif diff --git a/ndk/sources/android/libportable/arch-mips/clone.c b/ndk/sources/android/libportable/arch-mips/clone.c index 30cfe4bf6..2fc642168 100644 --- a/ndk/sources/android/libportable/arch-mips/clone.c +++ b/ndk/sources/android/libportable/arch-mips/clone.c @@ -23,6 +23,7 @@ #include #include #include +#include #define PORTABLE_TAG "clone_portable" #include @@ -58,11 +59,32 @@ int clone_portable(int (*fn)(void *), void *child_stack, int port_flags, void *a char *mips_term_signame; int portable_term_signum; char *portable_term_signame; + int cloning_vm = ((port_flags & CLONE_VM) == CLONE_VM); + int cloning_files = ((port_flags & CLONE_FILES) == CLONE_FILES); + int cloning_sighand = ((port_flags & CLONE_SIGHAND) == CLONE_SIGHAND); ALOGV(" "); ALOGV("%s(fn:%p, child_stack:%p, port_flags:0x%x, arg:%p, ...) {", __func__, fn, child_stack, port_flags, arg); + /* Shared file descriptor table requires shared memory. */ + if (cloning_files != cloning_vm) { + ALOGE("%s: cloning_files:%d != cloning_vm:%d) ...", __func__, + cloning_files, cloning_vm); + + ALOGE("%s: ... port_flags:0x%x Not Supported by Lib-Portable!", __func__, + port_flags); + } + + /* Shared signal handler table requires shared memory. */ + if (cloning_sighand != cloning_vm) { + ALOGE("%s: cloning_sighand:%d != cloning_vm:%d) ...", __func__, + cloning_sighand, cloning_vm); + + ALOGE("%s: ... port_flags:0x%x Not Supported by Lib-Portable!", __func__, + port_flags); + } + /* Extract optional parameters - they are cumulative. */ va_start(args, arg); if (port_flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID)) { @@ -84,14 +106,34 @@ int clone_portable(int (*fn)(void *), void *child_stack, int port_flags, void *a mips_flags = port_flags; } else { portable_term_signame = map_portable_signum_to_name(portable_term_signum); + ALOGV("%s: portable_term_signum:0x%x:'%s'", __func__, + portable_term_signum, portable_term_signame); mips_term_signum = signum_pton(portable_term_signum); mips_term_signame = map_mips_signum_to_name(mips_term_signum); + ALOGV("%s: mips_term_signum:0x%x:'%s'", __func__, + mips_term_signum, mips_term_signame); mips_flags = (port_flags & ~0xFF) | (mips_term_signum & 0xFF); } + ALOGV("%s: clone(%p, %p, 0x%x, %p, %p, %p, %p);", __func__, + fn, child_stack, mips_flags, arg, parent_tidptr, new_tls, child_tidptr); ret = clone(fn, child_stack, mips_flags, arg, parent_tidptr, new_tls, child_tidptr); + if (ret > 0) { + /* + * Disable mapping in the parent if the child could interfere + * and make things even worse than skipping the signal and + * file read mapping. + */ + if (cloning_files != cloning_vm) { + filefd_disable_mapping(); + } + if (cloning_sighand != cloning_vm) { + signal_disable_mapping(); + } + } + ALOGV("%s: return(ret:%d); }", __func__, ret); return ret; } diff --git a/ndk/sources/android/libportable/arch-mips/eventfd.c b/ndk/sources/android/libportable/arch-mips/eventfd.c new file mode 100644 index 000000000..c16d9bc2b --- /dev/null +++ b/ndk/sources/android/libportable/arch-mips/eventfd.c @@ -0,0 +1,95 @@ +/* + * Copyright 2012, 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 +#include + +#include +#include + +#include +#include +#include +#include + +#define PORTABLE_TAG "eventfd_portable" +#include + + +/* NOTE: LTP defaults to using O_NONBLOCK even if EFD_NONBLOCK is defined */ + + +/* + * Portable to Native event flags mapper. + */ +static inline int efd_flags_pton(int portable_flags) +{ + int native_flags = 0; + + ALOGV("%s(portable_flags:0x%x) {", __func__, portable_flags); + + if (portable_flags & EFD_NONBLOCK_PORTABLE) { + native_flags |= EFD_NONBLOCK; + portable_flags &= ~EFD_NONBLOCK_PORTABLE; + } + + if (portable_flags & EFD_CLOEXEC_PORTABLE) { + native_flags |= EFD_CLOEXEC; + portable_flags &= EFD_CLOEXEC_PORTABLE; + } + + if (portable_flags & EFD_SEMAPHORE_PORTABLE) { + native_flags |= EFD_SEMAPHORE; + portable_flags &= EFD_SEMAPHORE_PORTABLE; + } + + if (portable_flags != 0) { + ALOGW("%s: portable_flags:0x%x != 0; Unsupported Flags being used!", + __func__, portable_flags); + } + ALOGV("%s: return(native_flags:%d); }", __func__, native_flags); + return native_flags; +} + + +/* + * In the original eventfd() the portable_flags were unused up to + * linux 2.6.26 and had to be zero. Android simply uses the + * new eventfd2 system call number, so it likely best to just use + * the Android eventfd() for both eventfd and eventfd2 system calls. + */ +int eventfd_portable(unsigned int initval, int portable_flags) { + int rv; + int native_flags; + + ALOGV(" "); + ALOGV("%s(initval:%u, portable_flags:%d) {", __func__, + initval, portable_flags); + + native_flags = efd_flags_pton(portable_flags); + + rv = eventfd(initval, native_flags); + if (rv >= 0) { + if (native_flags & EFD_CLOEXEC) { + filefd_CLOEXEC_enabled(rv); + } + filefd_opened(rv, EVENT_FD_TYPE); + } + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + diff --git a/ndk/sources/android/libportable/arch-mips/fcntl.c b/ndk/sources/android/libportable/arch-mips/fcntl.c index 07ba5757b..bb0b3b7f1 100644 --- a/ndk/sources/android/libportable/arch-mips/fcntl.c +++ b/ndk/sources/android/libportable/arch-mips/fcntl.c @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include #include @@ -331,6 +333,22 @@ int fcntl_portable(int fd, int portable_cmd, ...) case F_GETLEASE: case F_NOTIFY: result = __fcntl64(fd, mips_cmd, arg); + if (result < 0) { + ALOGV("%s: result = %d = __fcntl64(fd:%d, mips_cmd:0x%x, arg:%p);", __func__, + result, fd, mips_cmd, arg); + } else { + if (mips_cmd == F_SETFD) { + /* + * File descriptor flag bits got set or cleared. + */ + flags = (int)arg; + if (flags & FD_CLOEXEC) { + filefd_CLOEXEC_enabled(fd); + } else { + filefd_CLOEXEC_disabled(fd); + } + } + } break; default: diff --git a/ndk/sources/android/libportable/arch-mips/filefd.c b/ndk/sources/android/libportable/arch-mips/filefd.c new file mode 100644 index 000000000..4911ee1e8 --- /dev/null +++ b/ndk/sources/android/libportable/arch-mips/filefd.c @@ -0,0 +1,502 @@ +/* + * Copyright 2012, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORTABLE_TAG "filefd_portable" +#include + +/* + * Maintaining a list of special file descriptors in lib-portable: + * --------------------------------------------------------------- + * + * These are file descriptors which were opened with system calls + * which make it possible to read kernel data structures via the + * read system call. See man pages for: + * signalfd(2) + * eventfd(2) + * timerfd_create(2) + * + * The files conditioned with signalfd(2) need to have their reads + * intercepted to correct signal numbers. This is done using this table + * of mapped files. + * + * The signalfd(2) semantics are maintained across execve(2) by exporting + * and importing environment variables for file descriptors that are not + * marked as close-on-execute. For example testing import code with: + * Eg: + * export ANDROID_PORTABLE_MAPPED_FILE_DESCRIPTORS=10,17 + * export ANDROID_PORTABLE_MAPPED_FILE_TYPES=2,1 + * + * Where + * filefd_mapped_file[10] = SIGNAL_FD_TYPE:2 + * filefd_FD_CLOEXEC_file[10] = 0; + * and + * filefd_mapped_file[17] = EVENT_FD_TYPE:1 + * filefd_FD_CLOEXEC_file[17] = 0; + * + * A table of CLOEXEC_files is maintained via call-backs + * in open_portable() and fcntl_portable() which indicates + * the files with close-on-execute semantics. + * + * The signalfd(2) fork(2) and thread semantics are not + * affected by the mapping of signalfd() file descriptor reads. + * + * This algorithm requires that threads have the same sharing + * attributes for file descriptors and memory and will be disabled + * by a call from clone() if the environment is unsuitable for it's use. + */ + +static char *fd_env_name = "ANDROID_PORTABLE_MAPPED_FILE_DESCRIPTORS"; +static char *type_env_name = "ANDROID_PORTABLE_MAPPED_FILE_TYPES"; +static enum filefd_type filefd_mapped_file[__FD_SETSIZE]; +static int filefd_FD_CLOEXEC_file[__FD_SETSIZE]; + +static volatile int filefd_mapped_files = 0; +static volatile int filefd_enabled = 1; + +/* + * Assuming sizeof(int)==4, and __FD_SETSIZE < 10000 each token will + * occupy a maximum of 5 characters (4 digits + delimiter:','). The tokens + * are the numbers above, a file descriptor (0..9999), and the filefd_type's + * which are a single digit. + * + * The arrays used to manipulate the environment variables are allocated using + * malloc to avoid overrunning the stack. + */ +#if __FD_SETSIZE >= 10000 +#error MAX_ENV_SIZE must be increased +#endif + +#define MAX_ENV_SIZE (__FD_SETSIZE * 5) + +static int export_fd_env() +{ + const int max_env_size = MAX_ENV_SIZE; + int type_env_bytes_remaining = max_env_size; + char *type_env_allocated = NULL, *type_env; + int fd_env_bytes_remaining = max_env_size; + char *fd_env_allocated = NULL, *fd_env; + int exported_file_descriptors = 0; + enum filefd_type fd_type; + int overwrite = 1; + int fd_count = 0; + int saved_errno; + int fd_cloexec; + int len; + int rv1; + int rv2; + int rv; + int fd; + + ALOGV("%s:() {", __func__); + + saved_errno = errno; + + type_env_allocated = malloc(max_env_size); + fd_env_allocated = malloc(max_env_size); + if (type_env_allocated == NULL || fd_env_allocated == NULL) { + ALOGE("%s: type_env_allocated:%p, fd_env_allocated:%p; FIXME!", __func__, + type_env_allocated, fd_env_allocated); + + rv = -1; + goto done; + } else { + ALOGV("%s: type_env_allocated:%p, fd_env_allocated:%p;", __func__, + type_env_allocated, fd_env_allocated); + } + + type_env = type_env_allocated; + fd_env = fd_env_allocated; + + for (fd = 0; fd < __FD_SETSIZE; fd++) { + fd_type = filefd_mapped_file[fd]; + if (fd_type != UNUSED_FD_TYPE) { + ++fd_count; + ALOGV("%s: fd_type = %d = filefd_mapped_file[fd:%d]; ++fdcount:%d;", __func__, + fd_type, fd, fd_count); + + fd_cloexec = filefd_FD_CLOEXEC_file[fd]; + ALOGV("%s: fd_cloexec = %d = filefd_FD_CLOEXEC_file[fd:%d];", __func__, + fd_cloexec, fd); + + if (fd_cloexec == 0) { + rv = snprintf(fd_env, fd_env_bytes_remaining, "%d,", fd); + ASSERT(rv > 0); + fd_env += rv; + fd_env_bytes_remaining -= rv; + rv = snprintf(type_env, type_env_bytes_remaining, "%d,", filefd_mapped_file[fd]); + ASSERT(rv > 0); + type_env += rv; + type_env_bytes_remaining -= rv; + exported_file_descriptors++; + } + + /* + * There is a chance of inconsistent results here if + * another thread is updating the array while it was + * being copied, but this code is only run during exec + * so the state of the file descriptors that the child + * sees will be inconsistent anyway. + */ + if (fd_count == filefd_mapped_files) + break; + } + } + if (fd_count != filefd_mapped_files) { + ALOGE("%s: fd_count:%d != filefd_mapped_files:%d; [Likely Race; add futex?]", __func__, + fd_count, filefd_mapped_files); + + } + if (exported_file_descriptors == 0) { + rv1 = unsetenv(fd_env_name); + rv2 = unsetenv(type_env_name); + if (rv1 != 0 || rv2 != 0) { + ALOGV("%s: Note: unsetenv() failed!", __func__); + } + rv = 0; + } else { + if (fd_env > fd_env_allocated) { + fd_env--; /* backup fd_env to last ',' */ + } + *fd_env = '\0'; + + if (type_env > type_env_allocated) { + type_env--; /* backup type_env to last ',' */ + } + *type_env = '\0'; + + rv = setenv(fd_env_name, fd_env_allocated, overwrite); + if (rv != 0) { + ALOGE("%s: rv:%d = setenv(fd_env_name:'%s', fd_env_allocated:'%s' ...);", __func__, + rv, fd_env_name, fd_env_allocated); + } else { + ALOGV("%s: rv:%d = setenv(fd_env_name:'%s', fd_env_allocated:'%s' ...);", __func__, + rv, fd_env_name, fd_env_allocated); + } + if (rv != 0) goto done; + + rv = setenv(type_env_name, type_env_allocated, overwrite); + + if (rv != 0) { + ALOGE("%s: rv:%d = setenv(type_env_name:'%s', type_env_allocated:'%s' ...);", + __func__, rv, type_env_name, type_env_allocated); + } else { + ALOGV("%s: rv:%d = setenv(type_env_name:'%s', type_env_allocated:'%s' ...);", + __func__, rv, type_env_name, type_env_allocated); + } + } + +done: + if (type_env_allocated) + free(type_env_allocated); + + if (fd_env_allocated) + free(fd_env_allocated); + + errno = saved_errno; + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + + +static int import_fd_env(int verify) +{ + char *type_env_allocated = NULL; + char *fd_env_allocated = NULL; + char *type_token_saved_ptr; + char *fd_token_saved_ptr; + enum filefd_type fd_type; + char *type_env, *fd_env; + int saved_errno; + char *type_token; + char *fd_token; + int rv = 0; + int fd; + + ALOGV("%s:(verify:%d) {", __func__, verify); + + saved_errno = errno; + + /* + * get file descriptor environment pointer and make a + * a copy of the string. + */ + fd_env = getenv(fd_env_name); + if (fd_env == NULL) { + ALOGV("%s: fd_env = NULL = getenv('%s');", __func__, + fd_env_name); + goto done; + } else { + ALOGV("%s: fd_env = '%s' = getenv('%s');", __func__, + fd_env, fd_env_name); + + fd_env_allocated = malloc(strlen(fd_env)+1); + if (fd_env_allocated == NULL) { + ALOGE("%s: fd_env_allocated = NULL; malloc failed", __func__); + goto done; + } + strcpy(fd_env_allocated, fd_env); + } + + /* + * get file descriptor environment pointer and make a copy of + * the string to our stack. + */ + type_env = getenv(type_env_name); + if (type_env == NULL) { + ALOGV("%s: type_env = NULL = getenv(type_env_name:'%s');", __func__, + type_env_name); + goto done; + } else { + ALOGV("%s: type_env = '%s' = getenv(type_env_name:'%s');", __func__, + type_env, type_env_name); + + type_env_allocated = malloc(strlen(type_env)+1); + if (type_env_allocated == NULL) { + ALOGE("%s: type_env_allocated = NULL; malloc failed", __func__); + goto done; + } + strcpy(type_env_allocated, type_env); + } + + /* + * Setup strtok_r(), use it to parse the env tokens, and + * initialise the filefd_mapped_file array. + */ + fd_token = strtok_r(fd_env_allocated, ",", &fd_token_saved_ptr); + type_token = strtok_r(type_env_allocated, ",", &type_token_saved_ptr); + while (fd_token && type_token) { + fd = atoi(fd_token); + ASSERT(fd >= 0 ); + ASSERT(fd < __FD_SETSIZE); + + fd_type = (enum filefd_type) atoi(type_token); + ASSERT(fd_type > UNUSED_FD_TYPE); + ASSERT(fd_type < MAX_FD_TYPE); + + if (fd >= 0 && fd < __FD_SETSIZE) { + if (fd_type > UNUSED_FD_TYPE && fd_type < MAX_FD_TYPE) { + if (verify) { + ASSERT(filefd_mapped_file[fd] == fd_type); + ALOGV("%s: filefd_mapped_file[fd:%d] == fd_type:%d;", __func__, + fd, fd_type); + } else { + ASSERT(filefd_mapped_file[fd] == UNUSED_FD_TYPE); + + __atomic_inc(&filefd_mapped_files); + ALOGV("%s: ++filefd_mapped_files:%d;", __func__, + filefd_mapped_files); + + filefd_mapped_file[fd] = fd_type; + ALOGV("%s: filefd_mapped_file[fd:%d] = fd_type:%d;", __func__, + fd, fd_type); + } + } + } + + fd_token = strtok_r(NULL, ",", &fd_token_saved_ptr); + type_token = strtok_r(NULL, ",", &type_token_saved_ptr); + } + +done: + if (type_env_allocated) + free(type_env_allocated); + if (fd_env_allocated) + free(fd_env_allocated); + + errno = saved_errno; + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + + +/* + * This function will get run by the linker when the library is loaded. + */ +static void __attribute__ ((constructor)) linker_import_fd_env(void) +{ + int rv; + int verify_consistancy = 0; + + ALOGV(" "); + ALOGV("%s() {", __func__); + + rv = import_fd_env(verify_consistancy); /* File type table not verified. */ + + ALOGV("%s: }", __func__); +} + + +__hidden void filefd_opened(int fd, enum filefd_type fd_type) +{ + ALOGV("%s(fd:%d) {", __func__, fd); + + if (fd >= 0 && fd < __FD_SETSIZE) { + if (filefd_mapped_file[fd] == UNUSED_FD_TYPE) { + __atomic_inc(&filefd_mapped_files); + filefd_mapped_file[fd] = fd_type; + } + ASSERT(filefd_mapped_file[fd] == fd_type); + } + + ALOGV("%s: }", __func__); +} + +__hidden void filefd_closed(int fd) +{ + ALOGV("%s(fd:%d) {", __func__, fd); + + if (fd >= 0 && fd < __FD_SETSIZE) { + if (filefd_mapped_file[fd] != UNUSED_FD_TYPE) { + filefd_mapped_file[fd] = UNUSED_FD_TYPE; + filefd_FD_CLOEXEC_file[fd] = 0; + __atomic_dec(&filefd_mapped_files); + } + } + ALOGV("%s: }", __func__); +} + + +__hidden void filefd_CLOEXEC_enabled(int fd) +{ + ALOGV("%s:(fd:%d) {", __func__, fd); + + if (fd >= 0 && fd < __FD_SETSIZE) { + filefd_FD_CLOEXEC_file[fd] = 1; + } + + ALOGV("%s: }", __func__); +} + +__hidden void filefd_CLOEXEC_disabled(int fd) +{ + ALOGV("%s:(fd:%d) {", __func__, fd); + + if (fd >= 0 && fd < __FD_SETSIZE) { + filefd_FD_CLOEXEC_file[fd] = 0; + } + + ALOGV("%s: }", __func__); +} + + +__hidden void filefd_disable_mapping() +{ + ALOGV("%s:() {", __func__); + + filefd_enabled = 0; + + ALOGV("%s: }", __func__); +} + + +int close_portable(int fd) +{ + int rv; + + ALOGV(" "); + ALOGV("%s(fd:%d) {", __func__, fd); + + rv = close(fd); + filefd_closed(fd); + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + + +int read_portable(int fd, void *buf, size_t count) +{ + int rv; + enum filefd_type fd_type; + + ALOGV(" "); + ALOGV("%s(fd:%d, buf:0x%p, count:%d) {", __func__, + fd, buf, count); + + fd_type = filefd_mapped_file[fd]; + ALOGV("%s:fd_type:%d", __func__, + fd_type); + + switch (fd_type) { + /* Reads on these descriptors are portable; no need to be mapped. */ + case UNUSED_FD_TYPE: + case EVENT_FD_TYPE: + case INOTIFY_FD_TYPE: + case TIMER_FD_TYPE: + rv = read(fd, buf, count); + break; + + /* The read() of a signalfd() file descriptor needs to be mapped. */ + case SIGNAL_FD_TYPE: + if (filefd_enabled) { + rv = read_signalfd_mapper(fd, buf, count); + } else { + rv = read(fd, buf, count); + } + break; + + default: + ALOGE("Unknown fd_type:%d!", fd_type); + rv = read(fd, buf, count); + break; + } + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + + +/* + * Export PORTABLE environment variables before execve(). + * Tries a second time if it detects an extremely unlikely + * race condition. + */ +int execve_portable(const char *filename, char *const argv[], char *const envp[]) +{ + int rv; + int mapped_files = filefd_mapped_files; + int verify_consistancy = 1; + + ALOGV(" "); + ALOGV("%s(filename:%p, argv:%p, envp:%p) {", __func__, + filename, argv, envp); + + export_fd_env(); + + if (mapped_files != filefd_mapped_files) { + export_fd_env(); + } + import_fd_env(verify_consistancy); /* File type table consistancy verified. */ + + rv = execve(filename, argv, envp); + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + diff --git a/ndk/sources/android/libportable/arch-mips/inotify.c b/ndk/sources/android/libportable/arch-mips/inotify.c new file mode 100644 index 000000000..c417aa2e6 --- /dev/null +++ b/ndk/sources/android/libportable/arch-mips/inotify.c @@ -0,0 +1,84 @@ +/* + * Copyright 2012, 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 +#include + +#include +#include + +#include +#include + +#include + + +#define PORTABLE_TAG "inotify_portable" +#include + +extern int syscall(int, ...); + + +/* + * NOTE: LTP defaults to using O_CLOEXEC for IN_CLOEXEC, + * and 02000000 if O_CLOEXEC isn't defined. + */ + + +/* + * Portable to Native event flags mapper. + */ +static inline int in_flags_pton(int portable_flags) +{ + int native_flags = 0; + + ALOGV("%s(portable_flags:0x%x) {", __func__, portable_flags); + + if (portable_flags & IN_NONBLOCK_PORTABLE) { + native_flags |= IN_NONBLOCK; + } + + if (portable_flags & IN_CLOEXEC_PORTABLE) { + native_flags |= IN_CLOEXEC; + } + + ALOGV("%s: return(native_flags:%d); }", __func__, native_flags); + return native_flags; +} + + +int inotify_init1_portable(int portable_flags) { + int rv; + int native_flags; + + ALOGV(" "); + ALOGV("%s(portable_flags:%d) {", __func__, + portable_flags); + + native_flags = in_flags_pton(portable_flags); + + rv = syscall(__NR_inotify_init1, native_flags); + if (rv >= 0) { + if (native_flags & IN_CLOEXEC) { + filefd_CLOEXEC_enabled(rv); + } + filefd_opened(rv, INOTIFY_FD_TYPE); + } + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + diff --git a/ndk/sources/android/libportable/arch-mips/open.c b/ndk/sources/android/libportable/arch-mips/open.c index 4307e2cca..4804f8880 100644 --- a/ndk/sources/android/libportable/arch-mips/open.c +++ b/ndk/sources/android/libportable/arch-mips/open.c @@ -19,6 +19,7 @@ #include #include #include +#include #define PORTABLE_TAG "open_portable" #include @@ -28,6 +29,7 @@ #error Bad build environment #endif + static inline int open_flags_pton(int flags) { int mipsflags = flags & O_ACCMODE_PORTABLE; @@ -67,7 +69,9 @@ static inline int open_flags_pton(int flags) return mipsflags; } + extern int __open(const char*, int, int); + int open_portable(const char *pathname, int flags, ...) { mode_t mode = 0; @@ -95,12 +99,20 @@ int open_portable(const char *pathname, int flags, ...) /* Can't print pathname as a string, might be bogus */ ALOGV("%s: fd = %d = __open(pathname:%p, native_flags:0x%x, mode:0x%x);", __func__, fd, pathname, native_flags, mode); + } else { + if (flags & O_CLOEXEC) { + filefd_CLOEXEC_enabled(fd); + } else { + filefd_CLOEXEC_disabled(fd); + } } ALOGV("%s: return(fd:%d); }", __func__, fd); return fd; } + extern int __openat(int, const char*, int, int); + int openat_portable(int dirfd, const char *pathname, int flags, ...) { mode_t mode = 0; @@ -128,6 +140,12 @@ int openat_portable(int dirfd, const char *pathname, int flags, ...) if (fd == -1) { ALOGV("%s: fd = %d = __open(pathname:0x%p, native_flags:0x%x, mode:0x%d);", __func__, fd, pathname, native_flags, mode); + } else { + if (flags & O_CLOEXEC) { + filefd_CLOEXEC_enabled(fd); + } else { + filefd_CLOEXEC_disabled(fd); + } } ALOGV("%s: return(fd:%d); }", __func__, fd); return fd; diff --git a/ndk/sources/android/libportable/arch-mips/pipe.c b/ndk/sources/android/libportable/arch-mips/pipe.c new file mode 100644 index 000000000..07d01a99c --- /dev/null +++ b/ndk/sources/android/libportable/arch-mips/pipe.c @@ -0,0 +1,86 @@ +/* + * Copyright 2012, 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. + */ + +#define _GNU_SOURCE /* GLibc compatibility to declare pipe2(2) */ +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +#define PORTABLE_TAG "pipe_portable" +#include + +extern int syscall(int, ...); + + +/* NOTE: LTP defaults to using O_NONBLOCK even if O_NONBLOCK is defined */ + + +/* + * Portable to Native event flags mapper. + */ +static inline int tdf_flags_pton(int portable_flags) +{ + int native_flags = 0; + + ALOGV("%s(portable_flags:0x%x) {", __func__, portable_flags); + + if (portable_flags & O_NONBLOCK_PORTABLE) { + native_flags |= O_NONBLOCK; + } + + if (portable_flags & O_CLOEXEC_PORTABLE) { + native_flags |= O_CLOEXEC; + } + + ALOGV("%s: return(native_flags:%d); }", __func__, native_flags); + return native_flags; +} + + +int pipe2_portable(int pipefd[2], int portable_flags) { + int native_flags; + int rv; + + ALOGV(" "); + ALOGV("%s(pipefd[2]:%p, portable_flags:0x%x) {", __func__, + pipefd, portable_flags); + + native_flags = tdf_flags_pton(portable_flags); + + rv = pipe2(pipefd, native_flags); + if (rv >= 0) { + ALOGV("%s: pipe2() returned pipefd[0]:%d, pipefd[1]:%d", __func__, + pipefd[0], pipefd[1]); + + if (native_flags & O_CLOEXEC) { + filefd_CLOEXEC_enabled(pipefd[0]); + filefd_CLOEXEC_enabled(pipefd[1]); + } + } + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + diff --git a/ndk/sources/android/libportable/arch-mips/signal.c b/ndk/sources/android/libportable/arch-mips/signal.c index eae7aaefa..59d27ca71 100644 --- a/ndk/sources/android/libportable/arch-mips/signal.c +++ b/ndk/sources/android/libportable/arch-mips/signal.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #define PORTABLE_TAG "signal_portable" #include @@ -35,8 +37,21 @@ #endif typedef void (*sig3handler_t)(int, siginfo_t *, void *); + +static volatile int signal_handler_mapping_enabled = 1; + extern int syscall(int, ...); + +__hidden void signal_disable_mapping() +{ + ALOGV("%s(): signal_handler_mapping_enabled:%d = 0;", __func__, + signal_handler_mapping_enabled); + + signal_handler_mapping_enabled = 0; +} + + /* * The next five hidden functions are not exposed in the * libportable shared object. They are used here and other @@ -473,6 +488,10 @@ static void mips_sigaction_handler(int mips_signum, siginfo_t *sip, void *ucp) siginfo_ntop(sip, portable_sip); } + + ALOGV("%s: Calling portable_sighandler:%p(portable_signum:%d, portable_sip:%p, ucp:%p);", + __func__, portable_sighandler, portable_signum, portable_sip, ucp); + portable_sighandler(portable_signum, portable_sip, ucp); ALOGV("%s: return; }", __func__); @@ -510,10 +529,18 @@ static sighandler_t sighandler_pton(sighandler_portable_t portable_handler, int break; default: - if (sigaction) - mips_handler = (sighandler_t) mips_sighandler; - else - mips_handler = (sighandler_t) mips_sigaction_handler; + /* + * Signal Mapping can be disabled in the rare case of the clone + * flags not being compatble for VM and file descriptors. + */ + if (signal_handler_mapping_enabled) { + if (sigaction) + mips_handler = (sighandler_t) mips_sighandler; + else + mips_handler = (sighandler_t) mips_sigaction_handler; + } else { + mips_handler = portable_handler; /* Don't MAP */ + } break; } @@ -530,7 +557,7 @@ static sighandler_t sighandler_pton(sighandler_portable_t portable_handler, int * * The last 2 parameters to this static function, mips_signal_fn*, specify which of * these functions to call. We intercept the above to functions, as well as signal(), - * functions below. + * and call the associated *_portable() functions below. * * In addition, we intercept the signal_handler with our own handlers that map the * signal number from the MIPS convention to the PORTABLE/ARM convention. @@ -1057,22 +1084,125 @@ int sigaction_portable(int portable_signum, const struct sigaction_portable *act } +/* + * Currently signalfd() isn't supported by bionic with + * only the portable syscall.c code using this code by + * intercepting the syscall(__NR_signalfd4, ...) in bionic. + */ +__hidden int do_signalfd4_portable(int fd, const sigset_portable_t *portable_sigmask, + int portable_sigsetsize, int portable_flags) +{ + sigset_t native_sigmask; + int native_sigsetsize = sizeof(native_sigmask); + int native_flags = 0; + int rv; + + ALOGV("%s(fd:%d, portable_sigmask:%p, portable_sigsetsize:%d, portable_flags:0x%x) {", + __func__, fd, portable_sigmask, portable_sigsetsize, portable_flags); + + sigset_pton((sigset_portable_t *)portable_sigmask, &native_sigmask); + + if (portable_flags & SFD_NONBLOCK_PORTABLE) { + native_flags |= SFD_NONBLOCK; + } + if (portable_flags & SFD_CLOEXEC_PORTABLE) { + native_flags |= SFD_CLOEXEC; + } + rv = syscall(__NR_signalfd4, fd, &native_sigmask, native_sigsetsize, native_flags); + + if (rv >= 0) { + if (native_flags & SFD_CLOEXEC) { + filefd_CLOEXEC_enabled(rv); + } + + /* + * Reads on this file descriptor must be mapped to be portable. + * The mapping should survive a fork and most clones naturally. + * For the system call to be completely portable it has to propagate + * these mapped files after an execve(). Environment variables have + * been added to do that. See filefd.c for details. + */ + filefd_opened(rv, SIGNAL_FD_TYPE); + } + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + + #if 0 /* - * So far it appears that signalfd() isn't supported by bionic - * the kernel trap numbers are available. + * signalfd() isn't available in Bionic yet. When it is, it will be implemented like + * the glibc version where the sigsetsize is computed in the bionic code and passed + * down to the kernel with __NR_signalfd4. + * + * This function can't be called from bionic, so there isn't an entry in the experimental + * linker.cpp table for testing and this function. */ -int signalfd_portable(int fd, const sigset_t *portable_sigmask, int flags) +int signalfd_portable(int fd, const sigset_portable_t *portable_sigmask, int portable_flags) { - sigset_t mips_sigmask; + int portable_sigsetsize = sizeof(sigset_portable_t); + int rv; - sigset_pton(portable_sigmask, &mips_sigmask); + ALOGV("%s(fd:%d, portable_sigmask:%p, portable_flags:0x%x) {", __func__, + fd, portable_sigmask, portable_flags); - return signalfd(fd, &mips_sigmask, flags); + rv = do_signalfd4_portable(fd, portable_sigsetsize, portable_sigmask, portable_flags); + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; } #endif +/* + * Called by read_portable() to do signalfd read() mapping. + */ +__hidden int read_signalfd_mapper(int fd, void *buf, size_t count) +{ + int rv; + + ALOGV("%s(fd:%d, buf:0x%p, count:%d) {", __func__, + fd, buf, count); + + rv = read(fd, buf, count); + if (rv > 0) { + int siginfos = rv/sizeof(struct signalfd_siginfo); + struct signalfd_siginfo *si = (struct signalfd_siginfo *) buf; + int i; + + /* Read signalfd_siginfo structure(s) if read is large enough */ + for (i = 0; i < siginfos; i++, si++) { + int ssi_signo; + + ssi_signo = si->ssi_signo; + si->ssi_signo = signum_ntop(si->ssi_signo); + ALOGV("%s: si->ssi_signo:%d = signum_ntop(si->ssi_signo:%d); i:%d", __func__, + si->ssi_signo, ssi_signo, i); + + si->ssi_errno = errno_ntop(si->ssi_errno); + + /* + * The ssi_codes appear to be generic; defined in + * the kernel in include/asm-generic/siginfo.h + */ + if (si->ssi_status > 0 && si->ssi_status <= NSIG) { + si->ssi_status = signum_ntop(si->ssi_status); + } + + /* + * The rest of the struct members, like + * ssi_trapno, ssi_int, ssi_ptr + * are not likely worth dealing with. + */ + } + } + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + + int sigsuspend_portable(const sigset_portable_t *portable_sigmask) { int rv; diff --git a/ndk/sources/android/libportable/arch-mips/syscall.c b/ndk/sources/android/libportable/arch-mips/syscall.c index 83f0cbdff..aa145b9b7 100644 --- a/ndk/sources/android/libportable/arch-mips/syscall.c +++ b/ndk/sources/android/libportable/arch-mips/syscall.c @@ -21,6 +21,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -35,6 +39,12 @@ * Minimal syscall support for LTP testing. * These are the system calls that LTP references explicitly. * Not all of them are exported via bionic header so use #ifdef. + * + * TODO: + * Add existing portable system calls currently redirected from + * experimental Bionic linker code so that calls to them via + * syscall() are also processed. For example, LTP only calls open() + * directly and never does a syscall(__NR_open, ...). */ @@ -100,11 +110,47 @@ int syscall_portable(int portable_number, ...) #endif #ifdef __NR_eventfd_portable - case __NR_eventfd_portable: native_number = __NR_eventfd; break; + /* + * Prior to 2.6.27 we only had this system call, + * which didn't have a flags argument. The kernel + * just provides a zero for flags when this system + * call number is used. + */ + case __NR_eventfd_portable: { + unsigned int initval; /* 64-bit counter initial value */ + int flags = 0; + + va_start(ap, portable_number); + + initval = va_arg(ap, int); + + va_end(ap); + + ret = eventfd_portable(initval, flags); /* Android uses __NR_eventfd2 in eventfd() */ + goto done; + } #endif #ifdef __NR_eventfd2_portable - case __NR_eventfd2_portable: native_number = __NR_eventfd2; break; + /* + * Starting with Linux 2.6.27 a flags argument was added. + * Both Bionic and glibc implement the eventfd() now with + * the additional flags argument. + */ + case __NR_eventfd2_portable: { + unsigned int initval; /* 64-bit counter initial value */ + int flags; + + va_start(ap, portable_number); + + initval = va_arg(ap, int); + flags = va_arg(ap, int); + + va_end(ap); + + ret = eventfd_portable(initval, flags); /* Android uses __NR_eventfd2 in eventfd() */ + goto done; + } #endif #ifdef __NR_exit_group_portable @@ -176,7 +222,16 @@ int syscall_portable(int portable_number, ...) #endif #ifdef __NR_inotify_init1_portable - case __NR_inotify_init1_portable: native_number = __NR_inotify_init1; break; + case __NR_inotify_init1_portable: { + int portable_flags; + + va_start(ap, portable_number); + portable_flags = va_arg(ap, int); + va_end(ap); + + ret = inotify_init1_portable(portable_flags); + goto done; + } #endif #ifdef __NR_keyctl_portable @@ -204,7 +259,18 @@ int syscall_portable(int portable_number, ...) #endif #ifdef __NR_pipe2_portable - case __NR_pipe2_portable: native_number = __NR_pipe2; break; + case __NR_pipe2_portable: { + int *pipefd_ptr; + int portable_flags; + + va_start(ap, portable_number); + pipefd_ptr = va_arg(ap, int *); + portable_flags = va_arg(ap, int); + va_end(ap); + + ret = pipe2_portable(pipefd_ptr, portable_flags); + goto done; + } #endif #ifdef __NR_readahead_portable @@ -312,7 +378,25 @@ int syscall_portable(int portable_number, ...) #endif #ifdef __NR_signalfd4_portable - case __NR_signalfd4_portable: native_number = __NR_signalfd4; break; + case __NR_signalfd4_portable: { + int fd; + sigset_portable_t *portable_sigmask; + int sigsetsize; + int flags; + + va_start(ap, portable_number); + + fd = va_arg(ap, int); + portable_sigmask = va_arg(ap, sigset_portable_t *); + sigsetsize = va_arg(ap, int); + flags = va_arg(ap, int); + + va_end(ap); + + ret = do_signalfd4_portable(fd, (const sigset_portable_t *) portable_sigmask, sigsetsize, + flags); + goto done; + } #endif #ifdef __NR_socketcall_portable @@ -423,7 +507,18 @@ int syscall_portable(int portable_number, ...) #endif #ifdef __NR_timerfd_create_portable - case __NR_timerfd_create_portable: native_number = __NR_timerfd_create; break; + case __NR_timerfd_create_portable: { + int clockid; + int flags; + + va_start(ap, portable_number); + clockid = va_arg(ap, int); /* clockid is portable */ + flags = va_arg(ap, int); /* flags need to be mapped */ + va_end(ap); + + ret = timerfd_create_portable(clockid, flags); + goto done; + } #endif #ifdef __NR_timerfd_gettime_portable diff --git a/ndk/sources/android/libportable/arch-mips/timerfd.c b/ndk/sources/android/libportable/arch-mips/timerfd.c new file mode 100644 index 000000000..3196d185b --- /dev/null +++ b/ndk/sources/android/libportable/arch-mips/timerfd.c @@ -0,0 +1,81 @@ +/* + * Copyright 2012, 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 +#include + +#include +#include + +#include +#include + +#include + + +#define PORTABLE_TAG "timerfd_portable" +#include + +extern int syscall(int, ...); + + +/* NOTE: LTP defaults to using O_NONBLOCK even if TFD_NONBLOCK is defined */ + + +/* + * Portable to Native event flags mapper. + */ +static inline int tdf_flags_pton(int portable_flags) +{ + int native_flags = 0; + + ALOGV("%s(portable_flags:0x%x) {", __func__, portable_flags); + + if (portable_flags & TFD_NONBLOCK_PORTABLE) { + native_flags |= TFD_NONBLOCK; + } + + if (portable_flags & TFD_CLOEXEC_PORTABLE) { + native_flags |= TFD_CLOEXEC; + } + + ALOGV("%s: return(native_flags:%d); }", __func__, native_flags); + return native_flags; +} + + +int timerfd_create_portable(int clockid, int portable_flags) { + int rv; + int native_flags; + + ALOGV(" "); + ALOGV("%s(clockid:%d, portable_flags:%d) {", __func__, + clockid, portable_flags); + + native_flags = tdf_flags_pton(portable_flags); + + rv = syscall(__NR_timerfd_create, clockid, native_flags); + if (rv >= 0) { + if (native_flags & TFD_CLOEXEC) { + filefd_CLOEXEC_enabled(rv); + } + filefd_opened(rv, TIMER_FD_TYPE); + } + + ALOGV("%s: return(rv:%d); }", __func__, rv); + return rv; +} + diff --git a/ndk/sources/android/libportable/common/include/eventfd_portable.h b/ndk/sources/android/libportable/common/include/eventfd_portable.h new file mode 100644 index 000000000..7572fc56a --- /dev/null +++ b/ndk/sources/android/libportable/common/include/eventfd_portable.h @@ -0,0 +1,63 @@ +/* + * Derived from bionic/libc/include/sys/eventfd.h + * + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef _SYS_EVENTFD_PORTABLE_H +#define _SYS_EVENTFD_PORTABLE_H + +#include +#include +#include + +__BEGIN_DECLS + +/* + * EFD_SEMAPHORE is defined in recent linux kernels; + * but isn't mentioned elsewhere. See linux 3.4 + * include/linux/eventfd.h for example. + */ +#define EFD_SEMAPHORE (1 << 0) + +#define EFD_SEMAPHORE_PORTABLE EFD_SEMAPHORE +#define EFD_CLOEXEC_PORTABLE O_CLOEXEC_PORTABLE +#define EFD_NONBLOCK_PORTABLE O_NONBLOCK_PORTABLE + +/* type of event counter */ +typedef uint64_t eventfd_portable_t; + +extern int eventfd_portable(unsigned int initval, int flags); + +#if 0 +/* Compatibility with GLibc; libportable versions don't appear to be necessary */ +extern int eventfd_read(int fd, eventfd_t *counter); +extern int eventfd_write(int fd, const eventfd_t counter); +#endif + +__END_DECLS + +#endif /* _SYS_EVENTFD_H */ diff --git a/ndk/sources/android/libportable/common/include/fcntl_portable.h b/ndk/sources/android/libportable/common/include/fcntl_portable.h index 19f49c2ba..6e99c8b30 100644 --- a/ndk/sources/android/libportable/common/include/fcntl_portable.h +++ b/ndk/sources/android/libportable/common/include/fcntl_portable.h @@ -72,6 +72,15 @@ #define O_NDELAY_PORTABLE O_NONBLOCK_PORTABLE #endif +/* From Bionic libc/kernel/common/asm-generic/fcntl.h */ +#ifndef O_CLOEXEC_PORTABLE +#define O_CLOEXEC_PORTABLE 02000000 +#endif + +#ifndef __ARCH_FLOCK64_PAD +#define __ARCH_FLOCK64_PAD +#endif + /* * For use with F_GETLK and F_SETLK */ diff --git a/ndk/sources/android/libportable/common/include/filefd_portable.h b/ndk/sources/android/libportable/common/include/filefd_portable.h new file mode 100644 index 000000000..10c7b566f --- /dev/null +++ b/ndk/sources/android/libportable/common/include/filefd_portable.h @@ -0,0 +1,44 @@ +/* + * Copyright 2012, 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. + */ + +#ifndef _FILEFD_PORTABLE_H_ +#define _FILEFD_PORTABLE_H_ + +/* + * Maintaining a list of special file descriptors in lib-portable + * which are maintained across a execve() via environment variables. + * See portable/arch-mips/filefd.c for details. + */ +enum filefd_type { + UNUSED_FD_TYPE = 0, + EVENT_FD_TYPE, + INOTIFY_FD_TYPE, + SIGNAL_FD_TYPE, + TIMER_FD_TYPE, + MAX_FD_TYPE +}; + +extern __hidden void filefd_opened(int fd, enum filefd_type fd_type); +extern __hidden void filefd_closed(int fd); +extern __hidden void filefd_CLOEXEC_enabled(int fd); +extern __hidden void filefd_CLOEXEC_disabled(int fd); +extern __hidden void filefd_disable_mapping(void); + +extern int close_portable(int fd); +extern int read_portable(int fd, void *buf, size_t count); +extern int pipe2_portable(int pipefd[2], int portable_flags); + +#endif /* _FILEFD_PORTABLE_H_ */ diff --git a/ndk/sources/android/libportable/common/include/inotify_portable.h b/ndk/sources/android/libportable/common/include/inotify_portable.h new file mode 100644 index 000000000..2f080479f --- /dev/null +++ b/ndk/sources/android/libportable/common/include/inotify_portable.h @@ -0,0 +1,51 @@ +/* + * Derived from bionic/libc/include/sys/eventfd.h + * + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS_INOTIFY_PORTABLE_H +#define _SYS_INOTIFY_PORTABLE_H + +#include +#include +#include +#include + +__BEGIN_DECLS + +#define IN_CLOEXEC O_CLOEXEC +#define IN_NONBLOCK O_NONBLOCK + +#define IN_CLOEXEC_PORTABLE O_CLOEXEC_PORTABLE +#define IN_NONBLOCK_PORTABLE O_NONBLOCK_PORTABLE + +extern int inotify_init1_portable(int flags); + +__END_DECLS + +#endif /* _SYS_INOTIFY_H */ diff --git a/ndk/sources/android/libportable/common/include/signal_portable.h b/ndk/sources/android/libportable/common/include/signal_portable.h index 815a00762..abb99873d 100644 --- a/ndk/sources/android/libportable/common/include/signal_portable.h +++ b/ndk/sources/android/libportable/common/include/signal_portable.h @@ -142,7 +142,14 @@ extern int tkill_portable(int tid, int portable_signum); extern int sigaltstack_portable(const portable_stack_t *ss, portable_stack_t *oss); extern int timer_create_portable(clockid_t, struct sigevent *, timer_t *); +#if 0 +extern int signalfd_portable(int fd, const sigset_portable_t *portable_sigmask, int flags); +#endif +extern __hidden int do_signalfd4_portable(int fd, const sigset_portable_t *portable_sigmask, + int portable_sigsetsize, int flags); + +extern __hidden int read_signalfd_mapper(int fd, void *buf, size_t count); extern __hidden char *map_portable_signum_to_name(int portable_signum); extern __hidden char *map_mips_signum_to_name(int mips_signum); extern __hidden int signum_pton(int portable_signum); @@ -153,6 +160,7 @@ typedef int (*rt_sigmask_fn)(int, const sigset_t *, sigset_t *, size_t); typedef int (*sigaction_fn)(int, const struct sigaction *, struct sigaction *); typedef int (*rt_sigaction_fn)(int, const struct sigaction *, struct sigaction *, size_t); + extern __hidden int do_sigmask(int portable_how, const sigset_portable_t *portable_sigset, sigset_portable_t *portable_oldset, sigmask_fn fn, rt_sigmask_fn rt_fn); @@ -181,6 +189,10 @@ extern __hidden int rt_sigqueueinfo_portable(pid_t pid, int sig, siginfo_portabl extern __hidden int rt_tgsigqueueinfo_portable(pid_t tgid, pid_t pid, int sig, siginfo_portable_t *uinfo); + +/* Called by clone when memory and signal handlers aren't compatable. */ +extern __hidden void signal_disable_mapping(void); + __END_DECLS #endif /* _SIGNAL_PORTABLE_H_ */ diff --git a/ndk/sources/android/libportable/common/include/signalfd_portable.h b/ndk/sources/android/libportable/common/include/signalfd_portable.h new file mode 100644 index 000000000..54ff47061 --- /dev/null +++ b/ndk/sources/android/libportable/common/include/signalfd_portable.h @@ -0,0 +1,60 @@ +/* + * Derived from Goldfish include/linux/signalfd.h + * + * Copyright (C) 2007 Davide Libenzi + * + */ + +#ifndef _LINUX_SIGNALFD_PORTABLE_H +#define _LINUX_SIGNALFD_PORTABLE_H + +#include +#include + +/* Flags for signalfd4. */ +#define SFD_CLOEXEC O_CLOEXEC +#define SFD_NONBLOCK O_NONBLOCK + +/* For O_CLOEXEC_PORTABLE and O_NONBLOCK_PORTABLE */ +#include "fcntl_portable.h" + +#define SFD_CLOEXEC_PORTABLE O_CLOEXEC_PORTABLE +#define SFD_NONBLOCK_PORTABLE O_NONBLOCK_PORTABLE + +/* + * This structure is the same for Native and Portable. + * However for MIPS ssi_signo and ssi_errno differ in their + * values and need to be mapped. + */ +struct signalfd_siginfo { + __u32 ssi_signo; + __s32 ssi_errno; + __s32 ssi_code; + __u32 ssi_pid; + __u32 ssi_uid; + __s32 ssi_fd; + __u32 ssi_tid; + __u32 ssi_band; + __u32 ssi_overrun; + __u32 ssi_trapno; + __s32 ssi_status; + __s32 ssi_int; + __u64 ssi_ptr; + __u64 ssi_utime; + __u64 ssi_stime; + __u64 ssi_addr; + + /* + * Pad structure to 128 bytes. Remember to update the + * pad size when you add new members. We use a fixed + * size structure to avoid compatibility problems with + * future versions, and we leave extra space for additional + * members. We use fixed size members because this structure + * comes out of a read(2) and we really don't want to have + * a compat (sp?) on read(2). + */ + __u8 __pad[48]; +}; + +#endif /* _LINUX_SIGNALFD_PORTABLE_H */ + diff --git a/ndk/sources/android/libportable/common/include/timerfd_portable.h b/ndk/sources/android/libportable/common/include/timerfd_portable.h new file mode 100644 index 000000000..f83c0edee --- /dev/null +++ b/ndk/sources/android/libportable/common/include/timerfd_portable.h @@ -0,0 +1,51 @@ +/* + * Derived from bionic/libc/include/sys/eventfd.h + * + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS_TIMERFD_PORTABLE_H +#define _SYS_TIMERFD_PORTABLE_H + +#include +#include +#include +#include + +__BEGIN_DECLS + +#define TFD_CLOEXEC O_CLOEXEC +#define TFD_NONBLOCK O_NONBLOCK + +#define TFD_CLOEXEC_PORTABLE O_CLOEXEC_PORTABLE +#define TFD_NONBLOCK_PORTABLE O_NONBLOCK_PORTABLE + +extern int timerfd_create_portable(int clockid, int flags); + +__END_DECLS + +#endif /* _SYS_TIMERFD_H */