k_resource_limit.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/assert.h"
  4. #include "core/core.h"
  5. #include "core/core_timing.h"
  6. #include "core/hle/kernel/k_resource_limit.h"
  7. #include "core/hle/kernel/svc_results.h"
  8. namespace Kernel {
  9. constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
  10. KResourceLimit::KResourceLimit(KernelCore& kernel_)
  11. : KAutoObjectWithSlabHeapAndContainer{kernel_}, lock{kernel_}, cond_var{kernel_} {}
  12. KResourceLimit::~KResourceLimit() = default;
  13. void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing_) {
  14. core_timing = core_timing_;
  15. }
  16. void KResourceLimit::Finalize() {}
  17. s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
  18. const auto index = static_cast<std::size_t>(which);
  19. s64 value{};
  20. {
  21. KScopedLightLock lk{lock};
  22. value = limit_values[index];
  23. ASSERT(value >= 0);
  24. ASSERT(current_values[index] <= limit_values[index]);
  25. ASSERT(current_hints[index] <= current_values[index]);
  26. }
  27. return value;
  28. }
  29. s64 KResourceLimit::GetCurrentValue(LimitableResource which) const {
  30. const auto index = static_cast<std::size_t>(which);
  31. s64 value{};
  32. {
  33. KScopedLightLock lk{lock};
  34. value = current_values[index];
  35. ASSERT(value >= 0);
  36. ASSERT(current_values[index] <= limit_values[index]);
  37. ASSERT(current_hints[index] <= current_values[index]);
  38. }
  39. return value;
  40. }
  41. s64 KResourceLimit::GetPeakValue(LimitableResource which) const {
  42. const auto index = static_cast<std::size_t>(which);
  43. s64 value{};
  44. {
  45. KScopedLightLock lk{lock};
  46. value = peak_values[index];
  47. ASSERT(value >= 0);
  48. ASSERT(current_values[index] <= limit_values[index]);
  49. ASSERT(current_hints[index] <= current_values[index]);
  50. }
  51. return value;
  52. }
  53. s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
  54. const auto index = static_cast<std::size_t>(which);
  55. s64 value{};
  56. {
  57. KScopedLightLock lk(lock);
  58. ASSERT(current_values[index] >= 0);
  59. ASSERT(current_values[index] <= limit_values[index]);
  60. ASSERT(current_hints[index] <= current_values[index]);
  61. value = limit_values[index] - current_values[index];
  62. }
  63. return value;
  64. }
  65. Result KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
  66. const auto index = static_cast<std::size_t>(which);
  67. KScopedLightLock lk(lock);
  68. R_UNLESS(current_values[index] <= value, ResultInvalidState);
  69. limit_values[index] = value;
  70. peak_values[index] = current_values[index];
  71. return ResultSuccess;
  72. }
  73. bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
  74. return Reserve(which, value, core_timing->GetGlobalTimeNs().count() + DefaultTimeout);
  75. }
  76. bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
  77. ASSERT(value >= 0);
  78. const auto index = static_cast<std::size_t>(which);
  79. KScopedLightLock lk(lock);
  80. ASSERT(current_hints[index] <= current_values[index]);
  81. if (current_hints[index] >= limit_values[index]) {
  82. return false;
  83. }
  84. // Loop until we reserve or run out of time.
  85. while (true) {
  86. ASSERT(current_values[index] <= limit_values[index]);
  87. ASSERT(current_hints[index] <= current_values[index]);
  88. // If we would overflow, don't allow to succeed.
  89. if (current_values[index] + value <= current_values[index]) {
  90. break;
  91. }
  92. if (current_values[index] + value <= limit_values[index]) {
  93. current_values[index] += value;
  94. current_hints[index] += value;
  95. peak_values[index] = std::max(peak_values[index], current_values[index]);
  96. return true;
  97. }
  98. if (current_hints[index] + value <= limit_values[index] &&
  99. (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
  100. waiter_count++;
  101. cond_var.Wait(&lock, timeout, false);
  102. waiter_count--;
  103. } else {
  104. break;
  105. }
  106. }
  107. return false;
  108. }
  109. void KResourceLimit::Release(LimitableResource which, s64 value) {
  110. Release(which, value, value);
  111. }
  112. void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) {
  113. ASSERT(value >= 0);
  114. ASSERT(hint >= 0);
  115. const auto index = static_cast<std::size_t>(which);
  116. KScopedLightLock lk(lock);
  117. ASSERT(current_values[index] <= limit_values[index]);
  118. ASSERT(current_hints[index] <= current_values[index]);
  119. ASSERT(value <= current_values[index]);
  120. ASSERT(hint <= current_hints[index]);
  121. current_values[index] -= value;
  122. current_hints[index] -= hint;
  123. if (waiter_count != 0) {
  124. cond_var.Broadcast();
  125. }
  126. }
  127. KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size) {
  128. auto* resource_limit = KResourceLimit::Create(system.Kernel());
  129. resource_limit->Initialize(&system.CoreTiming());
  130. // Initialize default resource limit values.
  131. // TODO(bunnei): These values are the system defaults, the limits for service processes are
  132. // lower. These should use the correct limit values.
  133. ASSERT(resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, physical_memory_size)
  134. .IsSuccess());
  135. ASSERT(resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
  136. ASSERT(resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
  137. ASSERT(resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200).IsSuccess());
  138. ASSERT(resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
  139. return resource_limit;
  140. }
  141. } // namespace Kernel