<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/directory_watcher.h"

#include <errno.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <unistd.h>

#include <algorithm>
#include <set>
#include <utility>
#include <vector>

#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/hash_tables.h"
#include "base/lock.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
#include "base/task.h"
#include "base/thread.h"
#include "base/waitable_event.h"

namespace {

class DirectoryWatcherImpl;

// Singleton to manage all inotify watches.
class InotifyReader {
 public:
  typedef int Watch;  // Watch descriptor used by AddWatch and RemoveWatch.
  static const Watch kInvalidWatch = -1;

  // Watch |path| for changes. |watcher| will be notified on each change.
  // Returns kInvalidWatch on failure.
  Watch AddWatch(const FilePath& path, DirectoryWatcherImpl* watcher);

  // Remove |watch|. Returns true on success.
  bool RemoveWatch(Watch watch, DirectoryWatcherImpl* watcher);

  // Callback for InotifyReaderTask.
  void OnInotifyEvent(const inotify_event* event);

 private:
  friend struct DefaultSingletonTraits<InotifyReader>;

  typedef std::set<DirectoryWatcherImpl*> WatcherSet;

  InotifyReader();
  ~InotifyReader();

  // We keep track of which delegates want to be notified on which watches.
  base::hash_map<Watch, WatcherSet> watchers_;

  // For each watch we also want to know the path it's watching.
  base::hash_map<Watch, FilePath> paths_;

  // Lock to protect delegates_ and paths_.
  Lock lock_;

  // Separate thread on which we run blocking read for inotify events.
  base::Thread thread_;

  // File descriptor returned by inotify_init.
  const int inotify_fd_;

  // Use self-pipe trick to unblock select during shutdown.
  int shutdown_pipe_[2];

  // Flag set to true when startup was successful.
  bool valid_;

  DISALLOW_COPY_AND_ASSIGN(InotifyReader);
};

class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate {
 public:
  typedef std::set<FilePath> FilePathSet;

  DirectoryWatcherImpl();
  ~DirectoryWatcherImpl();

  void EnsureSetupFinished();

  // Called for each event coming from one of watches.
  void OnInotifyEvent(const inotify_event* event);

  // Callback for RegisterSubtreeWatchesTask.
  bool OnEnumeratedSubtree(const FilePathSet& paths);

  // Start watching |path| for changes and notify |delegate| on each change.
  // If |recursive| is true, watch entire subtree.
  // Returns true if watch for |path| has been added successfully. Watches
  // required for |recursive| are added on a background thread and have no
  // effect on the return value.
  virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate,
                     MessageLoop* backend_loop, bool recursive);

 private:
  typedef std::set<InotifyReader::Watch> WatchSet;
  typedef std::set<ino_t> InodeSet;

  // Returns true if |inode| is watched by DirectoryWatcherImpl.
  bool IsInodeWatched(ino_t inode) const;

  // Delegate to notify upon changes.
  DirectoryWatcher::Delegate* delegate_;

  // Path we're watching (passed to delegate).
  FilePath root_path_;

  // Watch returned by InotifyReader.
  InotifyReader::Watch watch_;

  // Set of watched inodes.
  InodeSet inodes_watched_;

  // Keep track of registered watches.
  WatchSet watches_;

  // Lock to protect inodes_watched_ and watches_.
  Lock lock_;

  // Flag set to true when recursively watching subtree.
  bool recursive_;

  // Loop where we post directory change notifications to.
  MessageLoop* loop_;

  // Event signaled when the background task finished adding initial inotify
  // watches for recursive watch.
  base::WaitableEvent recursive_setup_finished_;

  DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImpl);
};

class RegisterSubtreeWatchesTask : public Task {
 public:
  RegisterSubtreeWatchesTask(DirectoryWatcherImpl* watcher,
                             const FilePath& path)
      : watcher_(watcher),
        path_(path) {
  }

  virtual void Run() {
    file_util::FileEnumerator dir_list(path_, true,
        file_util::FileEnumerator::DIRECTORIES);

    DirectoryWatcherImpl::FilePathSet subtree;
    for (FilePath subdirectory = dir_list.Next();
         !subdirectory.empty();
         subdirectory = dir_list.Next()) {
      subtree.insert(subdirectory);
    }
    watcher_->OnEnumeratedSubtree(subtree);
  }

 private:
  DirectoryWatcherImpl* watcher_;
  FilePath path_;

  DISALLOW_COPY_AND_ASSIGN(RegisterSubtreeWatchesTask);
};

class DirectoryWatcherImplNotifyTask : public Task {
 public:
  DirectoryWatcherImplNotifyTask(DirectoryWatcher::Delegate* delegate,
                                 const FilePath& path)
      : delegate_(delegate),
        path_(path) {
  }

  virtual void Run() {
    delegate_->OnDirectoryChanged(path_);
  }

 private:
  DirectoryWatcher::Delegate* delegate_;
  FilePath path_;

  DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImplNotifyTask);
};

class InotifyReaderTask : public Task {
 public:
  InotifyReaderTask(InotifyReader* reader, int inotify_fd, int shutdown_fd)
      : reader_(reader),
        inotify_fd_(inotify_fd),
        shutdown_fd_(shutdown_fd) {
  }

  virtual void Run() {
    while (true) {
      fd_set rfds;
      FD_ZERO(&rfds);
      FD_SET(inotify_fd_, &rfds);
      FD_SET(shutdown_fd_, &rfds);

      // Wait until some inotify events are available.
      int select_result =
        HANDLE_EINTR(select(std::max(inotify_fd_, shutdown_fd_) + 1,
                            &rfds, NULL, NULL, NULL));
      if (select_result < 0) {
        DLOG(WARNING) << "select failed: " << strerror(errno);
        return;
      }

      if (FD_ISSET(shutdown_fd_, &rfds))
        return;

      // Adjust buffer size to current event queue size.
      int buffer_size;
      int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd_, FIONREAD,
                                            &buffer_size));

      if (ioctl_result != 0) {
        DLOG(WARNING) << "ioctl failed: " << strerror(errno);
        return;
      }

      std::vector<char> buffer(buffer_size);

      ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd_, &buffer[0],
                                             buffer_size));

      if (bytes_read < 0) {
        DLOG(WARNING) << "read from inotify fd failed: " << strerror(errno);
        return;
      }

      ssize_t i = 0;
      while (i < bytes_read) {
        inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
        size_t event_size = sizeof(inotify_event) + event->len;
        DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
        reader_->OnInotifyEvent(event);
        i += event_size;
      }
    }
  }

 private:
  InotifyReader* reader_;
  int inotify_fd_;
  int shutdown_fd_;

  DISALLOW_COPY_AND_ASSIGN(InotifyReaderTask);
};

InotifyReader::InotifyReader()
    : thread_("inotify_reader"),
      inotify_fd_(inotify_init()),
      valid_(false) {
  shutdown_pipe_[0] = -1;
  shutdown_pipe_[1] = -1;
  if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
    thread_.message_loop()->PostTask(
        FROM_HERE, new InotifyReaderTask(this, inotify_fd_, shutdown_pipe_[0]));
    valid_ = true;
  }
}

InotifyReader::~InotifyReader() {
  if (valid_) {
    // Write to the self-pipe so that the select call in InotifyReaderTask
    // returns.
    HANDLE_EINTR(write(shutdown_pipe_[1], "", 1));
    thread_.Stop();
  }
  if (inotify_fd_ >= 0)
    close(inotify_fd_);
  if (shutdown_pipe_[0] >= 0)
    close(shutdown_pipe_[0]);
  if (shutdown_pipe_[1] >= 0)
    close(shutdown_pipe_[1]);
}

InotifyReader::Watch InotifyReader::AddWatch(
    const FilePath& path, DirectoryWatcherImpl* watcher) {

  if (!valid_)
    return kInvalidWatch;

  AutoLock auto_lock(lock_);

  Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
                                  IN_CREATE | IN_DELETE |
                                  IN_CLOSE_WRITE | IN_MOVE);

  if (watch == kInvalidWatch)
    return kInvalidWatch;

  if (paths_[watch].empty())
    paths_[watch] = path;  // We don't yet watch this path.

  watchers_[watch].insert(watcher);

  return watch;
}

bool InotifyReader::RemoveWatch(Watch watch,
                                DirectoryWatcherImpl* watcher) {
  if (!valid_)
    return false;

  AutoLock auto_lock(lock_);

  if (paths_[watch].empty())
    return false;  // We don't recognize this watch.

  watchers_[watch].erase(watcher);

  if (watchers_[watch].empty()) {
    paths_.erase(watch);
    watchers_.erase(watch);
    return (inotify_rm_watch(inotify_fd_, watch) == 0);
  }

  return true;
}

void InotifyReader::OnInotifyEvent(const inotify_event* event) {
  if (event->mask & IN_IGNORED)
    return;

  WatcherSet watchers_to_notify;
  FilePath changed_path;

  {
    AutoLock auto_lock(lock_);
    changed_path = paths_[event->wd];
    watchers_to_notify.insert(watchers_[event->wd].begin(),
                              watchers_[event->wd].end());
  }

  for (WatcherSet::iterator watcher = watchers_to_notify.begin();
       watcher != watchers_to_notify.end();
       ++watcher) {
    (*watcher)->OnInotifyEvent(event);
  }
}

DirectoryWatcherImpl::DirectoryWatcherImpl()
    : watch_(InotifyReader::kInvalidWatch),
      recursive_setup_finished_(false, false) {
}

DirectoryWatcherImpl::~DirectoryWatcherImpl() {
  if (watch_ == InotifyReader::kInvalidWatch)
    return;

  if (recursive_)
    recursive_setup_finished_.Wait();
  for (WatchSet::iterator watch = watches_.begin();
       watch != watches_.end();
       ++watch) {
    Singleton<InotifyReader>::get()->RemoveWatch(*watch, this);
  }
  watches_.clear();
  inodes_watched_.clear();
}

void DirectoryWatcherImpl::OnInotifyEvent(const inotify_event* event) {
  loop_->PostTask(FROM_HERE,
      new DirectoryWatcherImplNotifyTask(delegate_, root_path_));

  if (!(event->mask & IN_ISDIR))
    return;

  if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) {
    // TODO(phajdan.jr): add watch for this new directory.
    NOTIMPLEMENTED();
  } else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) {
    // TODO(phajdan.jr): remove our watch for this directory.
    NOTIMPLEMENTED();
  }
}

bool DirectoryWatcherImpl::IsInodeWatched(ino_t inode) const {
  return inodes_watched_.find(inode) != inodes_watched_.end();
}

