• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
usec_since_epoch()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 
usec_since_epoch()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 
EventListener()47 EventListener::EventListener() {
48   pthread_cond_init(&signal_cond_, NULL);
49 }
50 
~EventListener()51 EventListener::~EventListener() {
52   pthread_cond_destroy(&signal_cond_);
53 }
54 
AbsoluteFromDeltaMS(struct timespec * timeout,int ms_timeout)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 
EventListenerLock(EventEmitter * emitter)68 EventListenerLock::EventListenerLock(EventEmitter* emitter)
69     : EventListener(),
70       emitter_(emitter),
71       lock_(new sdk_util::AutoLock(emitter->GetLock())),
72       events_(0) {
73 }
74 
~EventListenerLock()75 EventListenerLock::~EventListenerLock() {
76   delete lock_;
77 }
78 
ReceiveEvents(EventEmitter * emitter,uint32_t events)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 
WaitOnEvent(uint32_t events,int ms_timeout)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 
ReceiveEvents(EventEmitter * emitter,uint32_t events)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 
WaitOnAny(EventRequest * requests,size_t cnt,int ms_timeout)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