| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- 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
- );
- }
-
- }
- }
|