diff --git a/ndk/sources/android/libportable/Android.mk b/ndk/sources/android/libportable/Android.mk index c118c1af6..a7937da7d 100644 --- a/ndk/sources/android/libportable/Android.mk +++ b/ndk/sources/android/libportable/Android.mk @@ -30,8 +30,9 @@ LOCAL_CFLAGS := -I $(LOCAL_PATH)/common/include ifeq ($(TARGET_ARCH),mips) libportable_arch_src_files += \ - arch-mips/errno.c \ + arch-mips/clone.c \ arch-mips/epoll.c \ + arch-mips/errno.c \ arch-mips/fcntl.c \ arch-mips/ioctl.c \ arch-mips/mmap.c \ diff --git a/ndk/sources/android/libportable/arch-mips/clone.c b/ndk/sources/android/libportable/arch-mips/clone.c new file mode 100644 index 000000000..57803a291 --- /dev/null +++ b/ndk/sources/android/libportable/arch-mips/clone.c @@ -0,0 +1,96 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORTABLE_TAG "clone_portable" +#include + + +/* + * This function maps the clone function call defined in: + * $TOP/bionic/libc/bionic/bionic_clone.c + * + * which calls the __bionic_clone() system call which is defined in: + * $TOP/bionic/libc/unistd/arch-mips/bionic/clone.S + * + * We have to map the low byte of the 'flags' parameter which + * contains the number of the termination signal sent to the + * parent when the child dies. + * + * Note that if this signal is specified as anything other than + * SIGCHLD, then the parent process must specify the __WALL or + * __WCLONE options when waiting for the child with wait(2). + * + * If no signal is specified, then the parent process is not + * signaled when the child terminates. + */ +int clone_portable(int (*fn)(void *), void *child_stack, int port_flags, void *arg, ...) +{ + va_list args; + int ret; + int mips_flags; + void *new_tls = NULL; + int *child_tidptr = NULL; + int *parent_tidptr = NULL; + int mips_term_signum; + char *mips_term_signame; + int portable_term_signum; + char *portable_term_signame; + + ALOGV(" "); + ALOGV("%s(fn:%p, child_stack:%p, port_flags:0x%x, arg:%p, ...) {", __func__, + fn, child_stack, port_flags, arg); + + /* Extract optional parameters - they are cumulative */ + va_start(args, arg); + if (port_flags & (CLONE_PARENT_SETTID|CLONE_SETTLS|CLONE_CHILD_SETTID)) { + parent_tidptr = va_arg(args, int*); + } + if (port_flags & (CLONE_SETTLS|CLONE_CHILD_SETTID)) { + new_tls = va_arg(args, void*); + } + if (port_flags & CLONE_CHILD_SETTID) { + child_tidptr = va_arg(args, int*); + } + va_end(args); + + /* + * Map the LSB of the flags as explained above. + */ + portable_term_signum = port_flags & 0xFF; + if (portable_term_signum == 0) { + mips_flags = port_flags; + } else { + portable_term_signame = map_portable_signum_to_name(portable_term_signum); + mips_term_signum = map_portable_signum_to_mips(portable_term_signum); + mips_term_signame = map_mips_signum_to_name(mips_term_signum); + mips_flags = (port_flags & ~0xFF) | (mips_term_signum & 0xFF); + } + + ret = clone(fn, child_stack, mips_flags, arg, parent_tidptr, + new_tls, child_tidptr); + + ALOGV("%s: return(ret:%d); }", __func__, ret); + return(ret); +}