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