sharpemu/tests/SharpEmu.Libs.Tests/Pthread/PthreadRwlockSemanticsTests.cs

83 lines
3.4 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.HLE;
using SharpEmu.Libs.Kernel;
using Xunit;
namespace SharpEmu.Libs.Tests.Pthread;
public sealed class PthreadRwlockSemanticsTests
{
[Fact]
public void SceTrywrlock_RegistersAndAcquiresFreeLock()
{
const ulong memoryBase = 0x6_0000_0000;
const ulong rwlockAddress = memoryBase + 0x100;
var memory = new FakeCpuMemory(memoryBase, 0x4000);
var context = new CpuContext(memory, Generation.Gen5);
context[CpuRegister.Rdi] = rwlockAddress;
Assert.Equal(0, KernelPthreadExtendedCompatExports.PthreadRwlockInit(context));
var manager = new ModuleManager();
manager.RegisterExports(SharpEmu.Generated.SysAbiExportRegistry.CreateExports(Generation.Gen5));
Assert.True(manager.TryGetExport("bIHoZCTomsI", out var export));
Assert.Equal("scePthreadRwlockTrywrlock", export.Name);
Assert.Equal("libKernel", export.LibraryName);
Assert.True(manager.TryDispatch("bIHoZCTomsI", context, out var result));
Assert.Equal(OrbisGen2Result.ORBIS_GEN2_OK, result);
Assert.Equal(0UL, context[CpuRegister.Rax]);
Assert.Equal(0, KernelPthreadExtendedCompatExports.PthreadRwlockUnlock(context));
Assert.Equal(0, KernelPthreadExtendedCompatExports.PthreadRwlockDestroy(context));
}
[Fact]
public async Task SceTrywrlock_ReturnsBusyWhileAnotherThreadReads()
{
const ulong memoryBase = 0x6_0001_0000;
const ulong rwlockAddress = memoryBase + 0x100;
var memory = new FakeCpuMemory(memoryBase, 0x4000);
var initializationContext = new CpuContext(memory, Generation.Gen5);
initializationContext[CpuRegister.Rdi] = rwlockAddress;
Assert.Equal(0, KernelPthreadExtendedCompatExports.PthreadRwlockInit(initializationContext));
using var readerReady = new ManualResetEventSlim(false);
using var releaseReader = new ManualResetEventSlim(false);
var readerTask = Task.Factory.StartNew(
() =>
{
var readerContext = new CpuContext(memory, Generation.Gen5);
readerContext[CpuRegister.Rdi] = rwlockAddress;
var lockResult = KernelPthreadExtendedCompatExports.PthreadRwlockRdlock(readerContext);
readerReady.Set();
releaseReader.Wait(TimeSpan.FromSeconds(5));
var unlockResult = lockResult == 0
? KernelPthreadExtendedCompatExports.PthreadRwlockUnlock(readerContext)
: int.MinValue;
return (lockResult, unlockResult);
},
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
try
{
Assert.True(readerReady.Wait(TimeSpan.FromSeconds(5)));
var writerContext = new CpuContext(memory, Generation.Gen5);
writerContext[CpuRegister.Rdi] = rwlockAddress;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_BUSY,
KernelPthreadExtendedCompatExports.PthreadRwlockTrywrlock(writerContext));
}
finally
{
releaseReader.Set();
}
Assert.Equal((0, 0), await readerTask.WaitAsync(TimeSpan.FromSeconds(5)));
Assert.Equal(0, KernelPthreadExtendedCompatExports.PthreadRwlockDestroy(initializationContext));
}
}