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 24 matching lines...) Expand all Loading... |
35 kFSEventStreamEventFlagItemIsFile = 0x00010000, | 35 kFSEventStreamEventFlagItemIsFile = 0x00010000, |
36 kFSEventStreamEventFlagItemIsDir = 0x00020000, | 36 kFSEventStreamEventFlagItemIsDir = 0x00020000, |
37 kFSEventStreamEventFlagItemIsSymlink = 0x00040000 | 37 kFSEventStreamEventFlagItemIsSymlink = 0x00040000 |
38 }; | 38 }; |
39 #endif | 39 #endif |
40 | 40 |
41 | 41 |
42 namespace dart { | 42 namespace dart { |
43 namespace bin { | 43 namespace bin { |
44 | 44 |
45 static Mutex* watcher_mutex = new Mutex(); | |
46 static Monitor* watcher_monitor = new Monitor(); | |
47 | |
48 class FSEventsWatcher; | |
49 static FSEventsWatcher* watcher = NULL; | |
50 | |
51 union FSEvent { | 45 union FSEvent { |
52 struct { | 46 struct { |
53 uint32_t exists; | 47 uint32_t exists; |
54 uint32_t flags; | 48 uint32_t flags; |
55 char path[PATH_MAX]; | 49 char path[PATH_MAX]; |
56 } data; | 50 } data; |
57 uint8_t bytes[PATH_MAX + 8]; | 51 uint8_t bytes[PATH_MAX + 8]; |
58 }; | 52 }; |
59 | 53 |
60 class FSEventsWatcher { | 54 class FSEventsWatcher { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 bool recursive() const { return recursive_; } | 86 bool recursive() const { return recursive_; } |
93 | 87 |
94 private: | 88 private: |
95 intptr_t base_path_length_; | 89 intptr_t base_path_length_; |
96 int read_fd_; | 90 int read_fd_; |
97 int write_fd_; | 91 int write_fd_; |
98 bool recursive_; | 92 bool recursive_; |
99 FSEventStreamRef ref_; | 93 FSEventStreamRef ref_; |
100 }; | 94 }; |
101 | 95 |
102 FSEventsWatcher() : run_loop_(0), users_(0) { | 96 FSEventsWatcher() : run_loop_(0) { |
103 Thread::Start(Run, reinterpret_cast<uword>(this)); | 97 Thread::Start(Run, reinterpret_cast<uword>(this)); |
104 } | 98 } |
105 | 99 |
106 ~FSEventsWatcher() { | 100 ~FSEventsWatcher() { |
107 CFRunLoopStop(run_loop_); | 101 CFRunLoopStop(run_loop_); |
108 } | 102 } |
109 | 103 |
| 104 Monitor& monitor() { return monitor_; } |
| 105 |
| 106 bool has_run_loop() const { return run_loop_ != NULL; } |
| 107 |
110 static void TimerCallback(CFRunLoopTimerRef timer, void* context) { | 108 static void TimerCallback(CFRunLoopTimerRef timer, void* context) { |
111 // Dummy callback to keep RunLoop alive. | 109 // Dummy callback to keep RunLoop alive. |
112 } | 110 } |
113 | 111 |
114 static void Run(uword arg) { | 112 static void Run(uword arg) { |
115 FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(arg); | 113 FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(arg); |
116 watcher->run_loop_ = CFRunLoopGetCurrent(); | 114 watcher->run_loop_ = CFRunLoopGetCurrent(); |
117 | 115 |
118 // Notify, as the run-loop is set. | 116 // Notify, as the run-loop is set. |
119 watcher_monitor->Enter(); | 117 watcher->monitor().Enter(); |
120 watcher_monitor->Notify(); | 118 watcher->monitor().Notify(); |
121 watcher_monitor->Exit(); | 119 watcher->monitor().Exit(); |
122 | 120 |
123 CFRunLoopTimerRef timer = CFRunLoopTimerCreate( | 121 CFRunLoopTimerRef timer = CFRunLoopTimerCreate( |
124 NULL, | 122 NULL, |
125 CFAbsoluteTimeGetCurrent() + 1, | 123 CFAbsoluteTimeGetCurrent() + 1, |
126 1, | 124 1, |
127 0, | 125 0, |
128 0, | 126 0, |
129 TimerCallback, | 127 TimerCallback, |
130 NULL); | 128 NULL); |
131 | 129 |
132 CFRunLoopAddTimer(watcher->run_loop_, timer, kCFRunLoopCommonModes); | 130 CFRunLoopAddTimer(watcher->run_loop_, timer, kCFRunLoopCommonModes); |
133 | 131 |
134 CFRunLoopRun(); | 132 CFRunLoopRun(); |
135 } | 133 } |
136 | 134 |
137 static void Increment() { | |
138 if (watcher == NULL) { | |
139 watcher_monitor->Enter(); | |
140 watcher = new FSEventsWatcher(); | |
141 while (watcher->run_loop_ == NULL) { | |
142 watcher_monitor->Wait(Monitor::kNoTimeout); | |
143 } | |
144 watcher_monitor->Exit(); | |
145 } | |
146 watcher->users_++; | |
147 } | |
148 | |
149 static void Decrement() { | |
150 ASSERT(watcher->users_ > 0); | |
151 watcher->users_--; | |
152 if (watcher->users_ == 0) { | |
153 delete watcher; | |
154 watcher = NULL; | |
155 } | |
156 } | |
157 | |
158 Node* AddPath(const char* path, int events, bool recursive) { | 135 Node* AddPath(const char* path, int events, bool recursive) { |
159 int fds[2]; | 136 int fds[2]; |
160 VOID_TEMP_FAILURE_RETRY(pipe(fds)); | 137 VOID_TEMP_FAILURE_RETRY(pipe(fds)); |
161 Socket::SetNonBlocking(fds[0]); | 138 Socket::SetNonBlocking(fds[0]); |
162 Socket::SetBlocking(fds[1]); | 139 Socket::SetBlocking(fds[1]); |
163 | 140 |
164 char base_path[PATH_MAX]; | 141 char base_path[PATH_MAX]; |
165 realpath(path, base_path); | 142 realpath(path, base_path); |
166 CFStringRef path_ref = CFStringCreateWithCString( | 143 CFStringRef path_ref = CFStringCreateWithCString( |
167 NULL, base_path, kCFStringEncodingUTF8); | 144 NULL, base_path, kCFStringEncodingUTF8); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 path += node->base_path_length(); | 185 path += node->base_path_length(); |
209 // If path is longer the base, skip next character ('/'). | 186 // If path is longer the base, skip next character ('/'). |
210 if (path[0] != '\0') path += 1; | 187 if (path[0] != '\0') path += 1; |
211 if (!node->recursive() && strstr(path, "/") != NULL) continue; | 188 if (!node->recursive() && strstr(path, "/") != NULL) continue; |
212 event.data.flags = event_flags[i]; | 189 event.data.flags = event_flags[i]; |
213 memmove(event.data.path, path, strlen(path) + 1); | 190 memmove(event.data.path, path, strlen(path) + 1); |
214 write(node->write_fd(), event.bytes, sizeof(event)); | 191 write(node->write_fd(), event.bytes, sizeof(event)); |
215 } | 192 } |
216 } | 193 } |
217 | 194 |
| 195 Monitor monitor_; |
218 CFRunLoopRef run_loop_; | 196 CFRunLoopRef run_loop_; |
219 int users_; | |
220 }; | 197 }; |
221 | 198 |
222 | 199 |
223 #define kCFCoreFoundationVersionNumber10_7 635.00 | 200 #define kCFCoreFoundationVersionNumber10_7 635.00 |
224 bool FileSystemWatcher::IsSupported() { | 201 bool FileSystemWatcher::IsSupported() { |
225 return kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_7; | 202 return kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_7; |
226 } | 203 } |
227 | 204 |
228 | 205 |
229 intptr_t FileSystemWatcher::WatchPath(const char* path, | 206 intptr_t FileSystemWatcher::Init() { |
| 207 FSEventsWatcher* watcher = new FSEventsWatcher(); |
| 208 watcher->monitor().Enter(); |
| 209 while (!watcher->has_run_loop()) { |
| 210 watcher->monitor().Wait(1); |
| 211 } |
| 212 watcher->monitor().Exit(); |
| 213 return reinterpret_cast<intptr_t>(watcher); |
| 214 } |
| 215 |
| 216 |
| 217 void FileSystemWatcher::Close(intptr_t id) { |
| 218 FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(id); |
| 219 delete watcher; |
| 220 } |
| 221 |
| 222 |
| 223 intptr_t FileSystemWatcher::WatchPath(intptr_t id, |
| 224 const char* path, |
230 int events, | 225 int events, |
231 bool recursive) { | 226 bool recursive) { |
232 MutexLocker lock(watcher_mutex); | 227 FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(id); |
233 FSEventsWatcher::Increment(); | |
234 | |
235 FSEventsWatcher::Node* node = watcher->AddPath(path, events, recursive); | 228 FSEventsWatcher::Node* node = watcher->AddPath(path, events, recursive); |
236 node->Start(); | 229 node->Start(); |
237 return reinterpret_cast<intptr_t>(node); | 230 return reinterpret_cast<intptr_t>(node); |
238 } | 231 } |
239 | 232 |
240 | 233 |
241 void FileSystemWatcher::UnwatchPath(intptr_t id) { | 234 void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) { |
242 MutexLocker lock(watcher_mutex); | 235 USE(id); |
243 | 236 FSEventsWatcher::Node* node = |
244 FSEventsWatcher::Node* node = reinterpret_cast<FSEventsWatcher::Node*>(id); | 237 reinterpret_cast<FSEventsWatcher::Node*>(path_id); |
245 node->Stop(); | 238 node->Stop(); |
246 delete node; | 239 delete node; |
247 | |
248 FSEventsWatcher::Decrement(); | |
249 } | 240 } |
250 | 241 |
251 | 242 |
252 intptr_t FileSystemWatcher::GetSocketId(intptr_t id) { | 243 intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) { |
253 return reinterpret_cast<FSEventsWatcher::Node*>(id)->read_fd(); | 244 return reinterpret_cast<FSEventsWatcher::Node*>(path_id)->read_fd(); |
254 } | 245 } |
255 | 246 |
256 | 247 |
257 Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) { | 248 Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) { |
258 intptr_t fd = GetSocketId(id); | 249 intptr_t fd = GetSocketId(id, path_id); |
259 intptr_t avail = FDUtils::AvailableBytes(fd); | 250 intptr_t avail = FDUtils::AvailableBytes(fd); |
260 int count = avail / sizeof(FSEvent); | 251 int count = avail / sizeof(FSEvent); |
261 if (count <= 0) return Dart_NewList(0); | 252 if (count <= 0) return Dart_NewList(0); |
262 Dart_Handle events = Dart_NewList(count); | 253 Dart_Handle events = Dart_NewList(count); |
263 FSEvent e; | 254 FSEvent e; |
264 for (int i = 0; i < count; i++) { | 255 for (int i = 0; i < count; i++) { |
265 intptr_t bytes = TEMP_FAILURE_RETRY(read(fd, e.bytes, sizeof(e))); | 256 intptr_t bytes = TEMP_FAILURE_RETRY(read(fd, e.bytes, sizeof(e))); |
266 if (bytes < 0) { | 257 if (bytes < 0) { |
267 return DartUtils::NewDartOSError(); | 258 return DartUtils::NewDartOSError(); |
268 } | 259 } |
269 size_t path_len = strlen(e.data.path); | 260 size_t path_len = strlen(e.data.path); |
270 Dart_Handle event = Dart_NewList(4); | 261 Dart_Handle event = Dart_NewList(5); |
271 int flags = e.data.flags; | 262 int flags = e.data.flags; |
272 int mask = 0; | 263 int mask = 0; |
273 if (flags & kFSEventStreamEventFlagItemRenamed) { | 264 if (flags & kFSEventStreamEventFlagItemRenamed) { |
274 if (path_len == 0) { | 265 if (path_len == 0) { |
275 // The moved path is the path being watched. | 266 // The moved path is the path being watched. |
276 mask |= kDeleteSelf; | 267 mask |= kDeleteSelf; |
277 } else { | 268 } else { |
278 mask |= e.data.exists ? kCreate : kDelete; | 269 mask |= e.data.exists ? kCreate : kDelete; |
279 } | 270 } |
280 } | 271 } |
281 if (flags & kFSEventStreamEventFlagItemModified) mask |= kModifyContent; | 272 if (flags & kFSEventStreamEventFlagItemModified) mask |= kModifyContent; |
282 if (flags & kFSEventStreamEventFlagItemXattrMod) mask |= kModefyAttribute; | 273 if (flags & kFSEventStreamEventFlagItemXattrMod) mask |= kModefyAttribute; |
283 if (flags & kFSEventStreamEventFlagItemCreated) mask |= kCreate; | 274 if (flags & kFSEventStreamEventFlagItemCreated) mask |= kCreate; |
284 if (flags & kFSEventStreamEventFlagItemIsDir) mask |= kIsDir; | 275 if (flags & kFSEventStreamEventFlagItemIsDir) mask |= kIsDir; |
285 if (flags & kFSEventStreamEventFlagItemRemoved) { | 276 if (flags & kFSEventStreamEventFlagItemRemoved) { |
286 if (path_len == 0) { | 277 if (path_len == 0) { |
287 // The removed path is the path being watched. | 278 // The removed path is the path being watched. |
288 mask |= kDeleteSelf; | 279 mask |= kDeleteSelf; |
289 } else { | 280 } else { |
290 mask |= kDelete; | 281 mask |= kDelete; |
291 } | 282 } |
292 } | 283 } |
293 Dart_ListSetAt(event, 0, Dart_NewInteger(mask)); | 284 Dart_ListSetAt(event, 0, Dart_NewInteger(mask)); |
294 Dart_ListSetAt(event, 1, Dart_NewInteger(1)); | 285 Dart_ListSetAt(event, 1, Dart_NewInteger(1)); |
295 Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8( | 286 Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8( |
296 reinterpret_cast<uint8_t*>(e.data.path), path_len)); | 287 reinterpret_cast<uint8_t*>(e.data.path), path_len)); |
297 Dart_ListSetAt(event, 3, Dart_NewBoolean(true)); | 288 Dart_ListSetAt(event, 3, Dart_NewBoolean(true)); |
| 289 Dart_ListSetAt(event, 4, Dart_NewInteger(path_id)); |
298 Dart_ListSetAt(events, i, event); | 290 Dart_ListSetAt(events, i, event); |
299 } | 291 } |
300 return events; | 292 return events; |
301 } | 293 } |
302 | 294 |
303 } // namespace bin | 295 } // namespace bin |
304 } // namespace dart | 296 } // namespace dart |
305 | 297 |
306 #endif // defined(TARGET_OS_MACOS) | 298 #endif // defined(TARGET_OS_MACOS) |
307 | 299 |
308 | 300 |
OLD | NEW |