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