bool DirectoryWatcherImpl::OnEnumeratedSubtree(const FilePathSet& subtree) {
  DCHECK(recursive_);

  if (watch_ == InotifyReader::kInvalidWatch) {
    recursive_setup_finished_.Signal();
    return false;
  }

  bool success = true;
  AutoLock auto_lock(lock_);
  for (FilePathSet::iterator subdirectory = subtree.begin();
       subdirectory != subtree.end();
       ++subdirectory) {
    ino_t inode;
    if (!file_util::GetInode(*subdirectory, &inode)) {
      success = false;
      continue;
    }
    if (IsInodeWatched(inode))
      continue;
    InotifyReader::Watch watch =
      Singleton<InotifyReader>::get()->AddWatch(*subdirectory, this);
    if (watch != InotifyReader::kInvalidWatch) {
      watches_.insert(watch);
      inodes_watched_.insert(inode);
    }
  }
  recursive_setup_finished_.Signal();
  return success;
}

bool DirectoryWatcherImpl::Watch(const FilePath& path,
                                 DirectoryWatcher::Delegate* delegate,
                                 MessageLoop* backend_loop, bool recursive) {

  // Can only watch one path.
  DCHECK(watch_ == InotifyReader::kInvalidWatch);

  ino_t inode;
  if (!file_util::GetInode(path, &inode))
    return false;

  InotifyReader::Watch watch =
      Singleton<InotifyReader>::get()->AddWatch(path, this);
  if (watch == InotifyReader::kInvalidWatch)
    return false;

  delegate_ = delegate;
  recursive_ = recursive;
  root_path_ = path;
  watch_ = watch;
  loop_ = MessageLoop::current();

  {
    AutoLock auto_lock(lock_);
    inodes_watched_.insert(inode);
    watches_.insert(watch_);
  }

  if (recursive_) {
    Task* subtree_task = new RegisterSubtreeWatchesTask(this, root_path_);
    if (backend_loop) {
      backend_loop->PostTask(FROM_HERE, subtree_task);
    } else {
      subtree_task->Run();
      delete subtree_task;
    }
  }

  return true;
}

}  // namespace

DirectoryWatcher::DirectoryWatcher() {
  impl_ = new DirectoryWatcherImpl();
}

<commit_msg>Fix a race condition in directory_watcher_inotify.cc: release lock before signaling the event dtor waits on.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/directory_watcher.h"

#include <errno.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <unistd.h>

#include <algorithm>
#include <set>
#include <utility>
#include <vector>

#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/hash_tables.h"
#include "base/lock.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "base/singleton.h"
#include "base/task.h"
#include "base/thread.h"
#include "base/waitable_event.h"

namespace {

class DirectoryWatcherImpl;

// Singleton to manage all inotify watches.
class InotifyReader {
 public:
  typedef int Watch;  // Watch descriptor used by AddWatch and RemoveWatch.
  static const Watch kInvalidWatch = -1;

  // Watch |path| for changes. |watcher| will be notified on each change.
  // Returns kInvalidWatch on failure.
  Watch AddWatch(const FilePath& path, DirectoryWatcherImpl* watcher);

  // Remove |watch|. Returns true on success.
  bool RemoveWatch(Watch watch, DirectoryWatcherImpl* watcher);

  // Callback for InotifyReaderTask.
  void OnInotifyEvent(const inotify_event* event);

 private:
  friend struct DefaultSingletonTraits<InotifyReader>;

  typedef std::set<DirectoryWatcherImpl*> WatcherSet;

  InotifyReader();
  ~InotifyReader();

  // We keep track of which delegates want to be notified on which watches.
  base::hash_map<Watch, WatcherSet> watchers_;

  // For each watch we also want to know the path it's watching.
  base::hash_map<Watch, FilePath> paths_;

  // Lock to protect delegates_ and paths_.
  Lock lock_;

  // Separate thread on which we run blocking read for inotify events.
  base::Thread thread_;

  // File descriptor returned by inotify_init.
  const int inotify_fd_;

  // Use self-pipe trick to unblock select during shutdown.
  int shutdown_pipe_[2];

  // Flag set to true when startup was successful.
  bool valid_;

  DISALLOW_COPY_AND_ASSIGN(InotifyReader);
};

class DirectoryWatcherImpl : public DirectoryWatcher::PlatformDelegate {
 public:
  typedef std::set<FilePath> FilePathSet;

  DirectoryWatcherImpl();
  ~DirectoryWatcherImpl();

  void EnsureSetupFinished();

  // Called for each event coming from one of watches.
  void OnInotifyEvent(const inotify_event* event);

  // Callback for RegisterSubtreeWatchesTask.
  bool OnEnumeratedSubtree(const FilePathSet& paths);

  // Start watching |path| for changes and notify |delegate| on each change.
  // If |recursive| is true, watch entire subtree.
  // Returns true if watch for |path| has been added successfully. Watches
  // required for |recursive| are added on a background thread and have no
  // effect on the return value.
  virtual bool Watch(const FilePath& path, DirectoryWatcher::Delegate* delegate,
                     MessageLoop* backend_loop, bool recursive);

 private:
  typedef std::set<InotifyReader::Watch> WatchSet;
  typedef std::set<ino_t> InodeSet;

  // Returns true if |inode| is watched by DirectoryWatcherImpl.
  bool IsInodeWatched(ino_t inode) const;

  // Delegate to notify upon changes.
  DirectoryWatcher::Delegate* delegate_;

  // Path we're watching (passed to delegate).
  FilePath root_path_;

  // Watch returned by InotifyReader.
  InotifyReader::Watch watch_;

  // Set of watched inodes.
  InodeSet inodes_watched_;

  // Keep track of registered watches.
  WatchSet watches_;

  // Lock to protect inodes_watched_ and watches_.
  Lock lock_;

  // Flag set to true when recursively watching subtree.
  bool recursive_;

  // Loop where we post directory change notifications to.
  MessageLoop* loop_;

  // Event signaled when the background task finished adding initial inotify
  // watches for recursive watch.
  base::WaitableEvent recursive_setup_finished_;

  DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImpl);
};

class RegisterSubtreeWatchesTask : public Task {
 public:
  RegisterSubtreeWatchesTask(DirectoryWatcherImpl* watcher,
                             const FilePath& path)
      : watcher_(watcher),
        path_(path) {
  }

  virtual void Run() {
    file_util::FileEnumerator dir_list(path_, true,
        file_util::FileEnumerator::DIRECTORIES);

    DirectoryWatcherImpl::FilePathSet subtree;
    for (FilePath subdirectory = dir_list.Next();
         !subdirectory.empty();
         subdirectory = dir_list.Next()) {
      subtree.insert(subdirectory);
    }
    watcher_->OnEnumeratedSubtree(subtree);
  }

 private:
  DirectoryWatcherImpl* watcher_;
  FilePath path_;

  DISALLOW_COPY_AND_ASSIGN(RegisterSubtreeWatchesTask);
};

class DirectoryWatcherImplNotifyTask : public Task {
 public:
  DirectoryWatcherImplNotifyTask(DirectoryWatcher::Delegate* delegate,
                                 const FilePath& path)
      : delegate_(delegate),
        path_(path) {
  }

  virtual void Run() {
    delegate_->OnDirectoryChanged(path_);
  }

 private:
  DirectoryWatcher::Delegate* delegate_;
  FilePath path_;

  DISALLOW_COPY_AND_ASSIGN(DirectoryWatcherImplNotifyTask);
};

class InotifyReaderTask : public Task {
 public:
  InotifyReaderTask(InotifyReader* reader, int inotify_fd, int shutdown_fd)
      : reader_(reader),
        inotify_fd_(inotify_fd),
        shutdown_fd_(shutdown_fd) {
  }

  virtual void Run() {
    while (true) {
      fd_set rfds;
      FD_ZERO(&rfds);
      FD_SET(inotify_fd_, &rfds);
      FD_SET(shutdown_fd_, &rfds);

      // Wait until some inotify events are available.
      int select_result =
        HANDLE_EINTR(select(std::max(inotify_fd_, shutdown_fd_) + 1,
                            &rfds, NULL, NULL, NULL));
      if (select_result < 0) {
        DLOG(WARNING) << "select failed: " << strerror(errno);
        return;
      }

      if (FD_ISSET(shutdown_fd_, &rfds))
        return;

      // Adjust buffer size to current event queue size.
      int buffer_size;
      int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd_, FIONREAD,
                                            &buffer_size));

      if (ioctl_result != 0) {
        DLOG(WARNING) << "ioctl failed: " << strerror(errno);
        return;
      }

      std::vector<char> buffer(buffer_size);

      ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd_, &buffer[0],
                                             buffer_size));

      if (bytes_read < 0) {
        DLOG(WARNING) << "read from inotify fd failed: " << strerror(errno);
        return;
      }

      ssize_t i = 0;
      while (i < bytes_read) {
        inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
        size_t event_size = sizeof(inotify_event) + event->len;
        DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
        reader_->OnInotifyEvent(event);
        i += event_size;
      }
    }
  }

 private:
  InotifyReader* reader_;
  int inotify_fd_;
  int shutdown_fd_;

  DISALLOW_COPY_AND_ASSIGN(InotifyReaderTask);
};

InotifyReader::InotifyReader()
    : thread_("inotify_reader"),
      inotify_fd_(inotify_init()),
      valid_(false) {
  shutdown_pipe_[0] = -1;
  shutdown_pipe_[1] = -1;
  if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
    thread_.message_loop()->PostTask(
        FROM_HERE, new InotifyReaderTask(this, inotify_fd_, shutdown_pipe_[0]));
    valid_ = true;
  }
}

InotifyReader::~InotifyReader() {
  if (valid_) {
    // Write to the self-pipe so that the select call in InotifyReaderTask
    // returns.
    HANDLE_EINTR(write(shutdown_pipe_[1], "", 1));
    thread_.Stop();
  }
  if (inotify_fd_ >= 0)
    close(inotify_fd_);
  if (shutdown_pipe_[0] >= 0)
    close(shutdown_pipe_[0]);
  if (shutdown_pipe_[1] >= 0)
    close(shutdown_pipe_[1]);
}

InotifyReader::Watch InotifyReader::AddWatch(
    const FilePath& path, DirectoryWatcherImpl* watcher) {

  if (!valid_)
    return kInvalidWatch;

  AutoLock auto_lock(lock_);

  Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
                                  IN_CREATE | IN_DELETE |
                                  IN_CLOSE_WRITE | IN_MOVE);

  if (watch == kInvalidWatch)
    return kInvalidWatch;

  if (paths_[watch].empty())
    paths_[watch] = path;  // We don't yet watch this path.

  watchers_[watch].insert(watcher);

  return watch;
}

