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

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: Simplify watching by removing FileSystemWatcher and adding FileSystemEntity.watch. 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
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(FSEventStreamRef ref, int fds[2])
43 : ref_(ref) {
44 fds_[0] = fds[0];
45 fds_[1] = fds[1];
46 }
47 ~Node() {
48 close(fds_[1]);
49 FSEventStreamInvalidate(ref_);
50 FSEventStreamRelease(ref_);
51 }
52
53 void Start() {
54 FSEventStreamStart(ref_);
55 }
56
57 void Stop() {
58 FSEventStreamStop(ref_);
59 }
60
61 int read_fd() const { return fds_[0]; }
62
63 private:
64 FSEventStreamRef ref_;
65 int fds_[2];
66 };
67
68 FSEventsWatcher() : run_loop_(0), users_(0) {
69 Thread::Start(Run, reinterpret_cast<uword>(this));
70 }
71
72 static void TimerCallback(CFRunLoopTimerRef timer, void* context) {
73 // Dummy callback to keep RunLoop alive.
74 }
75
76 static void Run(uword arg) {
77 FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(arg);
78 watcher->run_loop_ = CFRunLoopGetCurrent();
79
80 // Notify, as the run-loop is set.
81 watcher_monitor->Notify();
82
83 CFRunLoopTimerRef timer = CFRunLoopTimerCreate(
84 NULL,
85 CFAbsoluteTimeGetCurrent() + 1,
86 1,
87 0,
88 0,
89 TimerCallback,
90 NULL);
91
92 CFRunLoopAddTimer(watcher->run_loop_, timer, kCFRunLoopCommonModes);
93
94 CFRunLoopRun();
95 }
96
97 void Increment() {
98 users_++;
99 }
100
101 void Decrement() {
102 ASSERT(users_ > 0);
103 users_--;
104 if (users_ == 0) {
105 CFRunLoopStop(run_loop_);
106 watcher = NULL;
107 delete this;
108 }
109 }
110
111 Node* AddPath(const char* path, int events) {
112 int fds[2];
113 VOID_TEMP_FAILURE_RETRY(pipe(fds));
114 Socket::SetNonBlocking(fds[0]);
115 Socket::SetBlocking(fds[1]);
116
117 CFStringRef path_ref = CFStringCreateWithCString(
118 NULL, path, kCFStringEncodingUTF8);
119
120 FSEventStreamContext context;
121 context.version = 0;
122 context.info = reinterpret_cast<void*>(fds[1]);
123 context.retain = NULL;
124 context.release = NULL;
125 context.copyDescription = NULL;
126 FSEventStreamRef ref = FSEventStreamCreate(
127 NULL,
128 Callback,
129 &context,
130 CFArrayCreate(NULL, reinterpret_cast<const void**>(&path_ref), 1, NULL),
131 kFSEventStreamEventIdSinceNow,
132 0.10,
133 kFSEventStreamCreateFlagFileEvents);
134
135
136 FSEventStreamScheduleWithRunLoop(
137 ref,
138 run_loop_,
139 kCFRunLoopDefaultMode);
140
141 return new Node(ref, fds);
142 }
143
144 private:
145 static void Callback(ConstFSEventStreamRef ref,
146 void* client,
147 size_t num_events,
148 void* event_paths,
149 const FSEventStreamEventFlags event_flags[],
150 const FSEventStreamEventId event_ids[]) {
151 int fd = reinterpret_cast<int>(client);
152 for (size_t i = 0; i < num_events; i++) {
153 char *path = reinterpret_cast<char**>(event_paths)[i];
154 FSEvent event;
155 event.data.flags = event_flags[i];
156 memmove(event.data.path, path, strlen(path) + 1);
157 write(fd, event.bytes, sizeof(event));
158 }
159 }
160
161 CFRunLoopRef run_loop_;
162 int users_;
163 };
164
165 intptr_t FileSystemWatcher::Init() {
166 MutexLocker lock(watcher_mutex);
167 if (watcher == NULL) {
168 watcher = new FSEventsWatcher();
169 watcher_monitor->Enter();
170 watcher_monitor->Wait(Monitor::kNoTimeout);
171 watcher_monitor->Exit();
172 }
173 watcher->Increment();
174 return 0;
175 }
176
177
178 void FileSystemWatcher::Stop(intptr_t id) {
179 MutexLocker lock(watcher_mutex);
180 watcher->Decrement();
181 }
182
183
184 intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
185 if (path_id == -1) return -1;
186 FSEventsWatcher::Node* node =
187 reinterpret_cast<FSEventsWatcher::Node*>(path_id);
188 return node->read_fd();
189 }
190
191
192 intptr_t FileSystemWatcher::AddPath(intptr_t id, const char* path, int events) {
193 FSEventsWatcher::Node* node = watcher->AddPath(path, events);
194 node->Start();
195 return reinterpret_cast<intptr_t>(node);
196 }
197
198
199 bool FileSystemWatcher::RemovePath(intptr_t id, intptr_t path_id) {
200 FSEventsWatcher::Node* node =
201 reinterpret_cast<FSEventsWatcher::Node*>(path_id);
202 node->Stop();
203 delete node;
204 return true;
205 }
206
207
208 intptr_t FileSystemWatcher::ReadEvents(intptr_t id,
Søren Gjesse 2013/08/26 07:51:55 Again this should just be the _NativeSocket. If th
Anders Johnsen 2013/09/03 11:36:23 Done.
209 intptr_t path_id,
210 Event** events) {
211 intptr_t fd = GetSocketId(id, path_id);
212 intptr_t avail = FDUtils::AvailableBytes(fd);
213 int count = avail / sizeof(FSEvent);
214 if (count <= 0) return 0;
215 *events = new Event[count];
216 FSEvent e;
217 for (int i = 0; i < count; i++) {
218 intptr_t bytes = TEMP_FAILURE_RETRY(read(fd, e.bytes, sizeof(e)));
219 if (bytes < 0) return -1;
220 Event* event = *events + i;
221 event->event = 0;
222 event->path_id = id;
223 event->link = 1;
224 int flags = e.data.flags;
225 if (flags & kFSEventStreamEventFlagItemModified) {
226 event->event |= kModifyContent;
227 }
228 if (flags & kFSEventStreamEventFlagItemRenamed) event->event |= kMove;
229 if (flags & kFSEventStreamEventFlagItemXattrMod) {
230 event->event |= kModefyAttribute;
231 }
232 if (flags & kFSEventStreamEventFlagItemCreated) event->event |= kCreate;
233 if (flags & kFSEventStreamEventFlagItemRemoved) event->event |= kDelete;
234 event->filename = strdup(e.data.path);
235 }
236 return count;
237 }
238
239 } // namespace bin
240 } // namespace dart
241
242 #endif // defined(TARGET_OS_MACOS)
243
244
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698