Bug #42865 System call interrupt in mysql_real_connect
Submitted: 15 Feb 2009 10:16 Modified: 16 Mar 2009 11:05
Reporter: Petr Vodicka Email Updates:
Status: No Feedback Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S3 (Non-critical)
Version:5.1.31 OS:Linux
Assigned to: CPU Architecture:Any
Tags: (4), EINTR, mysql_real_connect, System call interrupted

[15 Feb 2009 10:16] Petr Vodicka
Description:
When mysql.options.connect_timeout = 2; is set with non-zero value, using mysql_real_connect can result with non-zero value indicating error with mysql_error set to 'Can't connect to MySQL server on '192.168.0.9' (4)' even there is no network or server problem.

How to repeat:
By forcing program to interrupt. Install signal function and send signal while mysql_real_connect is waiting for connection. Probably it will be easier to simulate it on loaded servers, networks or client with many signals coming to.

Try this code, edit your server setting in mysql_real_connect(). Use network server, not localhost:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <mysql/mysql.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>

static int terminated = 0;
static int ready = 0;

static void ignore_handler(int useless)
{
        /* Nothing! */
}

static void *thread(void *data)
{
        MYSQL mysql;
        MYSQL_RES *mysqlres;
        int i;
        int old_errno = 0;
#if 1
        struct sigaction catchsig;

        memset(&catchsig, 0, sizeof(catchsig));
        catchsig.sa_handler = ignore_handler;
        if (sigaction(SIGUSR1, &catchsig, NULL) == -1) {
                fprintf(stderr,"sigaction error");
                terminated = 1;
                return NULL;
        }
        ready = 1;
#endif

       /* Cycle for connecting to server */
        for (i=0; i<1000; i++) {
                mysql_init(&mysql);

                /* Set timeout */
                /* When 0 (indefinetely), mysql will use blocking mode on socket, when non-zero non-blocking mode is used */
                mysql.options.connect_timeout = 0;

                /* Remember old errno */
                old_errno = errno;

                /* Connect to server */
                if (!mysql_real_connect(&mysql, "192.168.0.7", "user", "pass", "dbname", 3306, NULL, 0)) {
                        fprintf(stderr, "i=%i errno=%i old_errno=%i mysql_error=%s\n", i, errno, old_errno, mysql_error(&mysql));
                        terminated = 1;
                        pthread_exit(NULL);
                        return NULL;
                }
                mysql_close(&mysql);
        }

        terminated = 1;

        pthread_exit(NULL);
        return NULL;
}

int main(void)
{
        pthread_t t;

        fprintf(stderr, "Running main()\n");

        /* Start thread */
        pthread_create(&t, NULL, thread, NULL);

        /* Send signals */
        while(!terminated) {
            if (ready)
                    pthread_kill(t, SIGUSR1);
            usleep(1);
        }

        fprintf(stderr, "Ending main()\n");

        return 0;
}

Suggested fix:
Change behaviour of function wait_for_data() in libmysql/client.c. If the poll() function return negative value and errno=EINTR repeat poll() call and not return error.

If you decide that this is the reason too, there is another one similar poll() within libmysql/net.c:net_data_is_ready()
[15 Feb 2009 10:19] Petr Vodicka
Use for simulate bug

Attachment: bugtest.c (text/plain), 1.61 KiB.

[15 Feb 2009 10:21] Petr Vodicka
Sorry, use:

mysql.options.connect_timeout = 1;
instead of 
mysql.options.connect_timeout = 0;
whis I type in bug report.

Or use bugtest.c attached file.
[16 Feb 2009 7:28] Sveta Smirnova
Thank you for the report.

But error 4 is "Interrupted system call":

$perror 4
OS error code   4:  Interrupted system call

So this is expected what you get this error if you kill thread which calls mysql_real_connect. Why do you see bug here?
[16 Feb 2009 10:10] Petr Vodicka
I confirm that EINTR is Interuption from signal while processing poll() request.

But I think, that EINTR should be processed inside by mysql client library directly because I did not expect EINTR, processing of it..

Also, it's not listed in manual of mysql_real_connect what mean (4). As a programmer I do expect that if I get non-zero from mysql_real_connect something bad was happened and probably I will give up connecting to MySQL. I am not also ordered to look in errno after mysql_real_connect. This is why I see it as a possible bug.
[16 Feb 2009 11:05] Sveta Smirnova
Thank you for the feedback.

But errno is system error and not MySQL error. To get MySQL error number please use function mysql_errno (http://dev.mysql.com/doc/refman/5.1/en/mysql-errno.html):

Running main()
i=0 errno=4 old_errno=0 mysql_error=Can't connect to MySQL server on '127.0.0.1' (4), mysql_errno=2003
Ending main()

So this is still looks not as MySQL bug for me.
[17 Mar 2009 0:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[9 May 2012 6:32] Shane Bester
see http://bugs.mysql.com/bug.php?id=64333