bool InotifyReader::RemoveWatch(Watch watch,
                                DirectoryWatcherImpl* watcher) {
  if (!valid_)
    return false;

  AutoLock auto_lock(lock_);

  if (paths_[watch].empty())
    return false;  // We don't recognize this watch.

  watchers_[watch].erase(watcher);

  if (watchers_[watch].empty()) {
    paths_.erase(watch);
    watchers_.erase(watch);
    return (inotify_rm_watch(inotify_fd_, watch) == 0);
  }

  return true;
}

void InotifyReader::OnInotifyEvent(const inotify_event* event) {
  if (event->mask & IN_IGNORED)
    return;

  WatcherSet watchers_to_notify;
  FilePath changed_path;

  {
    AutoLock auto_lock(lock_);
    changed_path = paths_[event->wd];
    watchers_to_notify.insert(watchers_[event->wd].begin(),
                              watchers_[event->wd].end());
  }

  for (WatcherSet::iterator watcher = watchers_to_notify.begin();
       watcher != watchers_to_notify.end();
       ++watcher) {
    (*watcher)->OnInotifyEvent(event);
  }
}

DirectoryWatcherImpl::DirectoryWatcherImpl()
    : watch_(InotifyReader::kInvalidWatch),
      recursive_setup_finished_(false, false) {
}

DirectoryWatcherImpl::~DirectoryWatcherImpl() {
  if (watch_ == InotifyReader::kInvalidWatch)
    return;

  if (recursive_)
    recursive_setup_finished_.Wait();
  for (WatchSet::iterator watch = watches_.begin();
       watch != watches_.end();
       ++watch) {
    Singleton<InotifyReader>::get()->RemoveWatch(*watch, this);
  }
  watches_.clear();
  inodes_watched_.clear();
}

void DirectoryWatcherImpl::OnInotifyEvent(const inotify_event* event) {
  loop_->PostTask(FROM_HERE,
      new DirectoryWatcherImplNotifyTask(delegate_, root_path_));

  if (!(event->mask & IN_ISDIR))
    return;

  if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) {
    // TODO(phajdan.jr): add watch for this new directory.
    NOTIMPLEMENTED();
  } else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) {
    // TODO(phajdan.jr): remove our watch for this directory.
    NOTIMPLEMENTED();
  }
}

bool DirectoryWatcherImpl::IsInodeWatched(ino_t inode) const {
  return inodes_watched_.find(inode) != inodes_watched_.end();
}

bool DirectoryWatcherImpl::OnEnumeratedSubtree(const FilePathSet& subtree) {
  DCHECK(recursive_);

  if (watch_ == InotifyReader::kInvalidWatch) {
    recursive_setup_finished_.Signal();
    return false;
  }

  bool success = true;

  {
    // Limit the scope of auto_lock so it releases lock_ before we signal
    // recursive_setup_finished_. Our dtor waits on recursive_setup_finished_
    // and could otherwise destroy the lock before we release it.
    AutoLock auto_lock(lock_);

    for (FilePathSet::iterator subdirectory = subtree.begin();
         subdirectory != subtree.end();
         ++subdirectory) {
      ino_t inode;
      if (!file_util::GetInode(*subdirectory, &inode)) {
        success = false;
        continue;
      }
      if (IsInodeWatched(inode))
        continue;
      InotifyReader::Watch watch =
        Singleton<InotifyReader>::get()->AddWatch(*subdirectory, this);
      if (watch != InotifyReader::kInvalidWatch) {
        watches_.insert(watch);
        inodes_watched_.insert(inode);
      }
    }
  }

  recursive_setup_finished_.Signal();
  return success;
}

bool DirectoryWatcherImpl::Watch(const FilePath& path,
                                 DirectoryWatcher::Delegate* delegate,
                                 MessageLoop* backend_loop, bool recursive) {

  // Can only watch one path.
  DCHECK(watch_ == InotifyReader::kInvalidWatch);

  ino_t inode;
  if (!file_util::GetInode(path, &inode))
    return false;

  InotifyReader::Watch watch =
      Singleton<InotifyReader>::get()->AddWatch(path, this);
  if (watch == InotifyReader::kInvalidWatch)
    return false;

  delegate_ = delegate;
  recursive_ = recursive;
  root_path_ = path;
  watch_ = watch;
  loop_ = MessageLoop::current();

  {
    AutoLock auto_lock(lock_);
    inodes_watched_.insert(inode);
    watches_.insert(watch_);
  }

  if (recursive_) {
    Task* subtree_task = new RegisterSubtreeWatchesTask(this, root_path_);
    if (backend_loop) {
      backend_loop->PostTask(FROM_HERE, subtree_task);
    } else {
      subtree_task->Run();
      delete subtree_task;
    }
  }

  return true;
}

}  // namespace

DirectoryWatcher::DirectoryWatcher() {
  impl_ = new DirectoryWatcherImpl();
}

<|endoftext|>


<commit_before>//Copyright (c) 2021 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <stack>

#include "linearAlg2D.h"
#include "logoutput.h"
#include "VoronoiUtils.h"
#include "optional.h"

