fix thread problems in log window (should address #2694 but I'm not calling it closed because maybe someone will jettison this log type completely)

note: in principle
1. _lines and the VirtualListSize are meant to be updated atomically
2. these can be written to from a different thread while the gui thread reads them
this necessitates a high degree of caution around how those variables are accessed, which is made complicated because VirtualListSize isn't a variable but rather done as a win32 call on the gui thread only
This commit is contained in:
zeromus 2021-05-09 14:52:50 -04:00
parent f67de7a23b
commit a886a9b12a
1 changed files with 47 additions and 16 deletions

View File

@ -47,7 +47,7 @@ namespace BizHawk.Client.EmuHawk
_logStream = new LogStream(); _logStream = new LogStream();
Log.HACK_LOG_STREAM = _logStream; Log.HACK_LOG_STREAM = _logStream;
Console.SetOut(new StreamWriter(_logStream) { AutoFlush = true }); Console.SetOut(new StreamWriter(_logStream) { AutoFlush = true });
_logStream.Emit = Append; _logStream.Emit = appendInvoked;
} }
private void Detach() private void Detach()
@ -64,6 +64,8 @@ namespace BizHawk.Client.EmuHawk
public void ShowReport(string title, string report) public void ShowReport(string title, string report)
{ {
var ss = report.Split('\n'); var ss = report.Split('\n');
lock (_lines)
foreach (var s in ss) foreach (var s in ss)
{ {
_lines.Add(s.TrimEnd('\r')); _lines.Add(s.TrimEnd('\r'));
@ -75,25 +77,52 @@ namespace BizHawk.Client.EmuHawk
btnClear.Visible = false; btnClear.Visible = false;
} }
public void Append(string str) private void append(string str, bool invoked)
{ {
var ss = str.Split('\n'); var ss = str.Split('\n');
foreach (var s in ss) foreach (var s in ss)
{ {
if (!string.IsNullOrWhiteSpace(s)) if (!string.IsNullOrWhiteSpace(s))
{ {
if (invoked)
Invoke((Action<string>)doAppendInvoked,s);
else
lock (_lines)
_lines.Add(s.TrimEnd('\r')); _lines.Add(s.TrimEnd('\r'));
virtualListView1.VirtualListSize++;
} }
} }
} }
private void doAppendInvoked(string value)
{
//note that we take precautions to update _lines and VirtualListSize together here
//the lock happens here and not outside the invoke because we want only one thread to be locking (that's the gui thread)
lock (_lines)
{
_lines.Add(value.TrimEnd('\r'));
virtualListView1.VirtualListSize = _lines.Count;
}
}
private void appendInvoked(string str)
{
append(str, true);
}
public void Append(string str)
{
append(str, false);
}
private void BtnClear_Click(object sender, EventArgs e) private void BtnClear_Click(object sender, EventArgs e)
{
lock (_lines)
{ {
_lines.Clear(); _lines.Clear();
virtualListView1.VirtualListSize = 0; virtualListView1.VirtualListSize = 0;
virtualListView1.SelectedIndices.Clear(); virtualListView1.SelectedIndices.Clear();
} }
}
private void BtnClose_Click(object sender, EventArgs e) private void BtnClose_Click(object sender, EventArgs e)
{ {
@ -126,6 +155,7 @@ namespace BizHawk.Client.EmuHawk
private void ButtonCopy_Click(object sender, EventArgs e) private void ButtonCopy_Click(object sender, EventArgs e)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
lock(_lines)
foreach (int i in virtualListView1.SelectedIndices) foreach (int i in virtualListView1.SelectedIndices)
sb.AppendLine(_lines[i]); sb.AppendLine(_lines[i]);
if (sb.Length > 0) if (sb.Length > 0)
@ -135,6 +165,7 @@ namespace BizHawk.Client.EmuHawk
private void ButtonCopyAll_Click(object sender, EventArgs e) private void ButtonCopyAll_Click(object sender, EventArgs e)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
lock(_lines)
foreach (var s in _lines) foreach (var s in _lines)
sb.AppendLine(s); sb.AppendLine(s);
if (sb.Length > 0) if (sb.Length > 0)
@ -200,7 +231,7 @@ namespace BizHawk.Client.EmuHawk
// TODO - buffer undecoded characters (this may be important) // TODO - buffer undecoded characters (this may be important)
//(use decoder = System.Text.Encoding.Unicode.GetDecoder()) //(use decoder = System.Text.Encoding.Unicode.GetDecoder())
string str = Encoding.ASCII.GetString(buffer, offset, count); string str = Encoding.ASCII.GetString(buffer, offset, count);
Emit?.Invoke(str); Emit(str);
} }
public Action<string> Emit; public Action<string> Emit;