monitor ThreadSocketHandler and terminate and restart if hung, convert _beginthread to CreateThread wrapper, disconnect inactive connections, ping, break up long messages to speed up initial download, better priorities for initiating connections, track how many nodes have requested our blocks and transactions, status #/offline and warning message on unsent blocks, minimize on close as separate option -- linux-test5

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@38 1a98c847-1fd6-4fd8-948a-caf3550aa51b
This commit is contained in:
s_nakamoto 2009-11-13 01:23:08 +00:00
parent 956468c29a
commit 70e79525c9
16 changed files with 685 additions and 392 deletions

View file

@ -8,7 +8,7 @@ the OpenSSL Toolkit (http://www.openssl.org/). This product includes
cryptographic software written by Eric Young (eay@cryptsoft.com).
WINDOWS BUILD NOTES
WINDOWS BUILD NOTES
Compilers Supported

View file

@ -13,6 +13,7 @@ UNIX BUILD NOTES
Dependencies
------------
Install the dev files for the shared libraries:
apt-get install build-essential
apt-get install libgtk2.0-dev
apt-get install libssl-dev

9
db.cpp
View file

@ -505,6 +505,13 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
{
vchDefaultKeyRet.clear();
// Modify defaults
#ifndef __WXMSW__
// Reports that tray icon can disappear on gnome, leaving no way to access the program
fMinimizeToTray = false;
fMinimizeOnClose = false;
#endif
//// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(cs_mapKeys)
CRITICAL_BLOCK(cs_mapWallet)
@ -638,7 +645,7 @@ bool LoadWallet(bool& fFirstRunRet)
CWalletDB().WriteDefaultKey(keyUser.GetPubKey());
}
_beginthread(ThreadFlushWalletDB, 0, NULL);
CreateThread(ThreadFlushWalletDB, NULL);
return true;
}

View file

@ -75,7 +75,6 @@
#include <net/if.h>
#include <ifaddrs.h>
#include <boost/filesystem.hpp>
#include <boost/thread/thread.hpp>
#include <boost/algorithm/string.hpp>
#endif

View file

@ -54,7 +54,7 @@ static bool Send(SOCKET hSocket, const char* pszSend)
const char* pszEnd = psz + strlen(psz);
while (psz < pszEnd)
{
int ret = send(hSocket, psz, pszEnd - psz, 0);
int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
if (ret < 0)
return false;
psz += ret;
@ -156,7 +156,7 @@ bool Wait(int nSeconds)
void ThreadIRCSeed(void* parg)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
SetThreadPriority(THREAD_PRIORITY_NORMAL);
int nErrorWait = 10;
int nRetryWait = 10;
@ -256,6 +256,7 @@ void ThreadIRCSeed(void* parg)
CAddress addr;
if (DecodeAddress(pszName, addr))
{
addr.nTime = GetAdjustedTime() - 51 * 60;
CAddrDB addrdb;
if (AddAddress(addrdb, addr))
printf("IRC got new address\n");

144
main.cpp
View file

@ -42,6 +42,9 @@ map<uint160, vector<unsigned char> > mapPubKeys;
CCriticalSection cs_mapKeys;
CKey keyUser;
map<uint256, int> mapRequestCount;
CCriticalSection cs_mapRequestCount;
// Settings
int fGenerateBitcoins = false;
int64 nTransactionFee = 0;
@ -274,7 +277,44 @@ int64 CWalletTx::GetTxTime() const
return nTimeReceived;
}
int CWalletTx::GetRequestCount() const
{
// Returns -1 if it wasn't being tracked
int nRequests = -1;
CRITICAL_BLOCK(cs_mapRequestCount)
{
if (IsCoinBase())
{
// Generated block
if (hashBlock != 0)
{
map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
if (mi != mapRequestCount.end())
nRequests = (*mi).second;
}
}
else
{
// Did anyone request this transaction?
map<uint256, int>::iterator mi = mapRequestCount.find(GetHash());
if (mi != mapRequestCount.end())
{
nRequests = (*mi).second;
// How about the block it's in?
if (nRequests == 0 && hashBlock != 0)
{
map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
if (mi != mapRequestCount.end())
nRequests = (*mi).second;
else
nRequests = 1; // If it's in someone else's block it must have got out
}
}
}
}
return nRequests;
}
@ -295,7 +335,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
CTxIndex txindex;
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
return 0;
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, true))
if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
return 0;
pblock = &blockTmp;
}
@ -1003,7 +1043,7 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
foreach(CBlockIndex* pindex, vDisconnect)
{
CBlock block;
if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos, true))
if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))
return error("Reorganize() : ReadFromDisk for disconnect failed");
if (!block.DisconnectBlock(txdb, pindex))
return error("Reorganize() : DisconnectBlock failed");
@ -1020,7 +1060,7 @@ bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{
CBlockIndex* pindex = vConnect[i];
CBlock block;
if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos, true))
if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))
return error("Reorganize() : ReadFromDisk for connect failed");
if (!block.ConnectBlock(txdb, pindex))
{
@ -1380,7 +1420,7 @@ bool CheckDiskSpace(int64 nAdditionalBytes)
{
fShutdown = true;
ThreadSafeMessageBox("Warning: Your disk space is low ", "Bitcoin", wxOK | wxICON_EXCLAMATION);
_beginthread(Shutdown, 0, NULL);
CreateThread(Shutdown, NULL);
return false;
}
return true;
@ -1547,7 +1587,7 @@ void PrintBlockTree()
// print item
CBlock block;
block.ReadFromDisk(pindex, true);
block.ReadFromDisk(pindex);
printf("%d (%u,%u) %s %s tx %d",
pindex->nHeight,
pindex->nFile,
@ -1623,7 +1663,8 @@ bool ProcessMessages(CNode* pfrom)
CDataStream& vRecv = pfrom->vRecv;
if (vRecv.empty())
return true;
//printf("ProcessMessages(%d bytes)\n", vRecv.size());
//if (fDebug)
// printf("ProcessMessages(%d bytes)\n", vRecv.size());
//
// Message format
@ -1666,7 +1707,8 @@ bool ProcessMessages(CNode* pfrom)
{
// Rewind and wait for rest of message
///// need a mechanism to give up waiting for overlong message size error
//printf("message-break\n");
//if (fDebug)
// printf("message-break\n");
vRecv.insert(vRecv.begin(), BEGIN(hdr), END(hdr));
Sleep(100);
break;
@ -1718,6 +1760,8 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
static map<unsigned int, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon();
if (fDebug)
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
@ -1739,18 +1783,19 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CAddress addrMe;
CAddress addrFrom;
uint64 nNonce = 1;
string strSubVer;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
if (pfrom->nVersion >= 106 && !vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (pfrom->nVersion >= 106 && !vRecv.empty())
vRecv >> strSubVer;
if (pfrom->nVersion == 0)
return false;
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce)
if (nNonce == nLocalHostNonce && nNonce > 1)
{
pfrom->fDisconnect = true;
pfrom->vRecv.clear();
pfrom->vSend.clear();
return true;
}
@ -1776,10 +1821,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true;
// Update the last seen time
if (pfrom->fNetworkNode)
AddressCurrentlyConnected(pfrom->addr);
printf("version message: version %d\n", pfrom->nVersion);
}
@ -1824,10 +1865,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vector<CInv> vInv;
vRecv >> vInv;
// Update the last seen time for this node's address
if (pfrom->fNetworkNode)
AddressCurrentlyConnected(pfrom->addr);
CTxDB txdb("r");
foreach(const CInv& inv, vInv)
{
@ -1842,6 +1879,14 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->AskFor(inv);
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), GetOrphanRoot(mapOrphanBlocks[inv.hash]));
// Track requests for our stuff
CRITICAL_BLOCK(cs_mapRequestCount)
{
map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
}
}
@ -1879,6 +1924,14 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->PushMessage(inv.GetCommand(), (*mi).second);
}
}
// Track requests for our stuff
CRITICAL_BLOCK(cs_mapRequestCount)
{
map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
}
}
@ -2086,11 +2139,23 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
else if (strCommand == "ping")
{
}
else
{
// Ignore unknown commands for extensibility
}
// Update the last seen time for this node's address
if (pfrom->fNetworkNode)
if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")
AddressCurrentlyConnected(pfrom->addr);
return true;
}
@ -2129,6 +2194,10 @@ bool SendMessages(CNode* pto)
}
}
// Keep-alive ping
if (pto->nLastSend && GetTime() - pto->nLastSend > 12 * 60 && pto->vSend.empty())
pto->PushMessage("ping");
//
// Message: addr
@ -2139,7 +2208,14 @@ bool SendMessages(CNode* pto)
{
// returns true if wasn't already contained in the set
if (pto->setAddrKnown.insert(addr).second)
{
vAddrToSend.push_back(addr);
if (vAddrToSend.size() >= 1000)
{
pto->PushMessage("addr", vAddrToSend);
vAddrToSend.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddrToSend.empty())
@ -2157,7 +2233,14 @@ bool SendMessages(CNode* pto)
{
// returns true if wasn't already contained in the set
if (pto->setInventoryKnown.insert(inv).second)
{
vInventoryToSend.push_back(inv);
if (vInventoryToSend.size() >= 1000)
{
pto->PushMessage("inv", vInventoryToSend);
vInventoryToSend.clear();
}
}
}
pto->vInventoryToSend.clear();
pto->setInventoryKnown2.clear();
@ -2179,6 +2262,11 @@ bool SendMessages(CNode* pto)
{
printf("sending getdata: %s\n", inv.ToString().c_str());
vAskFor.push_back(inv);
if (vAskFor.size() >= 1000)
{
pto->PushMessage("getdata", vAskFor);
vAskFor.clear();
}
}
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
@ -2226,8 +2314,8 @@ void GenerateBitcoins(bool fGenerate)
int nAddThreads = nProcessors - vnThreadsRunning[3];
printf("Starting %d BitcoinMiner threads\n", nAddThreads);
for (int i = 0; i < nAddThreads; i++)
if (_beginthread(ThreadBitcoinMiner, 0, NULL) == -1)
printf("Error: _beginthread(ThreadBitcoinMiner) failed\n");
if (!CreateThread(ThreadBitcoinMiner, NULL))
printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
}
}
@ -2304,7 +2392,7 @@ void BitcoinMiner()
CBigNum bnExtraNonce = 0;
while (fGenerateBitcoins)
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
Sleep(50);
if (fShutdown)
return;
@ -2440,7 +2528,7 @@ void BitcoinMiner()
printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
pblock->print();
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
SetThreadPriority(THREAD_PRIORITY_NORMAL);
CRITICAL_BLOCK(cs_main)
{
if (pindexPrev == pindexBest)
@ -2450,12 +2538,16 @@ void BitcoinMiner()
return;
key.MakeNewKey();
// Track how many getdata requests this block gets
CRITICAL_BLOCK(cs_mapRequestCount)
mapRequestCount[pblock->GetHash()] = 0;
// Process this block the same as if we had received it from another node
if (!ProcessBlock(NULL, pblock.release()))
printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n");
}
}
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
Sleep(500);
break;
@ -2534,7 +2626,7 @@ bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
setCoinsRet.clear();
// List of values less than target
int64 nLowestLarger = _I64_MAX;
int64 nLowestLarger = INT64_MAX;
CWalletTx* pcoinLowestLarger = NULL;
vector<pair<int64, CWalletTx*> > vValue;
int64 nTotalLower = 0;
@ -2777,6 +2869,10 @@ bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
return error("SendMoney() : Error finalizing transaction");
}
// Track how many getdata requests our transaction gets
CRITICAL_BLOCK(cs_mapRequestCount)
mapRequestCount[wtxNew.GetHash()] = 0;
printf("SendMoney: %s\n", wtxNew.GetHash().ToString().substr(0,6).c_str());
// Broadcast

