3

I'm writing a monitoring-file program based on the source code: https://github.com/kvikas/file-monitor-service/blob/master/

My program uses boost::asio::stream_descriptor::async_read_some() for asynchronous reading from the inotify descriptor http://linux.die.net/man/7/inotify

My code is as following:

Constructor:

void init(){
    int fd = inotify_init1(IN_NONBLOCK);
    int wd = inotify_add_watch(fd_, "./test.txt", IN_ALL_EVENTS);
    stream_.reset(new boost::asio::posix::stream_descriptor(io_service_, fd_)));
}

The asynchronous reading:

template<typename Monitor_Handler>
void async_monitor(Monitor_Handler handler) {
    stream_->async_read_some(boost::asio::buffer(buffer_),
            boost::bind(&monitor::handle_monitor<Monitor_Handler>,
                    shared_from_this(), boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred, handler));
}   

The handler:

template<typename Monitor_Handler>
void handle_monitor(const boost::system::error_code &ec,
        std::size_t bytes_transferred, Monitor_Handler handler) {       
    //process buffer    
    async_monitor(handler);

}

The error is that at first handle_monitor is invoked several times (multiple events such as MODIFY, ACCESS, OPEN...) for the first change in the monitored file. After that async_read_some method is called again, but I got no signal anymore (the handle_monitor is not called anymore)

However, when I tried to reset the inotify description, and readd the monitored files again ==> It worked, the handle_monitor is called for new changes in such monitored files.

Modified Code:

template<typename Monitor_Handler>
void handle_monitor(const boost::system::error_code &ec,
        std::size_t bytes_transferred, Monitor_Handler handler) {       
    //process buffer    
    async_monitor(handler);
    init();//for resetting the inotify desciptor

}

Could you guys help me explain this???? I'm dying for your answer.....

khanhhh89
  • 317
  • 5
  • 19

3 Answers3

4

This looks suspicious to me

void init(){
    int fd = inotify_init1(IN_NONBLOCK);
    int wd = inotify_add_watch(fd_, "./test.txt", IN_ALL_EVENTS);
    stream_.reset(new boost::asio::posix::stream_descriptor(io_service_, fd_)));
}

You should create the stream_descriptor with the value returned from notify_init1(), which would be fd instead of fd_. I assume fd_ is a class member, and likely uninitialized or initialized to 0.

Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • Thanks for your answer, I rewrite the fd variable. But it's not the problem. I narrow down the scope of my problem in this question. http://stackoverflow.com/questions/16397293/the-read-method-on-the-inotify-descriptor-does-not-return Could you help me explain this. Hope to see your answer – khanhhh89 May 07 '13 at 02:43
1

I would say, instead of using

int length = ::read(inotifyFd, buf, sizeof(buf));
inFd->async_read_some(boost::asio::null_buffers(),
boost::bind(&observeFilesystem,
boost::asio::placeholders::error))

it would be better to completely utilize aync_read_some as below

inFd->async_read_some(
boost::asio::buffer(buf, EVENT_BUF_LEN), 
boost::bind(&observeFilesystem,
boost::asio::placeholders::error));
Sandeep
  • 1,237
  • 1
  • 14
  • 29
-1
#include <string>
#include <algorithm>
#include <cstring>
#include <assert.h>
#include <sys/signalfd.h>
#include <sys/inotify.h>

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <iostream>



//compile with
//-------------
//g++ -std=c++0x -g -I/usr/local/include -I/home/rk/Downloads/websocketpp/src asio.cc -L/home/rk/Downloads/websocketpp -L/usr/local/lib/ -lwebsocketpp  -lboost_thread -lboost_exception -lboost_date_time -lboost_regex -lboost_system -o asio 

static int inotifyFd = -1;
static int signalFd = -1;
static boost::asio::io_service gIoSvc;
//A simple test program to test whether signalfd works with boost::asio or not.
static boost::asio::posix::stream_descriptor *gwMqFd = nullptr; //message queue on which the gateway listens for control requests.
static boost::asio::posix::stream_descriptor *inFd = nullptr; //message queue on which the gateway listens for control requests.
static void
handleMqRead(boost::system::error_code ec)
{
    std::cerr<<"\nRecvd signal";
    struct signalfd_siginfo fdsi;
    memset(&fdsi, 0, sizeof(fdsi));
    ssize_t s = ::read(signalFd, &fdsi, sizeof(struct signalfd_siginfo));
    if (s != sizeof(struct signalfd_siginfo)){
        std::cerr<<"read() on signalfd returns inconsistent size.";
        return;
    }
    gwMqFd->async_read_some(boost::asio::null_buffers(),
            boost::bind(&handleMqRead,
                boost::asio::placeholders::error));
    return;
}

#define EVENT_SIZE  (sizeof (struct inotify_event))
#define EVENT_BUF_LEN  (1024*(EVENT_SIZE + 16))
static void
observeFilesystem(boost::system::error_code ec)
{
    std::cerr<<"\nDirectory modified ...";
    char buf[EVENT_BUF_LEN];
    int length = ::read(inotifyFd, buf, sizeof(buf));
    inFd->async_read_some(boost::asio::null_buffers(),
            boost::bind(&observeFilesystem,
                boost::asio::placeholders::error));
    return;
}

int 
main(int argc, char* argv[])
{
    try{
        inFd = new boost::asio::posix::stream_descriptor(gIoSvc);
        gwMqFd = new boost::asio::posix::stream_descriptor(gIoSvc);
        sigset_t signalMask;
        sigemptyset(&signalMask);
        sigaddset(&signalMask, SIGCHLD);
        sigaddset(&signalMask, SIGTERM);
        sigprocmask(SIG_BLOCK, &signalMask, nullptr);
        signalFd = signalfd(-1, &signalMask, SFD_NONBLOCK | SFD_CLOEXEC);
        assert(signalFd > 0);
        gwMqFd->assign(signalFd);
        gwMqFd->async_read_some(boost::asio::null_buffers(),
             boost::bind(&handleMqRead,
                boost::asio::placeholders::error));

        inotifyFd = inotify_init();
        assert(inotifyFd > 0);
        inFd->assign(inotifyFd);
        std::string fqpn = ".";
        inotify_add_watch(inotifyFd, fqpn.c_str(), IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF | IN_MODIFY);
        inFd->async_read_some(boost::asio::null_buffers(),
             boost::bind(&observeFilesystem,
                boost::asio::placeholders::error));
        gIoSvc.run();
    }catch (std::exception& e){
        std::cerr << "Exception: " << e.what() << std::endl;
    }
    return 0;
}
Ravikumar Tulugu
  • 1,702
  • 2
  • 18
  • 40
  • -1. No explanation given. It relies on a https://github.com/zaphoyd/websocketpp .. an alternative but higher level library. Add some explanation for +1 :) – matiu Jun 21 '17 at 18:37