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