commit some crappy threading code for usbgecko

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6870 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman 2011-01-17 07:44:21 +00:00
parent d89d730778
commit fdd56f4621
2 changed files with 133 additions and 74 deletions

View File

@ -17,17 +17,47 @@
#include "EXI_Device.h" #include "EXI_Device.h"
#include "EXI_DeviceGecko.h" #include "EXI_DeviceGecko.h"
//#pragma optimize("",off)
THREAD_RETURN ClientThreadFunc(void *arg)
{
((GeckoSockServer*)arg)->ClientThread();
return 0;
}
#include "SFML/Network.hpp" int GeckoSockServer::client_count;
#include "Thread.h" Common::Thread *GeckoSockServer::connectionThread = NULL;
#include <queue> volatile bool GeckoSockServer::server_running;
std::queue<sf::SocketTCP> GeckoSockServer::waiting_socks;
Common::CriticalSection GeckoSockServer::connection_lock;
static Common::Thread *connectionThread = NULL; GeckoSockServer::GeckoSockServer()
static std::queue<sf::SocketTCP> waiting_socks; : clientThread(NULL)
static Common::CriticalSection cs_gecko; , client_running(false)
namespace { volatile bool server_running; } {
if (!connectionThread)
connectionThread = new Common::Thread(&GeckoConnectionWaiter, (void*)0);
}
static THREAD_RETURN GeckoConnectionWaiter(void*) GeckoSockServer::~GeckoSockServer()
{
if (client_running)
{
client_running = false;
clientThread->WaitForDeath();
}
delete clientThread;
clientThread = NULL;
if (--client_count <= 0)
{
server_running = false;
connectionThread->WaitForDeath();
delete connectionThread;
connectionThread = NULL;
}
}
THREAD_RETURN GeckoSockServer::GeckoConnectionWaiter(void*)
{ {
server_running = true; server_running = true;
@ -45,9 +75,9 @@ static THREAD_RETURN GeckoConnectionWaiter(void*)
{ {
if (server.Accept(new_client) == sf::Socket::Done) if (server.Accept(new_client) == sf::Socket::Done)
{ {
cs_gecko.Enter(); connection_lock.Enter();
waiting_socks.push(new_client); waiting_socks.push(new_client);
cs_gecko.Leave(); connection_lock.Leave();
} }
SLEEP(1); SLEEP(1);
} }
@ -55,73 +85,79 @@ static THREAD_RETURN GeckoConnectionWaiter(void*)
return 0; return 0;
} }
void GeckoConnectionWaiter_Shutdown() bool GeckoSockServer::GetAvailableSock(sf::SocketTCP &sock_to_fill)
{
server_running = false;
if (connectionThread)
{
connectionThread->WaitForDeath();
delete connectionThread;
connectionThread = NULL;
}
}
static bool GetAvailableSock(sf::SocketTCP& sock_to_fill)
{ {
bool sock_filled = false; bool sock_filled = false;
cs_gecko.Enter(); connection_lock.Enter();
if (waiting_socks.size()) if (waiting_socks.size())
{ {
sock_to_fill = waiting_socks.front(); sock_to_fill = waiting_socks.front();
if (clientThread)
{
if (client_running)
{
client_running = false;
clientThread->WaitForDeath();
}
delete clientThread;
clientThread = NULL;
}
clientThread = new Common::Thread(ClientThreadFunc, this);
client_count++;
waiting_socks.pop(); waiting_socks.pop();
sock_filled = true; sock_filled = true;
} }
cs_gecko.Leave(); connection_lock.Leave();
return sock_filled; return sock_filled;
} }
GeckoSockServer::GeckoSockServer() void GeckoSockServer::ClientThread()
{ {
if (!connectionThread) client_running = true;
connectionThread = new Common::Thread(GeckoConnectionWaiter, (void*)0);
} Common::SetCurrentThreadName("Gecko Client");
client.SetBlocking(false);
while (client_running)
{
u8 data;
std::size_t got = 0;
transfer_lock.Enter();
if (client.Receive((char*)&data, sizeof(data), got)
== sf::Socket::Disconnected)
client_running = false;
if (got)
recv_fifo.push(data);
if (send_fifo.size())
{
if (client.Send((char*)&send_fifo.front(), sizeof(u8))
== sf::Socket::Disconnected)
client_running = false;
send_fifo.pop();
}
transfer_lock.Leave();
SLEEP(1);
}
GeckoSockServer::~GeckoSockServer()
{
client.Close(); client.Close();
} }
CEXIGecko::CEXIGecko()
: m_uPosition(0)
, recv_fifo(false)
{
}
void CEXIGecko::SetCS(int cs)
{
if (cs)
m_uPosition = 0;
}
bool CEXIGecko::IsPresent()
{
return true;
}
void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize) void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
{ {
// We don't really care about _uSize
(void)_uSize;
if (!client.IsValid()) if (!client.IsValid())
if (!GetAvailableSock(client)) if (!GetAvailableSock(client))
{} ;// TODO nothing for now return;
// for debug // for debug
u32 oldval = _uData; u32 oldval = _uData;
// TODO do we really care about _uSize?
u8 data = 0;
std::size_t got;
switch (_uData >> 28) switch (_uData >> 28)
{ {
@ -130,26 +166,31 @@ void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
break; break;
case CMD_LED_ON: case CMD_LED_ON:
break; break;
// maybe should only | 2bytes?
case CMD_INIT: case CMD_INIT:
_uData = ident; _uData = ident;
break; break;
// PC -> Gecko // PC -> Gecko
// |= 0x08000000 if successful
case CMD_RECV: case CMD_RECV:
// TODO recv transfer_lock.Enter();
client.Receive((char*)&data, sizeof(data), got); if (recv_fifo.size())
recv_fifo = !!got; {
if (recv_fifo) _uData = 0x08000000 | (recv_fifo.front() << 16);
_uData = 0x08000000 | (data << 16); recv_fifo.pop();
}
transfer_lock.Leave();
break; break;
// Gecko -> PC // Gecko -> PC
// |= 0x04000000 if successful
case CMD_SEND: case CMD_SEND:
data = (_uData >> 20) & 0xff; transfer_lock.Enter();
// TODO send send_fifo.push(_uData >> 20);
client.Send((char*)&data, sizeof(data)); transfer_lock.Leave();
// If successful _uData = 0x04000000;
_uData |= 0x04000000;
break; break;
// Check if ok for Gecko -> PC, or FIFO full // Check if ok for Gecko -> PC, or FIFO full
// |= 0x04000000 if FIFO is not full // |= 0x04000000 if FIFO is not full
case CMD_CHK_TX: case CMD_CHK_TX:
@ -158,13 +199,14 @@ void CEXIGecko::ImmReadWrite(u32 &_uData, u32 _uSize)
// Check if data in FIFO for PC -> Gecko, or FIFO empty // Check if data in FIFO for PC -> Gecko, or FIFO empty
// |= 0x04000000 if data in recv FIFO // |= 0x04000000 if data in recv FIFO
case CMD_CHK_RX: case CMD_CHK_RX:
//_uData = recv_fifo ? 0x04000000 : 0; transfer_lock.Enter();
_uData = 0x04000000; _uData = recv_fifo.size() ? 0x04000000 : 0;
transfer_lock.Leave();
break; break;
default: default:
ERROR_LOG(EXPANSIONINTERFACE, "Uknown USBGecko command %x", _uData); ERROR_LOG(EXPANSIONINTERFACE, "Uknown USBGecko command %x", _uData);
break; break;
} }
if (_uData) { ERROR_LOG(EXPANSIONINTERFACE, "rw %x %08x %08x", oldval, _uData, _uSize); }
} }
//#pragma optimize("",on)

