diff --git a/core/libs/prx/libSceAjm.native/Export.cpp b/core/libs/prx/libSceAjm.native/Export.cpp index 7fe1d9502..62c0bc44e 100644 --- a/core/libs/prx/libSceAjm.native/Export.cpp +++ b/core/libs/prx/libSceAjm.native/Export.cpp @@ -14,13 +14,6 @@ static void AjmStub(const char* name) { extern "C" { -int APS5_VABI sceAjmBatchCancel(uint32_t context, uint32_t batch) { - (void)context; - (void)batch; - AjmStub(__func__); - return 0; -} - int APS5_VABI sceAjmBatchJobControl(AjmBatchInfo* info, uint32_t instance, uint64_t flags, const void* sideband_input, size_t sideband_input_size, void* sideband_output, size_t sideband_output_size) { (void)info; (void)instance; diff --git a/core/libs/prx/libSceAjm.native/src/Ajm.cpp b/core/libs/prx/libSceAjm.native/src/Ajm.cpp index 3b30d8d53..181ffbb05 100644 --- a/core/libs/prx/libSceAjm.native/src/Ajm.cpp +++ b/core/libs/prx/libSceAjm.native/src/Ajm.cpp @@ -26,6 +26,7 @@ extern "C" { // memory follow the SDK layouts. namespace { +constexpr int SCE_AJM_ERROR_INVALID_CONTEXT = static_cast(0x80930002); constexpr int SCE_AJM_ERROR_INVALID_INSTANCE = static_cast(0x80930003); constexpr int SCE_AJM_ERROR_INVALID_BATCH = static_cast(0x80930004); constexpr int SCE_AJM_ERROR_INVALID_PARAMETER = static_cast(0x80930005); @@ -1009,6 +1010,12 @@ int APS5_VABI sceAjmBatchWait(uint32_t context, uint32_t batch, uint32_t timeout return 0; } +int APS5_VABI sceAjmBatchCancel(uint32_t context, uint32_t batch) { + if (context == 0 || context >= g_nextContext.load(std::memory_order_relaxed)) return SCE_AJM_ERROR_INVALID_CONTEXT; + std::lock_guard lock(g_batchLock); + return g_batches.contains(batch) ? 0 : SCE_AJM_ERROR_INVALID_BATCH; +} + int APS5_VABI sceAjmBatchErrorDump(const AjmBatchInfo* info, AjmBatchError* error) { (void)info; if (error) std::memset(error, 0, sizeof(*error)); diff --git a/core/libs/tests/GuestAjm.cpp b/core/libs/tests/GuestAjm.cpp index 71524e885..e832b1b16 100644 --- a/core/libs/tests/GuestAjm.cpp +++ b/core/libs/tests/GuestAjm.cpp @@ -25,6 +25,7 @@ int APS5_VABI sceAjmBatchJobGetGaplessDecode(AjmBatchInfo*, std::uint32_t, void* int APS5_VABI sceAjmBatchJobGetCodecInfo(AjmBatchInfo*, std::uint32_t, void*, std::size_t); int APS5_VABI sceAjmBatchStart(std::uint32_t, const AjmBatchInfo*, int, AjmBatchError*, std::uint32_t*); int APS5_VABI sceAjmBatchWait(std::uint32_t, std::uint32_t, std::uint32_t, AjmBatchError*); +int APS5_VABI sceAjmBatchCancel(std::uint32_t, std::uint32_t); } static void Require(bool value) { if (!value) std::abort(); } @@ -339,6 +340,25 @@ void TestBatchWaitRelease(std::uint32_t context) { Require(sceAjmBatchWait(context, second + 1, 0, &error) == invalidBatch); } +void TestBatchCancel(std::uint32_t context) { + constexpr int invalidContext = static_cast(0x80930002); + constexpr int invalidBatch = static_cast(0x80930004); + std::vector batch(64); + AjmBatchInfo info{}; + AjmBatchError error{}; + std::uint32_t id = 0; + Require(sceAjmBatchInitialize(batch.data(), batch.size(), &info) == 0); + Require(sceAjmBatchStart(context, &info, 0, &error, &id) == 0); + Require(sceAjmBatchCancel(context, id) == 0); + Require(sceAjmBatchCancel(context, id) == 0); + Require(sceAjmBatchCancel(0, id) == invalidContext); + Require(sceAjmBatchCancel(context + 1, id) == invalidContext); + Require(sceAjmBatchWait(context, id, 0, &error) == 0); + Require(sceAjmBatchCancel(context, id) == invalidBatch); + Require(sceAjmBatchCancel(context, 0) == invalidBatch); + Require(sceAjmBatchCancel(context, id + 1) == invalidBatch); +} + } int main() { @@ -362,5 +382,6 @@ int main() { TestGaplessDecode(context); TestCodecInfo(context); TestBatchWaitRelease(context); + TestBatchCancel(context); Require(sceAjmFinalize(context) == 0); }