Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / tests / nacl_io_test / event_test.cc
blobf85f9e2cb92b41494b223ef43b64cb8a847af132
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 */
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>
14 #include "gtest/gtest.h"
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/pipe/pipe_node.h"
24 #include "nacl_io/stream/stream_fs.h"
26 #include "ppapi_simple/ps.h"
28 using namespace nacl_io;
29 using namespace sdk_util;
31 class EventListenerTester : public EventListener {
32 public:
33 EventListenerTester() : EventListener(), events_(0) {};
35 virtual void ReceiveEvents(EventEmitter* emitter, uint32_t events) {
36 events_ |= events;
39 uint32_t Events() { return events_; }
41 void Clear() { events_ = 0; }
43 uint32_t events_;
46 TEST(EmitterBasic, SingleThread) {
47 EventListenerTester listener_a;
48 EventListenerTester listener_b;
49 EventEmitter emitter;
51 emitter.RegisterListener(&listener_a, POLLIN | POLLOUT | POLLERR);
52 emitter.RegisterListener(&listener_b, POLLIN | POLLOUT | POLLERR);
54 EXPECT_EQ(0, emitter.GetEventStatus());
55 EXPECT_EQ(0, listener_a.Events());
58 AUTO_LOCK(emitter.GetLock())
59 emitter.RaiseEvents_Locked(POLLIN);
61 EXPECT_EQ(POLLIN, listener_a.Events());
63 listener_a.Clear();
66 AUTO_LOCK(emitter.GetLock())
67 emitter.RaiseEvents_Locked(POLLOUT);
69 EXPECT_EQ(POLLOUT, listener_a.Events());
70 EXPECT_EQ(POLLIN | POLLOUT, listener_b.Events());
73 class EmitterTest : public ::testing::Test {
74 public:
75 void SetUp() {
76 pthread_cond_init(&multi_cond_, NULL);
77 waiting_ = 0;
78 signaled_ = 0;
81 void TearDown() { pthread_cond_destroy(&multi_cond_); }
83 pthread_t CreateThread() {
84 pthread_t id;
85 EXPECT_EQ(0, pthread_create(&id, NULL, ThreadThunk, this));
86 return id;
89 static void* ThreadThunk(void* ptr) {
90 return static_cast<EmitterTest*>(ptr)->ThreadEntry();
93 void* ThreadEntry() {
94 EventListenerLock listener(&emitter_);
96 pthread_cond_signal(&multi_cond_);
97 waiting_++;
98 EXPECT_EQ(0, listener.WaitOnEvent(POLLIN, -1));
99 emitter_.ClearEvents_Locked(POLLIN);
100 AUTO_LOCK(signaled_lock_);
101 signaled_++;
102 return NULL;
105 int GetSignaledCount() {
106 AUTO_LOCK(signaled_lock_);
107 return signaled_;
110 protected:
111 pthread_cond_t multi_cond_;
112 EventEmitter emitter_;
113 int waiting_;
115 private:
116 int signaled_;
117 sdk_util::SimpleLock signaled_lock_;
120 // Temporarily disabled since it seems to be causing lockup in whe
121 // KernelWrapTests later on.
122 // TODO(sbc): renable once we fix http://crbug.com/378596
123 const int NUM_THREADS = 10;
124 TEST_F(EmitterTest, DISABLED_MultiThread) {
125 pthread_t threads[NUM_THREADS];
127 for (int a = 0; a < NUM_THREADS; a++)
128 threads[a] = CreateThread();
131 AUTO_LOCK(emitter_.GetLock());
133 // Wait for all threads to wait
134 while (waiting_ < NUM_THREADS)
135 pthread_cond_wait(&multi_cond_, emitter_.GetLock().mutex());
137 ASSERT_EQ(0, GetSignaledCount());
139 emitter_.RaiseEvents_Locked(POLLIN);
142 // sleep for 50 milliseconds
143 struct timespec sleeptime = {0, 50 * 1000 * 1000};
144 nanosleep(&sleeptime, NULL);
146 EXPECT_EQ(1, GetSignaledCount());
149 AUTO_LOCK(emitter_.GetLock());
150 emitter_.RaiseEvents_Locked(POLLIN);
153 nanosleep(&sleeptime, NULL);
154 EXPECT_EQ(2, GetSignaledCount());
156 // Clean up remaining threads.
157 while (GetSignaledCount() < waiting_) {
158 AUTO_LOCK(emitter_.GetLock());
159 emitter_.RaiseEvents_Locked(POLLIN);
162 for (int a = 0; a < NUM_THREADS; a++)
163 pthread_join(threads[a], NULL);
166 TEST(EventListenerPollTest, WaitForAny) {
167 ScopedEventEmitter emitter1(new EventEmitter());
168 ScopedEventEmitter emitter2(new EventEmitter());
169 ScopedEventEmitter emitter3(new EventEmitter());
170 EventListenerPoll listener;
171 EventRequest requests[3] = {
172 {emitter1, 0, 0}, {emitter2, 0, 0}, {emitter3, 0, 0}, };
173 Error error =
174 listener.WaitOnAny(requests, sizeof(requests) / sizeof(requests[0]), 1);
175 ASSERT_EQ(ETIMEDOUT, error);
178 TEST(PipeTest, Listener) {
179 const char hello[] = "Hello World.";
180 char tmp[64] = "Goodbye";
182 PipeEventEmitter pipe(32);
184 // Expect to time out on input.
186 EventListenerLock locker(&pipe);
187 EXPECT_EQ(ETIMEDOUT, locker.WaitOnEvent(POLLIN, 0));
190 // Output should be ready to go.
192 EventListenerLock locker(&pipe);
193 EXPECT_EQ(0, locker.WaitOnEvent(POLLOUT, 0));
194 int out_bytes = 0;
195 EXPECT_EQ(0, pipe.Write_Locked(hello, sizeof(hello), &out_bytes));
196 EXPECT_EQ(sizeof(hello), out_bytes);
199 // We should now be able to poll
201 EventListenerLock locker(&pipe);
202 EXPECT_EQ(0, locker.WaitOnEvent(POLLIN, 0));
203 int out_bytes = -1;
204 EXPECT_EQ(0, pipe.Read_Locked(tmp, sizeof(tmp), &out_bytes));
205 EXPECT_EQ(sizeof(hello), out_bytes);
208 // Verify we can read it correctly.
209 EXPECT_EQ(0, strcmp(hello, tmp));
212 class StreamFsForTesting : public StreamFs {
213 public:
214 StreamFsForTesting() {}
217 TEST(PipeNodeTest, Basic) {
218 ScopedFilesystem fs(new StreamFsForTesting());
220 PipeNode* pipe_node = new PipeNode(fs.get());
221 ScopedRef<PipeNode> pipe(pipe_node);
223 EXPECT_EQ(POLLOUT, pipe_node->GetEventStatus());
226 const int MAX_FDS = 32;
227 class SelectPollTest : public ::testing::Test {
228 public:
229 void SetUp() {
230 kp = new KernelProxy();
231 kp->Init(NULL);
232 EXPECT_EQ(0, kp->umount("/"));
233 EXPECT_EQ(0, kp->mount("", "/", "memfs", 0, NULL));
235 memset(&tv, 0, sizeof(tv));
238 void TearDown() { delete kp; }
240 void SetFDs(int* fds, int cnt) {
241 FD_ZERO(&rd_set);
242 FD_ZERO(&wr_set);
243 FD_ZERO(&ex_set);
245 for (int index = 0; index < cnt; index++) {
246 EXPECT_NE(-1, fds[index]);
247 FD_SET(fds[index], &rd_set);
248 FD_SET(fds[index], &wr_set);
249 FD_SET(fds[index], &ex_set);
251 pollfds[index].fd = fds[index];
252 pollfds[index].events = POLLIN | POLLOUT;
253 pollfds[index].revents = -1;
257 void CloseFDs(int* fds, int cnt) {
258 for (int index = 0; index < cnt; index++)
259 kp->close(fds[index]);
262 protected:
263 KernelProxy* kp;
265 timeval tv;
266 fd_set rd_set;
267 fd_set wr_set;
268 fd_set ex_set;
269 struct pollfd pollfds[MAX_FDS];
272 TEST_F(SelectPollTest, PollMemPipe) {
273 int fds[2];
275 // Both FDs for regular files should be read/write but not exception.
276 fds[0] = kp->open("/test.txt", O_CREAT | O_WRONLY, 0777);
277 fds[1] = kp->open("/test.txt", O_RDONLY, 0);
278 ASSERT_GT(fds[0], -1);
279 ASSERT_GT(fds[1], -1);
281 SetFDs(fds, 2);
283 ASSERT_EQ(2, kp->poll(pollfds, 2, 0));
284 ASSERT_EQ(POLLIN | POLLOUT, pollfds[0].revents);
285 ASSERT_EQ(POLLIN | POLLOUT, pollfds[1].revents);
286 CloseFDs(fds, 2);
288 // The write FD should select for write-only, read FD should not select
289 ASSERT_EQ(0, kp->pipe(fds));
290 SetFDs(fds, 2);
292 ASSERT_EQ(2, kp->poll(pollfds, 2, 0));
293 // TODO(bradnelson) fix poll based on open mode
294 // EXPECT_EQ(0, pollfds[0].revents);
295 // Bug 291018
296 ASSERT_EQ(POLLOUT, pollfds[1].revents);
298 CloseFDs(fds, 2);
301 TEST_F(SelectPollTest, SelectMemPipe) {
302 int fds[2];
304 // Both FDs for regular files should be read/write but not exception.
305 fds[0] = kp->open("/test.txt", O_CREAT | O_WRONLY, 0777);
306 fds[1] = kp->open("/test.txt", O_RDONLY, 0);
307 ASSERT_GT(fds[0], -1);
308 ASSERT_GT(fds[1], -1);
309 SetFDs(fds, 2);
311 ASSERT_EQ(4, kp->select(fds[1] + 1, &rd_set, &wr_set, &ex_set, &tv));
312 EXPECT_NE(0, FD_ISSET(fds[0], &rd_set));
313 EXPECT_NE(0, FD_ISSET(fds[1], &rd_set));
314 EXPECT_NE(0, FD_ISSET(fds[0], &wr_set));
315 EXPECT_NE(0, FD_ISSET(fds[1], &wr_set));
316 EXPECT_EQ(0, FD_ISSET(fds[0], &ex_set));
317 EXPECT_EQ(0, FD_ISSET(fds[1], &ex_set));
319 CloseFDs(fds, 2);
321 // The write FD should select for write-only, read FD should not select
322 ASSERT_EQ(0, kp->pipe(fds));
323 SetFDs(fds, 2);
325 ASSERT_EQ(2, kp->select(fds[1] + 1, &rd_set, &wr_set, &ex_set, &tv));
326 EXPECT_EQ(0, FD_ISSET(fds[0], &rd_set));
327 EXPECT_EQ(0, FD_ISSET(fds[1], &rd_set));
328 // TODO(bradnelson) fix poll based on open mode
329 // EXPECT_EQ(0, FD_ISSET(fds[0], &wr_set));
330 // Bug 291018
331 EXPECT_NE(0, FD_ISSET(fds[1], &wr_set));
332 EXPECT_EQ(0, FD_ISSET(fds[0], &ex_set));
333 EXPECT_EQ(0, FD_ISSET(fds[1], &ex_set));
337 * Test that calling select() only writes the initial parts of the fd_sets
338 * passed in.
339 * We had an issue when select() was calling FD_ZERO() on the incoming fd_sets
340 * which was causing corruption in ssh which always allocates the fd_sets to be
341 * hold 'nfds' worth of descriptors.
343 TEST_F(SelectPollTest, SelectPartialFdset) {
344 int fds[2];
346 // Both FDs for regular files should be read/write but not exception.
347 fds[0] = kp->open("/test.txt", O_CREAT | O_WRONLY, 0777);
348 fds[1] = kp->open("/test.txt", O_RDONLY, 0);
349 ASSERT_GT(fds[0], -1);
350 ASSERT_GT(fds[1], -1);
351 ASSERT_LT(fds[1], 8);
352 SetFDs(fds, 2);
354 // Fill in all the remaining bytes in the fd_sets a constant value
355 static const char guard_value = 0xab;
356 for (int i = 1; i < sizeof(fd_set); i++) {
357 ((char*)&rd_set)[i] = guard_value;
358 ((char*)&wr_set)[i] = guard_value;
359 ((char*)&ex_set)[i] = guard_value;
362 ASSERT_EQ(4, kp->select(fds[1] + 1, &rd_set, &wr_set, &ex_set, &tv));
364 // Verify guard values were not touched.
365 for (int i = 1; i < sizeof(fd_set); i++) {
366 ASSERT_EQ(guard_value, ((char*)&rd_set)[i]);
367 ASSERT_EQ(guard_value, ((char*)&wr_set)[i]);
368 ASSERT_EQ(guard_value, ((char*)&ex_set)[i]);