forked from qt-creator/qt-creator
zeroconf: clean up destruction/startup
* fixed race condition in destruction (hopefully ;) * cleaned startup status testing in MainConnection * faster shutdown/startup, less blocking in embedded lib getProperty Change-Id: I3e9062fa59465523feb47ba195cf4ef465d2c16c Reviewed-by: Daniel Molkentin <daniel.molkentin@nokia.com>
This commit is contained in:
@@ -215,10 +215,29 @@ static int read_all(dnssd_sock_t sd, char *buf, int len)
|
||||
{
|
||||
// Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while () loop instead.
|
||||
//if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
|
||||
int nErr = 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
ssize_t num_read = recv(sd, buf, len, 0);
|
||||
timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 100000;
|
||||
fd_set readFds, writeFds, exceptFds;
|
||||
memset(&readFds,0,sizeof(readFds));
|
||||
memset(&writeFds,0,sizeof(writeFds));
|
||||
memset(&exceptFds,0,sizeof(exceptFds));
|
||||
FD_SET(sd, &readFds);
|
||||
FD_SET(sd, &writeFds);
|
||||
FD_SET(sd, &exceptFds);
|
||||
ssize_t num_read = 0;
|
||||
int nVal=select(sd+1, &readFds, &writeFds, &exceptFds, &timeout);
|
||||
if (nVal < 1 || !FD_ISSET(sd, &readFds)) {
|
||||
++nErr;
|
||||
if (nErr < 5) // wait max 0.5s without reading
|
||||
continue;
|
||||
} else {
|
||||
num_read = recv(sd, buf, len, 0);
|
||||
}
|
||||
// It is valid to get an interrupted system call error e.g., somebody attaching
|
||||
// in a debugger, retry without failing
|
||||
if ((num_read < 0) && (errno == EINTR)) { syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue"); continue; }
|
||||
|
@@ -752,13 +752,17 @@ void ServiceGatherer::stopResolve(ZK_IP_Protocol protocol)
|
||||
{
|
||||
if ((protocol == ZK_PROTO_IPv4_OR_IPv6 || protocol == ZK_PROTO_IPv4)
|
||||
&& (status & ResolveConnectionActive) != 0) {
|
||||
lib()->refDeallocate(resolveConnection);
|
||||
QMutexLocker l(serviceBrowser->mainConnection->lock());
|
||||
if (serviceBrowser->mainConnection->status() < MainConnection::Stopping)
|
||||
lib()->refDeallocate(resolveConnection);
|
||||
status &= ~ResolveConnectionActive;
|
||||
serviceBrowser->updateFlowStatusForCancel();
|
||||
}
|
||||
if ((protocol == ZK_PROTO_IPv4_OR_IPv6 || protocol == ZK_PROTO_IPv6)
|
||||
&& (status & ResolveConnectionV6Active) != 0) {
|
||||
lib()->refDeallocate(resolveConnectionV6);
|
||||
QMutexLocker l(serviceBrowser->mainConnection->lock());
|
||||
if (serviceBrowser->mainConnection->status() < MainConnection::Stopping)
|
||||
lib()->refDeallocate(resolveConnectionV6);
|
||||
status &= ~ResolveConnectionV6Active;
|
||||
serviceBrowser->updateFlowStatusForCancel();
|
||||
}
|
||||
@@ -837,7 +841,9 @@ void ServiceGatherer::restartResolve(ZK_IP_Protocol protocol)
|
||||
void ServiceGatherer::stopTxt()
|
||||
{
|
||||
if ((status & TxtConnectionActive) == 0) return;
|
||||
lib()->refDeallocate(txtConnection);
|
||||
QMutexLocker l(serviceBrowser->mainConnection->lock());
|
||||
if (serviceBrowser->mainConnection->status() < MainConnection::Stopping)
|
||||
lib()->refDeallocate(txtConnection);
|
||||
status &= ~TxtConnectionActive;
|
||||
serviceBrowser->updateFlowStatusForCancel();
|
||||
}
|
||||
@@ -863,7 +869,9 @@ void ServiceGatherer::restartTxt()
|
||||
void ServiceGatherer::stopHostResolution()
|
||||
{
|
||||
if ((status & AddrConnectionActive) == 0) return;
|
||||
lib()->refDeallocate(addrConnection);
|
||||
QMutexLocker l(serviceBrowser->mainConnection->lock());
|
||||
if (serviceBrowser->mainConnection->status() < MainConnection::Stopping)
|
||||
lib()->refDeallocate(addrConnection);
|
||||
status &= ~AddrConnectionActive;
|
||||
serviceBrowser->updateFlowStatusForCancel();
|
||||
}
|
||||
@@ -1552,14 +1560,21 @@ void ServiceBrowserPrivate::startedBrowsing()
|
||||
|
||||
void MainConnection::stop(bool wait)
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
if (m_status.load() < Stopping)
|
||||
#else
|
||||
if (m_status < Stopping)
|
||||
#endif
|
||||
{
|
||||
if (QThread::currentThread() == m_thread)
|
||||
qCritical() << "ERROR ZerocConf::MainConnection::stop called from m_thread";
|
||||
// This will most likely lock if called from the connection thread (as mainThreadLock is non recusive)
|
||||
// Making it recursive would open a hole during the startup of the thread.
|
||||
// As of now this should always be called during the destruction of a browser,
|
||||
// so from another thread.
|
||||
increaseStatusTo(Stopping);
|
||||
if (m_mainRef)
|
||||
QMutexLocker l(mainThreadLock());
|
||||
QMutexLocker l2(lock());
|
||||
}
|
||||
if (m_mainRef) {
|
||||
lib->stopConnection(m_mainRef);
|
||||
m_mainRef = 0;
|
||||
}
|
||||
if (!m_thread)
|
||||
increaseStatusTo(Stopped);
|
||||
else if (wait && QThread::currentThread() != m_thread)
|
||||
@@ -1569,38 +1584,30 @@ void MainConnection::stop(bool wait)
|
||||
MainConnection::MainConnection():
|
||||
flowStatus(NormalRFS),
|
||||
lib(zeroConfLibInstance()->defaultLib()), m_lock(QMutex::Recursive),
|
||||
m_mainThreadLock(QMutex::Recursive), m_mainRef(0), m_failed(false), m_status(Starting), m_nErrs(0)
|
||||
m_mainThreadLock(QMutex::NonRecursive), m_mainRef(0), m_failed(false), m_status(Starting), m_nErrs(0)
|
||||
{
|
||||
if (lib.isNull()){
|
||||
qDebug() << "could not load a valid library for ZeroConf::MainConnection, failing";
|
||||
} else {
|
||||
m_thread = new ConnectionThread(*this);
|
||||
m_mainThreadLock.lock();
|
||||
m_thread->start(); // delay startup??
|
||||
}
|
||||
}
|
||||
|
||||
MainConnection::~MainConnection()
|
||||
{
|
||||
stop();
|
||||
stop(true);
|
||||
delete m_thread;
|
||||
// to do
|
||||
}
|
||||
|
||||
bool MainConnection::increaseStatusTo(int s)
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
int sAtt = m_status.load();
|
||||
#else
|
||||
int sAtt = m_status;
|
||||
#endif
|
||||
int sAtt = status();
|
||||
while (sAtt < s){
|
||||
if (m_status.testAndSetRelaxed(sAtt, s))
|
||||
return true;
|
||||
#if QT_VERSION >= 0x050000
|
||||
sAtt = m_status.load();
|
||||
#else
|
||||
sAtt = m_status;
|
||||
#endif
|
||||
sAtt = status();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1621,11 +1628,7 @@ void MainConnection::waitStartup()
|
||||
while (true){
|
||||
{
|
||||
QMutexLocker l(lock());
|
||||
#if QT_VERSION >= 0x050000
|
||||
sAtt = m_status.load();
|
||||
#else
|
||||
sAtt = m_status;
|
||||
#endif
|
||||
sAtt = status();
|
||||
if (sAtt >= Running)
|
||||
return;
|
||||
}
|
||||
@@ -1639,11 +1642,7 @@ void MainConnection::addBrowser(ServiceBrowserPrivate *browser)
|
||||
QList<ErrorMessage> errs;
|
||||
{
|
||||
QMutexLocker l(lock());
|
||||
#if QT_VERSION >= 0x050000
|
||||
actualStatus = m_status.load();
|
||||
#else
|
||||
actualStatus = m_status;
|
||||
#endif
|
||||
actualStatus = status();
|
||||
m_browsers.append(browser);
|
||||
errs = m_errors;
|
||||
}
|
||||
@@ -1716,11 +1715,7 @@ void MainConnection::abortLib(){
|
||||
void MainConnection::createConnection()
|
||||
{
|
||||
gotoValidLib();
|
||||
#if QT_VERSION >= 0x050000
|
||||
while (m_status.load() <= Running) {
|
||||
#else
|
||||
while (m_status <= Running) {
|
||||
#endif
|
||||
while (status() <= Running) {
|
||||
if (!lib) {
|
||||
increaseStatusTo(Stopped);
|
||||
break;
|
||||
@@ -1812,19 +1807,21 @@ void MainConnection::destroyConnection()
|
||||
|
||||
void MainConnection::handleEvents()
|
||||
{
|
||||
if (!m_status.testAndSetAcquire(Starting, Started)){
|
||||
appendError(ErrorMessage::WarningLevel, tr("MainConnection::handleEvents called with m_status != Starting, aborting"));
|
||||
increaseStatusTo(Stopped);
|
||||
return;
|
||||
try {
|
||||
if (!m_status.testAndSetAcquire(Starting, Started)){
|
||||
appendError(ErrorMessage::WarningLevel, tr("MainConnection::handleEvents called with m_status != Starting, aborting"));
|
||||
increaseStatusTo(Stopped);
|
||||
return;
|
||||
}
|
||||
m_nErrs = 0;
|
||||
createConnection();
|
||||
} catch(...) {
|
||||
mainThreadLock()->unlock();
|
||||
throw;
|
||||
}
|
||||
m_nErrs = 0;
|
||||
createConnection();
|
||||
mainThreadLock()->unlock();
|
||||
increaseStatusTo(Running);
|
||||
#if QT_VERSION >= 0x050000
|
||||
while (m_status.load() < Stopping) {
|
||||
#else
|
||||
while (m_status < Stopping) {
|
||||
#endif
|
||||
while (status() < Stopping) {
|
||||
QMutexLocker l(mainThreadLock());
|
||||
if (m_nErrs > 10)
|
||||
increaseStatusTo(Stopping);
|
||||
@@ -1861,16 +1858,22 @@ void MainConnection::handleEvents()
|
||||
|
||||
ZConfLib::ConnectionRef MainConnection::mainRef()
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
while (m_status.load() < Running){
|
||||
#else
|
||||
while (m_status < Running){
|
||||
#endif
|
||||
while (status() < Running){
|
||||
QThread::yieldCurrentThread();
|
||||
}
|
||||
return m_mainRef;
|
||||
}
|
||||
|
||||
MainConnection::Status MainConnection::status()
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
return static_cast<MainConnection::Status>(m_status.load());
|
||||
#else
|
||||
int val = m_status;
|
||||
return static_cast<MainConnection::Status>(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
QList<ErrorMessage> MainConnection::errors()
|
||||
{
|
||||
QMutexLocker l(lock());
|
||||
|
@@ -253,6 +253,7 @@ public:
|
||||
bool increaseStatusTo(int s);
|
||||
void handleEvents();
|
||||
ZConfLib::ConnectionRef mainRef();
|
||||
Status status();
|
||||
|
||||
QList<ErrorMessage> errors();
|
||||
bool isOk();
|
||||
|
Reference in New Issue
Block a user