summaryrefslogtreecommitdiff
path: root/Source/DirectFB/lib/voodoo/connection_raw.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/lib/voodoo/connection_raw.cpp')
-rwxr-xr-xSource/DirectFB/lib/voodoo/connection_raw.cpp341
1 files changed, 341 insertions, 0 deletions
diff --git a/Source/DirectFB/lib/voodoo/connection_raw.cpp b/Source/DirectFB/lib/voodoo/connection_raw.cpp
new file mode 100755
index 0000000..c6ba56a
--- /dev/null
+++ b/Source/DirectFB/lib/voodoo/connection_raw.cpp
@@ -0,0 +1,341 @@
+/*
+ (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>
+
+#ifdef VOODOO_CONNECTION_RAW_DUMP
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+
+extern "C" {
+#include <direct/debug.h>
+#include <direct/list.h>
+#include <direct/mem.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_raw.h>
+#include <voodoo/manager.h>
+#include <voodoo/packet.h>
+
+
+#include <vector>
+
+
+//namespace Voodoo {
+
+D_DEBUG_DOMAIN( Voodoo_Connection, "Voodoo/Connection", "Voodoo Connection" );
+D_DEBUG_DOMAIN( Voodoo_Input, "Voodoo/Input", "Voodoo Input" );
+D_DEBUG_DOMAIN( Voodoo_Output, "Voodoo/Output", "Voodoo Output" );
+
+/**********************************************************************************************************************/
+
+VoodooConnectionRaw::VoodooConnectionRaw( VoodooManager *manager,
+ VoodooLink *link )
+ :
+ VoodooConnectionLink( manager, link ),
+ stop( false ),
+ closed( false )
+{
+ D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this );
+
+ if (link->code) {
+ input.end = 4;
+
+ memcpy( input.buffer, &link->code, sizeof(u32) );
+ }
+}
+
+VoodooConnectionRaw::~VoodooConnectionRaw()
+{
+ D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooConnection );
+}
+
+void
+VoodooConnectionRaw::Start()
+{
+ D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooConnection );
+
+ io = direct_thread_create( DTT_DEFAULT, io_loop_main, this, "Voodoo IO" );
+}
+
+void
+VoodooConnectionRaw::Stop()
+{
+ D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this );
+
+ D_MAGIC_ASSERT( this, VoodooConnection );
+
+ direct_mutex_lock( &output.lock );
+
+ while (!closed && output.packets) {
+ D_DEBUG_AT( Voodoo_Connection, " -> waiting for output packets to be sent...\n" );
+
+ direct_waitqueue_wait( &output.wait, &output.lock );
+ }
+
+ direct_mutex_unlock( &output.lock );
+
+ stop = true;
+
+ link->WakeUp( link );
+
+ /* Wait for manager threads exiting. */
+ direct_thread_join( io );
+ direct_thread_destroy( io );
+
+ VoodooConnectionLink::Stop();
+}
+
+/**********************************************************************************************************************/
+
+void *
+VoodooConnectionRaw::io_loop()
+{
+ D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this );
+
+#ifdef VOODOO_CONNECTION_RAW_DUMP
+ int dump_fd = open("voodoo_write.raw", O_TRUNC|O_CREAT|O_WRONLY, 0660 );
+ int dump_read_fd = open("voodoo_read.raw", O_TRUNC|O_CREAT|O_WRONLY, 0660 );
+#endif
+
+ while (!stop) {
+ D_MAGIC_ASSERT( this, VoodooConnection );
+
+ if (input.start == input.max) {
+ input.start = 0;
+ input.end = 0;
+ input.last = 0;
+ input.max = VOODOO_CONNECTION_LINK_INPUT_BUF_MAX;
+ }
+
+ if (!stop) {
+ DirectResult ret;
+ VoodooChunk chunks[2];
+ VoodooChunk *chunk_read = NULL;
+ VoodooChunk *chunk_write = NULL;
+ size_t last = input.last;
+ VoodooPacket *packet = NULL;
+
+ std::vector<VoodooChunk> chunks_write;
+ std::vector<VoodooChunk> chunks_read;
+
+ if (!output.sending) {
+ direct_mutex_lock( &output.lock );
+
+ if (output.packets) {
+ VoodooPacket *packet = (VoodooPacket*) output.packets;
+
+ D_ASSERT( packet->sending );
+
+ output.sending = packet;
+ output.sent = 0;
+ }
+
+ direct_mutex_unlock( &output.lock );
+ }
+
+ if (output.sending) {
+ packet = output.sending;
+
+ D_ASSERT( packet->sending );
+
+ chunk_write = &chunks[1];
+
+ chunk_write->ptr = (char*) packet->data_start() + output.sent;
+ chunk_write->length = VOODOO_MSG_ALIGN(packet->size()) - output.sent;
+ chunk_write->done = 0;
+
+ chunks_write.push_back( chunks[1] );
+
+ chunk_write = chunks_write.data();
+ }
+
+ if (input.end < input.max && manager->DispatchReady()) {
+ chunk_read = &chunks[0];
+
+ chunk_read->ptr = input.buffer + input.end;
+ chunk_read->length = input.max - input.end;
+ chunk_read->done = 0;
+
+ chunks_read.push_back( chunks[0] );
+
+ chunk_read = chunks_read.data();
+ }
+
+
+ ret = link->SendReceive( link,
+ chunks_write.data(), chunks_write.size(),
+ chunks_read.data(), chunks_read.size() );
+ switch (ret) {
+ case DR_OK:
+ if (chunk_write && chunk_write->done) {
+ D_DEBUG_AT( Voodoo_Output, " -> Sent "_ZD"/"_ZD" bytes...\n", chunk_write->done, chunk_write->length );
+
+#ifdef VOODOO_CONNECTION_RAW_DUMP
+ write( dump_fd, chunk_write->ptr, chunk_write->done );
+#endif
+
+ output.sent += chunk_write->done;
+
+ if (output.sent == VOODOO_MSG_ALIGN(packet->size())) {
+ output.sending = NULL;
+
+ direct_mutex_lock( &output.lock );
+
+ packet->sending = false;
+
+ direct_list_remove( &output.packets, &packet->link );
+
+ direct_mutex_unlock( &output.lock );
+
+ direct_waitqueue_broadcast( &output.wait );
+ }
+ }
+ break;
+
+ case DR_TIMEOUT:
+ //D_DEBUG_AT( Voodoo_Connection, " -> timeout\n" );
+ break;
+
+ case DR_INTERRUPTED:
+ D_DEBUG_AT( Voodoo_Connection, " -> interrupted\n" );
+ break;
+
+ default:
+ if (ret == DR_IO)
+ D_DEBUG_AT( Voodoo_Connection, " -> Connection closed!\n" );
+ else
+ {
+ D_DERROR( ret, "Voodoo/ConnectionRaw: Could not receive data!\n" );
+ exit(0);
+ }
+
+ closed = true;
+
+ manager->handle_disconnect();
+
+ return NULL;
+ }
+
+
+ if (chunk_read && chunk_read->done) {
+ D_DEBUG_AT( Voodoo_Input, " -> Received "_ZD" bytes...\n", chunk_read->done );
+
+#ifdef VOODOO_CONNECTION_RAW_DUMP
+ write( dump_read_fd, chunk_read->ptr, chunk_read->done );
+#endif
+
+ input.end += (size_t) chunk_read->done;
+
+ do {
+ VoodooMessageHeader *header;
+ size_t aligned;
+
+ D_DEBUG_AT( Voodoo_Input, " { LAST "_ZD", INPUT LAST "_ZD" }\n", last, input.last );
+
+ if (input.end - last < 4) {
+ D_DEBUG_AT( Voodoo_Input, " -> ...only "_ZU" bytes left\n", input.end - last );
+ break;
+ }
+
+ /* Get the message header. */
+ header = (VoodooMessageHeader *)(input.buffer + last);
+ aligned = VOODOO_MSG_ALIGN( header->size );
+
+ D_DEBUG_AT( Voodoo_Input, " -> Next message has %d ("_ZD") bytes and is of type %d...\n",
+ header->size, aligned, header->type );
+
+ D_ASSERT( header->size >= (int) sizeof(VoodooMessageHeader) );
+ D_ASSERT( header->size <= MAX_MSG_SIZE );
+
+ if (aligned > input.end - last) {
+ D_DEBUG_AT( Voodoo_Input, " -> ...fetching tail of message.\n" );
+
+ /* Extend the buffer if the message doesn't fit into the default boundary. */
+ if (aligned > input.max - last)
+ input.max = last + aligned;
+
+ break;
+ }
+
+ last += aligned;
+ } while (last < input.end);
+
+ if (last != input.last) {
+ input.last = last;
+
+ D_DEBUG_AT( Voodoo_Input, " { START "_ZD", LAST "_ZD", END "_ZD", MAX "_ZD" }\n",
+ input.start, input.last, input.end, input.max );
+
+ // FIXME: don't copy, but read into packet directly, maybe call manager->GetPacket() at the top of this loop
+ VoodooPacket *p = VoodooPacket::Copy( input.last - input.start, VPHF_NONE,
+ input.last - input.start, input.buffer + input.start );
+
+ manager->DispatchPacket( p );
+
+ input.start = input.last;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**********************************************************************************************************************/
+
+void *
+VoodooConnectionRaw::io_loop_main( DirectThread *thread, void *arg )
+{
+ D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p, thread %p )\n", __func__, arg, thread );
+
+ VoodooConnectionRaw *connection = (VoodooConnectionRaw*) arg;
+
+ return connection->io_loop();
+}
+