MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:July 21 2009 12:36pm
Subject:Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2802)
Bug#37780
View as plain text  
* Ingo Struewing <Ingo.Struewing@stripped> [09/05/13 17:30]:
>  2802 Ingo Struewing	2009-05-13
>       Bug#37780 - main.kill fails randomly

Most of the patch is OK to push, but the piece that makes
SIGNAL_WITH_VIO_CLOSE a default option (from a hack that was only
used on Darwin and HP-UX 10.20), is not OK.

I spoke with the build team, and we no longer support Darwin 5/6. 
The oldest Darwin we support is 7.9, and even that is only for
5.0. HP-UX 10.20 we do not support at all.

I wrote a test program to check if signals break recv() on
latest Darwin systems -- they do.

The program is below:
----------------------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>

void die(const char *message)
{
  fprintf(stderr, "%s: %d, %s\n", message, errno, strerror(errno));
  exit(1);
}

struct sockaddr_in get_sockaddr_in(const char *hostname, int port)
{
  struct sockaddr_in result;
  struct hostent *hp;

  memset((void*) &result, 0, sizeof(result));
  result.sin_family= AF_INET;
  result.sin_port= htons(port);

  hp= gethostbyname(hostname);

  if (hp == NULL)
    die("gethostbyname failed");

  memcpy((void*) &result.sin_addr, (const void*) hp->h_addr, hp->h_length);
  return result;
}

extern "C" void dummy(int signal)
{
}

void set_signals()
{
  struct sigaction sa_usr1, unused;
  sigemptyset(&sa_usr1.sa_mask);
  sa_usr1.sa_handler= dummy;
  sa_usr1.sa_flags= 0;

  sigaction(SIGUSR1, &sa_usr1, &unused);
}

void *read_thread_func(void *)
{
  const int port= 22;
  const char *host= "localhost";

  struct sockaddr_in sin;
  int sock= socket(PF_INET, SOCK_STREAM, 0);
  char buff[2048];

  sin= get_sockaddr_in(host, port);

  if (connect(sock, (const sockaddr*) &sin, sizeof(sin)) < 0)
    die("connect failed");

  while (true)
  {
     ssize_t len= recv(sock, buff, sizeof(buff), 0);
     if (len < 0)
       die("recv failed");

     if (len > 0)
     {
       buff[len]= '\0';
       printf("%s\n", buff);
     }
  }
  return NULL;
}

int main()
{
  pthread_t read_thread;
  set_signals();

  if (pthread_create(&read_thread, NULL, read_thread_func, NULL))
    die("pthread_create failed");

  sleep(3);

  pthread_kill(read_thread, SIGUSR1);
  pthread_join(read_thread, NULL);
}
-------------------------------------------------------------

The hack was initially added to fix the broken socket API on
these systems -- signals there don't break reads.

By closing the vio when killing a thread you deny the killed
thread a chance to gracefully communicate with the client --
essentially, you terminate the exchange between the running thread
and the client somewhere in the middle.

So if we are to remove SIGNAL_WITH_VIO_CLOSE (which I fully support),
we should remove the code associated with it, rather than try to make
it a default behaviour.

As to the race condition between pthread_kill() and recv(), it
is known, and I think we should not pay such a dear price
for removing it.  

Please see some other comments inline.

> === modified file 'include/config-win.h'
> --- a/include/config-win.h	2009-04-03 15:14:49 +0000
> +++ b/include/config-win.h	2009-05-13 13:22:15 +0000
> @@ -222,11 +222,6 @@ typedef SSIZE_T ssize_t;
>  /* ERROR is defined in wingdi.h */
>  #undef ERROR
>  
> -/* We need to close files to break connections on shutdown */
> -#ifndef SIGNAL_WITH_VIO_CLOSE
> -#define SIGNAL_WITH_VIO_CLOSE
> -#endif
> -
>  /* All windows servers should support .sym files */
>  #undef USE_SYMDIR
>  #define USE_SYMDIR

OK.
Agree with Davi, please also remove bits from configure.in.

I assume the patch goes into 5.4?

> === modified file 'mysql-test/t/kill.test'
> --- a/mysql-test/t/kill.test	2009-02-13 17:00:42 +0000
> +++ b/mysql-test/t/kill.test	2009-05-13 13:22:15 +0000
> @@ -1,306 +1,314 @@
> -# This test doesn't work with the embedded version as this code
> -# assumes that one query is running while we are doing queries on
> -# a second connection.
> -# This would work if mysqltest run would be threaded and handle each
> -# connection in a separate thread.
> -#