25
main.h
View file

@ -34,6 +34,8 @@ extern int nBestHeight;
extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated;
extern map<uint256, int> mapRequestCount;
extern CCriticalSection cs_mapRequestCount;
// Settings
extern int fGenerateBitcoins;
@ -647,6 +649,15 @@ public:
nGetCreditCached = 0;
}
IMPLEMENT_SERIALIZE
(
nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
nVersion = this->nVersion;
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
)
int64 GetCredit(bool fUseCache=false) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
@ -661,15 +672,6 @@ public:
return nGetCreditCached;
}
IMPLEMENT_SERIALIZE
(
nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
nVersion = this->nVersion;
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
)
int SetMerkleBranch(const CBlock* pblock=NULL);
int GetDepthInMainChain() const;
@ -749,6 +751,7 @@ public:
int64 GetTxTime() const;
int GetRequestCount() const;
void AddSupportingTransactions(CTxDB& txdb);
@ -978,7 +981,7 @@ public:
return true;
}
bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions)
bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true)
{
SetNull();
@ -1027,7 +1030,7 @@ public:
int64 GetBlockValue(int64 nFees) const;
bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions);
bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions=true);
bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
bool CheckBlock() const;
bool AcceptBlock();

344
net.cpp
View file

@ -13,7 +13,6 @@ bool OpenNetworkConnection(const CAddress& addrConnect);
//
// Global state variables
//
@ -25,6 +24,7 @@ uint64 nLocalHostNonce = 0;
bool fShutdown = false;
array<int, 10> vnThreadsRunning;
SOCKET hListenSocket = INVALID_SOCKET;
int64 nThreadSocketHandlerHeartbeat = INT64_MAX;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
@ -65,7 +65,7 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
if (fProxy)
{
printf("Proxy connecting %s\n", addrConnect.ToStringLog().c_str());
printf("proxy connecting %s\n", addrConnect.ToStringLog().c_str());
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
@ -87,9 +87,11 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
if (pchRet[1] != 0x5a)
{
closesocket(hSocket);
return error("Proxy returned error %d", pchRet[1]);
if (pchRet[1] != 0x5b)
printf("ERROR: Proxy returned error %d\n", pchRet[1]);
return false;
}
printf("Proxy connection established %s\n", addrConnect.ToStringLog().c_str());
printf("proxy connected %s\n", addrConnect.ToStringLog().c_str());
}
hSocketRet = hSocket;
@ -219,6 +221,7 @@ bool AddAddress(CAddrDB& addrdb, CAddress addr, bool fCurrentlyOnline)
if (it == mapAddresses.end())
{
// New address
printf("AddAddress(%s)\n", addr.ToStringLog().c_str());
mapAddresses.insert(make_pair(addr.GetKey(), addr));
addrdb.WriteAddress(addr);
return true;
@ -256,7 +259,7 @@ void AddressCurrentlyConnected(const CAddress& addr)
if (it != mapAddresses.end())
{
CAddress& addrFound = (*it).second;
int64 nUpdateInterval = 60 * 60;
int64 nUpdateInterval = 20 * 60;
if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
{
// Periodically update most recently seen time
@ -417,7 +420,13 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
}
/// debug print
printf("trying connection %s\n", addrConnect.ToStringLog().c_str());
printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
addrConnect.ToStringLog().c_str(),
(double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
(double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
CRITICAL_BLOCK(cs_mapAddresses)
mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
// Connect
SOCKET hSocket;
@ -428,7 +437,7 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
// Set to nonblocking
#ifdef __WXMSW__
u_long nOne = 1;
u_long nOne = 1;
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
#else
@ -445,29 +454,23 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
CRITICAL_BLOCK(cs_vNodes)
vNodes.push_back(pnode);
CRITICAL_BLOCK(cs_mapAddresses)
mapAddresses[addrConnect.GetKey()].nLastFailed = 0;
pnode->nTimeConnected = GetTime();
return pnode;
}
else
{
CRITICAL_BLOCK(cs_mapAddresses)
mapAddresses[addrConnect.GetKey()].nLastFailed = GetAdjustedTime();
return NULL;
}
}
void CNode::DoDisconnect()
{
if (fDebug)
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("disconnecting node %s\n", addr.ToStringLog().c_str());
closesocket(hSocket);
// If outbound and never got version message, mark address as failed
if (!fInbound && !fSuccessfullyConnected)
CRITICAL_BLOCK(cs_mapAddresses)
mapAddresses[addr.GetKey()].nLastFailed = GetAdjustedTime();
// All of a nodes broadcasts and subscriptions are automatically torn down
// when it goes down, so a node has to stay up to keep its broadcast going.
@ -508,7 +511,7 @@ void ThreadSocketHandler(void* parg)
PrintException(&e, "ThreadSocketHandler()");
} catch (...) {
vnThreadsRunning[0]--;
PrintException(NULL, "ThreadSocketHandler()");
throw; // support pthread_cancel()
}
printf("ThreadSocketHandler exiting\n");
@ -531,15 +534,18 @@ void ThreadSocketHandler2(void* parg)
vector<CNode*> vNodesCopy = vNodes;
foreach(CNode* pnode, vNodesCopy)
{
if (pnode->ReadyToDisconnect() && pnode->vRecv.empty() && pnode->vSend.empty())
if (pnode->fDisconnect ||
(pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
{
// remove from vNodes
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
// close socket
pnode->DoDisconnect();
// hold in disconnected pool until all refs are released
pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 5 * 60);
if (pnode->fNetworkNode)
if (pnode->fNetworkNode || pnode->fInbound)
pnode->Release();
vNodesDisconnected.push_back(pnode);
}
@ -582,8 +588,10 @@ void ThreadSocketHandler2(void* parg)
fd_set fdsetRecv;
fd_set fdsetSend;
fd_set fdsetError;
FD_ZERO(&fdsetRecv);
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
SOCKET hSocketMax = 0;
FD_SET(hListenSocket, &fdsetRecv);
hSocketMax = max(hSocketMax, hListenSocket);
@ -592,6 +600,7 @@ void ThreadSocketHandler2(void* parg)
foreach(CNode* pnode, vNodes)
{
FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError);
hSocketMax = max(hSocketMax, pnode->hSocket);
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
if (!pnode->vSend.empty())
@ -600,30 +609,21 @@ void ThreadSocketHandler2(void* parg)
}
vnThreadsRunning[0]--;
int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, NULL, &timeout);
int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
vnThreadsRunning[0]++;
if (fShutdown)
return;
if (nSelect == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
printf("select failed: %d\n", nErr);
printf("socket select error %d\n", nErr);
for (int i = 0; i <= hSocketMax; i++)
{
FD_SET(i, &fdsetRecv);
FD_SET(i, &fdsetSend);
}
FD_ZERO(&fdsetSend);
FD_ZERO(&fdsetError);
Sleep(timeout.tv_usec/1000);
}
//// debug print
//foreach(CNode* pnode, vNodes)
//{
// printf("vRecv = %-5d ", pnode->vRecv.size());
// printf("vSend = %-5d ", pnode->vSend.size());
//}
//printf("\n");
//
// Accept new connections
@ -641,7 +641,7 @@ void ThreadSocketHandler2(void* parg)
if (hSocket == INVALID_SOCKET)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
printf("ERROR ThreadSocketHandler accept failed: %d\n", WSAGetLastError());
printf("socket error accept failed: %d\n", WSAGetLastError());
}
else
{
@ -669,7 +669,7 @@ void ThreadSocketHandler2(void* parg)
//
// Receive
//
if (FD_ISSET(hSocket, &fdsetRecv))
if (FD_ISSET(hSocket, &fdsetRecv) || FD_ISSET(hSocket, &fdsetError))
{
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
{
@ -677,25 +677,29 @@ void ThreadSocketHandler2(void* parg)
unsigned int nPos = vRecv.size();
// typical socket buffer is 8K-64K
const unsigned int nBufSize = 0x10000;
vRecv.resize(nPos + nBufSize);
int nBytes = recv(hSocket, &vRecv[nPos], nBufSize, 0);
vRecv.resize(nPos + max(nBytes, 0));
if (nBytes == 0)
char pchBuf[0x10000];
int nBytes = recv(hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
if (nBytes > 0)
{
vRecv.resize(nPos + nBytes);
memcpy(&vRecv[nPos], pchBuf, nBytes);
pnode->nLastRecv = GetTime();
}
else if (nBytes == 0)
{
// socket closed gracefully
if (!pnode->fDisconnect)
printf("recv: socket closed\n");
printf("socket closed\n");
pnode->fDisconnect = true;
}
else if (nBytes < 0)
{
// socket error
// error
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
if (!pnode->fDisconnect)
printf("recv failed: %d\n", nErr);
printf("socket recv error %d\n", nErr);
pnode->fDisconnect = true;
}
}
@ -712,28 +716,63 @@ void ThreadSocketHandler2(void* parg)
CDataStream& vSend = pnode->vSend;
if (!vSend.empty())
{
int nBytes = send(hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL);
int nBytes = send(hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
if (nBytes > 0)
{
vSend.erase(vSend.begin(), vSend.begin() + nBytes);
pnode->nLastSend = GetTime();
}
else if (nBytes == 0)
else if (nBytes < 0)
{
if (pnode->ReadyToDisconnect())
pnode->vSend.clear();
}
else
{
printf("send error %d\n", nBytes);
if (pnode->ReadyToDisconnect())
pnode->vSend.clear();
// error
int nErr = WSAGetLastError();
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
printf("socket send error %d\n", nErr);
pnode->fDisconnect = true;
}
}
}
}
}
//
// Inactivity checking
//
if (pnode->vSend.empty())
pnode->nLastSendEmpty = GetTime();
if (GetTime() - pnode->nTimeConnected > 60)
{
if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
{
printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
pnode->fDisconnect = true;
}
else if (GetTime() - pnode->nLastSend > 10 * 60 && GetTime() - pnode->nLastSendEmpty > 10 * 60)
{
printf("socket not sending\n");
pnode->fDisconnect = true;
}
else if (GetTime() - pnode->nLastRecv > (pnode->nVersion >= 107 ? 15*60 : 90*60))
{
printf("socket inactivity timeout\n");
pnode->fDisconnect = true;
}
}
}
//// debug heartbeat
static int64 nHeartbeat1;
if (GetTime() - nHeartbeat1 >= 5 * 60)
{
printf("%s sendrecv\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
nHeartbeat1 = GetTime();
fDebug = true;
}
nThreadSocketHandlerHeartbeat = GetTime();
Sleep(10);
}
}
@ -772,15 +811,20 @@ void ThreadOpenConnections2(void* parg)
{
printf("ThreadOpenConnections started\n");
// Connect to one specified address
// Connect to specific addresses
while (mapArgs.count("-connect"))
{
OpenNetworkConnection(CAddress(mapArgs["-connect"]));
for (int i = 0; i < 10; i++)
foreach(string strAddr, mapMultiArgs["-connect"])
{
Sleep(1000);
if (fShutdown)
return;
CAddress addr(strAddr, NODE_NETWORK);
if (addr.IsValid())
OpenNetworkConnection(addr);
for (int i = 0; i < 10; i++)
{
Sleep(1000);
if (fShutdown)
return;
}
}
}
@ -821,12 +865,7 @@ void ThreadOpenConnections2(void* parg)
// Choose an address to connect to based on most recently seen
//
CAddress addrConnect;
int64 nBestTime = 0;
int64 nDelay = ((60 * 60) << vNodes.size());
if (vNodes.size() >= 3)
nDelay *= 4;
if (nGotIRCAddresses > 0)
nDelay *= 100;
int64 nBest = INT64_MIN;
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect
set<unsigned int> setConnected;
@ -841,24 +880,51 @@ void ThreadOpenConnections2(void* parg)
const CAddress& addr = item.second;
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip))
continue;
int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
// Randomize the order in a deterministic way, putting the standard port first
int64 nRandomizer = (uint64)(addr.nLastFailed * 9567851 + addr.ip * 7789) % (1 * 60 * 60);
int64 nRandomizer = (uint64)(addr.nLastTry * 9567851 + addr.ip * 7789) % (30 * 60);
if (addr.port != DEFAULT_PORT)
nRandomizer += 1 * 60 * 60;
nRandomizer += 30 * 60;
// Last seen Base retry frequency
// <1 hour 10 min
// 1 hour 1 hour
// 4 hours 2 hours
// 24 hours 5 hours
// 48 hours 7 hours
// 7 days 13 hours
// 30 days 27 hours
// 90 days 46 hours
// 365 days 93 hours
int64 nDelay = 3600.0 * sqrt(fabs(nSinceLastSeen) / 3600.0) + nRandomizer;
// Fast reconnect for one hour after last seen
if (nSinceLastSeen < 60 * 60)
nDelay = 10 * 60;
// Limit retry frequency
if (GetAdjustedTime() < addr.nLastFailed + nDelay + nRandomizer)
if (nSinceLastTry < nDelay)
continue;
// Try again only after all addresses had a first attempt
int64 nTime = addr.nTime - nRandomizer;
if (addr.nLastFailed > addr.nTime)
nTime -= 365 * 24 * 60 * 60;
// If we have IRC, we'll be notified when they first come online,
// and again every 24 hours by the refresh broadcast.
if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
continue;
if (nTime > nBestTime)
// Only try the old stuff if we don't have enough connections
if (vNodes.size() >= 2 && nSinceLastSeen > 7 * 24 * 60 * 60)
continue;
if (vNodes.size() >= 4 && nSinceLastSeen > 24 * 60 * 60)
continue;
// If multiple addresses are ready, prioritize by time since
// last seen and time since last tried.
int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
if (nScore > nBest)
{
nBestTime = nTime;
nBest = nScore;
addrConnect = addr;
}
}
@ -941,7 +1007,7 @@ void ThreadMessageHandler(void* parg)
void ThreadMessageHandler2(void* parg)
{
printf("ThreadMessageHandler started\n");
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
loop
{
// Poll the connected nodes for messages
@ -1063,39 +1129,31 @@ bool BindListenPort(string& strError)
return true;
}
bool StartNode(string& strError)
void StartNode(void* parg)
{
strError = "";
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));
#ifdef __WXMSW__
// Get local host ip
char pszHostName[255];
if (gethostname(pszHostName, sizeof(pszHostName)) == SOCKET_ERROR)
char pszHostName[1000] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
{
strError = strprintf("Error: Unable to get IP address of this computer (gethostname returned error %d)", WSAGetLastError());
printf("%s\n", strError.c_str());
return false;
}
struct hostent* phostent = gethostbyname(pszHostName);
if (!phostent)
{
strError = strprintf("Error: Unable to get IP address of this computer (gethostbyname returned error %d)", WSAGetLastError());
printf("%s\n", strError.c_str());
return false;
}
// Take the first IP that isn't loopback 127.x.x.x
for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());
for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
{
CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);
if (addr.IsValid() && addr.GetByte(3) != 127)
struct hostent* phostent = gethostbyname(pszHostName);
if (phostent)
{
addrLocalHost = addr;
break;
// Take the first IP that isn't loopback 127.x.x.x
for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());
for (int i = 0; phostent->h_addr_list[i] != NULL; i++)
{
CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);
if (addr.IsValid() && addr.GetByte(3) != 127)
{
addrLocalHost = addr;
break;
}
}
}
}
#else
@ -1145,45 +1203,85 @@ bool StartNode(string& strError)
}
else
{
if (addrIncoming.ip)
if (addrIncoming.IsValid())
addrLocalHost.ip = addrIncoming.ip;
if (GetMyExternalIP(addrLocalHost.ip))
{
addrIncoming = addrLocalHost;
CWalletDB().WriteSetting("addrIncoming", addrIncoming);
printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
}
}
// Get addresses from IRC and advertise ours
if (_beginthread(ThreadIRCSeed, 0, NULL) == -1)
printf("Error: _beginthread(ThreadIRCSeed) failed\n");
//
// Start threads
//
if (_beginthread(ThreadSocketHandler, 0, NULL) == -1)
{
strError = "Error: _beginthread(ThreadSocketHandler) failed";
printf("%s\n", strError.c_str());
return false;
}
if (_beginthread(ThreadOpenConnections, 0, NULL) == -1)
{
strError = "Error: _beginthread(ThreadOpenConnections) failed";
printf("%s\n", strError.c_str());
return false;
}
// Get addresses from IRC and advertise ours
if (!CreateThread(ThreadIRCSeed, NULL))
printf("Error: CreateThread(ThreadIRCSeed) failed\n");
if (_beginthread(ThreadMessageHandler, 0, NULL) == -1)
{
strError = "Error: _beginthread(ThreadMessageHandler) failed";
printf("%s\n", strError.c_str());
return false;
}
// Send and receive from sockets, accept connections
pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
return true;
// Initiate outbound connections
if (!CreateThread(ThreadOpenConnections, NULL))
printf("Error: CreateThread(ThreadOpenConnections) failed\n");
// Process messages
if (!CreateThread(ThreadMessageHandler, NULL))
printf("Error: CreateThread(ThreadMessageHandler) failed\n");
// Generate coins in the background
GenerateBitcoins(fGenerateBitcoins);
//
// Thread monitoring
//
loop
{
Sleep(15000);
if (GetTime() - nThreadSocketHandlerHeartbeat > 4 * 60)
{
// First see if closing sockets will free it
printf("*** ThreadSocketHandler is stopped ***\n");
CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodes)
{
bool fGot = false;
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
TRY_CRITICAL_BLOCK(pnode->cs_vSend)
fGot = true;
if (!fGot)
{
printf("*** closing socket\n");
closesocket(pnode->hSocket);
pnode->fDisconnect = true;
}
}
}
Sleep(10000);
if (GetTime() - nThreadSocketHandlerHeartbeat < 60)
continue;
// Hopefully it never comes to this.
// We know it'll always be hung in the recv or send call.
// cs_vRecv or cs_vSend may be left permanently unreleased,
// but we always only use TRY_CRITICAL_SECTION on them.
printf("*** Restarting ThreadSocketHandler ***\n");
TerminateThread(hThreadSocketHandler, 0);
#ifdef __WXMSW__
CloseHandle(hThreadSocketHandler);
#endif
vnThreadsRunning[0] = 0;
// Restart
hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
nThreadSocketHandlerHeartbeat = GetTime();
}
}
}
bool StopNode()

