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

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

Issue 19263003: Add FileSystemWatcher class to dart:io. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix android socket. Created 7 years, 3 months 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "platform/globals.h"
6 #if defined(TARGET_OS_MACOS)
7
8 #include "bin/file_system_watcher.h"
9
10 #include <errno.h> // NOLINT
11 #include <fcntl.h> // NOLINT
12 #include <unistd.h> // NOLINT
13 #include <CoreServices/CoreServices.h> // NOLINT
14
15 #include "bin/eventhandler.h"
16 #include "bin/fdutils.h"
17 #include "bin/socket.h"
18 #include "bin/thread.h"
19
20
21 namespace dart {
22 namespace bin {
23
24 static Mutex* watcher_mutex = new Mutex();
25 static Monitor* watcher_monitor = new Monitor();
26
27 class FSEventsWatcher;
28 static FSEventsWatcher* watcher = NULL;
29
30 union FSEvent {
31 struct {
32 uint32_t flags;
33 char path[PATH_MAX];
34 } data;
35 uint8_t bytes[PATH_MAX + 4];
36 };
37
38 class FSEventsWatcher {
39 public:
40 class Node {
41 public:
42 Node(intptr_t base_path_length, int read_fd, int write_fd, bool recursive)
43 : base_path_length_(base_path_length),
44 read_fd_(read_fd),
45 write_fd_(write_fd),
46 recursive_(recursive),
47 ref_(NULL) {}
48
49 ~Node() {
50 close(write_fd_);
51 FSEventStreamInvalidate(ref_);
52 FSEventStreamRelease(ref_);
53 }
54
55 void set_ref(FSEventStreamRef ref) {
56 ref_ = ref;
57 }
58
59 void Start() {
60 FSEventStreamStart(ref_);
61 }
62
63 void Stop() {
64 FSEventStreamStop(ref_);
65 }
66
67 intptr_t base_path_length() const { return base_path_length_; }
68 int read_fd() const { return read_fd_; }
69 int write_fd() const { return write_fd_; }
70 bool recursive() const { return recursive_; }
71
72 private:
73 intptr_t base_path_length_;
74 int read_fd_;
75 int write_fd_;
76 bool recursive_;
77 FSEventStreamRef ref_;
78 };
79
80 FSEventsWatcher() : run_loop_(0), users_(0) {
81 Thread::Start(Run, reinterpret_cast<uword>(this));
82 }
83
84 ~FSEventsWatcher() {
85 CFRunLoopStop(run_loop_);
86 }
87
88 static void TimerCallback(CFRunLoopTimerRef timer, void* context) {
89 // Dummy callback to keep RunLoop alive.
90 }
91
92 static void Run(uword arg) {
93 FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(arg);
94 watcher->run_loop_ = CFRunLoopGetCurrent();
95
96 // Notify, as the run-loop is set.
97 watcher_monitor->Notify();
98
99 CFRunLoopTimerRef timer = CFRunLoopTimerCreate(
100 NULL,
101 CFAbsoluteTimeGetCurrent() + 1,
102 1,
103 0,
104 0,
105 TimerCallback,
106 NULL);
107
108 CFRunLoopAddTimer(watcher->run_loop_, timer, kCFRunLoopCommonModes);
109
110 CFRunLoopRun();
111 }
112
113 static void Increment() {
114 if (watcher == NULL) {
115 watcher = new FSEventsWatcher();
116 watcher_monitor->Enter();
117 watcher_monitor->Wait(Monitor::kNoTimeout);
118 watcher_monitor->Exit();
119 }
120 watcher->users_++;
121 }
122
123 static void Decrement() {
124 ASSERT(watcher->users_ > 0);
125 watcher->users_--;
126 if (watcher->users_ == 0) {
127 delete watcher;
128 watcher = NULL;
129 }
130 }
131
132 Node* AddPath(const char* path, int events, bool recursive) {
133 int fds[2];
134 VOID_TEMP_FAILURE_RETRY(pipe(fds));
135 Socket::SetNonBlocking(fds[0]);
136 Socket::SetBlocking(fds[1]);
137
138 char base_path[PATH_MAX];
139 realpath(path, base_path);
140 CFStringRef path_ref = CFStringCreateWithCString(
141 NULL, base_path, kCFStringEncodingUTF8);
142
143 Node* node = new Node(strlen(base_path), fds[0], fds[1], recursive);
144
145 FSEventStreamContext context;
146 context.version = 0;
147 context.info = reinterpret_cast<void*>(node);
148 context.retain = NULL;
149 context.release = NULL;
150 context.copyDescription = NULL;
151 FSEventStreamRef ref = FSEventStreamCreate(
152 NULL,
153 Callback,
154 &context,
155 CFArrayCreate(NULL, reinterpret_cast<const void**>(&path_ref), 1, NULL),
156 kFSEventStreamEventIdSinceNow,
157 0.10,
158 kFSEventStreamCreateFlagFileEvents);
159
160 node->set_ref(ref);
161
162 FSEventStreamScheduleWithRunLoop(
163 ref,
164 run_loop_,
165 kCFRunLoopDefaultMode);
166
167 return node;
168 }
169
170 private:
171 static void Callback(ConstFSEventStreamRef ref,
172 void* client,
173 size_t num_events,
174 void* event_paths,
175 const FSEventStreamEventFlags event_flags[],
176 const FSEventStreamEventId event_ids[]) {
177 Node* node = reinterpret_cast<Node*>(client);
178 for (size_t i = 0; i < num_events; i++) {
179 char *path = reinterpret_cast<char**>(event_paths)[i];
180 path += node->base_path_length() + 1;
181 if (!node->recursive() && strstr(path, "/") != NULL) continue;
182 FSEvent event;
183 event.data.flags = event_flags[i];
184 memmove(event.data.path, path, strlen(path) + 1);
185 write(node->write_fd(), event.bytes, sizeof(event));
186 }
187 }
188
189 CFRunLoopRef run_loop_;
190 int users_;
191 };
192
193
194 intptr_t FileSystemWatcher::WatchPath(const char* path,
195 int events,
196 bool recursive) {
197 MutexLocker lock(watcher_mutex);
198 FSEventsWatcher::Increment();
199
200 FSEventsWatcher::Node* node = watcher->AddPath(path, events, recursive);
201 node->Start();
202 return reinterpret_cast<intptr_t>(node);
203 }
204
205
206 void FileSystemWatcher::UnwatchPath(intptr_t id) {
207 MutexLocker lock(watcher_mutex);
208
209 FSEventsWatcher::Node* node = reinterpret_cast<FSEventsWatcher::Node*>(id);
210 node->Stop();
211 delete node;
212
213 FSEventsWatcher::Decrement();
214 }
215
216
217 intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
218 return reinterpret_cast<FSEventsWatcher::Node*>(id)->read_fd();
219 }
220
221
222 Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
223 intptr_t fd = GetSocketId(id);
224 intptr_t avail = FDUtils::AvailableBytes(fd);
225 int count = avail / sizeof(FSEvent);
226 if (count <= 0) return Dart_NewList(0);
227 Dart_Handle events = Dart_NewList(count);
228 FSEvent e;
229 for (int i = 0; i < count; i++) {
230 intptr_t bytes = TEMP_FAILURE_RETRY(read(fd, e.bytes, sizeof(e)));
231 if (bytes < 0) {
232 return DartUtils::NewDartOSError();
233 }
234 Dart_Handle event = Dart_NewList(3);
235 int flags = e.data.flags;
236 int mask = 0;
237 if (flags & kFSEventStreamEventFlagItemModified) mask |= kModifyContent;
238 if (flags & kFSEventStreamEventFlagItemRenamed) mask |= kMove;
239 if (flags & kFSEventStreamEventFlagItemXattrMod) mask |= kModefyAttribute;
240 if (flags & kFSEventStreamEventFlagItemCreated) mask |= kCreate;
241 if (flags & kFSEventStreamEventFlagItemRemoved) mask |= kDelete;
242 Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
243 Dart_ListSetAt(event, 1, Dart_NewInteger(1));
244 Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
245 reinterpret_cast<uint8_t*>(e.data.path), strlen(e.data.path)));
246 Dart_ListSetAt(events, i, event);
247 }
248 return events;
249 }
250
251 } // namespace bin
252 } // namespace dart
253
254 #endif // defined(TARGET_OS_MACOS)
255
256
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