The beginning of the registrar-side kernel->userland messaging service.
The passing of commands from kernel to registrar should be complete now, only the actual message delivery is missing. Completely untested yet. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10995 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <syscalls.h>
|
||||
|
||||
#include "Debug.h"
|
||||
#include "MessagingService.h"
|
||||
|
||||
// constructor
|
||||
MessagingArea::MessagingArea()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
MessagingArea::~MessagingArea()
|
||||
{
|
||||
if (fID >= 0)
|
||||
delete_area(fID);
|
||||
}
|
||||
|
||||
// Create
|
||||
status_t
|
||||
MessagingArea::Create(area_id kernelAreaID, sem_id lockSem, sem_id counterSem,
|
||||
MessagingArea *&area)
|
||||
{
|
||||
// allocate the object on the heap
|
||||
area = new(nothrow) MessagingArea;
|
||||
if (!area)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// clone the kernel area
|
||||
area_id areaID = clone_area("messaging", (void**)&area->fHeader,
|
||||
B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, kernelAreaID);
|
||||
if (areaID < 0) {
|
||||
delete area;
|
||||
return areaID;
|
||||
}
|
||||
|
||||
// finish the initialization of the object
|
||||
area->fID = areaID;
|
||||
area->fSize = area->fHeader->size;
|
||||
area->fLockSem = lockSem;
|
||||
area->fCounterSem = counterSem;
|
||||
area->fNextArea = NULL;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Lock
|
||||
bool
|
||||
MessagingArea::Lock()
|
||||
{
|
||||
// benaphore-like locking
|
||||
if (atomic_add(&fHeader->lock_counter, 1) == 0)
|
||||
return true;
|
||||
|
||||
return (acquire_sem(fLockSem) == B_OK);
|
||||
}
|
||||
|
||||
// Unlock
|
||||
void
|
||||
MessagingArea::Unlock()
|
||||
{
|
||||
if (atomic_add(&fHeader->lock_counter, -1) > 1)
|
||||
release_sem(fLockSem);
|
||||
}
|
||||
|
||||
// ID
|
||||
area_id
|
||||
MessagingArea::ID() const
|
||||
{
|
||||
return fID;
|
||||
}
|
||||
|
||||
// Size
|
||||
int32
|
||||
MessagingArea::Size() const
|
||||
{
|
||||
return fSize;
|
||||
}
|
||||
|
||||
// CountCommands
|
||||
int32
|
||||
MessagingArea::CountCommands() const
|
||||
{
|
||||
return fHeader->command_count;
|
||||
}
|
||||
|
||||
// PopCommand
|
||||
const messaging_command *
|
||||
MessagingArea::PopCommand()
|
||||
{
|
||||
if (fHeader->command_count == 0)
|
||||
return NULL;
|
||||
|
||||
// get the command
|
||||
messaging_command *command
|
||||
= (messaging_command*)((char*)fHeader + fHeader->first_command);
|
||||
|
||||
// remove it from the area
|
||||
// (as long as the area is still locked, noone will overwrite the contents)
|
||||
if (--fHeader->command_count == 0)
|
||||
fHeader->first_command = fHeader->last_command = 0;
|
||||
else
|
||||
fHeader->first_command = command->next_command;
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
// Discard
|
||||
void
|
||||
MessagingArea::Discard()
|
||||
{
|
||||
fHeader->size = 0;
|
||||
}
|
||||
|
||||
// NextKernelAreaID
|
||||
area_id
|
||||
MessagingArea::NextKernelAreaID() const
|
||||
{
|
||||
return fHeader->next_kernel_area;
|
||||
}
|
||||
|
||||
// SetNextArea
|
||||
void
|
||||
MessagingArea::SetNextArea(MessagingArea *area)
|
||||
{
|
||||
fNextArea = area;
|
||||
}
|
||||
|
||||
// NextArea
|
||||
MessagingArea *
|
||||
MessagingArea::NextArea() const
|
||||
{
|
||||
return fNextArea;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
MessagingService::MessagingService()
|
||||
: fLockSem(-1),
|
||||
fCounterSem(-1),
|
||||
fFirstArea(NULL),
|
||||
fCommandProcessor(-1),
|
||||
fTerminating(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
MessagingService::~MessagingService()
|
||||
{
|
||||
fTerminating = true;
|
||||
|
||||
if (fLockSem >= 0)
|
||||
delete_sem(fLockSem);
|
||||
if (fCounterSem >= 0)
|
||||
delete_sem(fCounterSem);
|
||||
|
||||
if (fCommandProcessor >= 0) {
|
||||
int32 result;
|
||||
wait_for_thread(fCommandProcessor, &result);
|
||||
}
|
||||
|
||||
delete fFirstArea;
|
||||
}
|
||||
|
||||
// Init
|
||||
status_t
|
||||
MessagingService::Init()
|
||||
{
|
||||
// create the semaphores
|
||||
fLockSem = create_sem(0, "messaging lock");
|
||||
if (fLockSem < 0)
|
||||
return fLockSem;
|
||||
|
||||
fCounterSem = create_sem(0, "messaging counter");
|
||||
if (fCounterSem < 0)
|
||||
return fCounterSem;
|
||||
|
||||
// spawn the command processor
|
||||
fCommandProcessor = spawn_thread(MessagingService::_CommandProcessorEntry,
|
||||
"messaging command processor", B_DISPLAY_PRIORITY, this);
|
||||
if (fCommandProcessor < 0)
|
||||
return fCommandProcessor;
|
||||
|
||||
// register with the kernel
|
||||
area_id areaID = _kern_register_messaging_service(fLockSem, fCounterSem);
|
||||
if (areaID < 0)
|
||||
return areaID;
|
||||
|
||||
// create the area
|
||||
status_t error = MessagingArea::Create(areaID, fLockSem, fCounterSem,
|
||||
fFirstArea);
|
||||
if (error != B_OK) {
|
||||
_kern_unregister_messaging_service();
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _CommandProcessorEntry
|
||||
int32
|
||||
MessagingService::_CommandProcessorEntry(void *data)
|
||||
{
|
||||
return ((MessagingService*)data)->_CommandProcessor();
|
||||
}
|
||||
|
||||
// _CommandProcessor
|
||||
int32
|
||||
MessagingService::_CommandProcessor()
|
||||
{
|
||||
while (!fTerminating) {
|
||||
// wait for the next command
|
||||
status_t error = acquire_sem(fCounterSem);
|
||||
if (error != B_OK)
|
||||
continue;
|
||||
|
||||
// get it from the first area
|
||||
MessagingArea *area = fFirstArea;
|
||||
area->Lock();
|
||||
while (area->CountCommands() > 0) {
|
||||
const messaging_command *command = area->PopCommand();
|
||||
if (!command) {
|
||||
// something's seriously wrong
|
||||
ERROR(("MessagingService::_CommandProcessor(): area %p (%ld) "
|
||||
"has command count %ld, but doesn't return any more "
|
||||
"commands.", area, area->ID(), area->CountCommands()));
|
||||
break;
|
||||
}
|
||||
|
||||
// dispatch the command
|
||||
// TODO: ...
|
||||
}
|
||||
|
||||
// there is a new area we don't know yet
|
||||
if (!area->NextArea() && area->NextKernelAreaID() >= 0) {
|
||||
// create it
|
||||
MessagingArea *nextArea;
|
||||
status_t error = MessagingArea::Create(area->NextKernelAreaID(),
|
||||
fLockSem, fCounterSem, nextArea);
|
||||
if (error == B_OK) {
|
||||
area->SetNextArea(nextArea);
|
||||
} else {
|
||||
// Bad, but what can we do?
|
||||
ERROR(("MessagingService::_CommandProcessor(): Failed to clone "
|
||||
"kernel area %ld: %s\n", area->NextKernelAreaID(),
|
||||
strerror(error)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if the current area is empty and there is a next one, we discard the
|
||||
// current one
|
||||
if (area->NextArea() && area->CountCommands() == 0) {
|
||||
fFirstArea = area->NextArea();
|
||||
area->Discard();
|
||||
area->Unlock();
|
||||
delete area;
|
||||
} else {
|
||||
area->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGING_SERVICE_H
|
||||
#define MESSAGING_SERVICE_H
|
||||
|
||||
#include <MessagingServiceDefs.h>
|
||||
|
||||
// MessagingArea
|
||||
class MessagingArea {
|
||||
public:
|
||||
~MessagingArea();
|
||||
|
||||
static status_t Create(area_id kernelAreaID, sem_id lockSem,
|
||||
sem_id counterSem, MessagingArea *&area);
|
||||
|
||||
bool Lock();
|
||||
void Unlock();
|
||||
|
||||
area_id ID() const;
|
||||
int32 Size() const;
|
||||
|
||||
int32 CountCommands() const;
|
||||
const messaging_command *PopCommand();
|
||||
|
||||
void Discard();
|
||||
|
||||
area_id NextKernelAreaID() const;
|
||||
void SetNextArea(MessagingArea *area);
|
||||
MessagingArea *NextArea() const;
|
||||
|
||||
private:
|
||||
MessagingArea();
|
||||
|
||||
messaging_area_header *fHeader;
|
||||
area_id fID;
|
||||
int32 fSize;
|
||||
sem_id fLockSem;
|
||||
sem_id fCounterSem; // TODO: Remove, if not needed.
|
||||
MessagingArea *fNextArea;
|
||||
};
|
||||
|
||||
// MessagingService
|
||||
class MessagingService {
|
||||
public:
|
||||
MessagingService();
|
||||
~MessagingService();
|
||||
|
||||
status_t Init();
|
||||
|
||||
private:
|
||||
static int32 _CommandProcessorEntry(void *data);
|
||||
int32 _CommandProcessor();
|
||||
|
||||
sem_id fLockSem;
|
||||
sem_id fCounterSem;
|
||||
MessagingArea *fFirstArea;
|
||||
thread_id fCommandProcessor;
|
||||
volatile bool fTerminating;
|
||||
};
|
||||
|
||||
#endif // MESSAGING_SERVICE_H
|
||||
Reference in New Issue
Block a user