diff options
Diffstat (limited to 'tests/nonblock-wrappers.h')
-rw-r--r-- | tests/nonblock-wrappers.h | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/tests/nonblock-wrappers.h b/tests/nonblock-wrappers.h new file mode 100644 index 00000000..19737c8d --- /dev/null +++ b/tests/nonblock-wrappers.h @@ -0,0 +1,479 @@ +/* + Copyright 2011 Kristian Nielsen and Monty Program Ab + + This file is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + Wrappers that re-implement the normal blocking libmysql API calls in terms + of the non-blocking API calls and explicit waiting. + + Used to test the non-blocking calls using mysql_client_test. +*/ + +#ifndef _WIN32 +#include <poll.h> +#else +#include <WinSock2.h> +#endif + +/* + Run the appropriate poll() syscall to wait for the event that libmysql + requested. Return which event(s) occurred. +*/ +static int +wait_for_mysql(MYSQL *mysql, int status) +{ +#ifdef _WIN32 + fd_set rs, ws, es; + int res; + struct timeval tv, *timeout; + my_socket s= mysql_get_socket(mysql); + FD_ZERO(&rs); + FD_ZERO(&ws); + FD_ZERO(&es); + if (status & MYSQL_WAIT_READ) + FD_SET(s, &rs); + if (status & MYSQL_WAIT_WRITE) + FD_SET(s, &ws); + if (status & MYSQL_WAIT_EXCEPT) + FD_SET(s, &es); + if (status & MYSQL_WAIT_TIMEOUT) + { + tv.tv_sec= mysql_get_timeout_value(mysql); + tv.tv_usec= 0; + timeout= &tv; + } + else + timeout= NULL; + res= select(1, &rs, &ws, &es, timeout); + if (res == 0) + return MYSQL_WAIT_TIMEOUT; + else if (res == SOCKET_ERROR) + return MYSQL_WAIT_TIMEOUT; + else + { + int status= 0; + if (FD_ISSET(s, &rs)) + status|= MYSQL_WAIT_READ; + if (FD_ISSET(s, &ws)) + status|= MYSQL_WAIT_WRITE; + if (FD_ISSET(s, &es)) + status|= MYSQL_WAIT_EXCEPT; + return status; + } +#else + struct pollfd pfd; + int timeout; + int res; + + pfd.fd= mysql_get_socket(mysql); + pfd.events= + (status & MYSQL_WAIT_READ ? POLLIN : 0) | + (status & MYSQL_WAIT_WRITE ? POLLOUT : 0) | + (status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0); + if (status & MYSQL_WAIT_TIMEOUT) + timeout= 1000*mysql_get_timeout_value(mysql); + else + timeout= -1; + do { + res= poll(&pfd, 1, timeout); + /* + In a real event framework, we should re-compute the timeout on getting + EINTR to account for the time elapsed before the interruption. + */ + } while (res < 0 && errno == EINTR); + if (res == 0) + return MYSQL_WAIT_TIMEOUT; + else if (res < 0) + return MYSQL_WAIT_TIMEOUT; + else + { + int status= 0; + if (pfd.revents & POLLIN) + status|= MYSQL_WAIT_READ; + if (pfd.revents & POLLOUT) + status|= MYSQL_WAIT_WRITE; + if (pfd.revents & POLLPRI) + status|= MYSQL_WAIT_EXCEPT; + return status; + } +#endif +} + + +/* + If WRAP_NONBLOCK_ENABLED is defined, it is a variable that can be used to + enable or disable the use of non-blocking API wrappers. If true the + non-blocking API will be used, if false the normal blocking API will be + called directly. +*/ +#ifdef WRAP_NONBLOCK_ENABLED +#define USE_BLOCKING(name__, invoke_blocking__) \ + if (!(WRAP_NONBLOCK_ENABLED)) return name__ invoke_blocking__; +#define USE_BLOCKING_VOID_RETURN(name__, invoke__) \ + if (!(WRAP_NONBLOCK_ENABLED)) { name__ invoke__; return; } +#else +#define USE_BLOCKING(name__, invoke_blocking__) +#define USE_BLOCKING_VOID_RETURN(name__, invoke__) +#endif + +/* + I would preferably have declared the wrappers static. + However, if we do so, compilers will warn about definitions not used, and + with -Werror this breaks compilation :-( +*/ +#define MK_WRAPPER(ret_type__, name__, decl__, invoke__, invoke_blocking__, cont_arg__, mysql__) \ +ret_type__ wrap_ ## name__ decl__ \ +{ \ + ret_type__ res; \ + int status; \ + USE_BLOCKING(name__, invoke_blocking__) \ + status= name__ ## _start invoke__; \ + while (status) \ + { \ + status= wait_for_mysql(mysql__, status); \ + status= name__ ## _cont(&res, cont_arg__, status); \ + } \ + return res; \ +} + +#define MK_WRAPPER_VOID_RETURN(name__, decl__, invoke__, cont_arg__, mysql__) \ +void wrap_ ## name__ decl__ \ +{ \ + int status; \ + USE_BLOCKING_VOID_RETURN(name__, invoke__) \ + status= name__ ## _start invoke__; \ + while (status) \ + { \ + status= wait_for_mysql(mysql__, status); \ + status= name__ ## _cont(cont_arg__, status); \ + } \ +} + +MK_WRAPPER( + MYSQL *, + mysql_real_connect, + (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag), + (&res, mysql, host, user, passwd, db, port, unix_socket, clientflag), + (mysql, host, user, passwd, db, port, unix_socket, clientflag), + mysql, + mysql) + + +MK_WRAPPER( + int, + mysql_real_query, + (MYSQL *mysql, const char *stmt_str, unsigned long length), + (&res, mysql, stmt_str, length), + (mysql, stmt_str, length), + mysql, + mysql) + +MK_WRAPPER( + MYSQL_ROW, + mysql_fetch_row, + (MYSQL_RES *result), + (&res, result), + (result), + result, + result->handle) + +MK_WRAPPER( + int, + mysql_set_character_set, + (MYSQL *mysql, const char *csname), + (&res, mysql, csname), + (mysql, csname), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_select_db, + (MYSQL *mysql, const char *db), + (&res, mysql, db), + (mysql, db), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_send_query, + (MYSQL *mysql, const char *q, unsigned long length), + (&res, mysql, q, length), + (mysql, q, length), + mysql, + mysql) + +MK_WRAPPER( + MYSQL_RES *, + mysql_store_result, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER_VOID_RETURN( + mysql_free_result, + (MYSQL_RES *result), + (result), + result, + result->handle) + +MK_WRAPPER_VOID_RETURN( + mysql_close, + (MYSQL *sock), + (sock), + sock, + sock) + +MK_WRAPPER( + my_bool, + mysql_change_user, + (MYSQL *mysql, const char *user, const char *passwd, const char *db), + (&res, mysql, user, passwd, db), + (mysql, user, passwd, db), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_query, + (MYSQL *mysql, const char *q), + (&res, mysql, q), + (mysql, q), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_shutdown, + (MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level), + (&res, mysql, shutdown_level), + (mysql, shutdown_level), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_dump_debug_info, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_refresh, + (MYSQL *mysql, unsigned int refresh_options), + (&res, mysql, refresh_options), + (mysql, refresh_options), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_kill, + (MYSQL *mysql, unsigned long pid), + (&res, mysql, pid), + (mysql, pid), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_set_server_option, + (MYSQL *mysql, enum enum_mysql_set_option option), + (&res, mysql, option), + (mysql, option), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_ping, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + const char *, + mysql_stat, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + my_bool, + mysql_read_query_result, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_stmt_prepare, + (MYSQL_STMT *stmt, const char *query, unsigned long length), + (&res, stmt, query, length), + (stmt, query, length), + stmt, + stmt->mysql) + +MK_WRAPPER( + int, + mysql_stmt_execute, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + int, + mysql_stmt_fetch, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + int, + mysql_stmt_store_result, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_stmt_close, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_stmt_reset, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_stmt_free_result, + (MYSQL_STMT *stmt), + (&res, stmt), + (stmt), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_stmt_send_long_data, + (MYSQL_STMT *stmt, unsigned int param_number, const char *data, unsigned long length), + (&res, stmt, param_number, data, length), + (stmt, param_number, data, length), + stmt, + stmt->mysql) + +MK_WRAPPER( + my_bool, + mysql_commit, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + my_bool, + mysql_rollback, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +MK_WRAPPER( + my_bool, + mysql_autocommit, + (MYSQL *mysql, my_bool auto_mode), + (&res, mysql, auto_mode), + (mysql, auto_mode), + mysql, + mysql) + +MK_WRAPPER( + int, + mysql_next_result, + (MYSQL *mysql), + (&res, mysql), + (mysql), + mysql, + mysql) + +#undef USE_BLOCKING +#undef MK_WRAPPER +#undef MK_WRAPPER_VOID_RETURN + + +#define mysql_real_connect wrap_mysql_real_connect +#define mysql_real_query wrap_mysql_real_query +#define mysql_fetch_row wrap_mysql_fetch_row +#define mysql_set_character_set wrap_mysql_set_character_set +#define mysql_select_db wrap_mysql_select_db +#define mysql_send_query wrap_mysql_send_query +#define mysql_store_result wrap_mysql_store_result +#define mysql_free_result wrap_mysql_free_result +#define mysql_close wrap_mysql_close +#define mysql_change_user wrap_mysql_change_user +#define mysql_query wrap_mysql_query +#define mysql_shutdown wrap_mysql_shutdown +#define mysql_dump_debug_info wrap_mysql_dump_debug_info +#define mysql_refresh wrap_mysql_refresh +#define mysql_kill wrap_mysql_kill +#define mysql_set_server_option wrap_mysql_set_server_option +#define mysql_ping wrap_mysql_ping +#define mysql_stat wrap_mysql_stat +#define mysql_list_dbs wrap_mysql_list_dbs +#define mysql_list_tables wrap_mysql_list_tables +#define mysql_list_processes wrap_mysql_list_processes +#define mysql_read_query_result wrap_mysql_read_query_result +#define mysql_stmt_prepare wrap_mysql_stmt_prepare +#define mysql_stmt_execute wrap_mysql_stmt_execute +#define mysql_stmt_fetch wrap_mysql_stmt_fetch +#define mysql_stmt_store_result wrap_mysql_stmt_store_result +#define mysql_stmt_close wrap_mysql_stmt_close +#define mysql_stmt_reset wrap_mysql_stmt_reset +#define mysql_stmt_free_result wrap_mysql_stmt_free_result +#define mysql_stmt_send_long_data wrap_mysql_stmt_send_long_data +#define mysql_commit wrap_mysql_commit +#define mysql_rollback wrap_mysql_rollback +#define mysql_autocommit wrap_mysql_autocommit +#define mysql_next_result wrap_mysql_next_result |