Bug #66434 mysql_library_end does not cleanup properly on Windows
Submitted: 17 Aug 2012 14:25 Modified: 20 Aug 2012 20:57
Reporter: Vyacheslav Chernyshev Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S2 (Serious)
Version:5.5.27 64bit OS:Windows (Windows 7 HP 64bit)
Assigned to: CPU Architecture:Any

[17 Aug 2012 14:25] Vyacheslav Chernyshev
Description:
While porting an application that was written for UNIX-like OS'es I've encountered a very weird behaviour of mysql_library_init - mysql_library_end sequence on Windows. mysql_library_init spawns some helper thread with stack trace that looks like:
    ntdll!ZwWriteFileGather ()
    ntdll!TpReleasePool ()
    ?? ()
but this thread is not terminated by mysql_library_end for some reason that is unknown to me.

My application uses POSIX compatibility layer provided by MinGW compiler, and does `pthread_exit(NULL);` instead of `return 0;` in main() function to ensure that thread-specific data used by main thread is properly cleaned up at shutdown and to wait for termination of all other threads. But as these helper threads created by MySQL are never terminated, my application just hangs forever.

How to repeat:
1. Download mysql-5.5.27-winx64.msi from http://dev.mysql.com/downloads/mysql/ and install it with default parameters.
2. Download x86_64-mingw-w64-gcc-4.7.1-release-c,c++,fortran-sjlj-rev2.7z from http://sourceforge.net/projects/mingwbuilds/files/windows-host/4.7.1/release/ and unpack it to disk C: (so you have C:\mingw directory after that).
3. Create directory bugtest on disk C:.
4. Copy C:\Program Files\MySQL\MySQL Server 5.5\lib\libmysql.dll to C:\bugtest.
5. Open notepad.exe and write this code there:
    #include <pthread.h>
    #include <mysql.h>

    int main(int argc, char *argv[])
    {
        mysql_library_init(0, NULL, NULL);
        mysql_library_end();

        pthread_exit(NULL);
    }
   Save this file as C:\bugtest\test.c
6. Open windows command promt (cmd.exe) and execute following commands:
    cd C:\bugtest
    C:\mingw\bin\gcc.exe test.c -I"C:\Program Files\MySQL\MySQL Server 5.5\include" -L"C:\Program Files\MySQL\MySQL Server 5.5\lib" -lpthread -lmysql -o test.exe
   Executable will be saved as C:\bugtest\test.exe
7. Launch C:\bugtest\test.exe to see that it hangs forever instead of terminating immediately.

Suggested fix:
I have not checked the source code of MySQL server yet to see whether it is possible, but I think that all helper threads created by MySQL must be terminated when mysql_library_end is called.
[17 Aug 2012 16:00] MySQL Verification Team
Thank you for the bug report. From the Manual:

http://dev.mysql.com/doc/refman/5.5/en/connector-cpp-installation-source-windows.html

Note
Please note the only compiler formally supported for Windows is Microsoft Visual Studio 2003 and above.
[17 Aug 2012 16:44] Vyacheslav Chernyshev
Hello Miguel. I know, but it really does not matter here as pthread layer on windows is using native WinAPI calls. I can write the code that uses windows-specific constructs and reproduces the same problem. Here it is (can be compiled by both MinGW and MSVC):
    #include <winsock2.h>
    #include <windows.h>
    #include <mysql.h>

    int main(int argc, char *argv[])
    {
        mysql_library_init(0, NULL, NULL);
        mysql_library_end();

        ExitThread(0);
    }
ExitThread(0) in main causes application to wait till all other threads terminate and it does not happen.
[20 Aug 2012 20:57] Vyacheslav Chernyshev
After digging through assembly of WinSock-related DLLs I have to admit that it is not a bug of MySQL. I'd like to explain the reason of such behaviour, just in case that somebody else will find the same issue. getservbyname("mysql", "tcp") is called during initialization of MySQL library. On Windows it is using WSA-specific service lookup functions (WSALookupServiceBegin, WSALookupServiceNext, WSALookupServiceEnd) internally. At first usage they trigger loading of namespace provider DLLs and one of them spawns this helper thread. Unfortunately it is not shut down when WSACleanup is called, so I'll have to workaround this problem myself.