25
net.h
View file

@ -29,7 +29,7 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
bool AnySubscribed(unsigned int nChannel);
bool BindListenPort(string& strError=REF(string()));
bool StartNode(string& strError=REF(string()));
void StartNode(void* parg);
bool StopNode();
@ -39,7 +39,6 @@ bool StopNode();
//
// Message header
// (4) message start
@ -139,7 +138,7 @@ public:
unsigned int nTime;
// memory only
unsigned int nLastFailed;
unsigned int nLastTry;
CAddress()
{
@ -183,7 +182,7 @@ public:
ip = INADDR_NONE;
port = DEFAULT_PORT;
nTime = GetAdjustedTime();
nLastFailed = 0;
nLastTry = 0;
}
bool SetAddress(const char* pszIn)
@ -458,6 +457,7 @@ extern uint64 nLocalHostNonce;
extern bool fShutdown;
extern array<int, 10> vnThreadsRunning;
extern SOCKET hListenSocket;
extern int64 nThreadSocketHandlerHeartbeat;
extern vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
@ -486,6 +486,10 @@ public:
CDataStream vRecv;
CCriticalSection cs_vSend;
CCriticalSection cs_vRecv;
int64 nLastSend;
int64 nLastRecv;
int64 nLastSendEmpty;
int64 nTimeConnected;
unsigned int nPushPos;
CAddress addr;
int nVersion;
@ -523,6 +527,10 @@ public:
hSocket = hSocketIn;
vSend.SetType(SER_NETWORK);
vRecv.SetType(SER_NETWORK);
nLastSend = 0;
nLastRecv = 0;
nLastSendEmpty = GetTime();
nTimeConnected = GetTime();
nPushPos = -1;
addr = addrIn;
nVersion = 0;
@ -542,7 +550,7 @@ public:
CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce);
PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, "linux-test5");
}
~CNode()
@ -557,11 +565,6 @@ private:
public:
bool ReadyToDisconnect()
{
return fDisconnect || GetRefCount() <= 0;
}
int GetRefCount()
{
return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
@ -635,6 +638,8 @@ public:
AbortMessage();
nPushPos = vSend.size();
vSend << CMessageHeader(pszCommand, 0);
if (fDebug)
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("sending: %s ", pszCommand);
}

