I'm not diff expert, but I tried "git diff" -- maybe now is better. Due to problem with new file I copy context of "mingw_lock.c" to smallest "ftello.c" -- surprisingly make install works and with new "libmingwex.a" I can compile "test-stdio.c" file and it is working.

Could you/Kai show example of performance drop with this patch?


W dniu 2015-08-02 o 01:43, JonY pisze:
On 8/2/2015 06:27, Mateusz wrote:
We have 4 functions from printf family that output to FILE stream:
printf, vprintf, fprintf, vfprintf

We have also puts/fputs functions that output to FILE stream and are
always directly from msvcrt.dll.

puts/fputs functions are atomic with Microsoft lock. If we want
mingw-w64 printf functions (__USE_MINGW_ANSI_STDIO) to be atomic against
puts/fputs functions, we must copy lock from Microsoft sources.

Microsoft use _lock_file/_unlock_file lock to stdio functions, so patch
for mingw-w64
printf, vprintf, fprintf, vfprintf
functions are obvious -- _lock_file -> __pformat -> _unlock_file

There is one problem: _lock_file/_unlock_file are exported from
msvcr*.dll starting from version msvcr90.dll. There are no such
functions in msvcrt.dll & msvcr80.dll.

My proposition: we can add obvious patch to mingw-w64 printf functions
family and copy _lock_file/_unlock_file from MS sources and add only to
libmsvcrt.a & libmsvcr80.a.

I attached diff file that is not complete -- there is to do add
mingw_lock.c source to libmsvcrt.a & libmsvcr80.a.

Please resend patch in unified diff form.

I spoke with Kai earlier, he wants __pformat behavior unchanged for
performance reasons, preferring programs to handle their own locking,
you may be able to convince him otherwise.




------------------------------------------------------------------------------


_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

diff --git a/mingw-w64-crt/stdio/ftello.c b/mingw-w64-crt/stdio/ftello.c
index 1a63987..31a0b5a 100644
--- a/mingw-w64-crt/stdio/ftello.c
+++ b/mingw-w64-crt/stdio/ftello.c
@@ -3,3 +3,95 @@
 _off_t ftello(FILE * stream){
   return (_off_t) ftello64(stream);
 }
+
+
+
+#include <stdio.h>
+#include <synchapi.h>
+#include "internal.h"
+
+
+_CRTIMP void __cdecl _lock(int locknum);
+_CRTIMP void __cdecl _unlock(int locknum);
+#define _STREAM_LOCKS   16
+#define _IOLOCKED       0x8000
+
+
+/***
+* _lock_file - Lock a FILE
+*
+*Purpose:
+*       Assert the lock for a stdio-level file
+*
+*Entry:
+*       pf = __piob[] entry (pointer to a FILE or _FILEX)
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void __cdecl _lock_file( FILE *pf )
+{
+        /*
+         * The way the FILE (pointed to by pf) is locked depends on whether
+         * it is part of _iob[] or not
+         */
+        if ( (pf >= (&__iob_func()[0])) && (pf <= 
(&__iob_func()[_IOB_ENTRIES-1])) )
+        {
+            /*
+             * FILE lies in _iob[] so the lock lies in _locktable[].
+             */
+            _lock( _STREAM_LOCKS + (int)(pf - (&__iob_func()[0])) );
+            /* We set _IOLOCKED to indicate we locked the stream */
+            pf->_flag |= _IOLOCKED;
+        }
+        else
+            /*
+             * Not part of _iob[]. Therefore, *pf is a _FILEX and the
+             * lock field of the struct is an initialized critical
+             * section.
+             */
+            EnterCriticalSection( &(((_FILEX *)pf)->lock) );
+}
+
+
+/***
+* _unlock_file - Unlock a FILE
+*
+*Purpose:
+*       Release the lock for a stdio-level file
+*
+*Entry:
+*       pf = __piob[] entry (pointer to a FILE or _FILEX)
+*
+*Exit:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void __cdecl _unlock_file( FILE *pf )
+{
+        /*
+         * The way the FILE (pointed to by pf) is unlocked depends on whether
+         * it is part of _iob[] or not
+         */
+        if ( (pf >= (&__iob_func()[0])) && (pf <= 
(&__iob_func()[_IOB_ENTRIES-1])) )
+        {
+            /*
+             * FILE lies in _iob[] so the lock lies in _locktable[].
+             * We reset _IOLOCKED to indicate we unlock the stream.
+             */
+             pf->_flag &= ~_IOLOCKED;
+            _unlock( _STREAM_LOCKS + (int)(pf - (&__iob_func()[0])) );
+        }
+        else
+            /*
+             * Not part of _iob[]. Therefore, *pf is a _FILEX and the
+             * lock field of the struct is an initialized critical
+             * section.
+             */
+            LeaveCriticalSection( &(((_FILEX *)pf)->lock) );
+}
diff --git a/mingw-w64-crt/stdio/mingw_fprintf.c 
b/mingw-w64-crt/stdio/mingw_fprintf.c
index 011a634..438941f 100644
--- a/mingw-w64-crt/stdio/mingw_fprintf.c
+++ b/mingw-w64-crt/stdio/mingw_fprintf.c
@@ -50,7 +50,9 @@ int __cdecl __fprintf(FILE *stream, const APICHAR *fmt, ...)
 {
   register int retval;
   va_list argv; va_start( argv, fmt );
+  _lock_file( stream );
   retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv 
);
+  _unlock_file( stream );
   va_end( argv );
   return retval;
 }
diff --git a/mingw-w64-crt/stdio/mingw_printf.c 
b/mingw-w64-crt/stdio/mingw_printf.c
index 5d23b02..fbd2e7d 100644
--- a/mingw-w64-crt/stdio/mingw_printf.c
+++ b/mingw-w64-crt/stdio/mingw_printf.c
@@ -50,7 +50,9 @@ int __cdecl __printf(const APICHAR *fmt, ...)
 {
   register int retval;
   va_list argv; va_start( argv, fmt );
+  _lock_file( stdout );
   retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv 
);
+  _unlock_file( stdout );
   va_end( argv );
   return retval;
 }
diff --git a/mingw-w64-crt/stdio/mingw_vfprintf.c 
b/mingw-w64-crt/stdio/mingw_vfprintf.c
index 68a0008..01ad01b 100644
--- a/mingw-w64-crt/stdio/mingw_vfprintf.c
+++ b/mingw-w64-crt/stdio/mingw_vfprintf.c
@@ -48,5 +48,11 @@ int __cdecl __vfprintf (FILE *, const APICHAR *, va_list) 
__MINGW_NOTHROW;
 
 int __cdecl __vfprintf(FILE *stream, const APICHAR *fmt, va_list argv)
 {
-  return __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv );
+  register int retval;
+
+  _lock_file( stream );
+  retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv 
);
+  _unlock_file( stream );
+
+  return retval;
 }
diff --git a/mingw-w64-crt/stdio/mingw_vprintf.c 
b/mingw-w64-crt/stdio/mingw_vprintf.c
index c60431a..4098d49 100644
--- a/mingw-w64-crt/stdio/mingw_vprintf.c
+++ b/mingw-w64-crt/stdio/mingw_vprintf.c
@@ -48,5 +48,11 @@ int __cdecl __vprintf (const APICHAR *, va_list) 
__MINGW_NOTHROW;
 
 int __cdecl __vprintf(const APICHAR *fmt, va_list argv)
 {
-  return __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv );
+  register int retval;
+
+  _lock_file( stdout );
+  retval = __pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv 
);
+  _unlock_file( stdout );
+
+  return retval;
 }
#define __USE_MINGW_ANSI_STDIO 1

#include <stdio.h>
#include <process.h>
#include <windows.h>
#include <sys/timeb.h>

#define ITERATIONS 100

int nIterations = ITERATIONS;

void Thread_printf( void* str )
{
    int i;
    char buf[ 88 ];

    Sleep( 100 );

    for( i = 0; i < nIterations; ++i )
    {
        printf( "%d: %s %s %s %s %s %s %s\n", i, (char*)str, (char*)str, 
(char*)str, (char*)str, (char*)str, (char*)str, (char*)str );
        sprintf( buf, "%d= %s %s %s %s %s %s %s", i, (char*)str, (char*)str, 
(char*)str, (char*)str, (char*)str, (char*)str, (char*)str );
        puts( buf );
    }
}

#define THREADS 8
#define MAX_THREADS 512

int nThreads = THREADS;

/*
  If we run this app without args, it will create 8 threads and each thread 
make 100 iterations of printf function.
  We can run this test.exe [nIterations] [nThreads] for more iterations/threads.
  For speed test we can run
  test.exe 100000 64 >outFile.txt
  Result should be (on screen or in file) with each line clean (not mixed).
  On my i5 3450S I can create only up to 64 threads.
*/

int main( int argc, char* argv[] )
{
    HANDLE h[ MAX_THREADS ];
    char buf[ MAX_THREADS ][12];
    int i;
    struct timeb tb;
    __int64 startTime, endTime;

    ftime( &tb );
    startTime = (__int64)tb.time * 1000 + tb.millitm; 

    if( argc > 1 )
        nIterations = atoi( argv[ 1 ] );
    if( nIterations < 1 )
        nIterations = ITERATIONS;

    if( argc > 2 )
        nThreads = atoi( argv[ 2 ] );
    if( nThreads > MAX_THREADS )
        nThreads = MAX_THREADS;
    else if( nThreads < 1 )
        nThreads = 1;

    for( i = 0; i < nThreads; i++ )
        sprintf( buf[ i ], "Thread_%d", i );

    for( i = 0; i < nThreads; i++ )
        h[ i ] = (HANDLE)_beginthread( &Thread_printf, 0, buf[ i ] );

    WaitForMultipleObjects( nThreads, h, TRUE, INFINITE );

    ftime( &tb );
    endTime = (__int64)tb.time * 1000 + tb.millitm;
    
    endTime -= startTime;
    fprintf( stderr, "nIterations = %d, nThreads = %d, Time: %0.2f s\n", 
nIterations, nThreads, (double)endTime / 1000.0 ); 

    return 0;
}
------------------------------------------------------------------------------
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to