kernel_object_test.cc revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <errno.h> 6#include <fcntl.h> 7#include <pthread.h> 8#include <sys/stat.h> 9 10#include <map> 11#include <string> 12 13#include "gtest/gtest.h" 14 15#include "nacl_io/kernel_handle.h" 16#include "nacl_io/kernel_object.h" 17#include "nacl_io/mount.h" 18#include "nacl_io/path.h" 19 20using namespace nacl_io; 21 22namespace { 23 24class MountNodeRefMock : public MountNode { 25 public: 26 MountNodeRefMock(Mount* mnt) : MountNode(mnt) {} 27}; 28 29class MountRefMock : public Mount { 30 public: 31 MountRefMock() {} 32 33 public: 34 Error Access(const Path& path, int a_mode) { return ENOSYS; } 35 Error Open(const Path& path, int mode, ScopedMountNode* out_node) { 36 out_node->reset(NULL); 37 return ENOSYS; 38 } 39 Error Unlink(const Path& path) { return 0; } 40 Error Mkdir(const Path& path, int permissions) { return 0; } 41 Error Rmdir(const Path& path) { return 0; } 42 Error Remove(const Path& path) { return 0; } 43}; 44 45class KernelHandleRefMock : public KernelHandle { 46 public: 47 KernelHandleRefMock(const ScopedMount& mnt, const ScopedMountNode& node) 48 : KernelHandle(mnt, node) {} 49}; 50 51class KernelObjectTest : public ::testing::Test { 52 public: 53 void SetUp() { 54 mnt.reset(new MountRefMock()); 55 node.reset(new MountNodeRefMock(mnt.get())); 56 } 57 58 void TearDown() { 59 // mnt is ref-counted, it doesn't need to be explicitly deleted. 60 node.reset(NULL); 61 mnt.reset(NULL); 62 } 63 64 KernelObject proxy; 65 ScopedMount mnt; 66 ScopedMountNode node; 67}; 68 69} // namespace 70 71#include <nacl_io/mount_mem.h> 72#include <nacl_io/mount_http.h> 73 74TEST_F(KernelObjectTest, Referencing) { 75 // The mount and node should have 1 ref count at this point 76 EXPECT_EQ(1, mnt->RefCount()); 77 EXPECT_EQ(1, node->RefCount()); 78 79 // Pass the mount and node into a KernelHandle 80 KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node); 81 ScopedKernelHandle handle_a(raw_handle); 82 83 // The mount and node should have 1 ref count at this point 84 EXPECT_EQ(1, handle_a->RefCount()); 85 EXPECT_EQ(2, mnt->RefCount()); 86 EXPECT_EQ(2, node->RefCount()); 87 88 ScopedKernelHandle handle_b = handle_a; 89 90 // There should be two references to the KernelHandle, the mount and node 91 // should be unchanged. 92 EXPECT_EQ(2, handle_a->RefCount()); 93 EXPECT_EQ(2, handle_b->RefCount()); 94 EXPECT_EQ(handle_a.get(), handle_b.get()); 95 EXPECT_EQ(2, mnt->RefCount()); 96 EXPECT_EQ(2, node->RefCount()); 97 98 // Allocating an FD should cause the KernelProxy to ref the handle and 99 // the node and mount should be unchanged. 100 int fd1 = proxy.AllocateFD(handle_a); 101 EXPECT_EQ(3, handle_a->RefCount()); 102 EXPECT_EQ(2, mnt->RefCount()); 103 EXPECT_EQ(2, node->RefCount()); 104 105 // If we "dup" the handle, we should bump the ref count on the handle 106 int fd2 = proxy.AllocateFD(handle_b); 107 EXPECT_EQ(4, handle_a->RefCount()); 108 EXPECT_EQ(2, mnt->RefCount()); 109 EXPECT_EQ(2, node->RefCount()); 110 111 // Handles are expected to come out in order 112 EXPECT_EQ(0, fd1); 113 EXPECT_EQ(1, fd2); 114 115 // Now we "free" the handles, since the proxy should hold them. 116 handle_a.reset(NULL); 117 handle_b.reset(NULL); 118 EXPECT_EQ(2, mnt->RefCount()); 119 EXPECT_EQ(2, node->RefCount()); 120 121 // We should find the handle by either fd 122 EXPECT_EQ(0, proxy.AcquireHandle(fd1, &handle_a)); 123 EXPECT_EQ(0, proxy.AcquireHandle(fd2, &handle_b)); 124 EXPECT_EQ(raw_handle, handle_a.get()); 125 EXPECT_EQ(raw_handle, handle_b.get()); 126 127 EXPECT_EQ(4, handle_a->RefCount()); 128 EXPECT_EQ(2, mnt->RefCount()); 129 EXPECT_EQ(2, node->RefCount()); 130 131 // A non existent fd should fail, and handleA should decrement as handleB 132 // is released by the call. 133 EXPECT_EQ(EBADF, proxy.AcquireHandle(-1, &handle_b)); 134 EXPECT_EQ(NULL, handle_b.get()); 135 EXPECT_EQ(3, handle_a->RefCount()); 136 137 EXPECT_EQ(EBADF, proxy.AcquireHandle(100, &handle_b)); 138 EXPECT_EQ(NULL, handle_b.get()); 139 140 // Now only the KernelProxy should reference the KernelHandle in the 141 // FD to KernelHandle Map. 142 handle_a.reset(); 143 handle_b.reset(); 144 145 EXPECT_EQ(2, raw_handle->RefCount()); 146 EXPECT_EQ(2, mnt->RefCount()); 147 EXPECT_EQ(2, node->RefCount()); 148 proxy.FreeFD(fd2); 149 EXPECT_EQ(1, raw_handle->RefCount()); 150 EXPECT_EQ(2, mnt->RefCount()); 151 EXPECT_EQ(2, node->RefCount()); 152 153 proxy.FreeFD(fd1); 154 EXPECT_EQ(1, mnt->RefCount()); 155 EXPECT_EQ(1, node->RefCount()); 156} 157 158TEST_F(KernelObjectTest, FreeAndReassignFD) { 159 // The mount and node should have 1 ref count at this point 160 EXPECT_EQ(1, mnt->RefCount()); 161 EXPECT_EQ(1, node->RefCount()); 162 163 KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node); 164 ScopedKernelHandle handle(raw_handle); 165 166 EXPECT_EQ(2, mnt->RefCount()); 167 EXPECT_EQ(2, node->RefCount()); 168 EXPECT_EQ(1, raw_handle->RefCount()); 169 170 proxy.AllocateFD(handle); 171 EXPECT_EQ(2, mnt->RefCount()); 172 EXPECT_EQ(2, node->RefCount()); 173 EXPECT_EQ(2, raw_handle->RefCount()); 174 175 proxy.FreeAndReassignFD(5, handle); 176 EXPECT_EQ(2, mnt->RefCount()); 177 EXPECT_EQ(2, node->RefCount()); 178 EXPECT_EQ(3, raw_handle->RefCount()); 179 180 handle.reset(); 181 EXPECT_EQ(2, raw_handle->RefCount()); 182 183 proxy.AcquireHandle(5, &handle); 184 EXPECT_EQ(3, raw_handle->RefCount()); 185 EXPECT_EQ(raw_handle, handle.get()); 186} 187 188