137
ui.cpp
View file

@ -25,6 +25,7 @@ map<string, string> mapAddressBook;
bool fRandSendTest = false;
void RandSend();
extern int g_isPainting;
bool fClosedToTray = false;
// Settings
int fShowGenerated = true;
@ -413,16 +414,17 @@ void Shutdown(void* parg)
void CMainFrame::OnClose(wxCloseEvent& event)
{
if (fMinimizeToTray && fMinimizeOnClose && event.CanVeto() && !IsIconized())
if (fMinimizeOnClose && event.CanVeto() && !IsIconized())
{
// Divert close to minimize
event.Veto();
fClosedToTray = true;
Iconize(true);
}
else
{
Destroy();
_beginthread(Shutdown, 0, NULL);
CreateThread(Shutdown, NULL);
}
}
@ -430,7 +432,16 @@ void CMainFrame::OnIconize(wxIconizeEvent& event)
{
// Hide the task bar button when minimized.
// Event is sent when the frame is minimized or restored.
Show(!fMinimizeToTray || !event.Iconized());
if (!event.Iconized())
fClosedToTray = false;
#ifndef __WXMSW__
// Tray is not reliable on Linux gnome
fClosedToTray = false;
#endif
if (fMinimizeToTray && event.Iconized())
fClosedToTray = true;
Show(!fClosedToTray);
ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
}
void CMainFrame::OnMouseEvents(wxMouseEvent& event)
@ -527,7 +538,6 @@ bool CMainFrame::DeleteLine(uint256 hashKey)
string FormatTxStatus(const CWalletTx& wtx)
{
// Status
int nDepth = wtx.GetDepthInMainChain();
if (!wtx.IsFinal())
{
if (wtx.nLockTime < 500000000)
@ -535,10 +545,16 @@ string FormatTxStatus(const CWalletTx& wtx)
else
return strprintf("Open until %s", DateTimeStr(wtx.nLockTime).c_str());
}
else if (nDepth < 6)
return strprintf("%d/unconfirmed", nDepth);
else
return strprintf("%d blocks", nDepth);
{
int nDepth = wtx.GetDepthInMainChain();
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
return strprintf("%d/offline?", nDepth);
else if (nDepth < 6)
return strprintf("%d/unconfirmed", nDepth);
else
return strprintf("%d blocks", nDepth);
}
}
string SingleLine(const string& strIn)
@ -629,9 +645,17 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
foreach(const CTxOut& txout, wtx.vout)
nUnmatured += txout.GetCredit();
if (wtx.IsInMainChain())
strDescription += strprintf(" (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
{
strDescription = strprintf("Generated (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
// Check if the block was requested by anyone
if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
strDescription = "Generated - Warning: This block was not received by any other nodes and will probably not be accepted!";
}
else
strDescription += " (not accepted)";
{
strDescription = "Generated (not accepted)";
}
}
}
else if (!mapValue["from"].empty() || !mapValue["message"].empty())
@ -701,8 +725,11 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
strStatus,
nTime ? DateTimeStr(nTime) : "",
"Payment to yourself",
FormatMoney(nNet - nValue, true),
FormatMoney(nValue, true));
"",
"");
/// issue: can't tell which is the payment and which is the change anymore
// FormatMoney(nNet - nValue, true),
// FormatMoney(nValue, true));
}
else if (fAllFromMe)
{
@ -1028,6 +1055,9 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount);
m_statusBar->SetStatusText(strStatus, 2);
if (fDebug && GetTime() - nThreadSocketHandlerHeartbeat > 60)
m_statusBar->SetStatusText(" ERROR: ThreadSocketHandler has stopped", 0);
// Pass through to listctrl to actually do the paint, we're just hooking the message
m_listCtrl->Disconnect(wxEVT_PAINT, (wxObjectEventFunction)NULL, NULL, this);
m_listCtrl->GetEventHandler()->ProcessEvent(event);
@ -1237,7 +1267,19 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
strHTML += "<b>Status:</b> " + FormatTxStatus(wtx) + "<br>";
strHTML += "<b>Status:</b> " + FormatTxStatus(wtx);
int nRequests = wtx.GetRequestCount();
if (nRequests != -1)
{
if (nRequests == 0)
strHTML += ", has not been successfully broadcast yet";
else if (nRequests == 1)
strHTML += strprintf(", broadcast through %d node", nRequests);
else
strHTML += strprintf(", broadcast through %d nodes", nRequests);
}
strHTML += "<br>";
strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";
@ -1366,9 +1408,10 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
if (fAllToMe)
{
// Payment to self
int64 nValue = wtx.vout[0].nValue;
strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";
strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";
/// issue: can't tell which is the payment and which is the change anymore
//int64 nValue = wtx.vout[0].nValue;
//strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";
//strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";
}
int64 nTxFee = nDebit - wtx.GetValueOut();
@ -1469,6 +1512,9 @@ COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
//m_listBox->Append("Test 2");
m_listBox->SetSelection(0);
SelectPage(0);
#ifndef __WXMSW__
m_checkBoxMinimizeOnClose->SetLabel("&Minimize on close");
#endif
// Init values
m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));
@ -1481,9 +1527,7 @@ COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
m_spinCtrlLimitProcessors->SetRange(1, nProcessors);
m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());
m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);
m_checkBoxMinimizeOnClose->Enable(fMinimizeToTray);
m_checkBoxMinimizeOnClose->SetValue(fMinimizeToTray && fMinimizeOnClose);
fTmpMinimizeOnClose = fMinimizeOnClose;
m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);
m_checkBoxUseProxy->SetValue(fUseProxy);
m_textCtrlProxyIP->Enable(fUseProxy);
m_textCtrlProxyPort->Enable(fUseProxy);
@ -1521,22 +1565,6 @@ void COptionsDialog::OnCheckBoxLimitProcessors(wxCommandEvent& event)
m_spinCtrlLimitProcessors->Enable(event.IsChecked());
}
void COptionsDialog::OnCheckBoxMinimizeToTray(wxCommandEvent& event)
{
m_checkBoxMinimizeOnClose->Enable(event.IsChecked());
// Save the value in fTmpMinimizeOnClose so we can
// show the checkbox unchecked when its parent is unchecked
if (event.IsChecked())
m_checkBoxMinimizeOnClose->SetValue(fTmpMinimizeOnClose);
else
{
fTmpMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
m_checkBoxMinimizeOnClose->SetValue(false);
}
}
void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
{
m_textCtrlProxyIP->Enable(event.IsChecked());
@ -1608,12 +1636,12 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event)
{
fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();
walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
ptaskbaricon->Show(fMinimizeToTray);
ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
}
if (fMinimizeOnClose != (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose))
if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())
{
fMinimizeOnClose = (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose);
fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();
walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
}
@ -1643,6 +1671,9 @@ CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
if (str.Find('Â') != wxNOT_FOUND)
str.Remove(str.Find('Â'), 1);
m_staticTextMain->SetLabel(str);
#ifndef __WXMSW__
SetSize(510, 380);
#endif
}
void CAboutDialog::OnButtonOK(wxCommandEvent& event)
@ -1849,7 +1880,7 @@ CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 n
SetTitle(strprintf("Sending %s to %s", FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));
m_textCtrlStatus->SetValue("");
_beginthread(SendingDialogStartTransfer, 0, this);
CreateThread(SendingDialogStartTransfer, this);
}
CSendingDialog::~CSendingDialog()
@ -2856,7 +2887,7 @@ CViewProductDialog::CViewProductDialog(wxWindow* parent, const CProduct& product
this->Layout();
// Request details from seller
_beginthread(ThreadRequestProductDetails, 0, new pair<CProduct, wxEvtHandler*>(product, GetEventHandler()));
CreateThread(ThreadRequestProductDetails, new pair<CProduct, wxEvtHandler*>(product, GetEventHandler()));
}
CViewProductDialog::~CViewProductDialog()
@ -3256,6 +3287,7 @@ void CEditReviewDialog::GetReview(CReview& review)
enum
{
ID_TASKBAR_RESTORE = 10001,
ID_TASKBAR_OPTIONS,
ID_TASKBAR_GENERATE,
ID_TASKBAR_EXIT,
};
@ -3263,6 +3295,7 @@ enum
BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)
EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)
EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)
EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)
EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)
EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)
EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)
@ -3312,9 +3345,18 @@ void CMyTaskBarIcon::OnMenuRestore(wxCommandEvent& event)
Restore();
}
void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)
{
// Since it's modal, get the main window to do it
wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_MENUOPTIONSOPTIONS);
pframeMain->AddPendingEvent(event2);
}
void CMyTaskBarIcon::Restore()
{
pframeMain->Show();
wxIconizeEvent event(0, false);
pframeMain->AddPendingEvent(event);
pframeMain->Iconize(false);
pframeMain->Raise();
}
@ -3344,6 +3386,7 @@ wxMenu* CMyTaskBarIcon::CreatePopupMenu()
{
wxMenu* pmenu = new wxMenu;
pmenu->Append(ID_TASKBAR_RESTORE, "&Open Bitcoin");
pmenu->Append(ID_TASKBAR_OPTIONS, "O&ptions...");
pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, "&Generate Coins")->Check(fGenerateBitcoins);
#ifndef __WXMAC_OSX__ // Mac has built-in quit menu
pmenu->AppendSeparator();
@ -3582,7 +3625,7 @@ bool CMyApp::OnInit2()
{
CBlockIndex* pindex = (*mi).second;
CBlock block;
block.ReadFromDisk(pindex, true);
block.ReadFromDisk(pindex);
block.BuildMerkleTree();
block.print();
printf("\n");
@ -3632,20 +3675,20 @@ bool CMyApp::OnInit2()
if (mapArgs.count("-min"))
pframeMain->Iconize(true);
pframeMain->Show(true); // have to show first to get taskbar button to hide
pframeMain->Show(!fMinimizeToTray || !pframeMain->IsIconized());
ptaskbaricon->Show(fMinimizeToTray);
if (fMinimizeToTray && pframeMain->IsIconized())
fClosedToTray = true;
pframeMain->Show(!fClosedToTray);
ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);
_beginthread(ThreadDelayedRepaint, 0, NULL);
CreateThread(ThreadDelayedRepaint, NULL);
if (!CheckDiskSpace())
return false;
RandAddSeedPerfmon();
if (!StartNode(strErrors))
wxMessageBox(strErrors, "Bitcoin");
GenerateBitcoins(fGenerateBitcoins);
if (!CreateThread(StartNode, NULL))
wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
if (fFirstRun)
SetStartOnSystemStartup(true);

