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 <poll.h> 8 #include <pthread.h> 9 #include <stdio.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/osunistd.h" 16 17 #include "sdk_util/auto_lock.h" 18 19 20 namespace nacl_io { 21 22 EventListener::EventListener() { 23 pthread_cond_init(&signal_cond_, NULL); 24 } 25 26 EventListener::~EventListener() { 27 pthread_cond_destroy(&signal_cond_); 28 } 29 30 // Before we can destroy ourselves, we must first unregister all the 31 // EventInfo objects from the various EventListeners 32 void EventListener::Destroy() { 33 EventInfoMap_t::iterator it; 34 35 // We do not take the lock since this is the only reference to this object. 36 for (it = event_info_map_.begin(); it != event_info_map_.end(); it++) { 37 if (it->second->emitter) { 38 it->second->emitter->UnregisterEventInfo(it->second); 39 } 40 } 41 42 EventEmitter::Destroy(); 43 } 44 45 uint32_t EventListener::GetEventStatus() { 46 // Always writable, but we can only assume it to be readable if there 47 // is an event waiting. 48 return signaled_.empty() ? POLLOUT : POLLIN | POLLOUT; 49 } 50 51 int EventListener::GetType() { 52 // For lack of a better type, report socket to signify it can be in an 53 // used to signal. 54 return S_IFSOCK; 55 } 56 57 // Called by EventEmitter, wakes up any blocking threads to verify if the wait 58 // conditions have been met. 59 void EventListener::Signal(const ScopedEventInfo& info) { 60 AUTO_LOCK(signal_lock_); 61 if (waiting_) { 62 signaled_.insert(info); 63 pthread_cond_broadcast(&signal_cond_); 64 } 65 } 66 67 static void AbsoluteFromDeltaMS(struct timespec* timeout, int ms_timeout) { 68 if (ms_timeout >= 0) { 69 uint64_t usec = usec_since_epoch(); 70 usec += ((int64_t) ms_timeout * 1000); 71 72 timeout->tv_nsec = (usec % 1000000) * 1000; 73 timeout->tv_sec = (usec / 1000000); 74 } else { 75 timeout->tv_sec = 0; 76 timeout->tv_nsec = 0; 77 } 78 } 79 80 Error EventListener::Wait(EventData* events, 81 int max, 82 int ms_timeout, 83 int* out_count) { 84 *out_count = 0; 85 86 if (max <= 0) 87 return EINVAL; 88 89 if (NULL == events) 90 return EFAULT; 91 92 { 93 AUTO_LOCK(info_lock_); 94 95 // Go through the "live" event infos and see if they are in a signaled state 96 EventInfoMap_t::iterator it = event_info_map_.begin(); 97 while ((it != event_info_map_.end()) && (*out_count < max)) { 98 ScopedEventInfo& info = it->second; 99 uint32_t event_bits = info->emitter->GetEventStatus() & info->filter; 100 101 if (event_bits) { 102 events[*out_count].events = event_bits; 103 events[*out_count].user_data = info->user_data; 104 (*out_count)++; 105 } 106 107 it++; 108 } 109 } // End of info_lock scope. 110 111 // We are done if we have a signal or no timeout specified. 112 if ((*out_count > 0) || (0 == ms_timeout)) 113 return 0; 114 115 // Compute the absolute time we can wait until. 116 struct timespec timeout; 117 AbsoluteFromDeltaMS(&timeout, ms_timeout); 118 119 // Keep looking if until we receive something. 120 while (0 == *out_count) { 121 // We are now officially waiting. 122 AUTO_LOCK(signal_lock_); 123 waiting_++; 124 125 // If we don't have any signals yet, wait for any Emitter to Signal. 126 while (signaled_.empty()) { 127 int return_code; 128 if (ms_timeout >= 0) { 129 return_code = pthread_cond_timedwait(&signal_cond_, 130 signal_lock_.mutex(), 131 &timeout); 132 } else { 133 return_code = pthread_cond_wait(&signal_cond_, signal_lock_.mutex()); 134 } 135 136 Error error(return_code); 137 138 // If there is no error, then we may have been signaled. 139 if (0 == error) 140 break; 141 142 // For any error case: 143 if (ETIMEDOUT == error) { 144 // A "TIMEOUT" is not an error. 145 error = 0; 146 } else { 147 // Otherwise this has gone bad, so return EBADF. 148 error = EBADF; 149 } 150 151 waiting_--; 152 return error; 153 } 154 155 // Copy signals over as long as we have room 156 while (!signaled_.empty() && (*out_count < max)) { 157 EventInfoSet_t::iterator it = signaled_.begin(); 158 159 events[*out_count].events = (*it)->events; 160 events[*out_count].user_data = (*it)->user_data; 161 (*out_count)++; 162 163 signaled_.erase(it); 164 } 165 166 // If we are the last thread waiting, clear out the signalled set 167 if (1 == waiting_) 168 signaled_.clear(); 169 170 // We are done waiting. 171 waiting_--; 172 } 173 174 return 0; 175 } 176 177 Error EventListener::Track(int id, 178 const ScopedEventEmitter& emitter, 179 uint32_t filter, 180 uint64_t user_data) { 181 AUTO_LOCK(info_lock_); 182 EventInfoMap_t::iterator it = event_info_map_.find(id); 183 184 // If it's not a streaming type, then it can not be added. 185 if ((emitter->GetType() & (S_IFIFO | S_IFSOCK)) == 0) 186 return EPERM; 187 188 if (it != event_info_map_.end()) 189 return EEXIST; 190 191 if (emitter.get() == this) 192 return EINVAL; 193 194 ScopedEventInfo info(new EventInfo); 195 info->emitter = emitter.get(); 196 info->listener = this; 197 info->id = id; 198 info->filter = filter; 199 info->user_data = user_data; 200 info->events = 0; 201 202 emitter->RegisterEventInfo(info); 203 event_info_map_[id] = info; 204 return 0; 205 } 206 207 Error EventListener::Update(int id, uint32_t filter, uint64_t user_data) { 208 AUTO_LOCK(info_lock_); 209 EventInfoMap_t::iterator it = event_info_map_.find(id); 210 if (it == event_info_map_.end()) 211 return ENOENT; 212 213 ScopedEventInfo& info = it->second; 214 info->filter = filter; 215 info->user_data = user_data; 216 return 0; 217 } 218 219 Error EventListener::Free(int id) { 220 AUTO_LOCK(info_lock_); 221 EventInfoMap_t::iterator it = event_info_map_.find(id); 222 if (event_info_map_.end() == it) 223 return ENOENT; 224 225 it->second->emitter->UnregisterEventInfo(it->second); 226 event_info_map_.erase(it); 227 return 0; 228 } 229 230 void EventListener::AbandonedEventInfo(const ScopedEventInfo& event) { 231 { 232 AUTO_LOCK(info_lock_); 233 234 event->emitter = NULL; 235 event_info_map_.erase(event->id); 236 } 237 238 // EventInfos abandoned by the destroyed emitter must still be kept in 239 // signaled_ set for POLLHUP. 240 event->events = POLLHUP; 241 Signal(event); 242 } 243 244 } // namespace nacl_io 245