Home | History | Annotate | Download | only in nacl_io_test
      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/pipe/pipe_node.h"
     24 #include "nacl_io/stream/stream_fs.h"
     25 
     26 #include "ppapi_simple/ps.h"
     27 
     28 using namespace nacl_io;
     29 using namespace sdk_util;
     30 
     31 class EventListenerTester : public EventListener {
     32  public:
     33   EventListenerTester() : EventListener(), events_(0) {};
     34 
     35   virtual void ReceiveEvents(EventEmitter* emitter, uint32_t events) {
     36     events_ |= events;
     37   }
     38 
     39   uint32_t Events() { return events_; }
     40 
     41   void Clear() { events_ = 0; }
     42 
     43   uint32_t events_;
     44 };
     45 
     46 TEST(EmitterBasic, SingleThread) {
     47   EventListenerTester listener_a;
     48   EventListenerTester listener_b;
     49   EventEmitter emitter;
     50 
     51   emitter.RegisterListener(&listener_a, POLLIN | POLLOUT | POLLERR);
     52   emitter.RegisterListener(&listener_b, POLLIN | POLLOUT | POLLERR);
     53 
     54   EXPECT_EQ(0, emitter.GetEventStatus());
     55   EXPECT_EQ(0, listener_a.Events());
     56 
     57   {
     58     AUTO_LOCK(emitter.GetLock())
     59     emitter.RaiseEvents_Locked(POLLIN);
     60   }
     61   EXPECT_EQ(POLLIN, listener_a.Events());
     62 
     63   listener_a.Clear();
     64 
     65   {
     66     AUTO_LOCK(emitter.GetLock())
     67     emitter.RaiseEvents_Locked(POLLOUT);
     68   }
     69   EXPECT_EQ(POLLOUT, listener_a.Events());
     70   EXPECT_EQ(POLLIN | POLLOUT, listener_b.Events());
     71 }
     72 
     73 class EmitterTest : public ::testing::Test {
     74  public:
     75   void SetUp() {
     76     pthread_cond_init(&multi_cond_, NULL);
     77     waiting_ = 0;
     78     signaled_ = 0;
     79   }
     80 
     81   void TearDown() { pthread_cond_destroy(&multi_cond_); }
     82 
     83   pthread_t CreateThread() {
     84     pthread_t id;
     85     EXPECT_EQ(0, pthread_create(&id, NULL, ThreadThunk, this));
     86     return id;
     87   }
     88 
     89   static void* ThreadThunk(void* ptr) {
     90     return static_cast<EmitterTest*>(ptr)->ThreadEntry();
     91   }
     92 
     93   void* ThreadEntry() {
     94     EventListenerLock listener(&emitter_);
     95 
     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;
    103   }
    104 
    105   int GetSignaledCount() {
    106     AUTO_LOCK(signaled_lock_);
    107     return signaled_;
    108   }
    109 
    110  protected:
    111   pthread_cond_t multi_cond_;
    112   EventEmitter emitter_;
    113   int waiting_;
    114 
    115  private:
    116   int signaled_;
    117   sdk_util::SimpleLock signaled_lock_;
    118 };
    119 
    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];
    126 
    127   for (int a = 0; a < NUM_THREADS; a++)
    128     threads[a] = CreateThread();
    129 
    130   {
    131     AUTO_LOCK(emitter_.GetLock());
    132 
    133     // Wait for all threads to wait
    134     while (waiting_ < NUM_THREADS)
    135       pthread_cond_wait(&multi_cond_, emitter_.GetLock().mutex());
    136 
    137     ASSERT_EQ(0, GetSignaledCount());
    138 
    139     emitter_.RaiseEvents_Locked(POLLIN);
    140   }
    141 
    142   // sleep for 50 milliseconds
    143   struct timespec sleeptime = {0, 50 * 1000 * 1000};
    144   nanosleep(&sleeptime, NULL);
    145 
    146   EXPECT_EQ(1, GetSignaledCount());
    147 
    148   {
    149     AUTO_LOCK(emitter_.GetLock());
    150     emitter_.RaiseEvents_Locked(POLLIN);
    151   }
    152 
    153   nanosleep(&sleeptime, NULL);
    154   EXPECT_EQ(2, GetSignaledCount());
    155 
    156   // Clean up remaining threads.
    157   while (GetSignaledCount() < waiting_) {
    158     AUTO_LOCK(emitter_.GetLock());
    159     emitter_.RaiseEvents_Locked(POLLIN);
    160   }
    161 
    162   for (int a = 0; a < NUM_THREADS; a++)
    163     pthread_join(threads[a], NULL);
    164 }
    165 
    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);
    176 }
    177 
    178 TEST(PipeTest, Listener) {
    179   const char hello[] = "Hello World.";
    180   char tmp[64] = "Goodbye";
    181 
    182   PipeEventEmitter pipe(32);
    183 
    184   // Expect to time out on input.
    185   {
    186     EventListenerLock locker(&pipe);
    187     EXPECT_EQ(ETIMEDOUT, locker.WaitOnEvent(POLLIN, 0));
    188   }
    189 
    190   // Output should be ready to go.
    191   {
    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);
    197   }
    198 
    199   // We should now be able to poll
    200   {
    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);
    206   }
    207 
    208   // Verify we can read it correctly.
    209   EXPECT_EQ(0, strcmp(hello, tmp));
    210 }
    211 
    212 class StreamFsForTesting : public StreamFs {
    213  public:
    214   StreamFsForTesting() {}
    215 };
    216 
    217 TEST(PipeNodeTest, Basic) {
    218   ScopedFilesystem fs(new StreamFsForTesting());
    219 
    220   PipeNode* pipe_node = new PipeNode(fs.get());
    221   ScopedRef<PipeNode> pipe(pipe_node);
    222 
    223   EXPECT_EQ(POLLOUT, pipe_node->GetEventStatus());
    224 }
    225 
    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));
    234 
    235     memset(&tv, 0, sizeof(tv));
    236   }
    237 
    238   void TearDown() { delete kp; }
    239 
    240   void SetFDs(int* fds, int cnt) {
    241     FD_ZERO(&rd_set);
    242     FD_ZERO(&wr_set);
    243     FD_ZERO(&ex_set);
    244 
    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);
    250 
    251       pollfds[index].fd = fds[index];
    252       pollfds[index].events = POLLIN | POLLOUT;
    253       pollfds[index].revents = -1;
    254     }
    255   }
    256 
    257   void CloseFDs(int* fds, int cnt) {
    258     for (int index = 0; index < cnt; index++)
    259       kp->close(fds[index]);
    260   }
    261 
    262  protected:
    263   KernelProxy* kp;
    264 
    265   timeval tv;
    266   fd_set rd_set;
    267   fd_set wr_set;
    268   fd_set ex_set;
    269   struct pollfd pollfds[MAX_FDS];
    270 };
    271 
    272 TEST_F(SelectPollTest, PollMemPipe) {
    273   int fds[2];
    274 
    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);
    280 
    281   SetFDs(fds, 2);
    282 
    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);
    287 
    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);
    291 
    292   ASSERT_EQ(2, kp->poll(pollfds, 2, 0));
    293   // TODO(noelallen) fix poll based on open mode
    294   // EXPECT_EQ(0, pollfds[0].revents);
    295   // Bug 291018
    296   ASSERT_EQ(POLLOUT, pollfds[1].revents);
    297 
    298   CloseFDs(fds, 2);
    299 }
    300 
    301 TEST_F(SelectPollTest, SelectMemPipe) {
    302   int fds[2];
    303 
    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);
    310 
    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));
    318 
    319   CloseFDs(fds, 2);
    320 
    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);
    324 
    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(noelallen) 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));
    334 }
    335 
    336 /**
    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.
    342  */
    343 TEST_F(SelectPollTest, SelectPartialFdset) {
    344   int fds[2];
    345 
    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);
    353 
    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;
    360   }
    361 
    362   ASSERT_EQ(4, kp->select(fds[1] + 1, &rd_set, &wr_set, &ex_set, &tv));
    363 
    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]);
    369   }
    370 }
    371