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