Skip to content

Commit 85fed9e

Browse files
committed
Fix ConsoleReader Threading
also fix for CI issues
1 parent 2bfd641 commit 85fed9e

File tree

3 files changed

+161
-18
lines changed

3 files changed

+161
-18
lines changed

sources/Core/Core/SilkMarshal.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public static ref readonly byte StringToNative(ReadOnlySpan<char> str, nint char
120120
var utf16 = new byte[(str.Length + 1) * 2];
121121
MemoryMarshal
122122
.CreateReadOnlySpan(ref Unsafe.AsRef(in str[0]), str.Length + 1)
123-
.CopyTo(MemoryMarshal.Cast<byte, char>(utf16));
123+
.CopyTo(MemoryMarshal.Cast<byte, char>(utf16.AsSpan()));
124124
return utf16;
125125
}
126126
case 4:
@@ -170,7 +170,7 @@ public static ref readonly byte StringToNative(ReadOnlySpan<char> str, nint char
170170
public static byte[]? StringArrayToArray(ReadOnlySpan<string?> strs, nint charSize = 1)
171171
{
172172
var ret = new byte[strs.Length * sizeof(nint)];
173-
var span = MemoryMarshal.Cast<byte, nint>(ret);
173+
var span = MemoryMarshal.Cast<byte, nint>(ret.AsSpan());
174174
for (var i = 0; i < strs.Length; i++)
175175
{
176176
var native = StringToArray(strs[i], charSize);
@@ -220,7 +220,7 @@ public static ref byte StringArrayToNative(ReadOnlySpan<string?> strs, nint char
220220
public static ref byte StringArrayToNative(ReadOnlySpan<string?[]> strs, nint charSize = 1)
221221
{
222222
var ret = new byte[strs.Length * sizeof(nint)];
223-
var span = MemoryMarshal.Cast<byte, nint>(ret);
223+
var span = MemoryMarshal.Cast<byte, nint>(ret.AsSpan());
224224
for (var i = 0; i < strs.Length; i++)
225225
{
226226
ref var native = ref StringArrayToNative(strs[i], charSize);
@@ -241,7 +241,7 @@ public static ref byte StringArrayToNative(ReadOnlySpan<string?[]> strs, nint ch
241241
public static ref byte StringArrayToNative(ReadOnlySpan<string[][]> strs, nint charSize = 1)
242242
{
243243
var ret = new byte[strs.Length * sizeof(nint)];
244-
var span = MemoryMarshal.Cast<byte, nint>(ret);
244+
var span = MemoryMarshal.Cast<byte, nint>(ret.AsSpan());
245245
for (var i = 0; i < strs.Length; i++)
246246
{
247247
ref var native = ref StringArrayToNative(strs[i], charSize);
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using ClangSharp;
10+
11+
namespace Silk.NET.SilkTouch.Logging
12+
{
13+
internal class ConcurrentStringWriter : StringWriter
14+
{
15+
private readonly object _lockObject = new object();
16+
17+
public ConcurrentStringWriter()
18+
{
19+
}
20+
21+
public ConcurrentStringWriter(IFormatProvider? formatProvider) : base(formatProvider)
22+
{
23+
}
24+
25+
public ConcurrentStringWriter(StringBuilder sb) : base(sb)
26+
{
27+
}
28+
29+
public ConcurrentStringWriter(StringBuilder sb, IFormatProvider? formatProvider) : base(sb, formatProvider)
30+
{
31+
}
32+
33+
// Writes a character to the underlying string buffer.
34+
//
35+
public override void Write(char value)
36+
{
37+
lock (_lockObject)
38+
{
39+
base.Write(value);
40+
}
41+
}
42+
43+
// Writes a range of a character array to the underlying string buffer.
44+
// This method will write count characters of data into this
45+
// StringWriter from the buffer character array starting at position
46+
// index.
47+
//
48+
public override void Write(char[] buffer, int index, int count)
49+
{
50+
lock (_lockObject)
51+
{
52+
base.Write(buffer, index, count);
53+
}
54+
}
55+
56+
public override void Write(ReadOnlySpan<char> buffer)
57+
{
58+
lock (_lockObject)
59+
{
60+
base.Write(buffer);
61+
}
62+
}
63+
64+
// Writes a string to the underlying string buffer. If the given string is
65+
// null, nothing is written.
66+
//
67+
public override void Write(string? value)
68+
{
69+
lock (_lockObject)
70+
{
71+
base.Write(value);
72+
}
73+
}
74+
75+
public override void Write(StringBuilder? value)
76+
{
77+
lock (_lockObject)
78+
{
79+
base.Write(value);
80+
}
81+
}
82+
83+
public override void WriteLine(ReadOnlySpan<char> buffer)
84+
{
85+
lock (_lockObject)
86+
{
87+
base.WriteLine(buffer);
88+
}
89+
}
90+
91+
public override void WriteLine(StringBuilder? value)
92+
{
93+
lock (_lockObject)
94+
{
95+
base.WriteLine(value);
96+
}
97+
}
98+
99+
public override Task WriteAsync(StringBuilder? value, CancellationToken cancellationToken = default)
100+
{
101+
if (cancellationToken.IsCancellationRequested)
102+
{
103+
return Task.FromCanceled(cancellationToken);
104+
}
105+
106+
lock (_lockObject)
107+
{
108+
base.Write(value);
109+
}
110+
111+
return Task.CompletedTask;
112+
}
113+
114+
public override Task WriteLineAsync(StringBuilder? value, CancellationToken cancellationToken = default)
115+
{
116+
if (cancellationToken.IsCancellationRequested)
117+
{
118+
return Task.FromCanceled(cancellationToken);
119+
}
120+
121+
lock (_lockObject)
122+
{
123+
base.WriteLine(value);
124+
}
125+
return Task.CompletedTask;
126+
}
127+
128+
public override Task WriteLineAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken = default)
129+
{
130+
if (cancellationToken.IsCancellationRequested)
131+
{
132+
return Task.FromCanceled(cancellationToken);
133+
}
134+
135+
WriteLine(buffer.Span);
136+
return Task.CompletedTask;
137+
}
138+
139+
public string FlushText()
140+
{
141+
string val = string.Empty;
142+
lock (_lockObject)
143+
{
144+
StringBuilder builder = GetStringBuilder();
145+
val = builder.ToString();
146+
builder.Clear();
147+
}
148+
return val;
149+
}
150+
}
151+
}

sources/SilkTouch/SilkTouch/Logging/ConsoleRenderer.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class ConsoleRenderer
1616
{
1717
private readonly IProgressService _progressService;
1818
private readonly TextWriter _originalOut;
19-
private readonly StringWriter _consoleOutput;
19+
private readonly ConcurrentStringWriter _consoleOutput;
2020
private readonly Timer _timer;
2121
private bool _isRunning = true;
2222
private int _progressBarCount;
@@ -30,7 +30,7 @@ public ConsoleRenderer(IProgressService progressService)
3030
{
3131
_progressService = progressService;
3232
_originalOut = Console.Out;
33-
_consoleOutput = new StringWriter();
33+
_consoleOutput = new ConcurrentStringWriter();
3434
Console.SetOut(_consoleOutput); // Redirect console output
3535

3636
_timer = new Timer(Render, null, 0, 500);
@@ -47,12 +47,8 @@ public void Stop()
4747
ClearProgressBars();
4848

4949
//Write out one fineal time before restoring output
50-
var output = _consoleOutput.GetStringBuilder().ToString();
51-
if (!string.IsNullOrWhiteSpace(output))
52-
{
53-
_originalOut.Write(output);
54-
_consoleOutput.GetStringBuilder().Clear();
55-
}
50+
var output = _consoleOutput.FlushText();
51+
_originalOut.Write(output);
5652

5753
Console.SetOut(_originalOut); // Restore original output
5854
}
@@ -70,12 +66,8 @@ private void Render(object? state)
7066
_progressBarCount = progressDictionary.Count();
7167

7268
// Write all console output captured since the last render
73-
var output = _consoleOutput.GetStringBuilder().ToString();
74-
if (!string.IsNullOrWhiteSpace(output))
75-
{
76-
_originalOut.Write(output);
77-
_consoleOutput.GetStringBuilder().Clear();
78-
}
69+
var output = _consoleOutput.FlushText();
70+
_originalOut.Write(output);
7971

8072
foreach (var kvp in progressDictionary)
8173
{

0 commit comments

Comments
 (0)