Exemplarily implemented notify_entry_moved(). Untested.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11160 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -12,6 +12,9 @@
|
||||
#include <fd.h>
|
||||
#include <lock.h>
|
||||
#include <khash.h>
|
||||
#include <messaging.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/KMessage.h>
|
||||
#include <util/list.h>
|
||||
|
||||
#include <malloc.h>
|
||||
@@ -57,6 +60,12 @@ struct monitor_hash_key {
|
||||
vnode_id node;
|
||||
};
|
||||
|
||||
struct interested_monitor_listener_list {
|
||||
struct list *listeners;
|
||||
monitor_listener *first_listener;
|
||||
uint32 flags;
|
||||
};
|
||||
|
||||
#define MONITORS_HASH_TABLE_SIZE 16
|
||||
|
||||
static hash_table *gMonitorHash;
|
||||
@@ -496,6 +505,130 @@ notify_listener(int op, mount_id device, vnode_id parentNode, vnode_id toParentN
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
get_interested_monitor_listeners(mount_id device, vnode_id node,
|
||||
uint32 flags, interested_monitor_listener_list *interestedListeners,
|
||||
int32 &interestedListenerCount)
|
||||
{
|
||||
// get the monitor for the node
|
||||
node_monitor *monitor = get_monitor_for(device, node);
|
||||
if (!monitor)
|
||||
return;
|
||||
|
||||
// iterate through the listeners until we find one with matching flags
|
||||
monitor_listener *listener = NULL;
|
||||
while ((listener = (monitor_listener*)list_get_next_item(
|
||||
&monitor->listeners, listener)) != NULL) {
|
||||
if (listener->flags & flags) {
|
||||
interested_monitor_listener_list &list
|
||||
= interestedListeners[interestedListenerCount++];
|
||||
list.listeners = &monitor->listeners;
|
||||
list.first_listener = listener;
|
||||
list.flags = flags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
status_t
|
||||
send_notification_message(KMessage &message,
|
||||
interested_monitor_listener_list *interestedListeners,
|
||||
int32 interestedListenerCount)
|
||||
{
|
||||
// Since the messaging service supports broadcasting and that is more
|
||||
// efficient than sending the messages individually, we collect the
|
||||
// listener targets in an array and send the message to them at once.
|
||||
const int32 maxTargetCount = 16;
|
||||
messaging_target targets[maxTargetCount];
|
||||
int32 targetCount = 0;
|
||||
|
||||
// iterate through the lists
|
||||
interested_monitor_listener_list *list = interestedListeners;
|
||||
for (int32 i = 0; i < interestedListenerCount; i++, list++) {
|
||||
// iterate through the listeners
|
||||
monitor_listener *listener = list->first_listener;
|
||||
do {
|
||||
if (listener->flags & list->flags) {
|
||||
// the listener's flags match: add it to the targets
|
||||
messaging_target &target = targets[targetCount++];
|
||||
target.port = listener->port;
|
||||
target.token = listener->token;
|
||||
|
||||
// if the target array is full, send the message
|
||||
if (targetCount == maxTargetCount) {
|
||||
status_t error = send_message(&message, targets,
|
||||
targetCount);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
targetCount = 0;
|
||||
}
|
||||
}
|
||||
} while ((listener = (monitor_listener*)list_get_next_item(
|
||||
list->listeners, listener)) != NULL);
|
||||
}
|
||||
|
||||
// if any targets are left (the usual case, unless the target array got
|
||||
// full early), send the message
|
||||
if (targetCount > 0)
|
||||
return send_message(&message, targets, targetCount);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
notify_entry_moved(mount_id device, vnode_id fromDirectory,
|
||||
const char *fromName, vnode_id toDirectory, const char *toName,
|
||||
vnode_id node)
|
||||
{
|
||||
if (!fromName || !toName)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// If node is a mount point, we need to resolve it to the mounted
|
||||
// volume's root node.
|
||||
mount_id nodeDevice = device;
|
||||
resolve_mount_point_to_volume_root(device, node, &nodeDevice, &node);
|
||||
|
||||
MutexLocker locker(gMonitorMutex);
|
||||
|
||||
// get the lists of all interested listeners
|
||||
interested_monitor_listener_list interestedListeners[3];
|
||||
int32 interestedListenerCount = 0;
|
||||
// ... for the node
|
||||
get_interested_monitor_listeners(nodeDevice, node, B_WATCH_NAME,
|
||||
interestedListeners, interestedListenerCount);
|
||||
// ... for the source directory
|
||||
get_interested_monitor_listeners(device, fromDirectory, B_WATCH_DIRECTORY,
|
||||
interestedListeners, interestedListenerCount);
|
||||
// ... for the target directory
|
||||
get_interested_monitor_listeners(device, toDirectory, B_WATCH_DIRECTORY,
|
||||
interestedListeners, interestedListenerCount);
|
||||
|
||||
if (interestedListenerCount == 0)
|
||||
return B_OK;
|
||||
|
||||
// there are iterested listeners: construct the message and send it
|
||||
char messageBuffer[1024];
|
||||
KMessage message;
|
||||
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NODE_MONITOR);
|
||||
message.AddInt32("opcode", B_ENTRY_MOVED);
|
||||
message.AddInt32("device", device);
|
||||
message.AddInt64("from directory", fromDirectory);
|
||||
message.AddInt64("to directory", toDirectory);
|
||||
message.AddInt32("node device", nodeDevice); // not R5
|
||||
message.AddInt64("node", node);
|
||||
message.AddString("from name", fromName); // not R5
|
||||
message.AddString("name", toName);
|
||||
|
||||
return send_notification_message(message, interestedListeners,
|
||||
interestedListenerCount);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// Userland syscalls
|
||||
|
||||
|
||||
Reference in New Issue
Block a user