1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-10 01:50:53 +09:00

Replace custom synchronized text writer (dotnet/corefx#30796)

TextWriter.Synchronized does this and isn't missing APIs, which can cause derived methods to not be called. Test added.

Commit migrated from 0b868a47b4
This commit is contained in:
Jeremy Kuhne 2018-07-03 20:36:54 -07:00 committed by Stephen Toub
parent 4d3212d7c3
commit 1052b59792
5 changed files with 30 additions and 394 deletions

View file

@ -13,39 +13,6 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextReader.#ReadToEnd():System.String")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextReader.#ReadKey(System.Boolean&):System.ConsoleKeyInfo")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextReader.#get_KeyAvailable():System.Boolean")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#get_NewLine():System.String")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#set_NewLine(System.String)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Dispose(System.Boolean)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Flush()")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Char)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Char[])")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Char[],System.Int32,System.Int32)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Boolean)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Int32)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.UInt32)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Int64)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.UInt64)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Single)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Double)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Decimal)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.String)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.Object)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#Write(System.String,System.Object[])")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine()")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Char)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Char[])")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Char[],System.Int32,System.Int32)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Boolean)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Int32)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.UInt32)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Int64)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.UInt64)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Single)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Double)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Decimal)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.String)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.Object)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextWriter.#WriteLine(System.String,System.Object[])")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ConsolePal.#ResetColor()")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ConsolePal.#GetCursorPosition(System.Int32&,System.Int32&)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ConsolePal.#RefreshColors(System.ConsoleColor&,System.ConsoleColor)")]

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
@ -26,7 +26,6 @@
<Compile Include="System\ConsoleModifiers.cs" />
<Compile Include="System\IO\ConsoleStream.cs" />
<Compile Include="System\IO\SyncTextReader.cs" />
<Compile Include="System\IO\SyncTextWriter.cs" />
<Compile Include="System\IO\Error.cs" />
<Compile Include="$(CommonPath)\System\Text\ConsoleEncoding.cs">
<Link>Common\System\Text\ConsoleEncoding.cs</Link>

View file

@ -115,7 +115,7 @@ namespace System
private static TextWriter CreateOutputWriter(Stream outputStream)
{
return SyncTextWriter.GetSynchronizedTextWriter(outputStream == Stream.Null ?
return TextWriter.Synchronized(outputStream == Stream.Null ?
StreamWriter.Null :
new StreamWriter(
stream: outputStream,
@ -408,7 +408,7 @@ namespace System
public static void SetOut(TextWriter newOut)
{
CheckNonNull(newOut, nameof(newOut));
newOut = SyncTextWriter.GetSynchronizedTextWriter(newOut);
newOut = TextWriter.Synchronized(newOut);
Volatile.Write(ref s_isOutTextWriterRedirected, true);
lock (InternalSyncObject)
@ -420,7 +420,7 @@ namespace System
public static void SetError(TextWriter newError)
{
CheckNonNull(newError, nameof(newError));
newError = SyncTextWriter.GetSynchronizedTextWriter(newError);
newError = TextWriter.Synchronized(newError);
Volatile.Write(ref s_isErrorTextWriterRedirected, true);
lock (InternalSyncObject)

View file

@ -1,346 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
namespace System.IO
{
/* SyncTextWriter intentionally locks on itself rather than a private lock object.
* This is done to synchronize different console writers.
* For example - colored console writers can be synchronized with non-colored
* writers by locking on Console.On (Issue#2855).
*/
internal sealed class SyncTextWriter : TextWriter, IDisposable
{
internal readonly TextWriter _out;
internal static SyncTextWriter GetSynchronizedTextWriter(TextWriter writer)
{
Debug.Assert(writer != null);
return writer as SyncTextWriter ??
new SyncTextWriter(writer);
}
internal SyncTextWriter(TextWriter t)
: base(t.FormatProvider)
{
_out = t;
}
public override Encoding Encoding
{
get { return _out.Encoding; }
}
public override IFormatProvider FormatProvider
{
get { return _out.FormatProvider; }
}
public override string NewLine
{
get { lock (this) { return _out.NewLine; } }
set { lock (this) { _out.NewLine = value; } }
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
lock (this)
{
_out.Dispose();
}
}
}
public override void Flush()
{
lock (this)
{
_out.Flush();
}
}
public override void Write(char value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(char[] buffer)
{
lock (this)
{
_out.Write(buffer);
}
}
public override void Write(char[] buffer, int index, int count)
{
lock (this)
{
_out.Write(buffer, index, count);
}
}
public override void Write(bool value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(int value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(uint value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(long value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(ulong value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(float value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(double value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(decimal value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(string value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(object value)
{
lock (this)
{
_out.Write(value);
}
}
public override void Write(string format, object[] arg)
{
lock (this)
{
_out.Write(format, arg);
}
}
public override void WriteLine()
{
lock (this)
{
_out.WriteLine();
}
}
public override void WriteLine(char value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(decimal value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(char[] buffer)
{
lock (this)
{
_out.WriteLine(buffer);
}
}
public override void WriteLine(char[] buffer, int index, int count)
{
lock (this)
{
_out.WriteLine(buffer, index, count);
}
}
public override void WriteLine(bool value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(int value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(uint value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(long value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(ulong value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(float value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(double value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(string value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(object value)
{
lock (this)
{
_out.WriteLine(value);
}
}
public override void WriteLine(string format, object[] arg)
{
lock (this)
{
_out.WriteLine(format, arg);
}
}
//
// On SyncTextWriter all APIs should run synchronously, even the async ones.
//
public override Task WriteAsync(char value)
{
Write(value);
return Task.CompletedTask;
}
public override Task WriteAsync(string value)
{
Write(value);
return Task.CompletedTask;
}
public override Task WriteAsync(char[] buffer, int index, int count)
{
Write(buffer, index, count);
return Task.CompletedTask;
}
public override Task WriteLineAsync(char value)
{
WriteLine(value);
return Task.CompletedTask;
}
public override Task WriteLineAsync(string value)
{
WriteLine(value);
return Task.CompletedTask;
}
public override Task WriteLineAsync(char[] buffer, int index, int count)
{
WriteLine(buffer, index, count);
return Task.CompletedTask;
}
public override Task FlushAsync()
{
Flush();
return Task.CompletedTask;
}
}
}

View file

@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
@ -11,7 +13,6 @@ using Xunit;
public class SyncTextWriter
{
[Fact]
public void SyncTextWriterLockedOnThis()
{
@ -22,14 +23,16 @@ public class SyncTextWriter
Console.SetOut(newWriter);
TextWriter syncWriter = Console.Out;
bool called = false;
newWriter.Callback = _ =>
newWriter.Callback = () =>
{
Assert.True(Monitor.IsEntered(syncWriter));
called = true;
};
Console.Write("c");
Assert.True(called);
Assert.True(newWriter.WriteCharCalled);
Console.Write("{0}", 32);
Assert.True(newWriter.WriteFormatCalled);
}
finally
{
@ -39,11 +42,24 @@ public class SyncTextWriter
private sealed class CallbackTextWriter : TextWriter
{
internal Action<char> Callback;
internal Action Callback;
public bool WriteCharCalled;
public bool WriteFormatCalled;
public override Encoding Encoding { get { return Encoding.UTF8; } }
public override void Write(char value) { Callback(value); }
public override void Write(char value)
{
WriteCharCalled = true;
Callback();
}
public override void Write(string format, object arg0)
{
WriteFormatCalled = true;
Callback();
}
}
}