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 
     69 EventListenerLock::EventListenerLock(EventEmitter* emitter)
     70     : EventListener(),
     71       emitter_(emitter),
     72       lock_(new sdk_util::AutoLock(emitter->GetLock())),
     73       events_(0) {
     74 }
     75 
     76 EventListenerLock::~EventListenerLock() {
     77   delete lock_;
     78 }
     79 
     80 void EventListenerLock::ReceiveEvents(EventEmitter* emitter,
     81                                       uint32_t events) {
     82   // We are using the emitter's mutex, which is already locked.
     83   pthread_cond_signal(&signal_cond_);
     84 }
     85 
     86 Error EventListenerLock::WaitOnEvent(uint32_t events, int ms_timeout) {
     87   struct timespec timeout;
     88   AbsoluteFromDeltaMS(&timeout, ms_timeout);
     89 
     90   emitter_->RegisterListener_Locked(this, events);
     91   while ((emitter_->GetEventStatus() & events) == 0) {
     92     int return_code;
     93     if (ms_timeout >= 0) {
     94       return_code = pthread_cond_timedwait(&signal_cond_,
     95                                            emitter_->GetLock().mutex(),
     96                                            &timeout);
     97     } else {
     98       return_code = pthread_cond_wait(&signal_cond_,
     99                                       emitter_->GetLock().mutex());
    100     }
    101 
    102     if (emitter_->GetEventStatus() & POLLERR)
    103       return_code = EINTR;
    104 
    105     // Return the failure, unlocked
    106     if (return_code != 0) {
    107       emitter_->UnregisterListener_Locked(this);
    108       return Error(return_code);
    109     }
    110   }
    111 
    112   emitter_->UnregisterListener_Locked(this);
    113   return 0;
    114 }
    115 
    116 void EventListenerPoll::ReceiveEvents(EventEmitter* emitter,
    117                                       uint32_t events) {
    118   AUTO_LOCK(signal_lock_);
    119   emitters_[emitter]->events |= events;
    120   signaled_++;
    121   pthread_cond_signal(&signal_cond_);
    122 }
    123 
    124 Error EventListenerPoll::WaitOnAny(EventRequest* requests,
    125                                    size_t cnt,
    126                                    int ms_timeout) {
    127 
    128   signaled_ = 0;
    129 
    130   // Build a map of request emitters to request data before
    131   // emitters can access them.
    132   for (size_t index = 0; index < cnt; index++) {
    133     EventRequest* request = requests + index;
    134     emitters_[request->emitter.get()] = request;
    135     request->events = 0;
    136   }
    137 
    138   // Emitters can now accessed the unlocked set, since each emitter is
    139   // responsible for it's own request.
    140   for (size_t index = 0; index < cnt; index++) {
    141     EventRequest* request = requests + index;
    142     request->emitter->RegisterListener(this, request->filter);
    143     uint32_t events = request->emitter->GetEventStatus() & request->filter;
    144 
    145     if (events) {
    146       AUTO_LOCK(signal_lock_);
    147       request->events |= events;
    148       signaled_++;
    149     }
    150   }
    151 
    152   struct timespec timeout;
    153   AbsoluteFromDeltaMS(&timeout, ms_timeout);
    154   int return_code = 0;
    155 
    156   {
    157     AUTO_LOCK(signal_lock_)
    158     while (0 == signaled_) {
    159       if (ms_timeout >= 0) {
    160         return_code = pthread_cond_timedwait(&signal_cond_,
    161                                               signal_lock_.mutex(),
    162                                               &timeout);
    163       } else {
    164         return_code = pthread_cond_wait(&signal_cond_,
    165                                         signal_lock_.mutex());
    166       }
    167 
    168       if (return_code != 0)
    169         signaled_++;
    170     }
    171   }
    172 
    173   // Unregister first to prevent emitters from modifying the set any further
    174   for (size_t index = 0; index < cnt; index++) {
    175     EventRequest* request = requests + index;
    176     request->emitter->UnregisterListener(this);
    177 
    178     if (request->events & POLLERR)
    179       return_code = EINTR;
    180   }
    181 
    182   // We can now release the map.
    183   emitters_.clear();
    184 
    185   return Error(return_code);
    186 }
    187 
    188 }  // namespace nacl_io
    189