aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs')
-rw-r--r--src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs b/src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs
new file mode 100644
index 00000000..b1ed7b68
--- /dev/null
+++ b/src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs
@@ -0,0 +1,109 @@
+using Microsoft.Win32.SafeHandles;
+using Ryujinx.Common.Logging;
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Ryujinx.Common.SystemInterop
+{
+ public partial class StdErrAdapter : IDisposable
+ {
+ private bool _disposable = false;
+ private Stream _pipeReader;
+ private Stream _pipeWriter;
+ private CancellationTokenSource _cancellationTokenSource;
+ private Task _worker;
+
+ public StdErrAdapter()
+ {
+ if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+ {
+ RegisterPosix();
+ }
+ }
+
+ [SupportedOSPlatform("linux")]
+ [SupportedOSPlatform("macos")]
+ private void RegisterPosix()
+ {
+ const int stdErrFileno = 2;
+
+ (int readFd, int writeFd) = MakePipe();
+ dup2(writeFd, stdErrFileno);
+
+ _pipeReader = CreateFileDescriptorStream(readFd);
+ _pipeWriter = CreateFileDescriptorStream(writeFd);
+
+ _cancellationTokenSource = new CancellationTokenSource();
+ _worker = Task.Run(async () => await EventWorkerAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
+ _disposable = true;
+ }
+
+ [SupportedOSPlatform("linux")]
+ [SupportedOSPlatform("macos")]
+ private async Task EventWorkerAsync(CancellationToken cancellationToken)
+ {
+ using TextReader reader = new StreamReader(_pipeReader, leaveOpen: true);
+ string line;
+ while (cancellationToken.IsCancellationRequested == false && (line = await reader.ReadLineAsync(cancellationToken)) != null)
+ {
+ Logger.Error?.PrintRawMsg(line);
+ }
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposable)
+ {
+ _disposable = false;
+
+ if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+ {
+ _cancellationTokenSource.Cancel();
+ _worker.Wait(0);
+ _pipeReader?.Close();
+ _pipeWriter?.Close();
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ [LibraryImport("libc", SetLastError = true)]
+ private static partial int dup2(int fd, int fd2);
+
+ [LibraryImport("libc", SetLastError = true)]
+ private static partial int pipe(Span<int> pipefd);
+
+ private static (int, int) MakePipe()
+ {
+ Span<int> pipefd = stackalloc int[2];
+
+ if (pipe(pipefd) == 0)
+ {
+ return (pipefd[0], pipefd[1]);
+ }
+ else
+ {
+ throw new();
+ }
+ }
+
+ [SupportedOSPlatform("linux")]
+ [SupportedOSPlatform("macos")]
+ private static Stream CreateFileDescriptorStream(int fd)
+ {
+ return new FileStream(
+ new SafeFileHandle((IntPtr)fd, ownsHandle: true),
+ FileAccess.ReadWrite
+ );
+ }
+
+ }
+}