2
ui.h
View file

@ -112,7 +112,6 @@ protected:
void OnListBox(wxCommandEvent& event);
void OnKillFocusTransactionFee(wxFocusEvent& event);
void OnCheckBoxLimitProcessors(wxCommandEvent& event);
void OnCheckBoxMinimizeToTray(wxCommandEvent& event);
void OnCheckBoxUseProxy(wxCommandEvent& event);
void OnKillFocusProxy(wxFocusEvent& event);
@ -447,6 +446,7 @@ protected:
// Event handlers
void OnLeftButtonDClick(wxTaskBarIconEvent& event);
void OnMenuRestore(wxCommandEvent& event);
void OnMenuOptions(wxCommandEvent& event);
void OnUpdateUIGenerate(wxUpdateUIEvent& event);
void OnMenuGenerate(wxCommandEvent& event);
void OnMenuExit(wxCommandEvent& event);

View file

@ -45,7 +45,7 @@ CMainFrameBase::CMainFrameBase( wxWindow* parent, wxWindowID id, const wxString&
m_menuOptions->Append( m_menuOptionsChangeYourAddress );
wxMenuItem* m_menuOptionsOptions;
m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( wxT("&Options...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_MENUOPTIONSOPTIONS, wxString( wxT("&Options...") ) , wxEmptyString, wxITEM_NORMAL );
m_menuOptions->Append( m_menuOptionsOptions );
m_menubar->Append( m_menuOptions, wxT("&Options") );
@ -428,21 +428,13 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w
bSizer69->Add( m_checkBoxStartOnSystemStartup, 0, wxALL, 5 );
m_checkBoxMinimizeToTray = new wxCheckBox( m_panelMain, wxID_ANY, wxT("&Minimize to the system tray instead of the taskbar"), wxDefaultPosition, wxDefaultSize, 0 );
m_checkBoxMinimizeToTray = new wxCheckBox( m_panelMain, wxID_ANY, wxT("&Minimize to the tray instead of the taskbar"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer69->Add( m_checkBoxMinimizeToTray, 0, wxALL, 5 );
wxBoxSizer* bSizer101;
bSizer101 = new wxBoxSizer( wxHORIZONTAL );
m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, wxT("M&inimize to the tray on close"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer101->Add( 16, 0, 0, 0, 5 );
m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, wxT("Mi&nimize to system tray on close"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer101->Add( m_checkBoxMinimizeOnClose, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
bSizer69->Add( bSizer101, 1, wxEXPAND, 5 );
bSizer69->Add( m_checkBoxMinimizeOnClose, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
wxBoxSizer* bSizer102;
bSizer102 = new wxBoxSizer( wxHORIZONTAL );

View file

@ -43,51 +43,52 @@
#define wxID_MAINFRAME 1000
#define wxID_VIEWSHOWGENERATED 1001
#define wxID_OPTIONSGENERATEBITCOINS 1002
#define wxID_BUTTONSEND 1003
#define wxID_BUTTONRECEIVE 1004
#define wxID_TEXTCTRLADDRESS 1005
#define wxID_BUTTONCOPY 1006
#define wxID_BUTTONCHANGE 1007
#define wxID_TRANSACTIONFEE 1008
#define wxID_PROXYIP 1009
#define wxID_PROXYPORT 1010
#define wxID_TEXTCTRLPAYTO 1011
#define wxID_BUTTONPASTE 1012
#define wxID_BUTTONADDRESSBOOK 1013
#define wxID_TEXTCTRLAMOUNT 1014
#define wxID_CHOICETRANSFERTYPE 1015
#define wxID_LISTCTRL 1016
#define wxID_BUTTONRENAME 1017
#define wxID_BUTTONNEW 1018
#define wxID_BUTTONEDIT 1019
#define wxID_BUTTONDELETE 1020
#define wxID_DEL0 1021
#define wxID_DEL1 1022
#define wxID_DEL2 1023
#define wxID_DEL3 1024
#define wxID_DEL4 1025
#define wxID_DEL5 1026
#define wxID_DEL6 1027
#define wxID_DEL7 1028
#define wxID_DEL8 1029
#define wxID_DEL9 1030
#define wxID_DEL10 1031
#define wxID_DEL11 1032
#define wxID_DEL12 1033
#define wxID_DEL13 1034
#define wxID_DEL14 1035
#define wxID_DEL15 1036
#define wxID_DEL16 1037
#define wxID_DEL17 1038
#define wxID_DEL18 1039
#define wxID_DEL19 1040
#define wxID_BUTTONPREVIEW 1041
#define wxID_BUTTONSAMPLE 1042
#define wxID_CANCEL2 1043
#define wxID_BUTTONBACK 1044
#define wxID_BUTTONNEXT 1045
#define wxID_SUBMIT 1046
#define wxID_TEXTCTRL 1047
#define wxID_MENUOPTIONSOPTIONS 1003
#define wxID_BUTTONSEND 1004
#define wxID_BUTTONRECEIVE 1005
#define wxID_TEXTCTRLADDRESS 1006
#define wxID_BUTTONCOPY 1007
#define wxID_BUTTONCHANGE 1008
#define wxID_TRANSACTIONFEE 1009
#define wxID_PROXYIP 1010
#define wxID_PROXYPORT 1011
#define wxID_TEXTCTRLPAYTO 1012
#define wxID_BUTTONPASTE 1013
#define wxID_BUTTONADDRESSBOOK 1014
#define wxID_TEXTCTRLAMOUNT 1015
#define wxID_CHOICETRANSFERTYPE 1016
#define wxID_LISTCTRL 1017
#define wxID_BUTTONRENAME 1018
#define wxID_BUTTONNEW 1019
#define wxID_BUTTONEDIT 1020
#define wxID_BUTTONDELETE 1021
#define wxID_DEL0 1022
#define wxID_DEL1 1023
#define wxID_DEL2 1024
#define wxID_DEL3 1025
#define wxID_DEL4 1026
#define wxID_DEL5 1027
#define wxID_DEL6 1028
#define wxID_DEL7 1029
#define wxID_DEL8 1030
#define wxID_DEL9 1031
#define wxID_DEL10 1032
#define wxID_DEL11 1033
#define wxID_DEL12 1034
#define wxID_DEL13 1035
#define wxID_DEL14 1036
#define wxID_DEL15 1037
#define wxID_DEL16 1038
#define wxID_DEL17 1039
#define wxID_DEL18 1040
#define wxID_DEL19 1041
#define wxID_BUTTONPREVIEW 1042
#define wxID_BUTTONSAMPLE 1043
#define wxID_CANCEL2 1044
#define wxID_BUTTONBACK 1045
#define wxID_BUTTONNEXT 1046
#define wxID_SUBMIT 1047
#define wxID_TEXTCTRL 1048
///////////////////////////////////////////////////////////////////////////////
/// Class CMainFrameBase
@ -203,7 +204,6 @@ class COptionsDialogBase : public wxDialog
wxStaticText* m_staticText35;
wxCheckBox* m_checkBoxStartOnSystemStartup;
wxCheckBox* m_checkBoxMinimizeToTray;
wxCheckBox* m_checkBoxMinimizeOnClose;
wxCheckBox* m_checkBoxUseProxy;

View file

@ -70,7 +70,7 @@
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxMenuBar" expanded="0">
<object class="wxMenuBar" expanded="1">
<property name="bg">240,240,240</property>
<property name="context_help"></property>
<property name="enabled">1</property>
@ -193,7 +193,7 @@
<property name="checked">0</property>
<property name="enabled">1</property>
<property name="help"></property>
<property name="id">wxID_ANY</property>
<property name="id">wxID_MENUOPTIONSOPTIONS</property>
<property name="kind">wxITEM_NORMAL</property>
<property name="label">&amp;Options...</property>
<property name="name">m_menuOptionsOptions</property>
@ -2319,7 +2319,7 @@
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">&amp;Minimize to the system tray instead of the taskbar</property>
<property name="label">&amp;Minimize to the tray instead of the taskbar</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_checkBoxMinimizeToTray</property>
@ -2360,75 +2360,54 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="1">
<property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="bg"></property>
<property name="checked">0</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">M&amp;inimize to the tray on close</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">bSizer101</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag"></property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">16</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="bg"></property>
<property name="checked">0</property>
<property name="context_help"></property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Mi&amp;nimize to system tray on close</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">m_checkBoxMinimizeOnClose</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<property name="name">m_checkBoxMinimizeOnClose</property>
<property name="permission">protected</property>
<property name="pos"></property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCheckBox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">

View file

@ -85,14 +85,14 @@ void RandAddSeed()
void RandAddSeedPerfmon()
{
#ifdef __WXMSW__
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// This can take up to 2 seconds, so only do it every 10 minutes
static int64 nLastPerfmon;
if (GetTime() < nLastPerfmon + 10 * 60)
return;
nLastPerfmon = GetTime();
#ifdef __WXMSW__
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// Seed with the entire set of perfmon data
unsigned char pdata[250000];
memset(pdata, 0, sizeof(pdata));
@ -109,9 +109,30 @@ void RandAddSeedPerfmon()
printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str(), nSize);
}
#else
printf("%s RandAddSeed()\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
#endif
}
uint64 GetRand(uint64 nMax)
{
if (nMax == 0)
return 0;
// The range of the random source must be a multiple of the modulus
// to give every possible output value an equal possibility
uint64 nRange = (UINT64_MAX / nMax) * nMax;
uint64 nRand = 0;
do
RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
while (nRand >= nRange);
return (nRand % nMax);
}
@ -449,28 +470,6 @@ string GetDataDir()
uint64 GetRand(uint64 nMax)
{
if (nMax == 0)
return 0;
// The range of the random source must be a multiple of the modulus
// to give every possible output value an equal possibility
uint64 nRange = (_UI64_MAX / nMax) * nMax;
uint64 nRand = 0;
do
RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
while (nRand >= nRange);
return (nRand % nMax);
}
//
@ -483,7 +482,6 @@ uint64 GetRand(uint64 nMax)
// note: NTP isn't implemented yet, so until then we just use the median
// of other nodes clocks to correct ours.
//
int64 GetTime()
{
return time(NULL);

105
util.h
View file

@ -54,9 +54,13 @@ inline T& REF(const T& val)
return (T&)val;
}
#ifndef __WXMSW__
#define _UI64_MAX UINT64_MAX
#define _I64_MAX INT64_MAX
#ifdef __WXMSW__
#define MSG_NOSIGNAL 0
#define MSG_DONTWAIT 0
#define UINT64_MAX _UI64_MAX
#define INT64_MAX _I64_MAX
#define INT64_MIN _I64_MIN
#else
#define WSAGetLastError() errno
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEMSGSIZE EMSGSIZE
@ -74,18 +78,6 @@ typedef u_int SOCKET;
#define MAX_PATH 1024
#define Sleep(n) wxMilliSleep(n)
#define Beep(n1,n2) (0)
inline int _beginthread(void(*pfn)(void*), unsigned nStack, void* parg) { thread(bind(pfn, parg)); return 0; }
inline void _endthread() { pthread_exit(NULL); }
inline int GetCurrentThread() { return 0; }
// threads are processes on linux, so setpriority affects just the one thread
inline void SetThreadPriority(int nThread, int nPriority) { setpriority(PRIO_PROCESS, getpid(), nPriority); }
#define THREAD_PRIORITY_LOWEST PRIO_MIN
#define THREAD_PRIORITY_BELOW_NORMAL 2
#define THREAD_PRIORITY_NORMAL 0
#define THREAD_PRIORITY_ABOVE_NORMAL 0
#endif
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
@ -133,6 +125,7 @@ void AddTimeData(unsigned int ip, int64 nTime);
// Wrapper to automatically initialize critical sections
class CCriticalSection
{
@ -201,8 +194,6 @@ public:
inline int OutputDebugStringF(const char* pszFormat, ...)
{
int ret = 0;
@ -498,3 +489,83 @@ inline uint160 Hash160(const vector<unsigned char>& vch)
RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
// Note: It turns out we might have been able to use boost::thread
// by using TerminateThread(boost::thread.native_handle(), 0);
#ifdef __WXMSW__
typedef HANDLE pthread_t;
inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
{
DWORD nUnused = 0;
HANDLE hthread =
CreateThread(
NULL, // default security
0, // inherit stack size from parent
(LPTHREAD_START_ROUTINE)pfn, // function pointer
parg, // argument
0, // creation option, start immediately
&nUnused); // thread identifier
if (hthread == NULL)
{
printf("Error: CreateThread() returned %d\n", GetLastError());
return (pthread_t)0;
}
if (!fWantHandle)
{
CloseHandle(hthread);
return (pthread_t)-1;
}
return hthread;
}
inline void SetThreadPriority(int nPriority)
{
SetThreadPriority(GetCurrentThread(), nPriority);
}
#else
inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
{
pthread_t hthread = 0;
int ret = pthread_create(&hthread, NULL, (void*(*)(void*))pfn, parg);
if (ret != 0)
{
printf("Error: pthread_create() returned %d\n", ret);
return (pthread_t)0;
}
if (!fWantHandle)
return (pthread_t)-1;
return hthread;
}
#define THREAD_PRIORITY_LOWEST PRIO_MIN
#define THREAD_PRIORITY_BELOW_NORMAL 2
#define THREAD_PRIORITY_NORMAL 0
#define THREAD_PRIORITY_ABOVE_NORMAL 0
inline void SetThreadPriority(int nPriority)
{
// threads are processes on linux, so PRIO_PROCESS affects just the one thread
setpriority(PRIO_PROCESS, getpid(), nPriority);
}
inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)
{
return (pthread_cancel(hthread) == 0);
}
inline void ExitThread(unsigned int nExitCode)
{
pthread_exit((void*)nExitCode);
}
#endif