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

Side by Side Diff: base/files/file_path_watcher_kqueue.cc

Issue 2353103002: Use FileDescriptorWatcher in FilePathWatcherKQueue. (Closed)
Patch Set: fix windows build error Created 4 years, 2 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/files/file_path_watcher_kqueue.h" 5 #include "base/files/file_path_watcher_kqueue.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <sys/param.h> 9 #include <sys/param.h>
10 10
(...skipping 18 matching lines...) Expand all
29 FilePathWatcherKQueue::~FilePathWatcherKQueue() {} 29 FilePathWatcherKQueue::~FilePathWatcherKQueue() {}
30 30
31 void FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) { 31 void FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) {
32 CloseFileDescriptor(&event.ident); 32 CloseFileDescriptor(&event.ident);
33 EventData* entry = EventDataForKevent(event); 33 EventData* entry = EventDataForKevent(event);
34 delete entry; 34 delete entry;
35 event.udata = NULL; 35 event.udata = NULL;
36 } 36 }
37 37
38 int FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) { 38 int FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) {
39 DCHECK(MessageLoopForIO::current());
40 // Make sure that we are working with a clean slate. 39 // Make sure that we are working with a clean slate.
41 DCHECK(events->empty()); 40 DCHECK(events->empty());
42 41
43 std::vector<FilePath::StringType> components; 42 std::vector<FilePath::StringType> components;
44 path.GetComponents(&components); 43 path.GetComponents(&components);
45 44
46 if (components.size() < 1) { 45 if (components.size() < 1) {
47 return -1; 46 return -1;
48 } 47 }
49 48
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 *target_file_affected = true; 222 *target_file_affected = true;
224 } 223 }
225 } else { 224 } else {
226 break; 225 break;
227 } 226 }
228 } 227 }
229 } 228 }
230 return true; 229 return true;
231 } 230 }
232 231
233 void FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) { 232 void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() {
234 DCHECK(MessageLoopForIO::current()); 233 CancelOnMessageLoopThread();
235 DCHECK_EQ(fd, kqueue_); 234 }
235
236 bool FilePathWatcherKQueue::Watch(const FilePath& path,
237 bool recursive,
238 const FilePathWatcher::Callback& callback) {
239 DCHECK(target_.value().empty()); // Can only watch one path.
240 DCHECK(!callback.is_null());
241 DCHECK_EQ(kqueue_, -1);
242 // Recursive watch is not supported using kqueue.
243 DCHECK(!recursive);
244
245 callback_ = callback;
246 target_ = path;
247
248 MessageLoop::current()->AddDestructionObserver(this);
249 set_task_runner(ThreadTaskRunnerHandle::Get());
250
251 kqueue_ = kqueue();
252 if (kqueue_ == -1) {
253 DPLOG(ERROR) << "kqueue";
254 return false;
255 }
256
257 int last_entry = EventsForPath(target_, &events_);
258 DCHECK_NE(last_entry, 0);
259
260 EventVector responses(last_entry);
261
262 int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry,
263 &responses[0], last_entry, NULL));
264 if (!AreKeventValuesValid(&responses[0], count)) {
265 // Calling Cancel() here to close any file descriptors that were opened.
266 // This would happen in the destructor anyways, but FilePathWatchers tend to
267 // be long lived, and if an error has occurred, there is no reason to waste
268 // the file descriptors.
269 Cancel();
270 return false;
271 }
272
273 // This creates an ownership cycle (|this| owns |kqueue_watch_controller_|
274 // which owns a callback which owns |this|). The cycle is broken when
275 // |kqueue_watch_controller_| is reset in CancelOnMessageLoopThread().
276 kqueue_watch_controller_ = FileDescriptorWatcher::WatchReadable(
277 kqueue_, Bind(&FilePathWatcherKQueue::OnKQueueReadable, this));
278 return true;
279 }
280
281 void FilePathWatcherKQueue::Cancel() {
282 if (!task_runner()) {
283 set_cancelled();
284 return;
285 }
286 if (!task_runner()->BelongsToCurrentThread()) {
287 task_runner()->PostTask(FROM_HERE,
288 base::Bind(&FilePathWatcherKQueue::Cancel, this));
289 return;
290 }
291 CancelOnMessageLoopThread();
292 }
293
294 void FilePathWatcherKQueue::OnKQueueReadable() {
295 DCHECK(task_runner()->BelongsToCurrentThread());
236 DCHECK(events_.size()); 296 DCHECK(events_.size());
237 297
238 // Request the file system update notifications that have occurred and return 298 // Request the file system update notifications that have occurred and return
239 // them in |updates|. |count| will contain the number of updates that have 299 // them in |updates|. |count| will contain the number of updates that have
240 // occurred. 300 // occurred.
241 EventVector updates(events_.size()); 301 EventVector updates(events_.size());
242 struct timespec timeout = {0, 0}; 302 struct timespec timeout = {0, 0};
243 int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), 303 int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(),
244 &timeout)); 304 &timeout));
245 305
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 callback_.Run(target_, true /* error */); 356 callback_.Run(target_, true /* error */);
297 Cancel(); 357 Cancel();
298 } 358 }
299 } 359 }
300 360
301 if (send_notification) { 361 if (send_notification) {
302 callback_.Run(target_, false); 362 callback_.Run(target_, false);
303 } 363 }
304 } 364 }
305 365
306 void FilePathWatcherKQueue::OnFileCanWriteWithoutBlocking(int fd) {
307 NOTREACHED();
308 }
309
310 void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() {
311 CancelOnMessageLoopThread();
312 }
313
314 bool FilePathWatcherKQueue::Watch(const FilePath& path,
315 bool recursive,
316 const FilePathWatcher::Callback& callback) {
317 DCHECK(MessageLoopForIO::current());
318 DCHECK(target_.value().empty()); // Can only watch one path.
319 DCHECK(!callback.is_null());
320 DCHECK_EQ(kqueue_, -1);
321
322 if (recursive) {
323 // Recursive watch is not supported using kqueue.
324 NOTIMPLEMENTED();
325 return false;
326 }
327
328 callback_ = callback;
329 target_ = path;
330
331 MessageLoop::current()->AddDestructionObserver(this);
332 io_task_runner_ = ThreadTaskRunnerHandle::Get();
333
334 kqueue_ = kqueue();
335 if (kqueue_ == -1) {
336 DPLOG(ERROR) << "kqueue";
337 return false;
338 }
339
340 int last_entry = EventsForPath(target_, &events_);
341 DCHECK_NE(last_entry, 0);
342
343 EventVector responses(last_entry);
344
345 int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry,
346 &responses[0], last_entry, NULL));
347 if (!AreKeventValuesValid(&responses[0], count)) {
348 // Calling Cancel() here to close any file descriptors that were opened.
349 // This would happen in the destructor anyways, but FilePathWatchers tend to
350 // be long lived, and if an error has occurred, there is no reason to waste
351 // the file descriptors.
352 Cancel();
353 return false;
354 }
355
356 return MessageLoopForIO::current()->WatchFileDescriptor(
357 kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this);
358 }
359
360 void FilePathWatcherKQueue::Cancel() {
361 SingleThreadTaskRunner* task_runner = io_task_runner_.get();
362 if (!task_runner) {
363 set_cancelled();
364 return;
365 }
366 if (!task_runner->BelongsToCurrentThread()) {
367 task_runner->PostTask(FROM_HERE,
368 base::Bind(&FilePathWatcherKQueue::Cancel, this));
369 return;
370 }
371 CancelOnMessageLoopThread();
372 }
373
374 void FilePathWatcherKQueue::CancelOnMessageLoopThread() { 366 void FilePathWatcherKQueue::CancelOnMessageLoopThread() {
375 DCHECK(MessageLoopForIO::current()); 367 DCHECK(!task_runner() || task_runner()->BelongsToCurrentThread());
376 if (!is_cancelled()) { 368 if (!is_cancelled()) {
377 set_cancelled(); 369 set_cancelled();
378 kqueue_watcher_.StopWatchingFileDescriptor(); 370 kqueue_watch_controller_.reset();
379 if (IGNORE_EINTR(close(kqueue_)) != 0) { 371 if (IGNORE_EINTR(close(kqueue_)) != 0) {
380 DPLOG(ERROR) << "close kqueue"; 372 DPLOG(ERROR) << "close kqueue";
381 } 373 }
382 kqueue_ = -1; 374 kqueue_ = -1;
383 std::for_each(events_.begin(), events_.end(), ReleaseEvent); 375 std::for_each(events_.begin(), events_.end(), ReleaseEvent);
384 events_.clear(); 376 events_.clear();
385 io_task_runner_ = NULL;
386 MessageLoop::current()->RemoveDestructionObserver(this); 377 MessageLoop::current()->RemoveDestructionObserver(this);
387 callback_.Reset(); 378 callback_.Reset();
388 } 379 }
389 } 380 }
390 381
391 } // namespace base 382 } // namespace base
OLDNEW
« no previous file with comments | « base/files/file_path_watcher_kqueue.h ('k') | components/policy/core/common/configuration_policy_provider_test.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698