Please update the comment, don't just remove it.
Quoting the bits from your reply to Davi:

Running the test on an embedded server hangs on waiting for the
target session to end. There is no vio connection that can be
closed.  The user thread is not in a state where SIGALRM awakes it
from. It is not in a wait condition. So KILL blows out with no
effect.

>  -- source include/not_embedded.inc
> +-- source include/have_debug_sync.inc
>  
> -# Disable concurrent inserts to avoid test failures when reading the
> -# connection id which was inserted into a table by another thread.
> -set @old_concurrent_insert= @@global.concurrent_insert;
> -set @@global.concurrent_insert= 0;
> +--disable_warnings
> +SET DEBUG_SYNC = 'RESET';
> +DROP TABLE IF EXISTS t1, t2, t3;
> +--enable_warnings

Checked the test case and found all the changes to be OK.

> === modified file 'sql/event_queue.cc'
> --- a/sql/event_queue.cc	2008-12-04 21:02:09 +0000
> +++ b/sql/event_queue.cc	2009-05-13 13:22:15 +0000
> @@ -742,11 +742,14 @@ Event_queue::cond_wait(THD *thd, struct 
>  
>    thd->enter_cond(&COND_queue_state, &LOCK_event_queue, msg);
>  
> -  DBUG_PRINT("info", ("pthread_cond_%swait", abstime? "timed":""));
> -  if (!abstime)
> -    pthread_cond_wait(&COND_queue_state, &LOCK_event_queue);
> -  else
> -    pthread_cond_timedwait(&COND_queue_state, &LOCK_event_queue, abstime);
> +  if (!thd->killed)
> +  {
> +    DBUG_PRINT("info", ("pthread_cond_%swait", abstime? "timed":""));
> +    if (!abstime)
> +      pthread_cond_wait(&COND_queue_state, &LOCK_event_queue);
> +    else
> +      pthread_cond_timedwait(&COND_queue_state, &LOCK_event_queue,
> abstime);
> +  }

OK.

>  
>    mutex_last_locked_in_func= func;
>    mutex_last_locked_at_line= line;
> 
> === modified file 'sql/lock.cc'
> --- a/sql/lock.cc	2009-03-18 21:22:12 +0000
> +++ b/sql/lock.cc	2009-05-13 13:22:15 +0000
> @@ -1128,6 +1128,14 @@ bool lock_global_read_lock(THD *thd)
>      const char *new_message= "Waiting to get readlock";
>      (void) pthread_mutex_lock(&LOCK_global_read_lock);
>  
> +    old_message= thd->enter_cond(&COND_global_read_lock,
> +                                 &LOCK_global_read_lock, new_message);
> +    DBUG_PRINT("info",
> +               ("waiting_for: %d  protect_against: %d",
> +                waiting_for_read_lock, protect_against_global_read_lock));
> +
> +    waiting_for_read_lock++;
> +
>  #if defined(ENABLED_DEBUG_SYNC)
>      /*
>        The below sync point fires if we have to wait for
> @@ -1136,27 +1144,18 @@ bool lock_global_read_lock(THD *thd)
>        WARNING: Beware to use WAIT_FOR with this sync point. We hold
>        LOCK_global_read_lock here.
>  
> -      Call the sync point before calling enter_cond() as it does use
> -      enter_cond() and exit_cond() itself if a WAIT_FOR action is
> -      executed in spite of the above warning.
> +      The sync point is after enter_cond() so that proc_info is
> +      available immediately after the sync point sends a SIGNAL. This
> +      can make tests more reliable.
>  
> -      Pre-set proc_info so that it is available immediately after the
> -      sync point sends a SIGNAL. This makes tests more reliable.
> +      The sync point is before the loop so that it is executed once only.
>      */
> -    if (protect_against_global_read_lock)
> +    if (protect_against_global_read_lock && !thd->killed)
>      {
> -      thd_proc_info(thd, new_message);
>        DEBUG_SYNC(thd, "wait_lock_global_read_lock");
>      }
OK. 

>  #endif /* defined(ENABLED_DEBUG_SYNC) */
>  
> -    old_message=thd->enter_cond(&COND_global_read_lock,
> &LOCK_global_read_lock,
> -                                new_message);
> -    DBUG_PRINT("info",
> -	       ("waiting_for: %d  protect_against: %d",
> -		waiting_for_read_lock, protect_against_global_read_lock));
> -
> -    waiting_for_read_lock++;
>      while (protect_against_global_read_lock && !thd->killed)
>        pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
>      waiting_for_read_lock--;
> @@ -1272,6 +1271,9 @@ bool wait_if_global_read_lock(THD *thd, 
>        DBUG_RETURN(is_not_commit);
>      }
>  
> +    old_message= thd->enter_cond(&COND_global_read_lock,
> +                                 &LOCK_global_read_lock, new_message);
> +
>  #if defined(ENABLED_DEBUG_SYNC)
>      /*
>        The below sync point fires if we have to wait for
> @@ -1280,22 +1282,19 @@ bool wait_if_global_read_lock(THD *thd, 
>        WARNING: Beware to use WAIT_FOR with this sync point. We hold
>        LOCK_global_read_lock here.
>  
> -      Call the sync point before calling enter_cond() as it does use
> -      enter_cond() and exit_cond() itself if a WAIT_FOR action is
> -      executed in spite of the above warning.
> +      The sync point is after enter_cond() so that proc_info is
> +      available immediately after the sync point sends a SIGNAL. This
> +      can make tests more reliable.
>  
> -      Pre-set proc_info so that it is available immediately after the
> -      sync point sends a SIGNAL. This makes tests more reliable.
> +      The sync point is before the loop so that it is executed once only.
>      */
> -    if (must_wait)
> +    if (must_wait && ! thd->killed &&
> +        (!abort_on_refresh || thd->version == refresh_version))
>      {
> -      thd_proc_info(thd, new_message);
>        DEBUG_SYNC(thd, "wait_if_global_read_lock");
>      }
>  #endif /* defined(ENABLED_DEBUG_SYNC) */
>  
> -    old_message=thd->enter_cond(&COND_global_read_lock,
> &LOCK_global_read_lock,
> -                                new_message);
>      while (must_wait && ! thd->killed &&
>  	   (!abort_on_refresh || thd->version == refresh_version))
>      {

OK.

> 
> === modified file 'sql/mdl.cc'
> --- a/sql/mdl.cc	2009-03-31 13:00:58 +0000
> +++ b/sql/mdl.cc	2009-05-13 13:22:15 +0000
> @@ -533,8 +533,6 @@ static inline void mdl_exit_cond(THD *th
>    mysys_var->current_cond= 0;
>    pthread_mutex_unlock(&mysys_var->mutex);
>  
> -  DEBUG_SYNC(thd, "mdl_exit_cond");
> -
>    (void) set_thd_proc_info(thd, old_msg, calling_func,
>                             calling_file, calling_line);
>  }

OK.
> 
> === modified file 'sql/slave.cc'
> --- a/sql/slave.cc	2009-04-13 13:24:28 +0000
> +++ b/sql/slave.cc	2009-05-13 13:22:15 +0000
> @@ -718,9 +718,17 @@ int start_slave_thread(pthread_handler h
>      while (start_id == *slave_run_id)
>      {
>        DBUG_PRINT("sleep",("Waiting for slave thread to start"));
> -      const char* old_msg = thd->enter_cond(start_cond,cond_lock,
> -                                            "Waiting for slave thread to start");
> -      pthread_cond_wait(start_cond,cond_lock);
> +      const char* old_msg= thd->enter_cond(start_cond, cond_lock,
> +                                           "Waiting for slave thread to start");
> +      /*
> +        It is not sufficient to test this at loop bottom. We must test
> +        it after registering the mutex in enter_cond(). If the kill
> +        happens after testing of thd->killed and before the mutex is
> +        registered, we could otherwise go waiting though thd->killed is
> +        set.
> +      */
> +      if (!thd->killed)
> +        pthread_cond_wait(start_cond, cond_lock);

OK.
>        thd->exit_cond(old_msg);
>        pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
>        if (thd->killed)
> @@ -2418,9 +2426,7 @@ static int try_to_reconnect(THD *thd, MY
>  {
>    mi->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
>    thd->proc_info= messages[SLAVE_RECON_MSG_WAIT];
> -#ifdef SIGNAL_WITH_VIO_CLOSE  
>    thd->clear_active_vio();
> -#endif
>    end_server(mysql);
>    if ((*retry_count)++)
>    {
> @@ -2760,9 +2766,7 @@ err:
>        can be called in the middle of closing the VIO associated with
>        the 'mysql' object, causing a crash.
>      */
> -#ifdef SIGNAL_WITH_VIO_CLOSE
>      thd->clear_active_vio();
> -#endif

Suggest to kill the #ifdef and the contents of it, since it
is never used now.

>      mysql_close(mysql);
>      mi->mysql=0;
>    }
> @@ -3884,9 +3888,7 @@ replication resumed in log '%s' at posit
>        general_log_print(thd, COM_CONNECT_OUT, "%s@%s:%d",
>                          mi->user, mi->host, mi->port);
>      }
> -#ifdef SIGNAL_WITH_VIO_CLOSE
>      thd->set_active_vio(mysql->net.vio);
> -#endif
>    }
>    mysql->reconnect= 1;
>    DBUG_PRINT("exit",("slave_was_killed: %d", slave_was_killed));
> 
> === modified file 'sql/sql_base.cc'
> --- a/sql/sql_base.cc	2009-04-03 15:14:49 +0000
> +++ b/sql/sql_base.cc	2009-05-13 13:22:15 +0000
> @@ -1024,7 +1024,7 @@ bool close_cached_tables(THD *thd, TABLE
>        }
>      }
>  
> -    if (found)
> +    if (found && ! thd->killed)
>      {
>        DBUG_PRINT("signal", ("Waiting for COND_refresh"));
>        pthread_cond_wait(&COND_refresh,&LOCK_open);
> @@ -7770,7 +7770,16 @@ static bool tdc_wait_for_old_versions(TH
>        break;
>      }
>      old_msg= thd->enter_cond(&COND_refresh, &LOCK_open, "Waiting for
> table");
> -    pthread_cond_wait(&COND_refresh, &LOCK_open);
> +    if (!thd->killed)
> +    {
> +      /*
> +        The sync point is after enter_cond() so that proc_info is
> +        available immediately after the sync point sends a SIGNAL. This
> +        can make tests more reliable.
> +      */
> +      DEBUG_SYNC(thd, "tdc_wait_for_table");
> +      pthread_cond_wait(&COND_refresh, &LOCK_open);
> +    }
>      /* LOCK_open mutex is unlocked by THD::exit_cond() as side-effect. */
>      thd->exit_cond(old_msg);

OK.

> +/**
> +  Awake a thread.
> +
> +  @param[in]    state_to_set            value for THD::killed
> +
> +  This is normally called from another thread's THD object.
> +
> +  @note Do always call this while holding LOCK_delete.
> +*/
> +
>  void THD::awake(THD::killed_state state_to_set)
>  {
>    DBUG_ENTER("THD::awake");
> -  DBUG_PRINT("enter", ("this: %p", this));
> +  DBUG_PRINT("enter", ("this: %p  current_thd: %p", this, current_thd));
>    THD_CHECK_SENTRY(this);
> -  safe_mutex_assert_owner(&LOCK_delete); 
> +  safe_mutex_assert_owner(&LOCK_delete);
>  
> +  /*
> +    Set the 'killed' flag of 'this', which is the target THD object.
> +  */
>    killed= state_to_set;
> +
>    if (state_to_set != THD::KILL_QUERY)
>    {
> -    thr_alarm_kill(thread_id);
> -    if (!slave_thread)
> -      thread_scheduler.post_kill_notification(this);
> -#ifdef SIGNAL_WITH_VIO_CLOSE
>      if (this != current_thd)
>      {
>        /*
> -        In addition to a signal, let's close the socket of the thread that
> -        is being killed. This is to make sure it does not block if the
> -        signal is lost. This needs to be done only on platforms where
> -        signals are not a reliable interruption mechanism.
> -
> -        If we're killing ourselves, we know that we're not blocked, so this
> -        hack is not used.
> +        Before sending a signal, let's close the socket of the thread
> +        that is being killed ("this", which is not the current thread).
> +        This is to make sure it does not block if the signal is lost.
> +        Another reason is that the target thread might not wait on the
> +        socket at the moment when we send the signal. It might come
> +        later to the blocking point. The closed connection prevents it
> +        from blocking.
> +
> +        If we are killing ourselves, we know that we are not blocked.
> +        We also know that we will check thd->killed before we go for
> +        reading the next statement.
>        */
>  
>        close_active_vio();
>      }
> -#endif    
> +
> +    /*
> +      Mark the target thread's alarm request expired, and signal alarm.
> +      This is done after closing the socket to avoid a possible race
> +      condition. If the target thread did already pass the last check of
> +      thd->killed but has not yet arrived in read(2), the signal would
> +      not affect it. It could still run into read(2). But As we have
> +      already closed the socket, read(2) will fail immediately.
> +
> +      If we reverse the two operations, the target thread could go into
> +      read(2) after the alarm signal came in and before the socket is
> +      closed. The closing operation itself might not awake the target
> +      thread on all platforms.
> +    */
> +    thr_alarm_kill(thread_id);
> +
> +    /* Send an event to "libevent" that a thread should be killed. */
> +    if (!slave_thread)
> +      thread_scheduler.post_kill_notification(this);
>    }

OK, but please remove close_active_vio().

> +
> +  /*
> +    Broadcast a condition to kick the target if it is waiting on it.
> +  */
>    if (mysys_var)
>    {
>      pthread_mutex_lock(&mysys_var->mutex);
> @@ -1187,6 +1221,11 @@ void THD::awake(THD::killed_state state_
>        It's true that we have set its thd->killed but it may not
>        see it immediately and so may have time to reach the cond_wait().
>  
> +      However, where possible, we test for killed once again after
> +      enter_cond(). This should make the signalling as safe as possible.
> +      However, there is still a small chance of failure on platforms with
> +      instuction or memory write reordering.
> +
>        We have to do the loop with trylock, because if we would use
>        pthread_mutex_lock(), we can cause a deadlock as we are here locking
>        the mysys_var->mutex and mysys_var->current_mutex in a different order
> @@ -1194,7 +1233,7 @@ void THD::awake(THD::killed_state state_
>        We only sleep for 2 seconds as we don't want to have LOCK_delete
>        locked too long time.
>  
> -      There is a small change we may not succeed in aborting a thread that
> +      There is a small chance we may not succeed in aborting a thread that
>        is not yet waiting for a mutex, but as this happens only for a
>        thread that was doing something else when the kill was issued and
>        which should detect the kill flag before it starts to wait, this
> @@ -1576,7 +1615,7 @@ int THD::send_explain_fields(select_resu
>                                Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF));
>  }
>  
> -#ifdef SIGNAL_WITH_VIO_CLOSE
> +
>  void THD::close_active_vio()
>  {
>    DBUG_ENTER("close_active_vio");
> @@ -1590,7 +1629,6 @@ void THD::close_active_vio()
>  #endif
>    DBUG_VOID_RETURN;
>  }
> -#endif
>  
>  
>  struct Item_change_record: public ilink
> 
> === modified file 'sql/sql_class.h'
> --- a/sql/sql_class.h	2009-04-14 23:53:44 +0000
> +++ b/sql/sql_class.h	2009-05-13 13:22:15 +0000
> @@ -1485,9 +1485,7 @@ public:
>  #ifndef __WIN__
>    sigset_t signals;
>  #endif
> -#ifdef SIGNAL_WITH_VIO_CLOSE
>    Vio* active_vio;
> -#endif
>    /*
>      This is to track items changed during execution of a prepared
>      statement/stored procedure. It's created by
> @@ -1715,6 +1713,12 @@ public:
>    DYNAMIC_ARRAY user_var_events;        /* For user variables replication */
>    MEM_ROOT      *user_var_events_alloc; /* Allocate above array elements here */
>  
> +  /*
> +    If checking this in conjunction with a wait condition, please
> +    include a check after enter_cond() if you want to avoid a race
> +    condition. For details see the implementation of awake(),
> +    especially the "broadcast" part.
> +  */
>    enum killed_state
>    {
>      NOT_KILLED=0,
> @@ -1903,7 +1907,6 @@ public:
>    void cleanup(void);
>    void cleanup_after_query();
>    bool store_globals();
> -#ifdef SIGNAL_WITH_VIO_CLOSE
>    inline void set_active_vio(Vio* vio)
>    {
>      pthread_mutex_lock(&LOCK_delete);
> @@ -1917,7 +1920,6 @@ public:
>      pthread_mutex_unlock(&LOCK_delete);
>    }
>    void close_active_vio();
> -#endif
>    void awake(THD::killed_state state_to_set);
>  
>  #ifndef MYSQL_CLIENT
> 
> === modified file 'sql/sql_connect.cc'
> --- a/sql/sql_connect.cc	2009-03-17 20:26:16 +0000
> +++ b/sql/sql_connect.cc	2009-05-13 13:22:15 +0000
> @@ -661,9 +661,7 @@ static int check_connection(THD *thd)
>  
>    DBUG_PRINT("info",
>               ("New connection received on %s", vio_description(net->vio)));
> -#ifdef SIGNAL_WITH_VIO_CLOSE
>    thd->set_active_vio(net->vio);
> -#endif
>  
>    if (!thd->main_security_ctx.host)         // If TCP/IP connection
>    {
> 
> === modified file 'sql/sql_parse.cc'
> --- a/sql/sql_parse.cc	2009-04-22 22:12:25 +0000
> +++ b/sql/sql_parse.cc	2009-05-13 13:22:15 +0000
> @@ -674,6 +674,22 @@ bool do_command(THD *thd)
>  
>    net_new_transaction(net);
>  
> +  /*
> +    Synchronization point for testing of KILL_CONNECTION.
> +    This sync point can wait here, to simulate slow code execution
> +    between the last test of thd->killed and blocking in read().
> +
> +    The goal of this test is to verify that a connection does not
> +    hang, if it is killed at this point of execution.
> +    (Bug#37780 - main.kill fails randomly)
> +
> +    Note that the sync point wait itself will be terminated by a
> +    kill. In this case it consumes a condition broadcast, but does
> +    not change anything else. The consumed broadcast should not
> +    matter here, because the read/recv() below doesn't use it.
> +  */
> +  DEBUG_SYNC(thd, "before_do_command_net_read");
> +
>    if ((packet_length= my_net_read(net)) == packet_error)
>    {
>      DBUG_PRINT("info",("Got error %d reading command from socket %s",
> 
> === modified file 'sql/sql_select.cc'
> --- a/sql/sql_select.cc	2009-04-13 09:51:24 +0000
> +++ b/sql/sql_select.cc	2009-05-13 13:22:15 +0000
> @@ -29,6 +29,7 @@
>  #endif
>  
>  #include "mysql_priv.h"
> +#include "debug_sync.h"
>  #include "sql_select.h"
>  #include "sql_cursor.h"
>  
> @@ -1416,6 +1417,7 @@ JOIN::optimize()
>    if (optimized)
>      DBUG_RETURN(0);
>    optimized= 1;
> +  DEBUG_SYNC(thd, "before_join_optimize");
>  
>    thd_proc_info(thd, "optimizing");
>    
> 
> === modified file 'vio/viosocket.c'
> --- a/vio/viosocket.c	2009-03-17 20:07:27 +0000
> +++ b/vio/viosocket.c	2009-05-13 13:22:15 +0000
> @@ -277,8 +277,10 @@ int vio_close(Vio * vio)
>      DBUG_ASSERT(vio->sd >= 0);
>      if (shutdown(vio->sd, SHUT_RDWR))
>        r= -1;
> +    DBUG_PRINT("vio", ("shut down socket: %d", vio->sd));
>      if (closesocket(vio->sd))
>        r= -1;
> +    DBUG_PRINT("vio", ("closed socket: %d", vio->sd));
>    }
>    if (r)
>    {

Thank you for working on this.
If after removing the part of the patch that is related to
close_active_vio() the test continues to sporadically fail,
please push anyway, but don't enable the test. 
Instead, open another bug report that will move it to "unstable"
test suite.

-- 
kostja
Thread
bzr commit into mysql-6.0-backup branch (ingo.struewing:2802) Bug#37780Ingo Struewing13 May
  • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2802)Bug#37780Davi Arnaut18 Jun
  • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2802)Bug#37780Konstantin Osipov21 Jul
    • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2802)Bug#37780Ingo Strüwing21 Jul
      • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2802)Bug#37780Konstantin Osipov21 Jul
      • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2802)Bug#37780Konstantin Osipov27 Jul