1// NodeMonitor.cpp
2
3#include <new>
4
5#include <Message.h>
6#include <Node.h>
7#include <NodeMonitor.h>
8
9#include "AutoLocker.h"
10#include "Debug.h"
11#include "NodeMonitor.h"
12#include "NodeMonitoringEvent.h"
13
14// node monitor constants
15static const int32 kDefaultNodeMonitorLimit = 4096;
16static const int32 kNodeMonitorLimitIncrement = 512;
17
18// private BeOS syscall to set the node monitor slot limit
19extern "C" int _kset_mon_limit_(int num);
20
21// constructor
22NodeMonitor::NodeMonitor(NodeMonitorListener* listener)
23	: BLooper("node monitor", B_DISPLAY_PRIORITY, 1000),
24	  fListener(listener),
25	  fCurrentNodeMonitorLimit(kDefaultNodeMonitorLimit)
26{
27	// set the initial limit -- just to be sure
28	_kset_mon_limit_(fCurrentNodeMonitorLimit);
29
30	// start volume watching
31	watch_node(NULL, B_WATCH_MOUNT, this);
32}
33
34// destructor
35NodeMonitor::~NodeMonitor()
36{
37	// stop volume watching
38	stop_watching(this);
39}
40
41// MessageReceived
42void
43NodeMonitor::MessageReceived(BMessage* message)
44{
45	switch (message->what) {
46		case B_NODE_MONITOR:
47		{
48			NodeMonitoringEvent* event = NULL;
49			int32 opcode;
50			if (message->FindInt32("opcode", &opcode) == B_OK) {
51				switch (opcode) {
52					case B_ENTRY_CREATED:
53						event = new(nothrow) EntryCreatedEvent;
54						break;
55					case B_ENTRY_REMOVED:
56						event = new(nothrow) EntryRemovedEvent;
57						break;
58					case B_ENTRY_MOVED:
59						event = new(nothrow) EntryMovedEvent;
60						break;
61					case B_STAT_CHANGED:
62						event = new(nothrow) StatChangedEvent;
63						break;
64					case B_ATTR_CHANGED:
65						event = new(nothrow) AttributeChangedEvent;
66						break;
67					case B_DEVICE_MOUNTED:
68						event = new(nothrow) VolumeMountedEvent;
69						break;
70					case B_DEVICE_UNMOUNTED:
71						event = new(nothrow) VolumeUnmountedEvent;
72						break;
73				}
74			}
75			if (event) {
76				if (event->Init(message) == B_OK)
77					fListener->ProcessNodeMonitoringEvent(event);
78				else
79					delete event;
80			}
81			break;
82		}
83		default:
84			BLooper::MessageReceived(message);
85	}
86}
87
88// StartWatching
89status_t
90NodeMonitor::StartWatching(const node_ref& ref)
91{
92	uint32 flags = B_WATCH_ALL;
93	status_t error = watch_node(&ref, flags, this);
94	// If starting to watch the node fail, we allocate more node
95	// monitoring slots and try again.
96	if (error != B_OK) {
97		error = _IncreaseLimit();
98		if (error == B_OK)
99			error = watch_node(&ref, flags, this);
100	}
101if (error == B_OK) {
102PRINT(("NodeMonitor: started watching node: (%ld, %lld)\n", ref.device,
103ref.node));
104}
105	return error;
106}
107
108// StopWatching
109status_t
110NodeMonitor::StopWatching(const node_ref& ref)
111{
112PRINT(("NodeMonitor: stopped watching node: (%ld, %lld)\n", ref.device,
113ref.node));
114	return watch_node(&ref, B_STOP_WATCHING, this);
115}
116
117// _IncreaseLimit
118status_t
119NodeMonitor::_IncreaseLimit()
120{
121	AutoLocker<BLooper> _(this);
122
123	int32 newLimit = fCurrentNodeMonitorLimit + kNodeMonitorLimitIncrement;
124	status_t error = _kset_mon_limit_(newLimit);
125	if (error == B_OK)
126		fCurrentNodeMonitorLimit = newLimit;
127	return error;
128}
129
130
131// #pragma mark -
132
133// constructor
134NodeMonitorListener::NodeMonitorListener()
135{
136}
137
138// destructor
139NodeMonitorListener::~NodeMonitorListener()
140{
141}
142