[GB.NET.CURL]

* BUG: Fix memory leaks when asynchronous clients are pending when quitting
  the program.


git-svn-id: svn://localhost/gambas/trunk@5392 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
Benoît Minisini 2012-11-28 22:55:23 +00:00
parent 76709ee739
commit 4512fa0c1d
4 changed files with 79 additions and 40 deletions

View file

@ -38,12 +38,41 @@
#include "CCurl.h" #include "CCurl.h"
#include "CProxy.h" #include "CProxy.h"
DECLARE_EVENT(EVENT_FINISHED); DECLARE_EVENT(EVENT_FINISHED);
DECLARE_EVENT(EVENT_ERROR); DECLARE_EVENT(EVENT_ERROR);
DECLARE_EVENT(EVENT_CONNECT); DECLARE_EVENT(EVENT_CONNECT);
DECLARE_EVENT(EVENT_READ); DECLARE_EVENT(EVENT_READ);
static CCURL *_async_list = NULL;
static void add_to_async_list(CCURL *_object)
{
if (THIS->in_list)
return;
#ifdef DEBUG
fprintf(stderr, "add_to_async_list: %p\n", THIS);
#endif
GB.List.Add(&_async_list, THIS, &THIS->list);
THIS->in_list = TRUE;
GB.Ref(THIS);
}
static void remove_from_async_list(CCURL *_object)
{
if (!THIS->in_list)
return;
#ifdef DEBUG
fprintf(stderr, "remove_from_async_list: %p\n", THIS);
#endif
GB.List.Remove(&_async_list, THIS, &THIS->list);
THIS->in_list = FALSE;
GB.Unref(POINTER(&_object));
}
/***************************************************** /*****************************************************
CURLM : a pointer to use curl_multi interface, CURLM : a pointer to use curl_multi interface,
allowing asynchrnous work without using threads allowing asynchrnous work without using threads
@ -198,9 +227,6 @@ void CURL_manage_error(void *_object, int error)
THIS_STATUS = (- (1000 + error)); THIS_STATUS = (- (1000 + error));
break; break;
} }
if (THIS->async)
GB.Unref(POINTER(&_object));
} }
void CURL_init_stream(void *_object) void CURL_init_stream(void *_object)
@ -262,29 +288,34 @@ static void CCURL_post_curl(intptr_t data)
void CURL_stop(void *_object) void CURL_stop(void *_object)
{ {
if (THIS_STATUS == NET_INACTIVE)
return;
if (THIS_CURL)
{
#if DEBUG
fprintf(stderr, "-- CURL_stop: [%p] curl_multi_remove_handle(%p)\n", THIS, THIS_CURL);
#endif
curl_multi_remove_handle(CCURL_multicurl,THIS_CURL);
#if DEBUG
fprintf(stderr, "-- CURL_stop: [%p] curl_easy_cleanup(%p)\n", THIS, THIS_CURL);
#endif
curl_easy_cleanup(THIS_CURL);
THIS_CURL = NULL;
}
if (THIS_FILE) if (THIS_FILE)
{ {
fclose(THIS_FILE); fclose(THIS_FILE);
THIS_FILE = NULL; THIS_FILE = NULL;
} }
if (THIS_CURL)
{
#if DEBUG
fprintf(stderr, "-- [%p] curl_multi_remove_handle(%p)\n", THIS, THIS_CURL);
#endif
curl_multi_remove_handle(CCURL_multicurl,THIS_CURL);
#if DEBUG
fprintf(stderr, "-- [%p] curl_easycleanup(%p)\n", THIS, THIS_CURL);
#endif
curl_easy_cleanup(THIS_CURL);
THIS_CURL = NULL;
}
THIS_STATUS = NET_INACTIVE; THIS_STATUS = NET_INACTIVE;
remove_from_async_list(THIS);
} }
static void Curl_init_post(void) static void init_post(void)
{ {
if (CCURL_pipe[0]!=-1) return; if (CCURL_pipe[0]!=-1) return;
@ -301,9 +332,9 @@ static void Curl_init_post(void)
void CURL_start_post(void *_object) void CURL_start_post(void *_object)
{ {
Curl_init_post(); init_post();
curl_multi_add_handle(CCURL_multicurl, THIS_CURL); curl_multi_add_handle(CCURL_multicurl, THIS_CURL);
GB.Ref(THIS); add_to_async_list(THIS);
} }
bool CURL_check_active(void *_object) bool CURL_check_active(void *_object)
@ -471,19 +502,10 @@ BEGIN_METHOD_VOID(Curl_free)
fprintf(stderr, "Curl_free: %p\n", THIS); fprintf(stderr, "Curl_free: %p\n", THIS);
#endif #endif
CURL_stop(THIS);
GB.FreeString(&THIS_URL); GB.FreeString(&THIS_URL);
if (THIS_FILE)
fclose(THIS_FILE);
if (THIS_CURL)
{
#if DEBUG
fprintf(stderr, "-- [%p] curl_easy_cleanup(%p)\n", THIS, THIS_CURL);
#endif
curl_easy_cleanup(THIS_CURL);
}
CURL_user_clear(&THIS->user); CURL_user_clear(&THIS->user);
CURL_proxy_clear(&THIS->proxy.proxy); CURL_proxy_clear(&THIS->proxy.proxy);
@ -500,9 +522,24 @@ END_METHOD
BEGIN_METHOD_VOID(Curl_exit) BEGIN_METHOD_VOID(Curl_exit)
CCURL *curl, *next;
#if DEBUG
fprintf(stderr, "-- CURL_exit: clear async list\n");
#endif
curl = _async_list;
while (curl)
{
next = curl->list.next;
remove_from_async_list(curl);
curl = next;
}
#if DEBUG #if DEBUG
fprintf(stderr, "-- curl_multi_cleanup()\n"); fprintf(stderr, "-- curl_multi_cleanup()\n");
#endif #endif
curl_multi_cleanup(CCURL_multicurl); curl_multi_cleanup(CCURL_multicurl);
END_METHOD END_METHOD

View file

@ -58,17 +58,19 @@ typedef
struct { struct {
GB_BASE ob; GB_BASE ob;
GB_STREAM stream; GB_STREAM stream;
GB_LIST list; // List of async curl objects
int status; int status;
CURL *curl; CURL *curl;
char *url; char *url;
FILE *file; FILE *file;
CPROXY proxy; CPROXY proxy;
CURL_USER user; CURL_USER user;
bool async;
int timeout; int timeout;
int method; // 0->Get, 1->Put int method; // 0->Get, 1->Put
bool debug;
char *data; char *data;
unsigned async : 1;
unsigned in_list : 1;
unsigned debug : 1;
} }
CCURL; CCURL;

View file

@ -116,7 +116,7 @@ static void ftp_initialize_curl_handle(void *_object)
curl_easy_setopt(THIS_CURL, CURLOPT_TIMEOUT,THIS->timeout); curl_easy_setopt(THIS_CURL, CURLOPT_TIMEOUT,THIS->timeout);
} }
curl_easy_setopt(THIS_CURL, CURLOPT_VERBOSE, THIS->debug); curl_easy_setopt(THIS_CURL, CURLOPT_VERBOSE, (bool)THIS->debug);
curl_easy_setopt(THIS_CURL, CURLOPT_PRIVATE,(char*)_object); curl_easy_setopt(THIS_CURL, CURLOPT_PRIVATE,(char*)_object);
CURL_proxy_set(&THIS->proxy.proxy,THIS_CURL); CURL_proxy_set(&THIS->proxy.proxy,THIS_CURL);
@ -280,7 +280,7 @@ END_METHOD
BEGIN_METHOD_VOID(FtpClient_free) BEGIN_METHOD_VOID(FtpClient_free)
CURL_stop(_object); //CURL_stop(_object);
ftp_reset(THIS_FTP); ftp_reset(THIS_FTP);
END_METHOD END_METHOD

View file

@ -188,7 +188,7 @@ static void http_initialize_curl_handle(void *_object, GB_ARRAY custom_headers)
curl_easy_setopt(THIS_CURL, CURLOPT_TIMEOUT,THIS->timeout); curl_easy_setopt(THIS_CURL, CURLOPT_TIMEOUT,THIS->timeout);
} }
curl_easy_setopt(THIS_CURL, CURLOPT_VERBOSE, THIS->debug); curl_easy_setopt(THIS_CURL, CURLOPT_VERBOSE, (bool)THIS->debug);
curl_easy_setopt(THIS_CURL, CURLOPT_PRIVATE,(char*)_object); curl_easy_setopt(THIS_CURL, CURLOPT_PRIVATE,(char*)_object);
curl_easy_setopt(THIS_CURL, CURLOPT_USERAGENT, THIS_HTTP->sUserAgent); curl_easy_setopt(THIS_CURL, CURLOPT_USERAGENT, THIS_HTTP->sUserAgent);
curl_easy_setopt(THIS_CURL, CURLOPT_ENCODING, THIS_HTTP->encoding); curl_easy_setopt(THIS_CURL, CURLOPT_ENCODING, THIS_HTTP->encoding);
@ -502,7 +502,7 @@ END_METHOD
BEGIN_METHOD_VOID(HttpClient_free) BEGIN_METHOD_VOID(HttpClient_free)
CURL_stop(_object); //CURL_stop(_object);
http_reset(THIS); http_reset(THIS);
GB.FreeString(&THIS_HTTP->sUserAgent); GB.FreeString(&THIS_HTTP->sUserAgent);