Commit 654b3e60 authored by Vasil Dimov's avatar Vasil Dimov

Merge mysql-5.5-bugteam -> mysql-5.5-innodb

parents 18520902 f3f1db2a
...@@ -112,6 +112,7 @@ static my_bool parsing_disabled= 0; ...@@ -112,6 +112,7 @@ static my_bool parsing_disabled= 0;
static my_bool display_result_vertically= FALSE, display_result_lower= FALSE, static my_bool display_result_vertically= FALSE, display_result_lower= FALSE,
display_metadata= FALSE, display_result_sorted= FALSE; display_metadata= FALSE, display_result_sorted= FALSE;
static my_bool disable_query_log= 0, disable_result_log= 0; static my_bool disable_query_log= 0, disable_result_log= 0;
static my_bool disable_connect_log= 1;
static my_bool disable_warnings= 0; static my_bool disable_warnings= 0;
static my_bool disable_info= 1; static my_bool disable_info= 1;
static my_bool abort_on_error= 1; static my_bool abort_on_error= 1;
...@@ -227,8 +228,9 @@ typedef struct ...@@ -227,8 +228,9 @@ typedef struct
int str_val_len; int str_val_len;
int int_val; int int_val;
int alloced_len; int alloced_len;
int int_dirty; /* do not update string if int is updated until first read */ bool int_dirty; /* do not update string if int is updated until first read */
int alloced; bool is_int;
bool alloced;
} VAR; } VAR;
/*Perl/shell-like variable registers */ /*Perl/shell-like variable registers */
...@@ -257,6 +259,7 @@ struct st_connection ...@@ -257,6 +259,7 @@ struct st_connection
pthread_mutex_t result_mutex; pthread_mutex_t result_mutex;
pthread_cond_t result_cond; pthread_cond_t result_cond;
int query_done; int query_done;
my_bool has_thread;
#endif /*EMBEDDED_LIBRARY*/ #endif /*EMBEDDED_LIBRARY*/
}; };
...@@ -286,6 +289,7 @@ enum enum_commands { ...@@ -286,6 +289,7 @@ enum enum_commands {
Q_EVAL_RESULT, Q_EVAL_RESULT,
Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG, Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
Q_ENABLE_CONNECT_LOG, Q_DISABLE_CONNECT_LOG,
Q_WAIT_FOR_SLAVE_TO_STOP, Q_WAIT_FOR_SLAVE_TO_STOP,
Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
Q_ENABLE_INFO, Q_DISABLE_INFO, Q_ENABLE_INFO, Q_DISABLE_INFO,
...@@ -351,6 +355,8 @@ const char *command_names[]= ...@@ -351,6 +355,8 @@ const char *command_names[]=
/* Enable/disable that the _result_ from a query is logged to result file */ /* Enable/disable that the _result_ from a query is logged to result file */
"enable_result_log", "enable_result_log",
"disable_result_log", "disable_result_log",
"enable_connect_log",
"disable_connect_log",
"wait_for_slave_to_stop", "wait_for_slave_to_stop",
"enable_warnings", "enable_warnings",
"disable_warnings", "disable_warnings",
...@@ -763,10 +769,9 @@ end_thread: ...@@ -763,10 +769,9 @@ end_thread:
return 0; return 0;
} }
static void wait_query_thread_done(struct st_connection *con) static void wait_query_thread_done(struct st_connection *con)
{ {
DBUG_ASSERT(con->tid); DBUG_ASSERT(con->has_thread);
if (!con->query_done) if (!con->query_done)
{ {
pthread_mutex_lock(&con->result_mutex); pthread_mutex_lock(&con->result_mutex);
...@@ -779,7 +784,7 @@ static void wait_query_thread_done(struct st_connection *con) ...@@ -779,7 +784,7 @@ static void wait_query_thread_done(struct st_connection *con)
static void signal_connection_thd(struct st_connection *cn, int command) static void signal_connection_thd(struct st_connection *cn, int command)
{ {
DBUG_ASSERT(cn->tid); DBUG_ASSERT(cn->has_thread);
cn->query_done= 0; cn->query_done= 0;
cn->command= command; cn->command= command;
pthread_mutex_lock(&cn->query_mutex); pthread_mutex_lock(&cn->query_mutex);
...@@ -791,13 +796,13 @@ static void signal_connection_thd(struct st_connection *cn, int command) ...@@ -791,13 +796,13 @@ static void signal_connection_thd(struct st_connection *cn, int command)
/* /*
Sometimes we try to execute queries when the connection is closed. Sometimes we try to execute queries when the connection is closed.
It's done to make sure it was closed completely. It's done to make sure it was closed completely.
So that if our connection is closed (cn->tid == 0), we just return So that if our connection is closed (cn->has_thread == 0), we just return
the mysql_send_query() result which is an error in this case. the mysql_send_query() result which is an error in this case.
*/ */
static int do_send_query(struct st_connection *cn, const char *q, int q_len) static int do_send_query(struct st_connection *cn, const char *q, int q_len)
{ {
if (!cn->tid) if (!cn->has_thread)
return mysql_send_query(&cn->mysql, q, q_len); return mysql_send_query(&cn->mysql, q, q_len);
cn->cur_query= q; cn->cur_query= q;
cn->cur_query_len= q_len; cn->cur_query_len= q_len;
...@@ -805,10 +810,9 @@ static int do_send_query(struct st_connection *cn, const char *q, int q_len) ...@@ -805,10 +810,9 @@ static int do_send_query(struct st_connection *cn, const char *q, int q_len)
return 0; return 0;
} }
static int do_read_query_result(struct st_connection *cn) static int do_read_query_result(struct st_connection *cn)
{ {
DBUG_ASSERT(cn->tid); DBUG_ASSERT(cn->has_thread);
wait_query_thread_done(cn); wait_query_thread_done(cn);
signal_connection_thd(cn, EMB_READ_QUERY_RESULT); signal_connection_thd(cn, EMB_READ_QUERY_RESULT);
wait_query_thread_done(cn); wait_query_thread_done(cn);
...@@ -819,12 +823,12 @@ static int do_read_query_result(struct st_connection *cn) ...@@ -819,12 +823,12 @@ static int do_read_query_result(struct st_connection *cn)
static void emb_close_connection(struct st_connection *cn) static void emb_close_connection(struct st_connection *cn)
{ {
if (!cn->tid) if (!cn->has_thread)
return; return;
wait_query_thread_done(cn); wait_query_thread_done(cn);
signal_connection_thd(cn, EMB_END_CONNECTION); signal_connection_thd(cn, EMB_END_CONNECTION);
pthread_join(cn->tid, NULL); pthread_join(cn->tid, NULL);
cn->tid= 0; cn->has_thread= FALSE;
pthread_mutex_destroy(&cn->query_mutex); pthread_mutex_destroy(&cn->query_mutex);
pthread_cond_destroy(&cn->query_cond); pthread_cond_destroy(&cn->query_cond);
pthread_mutex_destroy(&cn->result_mutex); pthread_mutex_destroy(&cn->result_mutex);
...@@ -842,9 +846,9 @@ static void init_connection_thd(struct st_connection *cn) ...@@ -842,9 +846,9 @@ static void init_connection_thd(struct st_connection *cn)
pthread_cond_init(&cn->result_cond, NULL) || pthread_cond_init(&cn->result_cond, NULL) ||
pthread_create(&cn->tid, &cn_thd_attrib, connection_thread, (void*)cn)) pthread_create(&cn->tid, &cn_thd_attrib, connection_thread, (void*)cn))
die("Error in the thread library"); die("Error in the thread library");
cn->has_thread=TRUE;
} }
#else /*EMBEDDED_LIBRARY*/ #else /*EMBEDDED_LIBRARY*/
#define do_send_query(cn,q,q_len) mysql_send_query(&cn->mysql, q, q_len) #define do_send_query(cn,q,q_len) mysql_send_query(&cn->mysql, q, q_len)
...@@ -2036,6 +2040,21 @@ static void var_free(void *v) ...@@ -2036,6 +2040,21 @@ static void var_free(void *v)
C_MODE_END C_MODE_END
void var_set_int(VAR *v, const char *str)
{
char *endptr;
/* Initially assume not a number */
v->int_val= 0;
v->is_int= false;
v->int_dirty= false;
if (!str) return;
v->int_val = (int) strtol(str, &endptr, 10);
/* It is an int if strtol consumed something up to end/space/tab */
if (endptr > str && (!*endptr || *endptr == ' ' || *endptr == '\t'))
v->is_int= true;
}
VAR *var_init(VAR *v, const char *name, int name_len, const char *val, VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
int val_len) int val_len)
...@@ -2070,11 +2089,10 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val, ...@@ -2070,11 +2089,10 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
memcpy(tmp_var->str_val, val, val_len); memcpy(tmp_var->str_val, val, val_len);
tmp_var->str_val[val_len]= 0; tmp_var->str_val[val_len]= 0;
} }
var_set_int(tmp_var, val);
tmp_var->name_len = name_len; tmp_var->name_len = name_len;
tmp_var->str_val_len = val_len; tmp_var->str_val_len = val_len;
tmp_var->alloced_len = val_alloc_len; tmp_var->alloced_len = val_alloc_len;
tmp_var->int_val = (val) ? atoi(val) : 0;
tmp_var->int_dirty = 0;
return tmp_var; return tmp_var;
} }
...@@ -2135,7 +2153,7 @@ VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw, ...@@ -2135,7 +2153,7 @@ VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw,
if (!raw && v->int_dirty) if (!raw && v->int_dirty)
{ {
sprintf(v->str_val, "%d", v->int_val); sprintf(v->str_val, "%d", v->int_val);
v->int_dirty = 0; v->int_dirty= false;
v->str_val_len = strlen(v->str_val); v->str_val_len = strlen(v->str_val);
} }
if (var_name_end) if (var_name_end)
...@@ -2197,7 +2215,7 @@ void var_set(const char *var_name, const char *var_name_end, ...@@ -2197,7 +2215,7 @@ void var_set(const char *var_name, const char *var_name_end,
if (v->int_dirty) if (v->int_dirty)
{ {
sprintf(v->str_val, "%d", v->int_val); sprintf(v->str_val, "%d", v->int_val);
v->int_dirty= 0; v->int_dirty=false;
v->str_val_len= strlen(v->str_val); v->str_val_len= strlen(v->str_val);
} }
/* setenv() expects \0-terminated strings */ /* setenv() expects \0-terminated strings */
...@@ -2267,8 +2285,14 @@ void var_query_set(VAR *var, const char *query, const char** query_end) ...@@ -2267,8 +2285,14 @@ void var_query_set(VAR *var, const char *query, const char** query_end)
DBUG_ENTER("var_query_set"); DBUG_ENTER("var_query_set");
LINT_INIT(res); LINT_INIT(res);
/* Only white space or ) allowed past ending ` */
while (end > query && *end != '`') while (end > query && *end != '`')
{
if (*end && (*end != ' ' && *end != '\t' && *end != '\n' && *end != ')'))
die("Spurious text after `query` expression");
--end; --end;
}
if (query == end) if (query == end)
die("Syntax error in query, missing '`'"); die("Syntax error in query, missing '`'");
++query; ++query;
...@@ -2497,6 +2521,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) ...@@ -2497,6 +2521,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
void var_copy(VAR *dest, VAR *src) void var_copy(VAR *dest, VAR *src)
{ {
dest->int_val= src->int_val; dest->int_val= src->int_val;
dest->is_int= src->is_int;
dest->int_dirty= src->int_dirty; dest->int_dirty= src->int_dirty;
/* Alloc/realloc data for str_val in dest */ /* Alloc/realloc data for str_val in dest */
...@@ -2580,9 +2605,7 @@ void eval_expr(VAR *v, const char *p, const char **p_end) ...@@ -2580,9 +2605,7 @@ void eval_expr(VAR *v, const char *p, const char **p_end)
v->str_val_len = new_val_len; v->str_val_len = new_val_len;
memcpy(v->str_val, p, new_val_len); memcpy(v->str_val, p, new_val_len);
v->str_val[new_val_len] = 0; v->str_val[new_val_len] = 0;
v->int_val=atoi(p); var_set_int(v, p);
DBUG_PRINT("info", ("atoi on '%s', returns: %d", p, v->int_val));
v->int_dirty=0;
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2929,6 +2952,8 @@ int do_modify_var(struct st_command *command, ...@@ -2929,6 +2952,8 @@ int do_modify_var(struct st_command *command,
die("The argument to %.*s must be a variable (start with $)", die("The argument to %.*s must be a variable (start with $)",
command->first_word_len, command->query); command->first_word_len, command->query);
v= var_get(p, &p, 1, 0); v= var_get(p, &p, 1, 0);
if (! v->is_int)
die("Cannot perform inc/dec on a non-numeric value");
switch (op) { switch (op) {
case DO_DEC: case DO_DEC:
v->int_val--; v->int_val--;
...@@ -2940,7 +2965,7 @@ int do_modify_var(struct st_command *command, ...@@ -2940,7 +2965,7 @@ int do_modify_var(struct st_command *command,
die("Invalid operator to do_modify_var"); die("Invalid operator to do_modify_var");
break; break;
} }
v->int_dirty= 1; v->int_dirty= true;
command->last_argument= (char*)++p; command->last_argument= (char*)++p;
return 0; return 0;
} }
...@@ -3984,7 +4009,18 @@ void do_perl(struct st_command *command) ...@@ -3984,7 +4009,18 @@ void do_perl(struct st_command *command)
if (!error) if (!error)
my_delete(temp_file_path, MYF(0)); my_delete(temp_file_path, MYF(0));
handle_command_error(command, WEXITSTATUS(error)); /* Check for error code that indicates perl could not be started */
int exstat= WEXITSTATUS(error);
#ifdef __WIN__
if (exstat == 1)
/* Text must begin 'perl not found' as mtr looks for it */
abort_not_supported_test("perl not found in path or did not start");
#else
if (exstat == 127)
abort_not_supported_test("perl not found in path");
#endif
else
handle_command_error(command, exstat);
} }
dynstr_free(&ds_delimiter); dynstr_free(&ds_delimiter);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -4898,6 +4934,16 @@ void select_connection_name(const char *name) ...@@ -4898,6 +4934,16 @@ void select_connection_name(const char *name)
set_current_connection(con); set_current_connection(con);
/* Connection logging if enabled */
if (!disable_connect_log && !disable_query_log)
{
DYNAMIC_STRING *ds= &ds_res;
dynstr_append_mem(ds, "connection ", 11);
replace_dynstr_append(ds, name);
dynstr_append_mem(ds, ";\n", 2);
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -4985,6 +5031,16 @@ void do_close_connection(struct st_command *command) ...@@ -4985,6 +5031,16 @@ void do_close_connection(struct st_command *command)
var_set_string("$CURRENT_CONNECTION", con->name); var_set_string("$CURRENT_CONNECTION", con->name);
} }
/* Connection logging if enabled */
if (!disable_connect_log && !disable_query_log)
{
DYNAMIC_STRING *ds= &ds_res;
dynstr_append_mem(ds, "disconnect ", 11);
replace_dynstr_append(ds, ds_connection.str);
dynstr_append_mem(ds, ";\n", 2);
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -5119,6 +5175,13 @@ int connect_n_handle_errors(struct st_command *command, ...@@ -5119,6 +5175,13 @@ int connect_n_handle_errors(struct st_command *command,
dynstr_append_mem(ds, delimiter, delimiter_length); dynstr_append_mem(ds, delimiter, delimiter_length);
dynstr_append_mem(ds, "\n", 1); dynstr_append_mem(ds, "\n", 1);
} }
/* Simlified logging if enabled */
if (!disable_connect_log && !disable_query_log)
{
replace_dynstr_append(ds, command->query);
dynstr_append_mem(ds, ";\n", 2);
}
while (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0, while (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
CLIENT_MULTI_STATEMENTS)) CLIENT_MULTI_STATEMENTS))
{ {
...@@ -7436,11 +7499,13 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) ...@@ -7436,11 +7499,13 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
(flags & QUERY_REAP_FLAG)); (flags & QUERY_REAP_FLAG));
DBUG_ENTER("run_query"); DBUG_ENTER("run_query");
init_dynamic_string(&ds_warnings, NULL, 0, 256);
if (cn->pending && (flags & QUERY_SEND_FLAG)) if (cn->pending && (flags & QUERY_SEND_FLAG))
die ("Cannot run query on connection between send and reap"); die ("Cannot run query on connection between send and reap");
if (!(flags & QUERY_SEND_FLAG) && !cn->pending)
die ("Cannot reap on a connection without pending send");
init_dynamic_string(&ds_warnings, NULL, 0, 256);
/* /*
Evaluate query if this is an eval command Evaluate query if this is an eval command
*/ */
...@@ -8185,6 +8250,8 @@ int main(int argc, char **argv) ...@@ -8185,6 +8250,8 @@ int main(int argc, char **argv)
case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break; case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break;
case Q_ENABLE_RESULT_LOG: disable_result_log=0; break; case Q_ENABLE_RESULT_LOG: disable_result_log=0; break;
case Q_DISABLE_RESULT_LOG: disable_result_log=1; break; case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
case Q_ENABLE_CONNECT_LOG: disable_connect_log=0; break;
case Q_DISABLE_CONNECT_LOG: disable_connect_log=1; break;
case Q_ENABLE_WARNINGS: disable_warnings=0; break; case Q_ENABLE_WARNINGS: disable_warnings=0; break;
case Q_DISABLE_WARNINGS: disable_warnings=1; break; case Q_DISABLE_WARNINGS: disable_warnings=1; break;
case Q_ENABLE_INFO: disable_info=0; break; case Q_ENABLE_INFO: disable_info=0; break;
......
...@@ -48,19 +48,30 @@ typedef struct st_pthread_link { ...@@ -48,19 +48,30 @@ typedef struct st_pthread_link {
struct st_pthread_link *next; struct st_pthread_link *next;
} pthread_link; } pthread_link;
typedef struct { /**
uint32 waiting; Implementation of Windows condition variables.
CRITICAL_SECTION lock_waiting; We use native conditions on Vista and later, and fallback to own
implementation on earlier OS version.
enum { */
SIGNAL= 0, typedef union
BROADCAST= 1, {
MAX_EVENTS= 2 /* Native condition (used on Vista and later) */
} EVENTS; CONDITION_VARIABLE native_cond;
HANDLE events[MAX_EVENTS]; /* Own implementation (used on XP) */
HANDLE broadcast_block_event; struct
{
uint32 waiting;
CRITICAL_SECTION lock_waiting;
enum
{
SIGNAL= 0,
BROADCAST= 1,
MAX_EVENTS= 2
} EVENTS;
HANDLE events[MAX_EVENTS];
HANDLE broadcast_block_event;
};
} pthread_cond_t; } pthread_cond_t;
...@@ -679,6 +690,47 @@ extern int rw_pr_destroy(rw_pr_lock_t *); ...@@ -679,6 +690,47 @@ extern int rw_pr_destroy(rw_pr_lock_t *);
#ifdef NEED_MY_RW_LOCK #ifdef NEED_MY_RW_LOCK
#ifdef _WIN32
/**
Implementation of Windows rwlock.
We use native (slim) rwlocks on Win7 and later, and fallback to portable
implementation on earlier Windows.
slim rwlock are also available on Vista/WS2008, but we do not use it
("trylock" APIs are missing on Vista)
*/
typedef union
{
/* Native rwlock (is_srwlock == TRUE) */
struct
{
SRWLOCK srwlock; /* native reader writer lock */
BOOL have_exclusive_srwlock; /* used for unlock */
};
/*
Portable implementation (is_srwlock == FALSE)
Fields are identical with Unix my_rw_lock_t fields.
*/
struct
{
pthread_mutex_t lock; /* lock for structure */
pthread_cond_t readers; /* waiting readers */
pthread_cond_t writers; /* waiting writers */
int state; /* -1:writer,0:free,>0:readers */
int waiters; /* number of waiting writers */
#ifdef SAFE_MUTEX
pthread_t write_thread;
#endif
};
} my_rw_lock_t;
#else /* _WIN32 */
/* /*
On systems which don't support native read/write locks we have On systems which don't support native read/write locks we have
to use own implementation. to use own implementation.
...@@ -694,6 +746,8 @@ typedef struct st_my_rw_lock_t { ...@@ -694,6 +746,8 @@ typedef struct st_my_rw_lock_t {
#endif #endif
} my_rw_lock_t; } my_rw_lock_t;
#endif /*! _WIN32 */
extern int my_rw_init(my_rw_lock_t *); extern int my_rw_init(my_rw_lock_t *);
extern int my_rw_destroy(my_rw_lock_t *); extern int my_rw_destroy(my_rw_lock_t *);
extern int my_rw_rdlock(my_rw_lock_t *); extern int my_rw_rdlock(my_rw_lock_t *);
......
...@@ -229,7 +229,8 @@ sub mtr_report_stats ($$;$) { ...@@ -229,7 +229,8 @@ sub mtr_report_stats ($$;$) {
# Find out how we where doing # Find out how we where doing
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
my $tot_skiped= 0; my $tot_skipped= 0;
my $tot_skipdetect= 0;
my $tot_passed= 0; my $tot_passed= 0;
my $tot_failed= 0; my $tot_failed= 0;
my $tot_tests= 0; my $tot_tests= 0;
...@@ -246,8 +247,9 @@ sub mtr_report_stats ($$;$) { ...@@ -246,8 +247,9 @@ sub mtr_report_stats ($$;$) {
} }
elsif ( $tinfo->{'result'} eq 'MTR_RES_SKIPPED' ) elsif ( $tinfo->{'result'} eq 'MTR_RES_SKIPPED' )
{ {
# Test was skipped # Test was skipped (disabled not counted)
$tot_skiped++; $tot_skipped++ unless $tinfo->{'disable'};
$tot_skipdetect++ if $tinfo->{'skip_detected_by_test'};
} }
elsif ( $tinfo->{'result'} eq 'MTR_RES_PASSED' ) elsif ( $tinfo->{'result'} eq 'MTR_RES_PASSED' )
{ {
...@@ -376,6 +378,9 @@ sub mtr_report_stats ($$;$) { ...@@ -376,6 +378,9 @@ sub mtr_report_stats ($$;$) {
print "All $tot_tests tests were successful.\n\n"; print "All $tot_tests tests were successful.\n\n";
} }
print "$tot_skipped tests were skipped, ".
"$tot_skipdetect by the test itself.\n\n" if $tot_skipped;
if ( $tot_failed != 0 || $found_problems) if ( $tot_failed != 0 || $found_problems)
{ {
mtr_error("there were failing test cases") unless $dont_error; mtr_error("there were failing test cases") unless $dont_error;
......
...@@ -126,12 +126,24 @@ my $path_vardir_trace; # unix formatted opt_vardir for trace files ...@@ -126,12 +126,24 @@ my $path_vardir_trace; # unix formatted opt_vardir for trace files
my $opt_tmpdir; # Path to use for tmp/ dir my $opt_tmpdir; # Path to use for tmp/ dir
my $opt_tmpdir_pid; my $opt_tmpdir_pid;
my $opt_start;
my $opt_start_dirty;
my $opt_start_exit;
my $start_only;
END { END {
if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ ) if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ )
{ {
# Remove the tempdir this process has created if (!$opt_start_exit)
mtr_verbose("Removing tmpdir '$opt_tmpdir"); {
rmtree($opt_tmpdir); # Remove the tempdir this process has created
mtr_verbose("Removing tmpdir $opt_tmpdir");
rmtree($opt_tmpdir);
}
else
{
mtr_warning("tmpdir $opt_tmpdir should be removed after the server has finished");
}
} }
} }
...@@ -234,10 +246,6 @@ my $opt_start_timeout = $ENV{MTR_START_TIMEOUT} || 180; # seconds ...@@ -234,10 +246,6 @@ my $opt_start_timeout = $ENV{MTR_START_TIMEOUT} || 180; # seconds
sub suite_timeout { return $opt_suite_timeout * 60; }; sub suite_timeout { return $opt_suite_timeout * 60; };
sub check_timeout { return $opt_testcase_timeout * 6; }; sub check_timeout { return $opt_testcase_timeout * 6; };
my $opt_start;
my $opt_start_dirty;
my $opt_start_exit;
my $start_only;
my $opt_wait_all; my $opt_wait_all;
my $opt_user_args; my $opt_user_args;
my $opt_repeat= 1; my $opt_repeat= 1;
...@@ -2186,6 +2194,11 @@ sub environment_setup { ...@@ -2186,6 +2194,11 @@ sub environment_setup {
# to detect that valgrind is being used from test cases # to detect that valgrind is being used from test cases
$ENV{'VALGRIND_TEST'}= $opt_valgrind; $ENV{'VALGRIND_TEST'}= $opt_valgrind;
# Add dir of this perl to aid mysqltest in finding perl
my $perldir= dirname($^X);
my $pathsep= ":";
$pathsep= ";" if IS_WINDOWS && ! IS_CYGWIN;
$ENV{'PATH'}= "$ENV{'PATH'}".$pathsep.$perldir;
} }
...@@ -3658,6 +3671,9 @@ sub run_testcase ($) { ...@@ -3658,6 +3671,9 @@ sub run_testcase ($) {
# Try to get reason from test log file # Try to get reason from test log file
find_testcase_skipped_reason($tinfo); find_testcase_skipped_reason($tinfo);
mtr_report_test_skipped($tinfo); mtr_report_test_skipped($tinfo);
# Restart if skipped due to missing perl, it may have had side effects
stop_all_servers($opt_shutdown_timeout)
if ($tinfo->{'comment'} =~ /^perl not found/);
} }
elsif ( $res == 65 ) elsif ( $res == 65 )
{ {
......
...@@ -177,6 +177,9 @@ mysqltest: At line 1: End of line junk detected: "disconnect default # comment ...@@ -177,6 +177,9 @@ mysqltest: At line 1: End of line junk detected: "disconnect default # comment
" "
mysqltest: At line 1: Extra delimiter ";" found mysqltest: At line 1: Extra delimiter ";" found
mysqltest: At line 1: Extra delimiter ";" found mysqltest: At line 1: Extra delimiter ";" found
mysqltest: At line 1: Spurious text after `query` expression
mysqltest: At line 1: Spurious text after `query` expression
mysqltest: At line 2: Spurious text after `query` expression
mysqltest: At line 1: Missing argument(s) to 'error' mysqltest: At line 1: Missing argument(s) to 'error'
mysqltest: At line 1: Missing argument(s) to 'error' mysqltest: At line 1: Missing argument(s) to 'error'
mysqltest: At line 1: The sqlstate definition must start with an uppercase S mysqltest: At line 1: The sqlstate definition must start with an uppercase S
...@@ -366,23 +369,24 @@ mysqltest: At line 1: Missing required argument 'sleep_delay' to command 'real_s ...@@ -366,23 +369,24 @@ mysqltest: At line 1: Missing required argument 'sleep_delay' to command 'real_s
mysqltest: At line 1: Invalid argument to sleep "abc" mysqltest: At line 1: Invalid argument to sleep "abc"
mysqltest: At line 1: Invalid argument to real_sleep "abc" mysqltest: At line 1: Invalid argument to real_sleep "abc"
1 1
2
101 101
hej -99
1
mysqltest: At line 1: Missing argument to inc mysqltest: At line 1: Missing argument to inc
mysqltest: At line 1: The argument to inc must be a variable (start with $) mysqltest: At line 1: The argument to inc must be a variable (start with $)
mysqltest: At line 1: Cannot perform inc/dec on a non-numeric value
mysqltest: At line 1: End of line junk detected: "1000" mysqltest: At line 1: End of line junk detected: "1000"
4 mysqltest: At line 1: Cannot perform inc/dec on a non-numeric value
4 mysqltest: At line 1: Cannot perform inc/dec on a non-numeric value
-96
-96
-1 -1
-2
99 99
hej
-1
mysqltest: At line 1: Missing argument to dec mysqltest: At line 1: Missing argument to dec
mysqltest: At line 1: The argument to dec must be a variable (start with $) mysqltest: At line 1: The argument to dec must be a variable (start with $)
mysqltest: At line 1: Cannot perform inc/dec on a non-numeric value
mysqltest: At line 1: End of line junk detected: "1000" mysqltest: At line 1: End of line junk detected: "1000"
mysqltest: At line 1: Cannot perform inc/dec on a non-numeric value
mysqltest: At line 1: Cannot perform inc/dec on a non-numeric value
mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: Missing arguments to system, nothing to do!
mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: Missing arguments to system, nothing to do!
system command 'NonExistsinfComamdn 2> /dev/null' failed system command 'NonExistsinfComamdn 2> /dev/null' failed
...@@ -449,12 +453,16 @@ mysqltest: At line 1: Missing required argument 'host' to command 'connect' ...@@ -449,12 +453,16 @@ mysqltest: At line 1: Missing required argument 'host' to command 'connect'
mysqltest: At line 1: query 'connect con2,localhost,root,,illegal_db' failed: 1049: Unknown database 'illegal_db' mysqltest: At line 1: query 'connect con2,localhost,root,,illegal_db' failed: 1049: Unknown database 'illegal_db'
mysqltest: At line 1: Illegal argument for port: 'illegal_port' mysqltest: At line 1: Illegal argument for port: 'illegal_port'
mysqltest: At line 1: Illegal option to connect: SMTP mysqltest: At line 1: Illegal option to connect: SMTP
OK 200 connects succeeded
mysqltest: The test didn't produce any output
mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 3: connection 'test_con1' not found in connection pool mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 3: connection 'test_con1' not found in connection pool
mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 2: Connection test_con1 already exists mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 2: Connection test_con1 already exists
show tables; show tables;
ERROR 3D000: No database selected ERROR 3D000: No database selected
connect con1,localhost,root,,;
connection default;
connection con1;
disconnect con1;
connection default;
Output from mysqltest-x.inc Output from mysqltest-x.inc
Output from mysqltest-x.inc Output from mysqltest-x.inc
Output from mysqltest-x.inc Output from mysqltest-x.inc
......
...@@ -205,7 +205,7 @@ DROP TABLE `t1`; ...@@ -205,7 +205,7 @@ DROP TABLE `t1`;
-- echo === Using mysqlbinlog to detect failure. Before the patch mysqlbinlog would find a corrupted event, thence would fail. -- echo === Using mysqlbinlog to detect failure. Before the patch mysqlbinlog would find a corrupted event, thence would fail.
-- let $MYSQLD_DATADIR= `SELECT @@datadir`; -- let $MYSQLD_DATADIR= `SELECT @@datadir`
-- exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog -- exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog
-- remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog -- remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog
...@@ -330,7 +330,7 @@ while($ntables) ...@@ -330,7 +330,7 @@ while($ntables)
-- echo ### assertion: check that binlog is not corrupt. Using mysqlbinlog to -- echo ### assertion: check that binlog is not corrupt. Using mysqlbinlog to
-- echo ### detect failure. Before the patch mysqlbinlog would find -- echo ### detect failure. Before the patch mysqlbinlog would find
-- echo ### a corrupted event, thence would fail. -- echo ### a corrupted event, thence would fail.
-- let $MYSQLD_DATADIR= `SELECT @@datadir`; -- let $MYSQLD_DATADIR= `SELECT @@datadir`
-- exec $MYSQL_BINLOG -v --hex $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug50018.binlog -- exec $MYSQL_BINLOG -v --hex $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug50018.binlog
## clean up ## clean up
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
# # # #
################################################################################ ################################################################################
let $save_div_precision_increment = `SELECT @@global.div_precision_increment` let $save_div_precision_increment = `SELECT @@global.div_precision_increment`;
#SET @save_div_precision_increment = @@global.div_precision_increment; #SET @save_div_precision_increment = @@global.div_precision_increment;
......
...@@ -9,7 +9,7 @@ SHOW VARIABLES LIKE 'secure_file_priv'; ...@@ -9,7 +9,7 @@ SHOW VARIABLES LIKE 'secure_file_priv';
# Doing this in a portable manner is difficult but we should be able to # Doing this in a portable manner is difficult but we should be able to
# count on the depth of the directory hierarchy used. Three steps up from # count on the depth of the directory hierarchy used. Three steps up from
# the datadir is the 'mysql_test' directory. # the datadir is the 'mysql_test' directory.
--let $PROTECTED_FILE=`SELECT concat(@@datadir,'/../../../bug50373.txt')`; --let $PROTECTED_FILE=`SELECT concat(@@datadir,'/../../../bug50373.txt')`
--eval SELECT * FROM t1 INTO OUTFILE '$PROTECTED_FILE'; --eval SELECT * FROM t1 INTO OUTFILE '$PROTECTED_FILE';
DELETE FROM t1; DELETE FROM t1;
--eval LOAD DATA INFILE '$PROTECTED_FILE' INTO TABLE t1; --eval LOAD DATA INFILE '$PROTECTED_FILE' INTO TABLE t1;
......
...@@ -494,6 +494,32 @@ remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; ...@@ -494,6 +494,32 @@ remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql;
--error 1 --error 1
--exec echo "--disable_query_log;" | $MYSQL_TEST 2>&1 --exec echo "--disable_query_log;" | $MYSQL_TEST 2>&1
#
# Extra text after ``
#
# Cannot use exec echo here as ` may or may not need to be escaped
--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql
let $x= `select 1` BOO ;
EOF
--error 1
--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1
remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql;
--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql
--let $x= `select 1`;
EOF
--error 1
--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1
remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql;
--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql
# Missing ; in next line should be detected and cause failure
let $x= `select 1`
let $x= 2;
echo $x;
EOF
--error 1
--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1
remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql;
# Allow trailing # comment # Allow trailing # comment
--sleep 1 # Wait for insert delayed to be executed. --sleep 1 # Wait for insert delayed to be executed.
...@@ -980,16 +1006,13 @@ EOF ...@@ -980,16 +1006,13 @@ EOF
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Test inc # Test inc
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
inc $i; let $i= 0;
echo $i;
inc $i; inc $i;
echo $i; echo $i;
let $i=100; let $i=100;
inc $i; inc $i;
echo $i; echo $i;
let $i= -100;
let $i=hej;
echo $i;
inc $i; inc $i;
echo $i; echo $i;
...@@ -998,7 +1021,13 @@ echo $i; ...@@ -998,7 +1021,13 @@ echo $i;
--error 1 --error 1
--exec echo "inc i;" | $MYSQL_TEST 2>&1 --exec echo "inc i;" | $MYSQL_TEST 2>&1
--error 1 --error 1
--exec echo "inc \$i;" | $MYSQL_TEST 2>&1
--error 1
--exec echo "let \$i=100; inc \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1 --exec echo "let \$i=100; inc \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1
--error 1
--exec echo "let \$i=text; inc \$i; echo \$i;" | $MYSQL_TEST 2>&1
--error 1
--exec echo "let \$i=10cc; inc \$i; echo \$i;" | $MYSQL_TEST 2>&1
inc $i; inc $i; inc $i; --echo $i inc $i; inc $i; inc $i; --echo $i
echo $i; echo $i;
...@@ -1008,25 +1037,25 @@ echo $i; ...@@ -1008,25 +1037,25 @@ echo $i;
# Test dec # Test dec
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
dec $d; let $d= 0;
echo $d;
dec $d; dec $d;
echo $d; echo $d;
let $d=100; let $d=100;
dec $d; dec $d;
echo $d; echo $d;
let $d=hej;
echo $d;
dec $d;
echo $d;
--error 1 --error 1
--exec echo "dec;" | $MYSQL_TEST 2>&1 --exec echo "dec;" | $MYSQL_TEST 2>&1
--error 1 --error 1
--exec echo "dec i;" | $MYSQL_TEST 2>&1 --exec echo "dec i;" | $MYSQL_TEST 2>&1
--error 1 --error 1
--exec echo "dec \$i;" | $MYSQL_TEST 2>&1
--error 1
--exec echo "let \$i=100; dec \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1 --exec echo "let \$i=100; dec \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1
--error 1
--exec echo "let \$i=text; dec \$i; echo \$i;" | $MYSQL_TEST 2>&1
--error 1
--exec echo "let \$i=10cc; dec \$i; echo \$i;" | $MYSQL_TEST 2>&1
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
...@@ -1439,19 +1468,6 @@ eval select "$long_rep" as x; ...@@ -1439,19 +1468,6 @@ eval select "$long_rep" as x;
--error 1 --error 1
--exec echo "connect (con1,localhost,root,,,,,SMTP POP);" | $MYSQL_TEST 2>&1 --exec echo "connect (con1,localhost,root,,,,,SMTP POP);" | $MYSQL_TEST 2>&1
# Repeat connect/disconnect
--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql
let $i=100;
while ($i)
{
connect (test_con1,localhost,root,,);
disconnect test_con1;
dec $i;
}
EOF
--exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql; echo OK; exit;" | $MYSQL_TEST 2>&1
remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql;
# Repeat connect/disconnect # Repeat connect/disconnect
--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql --write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql
let $i=200; let $i=200;
...@@ -1461,9 +1477,8 @@ while ($i) ...@@ -1461,9 +1477,8 @@ while ($i)
disconnect test_con1; disconnect test_con1;
dec $i; dec $i;
} }
echo 200 connects succeeded;
EOF EOF
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--error 1
--exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql;" | $MYSQL_TEST 2>&1 --exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql;" | $MYSQL_TEST 2>&1
remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql;
...@@ -1504,6 +1519,22 @@ show tables; ...@@ -1504,6 +1519,22 @@ show tables;
disconnect con2; disconnect con2;
connection default; connection default;
# Test enable_connect_log
--enable_connect_log
connect (con1,localhost,root,,);
connection default;
connection con1;
--disable_query_log
# These should not be logged
connect (con2,localhost,root,,*NO-ONE*);
connection con2;
disconnect con2;
connection con1;
--enable_query_log
disconnect con1;
connection default;
--disable_connect_log
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Test mysqltest arguments # Test mysqltest arguments
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
......
...@@ -24,7 +24,108 @@ ...@@ -24,7 +24,108 @@
#include <process.h> #include <process.h>
#include <sys/timeb.h> #include <sys/timeb.h>
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
/*
Windows native condition variables. We use runtime loading / function
pointers, because they are not available on XP
*/
/* Prototypes and function pointers for condition variable functions */
typedef VOID (WINAPI * InitializeConditionVariableProc)
(PCONDITION_VARIABLE ConditionVariable);
typedef BOOL (WINAPI * SleepConditionVariableCSProc)
(PCONDITION_VARIABLE ConditionVariable,
PCRITICAL_SECTION CriticalSection,
DWORD dwMilliseconds);
typedef VOID (WINAPI * WakeAllConditionVariableProc)
(PCONDITION_VARIABLE ConditionVariable);
typedef VOID (WINAPI * WakeConditionVariableProc)
(PCONDITION_VARIABLE ConditionVariable);
static InitializeConditionVariableProc my_InitializeConditionVariable;
static SleepConditionVariableCSProc my_SleepConditionVariableCS;
static WakeAllConditionVariableProc my_WakeAllConditionVariable;
static WakeConditionVariableProc my_WakeConditionVariable;
/**
Indicates if we have native condition variables,
initialized first time pthread_cond_init is called.
*/
static BOOL have_native_conditions= FALSE;
/**
Check if native conditions can be used, load function pointers
*/
static void check_native_cond_availability(void)
{
HMODULE module= GetModuleHandle("kernel32");
my_InitializeConditionVariable= (InitializeConditionVariableProc)
GetProcAddress(module, "InitializeConditionVariable");
my_SleepConditionVariableCS= (SleepConditionVariableCSProc)
GetProcAddress(module, "SleepConditionVariableCS");
my_WakeAllConditionVariable= (WakeAllConditionVariableProc)
GetProcAddress(module, "WakeAllConditionVariable");
my_WakeConditionVariable= (WakeConditionVariableProc)
GetProcAddress(module, "WakeConditionVariable");
if (my_InitializeConditionVariable)
have_native_conditions= TRUE;
}
/**
Convert abstime to milliseconds
*/
static DWORD get_milliseconds(const struct timespec *abstime)
{
long long millis;
union ft64 now;
if (abstime == NULL)
return INFINITE;
GetSystemTimeAsFileTime(&now.ft);
/*
Calculate time left to abstime
- subtract start time from current time(values are in 100ns units)
- convert to millisec by dividing with 10000
*/
millis= (abstime->tv.i64 - now.i64) / 10000;
/* Don't allow the timeout to be negative */
if (millis < 0)
return 0;
/*
Make sure the calculated timeout does not exceed original timeout
value which could cause "wait for ever" if system time changes
*/
if (millis > abstime->max_timeout_msec)
millis= abstime->max_timeout_msec;
if (millis > UINT_MAX)
millis= UINT_MAX;
return (DWORD)millis;
}
/*
Old (pre-vista) implementation using events
*/
static int legacy_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{ {
cond->waiting= 0; cond->waiting= 0;
InitializeCriticalSection(&cond->lock_waiting); InitializeCriticalSection(&cond->lock_waiting);
...@@ -53,7 +154,8 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) ...@@ -53,7 +154,8 @@ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
return 0; return 0;
} }
int pthread_cond_destroy(pthread_cond_t *cond)
static int legacy_cond_destroy(pthread_cond_t *cond)
{ {
DeleteCriticalSection(&cond->lock_waiting); DeleteCriticalSection(&cond->lock_waiting);
...@@ -65,48 +167,13 @@ int pthread_cond_destroy(pthread_cond_t *cond) ...@@ -65,48 +167,13 @@ int pthread_cond_destroy(pthread_cond_t *cond)
} }
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) static int legacy_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
{
return pthread_cond_timedwait(cond,mutex,NULL);
}
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
struct timespec *abstime) struct timespec *abstime)
{ {
int result; int result;
long timeout; DWORD timeout;
union ft64 now;
if( abstime != NULL )
{
GetSystemTimeAsFileTime(&now.ft);
/*
Calculate time left to abstime
- subtract start time from current time(values are in 100ns units)
- convert to millisec by dividing with 10000
*/
timeout= (long)((abstime->tv.i64 - now.i64) / 10000);
/* Don't allow the timeout to be negative */
if (timeout < 0)
timeout= 0L;
/*
Make sure the calucated timeout does not exceed original timeout
value which could cause "wait for ever" if system time changes
*/
if (timeout > abstime->max_timeout_msec)
timeout= abstime->max_timeout_msec;
}
else
{
/* No time specified; don't expire */
timeout= INFINITE;
}
timeout= get_milliseconds(abstime);
/* /*
Block access if previous broadcast hasn't finished. Block access if previous broadcast hasn't finished.
This is just for safety and should normally not This is just for safety and should normally not
...@@ -142,7 +209,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, ...@@ -142,7 +209,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
return result == WAIT_TIMEOUT ? ETIMEDOUT : 0; return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
} }
int pthread_cond_signal(pthread_cond_t *cond) static int legacy_cond_signal(pthread_cond_t *cond)
{ {
EnterCriticalSection(&cond->lock_waiting); EnterCriticalSection(&cond->lock_waiting);
...@@ -155,7 +222,7 @@ int pthread_cond_signal(pthread_cond_t *cond) ...@@ -155,7 +222,7 @@ int pthread_cond_signal(pthread_cond_t *cond)
} }
int pthread_cond_broadcast(pthread_cond_t *cond) static int legacy_cond_broadcast(pthread_cond_t *cond)
{ {
EnterCriticalSection(&cond->lock_waiting); EnterCriticalSection(&cond->lock_waiting);
/* /*
...@@ -177,6 +244,87 @@ int pthread_cond_broadcast(pthread_cond_t *cond) ...@@ -177,6 +244,87 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
} }
/*
Posix API functions. Just choose between native and legacy implementation.
*/
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
/*
Once initialization is used here rather than in my_init(), to
1) avoid my_init() pitfalls- undefined order in which initialization should
run
2) be potentially useful C++ (in static constructors that run before main())
3) just to simplify the API.
Also, the overhead of my_pthread_once is very small.
*/
static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
my_pthread_once(&once_control, check_native_cond_availability);
if (have_native_conditions)
{
my_InitializeConditionVariable(&cond->native_cond);
return 0;
}
else
return legacy_cond_init(cond, attr);
}
int pthread_cond_destroy(pthread_cond_t *cond)
{
if (have_native_conditions)
return 0; /* no destroy function */
else
return legacy_cond_destroy(cond);
}
int pthread_cond_broadcast(pthread_cond_t *cond)
{
if (have_native_conditions)
{
my_WakeAllConditionVariable(&cond->native_cond);
return 0;
}
else
return legacy_cond_broadcast(cond);
}
int pthread_cond_signal(pthread_cond_t *cond)
{
if (have_native_conditions)
{
my_WakeConditionVariable(&cond->native_cond);
return 0;
}
else
return legacy_cond_signal(cond);
}
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
struct timespec *abstime)
{
if (have_native_conditions)
{
DWORD timeout= get_milliseconds(abstime);
if (!my_SleepConditionVariableCS(&cond->native_cond, mutex, timeout))
return ETIMEDOUT;
return 0;
}
else
return legacy_cond_timedwait(cond, mutex, abstime);
}
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
return pthread_cond_timedwait(cond, mutex, NULL);
}
int pthread_attr_init(pthread_attr_t *connect_att) int pthread_attr_init(pthread_attr_t *connect_att)
{ {
connect_att->dwStackSize = 0; connect_att->dwStackSize = 0;
......
...@@ -155,8 +155,19 @@ int pthread_cancel(pthread_t thread) ...@@ -155,8 +155,19 @@ int pthread_cancel(pthread_t thread)
int my_pthread_once(my_pthread_once_t *once_control, int my_pthread_once(my_pthread_once_t *once_control,
void (*init_routine)(void)) void (*init_routine)(void))
{ {
LONG state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS, LONG state;
MY_PTHREAD_ONCE_INIT);
/*
Do "dirty" read to find out if initialization is already done, to
save an interlocked operation in common case. Memory barriers are ensured by
Visual C++ volatile implementation.
*/
if (*once_control == MY_PTHREAD_ONCE_DONE)
return 0;
state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS,
MY_PTHREAD_ONCE_INIT);
switch(state) switch(state)
{ {
case MY_PTHREAD_ONCE_INIT: case MY_PTHREAD_ONCE_INIT:
......
...@@ -20,6 +20,119 @@ ...@@ -20,6 +20,119 @@
#if defined(NEED_MY_RW_LOCK) #if defined(NEED_MY_RW_LOCK)
#include <errno.h> #include <errno.h>
#ifdef _WIN32
static BOOL have_srwlock= FALSE;
/* Prototypes and function pointers for windows functions */
typedef VOID (WINAPI* srw_func) (PSRWLOCK SRWLock);
typedef BOOL (WINAPI* srw_bool_func) (PSRWLOCK SRWLock);
static srw_func my_InitializeSRWLock;
static srw_func my_AcquireSRWLockExclusive;
static srw_func my_ReleaseSRWLockExclusive;
static srw_func my_AcquireSRWLockShared;
static srw_func my_ReleaseSRWLockShared;
static srw_bool_func my_TryAcquireSRWLockExclusive;
static srw_bool_func my_TryAcquireSRWLockShared;
/**
Check for presence of Windows slim reader writer lock function.
Load function pointers.
*/
static void check_srwlock_availability(void)
{
HMODULE module= GetModuleHandle("kernel32");
my_InitializeSRWLock= (srw_func) GetProcAddress(module,
"InitializeSRWLock");
my_AcquireSRWLockExclusive= (srw_func) GetProcAddress(module,
"AcquireSRWLockExclusive");
my_AcquireSRWLockShared= (srw_func) GetProcAddress(module,
"AcquireSRWLockShared");
my_ReleaseSRWLockExclusive= (srw_func) GetProcAddress(module,
"ReleaseSRWLockExclusive");
my_ReleaseSRWLockShared= (srw_func) GetProcAddress(module,
"ReleaseSRWLockShared");
my_TryAcquireSRWLockExclusive= (srw_bool_func) GetProcAddress(module,
"TryAcquireSRWLockExclusive");
my_TryAcquireSRWLockShared= (srw_bool_func) GetProcAddress(module,
"TryAcquireSRWLockShared");
/*
We currently require TryAcquireSRWLockExclusive. This API is missing on
Vista, this means SRWLock are only used starting with Win7.
If "trylock" usage for rwlocks is eliminated from server codebase (it is used
in a single place currently, in query cache), then SRWLock can be enabled on
Vista too. In this case condition below needs to be changed to e.g check
for my_InitializeSRWLock.
*/
if (my_TryAcquireSRWLockExclusive)
have_srwlock= TRUE;
}
static int srw_init(my_rw_lock_t *rwp)
{
my_InitializeSRWLock(&rwp->srwlock);
rwp->have_exclusive_srwlock = FALSE;
return 0;
}
static int srw_rdlock(my_rw_lock_t *rwp)
{
my_AcquireSRWLockShared(&rwp->srwlock);
return 0;
}
static int srw_tryrdlock(my_rw_lock_t *rwp)
{
if (!my_TryAcquireSRWLockShared(&rwp->srwlock))
return EBUSY;
return 0;
}
static int srw_wrlock(my_rw_lock_t *rwp)
{
my_AcquireSRWLockExclusive(&rwp->srwlock);
rwp->have_exclusive_srwlock= TRUE;
return 0;
}
static int srw_trywrlock(my_rw_lock_t *rwp)
{
if (!my_TryAcquireSRWLockExclusive(&rwp->srwlock))
return EBUSY;
rwp->have_exclusive_srwlock= TRUE;
return 0;
}
static int srw_unlock(my_rw_lock_t *rwp)
{
if (rwp->have_exclusive_srwlock)
{
rwp->have_exclusive_srwlock= FALSE;
my_ReleaseSRWLockExclusive(&rwp->srwlock);
}
else
{
my_ReleaseSRWLockShared(&rwp->srwlock);
}
return 0;
}
#endif /*_WIN32 */
/* /*
Source base from Sun Microsystems SPILT, simplified for MySQL use Source base from Sun Microsystems SPILT, simplified for MySQL use
-- Joshua Chamas -- Joshua Chamas
...@@ -63,6 +176,22 @@ int my_rw_init(my_rw_lock_t *rwp) ...@@ -63,6 +176,22 @@ int my_rw_init(my_rw_lock_t *rwp)
{ {
pthread_condattr_t cond_attr; pthread_condattr_t cond_attr;
#ifdef _WIN32
/*
Once initialization is used here rather than in my_init(), in order to
- avoid my_init() pitfalls- (undefined order in which initialization should
run)
- be potentially useful C++ (static constructors)
- just to simplify the API.
Also, the overhead is of my_pthread_once is very small.
*/
static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
my_pthread_once(&once_control, check_srwlock_availability);
if (have_srwlock)
return srw_init(rwp);
#endif
pthread_mutex_init( &rwp->lock, MY_MUTEX_INIT_FAST); pthread_mutex_init( &rwp->lock, MY_MUTEX_INIT_FAST);
pthread_condattr_init( &cond_attr ); pthread_condattr_init( &cond_attr );
pthread_cond_init( &rwp->readers, &cond_attr ); pthread_cond_init( &rwp->readers, &cond_attr );
...@@ -81,6 +210,10 @@ int my_rw_init(my_rw_lock_t *rwp) ...@@ -81,6 +210,10 @@ int my_rw_init(my_rw_lock_t *rwp)
int my_rw_destroy(my_rw_lock_t *rwp) int my_rw_destroy(my_rw_lock_t *rwp)
{ {
#ifdef _WIN32
if (have_srwlock)
return 0; /* no destroy function */
#endif
DBUG_ASSERT(rwp->state == 0); DBUG_ASSERT(rwp->state == 0);
pthread_mutex_destroy( &rwp->lock ); pthread_mutex_destroy( &rwp->lock );
pthread_cond_destroy( &rwp->readers ); pthread_cond_destroy( &rwp->readers );
...@@ -91,6 +224,11 @@ int my_rw_destroy(my_rw_lock_t *rwp) ...@@ -91,6 +224,11 @@ int my_rw_destroy(my_rw_lock_t *rwp)
int my_rw_rdlock(my_rw_lock_t *rwp) int my_rw_rdlock(my_rw_lock_t *rwp)
{ {
#ifdef _WIN32
if (have_srwlock)
return srw_rdlock(rwp);
#endif
pthread_mutex_lock(&rwp->lock); pthread_mutex_lock(&rwp->lock);
/* active or queued writers */ /* active or queued writers */
...@@ -105,6 +243,12 @@ int my_rw_rdlock(my_rw_lock_t *rwp) ...@@ -105,6 +243,12 @@ int my_rw_rdlock(my_rw_lock_t *rwp)
int my_rw_tryrdlock(my_rw_lock_t *rwp) int my_rw_tryrdlock(my_rw_lock_t *rwp)
{ {
int res; int res;
#ifdef _WIN32
if (have_srwlock)
return srw_tryrdlock(rwp);
#endif
pthread_mutex_lock(&rwp->lock); pthread_mutex_lock(&rwp->lock);
if ((rwp->state < 0 ) || rwp->waiters) if ((rwp->state < 0 ) || rwp->waiters)
res= EBUSY; /* Can't get lock */ res= EBUSY; /* Can't get lock */
...@@ -120,6 +264,11 @@ int my_rw_tryrdlock(my_rw_lock_t *rwp) ...@@ -120,6 +264,11 @@ int my_rw_tryrdlock(my_rw_lock_t *rwp)
int my_rw_wrlock(my_rw_lock_t *rwp) int my_rw_wrlock(my_rw_lock_t *rwp)
{ {
#ifdef _WIN32
if (have_srwlock)
return srw_wrlock(rwp);
#endif
pthread_mutex_lock(&rwp->lock); pthread_mutex_lock(&rwp->lock);
rwp->waiters++; /* another writer queued */ rwp->waiters++; /* another writer queued */
...@@ -140,6 +289,12 @@ int my_rw_wrlock(my_rw_lock_t *rwp) ...@@ -140,6 +289,12 @@ int my_rw_wrlock(my_rw_lock_t *rwp)
int my_rw_trywrlock(my_rw_lock_t *rwp) int my_rw_trywrlock(my_rw_lock_t *rwp)
{ {
int res; int res;
#ifdef _WIN32
if (have_srwlock)
return srw_trywrlock(rwp);
#endif
pthread_mutex_lock(&rwp->lock); pthread_mutex_lock(&rwp->lock);
if (rwp->state) if (rwp->state)
res= EBUSY; /* Can't get lock */ res= EBUSY; /* Can't get lock */
...@@ -158,6 +313,11 @@ int my_rw_trywrlock(my_rw_lock_t *rwp) ...@@ -158,6 +313,11 @@ int my_rw_trywrlock(my_rw_lock_t *rwp)
int my_rw_unlock(my_rw_lock_t *rwp) int my_rw_unlock(my_rw_lock_t *rwp)
{ {
#ifdef _WIN32
if (have_srwlock)
return srw_unlock(rwp);
#endif
DBUG_PRINT("rw_unlock", DBUG_PRINT("rw_unlock",
("state: %d waiters: %d", rwp->state, rwp->waiters)); ("state: %d waiters: %d", rwp->state, rwp->waiters));
pthread_mutex_lock(&rwp->lock); pthread_mutex_lock(&rwp->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment