# HG changeset patch # User Tero Marttila # Date 1237239218 -7200 # Node ID 83d53afa2551ab15287680019fec55b67ebd91ef # Parent 76a782abddca3c4c009d7406196575ed22f45b21 implement evsql_destroy, although it's still not callable from any callbacks diff -r 76a782abddca -r 83d53afa2551 src/core.c --- a/src/core.c Mon Mar 16 21:48:13 2009 +0200 +++ b/src/core.c Mon Mar 16 23:33:38 2009 +0200 @@ -86,10 +86,11 @@ */ static void _evsql_query_done (struct evsql_query *query, struct evsql_result *res) { if (res) { - if (query->cb_fn) + if (query->cb_fn) { // call the callback query->cb_fn(res, query->cb_arg); - else { + + } else { WARNING("supressing cb_fn because query was aborted"); // free the results @@ -155,6 +156,7 @@ LIST_REMOVE(conn, entry); // catch deadlocks + // XXX: still just assert? assert(!LIST_EMPTY(&conn->evsql->conn_list) || TAILQ_EMPTY(&conn->evsql->query_queue)); // free @@ -570,7 +572,7 @@ return evsql; error: - // XXX: more complicated than this? + // there's no other state yet free(evsql); return NULL; @@ -913,3 +915,53 @@ } } +void evsql_destroy (struct evsql *evsql) { + struct evsql_query *query; + struct evsql_conn *conn; + + // kill off all queued queries + while ((query = TAILQ_FIRST(&evsql->query_queue)) != NULL) { + // just free it, command first + free(query->command); query->command = NULL; + _evsql_query_free(query); + } + + // kill off all connections + while ((conn = LIST_FIRST(&evsql->conn_list)) != NULL) { + // kill off the query + if (conn->query) { + free(query->command); query->command = NULL; + _evsql_query_free(query); + + conn->query = NULL; + } + + // kill off the transaction + if (conn->trans) { + conn->trans->query = NULL; + _evsql_trans_release(conn->trans); + } + + // kill it off + _evsql_conn_release(conn); + } + + // then free the evsql itself + free(evsql); +} + +void _evsql_destroy_handler (int fd, short what, void *arg) +{ + struct evsql *evsql = arg; + + evsql_destroy(evsql); +} + +evsql_err_t evsql_destroy_next (struct evsql *evsql) +{ + struct timeval tv = {0, 0}; + + // schedule a one-time event + return event_base_once(evsql->ev_base, 0, EV_TIMEOUT, &_evsql_destroy_handler, evsql, &tv); +} + diff -r 76a782abddca -r 83d53afa2551 src/include/evsql.h --- a/src/include/evsql.h Mon Mar 16 21:48:13 2009 +0200 +++ b/src/include/evsql.h Mon Mar 16 23:33:38 2009 +0200 @@ -415,16 +415,25 @@ void *cb_arg ); -// @} - /** - * Close a connection. Callbacks for waiting queries will not be run. + * Close the evsql handle. IMPORTANT: There are severe restrictions on the use of this function. It must *NOT* be + * called from any evsql_*_cb callback, or the program will probably crash after the callback returns. * - * XXX: not implemented yet. + * Currently, the evsql handle can only be free'd if the entire evsql is idle, so this will silently abort any + * pending queries and transactions, which may lead to nasty things. + * + * As a workaround to the callback-issue, you can call evsql_destroy from the next event loop iteration, which is + * what evsql_destroy_next does for you. * * @param evsql the context handle from \ref evsql_new_ */ -void evsql_close (struct evsql *evsql); +void evsql_destroy (struct evsql *evsql); + +/** + * Call evsql_destroy in the next event loop iteration. If scheduling this fails, we return -1 (not a meaningful error + * code, but nonzero). + */ +evsql_err_t evsql_destroy_next (struct evsql *evsql); // @} diff -r 76a782abddca -r 83d53afa2551 src/internal.h --- a/src/internal.h Mon Mar 16 21:48:13 2009 +0200 +++ b/src/internal.h Mon Mar 16 23:33:38 2009 +0200 @@ -93,7 +93,6 @@ // our current query struct evsql_query *query; - }; /* diff -r 76a782abddca -r 83d53afa2551 src/result.c --- a/src/result.c Mon Mar 16 21:48:13 2009 +0200 +++ b/src/result.c Mon Mar 16 23:33:38 2009 +0200 @@ -255,4 +255,3 @@ } } -