Home | History | Annotate | Download | only in nacl_io
      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 #include <errno.h>
      6 #include <poll.h>
      7 #include <pthread.h>
      8 #include <stdio.h>
      9 #include <sys/time.h>
     10 
     11 #include "nacl_io/error.h"
     12 #include "nacl_io/event_listener.h"
     13 #include "nacl_io/kernel_wrap.h"
     14 #include "nacl_io/osstat.h"
     15 #include "nacl_io/ostime.h"
     16 #include "nacl_io/osunistd.h"
     17 
     18 #include "sdk_util/auto_lock.h"
     19 
     20 #if defined(WIN32)
     21 
     22 #define USECS_FROM_WIN_TO_TO_UNIX_EPOCH 11644473600000LL
     23 static uint64_t usec_since_epoch() {
     24   FILETIME ft;
     25   ULARGE_INTEGER ularge;
     26   GetSystemTimeAsFileTime(&ft);
     27 
     28   ularge.LowPart = ft.dwLowDateTime;
     29   ularge.HighPart = ft.dwHighDateTime;
     30 
     31   // Truncate to usec resolution.
     32   return ularge.QuadPart / 10;
     33 }
     34 
     35 #else
     36 
     37 static uint64_t usec_since_epoch() {
     38   struct timeval tv;
     39   gettimeofday(&tv, NULL);
     40   return tv.tv_usec + (tv.tv_sec * 1000000);
     41 }
     42 
     43 #endif
     44 
     45 namespace nacl_io {
     46 
     47 EventListener::EventListener() {
     48   pthread_cond_init(&signal_cond_, NULL);
     49 }
     50 
     51 EventListener::~EventListener() {
     52   pthread_cond_destroy(&signal_cond_);
     53 }
     54 
     55 static void AbsoluteFromDeltaMS(struct timespec* timeout, int ms_timeout) {
     56   if (ms_timeout >= 0) {
     57     uint64_t usec = usec_since_epoch();
     58     usec += ((int64_t)ms_timeout * 1000);
     59 
     60     timeout->tv_nsec = (usec % 1000000) * 1000;
     61     timeout->tv_sec = (usec / 1000000);
     62   } else {
     63     timeout->tv_sec = 0;
     64     timeout->tv_nsec = 0;
     65   }
     66 }
     67 
     68 EventListenerLock::EventListenerLock(EventEmitter* emitter)
     69     : EventListener(),
     70       emitter_(emitter),
     71       lock_(new sdk_util::AutoLock(emitter->GetLock())),
     72       events_(0) {
     73 }
     74 
     75 EventListenerLock::~EventListenerLock() {
     76   delete lock_;
     77 }
     78 
     79 void EventListenerLock::ReceiveEvents(EventEmitter* emitter, uint32_t events) {
     80   // We are using the emitter's mutex, which is already locked.
     81   pthread_cond_signal(&signal_cond_);
     82 }
     83 
     84 Error EventListenerLock::WaitOnEvent(uint32_t events, int ms_timeout) {
     85   struct timespec timeout;
     86   AbsoluteFromDeltaMS(&timeout, ms_timeout);
     87 
     88   emitter_->RegisterListener_Locked(this, events);
     89   while ((emitter_->GetEventStatus_Locked() & events) == 0) {
     90     int return_code;
     91     if (ms_timeout >= 0) {
     92       return_code = pthread_cond_timedwait(&signal_cond_,
     93                                            emitter_->GetLock().mutex(),
     94                                            &timeout);
     95     } else {
     96       return_code = pthread_cond_wait(&signal_cond_,
     97                                       emitter_->GetLock().mutex());
     98     }
     99 
    100     if (emitter_->GetEventStatus_Locked() & POLLERR)
    101       return_code = EINTR;
    102 
    103     // Return the failure, unlocked
    104     if (return_code != 0) {
    105       emitter_->UnregisterListener_Locked(this);
    106       return Error(return_code);
    107     }
    108   }
    109 
    110   emitter_->UnregisterListener_Locked(this);
    111   return 0;
    112 }
    113 
    114 void EventListenerPoll::ReceiveEvents(EventEmitter* emitter, uint32_t events) {
    115   AUTO_LOCK(signal_lock_);
    116   emitters_[emitter]->events |= events;
    117   signaled_++;
    118   pthread_cond_signal(&signal_cond_);
    119 }
    120 
    121 Error EventListenerPoll::WaitOnAny(EventRequest* requests,
    122                                    size_t cnt,
    123                                    int ms_timeout) {
    124   signaled_ = 0;
    125 
    126   // Build a map of request emitters to request data before
    127   // emitters can access them.
    128   for (size_t index = 0; index < cnt; index++) {
    129     EventRequest* request = requests + index;
    130     emitters_[request->emitter.get()] = request;
    131     request->events = 0;
    132   }
    133 
    134   // Emitters can now accessed the unlocked set, since each emitter is
    135   // responsible for it's own request.
    136   for (size_t index = 0; index < cnt; index++) {
    137     EventRequest* request = requests + index;
    138     request->emitter->RegisterListener(this, request->filter);
    139     uint32_t events = request->emitter->GetEventStatus() & request->filter;
    140 
    141     if (events) {
    142       AUTO_LOCK(signal_lock_);
    143       request->events |= events;
    144       signaled_++;
    145     }
    146   }
    147 
    148   struct timespec timeout;
    149   AbsoluteFromDeltaMS(&timeout, ms_timeout);
    150   int return_code = 0;
    151 
    152   {
    153     AUTO_LOCK(signal_lock_)
    154     while (0 == signaled_) {
    155       if (ms_timeout >= 0) {
    156         return_code = pthread_cond_timedwait(&signal_cond_,
    157                                               signal_lock_.mutex(),
    158                                               &timeout);
    159       } else {
    160         return_code = pthread_cond_wait(&signal_cond_,
    161                                         signal_lock_.mutex());
    162       }
    163 
    164       if (return_code != 0)
    165         signaled_++;
    166     }
    167   }
    168 
    169   // Unregister first to prevent emitters from modifying the set any further
    170   for (size_t index = 0; index < cnt; index++) {
    171     EventRequest* request = requests + index;
    172     request->emitter->UnregisterListener(this);
    173 
    174     if (request->events & POLLERR)
    175       return_code = EINTR;
    176   }
    177 
    178   // We can now release the map.
    179   emitters_.clear();
    180 
    181   return Error(return_code);
    182 }
    183 
    184 }  // namespace nacl_io
    185