Started to replace asynchronous thread cancellation with pthread_join/exit
combination (which mean the code now depends on libcurl never to hang!!). This should (again ;) ) fix #235. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@8700 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
8c22b21166
commit
4333eccc5c
@ -102,7 +102,7 @@ void NetworkHttp::startNetworkThread()
|
|||||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||||
// Should be the default, but just in case:
|
// Should be the default, but just in case:
|
||||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||||
|
|
||||||
m_thread_id.setAtomic(new pthread_t());
|
m_thread_id.setAtomic(new pthread_t());
|
||||||
int error = pthread_create(m_thread_id.getData(), &attr,
|
int error = pthread_create(m_thread_id.getData(), &attr,
|
||||||
@ -133,7 +133,9 @@ void *NetworkHttp::mainLoop(void *obj)
|
|||||||
|
|
||||||
me->m_current_request = NULL;
|
me->m_current_request = NULL;
|
||||||
me->m_all_requests.lock();
|
me->m_all_requests.lock();
|
||||||
while(me->m_all_requests.getData().size() == 0 ||
|
bool abort = false;
|
||||||
|
while(!abort ||
|
||||||
|
me->m_all_requests.getData().size() == 0 ||
|
||||||
me->m_all_requests.getData()[0]->getCommand() != Request::HC_QUIT )
|
me->m_all_requests.getData()[0]->getCommand() != Request::HC_QUIT )
|
||||||
{
|
{
|
||||||
bool empty = me->m_all_requests.getData().size()==0;
|
bool empty = me->m_all_requests.getData().size()==0;
|
||||||
@ -175,10 +177,13 @@ void *NetworkHttp::mainLoop(void *obj)
|
|||||||
case Request::HC_INIT: me->init(); break;
|
case Request::HC_INIT: me->init(); break;
|
||||||
case Request::HC_NEWS: assert(false); break;
|
case Request::HC_NEWS: assert(false); break;
|
||||||
case Request::HC_DOWNLOAD_FILE:
|
case Request::HC_DOWNLOAD_FILE:
|
||||||
me->downloadFileInternal(me->m_current_request);
|
CURLcode status = me->downloadFileInternal(me->m_current_request);
|
||||||
|
if(status==CURLE_ABORTED_BY_CALLBACK)
|
||||||
|
abort = true;
|
||||||
break;
|
break;
|
||||||
} // switch(request->getCommand())
|
} // switch(request->getCommand())
|
||||||
|
if(abort)
|
||||||
|
break;
|
||||||
if(me->m_current_request->manageMemory())
|
if(me->m_current_request->manageMemory())
|
||||||
{
|
{
|
||||||
delete me->m_current_request;
|
delete me->m_current_request;
|
||||||
@ -189,15 +194,9 @@ void *NetworkHttp::mainLoop(void *obj)
|
|||||||
me->m_all_requests.lock();
|
me->m_all_requests.lock();
|
||||||
} // while !quit
|
} // while !quit
|
||||||
if(UserConfigParams::logAddons())
|
if(UserConfigParams::logAddons())
|
||||||
printf("[addons] Network thread waiting to be cancelled.\n");
|
printf("[addons] Network exiting.\n");
|
||||||
|
|
||||||
// If the thread would exit here, it would be a lot more complicated for
|
pthread_exit(NULL);
|
||||||
// the main thread (which deletes this object) to detect this - locking
|
|
||||||
// a mutex (e.g. to signal the main thread when this object is finished)
|
|
||||||
// leads to a race condition since a thread waiting for a mutex apparently
|
|
||||||
// can't be cancelled, resulting in a deadlock.
|
|
||||||
while(1)
|
|
||||||
pthread_testcancel();
|
|
||||||
return 0;
|
return 0;
|
||||||
} // mainLoop
|
} // mainLoop
|
||||||
|
|
||||||
@ -233,16 +232,7 @@ NetworkHttp::~NetworkHttp()
|
|||||||
{
|
{
|
||||||
if(UserConfigParams::m_internet_status!=NetworkHttp::IPERM_ALLOWED)
|
if(UserConfigParams::m_internet_status!=NetworkHttp::IPERM_ALLOWED)
|
||||||
return;
|
return;
|
||||||
|
pthread_join(*m_thread_id.getData(), NULL);
|
||||||
m_thread_id.lock();
|
|
||||||
if(m_thread_id.getData())
|
|
||||||
{
|
|
||||||
printf("[addons] Cancelling network thread.\n");
|
|
||||||
int e = pthread_cancel(*m_thread_id.getData());
|
|
||||||
printf("[addons] Cancelled network thread. Return code: %d\n", e);
|
|
||||||
delete m_thread_id.getData();
|
|
||||||
}
|
|
||||||
m_thread_id.unlock();
|
|
||||||
|
|
||||||
pthread_cond_destroy(&m_cond_request);
|
pthread_cond_destroy(&m_cond_request);
|
||||||
|
|
||||||
@ -281,7 +271,9 @@ int NetworkHttp::init()
|
|||||||
|
|
||||||
Request r(Request::HC_DOWNLOAD_FILE, 9999, false,
|
Request r(Request::HC_DOWNLOAD_FILE, 9999, false,
|
||||||
"news.xml", "news.xml");
|
"news.xml", "news.xml");
|
||||||
if(!download || downloadFileInternal(&r))
|
CURLcode status = download ? downloadFileInternal(&r)
|
||||||
|
: CURLE_OK;
|
||||||
|
if(status==CURLE_OK)
|
||||||
{
|
{
|
||||||
std::string xml_file = file_manager->getAddonsFile("news.xml");
|
std::string xml_file = file_manager->getAddonsFile("news.xml");
|
||||||
if(download)
|
if(download)
|
||||||
@ -291,17 +283,18 @@ int NetworkHttp::init()
|
|||||||
#ifdef ADDONS_MANAGER
|
#ifdef ADDONS_MANAGER
|
||||||
loadAddonsList(xml, xml_file);
|
loadAddonsList(xml, xml_file);
|
||||||
#endif
|
#endif
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
// Abort requested by stk -> display no error message
|
||||||
#ifdef ADDONS_MANAGER
|
if(status==CURLE_ABORTED_BY_CALLBACK)
|
||||||
addons_manager->setErrorState();
|
|
||||||
if(UserConfigParams::logAddons())
|
|
||||||
printf("[addons] Can't download addons list.\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#ifdef ADDONS_MANAGER
|
||||||
|
addons_manager->setErrorState();
|
||||||
|
if(UserConfigParams::logAddons())
|
||||||
|
printf("[addons] Can't download addons list.\n");
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
} // init
|
} // init
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -342,7 +335,9 @@ void NetworkHttp::loadAddonsList(const XMLNode *xml,
|
|||||||
|
|
||||||
Request r(Request::HC_DOWNLOAD_FILE, 9999, false,
|
Request r(Request::HC_DOWNLOAD_FILE, 9999, false,
|
||||||
addon_list_url, "addons.xml");
|
addon_list_url, "addons.xml");
|
||||||
if(!download || downloadFileInternal(&r))
|
CURLcode status = download ? downloadFileInternal(&r)
|
||||||
|
: CURLE_OK;
|
||||||
|
if(status==CURLE_OK)
|
||||||
{
|
{
|
||||||
std::string xml_file = file_manager->getAddonsFile("addons.xml");
|
std::string xml_file = file_manager->getAddonsFile("addons.xml");
|
||||||
if(download)
|
if(download)
|
||||||
@ -354,6 +349,13 @@ void NetworkHttp::loadAddonsList(const XMLNode *xml,
|
|||||||
printf("[addons] Addons manager list downloaded\n");
|
printf("[addons] Addons manager list downloaded\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Aborted by STK in progress callback, don't display error message
|
||||||
|
if(status==CURLE_ABORTED_BY_CALLBACK)
|
||||||
|
return;
|
||||||
|
printf("[addons] Error on download addons.xml: %d\n",
|
||||||
|
status);
|
||||||
|
return;
|
||||||
} // loadAddonsList
|
} // loadAddonsList
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -363,7 +365,7 @@ void NetworkHttp::loadAddonsList(const XMLNode *xml,
|
|||||||
* \param request The request object containing the url and the path where
|
* \param request The request object containing the url and the path where
|
||||||
* the file is saved to.
|
* the file is saved to.
|
||||||
*/
|
*/
|
||||||
bool NetworkHttp::downloadFileInternal(Request *request)
|
CURLcode NetworkHttp::downloadFileInternal(Request *request)
|
||||||
{
|
{
|
||||||
std::string full_save =
|
std::string full_save =
|
||||||
file_manager->getAddonsFile(request->getSavePath());
|
file_manager->getAddonsFile(request->getSavePath());
|
||||||
@ -391,7 +393,7 @@ bool NetworkHttp::downloadFileInternal(Request *request)
|
|||||||
&NetworkHttp::progressDownload);
|
&NetworkHttp::progressDownload);
|
||||||
curl_easy_setopt(m_curl_session, CURLOPT_NOPROGRESS, 0);
|
curl_easy_setopt(m_curl_session, CURLOPT_NOPROGRESS, 0);
|
||||||
|
|
||||||
int status = curl_easy_perform(m_curl_session);
|
CURLcode status = curl_easy_perform(m_curl_session);
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
if(status==CURLE_OK)
|
if(status==CURLE_OK)
|
||||||
{
|
{
|
||||||
@ -418,7 +420,7 @@ bool NetworkHttp::downloadFileInternal(Request *request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
request->setProgress( (status==CURLE_OK) ? 1.0f : -1.0f );
|
request->setProgress( (status==CURLE_OK) ? 1.0f : -1.0f );
|
||||||
return status==CURLE_OK;
|
return status;
|
||||||
} // downloadFileInternal
|
} // downloadFileInternal
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -69,7 +69,7 @@ private:
|
|||||||
int init();
|
int init();
|
||||||
void loadAddonsList(const XMLNode *xml,
|
void loadAddonsList(const XMLNode *xml,
|
||||||
const std::string &filename);
|
const std::string &filename);
|
||||||
bool downloadFileInternal(Request *request);
|
CURLcode downloadFileInternal(Request *request);
|
||||||
static int progressDownload(void *clientp, double dltotal, double dlnow,
|
static int progressDownload(void *clientp, double dltotal, double dlnow,
|
||||||
double ultotal, double ulnow);
|
double ultotal, double ulnow);
|
||||||
void insertRequest(Request *request);
|
void insertRequest(Request *request);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user