beginning -- this is a snapshot -- of rewrite of how relay keeps

multiple thread out of a single game.  Add new class that locks
per-cid and start using it.  Very incomplete.
This commit is contained in:
Andy2 2011-06-22 06:51:26 -07:00
parent c87df3ce16
commit 3ebcc01e86
6 changed files with 432 additions and 152 deletions

View file

@ -30,6 +30,7 @@ SRC = \
states.cpp \ states.cpp \
timermgr.cpp \ timermgr.cpp \
tpool.cpp \ tpool.cpp \
cidlock.cpp \
xwrelay.cpp \ xwrelay.cpp \
# STATIC ?= -static # STATIC ?= -static

148
xwords4/relay/cidlock.cpp Normal file
View file

@ -0,0 +1,148 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2005-2011 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <assert.h>
#include "cidlock.h"
#include "mlock.h"
CidLock* CidLock::s_instance = NULL;
CidLock::CidLock() : m_nextCID(0)
{
pthread_mutex_init( &m_infos_mutex, NULL );
pthread_cond_init( &m_infos_condvar, NULL );
}
CidLock::~CidLock()
{
pthread_mutex_destroy( &m_infos_mutex );
}
void
CidLock::print_claimed()
{
char buf[256] = {0};
int len = 0;
// Assume we have the mutex!!!!
map< CookieID, CidInfo*>::iterator iter = m_infos.begin();
while ( iter != m_infos.end() ) {
CidInfo* info = iter->second;
if ( 0 != info->GetOwner() ) {
len += snprintf( &buf[len], sizeof(buf)-len, "%d,",
info->GetCid() );
}
++iter;
}
logf( XW_LOGINFO, "%s: claimed: %s", __func__, buf );
}
CidInfo*
CidLock::Claim( CookieID cid )
{
logf( XW_LOGINFO, "%s(%d)", __func__, cid );
CidInfo* info = NULL;
for ( ; ; ) {
MutexLock ml( &m_infos_mutex );
if ( 0 == cid ) {
cid = ++m_nextCID;
logf( XW_LOGINFO, "%s: assigned cid: %d", __func__, cid );
}
map< CookieID, CidInfo*>::iterator iter = m_infos.find( cid );
if ( iter == m_infos.end() ) { // not there at all
info = new CidInfo( cid );
m_infos.insert( pair<CookieID, CidInfo*>( cid, info ) );
} else {
if ( 0 == iter->second->GetOwner() ) {
info = iter->second;
}
}
if ( NULL != info ) { // we're done
info->SetOwner( pthread_self() );
print_claimed();
break;
}
logf( XW_LOGINFO, "%s(%d): waiting....", __func__, cid );
pthread_cond_wait( &m_infos_condvar, &m_infos_mutex );
}
logf( XW_LOGINFO, "%s(%d): DONE", __func__, cid );
return info;
}
CidInfo*
CidLock::ClaimSocket( int sock )
{
CidInfo* info = NULL;
logf( XW_LOGINFO, "%s(%d)", __func__, sock );
MutexLock ml( &m_infos_mutex );
map< CookieID, CidInfo*>::iterator iter = m_infos.begin();
while ( iter != m_infos.end() ) {
if ( sock == iter->second->GetSocket() ) {
info = iter->second;
break;
}
++iter;
}
logf( XW_LOGINFO, "%s(%d): DONE", __func__, info? info->GetCid():0 );
return info;
}
void
CidLock::Associate( const CookieRef* cref, int socket )
{
MutexLock ml( &m_infos_mutex );
map< CookieID, CidInfo*>::iterator iter = m_infos.begin();
while ( iter != m_infos.end() ) {
if ( cref == iter->second->GetRef() ) {
iter->second->SetSocket( socket );
break;
}
++iter;
}
}
void
CidLock::DisAssociate( const CookieRef* cref, int socket )
{
Associate( cref, 0 );
}
void
CidLock::Relinquish( CidInfo* claim )
{
CookieID cid = claim->GetCid();
logf( XW_LOGINFO, "%s(%d)", __func__, cid );
MutexLock ml( &m_infos_mutex );
map< CookieID, CidInfo*>::iterator iter = m_infos.find( cid );
assert( iter != m_infos.end() );
iter->second->SetOwner( 0 );
print_claimed();
pthread_cond_signal( &m_infos_condvar );
logf( XW_LOGINFO, "%s(%d): DONE", __func__, cid );
}

86
xwords4/relay/cidlock.h Normal file
View file

