diff options
Diffstat (limited to 'Source/DirectFB/lib/voodoo/connection_link.cpp')
-rwxr-xr-x | Source/DirectFB/lib/voodoo/connection_link.cpp | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/Source/DirectFB/lib/voodoo/connection_link.cpp b/Source/DirectFB/lib/voodoo/connection_link.cpp new file mode 100755 index 0000000..b0ae138 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_link.cpp @@ -0,0 +1,331 @@ +/* + (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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> + +extern "C" { +#include <direct/clock.h> +#include <direct/debug.h> +#include <direct/fastlz.h> +#include <direct/hash.h> +#include <direct/interface.h> +#include <direct/list.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_link.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" ); + +/**********************************************************************************************************************/ + +VoodooConnectionLink::VoodooConnectionLink( VoodooManager *manager, + VoodooLink *link ) + : + VoodooConnection( manager, link ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p )\n", __func__, this ); + + input.start = 0; + input.last = 0; + input.end = 0; + input.max = 0; + + output.packets = NULL; + output.sending = NULL; + + /* Initialize all locks. */ + direct_mutex_init( &output.lock ); + + /* Initialize all wait conditions. */ + direct_waitqueue_init( &output.wait ); + + /* Set default buffer limit. */ + input.max = VOODOO_CONNECTION_LINK_INPUT_BUF_MAX; + + /* Allocate buffers. */ + size_t input_buffer_size = VOODOO_CONNECTION_LINK_INPUT_BUF_MAX + VOODOO_PACKET_MAX + sizeof(VoodooPacketHeader); + + input.buffer = (u8*) D_MALLOC( input_buffer_size ); + + D_INFO( "VoodooConnection/Link: Allocated "_ZU" kB input buffer at %p\n", input_buffer_size/1024, input.buffer ); + + direct_tls_register( &output.tls, OutputTLS_Destructor ); +} + +VoodooConnectionLink::~VoodooConnectionLink() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + /* Acquire locks and wake up waiters. */ + direct_mutex_lock( &output.lock ); + direct_waitqueue_broadcast( &output.wait ); + direct_mutex_unlock( &output.lock ); + + /* Destroy conditions. */ + direct_waitqueue_deinit( &output.wait ); + + /* Destroy locks. */ + direct_mutex_deinit( &output.lock ); + + /* Deallocate buffers. */ + D_FREE( input.buffer ); + + direct_tls_unregister( &output.tls ); +} + +/**********************************************************************************************************************/ + +VoodooPacket * +VoodooConnectionLink::GetPacket( size_t length ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p, length "_ZU" )\n", __func__, this, length ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + D_ASSERT( length >= (int) sizeof(VoodooMessageHeader) ); + D_ASSUME( length <= MAX_MSG_SIZE ); + + if (length > MAX_MSG_SIZE) { + D_WARN( _ZU" exceeds maximum message size of %d", length, MAX_MSG_SIZE ); + return NULL; + } + + size_t aligned = VOODOO_MSG_ALIGN( length ); + + + Packets *packets = (Packets*) direct_tls_get( output.tls ); + + if (!packets) { + packets = new Packets( this ); + + direct_tls_set( output.tls, packets ); + } + + VoodooPacket *packet = packets->active; + + if (packet) { + if (packet->append( aligned )) + return packet; + + Flush( packet ); + } + + packet = packets->Get(); + if (packet) { + if (packet->sending) { + direct_mutex_lock( &output.lock ); + + while (packet->sending) + direct_waitqueue_wait( &output.wait, &output.lock ); + + direct_mutex_unlock( &output.lock ); + } + packet->reset( aligned ); + } + + return packet; +} + +void +VoodooConnectionLink::PutPacket( VoodooPacket *packet, bool flush ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p, %sflush )\n", __func__, this, flush ? "" : "NO " ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + Packets *packets = (Packets*) direct_tls_get( output.tls ); + + D_ASSERT( packets != NULL ); + D_ASSERT( packet == packets->active ); + + if (flush) { + Flush( packet ); + + packets->active = NULL; + } +} + +void +VoodooConnectionLink::Stop() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + direct_mutex_lock( &output.lock ); + + while (output.packets) { + VoodooPacket *packet = (VoodooPacket*) output.packets; + + D_DEBUG_AT( Voodoo_Connection, " -> discarding output packet %p\n", packet ); + + D_ASSUME( packet->sending ); + + packet->sending = false; + + direct_list_remove( &output.packets, &packet->link ); + } + + direct_mutex_unlock( &output.lock ); + + direct_waitqueue_broadcast( &output.wait ); +} + +void +VoodooConnectionLink::Flush( VoodooPacket *packet ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p, packet %p )\n", __func__, this, packet ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + direct_mutex_lock( &output.lock ); + + D_ASSERT( !direct_list_contains_element_EXPENSIVE( output.packets, &packet->link ) ); + + D_ASSERT( !packet->sending ); + + packet->sending = true; + + direct_list_append( &output.packets, &packet->link ); + + direct_mutex_unlock( &output.lock ); + + link->WakeUp( link ); +} + +void +VoodooConnectionLink::OutputTLS_Destructor( void *ptr ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( ptr %p )\n", __func__, ptr ); + + Packets *packets = (Packets*) ptr; + + delete packets; + + D_DEBUG_AT( Voodoo_Connection, " -> OutputTLS_Destructor done\n" ); +} + +VoodooConnectionLink::Packets::Packets( VoodooConnectionLink* connection ) + : + magic(0), + connection(connection), + next(0), + num(0), + active(NULL) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::Packets::%s( %p )\n", __func__, this ); + + memset( packets, 0, sizeof(packets) ); + + D_MAGIC_SET( this, Packets ); +} + +VoodooConnectionLink::Packets::~Packets() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::Packets::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, Packets ); + + for (size_t i=0; i<num; i++) { + if (packets[i]) { + D_DEBUG_AT( Voodoo_Connection, " -> destroying output packet "_ZU" (%p)\n", i, packets[i] ); + + if (packets[i]->sending) { + direct_mutex_lock( &connection->output.lock ); + + while (packets[i]->sending) { + D_DEBUG_AT( Voodoo_Connection, " -> packet sending, waiting...\n" ); + + direct_waitqueue_wait( &connection->output.wait, &connection->output.lock ); + } + + direct_mutex_unlock( &connection->output.lock ); + } + + D_FREE( packets[i] ); + } + } +} + +VoodooPacket * +VoodooConnectionLink::Packets::Get() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::Packets::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, Packets ); + + VoodooPacket *packet; + + if (num < VOODOO_CONNECTION_PACKET_NUM_OUTPUT) { + packet = packets[num] = VoodooPacket::New( 0 ); + + D_DEBUG_AT( Voodoo_Connection, " -> new ["_ZU"] %p\n", num, packet ); + + num++; + } + else { + packet = packets[next]; + + next = (next+1) % VOODOO_CONNECTION_PACKET_NUM_OUTPUT; + + D_DEBUG_AT( Voodoo_Connection, " -> reusing %p\n", packet ); + } + + active = packet; + + return packet; +} + |