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.
10 #include <sys/ioctl.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
{
33 EventListenerTester() : EventListener(), events_(0) {};
35 virtual void ReceiveEvents(EventEmitter
* emitter
, uint32_t events
) {
39 uint32_t Events() { return events_
; }
41 void Clear() { events_
= 0; }
46 TEST(EmitterBasic
, SingleThread
) {
47 EventListenerTester listener_a
;
48 EventListenerTester listener_b
;
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());
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
{
76 pthread_cond_init(&multi_cond_
, NULL
);
81 void TearDown() { pthread_cond_destroy(&multi_cond_
); }
83 pthread_t
CreateThread() {
85 EXPECT_EQ(0, pthread_create(&id
, NULL
, ThreadThunk
, this));
89 static void* ThreadThunk(void* ptr
) {
90 return static_cast<EmitterTest
*>(ptr
)->ThreadEntry();
94 EventListenerLock
listener(&emitter_
);
96 pthread_cond_signal(&multi_cond_
);
98 EXPECT_EQ(0, listener
.WaitOnEvent(POLLIN
, -1));
99 emitter_
.ClearEvents_Locked(POLLIN
);
100 AUTO_LOCK(signaled_lock_
);
105 int GetSignaledCount() {
106 AUTO_LOCK(signaled_lock_
);
111 pthread_cond_t multi_cond_
;
112 EventEmitter emitter_
;
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}, };
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));
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));
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
{
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
{
230 kp
= new KernelProxy();
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
) {
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
]);
269 struct pollfd pollfds
[MAX_FDS
];
272 TEST_F(SelectPollTest
, PollMemPipe
) {
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);
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
);
288 // The write FD should select for write-only, read FD should not select
289 ASSERT_EQ(0, kp
->pipe(fds
));
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);
296 ASSERT_EQ(POLLOUT
, pollfds
[1].revents
);
301 TEST_F(SelectPollTest
, SelectMemPipe
) {
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);
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
));
321 // The write FD should select for write-only, read FD should not select
322 ASSERT_EQ(0, kp
->pipe(fds
));
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));
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
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
) {
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);
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
]);