root/src/add-ons/kernel/file_systems/netfs/server/NodeMonitor.cpp
// NodeMonitor.cpp

#include <new>

#include <errno.h>
#include <sys/resource.h>

#include <AutoLocker.h>
#include <Message.h>
#include <Node.h>
#include <NodeMonitor.h>

#include "DebugSupport.h"
#include "NodeMonitor.h"
#include "NodeMonitoringEvent.h"

// node monitor constants
static const int32 kDefaultNodeMonitorLimit = 4096;
static const int32 kNodeMonitorLimitIncrement = 512;

// constructor
NodeMonitor::NodeMonitor(NodeMonitorListener* listener)
        : BLooper("node monitor", B_DISPLAY_PRIORITY, 1000),
          fListener(listener),
          fCurrentNodeMonitorLimit(kDefaultNodeMonitorLimit)
{
        // set the initial limit -- just to be sure
        struct rlimit rl;
        rl.rlim_cur = fCurrentNodeMonitorLimit;
        rl.rlim_max = RLIM_SAVED_MAX;
        setrlimit(RLIMIT_NOVMON, &rl);

        // start volume watching
        watch_node(NULL, B_WATCH_MOUNT, this);
}

// destructor
NodeMonitor::~NodeMonitor()
{
        // stop volume watching
        stop_watching(this);
}

// MessageReceived
void
NodeMonitor::MessageReceived(BMessage* message)
{
        switch (message->what) {
                case B_NODE_MONITOR:
                {
                        NodeMonitoringEvent* event = NULL;
                        int32 opcode;
                        if (message->FindInt32("opcode", &opcode) == B_OK) {
                                switch (opcode) {
                                        case B_ENTRY_CREATED:
                                                event = new(std::nothrow) EntryCreatedEvent;
                                                break;
                                        case B_ENTRY_REMOVED:
                                                event = new(std::nothrow) EntryRemovedEvent;
                                                break;
                                        case B_ENTRY_MOVED:
                                                event = new(std::nothrow) EntryMovedEvent;
                                                break;
                                        case B_STAT_CHANGED:
                                                event = new(std::nothrow) StatChangedEvent;
                                                break;
                                        case B_ATTR_CHANGED:
                                                event = new(std::nothrow) AttributeChangedEvent;
                                                break;
                                        case B_DEVICE_MOUNTED:
                                                event = new(std::nothrow) VolumeMountedEvent;
                                                break;
                                        case B_DEVICE_UNMOUNTED:
                                                event = new(std::nothrow) VolumeUnmountedEvent;
                                                break;
                                }
                        }
                        if (event) {
                                if (event->Init(message) == B_OK)
                                        fListener->ProcessNodeMonitoringEvent(event);
                                else
                                        delete event;
                        }
                        break;
                }
                default:
                        BLooper::MessageReceived(message);
        }
}

// StartWatching
status_t
NodeMonitor::StartWatching(const node_ref& ref)
{
        uint32 flags = B_WATCH_ALL;
        status_t error = watch_node(&ref, flags, this);
        // If starting to watch the node fail, we allocate more node
        // monitoring slots and try again.
        if (error != B_OK) {
                error = _IncreaseLimit();
                if (error == B_OK)
                        error = watch_node(&ref, flags, this);
        }
        if (error == B_OK) {
                PRINT("NodeMonitor: started watching node: "
                        "(%" B_PRIdDEV ", %" B_PRIdINO ")\n", ref.device, ref.node);
        }
        return error;
}

// StopWatching
status_t
NodeMonitor::StopWatching(const node_ref& ref)
{
        PRINT("NodeMonitor: stopped watching node: "
                "(%" B_PRIdDEV ", %" B_PRIdINO ")\n", ref.device, ref.node);
        return watch_node(&ref, B_STOP_WATCHING, this);
}

// _IncreaseLimit
status_t
NodeMonitor::_IncreaseLimit()
{
        AutoLocker<BLooper> _(this);

        int32 newLimit = fCurrentNodeMonitorLimit + kNodeMonitorLimitIncrement;
        struct rlimit rl;
        rl.rlim_cur = newLimit;
        rl.rlim_max = RLIM_SAVED_MAX;
        if (setrlimit(RLIMIT_NOVMON, &rl) < 0)
                return errno;

        fCurrentNodeMonitorLimit = newLimit;

        return B_OK;
}


// #pragma mark -

// constructor
NodeMonitorListener::NodeMonitorListener()
{
}

// destructor
NodeMonitorListener::~NodeMonitorListener()
{
}