@ -0,0 +1,86 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2005-2011 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _CIDLOCK_H_
#define _CIDLOCK_H_
#include <map>
#include "xwrelay.h"
#include "cref.h"
using namespace std;
class CidInfo {
public:
CidInfo( CookieID cid )
:m_cid(cid),
m_cref(NULL),
m_owner(NULL),
m_socket(0) {}
CookieID GetCid( void ) { return m_cid; }
CookieRef* GetRef( void ) { return m_cref; }
pthread_t GetOwner( void ) { return m_owner; }
int GetSocket( void ) { return m_socket; }
void SetRef( CookieRef* cref ) { m_cref = cref; }
void SetOwner( pthread_t owner ) { m_owner = owner; }
void SetSocket( int socket ) { m_socket = socket; }
private:
CookieID m_cid;
CookieRef* m_cref;
pthread_t m_owner;
int m_socket;
};
class CidLock {
public:
static CidLock* GetInstance() {
if ( NULL == s_instance ) {
s_instance = new CidLock();
}
return s_instance;
}
CidInfo* Claim( void ) { return Claim(0); }
CidInfo* Claim( CookieID cid );
CidInfo* ClaimSocket( int sock );
void Relinquish( CidInfo* claim );
void Associate( const CookieRef* cref, int socket );
void DisAssociate( const CookieRef* cref, int socket );
private:
CidLock();
~CidLock();
void print_claimed();
static CidLock* s_instance;
map< CookieID, CidInfo*> m_infos;
pthread_mutex_t m_infos_mutex;
pthread_cond_t m_infos_condvar;
int m_nextCID;
}; /* CidLock */
#endif

View file

@ -1283,7 +1283,7 @@ CookieRef::s_checkAllConnected( void* closure )
{ {
/* Need to ensure */ /* Need to ensure */
CookieRef* self = (CookieRef*)closure; CookieRef* self = (CookieRef*)closure;
SafeCref scr(self); SafeCref scr(self->GetCookieID(), false );
scr.CheckAllConnected(); scr.CheckAllConnected();
} }
@ -1294,7 +1294,7 @@ CookieRef::s_checkAck( void* closure )
CookieRef* self = at->m_this; CookieRef* self = at->m_this;
if ( NULL != self ) { if ( NULL != self ) {
at->m_this = NULL; at->m_this = NULL;
SafeCref scr(self); SafeCref scr(self->GetCookieID(), false );
scr.CheckNotAcked( at->m_hid ); scr.CheckNotAcked( at->m_hid );
} }
} }

View file

