Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
| 6 #if defined(TARGET_OS_MACOS) | 6 #if defined(TARGET_OS_MACOS) |
| 7 | 7 |
| 8 #include "bin/file_system_watcher.h" | 8 #include "bin/file_system_watcher.h" |
| 9 | 9 |
| 10 #include <errno.h> // NOLINT | 10 #include <errno.h> // NOLINT |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 48 uint32_t flags; | 48 uint32_t flags; |
| 49 char path[PATH_MAX]; | 49 char path[PATH_MAX]; |
| 50 } data; | 50 } data; |
| 51 uint8_t bytes[PATH_MAX + 8]; | 51 uint8_t bytes[PATH_MAX + 8]; |
| 52 }; | 52 }; |
| 53 | 53 |
| 54 class FSEventsWatcher { | 54 class FSEventsWatcher { |
| 55 public: | 55 public: |
| 56 class Node { | 56 class Node { |
| 57 public: | 57 public: |
| 58 Node(intptr_t base_path_length, int read_fd, int write_fd, bool recursive) | 58 Node(FSEventsWatcher* watcher, intptr_t base_path_length, int read_fd, |
| 59 : base_path_length_(base_path_length), | 59 int write_fd, bool recursive) |
| 60 read_fd_(read_fd), | 60 : watcher_(watcher), |
| 61 write_fd_(write_fd), | 61 ready_(false), |
|
Søren Gjesse
2014/02/06 13:04:19
Indent
Anders Johnsen
2014/02/06 13:15:22
Done.
| |
| 62 recursive_(recursive), | 62 base_path_length_(base_path_length), |
| 63 ref_(NULL) {} | 63 read_fd_(read_fd), |
| 64 write_fd_(write_fd), | |
| 65 recursive_(recursive), | |
| 66 ref_(NULL) {} | |
| 64 | 67 |
| 65 ~Node() { | 68 ~Node() { |
| 66 close(write_fd_); | 69 close(write_fd_); |
| 67 FSEventStreamInvalidate(ref_); | |
| 68 FSEventStreamRelease(ref_); | |
| 69 } | 70 } |
| 70 | 71 |
| 71 void set_ref(FSEventStreamRef ref) { | 72 void set_ref(FSEventStreamRef ref) { |
| 72 ref_ = ref; | 73 ref_ = ref; |
| 73 } | 74 } |
| 74 | 75 |
| 76 static void StartCallback(CFRunLoopTimerRef timer, void* info) { | |
| 77 Node* node = reinterpret_cast<Node*>(info); | |
| 78 FSEventStreamScheduleWithRunLoop( | |
| 79 node->ref_, | |
| 80 node->watcher_->run_loop_, | |
| 81 kCFRunLoopDefaultMode); | |
| 82 FSEventStreamStart(node->ref_); | |
| 83 FSEventStreamFlushSync(node->ref_); | |
| 84 node->watcher_->monitor_.Enter(); | |
| 85 node->ready_ = true; | |
| 86 node->watcher_->monitor_.Notify(); | |
| 87 node->watcher_->monitor_.Exit(); | |
| 88 } | |
| 89 | |
| 75 void Start() { | 90 void Start() { |
|
Søren Gjesse
2014/02/06 13:04:19
ASSERT(!ready_)
Anders Johnsen
2014/02/06 13:15:22
Done.
| |
| 76 FSEventStreamStart(ref_); | 91 CFRunLoopTimerContext context; |
| 92 memset(&context, 0, sizeof(context)); | |
| 93 context.info = this; | |
| 94 CFRunLoopTimerRef timer = CFRunLoopTimerCreate( | |
| 95 NULL, 0, 0, 0, 0, StartCallback, &context); | |
| 96 CFRunLoopAddTimer(watcher_->run_loop_, timer, kCFRunLoopCommonModes); | |
| 97 watcher_->monitor_.Enter(); | |
| 98 while (!ready_) { | |
| 99 watcher_->monitor_.Wait(Monitor::kNoTimeout); | |
| 100 } | |
| 101 watcher_->monitor_.Exit(); | |
| 102 } | |
| 103 | |
| 104 static void StopCallback(CFRunLoopTimerRef timer, void* info) { | |
| 105 Node* node = reinterpret_cast<Node*>(info); | |
| 106 FSEventStreamStop(node->ref_); | |
| 107 FSEventStreamInvalidate(node->ref_); | |
| 108 FSEventStreamRelease(node->ref_); | |
| 109 node->watcher_->monitor_.Enter(); | |
| 110 node->ready_ = false; | |
| 111 node->watcher_->monitor_.Notify(); | |
| 112 node->watcher_->monitor_.Exit(); | |
| 77 } | 113 } |
| 78 | 114 |
| 79 void Stop() { | 115 void Stop() { |
|
Søren Gjesse
2014/02/06 13:04:19
ASSERT(ready_)
Anders Johnsen
2014/02/06 13:15:22
Done.
| |
| 80 FSEventStreamStop(ref_); | 116 CFRunLoopTimerContext context; |
| 117 memset(&context, 0, sizeof(context)); | |
| 118 context.info = this; | |
| 119 CFRunLoopTimerRef timer = CFRunLoopTimerCreate( | |
| 120 NULL, 0, 0, 0, 0, StopCallback, &context); | |
| 121 CFRunLoopAddTimer(watcher_->run_loop_, timer, kCFRunLoopCommonModes); | |
| 122 watcher_->monitor_.Enter(); | |
| 123 while (ready_) { | |
| 124 watcher_->monitor_.Wait(Monitor::kNoTimeout); | |
| 125 } | |
| 126 watcher_->monitor_.Exit(); | |
| 81 } | 127 } |
| 82 | 128 |
| 129 bool ready() const { return ready_; } | |
| 83 intptr_t base_path_length() const { return base_path_length_; } | 130 intptr_t base_path_length() const { return base_path_length_; } |
| 84 int read_fd() const { return read_fd_; } | 131 int read_fd() const { return read_fd_; } |
| 85 int write_fd() const { return write_fd_; } | 132 int write_fd() const { return write_fd_; } |
| 86 bool recursive() const { return recursive_; } | 133 bool recursive() const { return recursive_; } |
| 87 | 134 |
| 88 private: | 135 private: |
| 136 FSEventsWatcher* watcher_; | |
| 137 bool ready_; | |
| 89 intptr_t base_path_length_; | 138 intptr_t base_path_length_; |
| 90 int read_fd_; | 139 int read_fd_; |
| 91 int write_fd_; | 140 int write_fd_; |
| 92 bool recursive_; | 141 bool recursive_; |
| 93 FSEventStreamRef ref_; | 142 FSEventStreamRef ref_; |
| 94 }; | 143 }; |
| 95 | 144 |
| 96 FSEventsWatcher() : run_loop_(0) { | 145 FSEventsWatcher() : run_loop_(0) { |
| 97 Thread::Start(Run, reinterpret_cast<uword>(this)); | 146 Thread::Start(Run, reinterpret_cast<uword>(this)); |
| 98 } | 147 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 int fds[2]; | 185 int fds[2]; |
| 137 VOID_TEMP_FAILURE_RETRY(pipe(fds)); | 186 VOID_TEMP_FAILURE_RETRY(pipe(fds)); |
| 138 Socket::SetNonBlocking(fds[0]); | 187 Socket::SetNonBlocking(fds[0]); |
| 139 Socket::SetBlocking(fds[1]); | 188 Socket::SetBlocking(fds[1]); |
| 140 | 189 |
| 141 char base_path[PATH_MAX]; | 190 char base_path[PATH_MAX]; |
| 142 realpath(path, base_path); | 191 realpath(path, base_path); |
| 143 CFStringRef path_ref = CFStringCreateWithCString( | 192 CFStringRef path_ref = CFStringCreateWithCString( |
| 144 NULL, base_path, kCFStringEncodingUTF8); | 193 NULL, base_path, kCFStringEncodingUTF8); |
| 145 | 194 |
| 146 Node* node = new Node(strlen(base_path), fds[0], fds[1], recursive); | 195 Node* node = new Node(this, strlen(base_path), fds[0], fds[1], recursive); |
| 147 | 196 |
| 148 FSEventStreamContext context; | 197 FSEventStreamContext context; |
| 149 context.version = 0; | 198 context.version = 0; |
| 150 context.info = reinterpret_cast<void*>(node); | 199 context.info = reinterpret_cast<void*>(node); |
| 151 context.retain = NULL; | 200 context.retain = NULL; |
| 152 context.release = NULL; | 201 context.release = NULL; |
| 153 context.copyDescription = NULL; | 202 context.copyDescription = NULL; |
| 154 FSEventStreamRef ref = FSEventStreamCreate( | 203 FSEventStreamRef ref = FSEventStreamCreate( |
| 155 NULL, | 204 NULL, |
| 156 Callback, | 205 Callback, |
| 157 &context, | 206 &context, |
| 158 CFArrayCreate(NULL, reinterpret_cast<const void**>(&path_ref), 1, NULL), | 207 CFArrayCreate(NULL, reinterpret_cast<const void**>(&path_ref), 1, NULL), |
| 159 kFSEventStreamEventIdSinceNow, | 208 kFSEventStreamEventIdSinceNow, |
| 160 0.10, | 209 0.10, |
| 161 kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents); | 210 kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents); |
| 162 | 211 |
| 163 node->set_ref(ref); | 212 node->set_ref(ref); |
| 164 | 213 |
| 165 FSEventStreamScheduleWithRunLoop( | |
| 166 ref, | |
| 167 run_loop_, | |
| 168 kCFRunLoopDefaultMode); | |
| 169 | |
| 170 return node; | 214 return node; |
| 171 } | 215 } |
| 172 | 216 |
| 173 private: | 217 private: |
| 174 static void Callback(ConstFSEventStreamRef ref, | 218 static void Callback(ConstFSEventStreamRef ref, |
| 175 void* client, | 219 void* client, |
| 176 size_t num_events, | 220 size_t num_events, |
| 177 void* event_paths, | 221 void* event_paths, |
| 178 const FSEventStreamEventFlags event_flags[], | 222 const FSEventStreamEventFlags event_flags[], |
| 179 const FSEventStreamEventId event_ids[]) { | 223 const FSEventStreamEventId event_ids[]) { |
| 180 Node* node = reinterpret_cast<Node*>(client); | 224 Node* node = reinterpret_cast<Node*>(client); |
|
Søren Gjesse
2014/02/06 13:04:19
Need to protect access to ready with the monitor.
Anders Johnsen
2014/02/06 13:15:22
As discussed offline, is on same thread as run-loo
| |
| 225 if (!node->ready()) return; | |
| 181 for (size_t i = 0; i < num_events; i++) { | 226 for (size_t i = 0; i < num_events; i++) { |
| 182 char *path = reinterpret_cast<char**>(event_paths)[i]; | 227 char *path = reinterpret_cast<char**>(event_paths)[i]; |
| 183 FSEvent event; | 228 FSEvent event; |
| 184 event.data.exists = File::GetType(path, false) != File::kDoesNotExist; | 229 event.data.exists = File::GetType(path, false) != File::kDoesNotExist; |
| 185 path += node->base_path_length(); | 230 path += node->base_path_length(); |
| 186 // If path is longer the base, skip next character ('/'). | 231 // If path is longer the base, skip next character ('/'). |
| 187 if (path[0] != '\0') path += 1; | 232 if (path[0] != '\0') path += 1; |
| 188 if (!node->recursive() && strstr(path, "/") != NULL) continue; | 233 if (!node->recursive() && strstr(path, "/") != NULL) continue; |
| 189 event.data.flags = event_flags[i]; | 234 event.data.flags = event_flags[i]; |
| 190 memmove(event.data.path, path, strlen(path) + 1); | 235 memmove(event.data.path, path, strlen(path) + 1); |
| 191 write(node->write_fd(), event.bytes, sizeof(event)); | 236 write(node->write_fd(), event.bytes, sizeof(event)); |
| 192 } | 237 } |
| 193 } | 238 } |
| 194 | 239 |
| 195 Monitor monitor_; | 240 Monitor monitor_; |
| 196 CFRunLoopRef run_loop_; | 241 CFRunLoopRef run_loop_; |
| 197 }; | 242 }; |
| 198 | 243 |
| 199 | 244 |
| 200 #define kCFCoreFoundationVersionNumber10_7 635.00 | 245 #define kCFCoreFoundationVersionNumber10_7 635.00 |
| 201 bool FileSystemWatcher::IsSupported() { | 246 bool FileSystemWatcher::IsSupported() { |
| 202 return kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_7; | 247 return kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_7; |
| 203 } | 248 } |
| 204 | 249 |
| 205 | 250 |
| 206 intptr_t FileSystemWatcher::Init() { | 251 intptr_t FileSystemWatcher::Init() { |
| 207 FSEventsWatcher* watcher = new FSEventsWatcher(); | 252 FSEventsWatcher* watcher = new FSEventsWatcher(); |
| 208 watcher->monitor().Enter(); | 253 watcher->monitor().Enter(); |
| 209 while (!watcher->has_run_loop()) { | 254 while (!watcher->has_run_loop()) { |
| 210 watcher->monitor().Wait(1); | 255 watcher->monitor().Wait(Monitor::kNoTimeout); |
| 211 } | 256 } |
| 212 watcher->monitor().Exit(); | 257 watcher->monitor().Exit(); |
| 213 return reinterpret_cast<intptr_t>(watcher); | 258 return reinterpret_cast<intptr_t>(watcher); |
| 214 } | 259 } |
| 215 | 260 |
| 216 | 261 |
| 217 void FileSystemWatcher::Close(intptr_t id) { | 262 void FileSystemWatcher::Close(intptr_t id) { |
| 218 FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(id); | 263 FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(id); |
| 219 delete watcher; | 264 delete watcher; |
| 220 } | 265 } |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 291 } | 336 } |
| 292 return events; | 337 return events; |
| 293 } | 338 } |
| 294 | 339 |
| 295 } // namespace bin | 340 } // namespace bin |
| 296 } // namespace dart | 341 } // namespace dart |
| 297 | 342 |
| 298 #endif // defined(TARGET_OS_MACOS) | 343 #endif // defined(TARGET_OS_MACOS) |
| 299 | 344 |
| 300 | 345 |
| OLD | NEW |