Ack with minor comments, see inline marked [AndersW].

regards,

Anders Widell

On 10/17/2016 06:25 PM, Hans Nordeback wrote:
>   osaf/libs/core/cplusplus/base/Makefile.am    |    2 +
>   osaf/libs/core/cplusplus/base/file_notify.cc |  175 
> +++++++++++++++++++++++++++
>   osaf/libs/core/cplusplus/base/file_notify.h  |   87 +++++++++++++
>   3 files changed, 264 insertions(+), 0 deletions(-)
>
>
> diff --git a/osaf/libs/core/cplusplus/base/Makefile.am 
> b/osaf/libs/core/cplusplus/base/Makefile.am
> --- a/osaf/libs/core/cplusplus/base/Makefile.am
> +++ b/osaf/libs/core/cplusplus/base/Makefile.am
> @@ -23,6 +23,7 @@ DEFAULT_INCLUDES =
>   SUBDIRS = tests
>   
>   noinst_HEADERS = \
> +     file_notify.h \
>       getenv.h \
>       macros.h \
>       process.h \
> @@ -38,5 +39,6 @@ libbase_la_CPPFLAGS = \
>   libbase_la_LDFLAGS = -static
>   
>   libbase_la_SOURCES = \
> +     file_notify.cc \
>       getenv.cc \
>       process.cc
> diff --git a/osaf/libs/core/cplusplus/base/file_notify.cc 
> b/osaf/libs/core/cplusplus/base/file_notify.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/file_notify.cc
> @@ -0,0 +1,175 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "base/file_notify.h"
> +#include <libgen.h>
[AndersW] Missing header <cerrno>
[AndersW] Missing header <cstdlib> (for free())
> +#include <cstring>
> +#include "time.h"
> +#include "osaf_poll.h"
> +#include "logtrace.h"
> +
> +namespace base {
> +
> +FileNotify::FileNotify() {
> +  if ((inotify_fd_ = inotify_init()) == -1) {
> +    LOG_NO("inotify_init failed: %s", strerror(errno));
> +  }
> +}
> +
> +FileNotify::~FileNotify() {
> +  close(inotify_fd_);
> +}
> +
> +void FileNotify::SplitFileName(const std::string &file_name) {
> +  char *tmp1 = strdup(file_name.c_str());
> +  char *tmp2 = strdup(file_name.c_str());
> +  file_path_ = dirname(tmp1);
> +  file_name_ = basename(tmp2);
> +  free(tmp1);
> +  free(tmp2);
> +}
> +
> +FileNotify::FileNotifyErrors
> +FileNotify::WaitForFileCreation(const std::string &file_name,
> +                                int timeout, int user_fd) {
> +  FileNotify::FileNotifyErrors rc {FileNotifyErrors::kOK};
> +  SplitFileName(file_name);
> +
> +  if ((inotify_wd_ =
> +       inotify_add_watch(inotify_fd_, file_path_.c_str(), IN_CREATE)) == -1) 
> {
> +    LOG_NO("inotify_add_watch failed: %s", strerror(errno));
> +    return FileNotifyErrors::kError;
> +  }
> +
> +  if (FileExists(file_name)) {
> +    TRACE("File already created: %s", file_name.c_str());
> +    inotify_rm_watch(inotify_fd_, inotify_wd_);
> +    return FileNotifyErrors::kOK;
> +  }
> +
> +  rc = ProcessEvents(timeout, user_fd);
> +  inotify_rm_watch(inotify_fd_, inotify_wd_);
> +  return rc;
> +}
> +
> +FileNotify::FileNotifyErrors
> +FileNotify::WaitForFileDeletion(
> +    const std::string &file_name, int timeout, int user_fd) {
> +  FileNotify::FileNotifyErrors rc { FileNotifyErrors::kOK };
> +
> +  if ((inotify_wd_ = inotify_add_watch(inotify_fd_, file_name.c_str(),
> +                                       IN_DELETE_SELF)) == -1) {
> +    if (errno == ENOENT) {
> +      TRACE("File already deleted: %s", file_name.c_str());
> +      return FileNotifyErrors::kOK;
> +    } else {
> +      LOG_NO("inotify_add_watch failed: %s", strerror(errno));
> +      return FileNotifyErrors::kError;
> +    }
> +  }
> +
> +  rc = ProcessEvents(timeout, user_fd);
> +  inotify_rm_watch(inotify_fd_, inotify_wd_);
> +  return rc;
> +}
> +
> +FileNotify::FileNotifyErrors
> +FileNotify::ProcessEvents(int timeout, int user_fd) {
> +  enum {
> +    FD_INOTIFY = 0,
> +    FD_USER,
> +    NUM_FDS
> +  };
> +
> +  timespec start_time;
> +  timespec time_left_ts;
> +  timespec timeout_ts;
> +  pollfd fds[NUM_FDS] {};
> +  fds[FD_INOTIFY].fd = inotify_fd_;
> +  fds[FD_INOTIFY].events = POLLIN;
> +  fds[FD_USER].fd = user_fd;
> +  fds[FD_USER].events = POLLIN;
> +
> +  osaf_millis_to_timespec(timeout, &timeout_ts);
[AndersW] Can use base::MillisToTimespec(), and intialize timeout_ts at 
the declaration above.
> +  start_time = base::ReadMonotonicClock();
> +
> +  while (true) {
> +    timespec current_time {0};
[AndersW] [osaf/libs/core/cplusplus/base/file_notify.cc:111]: (style) 
The scope of the variable 'current_time' can be reduced.
> +    timespec elapsed_time {0};
[AndersW] [osaf/libs/core/cplusplus/base/file_notify.cc:112]: (style) 
The scope of the variable 'elapsed_time' can be reduced.
> +
> +    TRACE("remaining timeout: %d", timeout);
> +    int rc = osaf_poll(&fds[0], NUM_FDS, timeout);
[AndersW] The type of the return value from osaf_poll() is unsigned, not 
int.
> +
> +    if (rc > 0) {
> +      if (fds[FD_INOTIFY].revents & POLLIN) {
> +        ssize_t num_read = read(inotify_fd_, buf_, kBufferSize);
> +
> +        if (num_read == 0) {
> +          LOG_WA("read returned zero");
> +          return FileNotifyErrors::kError;
> +        } else if (num_read == -1) {
> +          if (errno == EINTR) {
> +            continue;
> +          } else {
> +            LOG_WA("read error: %s", strerror(errno));
> +            return FileNotifyErrors::kError;
> +          }
> +        } else {
> +          for (char *p = buf_; p < buf_ + num_read;) {
> +            inotify_event *event = reinterpret_cast<inotify_event*> (p);
> +            if (event->mask & IN_DELETE_SELF) {
> +              TRACE("file name: %s deleted", file_name_.c_str());
> +              return FileNotifyErrors::kOK;
> +            }
> +            if (event->mask & IN_CREATE) {
> +              if (file_name_ == event->name) {
> +                TRACE("file name: %s created", file_name_.c_str());
> +                return FileNotifyErrors::kOK;
> +              }
> +            }
> +            if (event->mask & IN_IGNORED) {
> +              TRACE("IN_IGNORE received, (ignored)");
> +            }
> +            p += sizeof(inotify_event) + event->len;
> +          }
> +          // calculate remaining timeout
> +          current_time = base::ReadMonotonicClock();
> +
> +          if (current_time >= start_time) {
> +            elapsed_time = current_time - start_time;
> +          }
> +          if (elapsed_time >= timeout_ts) {
> +            return FileNotifyErrors::kTimeOut;
> +          }
> +          time_left_ts = timeout_ts - elapsed_time;
> +
> +          timeout = base::TimespecToMillis(time_left_ts);
> +        }
> +      }
> +      if (fds[FD_USER].revents & POLLIN) {
> +        return FileNotifyErrors::kUserFD;
> +      }
> +    } else if (rc == 0) {
> +      TRACE("timeout");
> +      return FileNotifyErrors::kTimeOut;
> +    } else {
[AndersW] This else clause is dead code, remove.
> +      LOG_WA("poll error %s", strerror(errno));
> +      return FileNotifyErrors::kError;
> +    }
> +  }
> +}
> +}  // namespace base
> diff --git a/osaf/libs/core/cplusplus/base/file_notify.h 
> b/osaf/libs/core/cplusplus/base/file_notify.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/file_notify.h
> @@ -0,0 +1,87 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include <unistd.h>
> +#include <sys/stat.h>
> +#include <limits.h>
> +#include <sys/inotify.h>
> +#include <string>
> +#include "base/macros.h"
> +
> +#ifndef OSAF_LIBS_CORE_CPLUSPLUS_BASE_FILE_NOTIFY_H_
> +#define OSAF_LIBS_CORE_CPLUSPLUS_BASE_FILE_NOTIFY_H_
> +
> +namespace base {
> +
> +class FileNotify {
> + public:
> +  enum class FileNotifyErrors {
> +    kOK = 0,
> +    kTimeOut,
> +    kError,
> +    kUserFD
> +  };
> +
> +  FileNotify();
> +  virtual ~FileNotify();
> +
> +  /**
> +   * @brief Wait for a file to be created with a timeout.
> +   *
> +   * @a file name in format /path/file.
> +   * This function blocks until the file has been created or until the @a 
> timeout expires,
> +   * whichever happens first.
> +   *
> +   */
> +  FileNotifyErrors WaitForFileCreation(const std::string &file_name,
> +                                       int timeout, int user_fd = -1);
> +
> +  /**
> +   * @brief Wait for a file to be deleted.
> +   *
> +   * @a file name in format /path/file.
> +   * This function blocks until the file has been deleted or until the @a 
> timeout expires,
> +   * whichever happens first.
> +   *
> +   */
> +  FileNotifyErrors WaitForFileDeletion(const std::string &file_name,
> +                                       int timeout, int user_fd = -1);
> +
> + private:
> +  static const int kBufferSize = 10 * (sizeof (inotify_event) + NAME_MAX + 
> 1);
> +
> +  FileNotifyErrors ProcessEvents(int timeout, int user_fd);
> +
> +  bool FileExists(const std::string& file_name) const {
> +    struct stat buffer;
> +    return stat(file_name.c_str(), &buffer) == 0;
> +  }
> +
> +  void SplitFileName(const std::string &file_name);
> +
> +  char buf_[kBufferSize] __attribute__((aligned(8))) = {};
> +  std::string file_path_;
> +  std::string file_name_;
> +
> +  int inotify_fd_{-1};
> +  int inotify_wd_{-1};
> +  DELETE_COPY_AND_MOVE_OPERATORS(FileNotify);
> +};
> +
> +}  // namespace base
> +
> +#endif  // OSAF_LIBS_CORE_CPLUSPLUS_BASE_FILE_NOTIFY_H_


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to