namespace cura
{

Point VoronoiUtils::p(const vd_t::vertex_type* node)
{
    return Point(node->x() + 0.5d, node->y() + 0.5d); //Round to nearest integer coordinates.
}

bool VoronoiUtils::isSourcePoint(Point p, const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments, coord_t snap_dist)
{
    if (cell.contains_point())
    {
        return shorterThen(p - getSourcePoint(cell, points, segments), snap_dist);
    }
    else
    {
        const Segment& segment = getSourceSegment(cell, points, segments);
        return shorterThen(p - segment.from(), snap_dist) || shorterThen(p - segment.to(), snap_dist);
    }
}

coord_t VoronoiUtils::getDistance(Point p, const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments)
{
    if (cell.contains_point())
    {
        return vSize(p - getSourcePoint(cell, points, segments));
    }
    else
    {
        const Segment& segment = getSourceSegment(cell, points, segments);
        return sqrt(LinearAlg2D::getDist2FromLineSegment(segment.from(), p, segment.to()));
    }
}

Point VoronoiUtils::getSourcePoint(const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments)
{
    assert(cell.contains_point());
    if(!cell.contains_point())
    {
        logWarning("Voronoi cell doesn't contain a source point!");
    }
    switch (cell.source_category())
    {
        case boost::polygon::SOURCE_CATEGORY_SINGLE_POINT:
            return points[cell.source_index()];
            break;
        case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT:
            assert(cell.source_index() - points.size() < segments.size());
            return segments[cell.source_index() - points.size()].to();
            break;
        case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT:
            assert(cell.source_index() - points.size() < segments.size());
            return segments[cell.source_index() - points.size()].from();
            break;
        default:
            assert(false && "getSourcePoint should only be called on point cells!\n");
            break;
    }
    return points[cell.source_index()];
}

PolygonsPointIndex VoronoiUtils::getSourcePointIndex(const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments)
{
    assert(cell.contains_point());
    if(!cell.contains_point())
    {
        logWarning("Voronoi cell doesn't contain a source point!");
    }
    assert(cell.source_category() != boost::polygon::SOURCE_CATEGORY_SINGLE_POINT);
    switch (cell.source_category())
    {
        case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT:
        {
            assert(cell.source_index() - points.size() < segments.size());
            PolygonsPointIndex ret = segments[cell.source_index() - points.size()];
            ++ret;
            return ret;
            break;
        }
        case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT:
        {
            assert(cell.source_index() - points.size() < segments.size());
            return segments[cell.source_index() - points.size()];
            break;
        }
        default:
            assert(false && "getSourcePoint should only be called on point cells!\n");
            break;
    }
    PolygonsPointIndex ret = segments[cell.source_index() - points.size()];
    return ++ret;
}

const VoronoiUtils::Segment& VoronoiUtils::getSourceSegment(const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments)
{
    assert(cell.contains_segment());
    if(!cell.contains_segment())
    {
        logWarning("Voronoi cell doesn't contain a source segment!");
    }
    return segments[cell.source_index() - points.size()];
}

std::vector<Point> VoronoiUtils::discretizeParabola(const Point& p, const Segment& segment, Point s, Point e, coord_t approximate_step_size, float transitioning_angle)
{
    std::vector<Point> discretized;
    // x is distance of point projected on the segment ab
    // xx is point projected on the segment ab
    const Point a = segment.from();
    const Point b = segment.to();
    const Point ab = b - a;
    const Point as = s - a;
    const Point ae = e - a;
    const coord_t ab_size = vSize(ab);
    const coord_t sx = dot(as, ab) / ab_size;
    const coord_t ex = dot(ae, ab) / ab_size;
    const coord_t sxex = ex - sx;

    const Point ap = p - a;
    const coord_t px = dot(ap, ab) / ab_size;

    const Point pxx = LinearAlg2D::getClosestOnLine(p, a, b);
    const Point ppxx = pxx - p;
    const coord_t d = vSize(ppxx);
    const PointMatrix rot = PointMatrix(turn90CCW(ppxx));

    if (d == 0)
    {
        discretized.emplace_back(s);
        discretized.emplace_back(e);
        return discretized;
    }

    const float marking_bound = atan(transitioning_angle * 0.5);
    coord_t msx = - marking_bound * d; // projected marking_start
    coord_t mex = marking_bound * d; // projected marking_end
    const coord_t marking_start_end_h = msx * msx / (2 * d) + d / 2;
    Point marking_start = rot.unapply(Point(msx, marking_start_end_h)) + pxx;
    Point marking_end = rot.unapply(Point(mex, marking_start_end_h)) + pxx;
    const int dir = (sx > ex) ? -1 : 1;
    if (dir < 0)
    {
        std::swap(marking_start, marking_end);
        std::swap(msx, mex);
    }

    bool add_marking_start = msx * dir > (sx - px) * dir && msx * dir < (ex - px) * dir;
    bool add_marking_end = mex * dir > (sx - px) * dir && mex * dir < (ex - px) * dir;

    const Point apex = rot.unapply(Point(0, d / 2)) + pxx;
    bool add_apex = (sx - px) * dir < 0 && (ex - px) * dir > 0;

    assert(!(add_marking_start && add_marking_end) || add_apex);
    if(add_marking_start && add_marking_end && !add_apex)
    {
        logWarning("Failing to discretize parabola! Must add an apex or one of the endpoints.");
    }

    const coord_t step_count = static_cast<coord_t>(static_cast<float>(std::abs(ex - sx)) / approximate_step_size + 0.5);

    discretized.emplace_back(s);
    for (coord_t step = 1; step < step_count; step++)
    {
        const coord_t x = sx + sxex * step / step_count - px;
        const coord_t y = x * x / (2 * d) + d / 2;

        if (add_marking_start && msx * dir < x * dir)
        {
            discretized.emplace_back(marking_start);
            add_marking_start = false;
        }
        if (add_apex && x * dir > 0)
        {
            discretized.emplace_back(apex);
            add_apex = false; // only add the apex just before the
        }
        if (add_marking_end && mex * dir < x * dir)
        {
            discretized.emplace_back(marking_end);
            add_marking_end = false;
        }
        const Point result = rot.unapply(Point(x, y)) + pxx;
        discretized.emplace_back(result);
    }
    if (add_apex)
    {
        discretized.emplace_back(apex);
    }
    if (add_marking_end)
    {
        discretized.emplace_back(marking_end);
    }
    discretized.emplace_back(e);
    return discretized;
}

/*
The following code has been adjusted from an implementation of Boost. This is the license:

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

// adapted from boost::polygon::voronoi_visual_utils.cpp
void VoronoiUtils::discretize(const Point& point, const Segment& segment, const coord_t max_dist, std::vector<Point>* discretization)
{
    // Apply the linear transformation to move start point of the segment to
    // the point with coordinates (0, 0) and the direction of the segment to
    // coincide the positive direction of the x-axis.
    const Point segm_vec = segment.to() - segment.from();
    const coord_t segment_length2 = vSize2(segm_vec);

    // Compute x-coordinates of the endpoints of the edge
    // in the transformed space.
    const coord_t projection_start = segment_length2 * getPointProjection((*discretization)[0], segment);
    const coord_t projection_end = segment_length2 * getPointProjection((*discretization)[1], segment);

    // Compute parabola parameters in the transformed space.
    // Parabola has next representation:
    // f(x) = ((x-rot_x)^2 + rot_y^2) / (2.0*rot_y).
    const Point point_vec = point - segment.from();
    const coord_t rot_x = dot(segm_vec, point_vec);
    const coord_t rot_y = cross(segm_vec, point_vec);

    // Save the last point.
    const Point last_point = (*discretization)[1];
    discretization->pop_back();

    // Use stack to avoid recursion.
    std::stack<coord_t> point_stack;
    point_stack.push(projection_end);
    Point cur(projection_start, parabolaY(projection_start, rot_x, rot_y));

    // Adjust max_dist parameter in the transformed space.
    const coord_t max_dist_transformed = max_dist * max_dist * segment_length2;
    while (!point_stack.empty())
    {
        const Point new_(point_stack.top(), parabolaY(point_stack.top(), rot_x, rot_y));
        const Point new_vec = new_ - cur;

        // Compute coordinates of the point of the parabola that is
        // furthest from the current line segment.
        const coord_t mid_x = new_vec.Y * rot_y / new_vec.X + rot_x;
        const coord_t mid_y = parabolaY(mid_x, rot_x, rot_y);
        Point mid_vec = Point(mid_x, mid_y) - cur;

        // Compute maximum distance between the given parabolic arc
        // and line segment that discretize it.
        coord_t dist = cross(mid_vec, new_vec);
        dist = dist * dist / vSize2(new_vec); // TODO overflows!!!
        if (dist <= max_dist_transformed)
        {
            // Distance between parabola and line segment is less than max_dist.
            point_stack.pop();
            const coord_t inter_x = (segm_vec.X * new_.X - segm_vec.Y * new_.Y) / segment_length2 + segment.from().X;
            const coord_t inter_y = (segm_vec.X * new_.Y + segm_vec.Y * new_.X) / segment_length2 + segment.from().Y;
            discretization->push_back(Point(inter_x, inter_y));
            cur = new_;
        }
        else
        {
            point_stack.push(mid_x);
        }
    }

    // Update last point.
    discretization->back() = last_point;
}

// adapted from boost::polygon::voronoi_visual_utils.cpp
coord_t VoronoiUtils::parabolaY(coord_t x, coord_t a, coord_t b)
{
    return ((x - a) * (x - a) + b * b) / (b + b);
}

// adapted from boost::polygon::voronoi_visual_utils.cpp
double VoronoiUtils::getPointProjection(const Point& point, const Segment& segment)
{
    Point segment_vec = segment.to() - segment.from();
    Point point_vec = point - segment.from();
    coord_t sqr_segment_length = vSize2(segment_vec);
    coord_t vec_dot = dot(segment_vec, point_vec);
    return static_cast<double>(vec_dot) / sqr_segment_length;
}

}//namespace cura
<commit_msg>Fix rounding for negative numbers<commit_after>//Copyright (c) 2021 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <stack>

#include "linearAlg2D.h"
#include "logoutput.h"
#include "VoronoiUtils.h"
#include "optional.h"

namespace cura
{

Point VoronoiUtils::p(const vd_t::vertex_type* node)
{
    const double x = node->x();
    const double y = node->y();
    return Point(x + 0.5d - (x < 0), y + 0.5d - (y < 0)); //Round to nearest integer coordinates.
}

bool VoronoiUtils::isSourcePoint(Point p, const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments, coord_t snap_dist)
{
    if (cell.contains_point())
    {
        return shorterThen(p - getSourcePoint(cell, points, segments), snap_dist);
    }
    else
    {
        const Segment& segment = getSourceSegment(cell, points, segments);
        return shorterThen(p - segment.from(), snap_dist) || shorterThen(p - segment.to(), snap_dist);
    }
}

coord_t VoronoiUtils::getDistance(Point p, const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments)
{
    if (cell.contains_point())
    {
        return vSize(p - getSourcePoint(cell, points, segments));
    }
    else
    {
        const Segment& segment = getSourceSegment(cell, points, segments);
        return sqrt(LinearAlg2D::getDist2FromLineSegment(segment.from(), p, segment.to()));
    }
}

Point VoronoiUtils::getSourcePoint(const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments)
{
    assert(cell.contains_point());
    if(!cell.contains_point())
    {
        logWarning("Voronoi cell doesn't contain a source point!");
    }
    switch (cell.source_category())
    {
        case boost::polygon::SOURCE_CATEGORY_SINGLE_POINT:
            return points[cell.source_index()];
            break;
        case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT:
            assert(cell.source_index() - points.size() < segments.size());
            return segments[cell.source_index() - points.size()].to();
            break;
        case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT:
            assert(cell.source_index() - points.size() < segments.size());
            return segments[cell.source_index() - points.size()].from();
            break;
        default:
            assert(false && "getSourcePoint should only be called on point cells!\n");
            break;
    }
    return points[cell.source_index()];
}

PolygonsPointIndex VoronoiUtils::getSourcePointIndex(const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments)
{
    assert(cell.contains_point());
    if(!cell.contains_point())
    {
        logWarning("Voronoi cell doesn't contain a source point!");
    }
    assert(cell.source_category() != boost::polygon::SOURCE_CATEGORY_SINGLE_POINT);
    switch (cell.source_category())
    {
        case boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT:
        {
            assert(cell.source_index() - points.size() < segments.size());
            PolygonsPointIndex ret = segments[cell.source_index() - points.size()];
            ++ret;
            return ret;
            break;
        }
        case boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT:
        {
            assert(cell.source_index() - points.size() < segments.size());
            return segments[cell.source_index() - points.size()];
            break;
        }
        default:
            assert(false && "getSourcePoint should only be called on point cells!\n");
            break;
    }
    PolygonsPointIndex ret = segments[cell.source_index() - points.size()];
    return ++ret;
}

const VoronoiUtils::Segment& VoronoiUtils::getSourceSegment(const vd_t::cell_type& cell, const std::vector<Point>& points, const std::vector<Segment>& segments)
{
    assert(cell.contains_segment());
    if(!cell.contains_segment())
    {
        logWarning("Voronoi cell doesn't contain a source segment!");
    }
    return segments[cell.source_index() - points.size()];
}

std::vector<Point> VoronoiUtils::discretizeParabola(const Point& p, const Segment& segment, Point s, Point e, coord_t approximate_step_size, float transitioning_angle)
{
    std::vector<Point> discretized;
    // x is distance of point projected on the segment ab
    // xx is point projected on the segment ab
    const Point a = segment.from();
    const Point b = segment.to();
    const Point ab = b - a;
    const Point as = s - a;
    const Point ae = e - a;
    const coord_t ab_size = vSize(ab);
    const coord_t sx = dot(as, ab) / ab_size;
    const coord_t ex = dot(ae, ab) / ab_size;
    const coord_t sxex = ex - sx;

    const Point ap = p - a;
    const coord_t px = dot(ap, ab) / ab_size;

    const Point pxx = LinearAlg2D::getClosestOnLine(p, a, b);
    const Point ppxx = pxx - p;
    const coord_t d = vSize(ppxx);
    const PointMatrix rot = PointMatrix(turn90CCW(ppxx));

    if (d == 0)
    {
        discretized.emplace_back(s);
        discretized.emplace_back(e);
        return discretized;
    }

    const float marking_bound = atan(transitioning_angle * 0.5);
    coord_t msx = - marking_bound * d; // projected marking_start
    coord_t mex = marking_bound * d; // projected marking_end
    const coord_t marking_start_end_h = msx * msx / (2 * d) + d / 2;
    Point marking_start = rot.unapply(Point(msx, marking_start_end_h)) + pxx;
    Point marking_end = rot.unapply(Point(mex, marking_start_end_h)) + pxx;
    const int dir = (sx > ex) ? -1 : 1;
    if (dir < 0)
    {
        std::swap(marking_start, marking_end);
        std::swap(msx, mex);
    }

    bool add_marking_start = msx * dir > (sx - px) * dir && msx * dir < (ex - px) * dir;
    bool add_marking_end = mex * dir > (sx - px) * dir && mex * dir < (ex - px) * dir;

    const Point apex = rot.unapply(Point(0, d / 2)) + pxx;
    bool add_apex = (sx - px) * dir < 0 && (ex - px) * dir > 0;

    assert(!(add_marking_start && add_marking_end) || add_apex);
    if(add_marking_start && add_marking_end && !add_apex)
    {
        logWarning("Failing to discretize parabola! Must add an apex or one of the endpoints.");
    }

    const coord_t step_count = static_cast<coord_t>(static_cast<float>(std::abs(ex - sx)) / approximate_step_size + 0.5);

    discretized.emplace_back(s);
    for (coord_t step = 1; step < step_count; step++)
    {
        const coord_t x = sx + sxex * step / step_count - px;
        const coord_t y = x * x / (2 * d) + d / 2;

        if (add_marking_start && msx * dir < x * dir)
        {
            discretized.emplace_back(marking_start);
            add_marking_start = false;
        }
        if (add_apex && x * dir > 0)
        {
            discretized.emplace_back(apex);
            add_apex = false; // only add the apex just before the
        }
        if (add_marking_end && mex * dir < x * dir)
        {
            discretized.emplace_back(marking_end);
            add_marking_end = false;
        }
        const Point result = rot.unapply(Point(x, y)) + pxx;
        discretized.emplace_back(result);
    }
    if (add_apex)
    {
        discretized.emplace_back(apex);
    }
    if (add_marking_end)
    {
        discretized.emplace_back(marking_end);
    }
    discretized.emplace_back(e);
    return discretized;
}

/*
The following code has been adjusted from an implementation of Boost. This is the license:

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

// adapted from boost::polygon::voronoi_visual_utils.cpp
void VoronoiUtils::discretize(const Point& point, const Segment& segment, const coord_t max_dist, std::vector<Point>* discretization)
{
    // Apply the linear transformation to move start point of the segment to
    // the point with coordinates (0, 0) and the direction of the segment to
    // coincide the positive direction of the x-axis.
    const Point segm_vec = segment.to() - segment.from();
    const coord_t segment_length2 = vSize2(segm_vec);

    // Compute x-coordinates of the endpoints of the edge
    // in the transformed space.
    const coord_t projection_start = segment_length2 * getPointProjection((*discretization)[0], segment);
    const coord_t projection_end = segment_length2 * getPointProjection((*discretization)[1], segment);

    // Compute parabola parameters in the transformed space.
    // Parabola has next representation:
    // f(x) = ((x-rot_x)^2 + rot_y^2) / (2.0*rot_y).
    const Point point_vec = point - segment.from();
    const coord_t rot_x = dot(segm_vec, point_vec);
    const coord_t rot_y = cross(segm_vec, point_vec);

    // Save the last point.
    const Point last_point = (*discretization)[1];
    discretization->pop_back();

    // Use stack to avoid recursion.
    std::stack<coord_t> point_stack;
    point_stack.push(projection_end);
    Point cur(projection_start, parabolaY(projection_start, rot_x, rot_y));

    // Adjust max_dist parameter in the transformed space.
    const coord_t max_dist_transformed = max_dist * max_dist * segment_length2;
    while (!point_stack.empty())
    {
        const Point new_(point_stack.top(), parabolaY(point_stack.top(), rot_x, rot_y));
        const Point new_vec = new_ - cur;

        // Compute coordinates of the point of the parabola that is
        // furthest from the current line segment.
        const coord_t mid_x = new_vec.Y * rot_y / new_vec.X + rot_x;
        const coord_t mid_y = parabolaY(mid_x, rot_x, rot_y);
        Point mid_vec = Point(mid_x, mid_y) - cur;

        // Compute maximum distance between the given parabolic arc
        // and line segment that discretize it.
        coord_t dist = cross(mid_vec, new_vec);
        dist = dist * dist / vSize2(new_vec); // TODO overflows!!!
        if (dist <= max_dist_transformed)
        {
            // Distance between parabola and line segment is less than max_dist.
            point_stack.pop();
            const coord_t inter_x = (segm_vec.X * new_.X - segm_vec.Y * new_.Y) / segment_length2 + segment.from().X;
            const coord_t inter_y = (segm_vec.X * new_.Y + segm_vec.Y * new_.X) / segment_length2 + segment.from().Y;
            discretization->push_back(Point(inter_x, inter_y));
            cur = new_;
        }
        else
        {
            point_stack.push(mid_x);
        }
    }

    // Update last point.
    discretization->back() = last_point;
}

// adapted from boost::polygon::voronoi_visual_utils.cpp
coord_t VoronoiUtils::parabolaY(coord_t x, coord_t a, coord_t b)
{
    return ((x - a) * (x - a) + b * b) / (b + b);
}

// adapted from boost::polygon::voronoi_visual_utils.cpp
double VoronoiUtils::getPointProjection(const Point& point, const Segment& segment)
{
    Point segment_vec = segment.to() - segment.from();
    Point point_vec = point - segment.from();
    coord_t sqr_segment_length = vSize2(segment_vec);
    coord_t vec_dot = dot(segment_vec, point_vec);
    return static_cast<double>(vec_dot) / sqr_segment_length;
}

}//namespace cura
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"

#include "DebugOperatorNew.h"

#include "KristalliProtocolModule.h"
#include "KristalliProtocolModuleEvents.h"
#include "Profiler.h"
#include "EventManager.h"
#include "CoreStringUtils.h"

#include "kNet.h"

#include <algorithm>

using namespace kNet;

namespace KristalliProtocol
{

namespace
{
    const std::string moduleName("KristalliProtocol");

/*
    const struct
    {
        SocketTransportLayer transport;
        int portNumber;
    } destinationPorts[] =
    {
        { SocketOverUDP, 2345 }, // The default Kristalli over UDP port.

        { SocketOverTCP, 2345 }, // The default Kristalli over TCP port.
        { SocketOverUDP, 123 }, // Network Time Protocol.

        { SocketOverTCP, 80 }, // HTTP.
        { SocketOverTCP, 443 }, // HTTPS.
        { SocketOverTCP, 20 }, // FTP Data.
        { SocketOverTCP, 21 }, // FTP Control.
        { SocketOverTCP, 22 }, // SSH.
        { SocketOverTCP, 23 }, // TELNET.
        { SocketOverUDP, 25 }, // SMTP. (Microsoft)
        { SocketOverTCP, 25 }, // SMTP.
        { SocketOverTCP, 110 }, // POP3 Server listen port.
        { SocketOverTCP, 995 }, // POP3 over SSL.
        { SocketOverTCP, 109 }, // POP2.
        { SocketOverTCP, 6667 }, // IRC.

        // For more info on the following windows ports, see: http://support.microsoft.com/kb/832017

        { SocketOverTCP, 135 }, // Windows RPC.
        { SocketOverUDP, 137 }, // Windows Cluster Administrator. / NetBIOS Name Resolution.
        { SocketOverUDP, 138 }, // Windows NetBIOS Datagram Service.
        { SocketOverTCP, 139 }, // Windows NetBIOS Session Service.

        { SocketOverUDP, 389 }, // Windows LDAP Server.
        { SocketOverTCP, 389 }, // Windows LDAP Server.

        { SocketOverTCP, 445 }, // Windows SMB.

        { SocketOverTCP, 5722 }, // Windows RPC.

        { SocketOverTCP, 993 }, // IMAP over SSL.

//        { SocketOverTCP, 1433 }, // SQL over TCP.
//        { SocketOverUDP, 1434 }, // SQL over UDP.

        { SocketOverUDP, 53 }, // DNS.
        { SocketOverTCP, 53 }, // DNS. Microsoft states it uses TCP 53 for DNS as well.
        { SocketOverUDP, 161 }, // SNMP agent port.
        { SocketOverUDP, 162 }, // SNMP manager port.
        { SocketOverUDP, 520 }, // RIP.
        { SocketOverUDP, 67 }, // DHCP client->server.
        { SocketOverUDP, 68 }, // DHCP server->client.
    };

    /// The number of different port choices to try from the list.
    const int cNumPortChoices = sizeof(destinationPorts) / sizeof(destinationPorts[0]);
*/
}

static const int cInitialAttempts = 1;
static const int cReconnectAttempts = 5;

KristalliProtocolModule::KristalliProtocolModule()
:IModule(NameStatic())
, serverConnection(0)
, server(0)
, reconnectAttempts(0)
{
}

KristalliProtocolModule::~KristalliProtocolModule()
{
    Disconnect();
}

void KristalliProtocolModule::Load()
{
}

void KristalliProtocolModule::Unload()
{
    Disconnect();
}

void KristalliProtocolModule::PreInitialize()
{
    kNet::SetLogChannels(kNet::LogInfo | kNet::LogError | kNet::LogUser); // Enable all log channels.
}

void KristalliProtocolModule::Initialize()
{
    EventManagerPtr event_manager = framework_->GetEventManager();

    networkEventCategory = event_manager->RegisterEventCategory("Kristalli");
    event_manager->RegisterEvent(networkEventCategory, Events::NETMESSAGE_IN, "NetMessageIn");
}

void KristalliProtocolModule::PostInitialize()
{
}

void KristalliProtocolModule::Uninitialize()
{
    Disconnect();
}

void KristalliProtocolModule::Update(f64 frametime)
{
    // Pulls all new inbound network messages and calls the message handler we've registered
    // for each of them.
    if (serverConnection)
        serverConnection->Process();

    // Note: Calling the above serverConnection->Process() may set serverConnection to null if the connection gets disconnected.
    // Therefore, in the code below, we cannot assume serverConnection is non-null, and must check it again.

    // Our client->server connection is never kept partially open.
    // That is, at the moment the server write-closes the connection, we also write-close the connection.
    // Check here if the server has write-closed, and also write-close our end if so.
    if (serverConnection && !serverConnection->IsReadOpen() && serverConnection->IsWriteOpen())
        serverConnection->Disconnect(0);

    // Process server incoming connections & messages if server up
    if (server)
        server->Process();

    if ((!serverConnection || serverConnection->GetConnectionState() == ConnectionClosed ||
        serverConnection->GetConnectionState() == ConnectionPending) && serverIp.length() != 0)
    {
        const int cReconnectTimeout = 5 * 1000.f;
        if (reconnectTimer.Test())
        {
            if (reconnectAttempts)
            {
                PerformConnection();
                --reconnectAttempts;
            }
            else
            {
                LogInfo("Failed to connect to " + serverIp + ":" + ToString(serverPort));
                framework_->GetEventManager()->SendEvent(networkEventCategory, Events::CONNECTION_FAILED, 0);
                reconnectTimer.Stop();
                serverIp = "";
            }
        }
        else if (!reconnectTimer.Enabled())
            reconnectTimer.StartMSecs(cReconnectTimeout);
    }

    // If connection was made, enable a larger number of reconnection attempts in case it gets lost
    if (serverConnection && serverConnection->GetConnectionState() == ConnectionOK)
        reconnectAttempts = cReconnectAttempts;

    RESETPROFILER;
}

const std::string &KristalliProtocolModule::NameStatic()
{
    return moduleName;
}

void KristalliProtocolModule::Connect(const char *ip, unsigned short port, SocketTransportLayer transport)
{
    if (Connected() && serverConnection && serverConnection->GetEndPoint().ToString() != serverIp)
        Disconnect();

    serverIp = ip;
    serverPort = port;
    serverTransport = transport;
    reconnectAttempts = cInitialAttempts; // Initial attempts when establishing connection

    if (!Connected())
        PerformConnection(); // Start performing a connection attempt to the desired address/port/transport
}

void KristalliProtocolModule::PerformConnection()
{
    if (Connected() && serverConnection)
    {
        serverConnection->Close();
//        network.CloseMessageConnection(serverConnection);
        serverConnection = 0;
    }

    // Connect to the server.
    serverConnection = network.Connect(serverIp.c_str(), serverPort, serverTransport, this);
    if (!serverConnection)
    {
        LogError("Unable to connect to " + serverIp + ":" + ToString(serverPort));
        return;
    }
}

void KristalliProtocolModule::Disconnect()
{
    // Clear the remembered destination server ip address so that the automatic connection timer will not try to reconnect.
    serverIp = "";
    reconnectTimer.Stop();

    if (serverConnection)
    {
        serverConnection->Disconnect();
//        network.CloseMessageConnection(serverConnection);
        ///\todo Wait? This closes the connection.
        serverConnection = 0;
    }

}

bool KristalliProtocolModule::StartServer(unsigned short port, SocketTransportLayer transport)
{
    StopServer();

    server = network.StartServer(port, transport, this);
    if (!server)
    {
        LogError("Failed to start server on port " + ToString((int)port));
        throw Exception(("Failed to start server on port " + ToString((int)port) + ". Please make sure that the port is free and not used by another application. The program will now abort.").c_str());
    }

    LogInfo("Started server on port " + ToString((int)port));
    return true;
}

void KristalliProtocolModule::StopServer()
{
    if (server)
    {
        network.StopServer();
        connections.clear();
        LogInfo("Stopped server");
        server = 0;
    }
}

void KristalliProtocolModule::NewConnectionEstablished(kNet::MessageConnection *source)
{
    source->RegisterInboundMessageHandler(this);
    ///\todo Regression. Re-enable. -jj.
//    source->SetDatagramInFlowRatePerSecond(200);

    UserConnection* connection = new UserConnection();
    connection->userID = AllocateNewConnectionID();
    connection->connection = source;
    connections.push_back(connection);

    LogInfo("User connected from " + source->GetEndPoint().ToString() + ", connection ID " + ToString((int)connection->userID));

    Events::KristalliUserConnected msg(connection);
    framework_->GetEventManager()->SendEvent(networkEventCategory, Events::USER_CONNECTED, &msg);
}

void KristalliProtocolModule::ClientDisconnected(MessageConnection *source)
{
    // Delete from connection list if it was a known user
    for(UserConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        if ((*iter)->connection == source)
        {
            Events::KristalliUserDisconnected msg((*iter));
            framework_->GetEventManager()->SendEvent(networkEventCategory, Events::USER_DISCONNECTED, &msg);

            LogInfo("User disconnected, connection ID " + ToString((int)(*iter)->userID));
            delete(*iter);
            connections.erase(iter);
            return;
        }

    LogInfo("Unknown user disconnected");
}

void KristalliProtocolModule::HandleMessage(MessageConnection *source, message_id_t id, const char *data, size_t numBytes)
{
    assert(source);
    assert(data);

    try
    {
        Events::KristalliNetMessageIn msg(source, id, data, numBytes);

        framework_->GetEventManager()->SendEvent(networkEventCategory, Events::NETMESSAGE_IN, &msg);
    } catch(std::exception &e)
    {
        LogError("KristalliProtocolModule: Exception \"" + std::string(e.what()) + "\" thrown when handling network message id " +
            ToString(id) + " size " + ToString((int)numBytes) + " from client " + source->ToString());
    }
}

bool KristalliProtocolModule::HandleEvent(event_category_id_t category_id, event_id_t event_id, IEventData* data)
{
    return false;
}

u8 KristalliProtocolModule::AllocateNewConnectionID() const
{
    u8 newID = 1;
    for(UserConnectionList::const_iterator iter = connections.begin(); iter != connections.end(); ++iter)
        newID = std::max((int)newID, (int)((*iter)->userID+1));

    return newID;
}

UserConnection* KristalliProtocolModule::GetUserConnection(MessageConnection* source)
{
    for (UserConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        if ((*iter)->connection == source)
            return (*iter);

    return 0;
}

UserConnection* KristalliProtocolModule::GetUserConnection(u8 id)
{
    for (UserConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        if ((*iter)->userID == id)
            return (*iter);

    return 0;
}

} // ~KristalliProtocolModule namespace

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace KristalliProtocol;

POCO_BEGIN_MANIFEST(IModule)
   POCO_EXPORT_CLASS(KristalliProtocolModule)
POCO_END_MANIFEST
<commit_msg>Updated to latest kNet API.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"

#include "DebugOperatorNew.h"

#include "KristalliProtocolModule.h"
#include "KristalliProtocolModuleEvents.h"
#include "Profiler.h"
#include "EventManager.h"
#include "CoreStringUtils.h"

#include "kNet.h"

#include <algorithm>

using namespace kNet;

namespace KristalliProtocol
{

namespace
{
    const std::string moduleName("KristalliProtocol");

/*
    const struct
    {
        SocketTransportLayer transport;
        int portNumber;
    } destinationPorts[] =
    {
        { SocketOverUDP, 2345 }, // The default Kristalli over UDP port.

        { SocketOverTCP, 2345 }, // The default Kristalli over TCP port.
        { SocketOverUDP, 123 }, // Network Time Protocol.

        { SocketOverTCP, 80 }, // HTTP.
        { SocketOverTCP, 443 }, // HTTPS.
        { SocketOverTCP, 20 }, // FTP Data.
        { SocketOverTCP, 21 }, // FTP Control.
        { SocketOverTCP, 22 }, // SSH.
        { SocketOverTCP, 23 }, // TELNET.
        { SocketOverUDP, 25 }, // SMTP. (Microsoft)
        { SocketOverTCP, 25 }, // SMTP.
        { SocketOverTCP, 110 }, // POP3 Server listen port.
        { SocketOverTCP, 995 }, // POP3 over SSL.
        { SocketOverTCP, 109 }, // POP2.
        { SocketOverTCP, 6667 }, // IRC.

        // For more info on the following windows ports, see: http://support.microsoft.com/kb/832017

        { SocketOverTCP, 135 }, // Windows RPC.
        { SocketOverUDP, 137 }, // Windows Cluster Administrator. / NetBIOS Name Resolution.
        { SocketOverUDP, 138 }, // Windows NetBIOS Datagram Service.
        { SocketOverTCP, 139 }, // Windows NetBIOS Session Service.

        { SocketOverUDP, 389 }, // Windows LDAP Server.
        { SocketOverTCP, 389 }, // Windows LDAP Server.

        { SocketOverTCP, 445 }, // Windows SMB.

        { SocketOverTCP, 5722 }, // Windows RPC.

        { SocketOverTCP, 993 }, // IMAP over SSL.

//        { SocketOverTCP, 1433 }, // SQL over TCP.
//        { SocketOverUDP, 1434 }, // SQL over UDP.

        { SocketOverUDP, 53 }, // DNS.
        { SocketOverTCP, 53 }, // DNS. Microsoft states it uses TCP 53 for DNS as well.
        { SocketOverUDP, 161 }, // SNMP agent port.
        { SocketOverUDP, 162 }, // SNMP manager port.
        { SocketOverUDP, 520 }, // RIP.
        { SocketOverUDP, 67 }, // DHCP client->server.
        { SocketOverUDP, 68 }, // DHCP server->client.
    };

    /// The number of different port choices to try from the list.
    const int cNumPortChoices = sizeof(destinationPorts) / sizeof(destinationPorts[0]);
*/
}

static const int cInitialAttempts = 1;
static const int cReconnectAttempts = 5;

KristalliProtocolModule::KristalliProtocolModule()
:IModule(NameStatic())
, serverConnection(0)
, server(0)
, reconnectAttempts(0)
{
}

KristalliProtocolModule::~KristalliProtocolModule()
{
    Disconnect();
}

void KristalliProtocolModule::Load()
{
}

void KristalliProtocolModule::Unload()
{
    Disconnect();
}

void KristalliProtocolModule::PreInitialize()
{
    kNet::SetLogChannels(kNet::LogInfo | kNet::LogError | kNet::LogUser); // Enable all log channels.
}

void KristalliProtocolModule::Initialize()
{
    EventManagerPtr event_manager = framework_->GetEventManager();

    networkEventCategory = event_manager->RegisterEventCategory("Kristalli");
    event_manager->RegisterEvent(networkEventCategory, Events::NETMESSAGE_IN, "NetMessageIn");
}

void KristalliProtocolModule::PostInitialize()
{
}

void KristalliProtocolModule::Uninitialize()
{
    Disconnect();
}

void KristalliProtocolModule::Update(f64 frametime)
{
    // Pulls all new inbound network messages and calls the message handler we've registered
    // for each of them.
    if (serverConnection)
        serverConnection->Process();

    // Note: Calling the above serverConnection->Process() may set serverConnection to null if the connection gets disconnected.
    // Therefore, in the code below, we cannot assume serverConnection is non-null, and must check it again.

    // Our client->server connection is never kept partially open.
    // That is, at the moment the server write-closes the connection, we also write-close the connection.
    // Check here if the server has write-closed, and also write-close our end if so.
    if (serverConnection && !serverConnection->IsReadOpen() && serverConnection->IsWriteOpen())
        serverConnection->Disconnect(0);

    // Process server incoming connections & messages if server up
    if (server)
        server->Process();

    if ((!serverConnection || serverConnection->GetConnectionState() == ConnectionClosed ||
        serverConnection->GetConnectionState() == ConnectionPending) && serverIp.length() != 0)
    {
        const int cReconnectTimeout = 5 * 1000.f;
        if (reconnectTimer.Test())
        {
            if (reconnectAttempts)
            {
                PerformConnection();
                --reconnectAttempts;
            }
            else
            {
                LogInfo("Failed to connect to " + serverIp + ":" + ToString(serverPort));
                framework_->GetEventManager()->SendEvent(networkEventCategory, Events::CONNECTION_FAILED, 0);
                reconnectTimer.Stop();
                serverIp = "";
            }
        }
        else if (!reconnectTimer.Enabled())
            reconnectTimer.StartMSecs(cReconnectTimeout);
    }

    // If connection was made, enable a larger number of reconnection attempts in case it gets lost
    if (serverConnection && serverConnection->GetConnectionState() == ConnectionOK)
        reconnectAttempts = cReconnectAttempts;

    RESETPROFILER;
}

const std::string &KristalliProtocolModule::NameStatic()
{
    return moduleName;
}

void KristalliProtocolModule::Connect(const char *ip, unsigned short port, SocketTransportLayer transport)
{
    if (Connected() && serverConnection && serverConnection->RemoteEndPoint().IPToString() != serverIp)
        Disconnect();

    serverIp = ip;
    serverPort = port;
    serverTransport = transport;
    reconnectAttempts = cInitialAttempts; // Initial attempts when establishing connection

    if (!Connected())
        PerformConnection(); // Start performing a connection attempt to the desired address/port/transport
}

void KristalliProtocolModule::PerformConnection()
{
    if (Connected() && serverConnection)
    {
        serverConnection->Close();
//        network.CloseMessageConnection(serverConnection);
        serverConnection = 0;
    }

    // Connect to the server.
    serverConnection = network.Connect(serverIp.c_str(), serverPort, serverTransport, this);
    if (!serverConnection)
    {
        LogError("Unable to connect to " + serverIp + ":" + ToString(serverPort));
        return;
    }
}

void KristalliProtocolModule::Disconnect()
{
    // Clear the remembered destination server ip address so that the automatic connection timer will not try to reconnect.
    serverIp = "";
    reconnectTimer.Stop();

    if (serverConnection)
    {
        serverConnection->Disconnect();
//        network.CloseMessageConnection(serverConnection);
        ///\todo Wait? This closes the connection.
        serverConnection = 0;
    }

}

bool KristalliProtocolModule::StartServer(unsigned short port, SocketTransportLayer transport)
{
    StopServer();

    const bool allowAddressReuse = true;
    server = network.StartServer(port, transport, this, allowAddressReuse);
    if (!server)
    {
        LogError("Failed to start server on port " + ToString((int)port));
        throw Exception(("Failed to start server on port " + ToString((int)port) + ". Please make sure that the port is free and not used by another application. The program will now abort.").c_str());
    }

    LogInfo("Started server on port " + ToString((int)port));
    return true;
}

void KristalliProtocolModule::StopServer()
{
    if (server)
    {
        network.StopServer();
        connections.clear();
        LogInfo("Stopped server");
        server = 0;
    }
}

void KristalliProtocolModule::NewConnectionEstablished(kNet::MessageConnection *source)
{
    source->RegisterInboundMessageHandler(this);
    ///\todo Regression. Re-enable. -jj.
//    source->SetDatagramInFlowRatePerSecond(200);

    UserConnection* connection = new UserConnection();
    connection->userID = AllocateNewConnectionID();
    connection->connection = source;
    connections.push_back(connection);

    LogInfo("User connected from " + source->RemoteEndPoint().ToString() + ", connection ID " + ToString((int)connection->userID));

    Events::KristalliUserConnected msg(connection);
    framework_->GetEventManager()->SendEvent(networkEventCategory, Events::USER_CONNECTED, &msg);
}

void KristalliProtocolModule::ClientDisconnected(MessageConnection *source)
{
    // Delete from connection list if it was a known user
    for(UserConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        if ((*iter)->connection == source)
        {
            Events::KristalliUserDisconnected msg((*iter));
            framework_->GetEventManager()->SendEvent(networkEventCategory, Events::USER_DISCONNECTED, &msg);

            LogInfo("User disconnected, connection ID " + ToString((int)(*iter)->userID));
            delete(*iter);
            connections.erase(iter);
            return;
        }

    LogInfo("Unknown user disconnected");
}

void KristalliProtocolModule::HandleMessage(MessageConnection *source, message_id_t id, const char *data, size_t numBytes)
{
    assert(source);
    assert(data);

    try
    {
        Events::KristalliNetMessageIn msg(source, id, data, numBytes);

        framework_->GetEventManager()->SendEvent(networkEventCategory, Events::NETMESSAGE_IN, &msg);
    } catch(std::exception &e)
    {
        LogError("KristalliProtocolModule: Exception \"" + std::string(e.what()) + "\" thrown when handling network message id " +
            ToString(id) + " size " + ToString((int)numBytes) + " from client " + source->ToString());
    }
}

bool KristalliProtocolModule::HandleEvent(event_category_id_t category_id, event_id_t event_id, IEventData* data)
{
    return false;
}

u8 KristalliProtocolModule::AllocateNewConnectionID() const
{
    u8 newID = 1;
    for(UserConnectionList::const_iterator iter = connections.begin(); iter != connections.end(); ++iter)
        newID = std::max((int)newID, (int)((*iter)->userID+1));

    return newID;
}

UserConnection* KristalliProtocolModule::GetUserConnection(MessageConnection* source)
{
    for (UserConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        if ((*iter)->connection == source)
            return (*iter);

    return 0;
}

UserConnection* KristalliProtocolModule::GetUserConnection(u8 id)
{
    for (UserConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter)
        if ((*iter)->userID == id)
            return (*iter);

    return 0;
}

} // ~KristalliProtocolModule namespace

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace KristalliProtocol;

POCO_BEGIN_MANIFEST(IModule)
   POCO_EXPORT_CLASS(KristalliProtocolModule)
POCO_END_MANIFEST
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#ifndef _Stroika_Foundation_Math_Overlap_inl_
#define _Stroika_Foundation_Math_Overlap_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Debug/Assertions.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Math {

            /*
             ********************************************************************************
             ********************************** Math::Overlaps ******************************
             ********************************************************************************
             */
            template    <typename T>
            bool    Overlaps (const pair<T, T>& i1, const pair<T, T>& i2)
            {
                Require (i1.first <= i1.second);
                Require (i2.first <= i2.second);

                /*
                 *                         |                i1               |
                 *  | A |                | B |             | C |           | D |           | E |
                 *  |                                        F                                 |
                 *
                 *  The algorithm is completely symetric. Pick one point as i1, and consider possible ranges for
                 *  interval i2, and name them A, B, C, D, E, or F.
                 *
                 *  The above captures the basic cases. i1 is a given range, and we consdier the possible
                 *  placements of A-F relative to i1.
                 *
                 *  The only ones obviously visually outside of the range p1 are A and E.
                 *
                 *  We CHOOSE to consider the case of empty insersections to be Overlap() - iff i2 (A-F) is empty.
                 */
                // CASE A
                if (i2.second < i1.first) {
                    return false;
                }
                // variant of case "A" where they touch at the edges but not the empty "A" case
                if (i2.second <= i1.first and (i1.first != i1.second and i2.first != i2.second)) {
                    return false;
                }
                // CASE E
                if (i2.first > i1.second) {
                    return false;
                }
                // variant of case "E" where they touch at the edges but not the empty "A" case
                if (i2.first >= i1.second and (i1.first != i1.second and i2.first != i2.second)) {
                    return false;
                }
                return true;
            }
            template    <typename T>
            inline  bool    Overlaps (T p1Start, T p1End, T p2Start, T p2End)
            {
                return Overlaps (pair<T, T> (p1Start, p1Start), pair<T, T> (p2Start, p2End));
            }

        }
    }
}
#endif  /*_Stroika_Foundation_Math_Overlap_inl_*/

<commit_msg>fixed serious bug in Math::Overlap/4 overload<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#ifndef _Stroika_Foundation_Math_Overlap_inl_
#define _Stroika_Foundation_Math_Overlap_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Debug/Assertions.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Math {

            /*
             ********************************************************************************
             ********************************** Math::Overlaps ******************************
             ********************************************************************************
             */
            template    <typename T>
            bool    Overlaps (const pair<T, T>& i1, const pair<T, T>& i2)
            {
                Require (i1.first <= i1.second);
                Require (i2.first <= i2.second);

                /*
                 *                         |                i1               |
                 *  | A |                | B |             | C |           | D |           | E |
                 *  |                                        F                                 |
                 *
                 *  The algorithm is completely symetric. Pick one point as i1, and consider possible ranges for
                 *  interval i2, and name them A, B, C, D, E, or F.
                 *
                 *  The above captures the basic cases. i1 is a given range, and we consdier the possible
                 *  placements of A-F relative to i1.
                 *
                 *  The only ones obviously visually outside of the range p1 are A and E.
                 *
                 *  We CHOOSE to consider the case of empty insersections to be Overlap() - iff i2 (A-F) is empty.
                 */
                // CASE A
                if (i2.second < i1.first) {
                    return false;
                }
                // variant of case "A" where they touch at the edges but not the empty "A" case
                if (i2.second <= i1.first and (i1.first != i1.second and i2.first != i2.second)) {
                    return false;
                }
                // CASE E
                if (i2.first > i1.second) {
                    return false;
                }
                // variant of case "E" where they touch at the edges but not the empty "A" case
                if (i2.first >= i1.second and (i1.first != i1.second and i2.first != i2.second)) {
                    return false;
                }
                return true;
            }
            template    <typename T>
            inline  bool    Overlaps (T p1Start, T p1End, T p2Start, T p2End)
            {
                return Overlaps (pair<T, T> (p1Start, p1End), pair<T, T> (p2Start, p2End));
            }

        }
    }
}
#endif  /*_Stroika_Foundation_Math_Overlap_inl_*/

<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include "Property.h"

using namespace MM;

TEST(FloatPropertyTruncationTests, SetValueIsTruncatedTo4Digits)
{
   FloatProperty fp;
   double v;

   ASSERT_TRUE(fp.Set(0.00004));
   ASSERT_TRUE(fp.Get(v));
   ASSERT_DOUBLE_EQ(0.0, v);

   ASSERT_TRUE(fp.Set(0.00005));
   ASSERT_TRUE(fp.Get(v));
   ASSERT_DOUBLE_EQ(0.0001, v);

   ASSERT_TRUE(fp.Set(-0.00004));
   ASSERT_TRUE(fp.Get(v));
   ASSERT_DOUBLE_EQ(0.0, v);

   ASSERT_TRUE(fp.Set(-0.00005));
   ASSERT_TRUE(fp.Get(v));
   ASSERT_DOUBLE_EQ(-0.0001, v);
}

TEST(FloatPropertyTruncationTests, LowerLimitIsTruncatedUp)
{
   FloatProperty fp;

   ASSERT_TRUE(fp.SetLimits(0.0, 1000.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit());
   ASSERT_TRUE(fp.SetLimits(0.00001, 1000.0));
   ASSERT_DOUBLE_EQ(0.0001, fp.GetLowerLimit());
   ASSERT_TRUE(fp.SetLimits(0.00011, 1000.0));
   ASSERT_DOUBLE_EQ(0.0002, fp.GetLowerLimit());

   ASSERT_TRUE(fp.SetLimits(-0.0, 1000.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit());
   ASSERT_TRUE(fp.SetLimits(-0.00001, 1000.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit());
   ASSERT_TRUE(fp.SetLimits(-0.00011, 1000.0));
   ASSERT_DOUBLE_EQ(-0.0001, fp.GetLowerLimit());
}

TEST(FloatPropertyTruncationTests, UpperLimitIsTruncatedDown)
{
   FloatProperty fp;

   ASSERT_TRUE(fp.SetLimits(-1000.0, 0.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit());
   ASSERT_TRUE(fp.SetLimits(-1000.0, 0.00001));
   ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit());
   ASSERT_TRUE(fp.SetLimits(-1000.0, 0.00011));
   ASSERT_DOUBLE_EQ(0.0001, fp.GetUpperLimit());

   ASSERT_TRUE(fp.SetLimits(-1000.0, -0.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit());
   ASSERT_TRUE(fp.SetLimits(-1000.0, -0.00001));
   ASSERT_DOUBLE_EQ(-0.0001, fp.GetUpperLimit());
   ASSERT_TRUE(fp.SetLimits(-1000.0, -0.00011));
   ASSERT_DOUBLE_EQ(-0.0002, fp.GetUpperLimit());
}

int main(int argc, char **argv)
{
   ::testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
}
<commit_msg>MMDevice: Fix unit test to work with current code<commit_after>#include <gtest/gtest.h>

#include "Property.h"

using namespace MM;

TEST(FloatPropertyTruncationTests, SetValueIsTruncatedTo4Digits)
{
   FloatProperty fp("TestProp");
   double v;

   ASSERT_TRUE(fp.Set(0.00004));
   ASSERT_TRUE(fp.Get(v));
   ASSERT_DOUBLE_EQ(0.0, v);

   ASSERT_TRUE(fp.Set(0.00005));
   ASSERT_TRUE(fp.Get(v));
   ASSERT_DOUBLE_EQ(0.0001, v);

   ASSERT_TRUE(fp.Set(-0.00004));
   ASSERT_TRUE(fp.Get(v));
   ASSERT_DOUBLE_EQ(0.0, v);

   ASSERT_TRUE(fp.Set(-0.00005));
   ASSERT_TRUE(fp.Get(v));
   ASSERT_DOUBLE_EQ(-0.0001, v);
}

TEST(FloatPropertyTruncationTests, LowerLimitIsTruncatedUp)
{
   FloatProperty fp("TestProp");

   ASSERT_TRUE(fp.SetLimits(0.0, 1000.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit());
   ASSERT_TRUE(fp.SetLimits(0.00001, 1000.0));
   ASSERT_DOUBLE_EQ(0.0001, fp.GetLowerLimit());
   ASSERT_TRUE(fp.SetLimits(0.00011, 1000.0));
   ASSERT_DOUBLE_EQ(0.0002, fp.GetLowerLimit());

   ASSERT_TRUE(fp.SetLimits(-0.0, 1000.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit());
   ASSERT_TRUE(fp.SetLimits(-0.00001, 1000.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetLowerLimit());
   ASSERT_TRUE(fp.SetLimits(-0.00011, 1000.0));
   ASSERT_DOUBLE_EQ(-0.0001, fp.GetLowerLimit());
}

TEST(FloatPropertyTruncationTests, UpperLimitIsTruncatedDown)
{
   FloatProperty fp("TestProp");

   ASSERT_TRUE(fp.SetLimits(-1000.0, 0.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit());
   ASSERT_TRUE(fp.SetLimits(-1000.0, 0.00001));
   ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit());
   ASSERT_TRUE(fp.SetLimits(-1000.0, 0.00011));
   ASSERT_DOUBLE_EQ(0.0001, fp.GetUpperLimit());

   ASSERT_TRUE(fp.SetLimits(-1000.0, -0.0));
   ASSERT_DOUBLE_EQ(0.0, fp.GetUpperLimit());
   ASSERT_TRUE(fp.SetLimits(-1000.0, -0.00001));
   ASSERT_DOUBLE_EQ(-0.0001, fp.GetUpperLimit());
   ASSERT_TRUE(fp.SetLimits(-1000.0, -0.00011));
   ASSERT_DOUBLE_EQ(-0.0002, fp.GetUpperLimit());
}

int main(int argc, char **argv)
{
   ::testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/lib/p9_ppe_utils.H $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file  p9_ppe_utils.H
/// @brief PPE commonly used functions
///
/// *HWP HW Owner        : Ashish More <ashish.more.@in.ibm.com>
/// *HWP HW Backup Owner : Brian Vanderpool <vanderp@us.ibm.com>
/// *HWP FW Owner        : Sangeetha T S <sangeet2@in.ibm.com>
/// *HWP Team            : PM
/// *HWP Level           : 2
/// *HWP Consumed by     : CMEs, GPEs, SBE, Cronus

#ifndef __P9_PPE_UTILS_H__
#define __P9_PPE_UTILS_H__
typedef struct
{
    uint16_t     number;
    std::string  name;
} PPEReg_t;

typedef struct
{
    PPEReg_t    reg;
    uint32_t    value;
} PPERegValue_t;

typedef struct
{
    PPEReg_t    reg;
    uint64_t    value;
} SCOMRegValue_t;

/**
 * @brief Offsets from base address for XIRs.
 */
const static uint64_t PPE_XIXCR    = 0x0;
const static uint64_t PPE_XIRAMRA  = 0x1;
const static uint64_t PPE_XIRAMGA  = 0x2;
const static uint64_t PPE_XIRAMDBG = 0x3;
const static uint64_t PPE_XIRAMEDR = 0x4;
const static uint64_t PPE_XIDBGPRO = 0x5;

enum PPE_DUMP_MODE
{
    XIRS           = 0x0,
    SNAPSHOT       = 0x1,
    HALT           = 0x2,
    FORCE_HALT     = 0x3
};
enum VERBOSE_MODE
{
    NOVERBOSE        = 0x0,
    VERBOSE          = 0x1,
    VERBOSEP         = 0x2,
};

enum INT_VEC_OFFSET
{
    MCHK_VEC = 0x000  ,  // 0,
    SRST_VEC = 0x040  ,  // 64,
    DSI_VEC  =  0x060 ,  // 96,
    ISI_VEC  =  0x080 ,  // 128,
    EXT_VEC  =  0x0A0 ,  // 160,
    ALIG_VEC = 0x0C0  ,  // 192,
    PRG_VEC  =  0x0E0 ,  // 224,
    DEC_VEC  =  0x100 ,  // 256,
    FIT_VEC  =  0x120 ,  // 288,
    WDT_VEC  =  0x140 ,  // 320,
} ;
enum PPE_XIRS
{
    XIR_XSR,
    XIR_IAR,
    XIR_IR,
    XIR_EDR,
    XIR_SPRG0,
};

enum PPE_SPECIAL_ACCESS
{
    MSR,
    CR,
};
enum PPE_SPRS
{
    CTR     = 9,
    DACR    = 316,
    DBCR    = 308,
    DEC     = 22,
    IVPR    = 63,
    ISR     = 62,
    LR      = 8,
    PIR     = 286,
    PVR     = 287,
    SPRG0   = 272,
    SRR0    = 26,
    SRR1    = 27,
    TCR     = 340,
    TSR     = 336,
    XER     = 1, //336,
};

// Note: EDR is available via XIR
enum PPE_GPRS
{
    R0  = 0,
    R1  = 1,
    R2  = 2,
    R3  = 3,
    R4  = 4,
    R5  = 5,
    R6  = 6,
    R7  = 7,
    R8  = 8,
    R9  = 9,
    R10 = 10,
    R13 = 13,
    R28 = 28,
    R29 = 29,
    R30 = 30,
    R31 = 31,
};

#endif  // __P9_PPE_UTILS_H__
<commit_msg>p9_ppe_commands : Enhanced single step<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/lib/p9_ppe_utils.H $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file  p9_ppe_utils.H
/// @brief PPE commonly used functions
///
/// *HWP HW Owner        : Ashish More <ashish.more.@in.ibm.com>
/// *HWP HW Backup Owner : Brian Vanderpool <vanderp@us.ibm.com>
/// *HWP FW Owner        : Sangeetha T S <sangeet2@in.ibm.com>
/// *HWP Team            : PM
/// *HWP Level           : 2
/// *HWP Consumed by     : CMEs, GPEs, SBE, Cronus

#ifndef __P9_PPE_UTILS_H__
#define __P9_PPE_UTILS_H__
typedef struct
{
    uint16_t    number;
    uint32_t    value;
} PPERegValue_t;

typedef struct
{
    PPERegValue_t     reg;
    std::string  name;
} PPEReg_t;

typedef struct
{
    uint16_t     number;
    std::string  name;
} PPEReg_num_name_t;

typedef struct
{
    PPEReg_t    reg;
    uint64_t    value;
} SCOMRegValue_t;

/**
 * @brief Offsets from base address for XIRs.
 */
const static uint64_t PPE_XIXCR    = 0x0;
const static uint64_t PPE_XIRAMRA  = 0x1;
const static uint64_t PPE_XIRAMGA  = 0x2;
const static uint64_t PPE_XIRAMDBG = 0x3;
const static uint64_t PPE_XIRAMEDR = 0x4;
const static uint64_t PPE_XIDBGPRO = 0x5;

enum PPE_DUMP_MODE
{
    XIRS           = 0x0,
    SNAPSHOT       = 0x1,
    HALT           = 0x2,
    FORCE_HALT     = 0x3
};
enum VERBOSE_MODE
{
    NOVERBOSE        = 0x0,
    VERBOSE          = 0x1,
    VERBOSEP         = 0x2,
};

enum INT_VEC_OFFSET
{
    MCHK_VEC = 0x000  ,  // 0,
    SRST_VEC = 0x040  ,  // 64,
    DSI_VEC  =  0x060 ,  // 96,
    ISI_VEC  =  0x080 ,  // 128,
    EXT_VEC  =  0x0A0 ,  // 160,
    ALIG_VEC = 0x0C0  ,  // 192,
    PRG_VEC  =  0x0E0 ,  // 224,
    DEC_VEC  =  0x100 ,  // 256,
    FIT_VEC  =  0x120 ,  // 288,
    WDT_VEC  =  0x140 ,  // 320,
} ;
enum PPE_XIRS
{
    XIR_XSR,
    XIR_IAR,
    XIR_IR,
    XIR_EDR,
    XIR_SPRG0,
};

//enum PPE_SPECIAL_ACCESS
//{
//    MSR,
//    CR,
//};
enum PPE_SPRS
{
    CTR     = 9,
    DACR    = 316,
    DBCR    = 308,
    DEC     = 22,
    EDR     = 61,
    IVPR    = 63,
    ISR     = 62,
    LR      = 8,
    PIR     = 286,
    PVR     = 287,
    SPRG0   = 272,
    SRR0    = 26,
    SRR1    = 27,
    TCR     = 340,
    TSR     = 336,
    XER     = 1,
    //Some unique identification no. FOR OTHER REGS(non sprn)
    XSR     = 4200,
    IAR     = 2,
    IR      = 3,
    MSR     = 42,
    CR      = 420,

};

// Note: EDR is available via XIR
enum PPE_GPRS
{
    R0  = 0,
    R1  = 1,
    R2  = 2,
    R3  = 3,
    R4  = 4,
    R5  = 5,
    R6  = 6,
    R7  = 7,
    R8  = 8,
    R9  = 9,
    R10 = 10,
    R13 = 13,
    R28 = 28,
    R29 = 29,
    R30 = 30,
    R31 = 31,
};

#endif  // __P9_PPE_UTILS_H__
<|endoftext|>