[MIPS] Added support for file descriptor related system calls.

Specifically these functions are now supported:
    signalfd4(), eventfd(), timerfd_create(),
    pipe(), and inotify_init1()

Modified syscall_portable() to call signalfd4_portable(),
eventfd_portable(), eventfd2_portable(), and timerfd_create().
These system calls enable the read system calls to access
kernel data structures.

The signalfd4() enables read to return a signalfd_siginfo structure
which have the signal number and errno mapped until an execve().
This is similar to the maintaining a table of signal handlers to
map the signal numbers done earlier. This mapping is extended to
the process after an execve() by passing the final set of mapped
file descriptors via a pair of environment variables.

Disabling signal and file descriptor read mapping in parent
if the child would break the mapping algorithms.

This code passes at least all of the non-POSIX LTP tests,
including an updated LTP signalfd4 test that posts SIGNALS
and uses this read() mechanism to get signal info.

inotify_init1 is similar to signalfd(), timerfd() and other
filefd functions which map read() calls. Unlike signalfd(), and
similar to timerfd(), the reads don't appear to need to be mapped.

The members of the inotify_event structure appear to be generic.
The mask bits like IN_MOVE_FROM and IN_MOVE_TO are defined in
generic files. The LTP test in testcases/kernel/syscalls/inotify
test for the inotify_event structure being inotify_event structure
being read and does seem to check it contents being correct.

Change-Id: I3f2dcd4e33437ac953cd9f67f56dccc6ec6e5e6f
Signed-off-by: Pete Delaney <piet.delaney@imgtec.com>
Signed-off-by: Chris Dearman <chris.dearman@imgtec.com>
Signed-off-by: Paul Lind <paul.lind@imgtec.com>
diff --git a/ndk/sources/android/libportable/Android.mk b/ndk/sources/android/libportable/Android.mk
index 1350012..1e0c79a 100644
--- a/ndk/sources/android/libportable/Android.mk
+++ b/ndk/sources/android/libportable/Android.mk
@@ -36,11 +36,15 @@
 			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 @@
 			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 30cfe4b..2fc6421 100644
--- a/ndk/sources/android/libportable/arch-mips/clone.c
+++ b/ndk/sources/android/libportable/arch-mips/clone.c
@@ -23,6 +23,7 @@
 #include <portability.h>
 #include <stdio.h>
 #include <errno.h>
+#include <filefd_portable.h>
 
 #define PORTABLE_TAG "clone_portable"
 #include <log_portable.h>
@@ -58,11 +59,32 @@
     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 @@
         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 0000000..c16d9bc
--- /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 <unistd.h>
+#include <fcntl.h>
+
+#include <asm/unistd-portable.h>
+#include <asm/unistd.h>
+
+#include <fcntl_portable.h>
+#include <sys/eventfd.h>
+#include <eventfd_portable.h>
+#include <filefd_portable.h>
+
+#define PORTABLE_TAG "eventfd_portable"
+#include <log_portable.h>
+
+
+/* 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 07ba575..bb0b3b7 100644
--- a/ndk/sources/android/libportable/arch-mips/fcntl.c
+++ b/ndk/sources/android/libportable/arch-mips/fcntl.c
@@ -20,7 +20,9 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
+#include <portability.h>
 #include <fcntl_portable.h>
+#include <filefd_portable.h>
 
 #include <portability.h>
 
@@ -331,6 +333,22 @@
     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 0000000..4911ee1
--- /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 <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <portability.h>
+#include <stdio.h>
+#include <errno.h>
+#include <errno_portable.h>
+#include <filefd_portable.h>
+#include <signal_portable.h>
+#include <sys/atomics.h>
+
+#define PORTABLE_TAG "filefd_portable"
+#include <log_portable.h>
+
+/*
+ * 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 0000000..c417aa2
--- /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 <unistd.h>
+#include <fcntl.h>
+
+#include <asm/unistd.h>
+#include <asm/unistd-portable.h>
+
+#include <fcntl_portable.h>
+#include <inotify_portable.h>
+
+#include <filefd_portable.h>
+
+
+#define PORTABLE_TAG "inotify_portable"
+#include <log_portable.h>
+
+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 4307e2c..4804f88 100644
--- a/ndk/sources/android/libportable/arch-mips/open.c
+++ b/ndk/sources/android/libportable/arch-mips/open.c
@@ -19,6 +19,7 @@
 #include <stdarg.h>
 #include <portability.h>
 #include <fcntl_portable.h>
+#include <filefd_portable.h>
 
 #define PORTABLE_TAG "open_portable"
 #include <log_portable.h>
@@ -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 @@
     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 @@
         /* 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 @@
     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 0000000..07d01a9
--- /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 <unistd.h>
+#include <fcntl.h>
+
+#include <portability.h>
+#include <asm/unistd.h>
+#include <asm/unistd-portable.h>
+
+#include <fcntl_portable.h>
+#include <asm/unistd-portable.h>
+#include <asm/unistd.h>
+#include <filefd_portable.h>
+
+
+#define PORTABLE_TAG "pipe_portable"
+#include <log_portable.h>
+
+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 eae7aae..59d27ca 100644
--- a/ndk/sources/android/libportable/arch-mips/signal.c
+++ b/ndk/sources/android/libportable/arch-mips/signal.c
@@ -25,6 +25,8 @@
 #include <errno_portable.h>
 #include <asm/unistd-portable.h>
 #include <asm/unistd.h>
+#include <signalfd_portable.h>
+#include <filefd_portable.h>
 
 #define PORTABLE_TAG "signal_portable"
 #include <log_portable.h>
@@ -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 @@
         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 @@
         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 @@
  *
  * 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 @@
 }
 
 
+/*
+ * 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 83f0cbd..aa145b9 100644
--- a/ndk/sources/android/libportable/arch-mips/syscall.c
+++ b/ndk/sources/android/libportable/arch-mips/syscall.c
@@ -21,6 +21,10 @@
 #include <time.h>
 #include <errno.h>
 #include <errno_portable.h>
+#include <eventfd_portable.h>
+#include <filefd_portable.h>
+#include <inotify_portable.h>
+#include <timerfd_portable.h>
 #include <asm/unistd-portable.h>
 #include <asm/unistd.h>
 
@@ -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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 0000000..3196d18
--- /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 <unistd.h>
+#include <fcntl.h>
+
+#include <asm/unistd.h>
+#include <asm/unistd-portable.h>
+
+#include <fcntl_portable.h>
+#include <timerfd_portable.h>
+
+#include <filefd_portable.h>
+
+
+#define PORTABLE_TAG "timerfd_portable"
+#include <log_portable.h>
+
+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 0000000..7572fc5
--- /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 <sys/cdefs.h>
+#include <portability.h>
+#include <fcntl_portable.h>
+
+__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 19f49c2..6e99c8b 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 0000000..10c7b56
--- /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 0000000..2f08047
--- /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 <sys/cdefs.h>
+#include <portability.h>
+#include <fcntl.h>
+#include <fcntl_portable.h>
+
+__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 815a007..abb9987 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 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 (*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_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 0000000..54ff470
--- /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 <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_SIGNALFD_PORTABLE_H
+#define _LINUX_SIGNALFD_PORTABLE_H
+
+#include <linux/types.h>
+#include <fcntl.h>
+
+/* 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 0000000..f83c0ed
--- /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 <sys/cdefs.h>
+#include <portability.h>
+#include <fcntl.h>
+#include <fcntl_portable.h>
+
+__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 */