summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-30 22:53:10 +0000
committerbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-30 22:53:10 +0000
commitbf8e245a2e97d870a884018df529ca50e5153f14 (patch)
tree2f5a186020ba09677b3c0f2cd4a3bbc89805a12b /native_client_sdk
parenta45012f4ca934774ccbdf935701d24c2fd882205 (diff)
downloadchromium_src-bf8e245a2e97d870a884018df529ca50e5153f14.zip
chromium_src-bf8e245a2e97d870a884018df529ca50e5153f14.tar.gz
chromium_src-bf8e245a2e97d870a884018df529ca50e5153f14.tar.bz2
[NaCl SDK] Add dup2 to nacl-mounts.
This CL also fixes a bug where closing a file twice (i.e. closing two file descriptors that point to the same kernel handle) would fail. The correct behavior is that close should only remove the connection between the file descriptor and the handle -- once the handle is no longer referenced, it should be closed. Other changes to make this work properly: * Modified KernelProxy::close() to release the node, not close it. * Removed Mount::Close. * Made Mount::AcquireNode/ReleaseNode non-virtual. They should not be overridden. * As a result, determining the number of nodes attached to a mount cannot be easily implemented by a Mount subclass; instead, Mount tracks this value itself. Some changes to improve testing: * Added ki_uninit to initialize the kernel intercept. This is run after every test that runs ki_init. * kernel_wrap_init only wraps once -- otherwise, after a second call to kernel_wrap_init will replace REAL(...) with the wrapped function. Other fixes: * nacl_mounts_test Makefile had an incorrect library include order; ppapi must be before gtest so the main function in the gtest library is not used. * nacl_mounts_test Makefile had a typo in the target name: "nacl_mount_test". * RefObject was not calling Destroy when an object's ref count reached zero. BUG=none R=noelallen@chromium.org NOTRY=true Review URL: https://chromiumcodereview.appspot.com/12089019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@179722 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc24
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_object.cc20
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_object.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc55
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_glibc.cc54
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc46
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_win.cc24
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount.cc27
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount.h20
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc7
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_dev.h3
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.cc13
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_http.cc7
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_http.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc11
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_mem.h8
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_node.cc11
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_node.h11
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/Makefile6
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/kernel_object_test.cc105
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_test.cc96
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/kernel_wrap_test.cc107
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/mount_html5fs_test.cc8
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc52
-rw-r--r--native_client_sdk/src/libraries/utils/ref_object.h5
31 files changed, 464 insertions, 268 deletions
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc
index 3163fa6..049b21a 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc
@@ -2,6 +2,7 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+#include <errno.h>
#include "nacl_mounts/kernel_intercept.h"
#include "nacl_mounts/kernel_proxy.h"
#include "nacl_mounts/kernel_wrap.h"
@@ -35,11 +36,26 @@ int ki_is_initialized() {
return s_kp != NULL;
}
+void ki_uninit() {
+ s_kp = NULL;
+}
+
int ki_chdir(const char* path) {
return s_kp->chdir(path);
}
char* ki_getcwd(char* buf, size_t size) {
+ // gtest uses getcwd in a static initializer. If we haven't initialized the
+ // kernel-intercept yet, just return ".".
+ if (!ki_is_initialized()) {
+ if (size < 2) {
+ errno = ERANGE;
+ return NULL;
+ }
+ buf[0] = '.';
+ buf[1] = 0;
+ return buf;
+ }
return s_kp->getcwd(buf, size);
}
@@ -51,6 +67,10 @@ int ki_dup(int oldfd) {
return s_kp->dup(oldfd);
}
+int ki_dup2(int oldfd, int newfd) {
+ return s_kp->dup2(oldfd, newfd);
+}
+
int ki_chmod(const char *path, mode_t mode) {
return s_kp->chmod(path, mode);
}
@@ -101,10 +121,14 @@ int ki_fsync(int fd) {
}
int ki_isatty(int fd) {
+ if (!ki_is_initialized())
+ return 0;
return s_kp->isatty(fd);
}
int ki_close(int fd) {
+ if (!ki_is_initialized())
+ return 0;
return s_kp->close(fd);
}
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h
index c7a3701..4fc45ec 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h
@@ -23,11 +23,13 @@ void ki_init_ppapi(void* kernel_proxy,
PP_Instance instance,
PPB_GetInterface get_browser_interface);
int ki_is_initialized();
+void ki_uninit();
int ki_chdir(const char* path);
char* ki_getcwd(char* buf, size_t size);
char* ki_getwd(char* buf);
int ki_dup(int oldfd);
+int ki_dup2(int oldfd, int newfd);
int ki_chmod(const char* path, mode_t mode);
int ki_stat(const char* path, struct stat* buf);
int ki_mkdir(const char* path, mode_t mode);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_object.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_object.cc
index b35cc5b..7ff99b7 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_object.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_object.cc
@@ -4,6 +4,7 @@
*/
#include "nacl_mounts/kernel_object.h"
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
@@ -103,8 +104,8 @@ int KernelObject::AllocateFD(KernelHandle* handle) {
AutoLock lock(&lock_);
int id;
- // Acquire then handle and it's mount since we are about
- // to track them with this FD.
+ // Acquire the handle and its mount since we are about to track it with
+ // this FD.
handle->Acquire();
handle->mount_->Acquire();
@@ -121,6 +122,21 @@ int KernelObject::AllocateFD(KernelHandle* handle) {
return id;
}
+void KernelObject::AssignFD(int fd, KernelHandle* handle) {
+ AutoLock lock(&lock_);
+
+ // Acquire the handle and its mount since we are about to track it with
+ // this FD.
+ handle->Acquire();
+ handle->mount_->Acquire();
+
+ if (fd >= handle_map_.size())
+ handle_map_.resize(fd + 1);
+
+ assert(handle_map_[fd] == NULL);
+ handle_map_[fd] = handle;
+}
+
void KernelObject::FreeFD(int fd) {
AutoLock lock(&lock_);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_object.h b/native_client_sdk/src/libraries/nacl_mounts/kernel_object.h
index ea3ae9f..7248ad9 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_object.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_object.h
@@ -38,6 +38,7 @@ class KernelObject {
// Allocate a new fd and assign the handle to it, while
// ref counting the handle and associated mount.
int AllocateFD(KernelHandle* handle);
+ void AssignFD(int fd, KernelHandle* handle);
void FreeFD(int fd);
protected:
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc
index bf82b7c..f6e10c4 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc
@@ -4,6 +4,7 @@
*/
#include "nacl_mounts/kernel_proxy.h"
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
@@ -83,10 +84,21 @@ int KernelProxy::close(int fd) {
KernelHandle* handle = AcquireHandle(fd);
if (NULL == handle) return -1;
- handle->mount_->Close(handle->node_);
+ Mount* mount = handle->mount_;
+ // Acquire the mount to ensure FreeFD doesn't prematurely destroy it.
+ mount->Acquire();
+
+ // FreeFD will release the handle/mount held by this fd.
FreeFD(fd);
+
+ // If this handle is the last reference to its node, releasing it will close
+ // the node.
ReleaseHandle(handle);
+
+ // Finally, release the mount.
+ mount->Release();
+
return 0;
}
@@ -100,6 +112,24 @@ int KernelProxy::dup(int oldfd) {
return newfd;
}
+int KernelProxy::dup2(int oldfd, int newfd) {
+ KernelHandle* old_handle = AcquireHandle(oldfd);
+ if (NULL == old_handle) return -1;
+
+ if (oldfd == newfd) {
+ ReleaseHandle(old_handle);
+ return 0;
+ }
+
+ // Ignore the result, we don't care if newfd is valid or not.
+ close(newfd);
+
+ AssignFD(newfd, old_handle);
+ ReleaseHandle(old_handle);
+
+ return newfd;
+}
+
char* KernelProxy::getcwd(char* buf, size_t size) {
AutoLock lock(&lock_);
@@ -165,30 +195,21 @@ int KernelProxy::rmdir(const char *path) {
}
int KernelProxy::stat(const char *path, struct stat *buf) {
- int fd = KernelProxy::open(path, O_RDONLY);
+ int fd = open(path, O_RDONLY);
if (-1 == fd) return -1;
-
+
int ret = fstat(fd, buf);
close(fd);
return ret;
}
int KernelProxy::chdir(const char* path) {
- Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
-
- MountNode* node = mnt->Open(rel, O_RDONLY);
- if (NULL == node) {
- errno = EEXIST;
- ReleaseMount(mnt);
+ struct stat statbuf;
+ if (stat(path, &statbuf) == -1)
return -1;
- }
- bool isDir = node->IsaDir();
- mnt->Close(node);
- ReleaseMount(mnt);
-
- if (isDir) {
+ bool is_dir = (statbuf.st_mode & S_IFDIR) != 0;
+ if (is_dir) {
AutoLock lock(&lock_);
cwd_ = GetAbsPathLocked(path).Join();
return 0;
@@ -243,7 +264,7 @@ int KernelProxy::mount(const char *source, const char *target,
mounts_[abs_targ] = mnt;
return 0;
}
- errno = EINVAL;
+ errno = EINVAL;
return -1;
}
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.h
index 2614fc8..0df80ee 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.h
@@ -40,6 +40,7 @@ class KernelProxy : protected KernelObject {
virtual int open(const char *path, int oflag);
virtual int close(int fd);
virtual int dup(int fd);
+ virtual int dup2(int fd, int newfd);
// System calls handled by KernelProxy (not mount-specific)
virtual int chdir(const char* path);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.h b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.h
index 38fb01f..d7ba17fa 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.h
@@ -39,6 +39,7 @@ int NAME(chdir)(const char* path) NOTHROW;
int NAME(chmod)(const char* path, chmod_mode_t mode) NOTHROW;
int NAME(close)(int fd);
int NAME(dup)(int oldfd) NOTHROW;
+int NAME(dup2)(int oldfd, int newfd) NOTHROW;
#if defined(WIN32)
int _fstat32(int fd, struct _stat32* buf);
int _fstat64(int fd, struct _stat64* buf);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_glibc.cc
index 7550b6a..3726b9e 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_glibc.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_glibc.cc
@@ -89,6 +89,7 @@ EXTERN_C_BEGIN
DECLARE(chdir)
DECLARE(close)
DECLARE(dup)
+DECLARE(dup2)
DECLARE(fstat)
DECLARE(getcwd)
DECLARE(getdents)
@@ -125,6 +126,10 @@ int WRAP(dup)(int fd, int* newfd) NOTHROW {
return (*newfd < 0) ? errno : 0;
}
+int WRAP(dup2)(int fd, int newfd) NOTHROW {
+ return (ki_dup2(fd, newfd) < 0) ? errno : 0;
+}
+
int WRAP(fstat)(int fd, struct nacl_abi_stat *nacl_buf) {
struct stat buf;
memset(&buf, 0, sizeof(struct stat));
@@ -140,17 +145,6 @@ int fsync(int fd) {
}
char* getcwd(char* buf, size_t size) NOTHROW {
- // gtest uses getcwd in a static initializer. If we haven't initialized the
- // kernel-intercept yet, just return ".".
- if (!ki_is_initialized()) {
- if (size < 2) {
- errno = ERANGE;
- return NULL;
- }
- buf[0] = '.';
- buf[1] = 0;
- return buf;
- }
return ki_getcwd(buf, size);
}
@@ -223,6 +217,9 @@ int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) {
}
int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) {
+ if (!ki_is_initialized())
+ return REAL(read)(fd, buf, count, nread);
+
*nread = ki_read(fd, buf, count);
return (*nread < 0) ? errno : 0;
}
@@ -267,24 +264,33 @@ int unlink(const char* path) NOTHROW {
}
int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) {
+ if (!ki_is_initialized())
+ return REAL(write)(fd, buf, count, nwrote);
+
*nwrote = ki_write(fd, buf, count);
return (*nwrote < 0) ? errno : 0;
}
void kernel_wrap_init() {
- DO_WRAP(chdir);
- DO_WRAP(close);
- DO_WRAP(dup);
- DO_WRAP(fstat);
- DO_WRAP(getcwd);
- DO_WRAP(getdents);
- DO_WRAP(mkdir);
- DO_WRAP(open);
- DO_WRAP(read);
- DO_WRAP(rmdir);
- DO_WRAP(seek);
- DO_WRAP(stat);
- DO_WRAP(write);
+ static bool wrapped = false;
+
+ if (!wrapped) {
+ wrapped = true;
+ DO_WRAP(chdir);
+ DO_WRAP(close);
+ DO_WRAP(dup);
+ DO_WRAP(dup2);
+ DO_WRAP(fstat);
+ DO_WRAP(getcwd);
+ DO_WRAP(getdents);
+ DO_WRAP(mkdir);
+ DO_WRAP(open);
+ DO_WRAP(read);
+ DO_WRAP(rmdir);
+ DO_WRAP(seek);
+ DO_WRAP(stat);
+ DO_WRAP(write);
+ }
}
EXTERN_C_END
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc
index 1e67faf..ff6b6bb 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_newlib.cc
@@ -35,6 +35,7 @@ DECLARE_STRUCT(filename)
DECLARE(fdio, close)
DECLARE(fdio, dup)
+DECLARE(fdio, dup2)
DECLARE(fdio, fstat)
DECLARE(fdio, getdents)
DECLARE(fdio, read)
@@ -65,6 +66,10 @@ int WRAP(dup)(int fd, int* newfd) {
return (*newfd < 0) ? errno : 0;
}
+int WRAP(dup2)(int fd, int newfd) {
+ return ki_dup2(fd, newfd);
+}
+
int WRAP(fstat)(int fd, struct stat *buf) {
return (ki_fstat(fd, buf) < 0) ? errno : 0;
}
@@ -74,17 +79,6 @@ int fsync(int fd) {
}
char* getcwd(char* buf, size_t size) {
- // gtest uses getcwd in a static initializer. If we haven't initialized the
- // kernel-intercept yet, just return ".".
- if (!ki_is_initialized()) {
- if (size < 2) {
- errno = ERANGE;
- return NULL;
- }
- buf[0] = '.';
- buf[1] = 0;
- return buf;
- }
return ki_getcwd(buf, size);
}
@@ -123,6 +117,9 @@ int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) {
}
int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) {
+ if (!ki_is_initialized())
+ return REAL(read)(fd, buf, count, nread);
+
ssize_t signed_nread = ki_read(fd, buf, count);
*nread = static_cast<size_t>(signed_nread);
return (signed_nread < 0) ? errno : 0;
@@ -158,6 +155,9 @@ int unlink(const char* path) {
}
int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) {
+ if (!ki_is_initialized())
+ return REAL(write)(fd, buf, count, nwrote);
+
ssize_t signed_nwrote = ki_write(fd, buf, count);
*nwrote = static_cast<size_t>(signed_nwrote);
return (signed_nwrote < 0) ? errno : 0;
@@ -165,15 +165,21 @@ int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) {
void kernel_wrap_init() {
- DO_WRAP(fdio, close);
- DO_WRAP(fdio, dup);
- DO_WRAP(fdio, fstat);
- DO_WRAP(fdio, getdents);
- DO_WRAP(fdio, read);
- DO_WRAP(fdio, seek);
- DO_WRAP(fdio, write);
- DO_WRAP(filename, open);
- DO_WRAP(filename, stat);
+ static bool wrapped = false;
+
+ if (!wrapped) {
+ wrapped = true;
+ DO_WRAP(fdio, close);
+ DO_WRAP(fdio, dup);
+ DO_WRAP(fdio, dup2);
+ DO_WRAP(fdio, fstat);
+ DO_WRAP(fdio, getdents);
+ DO_WRAP(fdio, read);
+ DO_WRAP(fdio, seek);
+ DO_WRAP(fdio, write);
+ DO_WRAP(filename, open);
+ DO_WRAP(filename, stat);
+ }
}
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_win.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_win.cc
index 935caad..f3355ed 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_win.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap_win.cc
@@ -67,6 +67,10 @@ int _dup(int oldfd) {
return ki_dup(oldfd);
}
+int _dup2(int oldfd, int newfd) {
+ return ki_dup2(oldfd, newfd);
+}
+
int _fstat32(int fd, struct _stat32* buf) {
struct stat ki_buf;
int res = ki_fstat(fd, &ki_buf);
@@ -100,17 +104,6 @@ int fsync(int fd) {
}
char* _getcwd(char* buf, int size) {
- // gtest uses getcwd in a static initializer. If we haven't initialized the
- // kernel-intercept yet, just return ".".
- if (!ki_is_initialized()) {
- if (size < 2) {
- errno = ERANGE;
- return NULL;
- }
- buf[0] = '.';
- buf[1] = 0;
- return buf;
- }
return ki_getcwd(buf, size);
}
@@ -168,10 +161,16 @@ errno_t _sopen_s(int* pfh, const char* path, int oflag, int shflag, int pmode) {
}
int _read(int fd, void* buf, size_t nbyte) {
+ if (!ki_is_initialized())
+ return 0;
+
return ki_read(fd, buf, nbyte);
}
int _read_nolock(int fd, void* buf, size_t nbyte) {
+ if (!ki_is_initialized())
+ return 0;
+
return ki_read(fd, buf, nbyte);
}
@@ -224,6 +223,9 @@ int _unlink(const char* path) {
}
int _write(int fd, const void* buf, size_t nbyte) {
+ if (!ki_is_initialized())
+ return 0;
+
return ki_write(fd, buf, nbyte);
}
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount.cc b/native_client_sdk/src/libraries/nacl_mounts/mount.cc
index e92f748..8c73594 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount.cc
@@ -16,8 +16,13 @@
#include "utils/auto_lock.h"
#include "utils/ref_object.h"
+#if defined(WIN32)
+#include <windows.h>
+#endif
+
Mount::Mount()
- : dev_(0) {
+ : dev_(0),
+ num_nodes_(0) {
}
Mount::~Mount() {}
@@ -49,3 +54,23 @@ int Mount::OpenModeToPermission(int mode) {
}
return out;
}
+
+void Mount::OnNodeCreated() {
+#if defined(__native_client__)
+ __sync_add_and_fetch(&num_nodes_, 1);
+#elif defined(WIN32)
+ InterlockedIncrement(&num_nodes_);
+#else
+#error Implement atomic functions for this platform.
+#endif
+}
+
+void Mount::OnNodeDestroyed() {
+#if defined(__native_client__)
+ __sync_sub_and_fetch(&num_nodes_, 1);
+#elif defined(WIN32)
+ InterlockedDecrement(&num_nodes_);
+#else
+#error Implement atomic functions for this platform.
+#endif
+}
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount.h b/native_client_sdk/src/libraries/nacl_mounts/mount.h
index 700097a..108fa7b 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount.h
@@ -30,9 +30,6 @@ class Mount : public RefObject {
// This function must assign a root node, or replace FindNode.
// |ppapi| can be NULL. If so, this mount cannot make any pepper calls.
virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
-
- // Destroy is called when the reference count reaches zero,
- // just before the destructor is called.
virtual void Destroy();
public:
@@ -42,13 +39,12 @@ class Mount : public RefObject {
PepperInterface* ppapi() { return ppapi_; }
// All paths are expected to containing a leading "/"
- virtual void AcquireNode(MountNode* node);
- virtual void ReleaseNode(MountNode* node);
+ void AcquireNode(MountNode* node);
+ void ReleaseNode(MountNode* node);
- // Open and Close will affect the RefCount on the node, so
- // there must be a call to close for each call to open.
+ // Open a node at |path|. The resulting MountNode is created with a ref
+ // count of 1, and will be Closed when the last reference is released.
virtual MountNode *Open(const Path& path, int mode) = 0;
- virtual int Close(MountNode* node) = 0;
// Unlink, Mkdir, Rmdir will affect the both the RefCount
// and the nlink number in the stat object.
@@ -60,9 +56,17 @@ class Mount : public RefObject {
// Convert from R,W,R/W open flags to STAT permission flags
static int OpenModeToPermission(int mode);
+ unsigned int num_nodes() const { return num_nodes_; }
+
+ // Should only be called by MountNode when a new node is created with this
+ // Mount as its parent.
+ void OnNodeCreated();
+ void OnNodeDestroyed();
+
protected:
// Device number for the mount.
int dev_;
+ unsigned int num_nodes_;
PepperInterface* ppapi_; // Weak reference.
private:
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc
index 83925da..e4d3fbff 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc
@@ -208,13 +208,6 @@ MountNode *MountDev::Open(const Path& path, int mode) {
return node;
}
-int MountDev::Close(MountNode* node) {
- AutoLock lock(&lock_);
- node->Close();
- node->Release();
- return 0;
-}
-
int MountDev::Unlink(const Path& path) {
errno = EINVAL;
return -1;
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_dev.h b/native_client_sdk/src/libraries/nacl_mounts/mount_dev.h
index 3c8c45d..4d81186 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_dev.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_dev.h
@@ -11,10 +11,7 @@ class MountNode;
class MountDev : public Mount {
public:
- // Open and Close will affect the RefCount on the node, so
- // there must be a call to close for each call to open.
virtual MountNode *Open(const Path& path, int mode);
- virtual int Close(MountNode* node);
virtual int Unlink(const Path& path);
virtual int Mkdir(const Path& path, int permissions);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.cc
index b8aed8a..6c18d73 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.cc
@@ -16,12 +16,6 @@
namespace {
-void ReleaseAndNullNode(MountNode** node) {
- if (*node)
- (*node)->Release();
- *node = NULL;
-}
-
#if defined(WIN32)
int64_t strtoull(const char* nptr, char** endptr, int base) {
return _strtoui64(nptr, endptr, base);
@@ -52,13 +46,6 @@ MountNode *MountHtml5Fs::Open(const Path& path, int mode) {
return node;
}
-int MountHtml5Fs::Close(MountNode* node) {
- AutoLock lock(&lock_);
- node->Close();
- node->Release();
- return 0;
-}
-
int MountHtml5Fs::Unlink(const Path& path) {
return Remove(path);
}
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.h b/native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.h
index 04843ce..4c54f171 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_html5fs.h
@@ -14,7 +14,6 @@ class MountNode;
class MountHtml5Fs: public Mount {
public:
virtual MountNode *Open(const Path& path, int mode);
- virtual int Close(MountNode* node);
virtual int Unlink(const Path& path);
virtual int Mkdir(const Path& path, int permissions);
virtual int Rmdir(const Path& path);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_http.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_http.cc
index f269a41..0a7b558 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_http.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_http.cc
@@ -470,13 +470,6 @@ MountNode *MountHttp::Open(const Path& path, int mode) {
return node;
}
-int MountHttp::Close(MountNode* node) {
- AutoLock lock(&lock_);
- node->Close();
- node->Release();
- return 0;
-}
-
int MountHttp::Unlink(const Path& path) {
errno = ENOSYS;
return -1;
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_http.h b/native_client_sdk/src/libraries/nacl_mounts/mount_http.h
index 6ba47b2..b9b1b83 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_http.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_http.h
@@ -15,7 +15,6 @@ class MountNode;
class MountHttp : public Mount {
public:
virtual MountNode *Open(const Path& path, int mode);
- virtual int Close(MountNode* node);
virtual int Unlink(const Path& path);
virtual int Mkdir(const Path& path, int permissions);
virtual int Rmdir(const Path& path);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc
index e0a35ca..3a81dd3 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_mem.cc
@@ -63,10 +63,6 @@ MountNode* MountMem::AllocateData(int mode) {
return ptr;
}
-void MountMem::ReleaseNode(MountNode* node) {
- node->Release();
-}
-
int MountMem::AllocateINO() {
const int INO_CNT = 8;
@@ -181,13 +177,6 @@ MountNode* MountMem::Open(const Path& path, int mode) {
return node;
}
-int MountMem::Close(MountNode* node) {
- AutoLock lock(&lock_);
- node->Close();
- ReleaseNode(node);
- return 0;
-}
-
int MountMem::Mkdir(const Path& path, int mode) {
AutoLock lock(&lock_);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_mem.h b/native_client_sdk/src/libraries/nacl_mounts/mount_mem.h
index 742ac17..e3cdec9 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_mem.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_mem.h
@@ -19,10 +19,9 @@ class MountMem : public Mount {
// The protected functions are only used internally and will not
// acquire or release the mount's lock themselves. The caller is
- // returned to use correct locking as needed.
- virtual MountNode *AllocateData(int mode);
- virtual MountNode *AllocatePath(int mode);
- virtual void ReleaseNode(MountNode *node);
+ // required to use correct locking as needed.
+ MountNode *AllocateData(int mode);
+ MountNode *AllocatePath(int mode);
// Allocate or free an INODE number.
int AllocateINO();
@@ -35,7 +34,6 @@ class MountMem : public Mount {
typedef std::vector<ino_t> INOList_t;
virtual MountNode *Open(const Path& path, int mode);
- virtual int Close(MountNode* node);
virtual int Unlink(const Path& path);
virtual int Mkdir(const Path& path, int perm);
virtual int Rmdir(const Path& path);
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_node.cc
index c27b419..5572ad4 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node.cc
@@ -18,9 +18,15 @@ MountNode::MountNode(Mount* mount, int ino, int dev)
memset(&stat_, 0, sizeof(stat_));
stat_.st_ino = ino;
stat_.st_dev = dev;
+
+ // Mount should normally never be NULL, but may be null in tests.
+ if (mount_)
+ mount_->OnNodeCreated();
}
MountNode::~MountNode() {
+ if (mount_)
+ mount_->OnNodeDestroyed();
}
bool MountNode::Init(int mode, short uid, short gid) {
@@ -30,6 +36,10 @@ bool MountNode::Init(int mode, short uid, short gid) {
return true;
}
+void MountNode::Destroy() {
+ Close();
+}
+
int MountNode::Close() {
FSync();
return 0;
@@ -54,6 +64,7 @@ int MountNode::Ioctl(int request, char* arg) {
errno = EINVAL;
return -1;
}
+
int MountNode::Read(size_t offs, void* buf, size_t count) {
errno = EINVAL;
return -1;
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node.h b/native_client_sdk/src/libraries/nacl_mounts/mount_node.h
index a11a6a9..0da2c32 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node.h
@@ -18,12 +18,17 @@ class MountNode : public RefObject {
protected:
virtual ~MountNode();
+ // This method is called by Destroy when the last reference to this
+ // MountNode is released. Override this instead of Destroy, but do not call
+ // it directly.
+ virtual int Close();
+
protected:
MountNode(Mount* mount, int ino, int dev);
virtual bool Init(int mode, short uid, short gid);
- virtual int Close();
+ virtual void Destroy();
-public:
+ public:
// Normal OS operations on a node (file), can be called by the kernel
// directly so it must lock and unlock appropriately. These functions
// must not be called by the mount.
@@ -43,7 +48,7 @@ public:
virtual bool IsaFile();
virtual bool IsaTTY();
-protected:
+ protected:
// Directory operations on the node are done by the Mount. The mount's lock
// must be held while these calls are made.
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/Makefile b/native_client_sdk/src/libraries/nacl_mounts_test/Makefile
index 3f76a15..7e6a128 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/Makefile
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/Makefile
@@ -42,7 +42,9 @@ include $(NACL_SDK_ROOT)/tools/common.mk
# and the set we do not.
#
DEPS=nacl_mounts ppapi_cpp
-LIBS=gtest_ppapi gtest gmock $(DEPS) ppapi pthread
+# Order matters here: gtest has a "main" function that will be used if
+# referenced before ppapi.
+LIBS=gtest_ppapi $(DEPS) gmock ppapi gtest pthread
#
# Use the library dependency macro for each dependency
@@ -55,7 +57,7 @@ $(foreach dep,$(DEPS),$(eval $(call DEPEND_RULE,$(dep))))
# The base name of the final NEXE, also the name of the NMF file containing
# the mapping between architecture and actual NEXE.
#
-TARGET=nacl_mount_test
+TARGET=nacl_mounts_test
#
# List of sources to compile
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_object_test.cc b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_object_test.cc
index 172cde4..d67243c 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_object_test.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_object_test.cc
@@ -18,13 +18,19 @@
#include "gtest/gtest.h"
-int g_MountCnt = 0;
-int g_HandleCnt = 0;
+namespace {
class MountRefMock : public Mount {
public:
- MountRefMock() : Mount() { g_MountCnt++; }
- ~MountRefMock() { g_MountCnt--; }
+ MountRefMock(int* mount_count, int* handle_count)
+ : mount_count(mount_count),
+ handle_count(handle_count) {
+ (*mount_count)++;
+ }
+
+ ~MountRefMock() {
+ (*mount_count)--;
+ }
public:
MountNode* Open(const Path& path, int mode) { return NULL; }
@@ -33,22 +39,50 @@ class MountRefMock : public Mount {
int Mkdir(const Path& path, int permissions) { return 0; }
int Rmdir(const Path& path) { return 0; }
int Remove(const Path& path) { return 0; }
+
+ public:
+ int* mount_count;
+ int* handle_count;
};
class KernelHandleRefMock : public KernelHandle {
public:
- KernelHandleRefMock(Mount* mnt, MountNode* node, int flags) :
- KernelHandle(mnt, node, flags) {
- g_HandleCnt++;
+ KernelHandleRefMock(Mount* mnt, MountNode* node, int flags)
+ : KernelHandle(mnt, node, flags) {
+ MountRefMock* mock_mount = static_cast<MountRefMock*>(mnt);
+ (*mock_mount->handle_count)++;
}
+
~KernelHandleRefMock() {
- g_HandleCnt--;
+ MountRefMock* mock_mount = static_cast<MountRefMock*>(mount_);
+ (*mock_mount->handle_count)--;
+ }
+};
+
+class KernelObjectTest : public ::testing::Test {
+ public:
+ KernelObjectTest()
+ : mount_count(0),
+ handle_count(0) {
+ proxy = new KernelObject;
+ mnt = new MountRefMock(&mount_count, &handle_count);
+ }
+
+ ~KernelObjectTest() {
+ // mnt is ref-counted, it doesn't need to be explicitly deleted.
+ delete proxy;
}
+
+ KernelObject* proxy;
+ MountRefMock* mnt;
+ int mount_count;
+ int handle_count;
};
-TEST(KernelObject, Referencing) {
- KernelObject* proxy = new KernelObject();
- Mount* mnt = new MountRefMock();
+} // namespace
+
+
+TEST_F(KernelObjectTest, Referencing) {
KernelHandle* handle = new KernelHandleRefMock(mnt, NULL, 0);
KernelHandle* handle2 = new KernelHandleRefMock(mnt, NULL, 0);
@@ -104,19 +138,52 @@ TEST(KernelObject, Referencing) {
EXPECT_EQ(1, handle2->RefCount());
EXPECT_EQ(3, mnt->RefCount());
- EXPECT_EQ(2, g_HandleCnt);
- EXPECT_EQ(1, g_MountCnt);
+ EXPECT_EQ(2, handle_count);
+ EXPECT_EQ(1, mount_count);
proxy->FreeFD(fd1);
- EXPECT_EQ(2, g_HandleCnt);
- EXPECT_EQ(1, g_MountCnt);
+ EXPECT_EQ(2, handle_count);
+ EXPECT_EQ(1, mount_count);
proxy->FreeFD(fd3);
- EXPECT_EQ(1, g_HandleCnt);
- EXPECT_EQ(1, g_MountCnt);
+ EXPECT_EQ(1, handle_count);
+ EXPECT_EQ(1, mount_count);
proxy->FreeFD(fd2);
- EXPECT_EQ(0, g_HandleCnt);
- EXPECT_EQ(0, g_MountCnt);
+ EXPECT_EQ(0, handle_count);
+ EXPECT_EQ(0, mount_count);
}
+TEST_F(KernelObjectTest, AssignFD) {
+ EXPECT_EQ(0, handle_count);
+
+ KernelHandle* handle = new KernelHandleRefMock(mnt, NULL, 0);
+
+ EXPECT_EQ(1, handle_count);
+ EXPECT_EQ(1, handle->RefCount());
+
+ proxy->AssignFD(2, handle);
+ EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(0));
+ EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(1));
+ EXPECT_EQ(handle, proxy->AcquireHandle(2));
+ proxy->ReleaseHandle(handle);
+
+ EXPECT_EQ(1, handle_count);
+ EXPECT_EQ(2, handle->RefCount());
+
+ proxy->AssignFD(0, handle);
+ EXPECT_EQ(handle, proxy->AcquireHandle(0));
+ EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(1));
+ EXPECT_EQ(handle, proxy->AcquireHandle(2));
+ proxy->ReleaseHandle(handle);
+ proxy->ReleaseHandle(handle);
+
+ EXPECT_EQ(1, handle_count);
+ EXPECT_EQ(3, handle->RefCount());
+
+ proxy->FreeFD(0);
+ proxy->FreeFD(2);
+ proxy->ReleaseHandle(handle); // handle is constructed with a refcount of 1.
+
+ EXPECT_EQ(0, handle_count);
+}
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.cc b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.cc
index d436bb3..f07a11e 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.cc
@@ -4,9 +4,13 @@
*/
#include "kernel_proxy_mock.h"
+#include "nacl_mounts/kernel_intercept.h"
KernelProxyMock::KernelProxyMock() {
}
KernelProxyMock::~KernelProxyMock() {
+ // Uninitialize the kernel proxy so wrapped functions passthrough to their
+ // unwrapped versions.
+ ki_uninit();
}
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.h b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.h
index 348dfda8..5c1da16 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.h
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_mock.h
@@ -22,6 +22,7 @@ class KernelProxyMock : public KernelProxy {
MOCK_METHOD2(chmod, int(const char*, mode_t));
MOCK_METHOD1(close, int(int));
MOCK_METHOD1(dup, int(int));
+ MOCK_METHOD2(dup2, int(int, int));
MOCK_METHOD2(fstat, int(int, struct stat*));
MOCK_METHOD1(fsync, int(int));
MOCK_METHOD2(getcwd, char*(char*, size_t));
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_test.cc b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_test.cc
index 771a429..a63f5a0 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_proxy_test.cc
@@ -21,10 +21,25 @@
#include "gtest/gtest.h"
-TEST(KernelProxy, WorkingDirectory) {
- char text[1024];
+class KernelProxyTest : public ::testing::Test {
+ public:
+ KernelProxyTest()
+ : kp_(new KernelProxy) {
+ ki_init(kp_);
+ }
+
+ ~KernelProxyTest() {
+ ki_uninit();
+ delete kp_;
+ }
+
+ private:
+ KernelProxy* kp_;
+};
+
- ki_init(new KernelProxy());
+TEST_F(KernelProxyTest, WorkingDirectory) {
+ char text[1024];
text[0] = 0;
ki_getcwd(text, sizeof(text));
@@ -39,7 +54,7 @@ TEST(KernelProxy, WorkingDirectory) {
EXPECT_STREQ("/", alloc);
EXPECT_EQ(-1, ki_chdir("/foo"));
- EXPECT_EQ(EEXIST, errno);
+ EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(0, ki_chdir("/"));
@@ -54,20 +69,18 @@ TEST(KernelProxy, WorkingDirectory) {
memset(text, 0, sizeof(text));
EXPECT_EQ(-1, ki_chdir("foo"));
- EXPECT_EQ(EEXIST, errno);
+ EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(0, ki_chdir(".."));
EXPECT_EQ(0, ki_chdir("/foo"));
EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
EXPECT_STREQ("/foo", text);
}
-TEST(KernelProxy, MemMountIO) {
+TEST_F(KernelProxyTest, MemMountIO) {
char text[1024];
int fd1, fd2, fd3;
int len;
- ki_init(new KernelProxy());
-
// Create "/foo"
EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
@@ -120,9 +133,7 @@ TEST(KernelProxy, MemMountIO) {
EXPECT_STREQ("HELLOWORLD", text);
}
-TEST(KernelProxy, MemMountLseek) {
- ki_init(new KernelProxy());
-
+TEST_F(KernelProxyTest, MemMountLseek) {
int fd = ki_open("/foo", O_CREAT | O_RDWR);
EXPECT_EQ(9, ki_write(fd, "Some text", 9));
@@ -140,6 +151,48 @@ TEST(KernelProxy, MemMountLseek) {
EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
}
+TEST_F(KernelProxyTest, CloseTwice) {
+ int fd = ki_open("/foo", O_CREAT | O_RDWR);
+ EXPECT_EQ(9, ki_write(fd, "Some text", 9));
+
+ int fd2 = ki_dup(fd);
+ EXPECT_NE(-1, fd2);
+
+ EXPECT_EQ(0, ki_close(fd));
+ EXPECT_EQ(0, ki_close(fd2));
+}
+
+TEST_F(KernelProxyTest, MemMountDup) {
+ int fd = ki_open("/foo", O_CREAT | O_RDWR);
+
+ int dup_fd = ki_dup(fd);
+ EXPECT_NE(-1, dup_fd);
+
+ EXPECT_EQ(9, ki_write(fd, "Some text", 9));
+ EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
+ EXPECT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
+
+ int dup2_fd = 123;
+ EXPECT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
+ EXPECT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
+
+ int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
+
+ EXPECT_EQ(fd, ki_dup2(new_fd, fd));
+ // fd, new_fd -> "/bar"
+ // dup_fd, dup2_fd -> "/foo"
+
+ // We should still be able to write to dup_fd (i.e. it should not be closed).
+ EXPECT_EQ(4, ki_write(dup_fd, "more", 4));
+
+ EXPECT_EQ(0, ki_close(dup2_fd));
+ // fd, new_fd -> "/bar"
+ // dup_fd -> "/foo"
+
+ EXPECT_EQ(dup_fd, ki_dup2(fd, dup_fd));
+ // fd, new_fd, dup_fd -> "/bar"
+}
+
StringMap_t g_StringMap;
@@ -160,8 +213,25 @@ class KernelProxyMountMock : public KernelProxy {
}
};
-TEST(KernelProxy, MountInit) {
- ki_init(new KernelProxyMountMock());
+class KernelProxyMountTest : public ::testing::Test {
+ public:
+ KernelProxyMountTest()
+ : kp_(new KernelProxyMountMock) {
+ ki_init(kp_);
+ }
+
+ ~KernelProxyMountTest() {
+ ki_uninit();
+ delete kp_;
+ }
+
+ private:
+ KernelProxy* kp_;
+};
+
+
+
+TEST_F(KernelProxyMountTest, MountInit) {
int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
EXPECT_EQ("bar", g_StringMap["foo"]);
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_wrap_test.cc b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_wrap_test.cc
index 7a7f920..41b10bd 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/kernel_wrap_test.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/kernel_wrap_test.cc
@@ -72,46 +72,53 @@ void MakeDummyStatbuf(struct stat* statbuf) {
statbuf->st_ctime = 11;
}
-} // namespace
+class KernelWrapTest : public ::testing::Test {
+ public:
+ KernelWrapTest() {
+ ki_init(&mock);
+ }
+
+ ~KernelWrapTest() {
+ ki_uninit();
+ }
-TEST(KernelWrap, access) {
KernelProxyMock mock;
- ki_init(&mock);
+};
+
+} // namespace
+
+
+TEST_F(KernelWrapTest, access) {
EXPECT_CALL(mock, access(StrEq("access"), 12)).Times(1);
access("access", 12);
}
-TEST(KernelWrap, chdir) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, chdir) {
EXPECT_CALL(mock, chdir(StrEq("chdir"))).Times(1);
chdir("chdir");
}
-TEST(KernelWrap, chmod) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, chmod) {
EXPECT_CALL(mock, chmod(StrEq("chmod"), 23)).Times(1);
chmod("chmod", 23);
}
-TEST(KernelWrap, close) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, close) {
EXPECT_CALL(mock, close(34)).Times(1);
close(34);
}
-TEST(KernelWrap, dup) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, dup) {
EXPECT_CALL(mock, dup(123)).Times(1);
dup(123);
}
-TEST(KernelWrap, fstat) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, dup2) {
+ EXPECT_CALL(mock, dup2(123, 234)).Times(1);
+ dup2(123, 234);
+}
+
+TEST_F(KernelWrapTest, fstat) {
struct stat in_statbuf;
MakeDummyStatbuf(&in_statbuf);
EXPECT_CALL(mock, fstat(234, _))
@@ -122,24 +129,18 @@ TEST(KernelWrap, fstat) {
EXPECT_THAT(&in_statbuf, IsEqualToStatbuf(&out_statbuf));
}
-TEST(KernelWrap, fsync) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, fsync) {
EXPECT_CALL(mock, fsync(345)).Times(1);
fsync(345);
}
-TEST(KernelWrap, getcwd) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, getcwd) {
EXPECT_CALL(mock, getcwd(StrEq("getcwd"), 1)).Times(1);
char buffer[] = "getcwd";
getcwd(buffer, 1);
}
-TEST(KernelWrap, getdents) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, getdents) {
EXPECT_CALL(mock, getdents(456, NULL, 567)).Times(1);
getdents(456, NULL, 567);
}
@@ -148,9 +149,7 @@ TEST(KernelWrap, getdents) {
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
-TEST(KernelWrap, getwd) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, getwd) {
EXPECT_CALL(mock, getwd(StrEq("getwd"))).Times(1);
char buffer[] = "getwd";
getwd(buffer);
@@ -159,23 +158,17 @@ TEST(KernelWrap, getwd) {
#pragma GCC diagnostic warning "-Wdeprecated-declarations"
#endif
-TEST(KernelWrap, isatty) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, isatty) {
EXPECT_CALL(mock, isatty(678)).Times(1);
isatty(678);
}
-TEST(KernelWrap, lseek) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, lseek) {
EXPECT_CALL(mock, lseek(789, 891, 912)).Times(1);
lseek(789, 891, 912);
}
-TEST(KernelWrap, mkdir) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, mkdir) {
#if defined(WIN32)
EXPECT_CALL(mock, mkdir(StrEq("mkdir"), 0777)).Times(1);
mkdir("mkdir");
@@ -185,46 +178,34 @@ TEST(KernelWrap, mkdir) {
#endif
}
-TEST(KernelWrap, mount) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, mount) {
EXPECT_CALL(mock,
mount(StrEq("mount1"), StrEq("mount2"), StrEq("mount3"), 2345, NULL))
.Times(1);
mount("mount1", "mount2", "mount3", 2345, NULL);
}
-TEST(KernelWrap, open) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, open) {
EXPECT_CALL(mock, open(StrEq("open"), 3456)).Times(1);
open("open", 3456);
}
-TEST(KernelWrap, read) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, read) {
EXPECT_CALL(mock, read(4567, NULL, 5678)).Times(1);
read(4567, NULL, 5678);
}
-TEST(KernelWrap, remove) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, remove) {
EXPECT_CALL(mock, remove(StrEq("remove"))).Times(1);
remove("remove");
}
-TEST(KernelWrap, rmdir) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, rmdir) {
EXPECT_CALL(mock, rmdir(StrEq("rmdir"))).Times(1);
rmdir("rmdir");
}
-TEST(KernelWrap, stat) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, stat) {
struct stat in_statbuf;
MakeDummyStatbuf(&in_statbuf);
EXPECT_CALL(mock, stat(StrEq("stat"), _))
@@ -235,23 +216,17 @@ TEST(KernelWrap, stat) {
EXPECT_THAT(&in_statbuf, IsEqualToStatbuf(&out_statbuf));
}
-TEST(KernelWrap, umount) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, umount) {
EXPECT_CALL(mock, umount(StrEq("umount"))).Times(1);
umount("umount");
}
-TEST(KernelWrap, unlink) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, unlink) {
EXPECT_CALL(mock, unlink(StrEq("unlink"))).Times(1);
unlink("unlink");
}
-TEST(KernelWrap, write) {
- KernelProxyMock mock;
- ki_init(&mock);
+TEST_F(KernelWrapTest, write) {
EXPECT_CALL(mock, write(6789, NULL, 7891)).Times(1);
write(6789, NULL, 7891);
}
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/mount_html5fs_test.cc b/native_client_sdk/src/libraries/nacl_mounts_test/mount_html5fs_test.cc
index 1a3c819..03b87e3 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/mount_html5fs_test.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/mount_html5fs_test.cc
@@ -80,6 +80,7 @@ class MountHtml5FsMock : public MountHtml5Fs {
class MountHtml5FsTest : public ::testing::Test {
public:
MountHtml5FsTest();
+ ~MountHtml5FsTest();
void SetUpFilesystem(PP_FileSystemType, int);
protected:
@@ -93,6 +94,10 @@ MountHtml5FsTest::MountHtml5FsTest()
: ppapi_(NULL) {
}
+MountHtml5FsTest::~MountHtml5FsTest() {
+ delete ppapi_;
+}
+
void MountHtml5FsTest::SetUpFilesystem(PP_FileSystemType fstype,
int expected_size) {
ppapi_ = new PepperInterfaceMock(instance_);
@@ -162,7 +167,7 @@ void MountHtml5FsNodeTest::SetUp() {
}
void MountHtml5FsNodeTest::TearDown() {
- mnt_->Close(node_);
+ mnt_->ReleaseNode(node_);
delete mnt_;
}
@@ -222,6 +227,7 @@ TEST_F(MountHtml5FsTest, Remove) {
int32_t result = mnt.Remove(Path(path));
ASSERT_EQ(0, result);
}
+
TEST_F(MountHtml5FsNodeTest, OpenAndClose) {
}
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc b/native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc
index a167866..cf89f4b 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc
@@ -20,30 +20,15 @@ namespace {
class MountMemMock : public MountMem {
public:
- MountMemMock()
- : MountMem(),
- nodes_(0) {
+ MountMemMock() {
StringMap_t map;
Init(1, map, NULL);
};
-
- MountNode* AllocateData(int mode) {
- nodes_++;
- return MountMem::AllocateData(mode);
- }
-
- void ReleaseNode(MountNode* node) {
- if (!node->Release()) {
- nodes_--;
- }
- }
-
- int nodes_;
};
class MountDevMock : public MountDev {
public:
- MountDevMock() : MountDev() {
+ MountDevMock() {
StringMap_t map;
Init(1, map, NULL);
}
@@ -61,7 +46,8 @@ TEST(MountTest, Sanity) {
char buf1[1024];
- EXPECT_EQ(0, mnt->nodes_);
+ // A memory mount starts with one directory node: the root.
+ EXPECT_EQ(1, mnt->num_nodes());
// Fail to open non existant file
EXPECT_EQ(NULL_NODE, mnt->Open(Path("/foo"), O_RDWR));
@@ -72,7 +58,7 @@ TEST(MountTest, Sanity) {
EXPECT_NE(NULL_NODE, file);
if (file == NULL) return;
EXPECT_EQ(2, file->RefCount());
- EXPECT_EQ(1, mnt->nodes_);
+ EXPECT_EQ(2, mnt->num_nodes());
// Open the root directory
root = mnt->Open(Path("/"), O_RDWR);
@@ -86,7 +72,7 @@ TEST(MountTest, Sanity) {
// Fail to re-create the same file
EXPECT_EQ(NULL_NODE, mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL));
EXPECT_EQ(errno, EEXIST);
- EXPECT_EQ(1, mnt->nodes_);
+ EXPECT_EQ(2, mnt->num_nodes());
// Fail to create a directory with the same name
EXPECT_EQ(-1, mnt->Mkdir(Path("/foo"), O_RDWR));
@@ -102,18 +88,18 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(file, mnt->Open(Path("/foo"), O_RDWR | O_CREAT));
EXPECT_EQ(sizeof(buf1), file->GetSize());
EXPECT_EQ(3, file->RefCount());
- EXPECT_EQ(1, mnt->nodes_);
+ EXPECT_EQ(2, mnt->num_nodes());
// Attempt to close and delete the file
- EXPECT_EQ(0, mnt->Close(file));
- EXPECT_EQ(1, mnt->nodes_);
+ mnt->ReleaseNode(file);
+ EXPECT_EQ(2, mnt->num_nodes());
EXPECT_EQ(0, mnt->Unlink(Path("/foo")));
- EXPECT_EQ(1, mnt->nodes_);
+ EXPECT_EQ(2, mnt->num_nodes());
EXPECT_EQ(-1, mnt->Unlink(Path("/foo")));
- EXPECT_EQ(1, mnt->nodes_);
+ EXPECT_EQ(2, mnt->num_nodes());
EXPECT_EQ(errno, ENOENT);
- EXPECT_EQ(0, mnt->Close(file));
- EXPECT_EQ(0, mnt->nodes_);
+ mnt->ReleaseNode(file);
+ EXPECT_EQ(1, mnt->num_nodes());
// Recreate foo as a directory
EXPECT_EQ(0, mnt->Mkdir(Path("/foo"), O_RDWR));
@@ -130,9 +116,9 @@ TEST(MountTest, Sanity) {
// Unlink the file, then delete the directory
EXPECT_EQ(0, mnt->Unlink(Path("/foo/bar")));
EXPECT_EQ(0, mnt->Rmdir(Path("/foo")));
- EXPECT_EQ(1, mnt->nodes_);
- EXPECT_EQ(0, mnt->Close(file));
- EXPECT_EQ(0, mnt->nodes_);
+ EXPECT_EQ(2, mnt->num_nodes());
+ mnt->ReleaseNode(file);
+ EXPECT_EQ(1, mnt->num_nodes());
// Verify the directory is gone
file = mnt->Open(Path("/foo"), O_RDWR);
@@ -147,7 +133,7 @@ TEST(MountTest, MemMountRemove) {
EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR));
file = mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL);
EXPECT_NE(NULL_NODE, file);
- EXPECT_EQ(0, mnt->Close(file));
+ mnt->ReleaseNode(file);
EXPECT_EQ(0, mnt->Remove(Path("/dir")));
EXPECT_EQ(0, mnt->Remove(Path("/file")));
@@ -171,7 +157,7 @@ TEST(MountTest, DevNull) {
const int kBufferLength = 100;
char buffer[kBufferLength];
EXPECT_EQ(0, dev_null->Read(0, &buffer[0], kBufferLength));
- EXPECT_EQ(0, mnt->Close(dev_null));
+ mnt->ReleaseNode(dev_null);
}
TEST(MountTest, DevZero) {
@@ -193,7 +179,7 @@ TEST(MountTest, DevZero) {
char zero_buffer[kBufferLength];
memset(&zero_buffer[0], 0, kBufferLength);
EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
- EXPECT_EQ(0, mnt->Close(dev_zero));
+ mnt->ReleaseNode(dev_zero);
}
TEST(MountTest, DevUrandom) {
diff --git a/native_client_sdk/src/libraries/utils/ref_object.h b/native_client_sdk/src/libraries/utils/ref_object.h
index 6cd8c84..d3eb9f8 100644
--- a/native_client_sdk/src/libraries/utils/ref_object.h
+++ b/native_client_sdk/src/libraries/utils/ref_object.h
@@ -21,8 +21,10 @@ class RefObject {
void Acquire() {
ref_count_++;
}
+
bool Release() {
if (--ref_count_ == 0) {
+ Destroy();
delete this;
return false;
}
@@ -34,6 +36,9 @@ class RefObject {
pthread_mutex_destroy(&lock_);
}
+ // Override to clean up object when last reference is released.
+ virtual void Destroy() {}
+
pthread_mutex_t lock_;
private: