PDA

View Full Version : QThread quit() issue.



rokkamraja
15th December 2009, 13:54
Hi All,

I am trying to use Curl and QThread to make asynchronous calls. So I have created my own HTTP Handler class in which I perform curl requests using QTimer in separate threads. Now, all instances of below class are being called from a singleton class which is non-gui and its methods will be called from GUI thread. I have 3 instances of Handler.

Strangely, the code works fine on every Windows machine and also MAC, except for WIN7 64 bit where it crashes.

The crash exception code is c00005. 1st instance runs successfully, and then 2nd instance starts and after its 1st requestFinished signal I do a handle->finish, in which I call quit(), (now changed it to exit(0) ) which crashes the application.

Can anyone please tell me where possibly a crash can happen during quit() and how to go about debugging ?

The thread code is pasted below;

Subclassed QThread and code is below:

HTTPHANDLER.h

#include <QThread>

#include <QByteArray>

#include <QMutex>

#include <QMap>

class HttpHandler : public QThread

{

Q_OBJECT

friend size_t gHttpHandlerCurlDataAvailableCallback(void *ptr, size_t size, size_t nmemb, void *stream);

public:

HttpHandler();

~HttpHandler();

bool setRequest(QString url, QByteArray postData, QMap<QString,QString> headerList);

void execute();

void finish();

void userAgentUse( QString &userAgent );

signals:

void requestFinished(int curl_code, QByteArray response);

protected:

virtual void run();

protected slots:

void perform();

private:

size_t curlDataReceived(void *ptr, size_t size, size_t nmemb);

bool m_requestPending;

QMutex m_mutex;

QMutex m_mutex1;

QString m_url;

QByteArray m_respData;

QByteArray m_reqData;

QMap<QString, QString> m_reqHeaders;

QThread *prevThread;

};


HTTPHANDLER.cpp


#include "httphandler.h"

#include <QTimer>

#include "curl.h"

#include <storageengine.h>

#include <Log.h>

size_t gCurlVerboseCallBack(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)

{

QByteArray ba;

ba.append(data, size);

QString str(ba);

return 0;

}

size_t gHttpHandlerCurlDataAvailableCallback(void *ptr, size_t size, size_t nmemb, void *stream)

{

HttpHandler *handler = (HttpHandler *)stream;

return handler->curlDataReceived(ptr, size, nmemb);

}

HttpHandler::HttpHandler()

: m_requestPending(false)

{

}

HttpHandler::~HttpHandler()

{

if (isRunning())

{

QMutexLocker lock( &m_mutex );

terminate();

wait();

}
}

bool HttpHandler::setRequest(QString url, QByteArray postData, QMap<QString,QString> headerList)

{

QMutexLocker lock(&m_mutex);

if (m_requestPending)

{

return false;

}

//accept request

m_url = url;

m_reqData = postData;

m_reqHeaders = headerList;

m_respData.clear();

m_requestPending = true;

return true;

}

void HttpHandler::execute()

{

if( isRunning() )

{

terminate();

wait();

}
prevThread = this->thread();

QObject::moveToThread( this );

start();

}

void HttpHandler::run()

{
QTimer::singleShot(0, this, SLOT(perform()));

exec();

}

void HttpHandler::finish()

{

DimdimLogger::getInstance()->write("HttpHandler Finished\n");

QMutexLocker lock(&m_mutex);

m_requestPending = false;

exit(0);

moveToThread( prevThread );
}

void HttpHandler::userAgentUse( QString &userAgent )

{

QMutexLocker lock(&m_mutex);

#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)

userAgent = "API/5.5/windows";

#elif defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)

userAgent = "API/5.5/linux";

#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)

#if !defined(MAC_OS_X_VERSION_10_6)

userAgent = "API/5.5/snow_leopard";

#else

userAgent = "API/5.5/leopard";

#endif

#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)

userAgent = "API/5.5/unix";

#endif

}

void HttpHandler::perform()

{

char * cv = curl_version();

CURL * curl_handle = curl_easy_init();

// curl_easy_setopt(curl_handle, CURLOPT_TCP_NODELAY, 1);

// curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);

// curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, -1);

QString userAgent;

userAgentUse( userAgent );

curl_easy_setopt( curl_handle, CURLOPT_USERAGENT, userAgent.toStdString().c_str() );

// curl_easy_setopt(curl_handle, CURLOPT_DEBUGDATA, this);

// curl_easy_setopt(curl_handle, CURLOPT_DEBUGFUNCTION, gCurlVerboseCallBack);

// curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);

m_url.toStdString().c_str());

//set proxy info

QString proxyAddress, socksVersion, domain, p_userName, p_password, auth, autodetect;

StorageEngine::getInstance()->readProxyInfo1( proxyAddress, socksVersion, domain, p_userName, p_password, autodetect );

//set proxy info

if( ( socksVersion.compare("3") != 0) && //not direct connection

( socksVersion.compare("4") != 0) ) //bypass not selected by user

{

curl_easy_setopt( curl_handle, CURLOPT_PROXY,

proxyAddress.toAscii().data());

//curl_easy_setopt( curl_handle, CURLOPT_USERPWD, "");

if( !domain.isEmpty() )

{

auth.append( domain );

if( !p_userName.isEmpty() )

{

auth.append( "/" + p_userName );

if( !p_password.isEmpty() )

{

auth.append( ":" + p_password );

}

}

}

curl_easy_setopt( curl_handle, CURLOPT_PROXYUSERPWD, auth.toStdString().c_str() );

if( socksVersion.compare( "1" ) == 0 )

{

curl_easy_setopt(curl_handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4 );

}

else if( socksVersion.compare( "2" ) == 0 )

{

curl_easy_setopt(curl_handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5 );

}

else

{

curl_easy_setopt(curl_handle, CURLOPT_HTTPPROXYTUNNEL, 1);

curl_easy_setopt(curl_handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);

}

}

m_url.toAscii().data());

//set POST fields

//curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, m_reqData.length() );

if( m_reqData.isEmpty() )

{

curl_easy_setopt( curl_handle, CURLOPT_HTTPGET, 1 );

}

else

{

curl_easy_setopt(curl_handle, CURLOPT_POST, 1);

curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, m_reqData.data());

}

//set the CURL callbacks

curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, gHttpHandlerCurlDataAvailableCallback);

curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, this);

//set headers

struct curl_slist *headerlist=NULL;

if (m_reqHeaders.size() > 0)

{

QMap<QString,QString>::iterator iter = m_reqHeaders.begin();

for (;iter != m_reqHeaders.end(); ++iter)

{

QString field;

field = iter.key() + ": " + iter.value();

headerlist = curl_slist_append(headerlist, field.toAscii().data());

}

}

DimdimLogger::getInstance()->write("HttpHandler: URL is: %s\n", m_url.toAscii().data());

CURLcode curl_error = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headerlist);

if (CURLE_OK != curl_error)

{

emit requestFinished((int) curl_error, m_respData);

curl_slist_free_all(headerlist);

curl_easy_cleanup(curl_handle);

return;

}

char *url = strdup( m_url.toStdString().c_str() );

curl_easy_setopt(curl_handle, CURLOPT_URL, url);

m_url.toAscii().data());

curl_error = curl_easy_perform(curl_handle);

m_url.toAscii().data());


if (headerlist)

curl_slist_free_all(headerlist);

curl_easy_cleanup(curl_handle);

curl_handle = NULL;

free( url );
emit requestFinished((int)curl_error, m_respData);

}

size_t HttpHandler::curlDataReceived(void *ptr, size_t size, size_t nmemb)

{

QMutexLocker lock(&m_mutex);

QByteArray ba;

ba.append((const char *)ptr, size * nmemb);

QString str(ba);

m_respData.append((const char *)ptr, size * nmemb);

return size * nmemb;

}

faldzip
15th December 2009, 16:34
I don't think that anyone is going to read this... Use the CODE tags and paste only important part of code.