| 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 |