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