@ -55,17 +55,16 @@ CRefMgr::Get()
} /* Get */ } /* Get */
CRefMgr::CRefMgr() CRefMgr::CRefMgr()
: m_nextCID(0) : m_nRoomsFilled(0)
, m_nRoomsFilled(0)
, m_startTime(time(NULL)) , m_startTime(time(NULL))
{ {
/* should be using pthread_once() here */ /* should be using pthread_once() here */
pthread_mutex_init( &m_SocketStuffMutex, NULL ); pthread_mutex_init( &m_SocketStuffMutex, NULL );
pthread_mutex_init( &m_nextCIDMutex, NULL );
pthread_mutex_init( &m_roomsFilledMutex, NULL ); pthread_mutex_init( &m_roomsFilledMutex, NULL );
pthread_mutex_init( &m_freeList_mutex, NULL ); pthread_mutex_init( &m_freeList_mutex, NULL );
pthread_rwlock_init( &m_cookieMapRWLock, NULL ); pthread_rwlock_init( &m_cookieMapRWLock, NULL );
m_db = DBMgr::Get(); m_db = DBMgr::Get();
m_cidlock = CidLock::GetInstance();
} }
CRefMgr::~CRefMgr() CRefMgr::~CRefMgr()
@ -101,21 +100,21 @@ CRefMgr::CloseAll()
} }
cref = iter->second; cref = iter->second;
{ {
SafeCref scr( cref ); /* cref */ SafeCref scr( cref->GetCookieID(), false ); /* cref */
scr.Shutdown(); scr.Shutdown();
} }
} }
} }
} /* CloseAll */ } /* CloseAll */
CookieID /* CookieID */
CRefMgr::nextCID( const char* connName ) /* CRefMgr::nextCID( const char* connName ) */
{ /* { */
/* Later may want to guarantee that wrap-around doesn't cause an overlap. /* /\* Later may want to guarantee that wrap-around doesn't cause an overlap. */
But that's really only a theoretical possibility. */ /* But that's really only a theoretical possibility. *\/ */
MutexLock ml(&m_nextCIDMutex); /* MutexLock ml(&m_nextCIDMutex); */
return ++m_nextCID; /* return ++m_nextCID; */
} /* nextCID */ /* } /\* nextCID *\/ */
void void
CRefMgr::IncrementFullCount( void ) CRefMgr::IncrementFullCount( void )
@ -179,7 +178,7 @@ CRefMgr::GetStats( CrefMgrInfo& mgrInfo )
info.m_startTime = cref->GetStarttime(); info.m_startTime = cref->GetStarttime();
info.m_langCode = cref->GetLangCode(); info.m_langCode = cref->GetLangCode();
SafeCref sc(cref); SafeCref sc(cref->GetCookieID(), false );
sc.GetHostsConnected( &info.m_hostsIds, &info.m_hostSeeds, sc.GetHostsConnected( &info.m_hostsIds, &info.m_hostSeeds,
&info.m_hostIps ); &info.m_hostIps );
@ -229,13 +228,13 @@ CRefMgr::getFromFreeList( void )
} }
/* connect case */ /* connect case */
CookieRef* CidInfo*
CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket, CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket,
int nPlayersH, int nPlayersT, int langCode, int nPlayersH, int nPlayersT, int langCode,
int seed, bool wantsPublic, int seed, bool wantsPublic,
bool makePublic, bool* seenSeed ) bool makePublic, bool* seenSeed )
{ {
CookieRef* cref; CidInfo* cinfo;
CookieID cid; CookieID cid;
char connNameBuf[MAX_CONNNAME_LEN+1] = {0}; char connNameBuf[MAX_CONNNAME_LEN+1] = {0};
int alreadyHere = 0; int alreadyHere = 0;
@ -258,11 +257,13 @@ CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket,
} }
if ( cid > 0 ) { if ( cid > 0 ) {
cref = getCookieRef_impl( cid ); cinfo = getCookieRef_impl( cid );
} else { } else {
cid = nextCID( NULL ); cinfo = m_cidlock->Claim();
cref = AddNew( cookie, connNameBuf, cid, langCode, cid = cinfo->GetCid();
nPlayersT, alreadyHere ); CookieRef* cref = AddNew( cookie, connNameBuf, cid, langCode,
nPlayersT, alreadyHere );
cinfo->SetRef( cref );
if ( !connNameBuf[0] ) { /* didn't exist in DB */ if ( !connNameBuf[0] ) { /* didn't exist in DB */
m_db->AddNew( cookie, cref->ConnName(), cid, langCode, nPlayersT, m_db->AddNew( cookie, cref->ConnName(), cid, langCode, nPlayersT,
wantsPublic || makePublic ); wantsPublic || makePublic );
@ -271,17 +272,18 @@ CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket,
} }
} }
return cref; return cinfo;
} /* getMakeCookieRef */ } /* getMakeCookieRef */
/* reconnect case */ /* reconnect case */
CookieRef* CidInfo*
CRefMgr::getMakeCookieRef( const char* connName, const char* cookie, CRefMgr::getMakeCookieRef( const char* connName, const char* cookie,
HostID hid, int socket, int nPlayersH, HostID hid, int socket, int nPlayersH,
int nPlayersS, int seed, int langCode, int nPlayersS, int seed, int langCode,
bool isPublic, bool* isDead ) bool isPublic, bool* isDead )
{ {
CookieRef* cref = NULL; CookieRef* cref = NULL;
CidInfo* cinfo;
/* fetch these from DB */ /* fetch these from DB */
char curCookie[MAX_INVITE_LEN+1]; char curCookie[MAX_INVITE_LEN+1];
@ -293,11 +295,13 @@ CRefMgr::getMakeCookieRef( const char* connName, const char* cookie,
&curLangCode, &nPlayersT, &nAlreadyHere, &curLangCode, &nPlayersT, &nAlreadyHere,
isDead ); isDead );
if ( 0 != cid ) { /* already open */ if ( 0 != cid ) { /* already open */
cref = getCookieRef_impl( cid ); cinfo = getCookieRef_impl( cid );
} else { } else {
CookieID cid;
/* The entry may not even be in the DB, e.g. if it got deleted. /* The entry may not even be in the DB, e.g. if it got deleted.
Deal with that possibility by taking the caller's word for it. */ Deal with that possibility by taking the caller's word for it. */
CookieID cid = nextCID( NULL ); cinfo = m_cidlock->Claim();
cid = cinfo->GetCid();
if ( nPlayersT == 0 ) { /* wasn't in the DB */ if ( nPlayersT == 0 ) { /* wasn't in the DB */
m_db->AddNew( cookie, connName, cid, langCode, nPlayersS, isPublic ); m_db->AddNew( cookie, connName, cid, langCode, nPlayersS, isPublic );
@ -309,15 +313,17 @@ CRefMgr::getMakeCookieRef( const char* connName, const char* cookie,
cref = AddNew( cookie, connName, cid, curLangCode, nPlayersT, cref = AddNew( cookie, connName, cid, curLangCode, nPlayersT,
nAlreadyHere ); nAlreadyHere );
cinfo->SetRef( cref );
m_db->AddCID( connName, cid ); m_db->AddCID( connName, cid );
} }
return cref; return cinfo;
} /* getMakeCookieRef */ } /* getMakeCookieRef */
CookieRef* CidInfo*
CRefMgr::getMakeCookieRef( const char* const connName, bool* isDead ) CRefMgr::getMakeCookieRef( const char* const connName, bool* isDead )
{ {
CookieRef* cref = NULL; CookieRef* cref = NULL;
CidInfo* cinfo;
char curCookie[MAX_INVITE_LEN+1]; char curCookie[MAX_INVITE_LEN+1];
int curLangCode; int curLangCode;
int nPlayersT = 0; int nPlayersT = 0;
@ -327,23 +333,25 @@ CRefMgr::getMakeCookieRef( const char* const connName, bool* isDead )
&curLangCode, &nPlayersT, &nAlreadyHere, &curLangCode, &nPlayersT, &nAlreadyHere,
isDead ); isDead );
if ( 0 != cid ) { /* already open */ if ( 0 != cid ) { /* already open */
cref = getCookieRef_impl( cid ); cinfo = getCookieRef_impl( cid );
} else { } else {
if ( nPlayersT == 0 ) { /* wasn't in the DB */ if ( nPlayersT == 0 ) { /* wasn't in the DB */
/* do nothing; insufficient info to fake it */ /* do nothing; insufficient info to fake it */
} else { } else {
CookieID cid = nextCID( NULL ); cinfo = m_cidlock->Claim();
cref = AddNew( curCookie, connName, cid, curLangCode, nPlayersT, cref = AddNew( curCookie, connName, cinfo->GetCid(), curLangCode,
nAlreadyHere ); nPlayersT, nAlreadyHere );
m_db->AddCID( connName, cid ); cinfo->SetRef( cref );
m_db->AddCID( connName, cinfo->GetCid() );
} }
} }
return cref; return cinfo;
} }
bool bool
CRefMgr::Associate( int socket, CookieRef* cref ) CRefMgr::Associate( int socket, CookieRef* cref )
{ {
m_cidlock->Associate( cref, socket );
MutexLock ml( &m_SocketStuffMutex ); MutexLock ml( &m_SocketStuffMutex );
return Associate_locked( socket, cref ); return Associate_locked( socket, cref );
} }
@ -372,6 +380,7 @@ CRefMgr::Associate_locked( int socket, CookieRef* cref )
void void
CRefMgr::Disassociate_locked( int socket, CookieRef* cref ) CRefMgr::Disassociate_locked( int socket, CookieRef* cref )
{ {
m_cidlock->DisAssociate( cref, socket );
SocketMap::iterator iter = m_SocketStuff.find( socket ); SocketMap::iterator iter = m_SocketStuff.find( socket );
if ( iter == m_SocketStuff.end() ) { if ( iter == m_SocketStuff.end() ) {
logf( XW_LOGERROR, "can't find SocketStuff for socket %d", socket ); logf( XW_LOGERROR, "can't find SocketStuff for socket %d", socket );
@ -457,24 +466,26 @@ CRefMgr::MakeSocketsIterator()
return iter; return iter;
} }
CookieRef* CidInfo*
CRefMgr::getCookieRef( CookieID cookieID ) CRefMgr::getCookieRef( CookieID cookieID )
{ {
return getCookieRef_impl( cookieID ); return getCookieRef_impl( cookieID );
} /* getCookieRef */ } /* getCookieRef */
CookieRef* CidInfo*
CRefMgr::getCookieRef( int socket ) CRefMgr::getCookieRef( int socket )
{ {
CookieRef* cref = NULL; CidInfo* cinfo = m_cidlock->ClaimSocket( socket );
MutexLock ml( &m_SocketStuffMutex ); /* if ( NULL == cinfo ) { */
SocketMap::iterator iter = m_SocketStuff.find( socket ); /* MutexLock ml( &m_SocketStuffMutex ); */
if ( iter != m_SocketStuff.end() ) { /* SocketMap::iterator iter = m_SocketStuff.find( socket ); */
SocketStuff* stuff = iter->second; /* if ( iter != m_SocketStuff.end() ) { */
cref = stuff->m_cref; /* SocketStuff* stuff = iter->second; */
} /* cinfo = m_cidlock->Claim( stuff->m_cref->GetCookieID() ); */
/* } */
/* } */
return cref; return cinfo;
} /* getCookieRef */ } /* getCookieRef */
#ifdef RELAY_HEARTBEAT #ifdef RELAY_HEARTBEAT
@ -566,8 +577,9 @@ CRefMgr::Recycle_locked( CookieRef* cref )
void void
CRefMgr::Recycle( CookieID id ) CRefMgr::Recycle( CookieID id )
{ {
CookieRef* cref = getCookieRef( id ); CidInfo* cinfo = getCookieRef( id );
if ( cref != NULL ) { if ( cinfo != NULL ) {
CookieRef* cref = cinfo->GetRef();
cref->Lock(); cref->Lock();
Recycle_locked( cref ); Recycle_locked( cref );
} }
@ -580,22 +592,24 @@ CRefMgr::Recycle( const char* connName )
Recycle( id ); Recycle( id );
} /* Delete */ } /* Delete */
CookieRef* CidInfo*
CRefMgr::getCookieRef_impl( CookieID cookieID ) CRefMgr::getCookieRef_impl( CookieID cid )
{ {
CookieRef* ref = NULL; CidInfo* info = m_cidlock->Claim( cid );
RWReadLock rwl( &m_cookieMapRWLock ); /* CookieRef* ref = NULL; */
/* RWReadLock rwl( &m_cookieMapRWLock ); */
CookieMap::iterator iter = m_cookieMap.find( cookieID ); /* CookieMap::iterator iter = m_cookieMap.find( cid ); */
while ( iter != m_cookieMap.end() ) { /* while ( iter != m_cookieMap.end() ) { */
CookieRef* second = iter->second; /* CookieRef* second = iter->second; */
if ( second->GetCookieID() == cookieID ) { /* if ( second->GetCookieID() == cid ) { */
ref = second; /* ref = second; */
break; /* break; */
} /* } */
++iter; /* ++iter; */
} /* } */
return ref; /* info->SetRef( ref ); */
return info;
} }
#ifdef RELAY_HEARTBEAT #ifdef RELAY_HEARTBEAT
@ -661,20 +675,21 @@ CookieMapIterator::Next()
SafeCref::SafeCref( const char* cookie, int socket, int nPlayersH, int nPlayersS, SafeCref::SafeCref( const char* cookie, int socket, int nPlayersH, int nPlayersS,
unsigned short gameSeed, int langCode, bool wantsPublic, unsigned short gameSeed, int langCode, bool wantsPublic,
bool makePublic ) bool makePublic )
: m_cref( NULL ) : m_cinfo( NULL )
, m_mgr( CRefMgr::Get() ) , m_mgr( CRefMgr::Get() )
, m_isValid( false ) , m_isValid( false )
, m_seenSeed( false ) , m_seenSeed( false )
{ {
CookieRef* cref; CidInfo* cinfo;
cref = m_mgr->getMakeCookieRef( cookie, 0, socket, cinfo = m_mgr->getMakeCookieRef( cookie, 0, socket,
nPlayersH, nPlayersS, langCode, nPlayersH, nPlayersS, langCode,
gameSeed, wantsPublic, makePublic, gameSeed, wantsPublic, makePublic,
&m_seenSeed ); &m_seenSeed );
if ( cref != NULL ) { if ( cinfo != NULL ) {
CookieRef* cref = cinfo->GetRef();
m_locked = cref->Lock(); m_locked = cref->Lock();
m_cref = cref; m_cinfo = cinfo;
m_isValid = true; m_isValid = true;
} }
} }
@ -684,20 +699,20 @@ SafeCref::SafeCref( const char* connName, const char* cookie, HostID hid,
int socket, int nPlayersH, int nPlayersS, int socket, int nPlayersH, int nPlayersS,
unsigned short gameSeed, int langCode, unsigned short gameSeed, int langCode,
bool wantsPublic, bool makePublic ) bool wantsPublic, bool makePublic )
: m_cref( NULL ) : m_cinfo( NULL )
, m_mgr( CRefMgr::Get() ) , m_mgr( CRefMgr::Get() )
, m_isValid( false ) , m_isValid( false )
{ {
CookieRef* cref; CidInfo* cinfo;
assert( hid <= 4 ); /* no more than 4 hosts */ assert( hid <= 4 ); /* no more than 4 hosts */
bool isDead = false; bool isDead = false;
cref = m_mgr->getMakeCookieRef( connName, cookie, hid, socket, nPlayersH, cinfo = m_mgr->getMakeCookieRef( connName, cookie, hid, socket, nPlayersH,
nPlayersS, gameSeed, langCode, nPlayersS, gameSeed, langCode,
wantsPublic || makePublic, &isDead ); wantsPublic || makePublic, &isDead );
if ( cref != NULL ) { if ( cinfo != NULL ) {
m_locked = cref->Lock(); m_locked = cinfo->GetRef()->Lock();
m_cref = cref; m_cinfo = cinfo;
m_isValid = true; m_isValid = true;
m_dead = isDead; m_dead = isDead;
} }
@ -705,63 +720,70 @@ SafeCref::SafeCref( const char* connName, const char* cookie, HostID hid,
/* ConnName case -- must exist */ /* ConnName case -- must exist */
SafeCref::SafeCref( const char* const connName ) SafeCref::SafeCref( const char* const connName )
: m_cref( NULL ) : m_cinfo( NULL )
, m_mgr( CRefMgr::Get() ) , m_mgr( CRefMgr::Get() )
, m_isValid( false ) , m_isValid( false )
{ {
bool isDead = false; bool isDead = false;
CookieRef* cref = m_mgr->getMakeCookieRef( connName, &isDead ); CidInfo* cinfo = m_mgr->getMakeCookieRef( connName, &isDead );
if ( cref != NULL ) { if ( cinfo != NULL ) {
m_locked = cref->Lock(); m_locked = cinfo->GetRef()->Lock();
m_cref = cref; m_cinfo = cinfo;
m_isValid = true; m_isValid = true;
m_dead = isDead; m_dead = isDead;
} }
} }
SafeCref::SafeCref( CookieID connID, bool failOk ) SafeCref::SafeCref( CookieID connID, bool failOk )
: m_cref( NULL ) : m_cinfo( NULL )
, m_mgr( CRefMgr::Get() ) , m_mgr( CRefMgr::Get() )
, m_isValid( false ) , m_isValid( false )
{ {
CookieRef* cref = m_mgr->getCookieRef( connID ); CidInfo* cinfo = m_mgr->getCookieRef( connID );
if ( cref != NULL ) { /* known cookie? */ if ( cinfo != NULL ) { /* known cookie? */
CookieRef* cref = cinfo->GetRef();
m_locked = cref->Lock(); m_locked = cref->Lock();
m_isValid = m_locked && connID == cref->GetCookieID(); m_isValid = m_locked && connID == cref->GetCookieID();
m_cref = cref; m_cinfo = cinfo;
} }
} }
SafeCref::SafeCref( int socket ) SafeCref::SafeCref( int socket )
: m_cref( NULL ) : m_cinfo( NULL )
, m_mgr( CRefMgr::Get() ) , m_mgr( CRefMgr::Get() )
, m_isValid( false ) , m_isValid( false )
{ {
CookieRef* cref = m_mgr->getCookieRef( socket ); CidInfo* cinfo = m_mgr->getCookieRef( socket );
if ( cref != NULL ) { /* known socket? */ if ( cinfo != NULL ) { /* known socket? */
CookieRef* cref = cinfo->GetRef();
m_locked = cref->Lock(); m_locked = cref->Lock();
m_isValid = m_locked && cref->HasSocket_locked( socket ); m_isValid = m_locked && cref->HasSocket_locked( socket );
m_cref = cref; m_cinfo = cinfo;
} }
} }
SafeCref::SafeCref( CookieRef* cref ) /* SafeCref::SafeCref( CookieRef* cref ) */
: m_cref( NULL ) /* : m_cinfo( NULL ) */
, m_mgr( CRefMgr::Get() ) /* , m_mgr( CRefMgr::Get() ) */
, m_isValid( false ) /* , m_isValid( false ) */
{ /* { */
m_locked = cref->Lock(); /* assert(0); /\* path to this? *\/ */
m_isValid = m_locked; /* m_locked = cref->Lock(); */
m_cref = cref; /* m_isValid = m_locked; */
} /* // m_cref = cref; */
/* } */
SafeCref::~SafeCref() SafeCref::~SafeCref()
{ {
if ( m_cref != NULL && m_locked ) { if ( m_cinfo != NULL ) {
if ( m_cref->ShouldDie() ) { if ( m_locked ) {
m_mgr->Recycle_locked( m_cref ); CookieRef* cref = m_cinfo->GetRef();
} else { if ( cref->ShouldDie() ) {
m_cref->Unlock(); m_mgr->Recycle_locked( cref );
} else {
cref->Unlock();
}
} }
m_mgr->m_cidlock->Relinquish( m_cinfo );
} }
} }

View file

@ -27,6 +27,7 @@
#include "cref.h" #include "cref.h"
#include "dbmgr.h" #include "dbmgr.h"
#include "mlock.h" #include "mlock.h"
#include "cidlock.h"
typedef map<CookieID,CookieRef*> CookieMap; typedef map<CookieID,CookieRef*> CookieMap;
class CookieMapIterator; class CookieMapIterator;
@ -135,24 +136,24 @@ class CRefMgr {
CookieRef* getFromFreeList( void ); CookieRef* getFromFreeList( void );
/* connect case */ /* connect case */
CookieRef* getMakeCookieRef( const char* cookie, CidInfo* getMakeCookieRef( const char* cookie,
HostID hid, int socket, int nPlayersH, HostID hid, int socket, int nPlayersH,
int nPlayersS, int langCode, int seed, int nPlayersS, int langCode, int seed,
bool wantsPublic, bool makePublic, bool wantsPublic, bool makePublic,
bool* seenSeed ); bool* seenSeed );
/* reconnect case; just the stuff we don't have in db */ /* reconnect case; just the stuff we don't have in db */
CookieRef* getMakeCookieRef( const char* connName, const char* cookie, CidInfo* getMakeCookieRef( const char* connName, const char* cookie,
HostID hid, int socket, int nPlayersH, HostID hid, int socket, int nPlayersH,
int nPlayersS, int seed, int langCode, int nPlayersS, int seed, int langCode,
bool isPublic, bool* isDead ); bool isPublic, bool* isDead );
CookieRef* getMakeCookieRef( const char* const connName, bool* isDead ); CidInfo* getMakeCookieRef( const char* const connName, bool* isDead );
CookieRef* getCookieRef( CookieID cookieID ); CidInfo* getCookieRef( CookieID cookieID );
CookieRef* getCookieRef( int socket ); CidInfo* getCookieRef( int socket );
bool checkCookieRef_locked( CookieRef* cref ); bool checkCookieRef_locked( CookieRef* cref );
CookieRef* getCookieRef_impl( CookieID cookieID ); CidInfo* getCookieRef_impl( CookieID cookieID );
CookieRef* AddNew( const char* cookie, const char* connName, CookieID id, CookieRef* AddNew( const char* cookie, const char* connName, CookieID id,
int langCode, int nPlayers, int nAlreadyHere ); int langCode, int nPlayers, int nAlreadyHere );
CookieRef* FindOpenGameFor( const char* cookie, const char* connName, CookieRef* FindOpenGameFor( const char* cookie, const char* connName,
@ -166,8 +167,8 @@ class CRefMgr {
static void heartbeatProc( void* closure ); static void heartbeatProc( void* closure );
void checkHeartbeats( time_t now ); void checkHeartbeats( time_t now );
pthread_mutex_t m_nextCIDMutex; /* pthread_mutex_t m_nextCIDMutex; */
CookieID m_nextCID; /* CookieID m_nextCID; */
pthread_mutex_t m_roomsFilledMutex; pthread_mutex_t m_roomsFilledMutex;
int m_nRoomsFilled; int m_nRoomsFilled;
@ -182,6 +183,7 @@ class CRefMgr {
string m_ports; string m_ports;
DBMgr* m_db; DBMgr* m_db;
CidLock* m_cidlock;
friend class CookieMapIterator; friend class CookieMapIterator;
}; /* CRefMgr */ }; /* CRefMgr */
@ -205,13 +207,14 @@ class SafeCref {
SafeCref( const char* const connName ); SafeCref( const char* const connName );
SafeCref( CookieID cid, bool failOk = false ); SafeCref( CookieID cid, bool failOk = false );
SafeCref( int socket ); SafeCref( int socket );
SafeCref( CookieRef* cref ); /* SafeCref( CookieRef* cref ); */
~SafeCref(); ~SafeCref();
bool Forward( HostID src, HostID dest, unsigned char* buf, int buflen ) { bool Forward( HostID src, HostID dest, unsigned char* buf, int buflen ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_Forward( src, dest, buf, buflen ); assert( 0 != cref->GetCookieID() );
cref->_Forward( src, dest, buf, buflen );
return true; return true;
} else { } else {
return false; return false;
@ -219,9 +222,10 @@ class SafeCref {
} }
bool Connect( int socket, int nPlayersH, int nPlayersS, int seed ) { bool Connect( int socket, int nPlayersH, int nPlayersS, int seed ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
return m_cref->_Connect( socket, nPlayersH, nPlayersS, seed, assert( 0 != cref->GetCookieID() );
m_seenSeed ); return cref->_Connect( socket, nPlayersH, nPlayersS, seed,
m_seenSeed );
} else { } else {
return false; return false;
} }
@ -229,9 +233,10 @@ class SafeCref {
bool Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS, bool Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
int seed ) { int seed ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_Reconnect( socket, srcID, nPlayersH, nPlayersS, assert( 0 != cref->GetCookieID() );
seed, m_dead ); cref->_Reconnect( socket, srcID, nPlayersH, nPlayersS,
seed, m_dead );
return true; return true;
} else { } else {
return false; return false;
@ -239,23 +244,26 @@ class SafeCref {
} }
void Disconnect(int socket, HostID hostID ) { void Disconnect(int socket, HostID hostID ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_Disconnect( socket, hostID ); assert( 0 != cref->GetCookieID() );
cref->_Disconnect( socket, hostID );
} }
} }
void DeviceGone( HostID hid, int seed ) void DeviceGone( HostID hid, int seed )
{ {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_DeviceGone( hid, seed ); assert( 0 != cref->GetCookieID() );
cref->_DeviceGone( hid, seed );
} }
} }
bool HandleAck(HostID hostID ) { bool HandleAck(HostID hostID ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_HandleAck( hostID ); assert( 0 != cref->GetCookieID() );
cref->_HandleAck( hostID );
return true; return true;
} else { } else {
return false; return false;
@ -263,22 +271,25 @@ class SafeCref {
} }
void Shutdown() { void Shutdown() {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_Shutdown(); assert( 0 != cref->GetCookieID() );
cref->_Shutdown();
} }
} }
void Remove( int socket ) { void Remove( int socket ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_Remove( socket ); assert( 0 != cref->GetCookieID() );
cref->_Remove( socket );
} }
} }
#ifdef RELAY_HEARTBEAT #ifdef RELAY_HEARTBEAT
bool HandleHeartbeat( HostID id, int socket ) { bool HandleHeartbeat( HostID id, int socket ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_HandleHeartbeat( id, socket ); assert( 0 != cref->GetCookieID() );
cref->_HandleHeartbeat( id, socket );
return true; return true;
} else { } else {
return false; return false;
@ -286,37 +297,43 @@ class SafeCref {
} }
void CheckHeartbeats( time_t now ) { void CheckHeartbeats( time_t now ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); CookieRef* cref = m_cinfo->GetRef();
m_cref->_CheckHeartbeats( now ); assert( 0 != cref->GetCookieID() );
cref->_CheckHeartbeats( now );
} }
} }
#endif #endif
void PrintCookieInfo( string& out ) { void PrintCookieInfo( string& out ) {
if ( IsValid() ) { if ( IsValid() ) {
m_cref->_PrintCookieInfo( out ); CookieRef* cref = m_cinfo->GetRef();
cref->_PrintCookieInfo( out );
} }
} }
void CheckAllConnected() { void CheckAllConnected() {
if ( IsValid() ) { if ( IsValid() ) {
m_cref->_CheckAllConnected(); CookieRef* cref = m_cinfo->GetRef();
cref->_CheckAllConnected();
} }
} }
void CheckNotAcked( HostID hid ) { void CheckNotAcked( HostID hid ) {
if ( IsValid() ) { if ( IsValid() ) {
m_cref->_CheckNotAcked( hid ); CookieRef* cref = m_cinfo->GetRef();
cref->_CheckNotAcked( hid );
} }
} }
const char* Cookie() { const char* Cookie() {
if ( IsValid() ) { if ( IsValid() ) {
return m_cref->Cookie(); CookieRef* cref = m_cinfo->GetRef();
return cref->Cookie();
} else { } else {
return ""; /* so don't crash.... */ return ""; /* so don't crash.... */
} }
} }
const char* ConnName() { const char* ConnName() {
if ( IsValid() ) { if ( IsValid() ) {
return m_cref->ConnName(); CookieRef* cref = m_cinfo->GetRef();
return cref->ConnName();
} else { } else {
return ""; /* so don't crash.... */ return ""; /* so don't crash.... */
} }
@ -324,7 +341,8 @@ class SafeCref {
CookieID GetCookieID() { CookieID GetCookieID() {
if ( IsValid() ) { if ( IsValid() ) {
return m_cref->GetCookieID(); CookieRef* cref = m_cinfo->GetRef();
return cref->GetCookieID();
} else { } else {
return 0; /* so don't crash.... */ return 0; /* so don't crash.... */
} }
@ -332,14 +350,16 @@ class SafeCref {
int GetPlayersTotal() { int GetPlayersTotal() {
if ( IsValid() ) { if ( IsValid() ) {
return m_cref->GetPlayersSought(); CookieRef* cref = m_cinfo->GetRef();
return cref->GetPlayersSought();
} else { } else {
return -1; /* so don't crash.... */ return -1; /* so don't crash.... */
} }
} }
int GetPlayersHere() { int GetPlayersHere() {
if ( IsValid() ) { if ( IsValid() ) {
return m_cref->GetPlayersHere(); CookieRef* cref = m_cinfo->GetRef();
return cref->GetPlayersHere();
} else { } else {
return -1; /* so don't crash.... */ return -1; /* so don't crash.... */
} }
@ -347,7 +367,8 @@ class SafeCref {
const char* StateString() { const char* StateString() {
if ( IsValid() ) { if ( IsValid() ) {
return stateString( m_cref->CurState() ); CookieRef* cref = m_cinfo->GetRef();
return stateString( cref->CurState() );
} else { } else {
return ""; return "";
} }
@ -355,13 +376,15 @@ class SafeCref {
void GetHostsConnected( string* hosts, string* seeds, string* addrs ) { void GetHostsConnected( string* hosts, string* seeds, string* addrs ) {
if ( IsValid() ) { if ( IsValid() ) {
m_cref->_FormatHostInfo( hosts, seeds, addrs ); CookieRef* cref = m_cinfo->GetRef();
cref->_FormatHostInfo( hosts, seeds, addrs );
} }
} }
time_t GetStartTime(void) { time_t GetStartTime(void) {
if ( IsValid() ) { if ( IsValid() ) {
return m_cref->GetStarttime(); CookieRef* cref = m_cinfo->GetRef();
return cref->GetStarttime();
} else { } else {
return 0; return 0;
} }
@ -371,7 +394,7 @@ class SafeCref {
bool SeenSeed() { return m_seenSeed; } bool SeenSeed() { return m_seenSeed; }
private: private:
CookieRef* m_cref; CidInfo* m_cinfo;
CRefMgr* m_mgr; CRefMgr* m_mgr;
bool m_isValid; bool m_isValid;
bool m_locked; bool m_locked;