Browse Source

Merge fcf1e90bf6 into 3068850405

pull/19426/merge
Brycen G 23 hours ago
committed by GitHub
parent
commit
690f4be20c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 120
      src/Avalonia.X11/Dispatching/X11PlatformThreading.cs

120
src/Avalonia.X11/Dispatching/X11PlatformThreading.cs

@ -1,9 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Platform;
using Avalonia.Threading;
using Avalonia.X11.Dispatching;
using static Avalonia.X11.XLib;
@ -15,59 +13,59 @@ namespace Avalonia.X11
private readonly AvaloniaX11Platform _platform;
private Thread _mainThread = Thread.CurrentThread;
[StructLayout(LayoutKind.Explicit)]
private struct epoll_data
[StructLayout(LayoutKind.Sequential)]
public struct fd_set
{
[FieldOffset(0)]
public IntPtr ptr;
[FieldOffset(0)]
public int fd;
[FieldOffset(0)]
public uint u32;
[FieldOffset(0)]
public ulong u64;
public const int FD_SETSIZE = 1024;
public fixed uint fds[FD_SETSIZE / 32];
public void Set(int fd)
{
var idx = fd / 32;
if (idx >= FD_SETSIZE / 32)
throw new ArgumentOutOfRangeException(nameof(fd));
var bit = fd % 32;
fds[idx] |= 1u << bit;
}
}
private const int EPOLLIN = 1;
private const int EPOLL_CTL_ADD = 1;
private const int O_NONBLOCK = 2048;
[StructLayout(LayoutKind.Sequential)]
private struct epoll_event
public struct timeval
{
public uint events;
public epoll_data data;
public int tv_sec;
public int tv_usec;
public timeval(int milliseconds)
{
tv_sec = milliseconds / 1000;
tv_usec = (milliseconds % 1000) * 1000;
}
}
[DllImport("libc")]
private extern static int epoll_create1(int size);
[DllImport("libc")]
private extern static int epoll_ctl(int epfd, int op, int fd, ref epoll_event __event);
private const int O_NONBLOCK = 2048;
[DllImport("libc")]
private extern static int epoll_wait(int epfd, epoll_event* events, int maxevents, int timeout);
[DllImport("libc", EntryPoint = "select")]
private static extern int select(
int nfds,
ref fd_set readfds,
ref fd_set writefds,
ref fd_set exceptfds,
timeval* timeout);
[DllImport("libc")]
private extern static int pipe2(int* fds, int flags);
[DllImport("libc")]
private extern static IntPtr write(int fd, void* buf, IntPtr count);
[DllImport("libc")]
private extern static IntPtr read(int fd, void* buf, IntPtr count);
private enum EventCodes
{
X11 = 1,
Signal =2
}
private int _sigread, _sigwrite;
private readonly int _sigread, _sigwrite, _x11Fd;
private object _lock = new object();
private bool _signaled;
private bool _wakeupRequested;
private long? _nextTimer;
private int _epoll;
private Stopwatch _clock = Stopwatch.StartNew();
private readonly X11EventDispatcher _x11Events;
@ -75,30 +73,12 @@ namespace Avalonia.X11
{
_platform = platform;
_x11Events = new X11EventDispatcher(platform);
var ev = new epoll_event()
{
events = EPOLLIN,
data = {u32 = (int)EventCodes.X11}
};
_epoll = epoll_create1(0);
if (_epoll == -1)
throw new X11Exception("epoll_create1 failed");
if (epoll_ctl(_epoll, EPOLL_CTL_ADD, _x11Events.Fd, ref ev) == -1)
throw new X11Exception("Unable to attach X11 connection handle to epoll");
_x11Fd = XConnectionNumber(platform.Display);
var fds = stackalloc int[2];
pipe2(fds, O_NONBLOCK);
_sigread = fds[0];
_sigwrite = fds[1];
ev = new epoll_event
{
events = EPOLLIN,
data = {u32 = (int)EventCodes.Signal}
};
if (epoll_ctl(_epoll, EPOLL_CTL_ADD, _sigread, ref ev) == -1)
throw new X11Exception("Unable to attach signal pipe to epoll");
}
private void CheckSignaled()
@ -112,7 +92,6 @@ namespace Avalonia.X11
Signaled?.Invoke();
}
public void RunLoop(CancellationToken cancellationToken)
{
@ -126,20 +105,27 @@ namespace Avalonia.X11
if (cancellationToken.IsCancellationRequested)
return;
//Flush whatever requests were made to XServer
_x11Events.Flush();
epoll_event ev;
if (!_x11Events.IsPending)
{
now = _clock.ElapsedMilliseconds;
if (_nextTimer < now)
continue;
var timeout = _nextTimer == null ? (int)-1 : Math.Max(1, _nextTimer.Value - now);
epoll_wait(_epoll, &ev, 1, (int)Math.Min(int.MaxValue, timeout));
// Drain the signaled pipe
fd_set readFds = default, writeFds = default, exceptFds = default;
readFds.Set(_x11Fd);
readFds.Set(_sigread);
var timeoutMs = _nextTimer == null ? (int?)null : Math.Max(1, (int)(_nextTimer.Value - now));
var timeout = timeoutMs.HasValue ? new timeval(timeoutMs.Value) : default;
select(Math.Max(_x11Fd, _sigread) + 1,
ref readFds,
ref writeFds,
ref exceptFds,
timeoutMs.HasValue ? &timeout : null);
int buf = 0;
while (read(_sigread, &buf, new IntPtr(4)).ToInt64() > 0)
{
@ -151,6 +137,7 @@ namespace Avalonia.X11
if (cancellationToken.IsCancellationRequested)
return;
CheckSignaled();
_x11Events.DispatchX11Events(cancellationToken);
while (_platform.EventGrouperDispatchQueue.HasJobs)
@ -165,7 +152,7 @@ namespace Avalonia.X11
{
lock (_lock)
{
if(_wakeupRequested)
if (_wakeupRequested)
return;
_wakeupRequested = true;
int buf = 0;
@ -177,7 +164,7 @@ namespace Avalonia.X11
{
lock (_lock)
{
if(_signaled)
if (_signaled)
return;
_signaled = true;
Wakeup();
@ -185,7 +172,7 @@ namespace Avalonia.X11
}
public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _mainThread;
public event Action? Signaled;
public event Action? Timer;
@ -196,7 +183,6 @@ namespace Avalonia.X11
Wakeup();
}
public long Now => _clock.ElapsedMilliseconds;
public bool CanQueryPendingInput => true;

Loading…
Cancel
Save