Hi, see my comment below/Thanks HansN
On 11/07/2016 11:43 AM, Anders Widell wrote: > Hi! > > See my reply marked [AndersW] below. > > regards, > > Anders Widell > > > On 11/03/2016 10:25 AM, ramesh betham wrote: >> Ack with very minor comments inline. >> >> Regards, >> Ramesh. >> >> On 10/27/2016 8:55 PM, Hans Nordeback wrote: >>> osaf/libs/core/cplusplus/base/Makefile.am | 2 + >>> osaf/libs/core/cplusplus/base/file_notify.cc | 190 >>> +++++++++++++++++++++++++++ >>> osaf/libs/core/cplusplus/base/file_notify.h | 102 ++++++++++++++ >>> 3 files changed, 294 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,190 @@ >>> +/* -*- 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, >>> + const std::vector<int>& user_fds, >>> int timeout) { >>> + 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; >>> + } >> [Ramesh]: How about checking FileExists() first i.e., before adding >> to watch. > [AndersW] No, I think that would introduce a race. [HansN] AndersW is correct, if the FileExists is moved before adding the watch and e.g. the watched file is created after FileExists but before adding the watch, this file creation will be missed. >>> + >>> + rc = ProcessEvents(user_fds, timeout); >>> + inotify_rm_watch(inotify_fd_, inotify_wd_); >>> + return rc; >>> +} >>> + >>> +FileNotify::FileNotifyErrors >>> +FileNotify::WaitForFileDeletion(const std::string &file_name, >>> + const std::vector<int>& user_fds, >>> + int timeout) { >>> + 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(user_fds, timeout); >>> + inotify_rm_watch(inotify_fd_, inotify_wd_); >>> + return rc; >>> +} >>> + >>> +FileNotify::FileNotifyErrors >>> +FileNotify::ProcessEvents(const std::vector<int>& user_fds, int >>> timeout) { >>> + 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 { >>> + for (char *p = buf_; p < buf_ + num_read;) { >>> + inotify_event *event = reinterpret_cast<inotify_event*> >>> (p); >>> + if (event->mask & IN_DELETE_SELF) { >> [Ramesh]: Have TRACE for delete too. >>> + 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; >>> + } >>> + if (timeout != -1) { >>> + // calculate remaining timeout only if timeout is not >>> infinite (-1) >>> + timespec current_time {0}; >>> + timespec elapsed_time {0}; >>> + >>> + 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,102 @@ >>> +/* -*- 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, >>> + const std::vector<int>& user_fds, int timeout); >>> + >>> + FileNotifyErrors >>> + WaitForFileCreation(const std::string &file_name, int timeout) { >>> + std::vector<int> empty_user_fds; >>> + return WaitForFileCreation(file_name, empty_user_fds, timeout); >>> + } >>> + >>> + /** >>> + * @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, >>> + const std::vector<int>& user_fds, int timeout); >>> + >>> + FileNotifyErrors >>> + WaitForFileDeletion(const std::string &file_name, int timeout) { >>> + std::vector<int> empty_user_fds; >>> + return WaitForFileDeletion(file_name, empty_user_fds, timeout); >>> + } >>> + >>> + private: >>> + static const int kBufferSize = 10 * (sizeof (inotify_event) + >>> NAME_MAX + 1); >>> + >>> + FileNotifyErrors ProcessEvents(const std::vector<int>& user_fds, >>> int timeout); >>> + >>> + 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_ >> > ------------------------------------------------------------------------------ Developer Access Program for Intel Xeon Phi Processors Access to Intel Xeon Phi processor-based developer platforms. With one year of Intel Parallel Studio XE. Training and support from Colfax. Order your platform today. http://sdm.link/xeonphi _______________________________________________ Opensaf-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/opensaf-devel
