summaryrefslogtreecommitdiff
path: root/Source/DirectFB/lib/voodoo/manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/lib/voodoo/manager.cpp')
-rwxr-xr-xSource/DirectFB/lib/voodoo/manager.cpp937
1 files changed, 937 insertions, 0 deletions
diff --git a/Source/DirectFB/lib/voodoo/manager.cpp b/Source/DirectFB/lib/voodoo/manager.cpp
new file mode 100755
index 0000000..3b2f70c
--- /dev/null
+++ b/Source/DirectFB/lib/voodoo/manager.cpp
@@ -0,0 +1,937 @@
+/*
+ (c) Copyright 2001-2011 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+//#define DIRECT_ENABLE_DEBUG
+
+#include <config.h>
+
+#include <algorithm>
+
+extern "C" {
+#include <direct/debug.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+#include <direct/thread.h>
+#include <direct/util.h>
+
+#include <voodoo/conf.h>
+#include <voodoo/internal.h>
+#include <voodoo/link.h>
+}
+
+#include <voodoo/connection_packet.h>
+#include <voodoo/connection_raw.h>
+#include <voodoo/dispatcher.h>
+#include <voodoo/manager.h>
+#include <voodoo/packet.h>
+
+
+//namespace Voodoo {
+
+D_DEBUG_DOMAIN( Voodoo_Dispatch, "Voodoo/Dispatch", "Voodoo Dispatch" );
+D_DEBUG_DOMAIN( Voodoo_Manager, "Voodoo/Manager", "Voodoo Manager" );
+
+/**********************************************************************************************************************/
+
+VoodooManager::VoodooManager( VoodooLink *link,
+ VoodooContext *context )
+ :
+ magic(0),
+ is_quit(false),
+ msg_count(0),
+ msg_serial(0)
+{
+ D_ASSERT( link != NULL );
+
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ /* Store link and context */
+ this->link = link;
+ this->context = context;
+
+
+ instances.last = 0;
+
+ response.current = NULL;
+
+
+ /* Initialize all locks. */
+ direct_recursive_mutex_init( &instances.lock );
+ direct_recursive_mutex_init( &response.lock );
+
+ /* Initialize all wait conditions. */
+ direct_waitqueue_init( &response.wait_get );
+ direct_waitqueue_init( &response.wait_put );
+
+ D_MAGIC_SET( this, VoodooManager );
+
+
+ dispatcher = new VoodooDispatcher( this );
+
+
+ /* Add connection */
+ if ((link->code & 0x8000ffff) == 0x80008676) {
+ D_INFO( "Voodoo/Manager: Connection mode is PACKET\n" );
+
+ connection = new VoodooConnectionPacket( this, link );
+ }
+ else {
+ D_INFO( "Voodoo/Manager: Connection mode is RAW\n" );
+
+ connection = new VoodooConnectionRaw( this, link );
+
+ // FIXME: query manager dynamically for compression instead
+ voodoo_config->compression_min = 0;
+ }
+
+ connection->Start();
+}
+
+static void
+instance_iterator( std::pair<VoodooInstanceID,VoodooInstance*> pair )
+{
+ D_DEBUG_AT( Voodoo_Manager, "%s( id %u, instance %p )\n", __func__, pair.first, pair.second );
+
+ pair.second->Release();
+}
+
+VoodooManager::~VoodooManager()
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+
+ if (!is_quit)
+ quit();
+
+ connection->Stop();
+
+ /* Destroy dispatcher */
+ delete dispatcher;
+
+ /* Remove connection */
+ delete connection;
+
+ /* Destroy conditions. */
+ direct_waitqueue_deinit( &response.wait_get );
+ direct_waitqueue_deinit( &response.wait_put );
+
+ /* Destroy locks. */
+ direct_mutex_deinit( &instances.lock );
+ direct_mutex_deinit( &response.lock );
+
+ /* Release all remaining interfaces. */
+ std::for_each( instances.remote.begin(), instances.remote.end(), instance_iterator );
+ std::for_each( instances.local.begin(), instances.local.end(), instance_iterator );
+
+ D_MAGIC_CLEAR( this );
+}
+
+/**********************************************************************************************************************/
+
+void
+VoodooManager::DispatchPacket( VoodooPacket *packet )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p, packet %p )\n", __func__, this, packet );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSUME( !is_quit );
+
+ if (is_quit)
+ return;
+
+ dispatcher->PutPacket( packet );
+}
+
+bool
+VoodooManager::DispatchReady()
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+// D_ASSUME( !is_quit );
+
+ if (is_quit)
+ return false;
+
+ return dispatcher->Ready();
+}
+
+/**********************************************************************************************************************/
+
+void
+VoodooManager::quit()
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSUME( !is_quit );
+
+ if (is_quit)
+ return;
+
+ /* Have all threads quit upon this. */
+ is_quit = true;
+
+ /* Acquire locks and wake up waiters. */
+ direct_mutex_lock( &response.lock );
+ direct_waitqueue_broadcast( &response.wait_get );
+ direct_waitqueue_broadcast( &response.wait_put );
+ direct_mutex_unlock( &response.lock );
+}
+
+void
+VoodooManager::handle_disconnect()
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Remote site disconnected from manager at %p!\n", this );
+
+ quit();
+}
+
+void
+VoodooManager::handle_super( VoodooSuperMessage *super )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ DirectResult ret;
+ const char *name;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( super != NULL );
+ D_ASSERT( super->header.size >= (int) sizeof(VoodooSuperMessage) );
+ D_ASSERT( super->header.type == VMSG_SUPER );
+
+ name = (const char *) (super + 1);
+
+ D_DEBUG_AT( Voodoo_Dispatch, " -> Handling SUPER message %llu for '%s' (%d bytes).\n",
+ (unsigned long long)super->header.serial, name, super->header.size );
+
+ VoodooInstanceID instance_id;
+
+ ret = context->HandleSuper( this, name, &instance_id );
+ if (ret)
+ do_respond( true, super->header.serial, ret );
+ else
+ do_respond( true, super->header.serial, DR_OK, instance_id );
+}
+
+typedef struct {
+ VoodooManager *manager;
+ VoodooInstance *instance;
+ VoodooRequestMessage *request;
+} DispatchAsyncContext;
+
+void *
+VoodooManager::dispatch_async_thread( DirectThread *thread,
+ void *arg )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, arg );
+
+ DirectResult ret;
+ DispatchAsyncContext *context = (DispatchAsyncContext*) arg;
+ VoodooManager *manager = context->manager;
+ VoodooInstance *instance = context->instance;
+ VoodooRequestMessage *request = context->request;
+
+ ret = instance->Dispatch( manager, request );
+
+ if (ret && (request->flags & VREQ_RESPOND))
+ manager->do_respond( true, request->header.serial, ret );
+
+ D_FREE( context );
+
+ return NULL;
+}
+
+void
+VoodooManager::handle_request( VoodooRequestMessage *request )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ DirectResult ret;
+ VoodooInstance *instance;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( request != NULL );
+ D_ASSERT( request->header.size >= (int) sizeof(VoodooRequestMessage) );
+ D_ASSERT( request->header.type == VMSG_REQUEST );
+
+ D_DEBUG_AT( Voodoo_Dispatch, " -> Handling REQUEST message %llu to %u::%u %s%s(%d bytes).\n",
+ (unsigned long long)request->header.serial, request->instance, request->method,
+ (request->flags & VREQ_RESPOND) ? "[RESPONDING] " : "",
+ (request->flags & VREQ_ASYNC) ? "[ASYNC] " : "",
+ request->header.size );
+
+ direct_mutex_lock( &instances.lock );
+
+ InstanceMap::iterator itr = instances.local.find( request->instance );
+
+ if (itr == instances.local.end()) {
+ direct_mutex_unlock( &instances.lock );
+
+ D_ERROR( "Voodoo/Dispatch: "
+ "Requested instance %u doesn't exist (anymore)!\n", request->instance );
+
+ if (request->flags & VREQ_RESPOND)
+ do_respond( true, request->header.serial, DR_NOSUCHINSTANCE );
+
+ return;
+ }
+
+ instance = (*itr).second;
+
+ if (request->flags & VREQ_ASYNC) {
+ DirectThread *thread;
+ DispatchAsyncContext *context;
+
+ context = (DispatchAsyncContext*) D_MALLOC( sizeof(DispatchAsyncContext) + request->header.size );
+ if (!context) {
+ D_WARN( "out of memory" );
+ direct_mutex_unlock( &instances.lock );
+ return;
+ }
+
+ context->manager = this;
+ context->instance = instance;
+ context->request = (VoodooRequestMessage*) (context + 1);
+
+ direct_memcpy( context->request, request, request->header.size );
+
+ thread = direct_thread_create( DTT_DEFAULT, dispatch_async_thread, context, "Voodoo Async" );
+ direct_thread_detach( thread );
+ // FIXME: free thread?
+ }
+ else {
+ ret = instance->Dispatch( this, request );
+
+ if (ret && (request->flags & VREQ_RESPOND))
+ do_respond( true, request->header.serial, ret );
+ }
+
+ direct_mutex_unlock( &instances.lock );
+}
+
+void
+VoodooManager::handle_response( VoodooResponseMessage *msg )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( msg != NULL );
+ D_ASSERT( msg->header.size >= (int) sizeof(VoodooResponseMessage) );
+ D_ASSERT( msg->header.type == VMSG_RESPONSE );
+ D_ASSERT( msg->request < msg_serial );
+
+ D_DEBUG_AT( Voodoo_Dispatch, " -> Handling RESPONSE message %llu (%s) with instance %u for request "
+ "%llu (%d bytes).\n", (unsigned long long)msg->header.serial, DirectResultString( msg->result ),
+ msg->instance, (unsigned long long)msg->request, msg->header.size );
+
+ direct_mutex_lock( &response.lock );
+
+ D_ASSERT( response.current == NULL );
+
+ response.current = msg;
+
+ direct_mutex_unlock( &response.lock );
+
+
+ direct_waitqueue_broadcast( &response.wait_get );
+
+ direct_mutex_lock( &response.lock );
+
+ while (response.current && !is_quit)
+ direct_waitqueue_wait( &response.wait_put, &response.lock );
+
+ direct_mutex_unlock( &response.lock );
+}
+
+/**************************************************************************************************/
+
+DirectResult
+VoodooManager::lock_response( VoodooMessageSerial request,
+ VoodooResponseMessage **ret_response )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ VoodooResponseMessage *msg = NULL;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( ret_response != NULL );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Locking response to request %llu...\n", (unsigned long long)request );
+
+ direct_mutex_lock( &response.lock );
+
+ while (!is_quit) {
+ msg = response.current;
+ if (msg && msg->request == request)
+ break;
+
+ if (msg)
+ D_DEBUG_AT( Voodoo_Manager, " -> ...current response is for request %llu...\n", (unsigned long long)msg->request );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> ...(still) waiting for response to request %llu...\n", (unsigned long long)request );
+
+ direct_waitqueue_wait( &response.wait_get, &response.lock );
+ }
+
+ if (is_quit) {
+ D_ERROR( "Voodoo/Manager: Quit while waiting for response!\n" );
+ direct_mutex_unlock( &response.lock );
+ return DR_DESTROYED;
+ }
+
+ D_DEBUG_AT( Voodoo_Manager, " -> ...locked response %llu to request %llu (%d bytes).\n",
+ (unsigned long long)msg->header.serial, (unsigned long long)request, msg->header.size );
+
+ *ret_response = msg;
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::unlock_response( VoodooResponseMessage *msg )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( msg != NULL );
+ D_ASSERT( msg == response.current );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Unlocking response %llu to request %llu (%d bytes)...\n",
+ (unsigned long long)msg->header.serial, (unsigned long long)msg->request, msg->header.size );
+
+ response.current = NULL;
+
+ direct_mutex_unlock( &response.lock );
+
+ direct_waitqueue_broadcast( &response.wait_put );
+
+ return DR_OK;
+}
+
+
+
+
+DirectResult
+VoodooManager::do_super( const char *name,
+ VoodooInstanceID *ret_instance )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ DirectResult ret;
+ int len;
+ int size;
+ VoodooPacket *packet;
+ VoodooMessageSerial serial;
+ VoodooSuperMessage *msg;
+ VoodooResponseMessage *response;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( name != NULL );
+ D_ASSERT( ret_instance != NULL );
+
+ if (is_quit) {
+ D_DEBUG_AT( Voodoo_Manager, " -> QUIT!\n" );
+ return DR_IO;
+ }
+
+ /* Calculate the total message size. */
+ len = strlen( name ) + 1;
+ size = sizeof(VoodooSuperMessage) + len;
+
+
+ /* Lock the output buffer for direct writing. */
+ packet = connection->GetPacket( size );
+ if (!packet)
+ return DR_FAILURE;
+
+ msg = (VoodooSuperMessage*) packet->data_raw();
+
+ serial = msg_serial++;
+
+ /* Fill message header. */
+ msg->header.size = size;
+ msg->header.serial = serial;
+ msg->header.type = VMSG_SUPER;
+
+ /* Append the name of the super interface to create. */
+ direct_memcpy( msg + 1, name, len );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Sending SUPER message %llu for '%s' (%d bytes).\n", (unsigned long long)serial, name, size );
+
+ /* Unlock the output buffer. */
+ connection->PutPacket( packet, true );
+
+
+ /* Wait for and lock the response buffer. */
+ ret = lock_response( serial, &response );
+ if (ret) {
+ D_ERROR( "Voodoo/Manager: "
+ "Waiting for the response failed (%s)!\n", DirectResultString( ret ) );
+ return ret;
+ }
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Got response %llu (%s) with instance %u for request %llu "
+ "(%d bytes).\n", (unsigned long long)response->header.serial, DirectResultString( ret ),
+ response->instance, (unsigned long long)response->request, response->header.size );
+
+ ret = response->result;
+ if (ret) {
+ D_ERROR( "Voodoo/Manager: Could not create remote super interface '%s' (%s)!\n",
+ name, DirectResultString( ret ) );
+ unlock_response( response );
+ return ret;
+ }
+
+ D_INFO( "Voodoo/Manager: Created remote super interface '%s'.\n", name );
+
+ /* Return the new instance ID. */
+ *ret_instance = response->instance;
+
+ /* Unlock the response buffer. */
+ unlock_response( response );
+
+ return DR_OK;
+}
+
+void
+VoodooManager::write_blocks( void *dst,
+ const VoodooMessageBlock *blocks,
+ size_t num )
+{
+ size_t i;
+ u32 *d32 = (u32*) dst;
+
+ for (i=0; i<num; i++) {
+ /* Write block type and length. */
+ d32[0] = blocks[i].type;
+ d32[1] = blocks[i].len;
+
+ /* Write block content. */
+ if (blocks[i].ptr) {
+ u32 *s32 = (u32*) blocks[i].ptr;
+
+ switch (blocks[i].len) {
+ case 16:
+ d32[5] = s32[3];
+ case 12:
+ d32[4] = s32[2];
+ case 8:
+ d32[3] = s32[1];
+ case 4:
+ d32[2] = s32[0];
+ break;
+
+ default:
+ direct_memcpy( &d32[2], blocks[i].ptr, blocks[i].len );
+ }
+ }
+ else if (blocks[i].len) {
+ D_ASSERT( blocks[i].len == 4 );
+
+ d32[2] = blocks[i].val;
+ }
+
+ /* Advance message data pointer. */
+ d32 += 2 + (VOODOO_MSG_ALIGN(blocks[i].len) >> 2);
+ }
+
+ /* Write terminator. */
+ d32[0] = VMBT_NONE;
+}
+
+DirectResult
+VoodooManager::do_request( VoodooInstanceID instance,
+ VoodooMethodID method,
+ VoodooRequestFlags flags,
+ VoodooResponseMessage **ret_response,
+ VoodooMessageBlock *blocks,
+ size_t num_blocks,
+ size_t data_size )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ DirectResult ret;
+ size_t size;
+ VoodooPacket *packet;
+ VoodooMessageSerial serial;
+ VoodooRequestMessage *msg;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( instance != VOODOO_INSTANCE_NONE );
+ D_ASSERT( ret_response != NULL || !(flags & VREQ_RESPOND) );
+ D_ASSUME( (flags & (VREQ_RESPOND | VREQ_QUEUE)) != (VREQ_RESPOND | VREQ_QUEUE) );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Instance %u, method %u, flags 0x%08x...\n", instance, method, flags );
+
+ if (is_quit) {
+ D_DEBUG_AT( Voodoo_Manager, " -> QUIT!\n" );
+ return DR_IO;
+ }
+
+ /* Calculate the total message size. */
+ size = sizeof(VoodooRequestMessage) + data_size;
+
+ D_DEBUG_AT( Voodoo_Manager, " -> complete message size: %d\n", size );
+
+ /* Lock the output buffer for direct writing. */
+ packet = connection->GetPacket( size );
+ if (!packet)
+ return DR_FAILURE;
+
+ msg = (VoodooRequestMessage*) packet->data_raw();
+
+ serial = msg_serial++;
+
+ /* Fill message header. */
+ msg->header.size = size;
+ msg->header.serial = serial;
+ msg->header.type = VMSG_REQUEST;
+
+ /* Fill message body. */
+ msg->instance = instance;
+ msg->method = method;
+ msg->flags = flags;
+
+ /* Append custom data. */
+ write_blocks( msg + 1, blocks, num_blocks );
+
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Sending REQUEST message %llu to %u::%u %s(%d bytes).\n",
+ (unsigned long long)serial, instance, method, (flags & VREQ_RESPOND) ? "[RESPONDING] " : "", size );
+
+ /* Unlock the output buffer. */
+ connection->PutPacket( packet, !(flags & VREQ_QUEUE) );
+
+ /* Wait for and lock the response buffer. */
+ if (flags & VREQ_RESPOND) {
+ VoodooResponseMessage *response;
+
+ ret = lock_response( serial, &response );
+ if (ret) {
+ D_ERROR( "Voodoo/Manager: "
+ "Waiting for the response failed (%s)!\n", DirectResultString( ret ) );
+ return ret;
+ }
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Got response %llu (%s) with instance %u for request %llu "
+ "(%d bytes).\n", (unsigned long long)response->header.serial, DirectResultString( response->result ),
+ response->instance, (unsigned long long)response->request, response->header.size );
+
+ *ret_response = response;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::next_response( VoodooResponseMessage *response,
+ VoodooResponseMessage **ret_response )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ DirectResult ret;
+ VoodooMessageSerial serial;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( response != NULL );
+
+ serial = response->request;
+
+ /* Unlock the response buffer. */
+ unlock_response( response );
+
+ ret = lock_response( serial, &response );
+ if (ret) {
+ D_ERROR( "Voodoo/Manager: "
+ "Waiting for the response failed (%s)!\n", DirectResultString( ret ) );
+ return ret;
+ }
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Got response %llu (%s) with instance %u for request %llu "
+ "(%d bytes).\n", (unsigned long long)response->header.serial, DirectResultString( response->result ),
+ response->instance, (unsigned long long)response->request, response->header.size );
+
+ *ret_response = response;
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::finish_request( VoodooResponseMessage *response )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( response != NULL );
+
+ /* Unlock the response buffer. */
+ return unlock_response( response );
+}
+
+DirectResult
+VoodooManager::do_respond( bool flush,
+ VoodooMessageSerial request,
+ DirectResult result,
+ VoodooInstanceID instance,
+ VoodooMessageBlock *blocks,
+ size_t num_blocks,
+ size_t data_size )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ size_t size;
+ VoodooPacket *packet;
+ VoodooMessageSerial serial;
+ VoodooResponseMessage *msg;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Request %llu, result %d, instance %u...\n", (unsigned long long)request, result, instance );
+
+ if (is_quit) {
+ D_DEBUG_AT( Voodoo_Manager, " -> QUIT!\n" );
+ return DR_IO;
+ }
+
+ /* Calculate the total message size. */
+ size = sizeof(VoodooResponseMessage) + data_size;
+
+ D_DEBUG_AT( Voodoo_Manager, " -> complete message size: %d\n", size );
+
+
+ /* Lock the output buffer for direct writing. */
+ packet = connection->GetPacket( size );
+ if (!packet)
+ return DR_FAILURE;
+
+ msg = (VoodooResponseMessage*) packet->data_raw();
+
+ serial = msg_serial++;
+
+ /* Fill message header. */
+ msg->header.size = size;
+ msg->header.serial = serial;
+ msg->header.type = VMSG_RESPONSE;
+
+ /* Fill message body. */
+ msg->request = request;
+ msg->result = result;
+ msg->instance = instance;
+
+ /* Append custom data. */
+ write_blocks( msg + 1, blocks, num_blocks );
+
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Sending RESPONSE message %llu (%s) with instance %u for request %llu (%d bytes).\n",
+ (unsigned long long)serial, DirectResultString( result ), instance, (unsigned long long)request, size );
+
+ /* Unlock the output buffer. */
+ connection->PutPacket( packet, flush );
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::register_local( VoodooInstance *instance,
+ VoodooInstanceID *ret_instance )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ VoodooInstanceID instance_id;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( instance != NULL );
+ D_ASSERT( ret_instance != NULL );
+
+ instance->AddRef();
+
+ direct_mutex_lock( &instances.lock );
+
+ instance_id = ++instances.last;
+
+ instances.local[instance_id] = instance;
+
+ direct_mutex_unlock( &instances.lock );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Added local instance %u (%p)\n", instance_id, instance );
+
+ *ret_instance = instance_id;
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::unregister_local( VoodooInstanceID instance_id )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ VoodooInstance *instance;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+
+ direct_mutex_lock( &instances.lock );
+
+ InstanceMap::iterator itr = instances.local.find( instance_id );
+
+ if (itr == instances.local.end()) {
+ direct_mutex_unlock( &instances.lock );
+ return DR_NOSUCHINSTANCE;
+ }
+
+ instance = (*itr).second;
+
+ instances.local.erase( itr );
+
+ direct_mutex_unlock( &instances.lock );
+
+ instance->Release();
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::lookup_local( VoodooInstanceID instance_id,
+ VoodooInstance **ret_instance )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ VoodooInstance *instance;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( instance_id != VOODOO_INSTANCE_NONE );
+ D_ASSERT( ret_instance != NULL );
+
+ direct_mutex_lock( &instances.lock );
+
+ InstanceMap::iterator itr = instances.local.find( instance_id );
+
+ direct_mutex_unlock( &instances.lock );
+
+ if (itr == instances.local.end())
+ return DR_NOSUCHINSTANCE;
+
+ instance = (*itr).second;
+
+ // FIXME: addref?
+
+ *ret_instance = instance;
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::register_remote( VoodooInstance *instance,
+ VoodooInstanceID instance_id )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( instance != NULL );
+ D_ASSERT( instance_id != VOODOO_INSTANCE_NONE );
+
+ instance->AddRef();
+
+ direct_mutex_lock( &instances.lock );
+
+ instances.remote[instance_id] = instance;
+
+ direct_mutex_unlock( &instances.lock );
+
+ D_DEBUG_AT( Voodoo_Manager, " -> Added remote instance %u (%p)\n", instance_id, instance );
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::unregister_remote( VoodooInstanceID instance_id )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ VoodooInstance *instance;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+
+ direct_mutex_lock( &instances.lock );
+
+ InstanceMap::iterator itr = instances.remote.find( instance_id );
+
+ if (itr == instances.remote.end()) {
+ direct_mutex_unlock( &instances.lock );
+ return DR_NOSUCHINSTANCE;
+ }
+
+ instance = (*itr).second;
+
+ instances.remote.erase( itr );
+
+ direct_mutex_unlock( &instances.lock );
+
+ instance->Release();
+
+ return DR_OK;
+}
+
+DirectResult
+VoodooManager::lookup_remote( VoodooInstanceID instance_id,
+ VoodooInstance **ret_instance )
+{
+ D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this );
+
+ VoodooInstance *instance;
+
+ D_MAGIC_ASSERT( this, VoodooManager );
+ D_ASSERT( instance_id != VOODOO_INSTANCE_NONE );
+ D_ASSERT( ret_instance != NULL );
+
+ direct_mutex_lock( &instances.lock );
+
+ InstanceMap::iterator itr = instances.remote.find( instance_id );
+
+ direct_mutex_unlock( &instances.lock );
+
+ if (itr == instances.remote.end())
+ return DR_NOSUCHINSTANCE;
+
+ instance = (*itr).second;
+
+ // FIXME: addref?
+
+ *ret_instance = instance;
+
+ return DR_OK;
+}
+
+//}
+