Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: runtime/bin/file_system_watcher_macos.cc

Issue 98773002: Rewrite file-system-watcher to better handle the different system APIs. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Android impl and doc fix. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/file_system_watcher_linux.cc ('k') | runtime/bin/file_system_watcher_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/bin/file_system_watcher_linux.cc ('k') | runtime/bin/file_system_watcher_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698