mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-30 08:01:02 +00:00
Win32: Fix deadlocks if Sys_Printf() or Sys_Error() was called in thread
If those functions (e.g. called by common->Printf(), common->Error()) weren't called from the mainthread and win_outputEditString was set to 1, a deadlock could occur. Specifically, the async thread (handling sound) was calling common->Warning() -> Sys_Printf() -> Conbuf_AppendText() which called SendMessageA() which blocks until the main thread handles the message. The main thread however was in idSampleDecoderLocal::Decode() trying to enter CRITICAL_SECTION_ONE, which was held by the async thread (it's used to synchronize sound handling between main and async thread). So now if Sys_Printf() (or Sys_Error() which should have the same problem) is not called by the main thread, the text is buffered and Conbuf_AppendText() is called for the buffered lines in the next frame in Win_Frame().
This commit is contained in:
parent
a523c28c18
commit
d5fd0990a1
1 changed files with 62 additions and 4 deletions
|
@ -113,6 +113,9 @@ PWGLSWAPLAYERBUFFERS qwglSwapLayerBuffers;
|
||||||
|
|
||||||
#endif /* End stuff required for tools */
|
#endif /* End stuff required for tools */
|
||||||
|
|
||||||
|
static bool hadError = false;
|
||||||
|
static char errorText[4096];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
Sys_Error
|
Sys_Error
|
||||||
|
@ -125,11 +128,28 @@ void Sys_Error( const char *error, ... ) {
|
||||||
char text[4096];
|
char text[4096];
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
|
||||||
|
if ( !Sys_IsMainThread() ) {
|
||||||
|
// to avoid deadlocks we mustn't call Conbuf_AppendText() etc if not in main thread!
|
||||||
|
va_start(argptr, error);
|
||||||
|
vsprintf(errorText, error, argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
|
||||||
|
printf("%s", errorText);
|
||||||
|
OutputDebugString( errorText );
|
||||||
|
|
||||||
|
hadError = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
va_start( argptr, error );
|
va_start( argptr, error );
|
||||||
vsprintf( text, error, argptr );
|
vsprintf( text, error, argptr );
|
||||||
va_end( argptr);
|
va_end( argptr);
|
||||||
|
|
||||||
printf("%s", text);
|
if ( !hadError ) {
|
||||||
|
// if we had an error in another thread, printf() and OutputDebugString() has already been called for this
|
||||||
|
printf( "%s", text );
|
||||||
|
OutputDebugString( text );
|
||||||
|
}
|
||||||
|
|
||||||
Conbuf_AppendText( text );
|
Conbuf_AppendText( text );
|
||||||
Conbuf_AppendText( "\n" );
|
Conbuf_AppendText( "\n" );
|
||||||
|
@ -183,13 +203,22 @@ void Sys_Quit( void ) {
|
||||||
Sys_Printf
|
Sys_Printf
|
||||||
==============
|
==============
|
||||||
*/
|
*/
|
||||||
#define MAXPRINTMSG 4096
|
|
||||||
|
enum {
|
||||||
|
MAXPRINTMSG = 4096,
|
||||||
|
MAXNUMBUFFEREDLINES = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
static char bufferedPrintfLines[MAXNUMBUFFEREDLINES][MAXPRINTMSG];
|
||||||
|
static int curNumBufferedPrintfLines = 0;
|
||||||
|
static CRITICAL_SECTION printfCritSect;
|
||||||
|
|
||||||
void Sys_Printf( const char *fmt, ... ) {
|
void Sys_Printf( const char *fmt, ... ) {
|
||||||
char msg[MAXPRINTMSG];
|
char msg[MAXPRINTMSG];
|
||||||
|
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
va_start(argptr, fmt);
|
va_start(argptr, fmt);
|
||||||
idStr::vsnPrintf( msg, MAXPRINTMSG-1, fmt, argptr );
|
int len = idStr::vsnPrintf( msg, MAXPRINTMSG-1, fmt, argptr );
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
msg[sizeof(msg)-1] = '\0';
|
msg[sizeof(msg)-1] = '\0';
|
||||||
|
|
||||||
|
@ -199,7 +228,18 @@ void Sys_Printf( const char *fmt, ... ) {
|
||||||
OutputDebugString( msg );
|
OutputDebugString( msg );
|
||||||
}
|
}
|
||||||
if ( win32.win_outputEditString.GetBool() ) {
|
if ( win32.win_outputEditString.GetBool() ) {
|
||||||
Conbuf_AppendText( msg );
|
if ( Sys_IsMainThread() ) {
|
||||||
|
Conbuf_AppendText( msg );
|
||||||
|
} else {
|
||||||
|
EnterCriticalSection( &printfCritSect );
|
||||||
|
int idx = curNumBufferedPrintfLines++;
|
||||||
|
if ( idx < MAXNUMBUFFEREDLINES ) {
|
||||||
|
if ( len >= MAXPRINTMSG )
|
||||||
|
len = MAXPRINTMSG - 1;
|
||||||
|
memcpy( bufferedPrintfLines[idx], msg, len + 1 );
|
||||||
|
}
|
||||||
|
LeaveCriticalSection( &printfCritSect );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,6 +787,22 @@ void Win_Frame( void ) {
|
||||||
}
|
}
|
||||||
win32.win_viewlog.ClearModified();
|
win32.win_viewlog.ClearModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( curNumBufferedPrintfLines > 0 ) {
|
||||||
|
// if Sys_Printf() had been called in another thread, add those lines to the windows console now
|
||||||
|
EnterCriticalSection( &printfCritSect );
|
||||||
|
int n = Min( curNumBufferedPrintfLines, (int)MAXNUMBUFFEREDLINES );
|
||||||
|
for ( int i = 0; i < n; ++i ) {
|
||||||
|
Conbuf_AppendText( bufferedPrintfLines[i] );
|
||||||
|
}
|
||||||
|
curNumBufferedPrintfLines = 0;
|
||||||
|
LeaveCriticalSection( &printfCritSect );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( hadError ) {
|
||||||
|
// if Sys_Error() had been called in another thread, handle it now
|
||||||
|
Sys_Error( "%s", errorText );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the MFC tools use Win_GetWindowScalingFactor() for High-DPI support
|
// the MFC tools use Win_GetWindowScalingFactor() for High-DPI support
|
||||||
|
@ -921,6 +977,8 @@ WinMain
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
const HCURSOR hcurSave = ::SetCursor( LoadCursor( 0, IDC_WAIT ) );
|
const HCURSOR hcurSave = ::SetCursor( LoadCursor( 0, IDC_WAIT ) );
|
||||||
|
|
||||||
|
InitializeCriticalSection( &printfCritSect );
|
||||||
|
|
||||||
#ifdef ID_DEDICATED
|
#ifdef ID_DEDICATED
|
||||||
MSG msg;
|
MSG msg;
|
||||||
#else
|
#else
|
||||||
|
|
Loading…
Reference in a new issue