• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DemoBytom / DemoEngine / 13123725757

03 Feb 2025 10:03PM UTC coverage: 10.779% (-0.8%) from 11.563%
13123725757

push

coveralls.net

DemoBytom
Fixing winforms deadlocks

an await operation must return to the thread it was spawned on, because due to using winforms the main thread must be SDA.
But because the windows messages are handled by a loop, and that loop had a async operation - the message to switch back to main thread deadlocks

227 of 2106 relevant lines covered (10.78%)

24786.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Demo.Engine.Core/Services/EngineService.cs
1
// Copyright © Michał Dembski and contributors.
2
// Distributed under MIT license. See LICENSE file in the root for more information.
3

4
using System.Numerics;
5
using Demo.Engine.Core.Components.Keyboard;
6
using Demo.Engine.Core.Interfaces;
7
using Demo.Engine.Core.Interfaces.Rendering;
8
using Demo.Engine.Core.Platform;
9
using Microsoft.Extensions.DependencyInjection;
10
using Microsoft.Extensions.Hosting;
11
using Microsoft.Extensions.Logging;
12
using Vortice.Mathematics;
13

14
namespace Demo.Engine.Core.Services;
15

16
public class EngineService : ServiceBase
17
{
18
    private bool _disposedValue;
19
    private readonly CancellationTokenSource _loopCancellationTokenSource = new();
×
20
    private readonly IServiceScopeFactory _scopeFactory;
21

22
    public EngineService(
23
        IHostApplicationLifetime applicationLifetime,
24
        ILogger<EngineService> logger,
25
        IServiceScopeFactory scopeFactory)
26
        : base("Engine",
×
27
              logger, applicationLifetime) => _scopeFactory = scopeFactory;
×
28

29
    private IServiceProvider? _sp;
30

31
    protected override async Task ExecuteAsync()
32
    {
33
        using var scope = _scopeFactory.CreateScope();
×
34
        _sp = scope.ServiceProvider;
×
35
        _drawables =
×
36
            [
×
37
                scope.ServiceProvider.GetRequiredService<ICube>(),
×
38
                //scope.ServiceProvider.GetRequiredService<ICube>()
×
39
            ];
×
40
        var mainLoop = scope.ServiceProvider.GetRequiredService<IMainLoopService>();
×
41

42
        await mainLoop.RunAsync(
×
43
            Update,
×
44
            Render,
×
45
            _loopCancellationTokenSource.Token)
×
46
            .ConfigureAwait(true);
×
47
        _sp = null;
×
48
    }
×
49

50
    private float _r, _g, _b = 0.0f;
51

52
    private float _sin = 0.0f;
53
    private bool _fullscreen = false;
54
    private bool _f11Pressed = false;
55

56
    //private bool _dontCreate = false;
57
    private ValueTask Update(
58
        IRenderingSurface renderingSurface,
59
        KeyboardHandle keyboardHandle,
60
        KeyboardCharCache keyboardCharCache)
61
    {
62
        if (keyboardHandle.GetKeyPressed(VirtualKeys.OemOpenBrackets))
×
63
        {
64
            keyboardCharCache.Clear();
×
65
        }
66
        if (keyboardHandle.GetKeyPressed(VirtualKeys.OemCloseBrackets))
×
67
        {
68
            var str = keyboardCharCache?.ReadCache();
×
69
            if (!string.IsNullOrEmpty(str))
×
70
            {
71
                _logger.LogInformation(str);
×
72
            }
73
        }
74
        if (keyboardHandle.GetKeyPressed(VirtualKeys.Escape))
×
75
        {
76
            _loopCancellationTokenSource.Cancel();
×
77
            foreach (var drawable in _drawables)
×
78
            {
79
                (drawable as IDisposable)?.Dispose();
×
80
            }
81

82
            _drawables = [];
×
83
            return ValueTask.CompletedTask;
×
84
        }
85
        if (keyboardHandle.GetKeyPressed(VirtualKeys.F11))
×
86
        {
87
            if (!_f11Pressed)
×
88
            {
89
                _fullscreen = !_fullscreen;
×
90
            }
91
            _f11Pressed = true;
×
92
        }
93
        else
94
        {
95
            _f11Pressed = false;
×
96
        }
97

98
        if (keyboardHandle.GetKeyPressed(VirtualKeys.Back)
×
99
            && _drawables.ElementAtOrDefault(0) is IDisposable d)
×
100
        {
101
            System.Diagnostics.Debug.WriteLine("Removing cube!");
102

103
            _drawables = _drawables.Length > 0
×
104
                ? _drawables[1..]
×
105
                : [];
×
106

107
            d?.Dispose();
×
108

109
            System.Diagnostics.Debug.WriteLine("Cube removed!");
110
        }
111
        if (keyboardHandle.GetKeyPressed(VirtualKeys.Enter)
×
112
            && _drawables.Length < 2
×
113
            && _sp is not null)
×
114
        {
115
            System.Diagnostics.Debug.WriteLine("Adding new Cube!");
116
            _drawables = new List<ICube>(_drawables)
×
117
                {
×
118
                    _sp.GetRequiredService<ICube>()
×
119
                }.ToArray();
×
120
            System.Diagnostics.Debug.WriteLine("Cube added!!");
121
        }
122

123
        //if (_drawables.Length == 2)
124
        //{
125
        //    foreach (var drawable in _drawables)
126
        //    {
127
        //        (drawable as IDisposable)?.Dispose();
128
        //    }
129

130
        //    _drawables = Array.Empty<ICube>();
131
        //}
132
        //else if (_drawables.Length < 2 && _sp is not null /*&& _dontCreate == false*/)
133
        //{
134
        //    _drawables = new List<ICube>(_drawables)
135
        //        {
136
        //            _sp.GetRequiredService<ICube>()
137
        //        }.ToArray();
138
        //    //_dontCreate = true;
139
        //}
140

141
        //Share the rainbow
142
        _r = MathF.Sin((_sin + 0) * MathF.PI / 180);
×
143
        _g = MathF.Sin((_sin + 120) * MathF.PI / 180);
×
144
        _b = MathF.Sin((_sin + 240) * MathF.PI / 180);
×
145

146
        //Taste the rainbow
147
        if (++_sin > 360)
×
148
        {
149
            _sin = 0;
×
150
        }
151

152
        _drawables.ElementAtOrDefault(0)
×
153
            ?.Update(renderingSurface, Vector3.Zero, _angleInRadians);
×
154
        _drawables.ElementAtOrDefault(1)
×
155
            ?.Update(renderingSurface, new Vector3(0.5f, 0.0f, -0.5f), -_angleInRadians * 1.5f);
×
156

157
        return ValueTask.CompletedTask;
×
158
    }
159

160
    /// <summary>
161
    /// https://bitbucket.org/snippets/DemoBytom/aejA59/maps-value-between-from-one-min-max-range
162
    /// </summary>
163
    public static float Map(float value, float inMin, float inMax, float outMin, float outMax)
164
        => ((value - inMin) * (outMax - outMin) / (inMax - inMin)) + outMin;
×
165

166
    private float _angleInRadians = 0.0f;
167
    private ICube[] _drawables = [];
×
168
    private const float TWO_PI = MathHelper.TwoPi;
169

170
    private ValueTask Render(
171
        IRenderingEngine renderingEngine,
172
        Guid renderingSurfaceId)
173
    {
174
        _angleInRadians = (_angleInRadians + 0.01f) % TWO_PI;
×
175

176
        renderingEngine.Draw(
×
177
            color: new Color4(_r, _g, _b, 1.0f),
×
178
            renderingSurfaceId: renderingSurfaceId,
×
179
            drawables: _drawables);
×
180

181
        //if (renderingEngine.Control.IsFullscreen != _fullscreen)
182
        //{
183
        //    renderingEngine.SetFullscreen(_fullscreen);
184
        //}
185

186
        return ValueTask.CompletedTask;
×
187
    }
188

189
    #region IDisposable
190

191
    protected override void Dispose(bool disposing)
192
    {
193
        if (!_disposedValue)
×
194
        {
195
            if (disposing)
×
196
            {
197
                _loopCancellationTokenSource.Dispose();
×
198
                foreach (var drawable in _drawables)
×
199
                {
200
                    if (drawable is IDisposable disposable)
×
201
                    {
202
                        disposable.Dispose();
×
203
                    }
204
                }
205
            }
206

207
            _disposedValue = true;
×
208
        }
209
        base.Dispose(disposing);
×
210
    }
×
211

212
    #endregion IDisposable
213
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc