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