From 26dd5fd5310d679150931c9c381cfa97c2ce8b93 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 6 Feb 2003 23:39:54 +0000 Subject: [PATCH] * RVolumeList: - Added locking, listener support. - Changed message handling from BHandler to MessageHandler interface. - Fixed bugs. * RDiskDeviceList: - Locking uses an external lock now (the same one as the volume list) - Prepared for message handling (MessageHandler). * DiskDeviceManager: - Added priority message queue and message handler thread -- should be more or less complete now. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2644 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/registrar/DiskDeviceManager.cpp | 107 ++++++++++++- src/servers/registrar/DiskDeviceManager.h | 19 ++- src/servers/registrar/RDiskDeviceList.cpp | 40 ++++- src/servers/registrar/RDiskDeviceList.h | 19 ++- src/servers/registrar/RVolumeList.cpp | 157 +++++++++++++------- src/servers/registrar/RVolumeList.h | 32 +++- 6 files changed, 295 insertions(+), 79 deletions(-) diff --git a/src/servers/registrar/DiskDeviceManager.cpp b/src/servers/registrar/DiskDeviceManager.cpp index 76667d0845..c4c4e7db3e 100644 --- a/src/servers/registrar/DiskDeviceManager.cpp +++ b/src/servers/registrar/DiskDeviceManager.cpp @@ -3,28 +3,49 @@ // by the OpenBeOS license. //--------------------------------------------------------------------- +#include #include #include "DiskDeviceManager.h" +enum { + REQUEST_PRIORITY = 0, + NODE_MONITOR_PRIORITY = 10, +}; + // constructor DiskDeviceManager::DiskDeviceManager() : BLooper("disk device manager"), - fDeviceList(), - fVolumeList() + fDeviceListLock(), + fVolumeList(BMessenger(this), fDeviceListLock), + fDeviceList(BMessenger(this), fDeviceListLock, fVolumeList), + fMessageQueue(), + fWorker(-1), + fMessageCounter(-1), + fTerminating(false) { - AddHandler(&fVolumeList); + // set up the device list + fVolumeList.Rescan(); fVolumeList.Dump(); fDeviceList.Rescan(); fDeviceList.Dump(); + // start the worker thread + fMessageCounter = create_sem(0, "disk device manager msgcounter"); + if (fMessageCounter >= 0) { + fWorker = spawn_thread(_WorkerEntry, "disk device manager worker", + B_NORMAL_PRIORITY, this); + if (fWorker >= 0) + resume_thread(fWorker); + } } // destructor DiskDeviceManager::~DiskDeviceManager() { - Lock(); - RemoveHandler(&fVolumeList); - Unlock(); + fTerminating = true; + delete_sem(fMessageCounter); + int32 dummy; + wait_for_thread(fWorker, &dummy); } // MessageReceived @@ -37,6 +58,14 @@ DiskDeviceManager::MessageReceived(BMessage *message) case B_REG_UPDATE_DISK_DEVICE: case B_REG_DEVICE_START_WATCHING: case B_REG_DEVICE_STOP_WATCHING: + DetachCurrentMessage(); + if (!_PushMessage(message, REQUEST_PRIORITY)) + delete message; + break; + case B_NODE_MONITOR: + DetachCurrentMessage(); + if (!_PushMessage(message, NODE_MONITOR_PRIORITY)) + delete message; break; default: BLooper::MessageReceived(message); @@ -44,3 +73,69 @@ DiskDeviceManager::MessageReceived(BMessage *message) } } +// _PushMessage +bool +DiskDeviceManager::_PushMessage(BMessage *message, int32 priority) +{ + bool result = fMessageQueue.PushMessage(message, priority); + if (result) + release_sem(fMessageCounter); + return result; +} + +// _PopMessage +BMessage * +DiskDeviceManager::_PopMessage() +{ + BMessage *result = NULL; + status_t error = acquire_sem(fMessageCounter); + if (error == B_OK) + result = fMessageQueue.PopMessage(); + return result; +} + +// _WorkerEntry +int32 +DiskDeviceManager::_WorkerEntry(void *parameters) +{ + return static_cast(parameters)->_Worker(); +} + +// _Worker +int32 +DiskDeviceManager::_Worker() +{ + while (!fTerminating) { + if (BMessage *message = _PopMessage()) { + // dispatch the message + switch (message->what) { + case B_REG_NEXT_DISK_DEVICE: + case B_REG_GET_DISK_DEVICE: + case B_REG_UPDATE_DISK_DEVICE: + case B_REG_DEVICE_START_WATCHING: + case B_REG_DEVICE_STOP_WATCHING: + fDeviceList.HandleMessage(message); + break; + case B_NODE_MONITOR: + { + int32 opcode = 0; + if (message->FindInt32("opcode", &opcode) == B_OK) { + if (opcode == B_DEVICE_MOUNTED + || opcode == B_DEVICE_UNMOUNTED) { + fVolumeList.HandleMessage(message); + } else { + fDeviceList.HandleMessage(message); + } + } + break; + } + default: + // error + break; + } + delete message; + } + } + return 0; +} + diff --git a/src/servers/registrar/DiskDeviceManager.h b/src/servers/registrar/DiskDeviceManager.h index 1d6c98ffda..a9af8678cc 100644 --- a/src/servers/registrar/DiskDeviceManager.h +++ b/src/servers/registrar/DiskDeviceManager.h @@ -6,8 +6,11 @@ #ifndef DISK_DEVICE_MANAGER_H #define DISK_DEVICE_MANAGER_H +#include #include +#include +#include "PriorityMessageQueue.h" #include "RDiskDeviceList.h" #include "RVolumeList.h" @@ -19,8 +22,20 @@ public: virtual void MessageReceived(BMessage *message); private: - RDiskDeviceList fDeviceList; - RVolumeList fVolumeList; + bool _PushMessage(BMessage *message, int32 priority); + BMessage *_PopMessage(); + + static int32 _WorkerEntry(void *parameters); + int32 _Worker(); + +private: + BLocker fDeviceListLock; + RVolumeList fVolumeList; + RDiskDeviceList fDeviceList; + PriorityMessageQueue fMessageQueue; + thread_id fWorker; + sem_id fMessageCounter; + bool fTerminating; }; #endif // DISK_DEVICE_MANAGER_H diff --git a/src/servers/registrar/RDiskDeviceList.cpp b/src/servers/registrar/RDiskDeviceList.cpp index a22fe583ab..4ab39aa115 100644 --- a/src/servers/registrar/RDiskDeviceList.cpp +++ b/src/servers/registrar/RDiskDeviceList.cpp @@ -14,7 +14,7 @@ #include #include #include -//#include +#include #include #include "RDiskDeviceList.h" @@ -72,12 +72,18 @@ private: }; // constructor -RDiskDeviceList::RDiskDeviceList() - : fLock(), +RDiskDeviceList::RDiskDeviceList(BMessenger target, BLocker &lock, + RVolumeList &volumeList) + : MessageHandler(), + RVolumeListListener(), + fLock(lock), + fTarget(target), + fVolumeList(volumeList), fDevices(20, true), fSessions(40, false), fPartitions(80, false) { + fVolumeList.SetListener(this); } // destructor @@ -85,6 +91,34 @@ RDiskDeviceList::~RDiskDeviceList() { } +// HandleMessage +void +RDiskDeviceList::HandleMessage(BMessage *message) +{ + if (Lock()) { + switch (message->what) { + default: + MessageHandler::HandleMessage(message); + break; + } + Unlock(); + } +} + +// VolumeMounted +void +RDiskDeviceList::VolumeMounted(const RVolume *volume) +{ + PRINT(("RDiskDeviceList::VolumeMounted(%ld)\n", volume->ID())); +} + +// VolumeUnmounted +void +RDiskDeviceList::VolumeUnmounted(const RVolume *volume) +{ + PRINT(("RDiskDeviceList::VolumeUnmounted(%ld)\n", volume->ID())); +} + // AddDevice bool RDiskDeviceList::AddDevice(RDiskDevice *device) diff --git a/src/servers/registrar/RDiskDeviceList.h b/src/servers/registrar/RDiskDeviceList.h index 234f2056f0..bf3988c71f 100644 --- a/src/servers/registrar/RDiskDeviceList.h +++ b/src/servers/registrar/RDiskDeviceList.h @@ -6,21 +6,30 @@ #ifndef DISK_DEVICE_LIST_H #define DISK_DEVICE_LIST_H -#include +#include #include +#include "MessageHandler.h" +#include "RVolumeList.h" + class BDirectory; class BEntry; +class BLocker; class RDiskDevice; class RPartition; class RSession; -class RDiskDeviceList { +class RDiskDeviceList : public MessageHandler, public RVolumeListListener { public: - RDiskDeviceList(); + RDiskDeviceList(BMessenger target, BLocker &lock, RVolumeList &volumeList); ~RDiskDeviceList(); + virtual void HandleMessage(BMessage *message); + + void RDiskDeviceList::VolumeMounted(const RVolume *volume); + void RDiskDeviceList::VolumeUnmounted(const RVolume *volume); + bool AddDevice(RDiskDevice *device); bool RemoveDevice(int32 index); bool RemoveDevice(RDiskDevice *device); @@ -59,7 +68,9 @@ private: status_t _ScanDevice(const char *path); private: - BLocker fLock; + mutable BLocker &fLock; + BMessenger fTarget; + RVolumeList &fVolumeList; BObjectList fDevices; // sorted by ID BObjectList fSessions; // BObjectList fPartitions; // diff --git a/src/servers/registrar/RVolumeList.cpp b/src/servers/registrar/RVolumeList.cpp index c636db1de4..b7cc288e38 100644 --- a/src/servers/registrar/RVolumeList.cpp +++ b/src/servers/registrar/RVolumeList.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -79,66 +80,84 @@ RVolume::Unset() } +// RVolumeListListener + +// constructor +RVolumeListListener::RVolumeListListener() +{ +} + +// destructor +RVolumeListListener::~RVolumeListListener() +{ +} + +// VolumeMounted +void +RVolumeListListener::VolumeMounted(const RVolume *volume) +{ +} + +// VolumeUnmounted +void +RVolumeListListener::VolumeUnmounted(const RVolume *volume) +{ +} + + // RVolumeList // constructor -RVolumeList::RVolumeList() - : BHandler(), +RVolumeList::RVolumeList(BMessenger target, BLocker &lock) + : MessageHandler(), + fLock(lock), + fTarget(target), fVolumes(20, true), - fRoster() + fRoster(), + fListener(NULL) { +// TODO: Remove work-around. At this time R5 libbe's watching functions don't +// work for us. We have an own implementation in `NodeMonitoring.cpp'. +// fRoster.StartWatching(BMessenger(this)); + watch_node(NULL, B_WATCH_MOUNT, fTarget); + Rescan(); } // destructor RVolumeList::~RVolumeList() { -} - -// MessageReceived -void -RVolumeList::MessageReceived(BMessage *message) -{ - switch (message->what) { - case B_NODE_MONITOR: - { - int32 opcode = 0; - if (message->FindInt32("opcode", &opcode) == B_OK) { - switch (opcode) { - case B_DEVICE_MOUNTED: - _DeviceMounted(message); - break; - case B_DEVICE_UNMOUNTED: - _DeviceUnmounted(message); - break; - } - } - break; - } - default: - BHandler::MessageReceived(message); - break; - } -} - -// SetNextHandler -void -RVolumeList::SetNextHandler(BHandler *handler) -{ - // stop watching volumes, if removed from looper - if (!handler) { // TODO: Remove work-around. At this time R5 libbe's watching functions don't // work for us. We have an own implementation in `NodeMonitoring.cpp'. // fRoster.StopWatching(); - stop_watching(BMessenger(this)); - } - BHandler::SetNextHandler(handler); - // start watching volumes and rescan list, if added to looper - if (handler) { -// TODO: Remove work-around. At this time R5 libbe's watching functions don't -// work for us. We have an own implementation in `NodeMonitoring.cpp'. -// fRoster.StartWatching(BMessenger(this)); - watch_node(NULL, B_WATCH_MOUNT, BMessenger(this)); - Rescan(); + stop_watching(fTarget); +} + +// HandleMessage +void +RVolumeList::HandleMessage(BMessage *message) +{ + if (Lock()) { + switch (message->what) { + case B_NODE_MONITOR: + { + int32 opcode = 0; + if (message->FindInt32("opcode", &opcode) == B_OK) { + switch (opcode) { + case B_DEVICE_MOUNTED: + _DeviceMounted(message); + break; + case B_DEVICE_UNMOUNTED: + _DeviceUnmounted(message); + break; + } + } + break; + } + default: + MessageHandler::HandleMessage(message); + break; + } + Unlock(); } } @@ -158,23 +177,37 @@ RVolumeList::Rescan() const RVolume * RVolumeList::VolumeForDevicePath(const char *devicePath) const { -// TODO: ... - return NULL; + const RVolume *volume = NULL; + if (devicePath && fLock.Lock()) { + bool found = false; + int32 index = fVolumes.FindBinaryInsertionIndex( + CompareDevicePathPredicate(devicePath), &found); + if (found) + volume = fVolumes.ItemAt(index); + fLock.Unlock(); + } + return volume; } // Lock bool RVolumeList::Lock() { -// TODO: ... - return false; + return fLock.Lock(); } // Unlock void RVolumeList::Unlock() { -// TODO: ... + fLock.Unlock(); +} + +// SetListener +void +RVolumeList::SetListener(RVolumeListListener *listener) +{ + fListener = listener; } // Dump @@ -189,21 +222,24 @@ RVolumeList::Dump() const } // _AddVolume -void +RVolume * RVolumeList::_AddVolume(dev_t id) { - if (RVolume *volume = new RVolume) { + RVolume *volume = new RVolume; + if (volume) { status_t error = volume->SetTo(id); if (error == B_OK) { fVolumes.BinaryInsert(volume, CompareDevicePathPredicate(volume->DevicePath())); } else { delete volume; + volume = NULL; PRINT(("RVolumeList::_AddVolume(): initializing RVolume failed: " "%s\n", strerror(error))); } } else PRINT(("RVolumeList::_AddVolume(): no memory!\n")); + return volume; } // _DeviceMounted @@ -213,7 +249,10 @@ RVolumeList::_DeviceMounted(BMessage *message) dev_t device; if (message->FindInt32("new device", &device) == B_OK) { PRINT(("RVolumeList::_DeviceMounted(%ld)\n", device)); - _AddVolume(device); + if (RVolume *volume = _AddVolume(device)) { + if (fListener) + fListener->VolumeMounted(volume); + } } } @@ -224,8 +263,12 @@ RVolumeList::_DeviceUnmounted(BMessage *message) dev_t device; if (message->FindInt32("device", &device) == B_OK) { PRINT(("RVolumeList::_DeviceUnmounted(%ld)\n", device)); - if (RVolume *volume = fVolumes.FindIf(CompareIDPredicate(volume))) - fVolumes.RemoveItem(volume); + if (RVolume *volume = fVolumes.FindIf(CompareIDPredicate(device))) { + fVolumes.RemoveItem(volume, false); + if (fListener) + fListener->VolumeUnmounted(volume); + delete volume; + } } } diff --git a/src/servers/registrar/RVolumeList.h b/src/servers/registrar/RVolumeList.h index acf4bd4602..9315c6dff3 100644 --- a/src/servers/registrar/RVolumeList.h +++ b/src/servers/registrar/RVolumeList.h @@ -6,11 +6,15 @@ #ifndef VOLUME_LIST_H #define VOLUME_LIST_H -#include +#include #include #include #include +#include "MessageHandler.h" + +class BLocker; + // RVolume class RVolume { public: @@ -32,14 +36,23 @@ private: char fDevicePath[B_FILE_NAME_LENGTH]; }; -// RVolumeList -class RVolumeList : public BHandler { +// RVolumeListListener +class RVolumeListListener { public: - RVolumeList(); + RVolumeListListener(); + virtual ~RVolumeListListener(); + + virtual void VolumeMounted(const RVolume *volume); + virtual void VolumeUnmounted(const RVolume *volume); +}; + +// RVolumeList +class RVolumeList : public MessageHandler { +public: + RVolumeList(BMessenger target, BLocker &lock); virtual ~RVolumeList(); - virtual void MessageReceived(BMessage *message); - virtual void SetNextHandler(BHandler *handler); + virtual void HandleMessage(BMessage *message); status_t Rescan(); @@ -48,16 +61,21 @@ public: bool Lock(); void Unlock(); + void SetListener(RVolumeListListener *listener); + void Dump() const; private: - void _AddVolume(dev_t id); + RVolume *_AddVolume(dev_t id); void _DeviceMounted(BMessage *message); void _DeviceUnmounted(BMessage *message); private: + mutable BLocker &fLock; + BMessenger fTarget; BObjectList fVolumes; BVolumeRoster fRoster; + RVolumeListListener *fListener; }; #endif // VOLUME_LIST_H