* Added the class MessagingCommandHandler, instances of which can be
registered as handlers for specific commands sent by the kernel. (Beautifully object-oriented :-) * Fixed a bug regarding MessageArea creation (the object was deleted twice on error). * Actually resume the command processor thread. * Turned the class into a singleton. * Now always process all commands found in an area (should minimize latencies). Modulo bugs the class is now complete. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11027 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
27bd55fdf3
commit
73895a69a0
@ -3,6 +3,7 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <new>
|
||||
|
||||
#include <string.h>
|
||||
@ -12,6 +13,9 @@
|
||||
#include "Debug.h"
|
||||
#include "MessagingService.h"
|
||||
|
||||
// sService -- the singleton instance
|
||||
MessagingService *MessagingService::sService = NULL;
|
||||
|
||||
// constructor
|
||||
MessagingArea::MessagingArea()
|
||||
{
|
||||
@ -27,10 +31,10 @@ MessagingArea::~MessagingArea()
|
||||
// Create
|
||||
status_t
|
||||
MessagingArea::Create(area_id kernelAreaID, sem_id lockSem, sem_id counterSem,
|
||||
MessagingArea *&area)
|
||||
MessagingArea *&_area)
|
||||
{
|
||||
// allocate the object on the heap
|
||||
area = new(nothrow) MessagingArea;
|
||||
MessagingArea *area = new(nothrow) MessagingArea;
|
||||
if (!area)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
@ -49,6 +53,7 @@ MessagingArea::Create(area_id kernelAreaID, sem_id lockSem, sem_id counterSem,
|
||||
area->fCounterSem = counterSem;
|
||||
area->fNextArea = NULL;
|
||||
|
||||
_area = area;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -144,11 +149,17 @@ MessagingArea::NextArea() const
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// CommandHandlerMap
|
||||
struct MessagingService::CommandHandlerMap
|
||||
: map<uint32, MessagingCommandHandler*> {
|
||||
};
|
||||
|
||||
// constructor
|
||||
MessagingService::MessagingService()
|
||||
: fLockSem(-1),
|
||||
fCounterSem(-1),
|
||||
fFirstArea(NULL),
|
||||
fCommandHandlers(NULL),
|
||||
fCommandProcessor(-1),
|
||||
fTerminating(false)
|
||||
{
|
||||
@ -169,6 +180,8 @@ MessagingService::~MessagingService()
|
||||
wait_for_thread(fCommandProcessor, &result);
|
||||
}
|
||||
|
||||
delete fCommandHandlers;
|
||||
|
||||
delete fFirstArea;
|
||||
}
|
||||
|
||||
@ -185,6 +198,11 @@ MessagingService::Init()
|
||||
if (fCounterSem < 0)
|
||||
return fCounterSem;
|
||||
|
||||
// create the command handler map
|
||||
fCommandHandlers = new(nothrow) CommandHandlerMap;
|
||||
if (!fCommandHandlers)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// spawn the command processor
|
||||
fCommandProcessor = spawn_thread(MessagingService::_CommandProcessorEntry,
|
||||
"messaging command processor", B_DISPLAY_PRIORITY, this);
|
||||
@ -204,9 +222,75 @@ MessagingService::Init()
|
||||
return error;
|
||||
}
|
||||
|
||||
// resume the command processor
|
||||
resume_thread(fCommandProcessor);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// CreateDefault
|
||||
status_t
|
||||
MessagingService::CreateDefault()
|
||||
{
|
||||
if (sService)
|
||||
return B_OK;
|
||||
|
||||
// create the service
|
||||
MessagingService *service = new(nothrow) MessagingService;
|
||||
if (!service)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// init it
|
||||
status_t error = service->Init();
|
||||
if (error != B_OK) {
|
||||
delete service;
|
||||
return error;
|
||||
}
|
||||
|
||||
sService = service;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// DeleteDefault
|
||||
void
|
||||
MessagingService::DeleteDefault()
|
||||
{
|
||||
if (sService) {
|
||||
delete sService;
|
||||
sService = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Default
|
||||
MessagingService *
|
||||
MessagingService::Default()
|
||||
{
|
||||
return sService;
|
||||
}
|
||||
|
||||
// SetCommandHandler
|
||||
void
|
||||
MessagingService::SetCommandHandler(uint32 command,
|
||||
MessagingCommandHandler *handler)
|
||||
{
|
||||
if (handler) {
|
||||
(*fCommandHandlers)[command] = handler;
|
||||
} else {
|
||||
// no handler: remove and existing entry
|
||||
CommandHandlerMap::iterator it = fCommandHandlers->find(command);
|
||||
if (it != fCommandHandlers->end())
|
||||
fCommandHandlers->erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
// _GetCommandHandler
|
||||
MessagingCommandHandler *
|
||||
MessagingService::_GetCommandHandler(uint32 command) const
|
||||
{
|
||||
CommandHandlerMap::iterator it = fCommandHandlers->find(command);
|
||||
return (it != fCommandHandlers->end() ? it->second : NULL);
|
||||
}
|
||||
|
||||
// _CommandProcessorEntry
|
||||
int32
|
||||
MessagingService::_CommandProcessorEntry(void *data)
|
||||
@ -218,11 +302,15 @@ MessagingService::_CommandProcessorEntry(void *data)
|
||||
int32
|
||||
MessagingService::_CommandProcessor()
|
||||
{
|
||||
bool commandWaiting = false;
|
||||
while (!fTerminating) {
|
||||
// wait for the next command
|
||||
status_t error = acquire_sem(fCounterSem);
|
||||
if (error != B_OK)
|
||||
continue;
|
||||
if (!commandWaiting) {
|
||||
status_t error = acquire_sem(fCounterSem);
|
||||
if (error != B_OK)
|
||||
continue;
|
||||
} else
|
||||
commandWaiting = false;
|
||||
|
||||
// get it from the first area
|
||||
MessagingArea *area = fFirstArea;
|
||||
@ -238,7 +326,12 @@ MessagingService::_CommandProcessor()
|
||||
}
|
||||
|
||||
// dispatch the command
|
||||
// TODO: ...
|
||||
MessagingCommandHandler *handler
|
||||
= _GetCommandHandler(command->command);
|
||||
if (handler) {
|
||||
handler->HandleMessagingCommand(command->command, command->data,
|
||||
command->size - sizeof(messaging_command));
|
||||
}
|
||||
}
|
||||
|
||||
// there is a new area we don't know yet
|
||||
@ -249,6 +342,7 @@ MessagingService::_CommandProcessor()
|
||||
fLockSem, fCounterSem, nextArea);
|
||||
if (error == B_OK) {
|
||||
area->SetNextArea(nextArea);
|
||||
commandWaiting = true;
|
||||
} else {
|
||||
// Bad, but what can we do?
|
||||
ERROR(("MessagingService::_CommandProcessor(): Failed to clone "
|
||||
|
@ -8,6 +8,16 @@
|
||||
|
||||
#include <MessagingServiceDefs.h>
|
||||
|
||||
// MessagingCommandHandler
|
||||
class MessagingCommandHandler {
|
||||
public:
|
||||
MessagingCommandHandler();
|
||||
virtual ~MessagingCommandHandler();
|
||||
|
||||
virtual void HandleMessagingCommand(uint32 command, const void *data,
|
||||
int32 dataSize) = 0;
|
||||
};
|
||||
|
||||
// MessagingArea
|
||||
class MessagingArea {
|
||||
public:
|
||||
@ -44,21 +54,35 @@ private:
|
||||
|
||||
// MessagingService
|
||||
class MessagingService {
|
||||
public:
|
||||
private:
|
||||
MessagingService();
|
||||
~MessagingService();
|
||||
|
||||
status_t Init();
|
||||
|
||||
public:
|
||||
static status_t CreateDefault();
|
||||
static void DeleteDefault();
|
||||
static MessagingService *Default();
|
||||
|
||||
void SetCommandHandler(uint32 command, MessagingCommandHandler *handler);
|
||||
|
||||
private:
|
||||
MessagingCommandHandler *_GetCommandHandler(uint32 command) const;
|
||||
|
||||
static int32 _CommandProcessorEntry(void *data);
|
||||
int32 _CommandProcessor();
|
||||
|
||||
sem_id fLockSem;
|
||||
sem_id fCounterSem;
|
||||
MessagingArea *fFirstArea;
|
||||
thread_id fCommandProcessor;
|
||||
volatile bool fTerminating;
|
||||
struct CommandHandlerMap;
|
||||
|
||||
static MessagingService *sService;
|
||||
|
||||
sem_id fLockSem;
|
||||
sem_id fCounterSem;
|
||||
MessagingArea *fFirstArea;
|
||||
CommandHandlerMap *fCommandHandlers;
|
||||
thread_id fCommandProcessor;
|
||||
volatile bool fTerminating;
|
||||
};
|
||||
|
||||
#endif // MESSAGING_SERVICE_H
|
||||
|
Loading…
Reference in New Issue
Block a user