address_arbiter.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/common_types.h"
  5. #include "core/mem_map.h"
  6. #include "core/hle/hle.h"
  7. #include "core/hle/kernel/address_arbiter.h"
  8. #include "core/hle/kernel/thread.h"
  9. ////////////////////////////////////////////////////////////////////////////////////////////////////
  10. // Kernel namespace
  11. namespace Kernel {
  12. class AddressArbiter : public Object {
  13. public:
  14. std::string GetTypeName() const override { return "Arbiter"; }
  15. std::string GetName() const override { return name; }
  16. static const HandleType HANDLE_TYPE = HandleType::AddressArbiter;
  17. HandleType GetHandleType() const override { return HANDLE_TYPE; }
  18. std::string name; ///< Name of address arbiter object (optional)
  19. };
  20. ////////////////////////////////////////////////////////////////////////////////////////////////////
  21. /// Arbitrate an address
  22. ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) {
  23. Object* object = Kernel::g_handle_table.GetGeneric(handle).get();
  24. if (object == nullptr)
  25. return InvalidHandle(ErrorModule::Kernel);
  26. switch (type) {
  27. // Signal thread(s) waiting for arbitrate address...
  28. case ArbitrationType::Signal:
  29. // Negative value means resume all threads
  30. if (value < 0) {
  31. ArbitrateAllThreads(object, address);
  32. } else {
  33. // Resume first N threads
  34. for(int i = 0; i < value; i++)
  35. ArbitrateHighestPriorityThread(object, address);
  36. }
  37. break;
  38. // Wait current thread (acquire the arbiter)...
  39. case ArbitrationType::WaitIfLessThan:
  40. if ((s32)Memory::Read32(address) <= value) {
  41. Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address);
  42. HLE::Reschedule(__func__);
  43. }
  44. break;
  45. case ArbitrationType::WaitIfLessThanWithTimeout:
  46. if ((s32)Memory::Read32(address) <= value) {
  47. Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address);
  48. Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds);
  49. HLE::Reschedule(__func__);
  50. }
  51. break;
  52. case ArbitrationType::DecrementAndWaitIfLessThan:
  53. {
  54. s32 memory_value = Memory::Read32(address) - 1;
  55. Memory::Write32(address, memory_value);
  56. if (memory_value <= value) {
  57. Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address);
  58. HLE::Reschedule(__func__);
  59. }
  60. break;
  61. }
  62. case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout:
  63. {
  64. s32 memory_value = Memory::Read32(address) - 1;
  65. Memory::Write32(address, memory_value);
  66. if (memory_value <= value) {
  67. Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address);
  68. Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds);
  69. HLE::Reschedule(__func__);
  70. }
  71. break;
  72. }
  73. default:
  74. LOG_ERROR(Kernel, "unknown type=%d", type);
  75. return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage);
  76. }
  77. return RESULT_SUCCESS;
  78. }
  79. /// Create an address arbiter
  80. AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) {
  81. AddressArbiter* address_arbiter = new AddressArbiter;
  82. // TOOD(yuriks): Fix error reporting
  83. handle = Kernel::g_handle_table.Create(address_arbiter).ValueOr(INVALID_HANDLE);
  84. address_arbiter->name = name;
  85. return address_arbiter;
  86. }
  87. /// Create an address arbiter
  88. Handle CreateAddressArbiter(const std::string& name) {
  89. Handle handle;
  90. CreateAddressArbiter(handle, name);
  91. return handle;
  92. }
  93. } // namespace Kernel