event_test.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
1/* Copyright (c) 2013 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 6#include <errno.h> 7#include <fcntl.h> 8#include <pthread.h> 9#include <stdio.h> 10#include <sys/ioctl.h> 11#include <sys/stat.h> 12#include <sys/time.h> 13 14#include "gtest/gtest.h" 15 16#include "nacl_io/event_emitter.h" 17#include "nacl_io/event_listener.h" 18#include "nacl_io/event_listener.h" 19#include "nacl_io/event_listener.h" 20#include "nacl_io/kernel_intercept.h" 21#include "nacl_io/kernel_proxy.h" 22#include "nacl_io/kernel_wrap.h" 23#include "nacl_io/mount_node_pipe.h" 24#include "nacl_io/mount_stream.h" 25 26#include "ppapi_simple/ps.h" 27 28 29using namespace nacl_io; 30using namespace sdk_util; 31 32 33class EventListenerTester : public EventListener { 34 public: 35 EventListenerTester() : EventListener(), events_(0) {}; 36 37 virtual void ReceiveEvents(EventEmitter* emitter, uint32_t events) { 38 events_ |= events; 39 } 40 41 uint32_t Events() { 42 return events_; 43 } 44 45 void Clear() { 46 events_ = 0; 47 } 48 49 uint32_t events_; 50}; 51 52 53TEST(EmitterBasic, SingleThread) { 54 EventListenerTester listener_a; 55 EventListenerTester listener_b; 56 EventEmitter emitter; 57 58 emitter.RegisterListener(&listener_a, POLLIN | POLLOUT | POLLERR); 59 emitter.RegisterListener(&listener_b, POLLIN | POLLOUT | POLLERR); 60 61 EXPECT_EQ(0, emitter.GetEventStatus()); 62 EXPECT_EQ(0, listener_a.Events()); 63 64 { 65 AUTO_LOCK(emitter.GetLock()) 66 emitter.RaiseEvents_Locked(POLLIN); 67 } 68 EXPECT_EQ(POLLIN, listener_a.Events()); 69 70 listener_a.Clear(); 71 72 { 73 AUTO_LOCK(emitter.GetLock()) 74 emitter.RaiseEvents_Locked(POLLOUT); 75 } 76 EXPECT_EQ(POLLOUT, listener_a.Events()); 77 EXPECT_EQ(POLLIN | POLLOUT, listener_b.Events()); 78} 79 80class EmitterTest : public ::testing::Test { 81 public: 82 void SetUp() { 83 pthread_cond_init(&multi_cond_, NULL); 84 waiting_ = 0; 85 signaled_ = 0; 86 } 87 88 void TearDown() { 89 pthread_cond_destroy(&multi_cond_); 90 } 91 92 void CreateThread() { 93 pthread_t id; 94 EXPECT_EQ(0, pthread_create(&id, NULL, ThreadThunk, this)); 95 } 96 97 static void* ThreadThunk(void *ptr) { 98 return static_cast<EmitterTest*>(ptr)->ThreadEntry(); 99 } 100 101 void* ThreadEntry() { 102 EventListenerLock listener(&emitter_); 103 104 pthread_cond_signal(&multi_cond_); 105 waiting_++; 106 EXPECT_EQ(0, listener.WaitOnEvent(POLLIN, -1)); 107 emitter_.ClearEvents_Locked(POLLIN); 108 signaled_++; 109 return NULL; 110 } 111 112 protected: 113 pthread_cond_t multi_cond_; 114 EventEmitter emitter_; 115 116 uint32_t waiting_; 117 uint32_t signaled_; 118}; 119 120 121const int NUM_THREADS = 10; 122TEST_F(EmitterTest, MultiThread) { 123 for (int a=0; a <NUM_THREADS; a++) 124 CreateThread(); 125 126 { 127 AUTO_LOCK(emitter_.GetLock()); 128 129 // Wait for all threads to wait 130 while(waiting_ < NUM_THREADS) 131 pthread_cond_wait(&multi_cond_, emitter_.GetLock().mutex()); 132 133 ASSERT_EQ(0, signaled_); 134 135 emitter_.RaiseEvents_Locked(POLLIN); 136 } 137 138 // sleep for 50 milliseconds 139 struct timespec sleeptime = { 0, 50 * 1000 * 1000 }; 140 nanosleep(&sleeptime, NULL); 141 142 EXPECT_EQ(1, signaled_); 143 144 { 145 AUTO_LOCK(emitter_.GetLock()); 146 emitter_.RaiseEvents_Locked(POLLIN); 147 } 148 149 nanosleep(&sleeptime, NULL); 150 EXPECT_EQ(2, signaled_); 151 152 // Clean up remaining threads. 153 while (signaled_ < waiting_) { 154 AUTO_LOCK(emitter_.GetLock()); 155 emitter_.RaiseEvents_Locked(POLLIN); 156 } 157} 158 159TEST(EventListenerPollTest, WaitForAny) { 160 ScopedEventEmitter emitter1(new EventEmitter()); 161 ScopedEventEmitter emitter2(new EventEmitter()); 162 ScopedEventEmitter emitter3(new EventEmitter()); 163 EventListenerPoll listener; 164 EventRequest requests[3] = { 165 { emitter1, 0, 0 }, 166 { emitter2, 0, 0 }, 167 { emitter3, 0, 0 }, 168 }; 169 Error error = listener.WaitOnAny(requests, 170 sizeof(requests)/sizeof(requests[0]), 171 1); 172 ASSERT_EQ(ETIMEDOUT, error); 173} 174 175TEST(PipeTest, Listener) { 176 const char hello[] = "Hello World."; 177 char tmp[64] = "Goodbye"; 178 179 EventEmitterPipe pipe(32); 180 181 // Expect to time out on input. 182 { 183 EventListenerLock locker(&pipe); 184 EXPECT_EQ(ETIMEDOUT, locker.WaitOnEvent(POLLIN, 0)); 185 } 186 187 // Output should be ready to go. 188 { 189 EventListenerLock locker(&pipe); 190 EXPECT_EQ(0, locker.WaitOnEvent(POLLOUT, 0)); 191 EXPECT_EQ(sizeof(hello), pipe.Write_Locked(hello, sizeof(hello))); 192 } 193 194 // We should now be able to poll 195 { 196 EventListenerLock locker(&pipe); 197 EXPECT_EQ(0, locker.WaitOnEvent(POLLIN, 0)); 198 EXPECT_EQ(sizeof(hello), pipe.Read_Locked(tmp, sizeof(tmp))); 199 } 200 201 // Verify we can read it correctly. 202 EXPECT_EQ(0, strcmp(hello, tmp)); 203} 204 205 206class TestMountStream : public MountStream { 207 public: 208 TestMountStream() {} 209}; 210 211TEST(PipeNodeTest, Basic) { 212 ScopedMount mnt(new TestMountStream()); 213 214 MountNodePipe* pipe_node = new MountNodePipe(mnt.get()); 215 ScopedRef<MountNodePipe> pipe(pipe_node); 216 217 EXPECT_EQ(POLLOUT, pipe_node->GetEventStatus()); 218} 219 220const int MAX_FDS = 32; 221class SelectPollTest : public ::testing::Test { 222 public: 223 void SetUp() { 224 kp = new KernelProxy(); 225 kp->Init(NULL); 226 EXPECT_EQ(0, kp->umount("/")); 227 EXPECT_EQ(0, kp->mount("", "/", "memfs", 0, NULL)); 228 229 memset(&tv, 0, sizeof(tv)); 230 } 231 232 void TearDown() { 233 delete kp; 234 } 235 236 void SetFDs(int* fds, int cnt) { 237 FD_ZERO(&rd_set); 238 FD_ZERO(&wr_set); 239 FD_ZERO(&ex_set); 240 241 for (int index = 0; index < cnt; index++) { 242 EXPECT_NE(-1, fds[index]); 243 FD_SET(fds[index], &rd_set); 244 FD_SET(fds[index], &wr_set); 245 FD_SET(fds[index], &ex_set); 246 247 pollfds[index].fd = fds[index]; 248 pollfds[index].events = POLLIN | POLLOUT; 249 pollfds[index].revents = -1; 250 } 251 } 252 253 void CloseFDs(int* fds, int cnt) { 254 for (int index = 0; index < cnt; index++) 255 kp->close(fds[index]); 256 } 257 258 protected: 259 KernelProxy* kp; 260 261 timeval tv; 262 fd_set rd_set; 263 fd_set wr_set; 264 fd_set ex_set; 265 struct pollfd pollfds[MAX_FDS]; 266}; 267 268TEST_F(SelectPollTest, PollMemPipe) { 269 int fds[2]; 270 271 // Both FDs for regular files should be read/write but not exception. 272 fds[0] = kp->open("/test.txt", O_CREAT | O_WRONLY); 273 fds[1] = kp->open("/test.txt", O_RDONLY); 274 ASSERT_GT(fds[0], -1); 275 ASSERT_GT(fds[1], -1); 276 277 SetFDs(fds, 2); 278 279 ASSERT_EQ(2, kp->poll(pollfds, 2, 0)); 280 ASSERT_EQ(POLLIN | POLLOUT, pollfds[0].revents); 281 ASSERT_EQ(POLLIN | POLLOUT, pollfds[1].revents); 282 CloseFDs(fds, 2); 283 284 // The write FD should select for write-only, read FD should not select 285 ASSERT_EQ(0, kp->pipe(fds)); 286 SetFDs(fds, 2); 287 288 ASSERT_EQ(2, kp->poll(pollfds, 2, 0)); 289 // TODO(noelallen) fix poll based on open mode 290 // EXPECT_EQ(0, pollfds[0].revents); 291 // Bug 291018 292 ASSERT_EQ(POLLOUT, pollfds[1].revents); 293 294 CloseFDs(fds, 2); 295} 296 297TEST_F(SelectPollTest, SelectMemPipe) { 298 int fds[2]; 299 300 // Both FDs for regular files should be read/write but not exception. 301 fds[0] = kp->open("/test.txt", O_CREAT | O_WRONLY); 302 fds[1] = kp->open("/test.txt", O_RDONLY); 303 ASSERT_GT(fds[0], -1); 304 ASSERT_GT(fds[1], -1); 305 SetFDs(fds, 2); 306 307 ASSERT_EQ(4, kp->select(fds[1] + 1, &rd_set, &wr_set, &ex_set, &tv)); 308 EXPECT_NE(0, FD_ISSET(fds[0], &rd_set)); 309 EXPECT_NE(0, FD_ISSET(fds[1], &rd_set)); 310 EXPECT_NE(0, FD_ISSET(fds[0], &wr_set)); 311 EXPECT_NE(0, FD_ISSET(fds[1], &wr_set)); 312 EXPECT_EQ(0, FD_ISSET(fds[0], &ex_set)); 313 EXPECT_EQ(0, FD_ISSET(fds[1], &ex_set)); 314 315 CloseFDs(fds, 2); 316 317 // The write FD should select for write-only, read FD should not select 318 ASSERT_EQ(0, kp->pipe(fds)); 319 SetFDs(fds, 2); 320 321 ASSERT_EQ(2, kp->select(fds[1] + 1, &rd_set, &wr_set, &ex_set, &tv)); 322 EXPECT_EQ(0, FD_ISSET(fds[0], &rd_set)); 323 EXPECT_EQ(0, FD_ISSET(fds[1], &rd_set)); 324 // TODO(noelallen) fix poll based on open mode 325 // EXPECT_EQ(0, FD_ISSET(fds[0], &wr_set)); 326 // Bug 291018 327 EXPECT_NE(0, FD_ISSET(fds[1], &wr_set)); 328 EXPECT_EQ(0, FD_ISSET(fds[0], &ex_set)); 329 EXPECT_EQ(0, FD_ISSET(fds[1], &ex_set)); 330} 331 332 333