View File

@ -19,6 +19,8 @@
#define _EXIDEVICE_GECKO_H #define _EXIDEVICE_GECKO_H
#include "SFML/Network.hpp" #include "SFML/Network.hpp"
#include "Thread.h"
#include <queue>
class GeckoSockServer class GeckoSockServer
: public sf::SocketTCP : public sf::SocketTCP
@ -26,9 +28,28 @@ class GeckoSockServer
public: public:
GeckoSockServer(); GeckoSockServer();
~GeckoSockServer(); ~GeckoSockServer();
bool GetAvailableSock(sf::SocketTCP &sock_to_fill);
//private: // Client for this server object
sf::SocketTCP client; sf::SocketTCP client;
void ClientThread();
Common::Thread *clientThread;
Common::CriticalSection transfer_lock;
std::queue<u8> send_fifo;
std::queue<u8> recv_fifo;
private:
static int client_count;
volatile bool client_running;
// Only ever one server thread
static THREAD_RETURN GeckoConnectionWaiter(void*);
static volatile bool server_running;
static Common::Thread *connectionThread;
static std::queue<sf::SocketTCP> waiting_socks;
static Common::CriticalSection connection_lock;
}; };
class CEXIGecko class CEXIGecko
@ -36,9 +57,8 @@ class CEXIGecko
, private GeckoSockServer , private GeckoSockServer
{ {
public: public:
CEXIGecko(); CEXIGecko() {}
void SetCS(int _iCS); bool IsPresent() { return true; }
bool IsPresent();
void ImmReadWrite(u32 &_uData, u32 _uSize); void ImmReadWrite(u32 &_uData, u32 _uSize);
private: private:
@ -53,9 +73,6 @@ private:
CMD_CHK_RX = 0xd, CMD_CHK_RX = 0xd,
}; };
u32 m_uPosition;
bool recv_fifo;
static const u32 ident = 0x04700000; static const u32 ident = 0x04700000;
}; };