Hi,
the design can be more general, WaitForFileCreation/Deletion can be change to 
WaitForEvent(Events, timeout),
where Events contains filename + filedescriptors. When an event happens it will 
be returned.
/Thanks HansN

-----Original Message-----
From: Hans Nordeback [mailto:hans.nordeb...@ericsson.com] 
Sent: den 22 oktober 2016 14:54
To: Anders Widell <anders.wid...@ericsson.com>; mahesh.va...@oracle.com; 
ramesh.bet...@oracle.com
Cc: opensaf-devel@lists.sourceforge.net
Subject: [devel] [PATCH 1 of 3] base: Use inotify to improve response time for 
transport monitor process V3 [#2091]

 osaf/libs/core/cplusplus/base/Makefile.am    |    2 +
 osaf/libs/core/cplusplus/base/file_notify.cc |  188 
+++++++++++++++++++++++++++  osaf/libs/core/cplusplus/base/file_notify.h  |  
103 ++++++++++++++
 3 files changed, 293 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
@@ -24,6 +24,7 @@ SUBDIRS = tests
 
 noinst_HEADERS = \
        buffer.h \
+       file_notify.h \
        getenv.h \
        log_message.h \
        macros.h \
@@ -43,6 +44,7 @@ libbase_la_CPPFLAGS = \  libbase_la_LDFLAGS = -static
 
 libbase_la_SOURCES = \
+       file_notify.cc \
        getenv.cc \
        log_message.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,188 @@
+/*      -*- 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>
+#include <cerrno>
+#include <cstdlib>
+#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, const std::vector<int>& 
+user_fds) {
+  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_fds);
+  inotify_rm_watch(inotify_fd_, inotify_wd_);
+  return rc;
+}
+
+FileNotify::FileNotifyErrors
+FileNotify::WaitForFileDeletion(const std::string &file_name,
+                                int timeout,
+                                const std::vector<int>& user_fds) {
+  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_fds);
+  inotify_rm_watch(inotify_fd_, inotify_wd_);
+  return rc;
+}
+
+FileNotify::FileNotifyErrors
+FileNotify::ProcessEvents(int timeout, const std::vector<int>& 
+user_fds) {
+  enum {
+    FD_INOTIFY = 0,
+  };
+
+  timespec start_time {0};
+  timespec time_left_ts {0};
+  timespec timeout_ts {0};
+
+  int num_of_fds = user_fds.size() + 1;
+  pollfd* fds = new pollfd[num_of_fds];
+
+  fds[FD_INOTIFY].fd = inotify_fd_;
+  fds[FD_INOTIFY].events = POLLIN;
+  for (int i = 1; i < num_of_fds; ++i) {
+    fds[i].fd = user_fds[i-1];
+    fds[i].events = POLLIN;
+  }
+
+  timeout_ts = base::MillisToTimespec(timeout);  start_time = 
+ base::ReadMonotonicClock();
+
+  while (true) {
+    TRACE("remaining timeout: %d", timeout);
+    unsigned rc = osaf_poll(fds, num_of_fds, timeout);
+
+    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");
+          delete [] fds;
+          return FileNotifyErrors::kError;
+        } else if (num_read == -1) {
+          if (errno == EINTR) {
+            continue;
+          } else {
+            LOG_WA("read error: %s", strerror(errno));
+            delete [] fds;
+            return FileNotifyErrors::kError;
+          }
+        } else {
+          timespec current_time {0};
+          timespec elapsed_time {0};
+          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());
+              delete [] fds;
+              return FileNotifyErrors::kOK;
+            }
+            if (event->mask & IN_CREATE) {
+              if (file_name_ == event->name) {
+                TRACE("file name: %s created", file_name_.c_str());
+                delete [] fds;
+                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);
+        }
+      }
+      // Check user file descriptors
+      for (int i = 1; i < num_of_fds; i++) {
+        if ((fds[i].revents & POLLIN) ||
+            (fds[i].revents & POLLHUP) ||
+            (fds[i].revents & POLLERR)) {
+          delete [] fds;
+          return FileNotifyErrors::kUserFD;
+        }
+      }
+    } else if (rc == 0) {
+      TRACE("timeout");
+      delete [] fds;
+      return FileNotifyErrors::kTimeOut;
+    }
+  }
+}
+}  // 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,103 @@
+/*      -*- 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 <vector>
+#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, const std::vector<int>& user_fds);
+
+  FileNotifyErrors
+  WaitForFileCreation(const std::string &file_name, int timeout) {
+    std::vector<int> empty_user_fds;
+    return WaitForFileCreation(file_name, timeout, empty_user_fds);  }
+
+  /**
+   * @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, const std::vector<int>& user_fds);
+
+  FileNotifyErrors
+    WaitForFileDeletion(const std::string &file_name, int timeout) {
+    std::vector<int> empty_user_fds;
+    return WaitForFileDeletion(file_name, timeout, empty_user_fds);  }
+
+
+ private:
+  static const int kBufferSize = 10 * (sizeof (inotify_event) + NAME_MAX + 1);
+
+  FileNotifyErrors ProcessEvents(int timeout, const std::vector<int>& 
user_fds);
+
+  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

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