KThread.cs 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. using ChocolArm64;
  2. using ChocolArm64.Memory;
  3. using Ryujinx.HLE.HOS.Kernel.Common;
  4. using Ryujinx.HLE.HOS.Kernel.Process;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. namespace Ryujinx.HLE.HOS.Kernel.Threading
  9. {
  10. class KThread : KSynchronizationObject, IKFutureSchedulerObject
  11. {
  12. public CpuThread Context { get; private set; }
  13. public long AffinityMask { get; set; }
  14. public long ThreadUid { get; private set; }
  15. public long TotalTimeRunning { get; set; }
  16. public KSynchronizationObject SignaledObj { get; set; }
  17. public ulong CondVarAddress { get; set; }
  18. private ulong _entrypoint;
  19. public ulong MutexAddress { get; set; }
  20. public KProcess Owner { get; private set; }
  21. private ulong _tlsAddress;
  22. public ulong TlsAddress => _tlsAddress;
  23. public ulong TlsDramAddress { get; private set; }
  24. public long LastScheduledTime { get; set; }
  25. public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
  26. public LinkedList<KThread> Withholder { get; set; }
  27. public LinkedListNode<KThread> WithholderNode { get; set; }
  28. public LinkedListNode<KThread> ProcessListNode { get; set; }
  29. private LinkedList<KThread> _mutexWaiters;
  30. private LinkedListNode<KThread> _mutexWaiterNode;
  31. public KThread MutexOwner { get; private set; }
  32. public int ThreadHandleForUserMutex { get; set; }
  33. private ThreadSchedState _forcePauseFlags;
  34. public KernelResult ObjSyncResult { get; set; }
  35. public int DynamicPriority { get; set; }
  36. public int CurrentCore { get; set; }
  37. public int BasePriority { get; set; }
  38. public int PreferredCore { get; set; }
  39. private long _affinityMaskOverride;
  40. private int _preferredCoreOverride;
  41. private int _affinityOverrideCount;
  42. public ThreadSchedState SchedFlags { get; private set; }
  43. public bool ShallBeTerminated { get; private set; }
  44. public bool SyncCancelled { get; set; }
  45. public bool WaitingSync { get; set; }
  46. private bool _hasExited;
  47. private bool _hasBeenInitialized;
  48. private bool _hasBeenReleased;
  49. public bool WaitingInArbitration { get; set; }
  50. private KScheduler _scheduler;
  51. private KSchedulingData _schedulingData;
  52. public long LastPc { get; set; }
  53. public KThread(Horizon system) : base(system)
  54. {
  55. _scheduler = system.Scheduler;
  56. _schedulingData = system.Scheduler.SchedulingData;
  57. SiblingsPerCore = new LinkedListNode<KThread>[KScheduler.CpuCoresCount];
  58. _mutexWaiters = new LinkedList<KThread>();
  59. }
  60. public KernelResult Initialize(
  61. ulong entrypoint,
  62. ulong argsPtr,
  63. ulong stackTop,
  64. int priority,
  65. int defaultCpuCore,
  66. KProcess owner,
  67. ThreadType type = ThreadType.User)
  68. {
  69. if ((uint)type > 3)
  70. {
  71. throw new ArgumentException($"Invalid thread type \"{type}\".");
  72. }
  73. PreferredCore = defaultCpuCore;
  74. AffinityMask |= 1L << defaultCpuCore;
  75. SchedFlags = type == ThreadType.Dummy
  76. ? ThreadSchedState.Running
  77. : ThreadSchedState.None;
  78. CurrentCore = PreferredCore;
  79. DynamicPriority = priority;
  80. BasePriority = priority;
  81. ObjSyncResult = KernelResult.ThreadNotStarted;
  82. _entrypoint = entrypoint;
  83. if (type == ThreadType.User)
  84. {
  85. if (owner.AllocateThreadLocalStorage(out _tlsAddress) != KernelResult.Success)
  86. {
  87. return KernelResult.OutOfMemory;
  88. }
  89. TlsDramAddress = owner.MemoryManager.GetDramAddressFromVa(_tlsAddress);
  90. MemoryHelper.FillWithZeros(owner.CpuMemory, (long)_tlsAddress, KTlsPageInfo.TlsEntrySize);
  91. }
  92. bool is64Bits;
  93. if (owner != null)
  94. {
  95. Owner = owner;
  96. owner.IncrementReferenceCount();
  97. owner.IncrementThreadCount();
  98. is64Bits = (owner.MmuFlags & 1) != 0;
  99. }
  100. else
  101. {
  102. is64Bits = true;
  103. }
  104. Context = new CpuThread(owner.Translator, owner.CpuMemory, (long)entrypoint);
  105. Context.ThreadState.IsAarch32 = (Owner.MmuFlags & 1) == 0;
  106. Context.ThreadState.X0 = argsPtr;
  107. Context.ThreadState.X31 = stackTop;
  108. Context.ThreadState.CntfrqEl0 = 19200000;
  109. Context.ThreadState.Tpidr = (long)_tlsAddress;
  110. owner.SubscribeThreadEventHandlers(Context);
  111. Context.WorkFinished += ThreadFinishedHandler;
  112. ThreadUid = System.GetThreadUid();
  113. _hasBeenInitialized = true;
  114. if (owner != null)
  115. {
  116. owner.AddThread(this);
  117. if (owner.IsPaused)
  118. {
  119. System.CriticalSection.Enter();
  120. if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
  121. {
  122. System.CriticalSection.Leave();
  123. return KernelResult.Success;
  124. }
  125. _forcePauseFlags |= ThreadSchedState.ProcessPauseFlag;
  126. CombineForcePauseFlags();
  127. System.CriticalSection.Leave();
  128. }
  129. }
  130. return KernelResult.Success;
  131. }
  132. public KernelResult Start()
  133. {
  134. if (!System.KernelInitialized)
  135. {
  136. System.CriticalSection.Enter();
  137. if (!ShallBeTerminated && SchedFlags != ThreadSchedState.TerminationPending)
  138. {
  139. _forcePauseFlags |= ThreadSchedState.KernelInitPauseFlag;
  140. CombineForcePauseFlags();
  141. }
  142. System.CriticalSection.Leave();
  143. }
  144. KernelResult result = KernelResult.ThreadTerminating;
  145. System.CriticalSection.Enter();
  146. if (!ShallBeTerminated)
  147. {
  148. KThread currentThread = System.Scheduler.GetCurrentThread();
  149. while (SchedFlags != ThreadSchedState.TerminationPending &&
  150. currentThread.SchedFlags != ThreadSchedState.TerminationPending &&
  151. !currentThread.ShallBeTerminated)
  152. {
  153. if ((SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.None)
  154. {
  155. result = KernelResult.InvalidState;
  156. break;
  157. }
  158. if (currentThread._forcePauseFlags == ThreadSchedState.None)
  159. {
  160. if (Owner != null && _forcePauseFlags != ThreadSchedState.None)
  161. {
  162. CombineForcePauseFlags();
  163. }
  164. SetNewSchedFlags(ThreadSchedState.Running);
  165. result = KernelResult.Success;
  166. break;
  167. }
  168. else
  169. {
  170. currentThread.CombineForcePauseFlags();
  171. System.CriticalSection.Leave();
  172. System.CriticalSection.Enter();
  173. if (currentThread.ShallBeTerminated)
  174. {
  175. break;
  176. }
  177. }
  178. }
  179. }
  180. System.CriticalSection.Leave();
  181. return result;
  182. }
  183. public void Exit()
  184. {
  185. //TODO: Debug event.
  186. if (Owner != null)
  187. {
  188. Owner.ResourceLimit?.Release(LimitableResource.Thread, 0, 1);
  189. _hasBeenReleased = true;
  190. }
  191. System.CriticalSection.Enter();
  192. _forcePauseFlags &= ~ThreadSchedState.ForcePauseMask;
  193. ExitImpl();
  194. System.CriticalSection.Leave();
  195. DecrementReferenceCount();
  196. }
  197. private void ExitImpl()
  198. {
  199. System.CriticalSection.Enter();
  200. SetNewSchedFlags(ThreadSchedState.TerminationPending);
  201. _hasExited = true;
  202. Signal();
  203. System.CriticalSection.Leave();
  204. }
  205. public KernelResult Sleep(long timeout)
  206. {
  207. System.CriticalSection.Enter();
  208. if (ShallBeTerminated || SchedFlags == ThreadSchedState.TerminationPending)
  209. {
  210. System.CriticalSection.Leave();
  211. return KernelResult.ThreadTerminating;
  212. }
  213. SetNewSchedFlags(ThreadSchedState.Paused);
  214. if (timeout > 0)
  215. {
  216. System.TimeManager.ScheduleFutureInvocation(this, timeout);
  217. }
  218. System.CriticalSection.Leave();
  219. if (timeout > 0)
  220. {
  221. System.TimeManager.UnscheduleFutureInvocation(this);
  222. }
  223. return 0;
  224. }
  225. public void Yield()
  226. {
  227. System.CriticalSection.Enter();
  228. if (SchedFlags != ThreadSchedState.Running)
  229. {
  230. System.CriticalSection.Leave();
  231. System.Scheduler.ContextSwitch();
  232. return;
  233. }
  234. if (DynamicPriority < KScheduler.PrioritiesCount)
  235. {
  236. //Move current thread to the end of the queue.
  237. _schedulingData.Reschedule(DynamicPriority, CurrentCore, this);
  238. }
  239. _scheduler.ThreadReselectionRequested = true;
  240. System.CriticalSection.Leave();
  241. System.Scheduler.ContextSwitch();
  242. }
  243. public void YieldWithLoadBalancing()
  244. {
  245. System.CriticalSection.Enter();
  246. if (SchedFlags != ThreadSchedState.Running)
  247. {
  248. System.CriticalSection.Leave();
  249. System.Scheduler.ContextSwitch();
  250. return;
  251. }
  252. int prio = DynamicPriority;
  253. int core = CurrentCore;
  254. KThread nextThreadOnCurrentQueue = null;
  255. if (DynamicPriority < KScheduler.PrioritiesCount)
  256. {
  257. //Move current thread to the end of the queue.
  258. _schedulingData.Reschedule(prio, core, this);
  259. Func<KThread, bool> predicate = x => x.DynamicPriority == prio;
  260. nextThreadOnCurrentQueue = _schedulingData.ScheduledThreads(core).FirstOrDefault(predicate);
  261. }
  262. IEnumerable<KThread> SuitableCandidates()
  263. {
  264. foreach (KThread thread in _schedulingData.SuggestedThreads(core))
  265. {
  266. int srcCore = thread.CurrentCore;
  267. if (srcCore >= 0)
  268. {
  269. KThread selectedSrcCore = _scheduler.CoreContexts[srcCore].SelectedThread;
  270. if (selectedSrcCore == thread || ((selectedSrcCore?.DynamicPriority ?? 2) < 2))
  271. {
  272. continue;
  273. }
  274. }
  275. //If the candidate was scheduled after the current thread, then it's not worth it,
  276. //unless the priority is higher than the current one.
  277. if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime ||
  278. nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
  279. {
  280. yield return thread;
  281. }
  282. }
  283. }
  284. KThread dst = SuitableCandidates().FirstOrDefault(x => x.DynamicPriority <= prio);
  285. if (dst != null)
  286. {
  287. _schedulingData.TransferToCore(dst.DynamicPriority, core, dst);
  288. _scheduler.ThreadReselectionRequested = true;
  289. }
  290. if (this != nextThreadOnCurrentQueue)
  291. {
  292. _scheduler.ThreadReselectionRequested = true;
  293. }
  294. System.CriticalSection.Leave();
  295. System.Scheduler.ContextSwitch();
  296. }
  297. public void YieldAndWaitForLoadBalancing()
  298. {
  299. System.CriticalSection.Enter();
  300. if (SchedFlags != ThreadSchedState.Running)
  301. {
  302. System.CriticalSection.Leave();
  303. System.Scheduler.ContextSwitch();
  304. return;
  305. }
  306. int core = CurrentCore;
  307. _schedulingData.TransferToCore(DynamicPriority, -1, this);
  308. KThread selectedThread = null;
  309. if (!_schedulingData.ScheduledThreads(core).Any())
  310. {
  311. foreach (KThread thread in _schedulingData.SuggestedThreads(core))
  312. {
  313. if (thread.CurrentCore < 0)
  314. {
  315. continue;
  316. }
  317. KThread firstCandidate = _schedulingData.ScheduledThreads(thread.CurrentCore).FirstOrDefault();
  318. if (firstCandidate == thread)
  319. {
  320. continue;
  321. }
  322. if (firstCandidate == null || firstCandidate.DynamicPriority >= 2)
  323. {
  324. _schedulingData.TransferToCore(thread.DynamicPriority, core, thread);
  325. selectedThread = thread;
  326. }
  327. break;
  328. }
  329. }
  330. if (selectedThread != this)
  331. {
  332. _scheduler.ThreadReselectionRequested = true;
  333. }
  334. System.CriticalSection.Leave();
  335. System.Scheduler.ContextSwitch();
  336. }
  337. public void SetPriority(int priority)
  338. {
  339. System.CriticalSection.Enter();
  340. BasePriority = priority;
  341. UpdatePriorityInheritance();
  342. System.CriticalSection.Leave();
  343. }
  344. public KernelResult SetActivity(bool pause)
  345. {
  346. KernelResult result = KernelResult.Success;
  347. System.CriticalSection.Enter();
  348. ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask;
  349. if (lowNibble != ThreadSchedState.Paused && lowNibble != ThreadSchedState.Running)
  350. {
  351. System.CriticalSection.Leave();
  352. return KernelResult.InvalidState;
  353. }
  354. System.CriticalSection.Enter();
  355. if (!ShallBeTerminated && SchedFlags != ThreadSchedState.TerminationPending)
  356. {
  357. if (pause)
  358. {
  359. //Pause, the force pause flag should be clear (thread is NOT paused).
  360. if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0)
  361. {
  362. _forcePauseFlags |= ThreadSchedState.ThreadPauseFlag;
  363. CombineForcePauseFlags();
  364. }
  365. else
  366. {
  367. result = KernelResult.InvalidState;
  368. }
  369. }
  370. else
  371. {
  372. //Unpause, the force pause flag should be set (thread is paused).
  373. if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) != 0)
  374. {
  375. ThreadSchedState oldForcePauseFlags = _forcePauseFlags;
  376. _forcePauseFlags &= ~ThreadSchedState.ThreadPauseFlag;
  377. if ((oldForcePauseFlags & ~ThreadSchedState.ThreadPauseFlag) == ThreadSchedState.None)
  378. {
  379. ThreadSchedState oldSchedFlags = SchedFlags;
  380. SchedFlags &= ThreadSchedState.LowMask;
  381. AdjustScheduling(oldSchedFlags);
  382. }
  383. }
  384. else
  385. {
  386. result = KernelResult.InvalidState;
  387. }
  388. }
  389. }
  390. System.CriticalSection.Leave();
  391. System.CriticalSection.Leave();
  392. return result;
  393. }
  394. public void CancelSynchronization()
  395. {
  396. System.CriticalSection.Enter();
  397. if ((SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.Paused || !WaitingSync)
  398. {
  399. SyncCancelled = true;
  400. }
  401. else if (Withholder != null)
  402. {
  403. Withholder.Remove(WithholderNode);
  404. SetNewSchedFlags(ThreadSchedState.Running);
  405. Withholder = null;
  406. SyncCancelled = true;
  407. }
  408. else
  409. {
  410. SignaledObj = null;
  411. ObjSyncResult = KernelResult.Cancelled;
  412. SetNewSchedFlags(ThreadSchedState.Running);
  413. SyncCancelled = false;
  414. }
  415. System.CriticalSection.Leave();
  416. }
  417. public KernelResult SetCoreAndAffinityMask(int newCore, long newAffinityMask)
  418. {
  419. System.CriticalSection.Enter();
  420. bool useOverride = _affinityOverrideCount != 0;
  421. //The value -3 is "do not change the preferred core".
  422. if (newCore == -3)
  423. {
  424. newCore = useOverride ? _preferredCoreOverride : PreferredCore;
  425. if ((newAffinityMask & (1 << newCore)) == 0)
  426. {
  427. System.CriticalSection.Leave();
  428. return KernelResult.InvalidCombination;
  429. }
  430. }
  431. if (useOverride)
  432. {
  433. _preferredCoreOverride = newCore;
  434. _affinityMaskOverride = newAffinityMask;
  435. }
  436. else
  437. {
  438. long oldAffinityMask = AffinityMask;
  439. PreferredCore = newCore;
  440. AffinityMask = newAffinityMask;
  441. if (oldAffinityMask != newAffinityMask)
  442. {
  443. int oldCore = CurrentCore;
  444. if (CurrentCore >= 0 && ((AffinityMask >> CurrentCore) & 1) == 0)
  445. {
  446. if (PreferredCore < 0)
  447. {
  448. CurrentCore = HighestSetCore(AffinityMask);
  449. }
  450. else
  451. {
  452. CurrentCore = PreferredCore;
  453. }
  454. }
  455. AdjustSchedulingForNewAffinity(oldAffinityMask, oldCore);
  456. }
  457. }
  458. System.CriticalSection.Leave();
  459. return KernelResult.Success;
  460. }
  461. private static int HighestSetCore(long mask)
  462. {
  463. for (int core = KScheduler.CpuCoresCount - 1; core >= 0; core--)
  464. {
  465. if (((mask >> core) & 1) != 0)
  466. {
  467. return core;
  468. }
  469. }
  470. return -1;
  471. }
  472. private void CombineForcePauseFlags()
  473. {
  474. ThreadSchedState oldFlags = SchedFlags;
  475. ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask;
  476. SchedFlags = lowNibble | _forcePauseFlags;
  477. AdjustScheduling(oldFlags);
  478. }
  479. private void SetNewSchedFlags(ThreadSchedState newFlags)
  480. {
  481. System.CriticalSection.Enter();
  482. ThreadSchedState oldFlags = SchedFlags;
  483. SchedFlags = (oldFlags & ThreadSchedState.HighMask) | newFlags;
  484. if ((oldFlags & ThreadSchedState.LowMask) != newFlags)
  485. {
  486. AdjustScheduling(oldFlags);
  487. }
  488. System.CriticalSection.Leave();
  489. }
  490. public void ReleaseAndResume()
  491. {
  492. System.CriticalSection.Enter();
  493. if ((SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
  494. {
  495. if (Withholder != null)
  496. {
  497. Withholder.Remove(WithholderNode);
  498. SetNewSchedFlags(ThreadSchedState.Running);
  499. Withholder = null;
  500. }
  501. else
  502. {
  503. SetNewSchedFlags(ThreadSchedState.Running);
  504. }
  505. }
  506. System.CriticalSection.Leave();
  507. }
  508. public void Reschedule(ThreadSchedState newFlags)
  509. {
  510. System.CriticalSection.Enter();
  511. ThreadSchedState oldFlags = SchedFlags;
  512. SchedFlags = (oldFlags & ThreadSchedState.HighMask) |
  513. (newFlags & ThreadSchedState.LowMask);
  514. AdjustScheduling(oldFlags);
  515. System.CriticalSection.Leave();
  516. }
  517. public void AddMutexWaiter(KThread requester)
  518. {
  519. AddToMutexWaitersList(requester);
  520. requester.MutexOwner = this;
  521. UpdatePriorityInheritance();
  522. }
  523. public void RemoveMutexWaiter(KThread thread)
  524. {
  525. if (thread._mutexWaiterNode?.List != null)
  526. {
  527. _mutexWaiters.Remove(thread._mutexWaiterNode);
  528. }
  529. thread.MutexOwner = null;
  530. UpdatePriorityInheritance();
  531. }
  532. public KThread RelinquishMutex(ulong mutexAddress, out int count)
  533. {
  534. count = 0;
  535. if (_mutexWaiters.First == null)
  536. {
  537. return null;
  538. }
  539. KThread newMutexOwner = null;
  540. LinkedListNode<KThread> currentNode = _mutexWaiters.First;
  541. do
  542. {
  543. //Skip all threads that are not waiting for this mutex.
  544. while (currentNode != null && currentNode.Value.MutexAddress != mutexAddress)
  545. {
  546. currentNode = currentNode.Next;
  547. }
  548. if (currentNode == null)
  549. {
  550. break;
  551. }
  552. LinkedListNode<KThread> nextNode = currentNode.Next;
  553. _mutexWaiters.Remove(currentNode);
  554. currentNode.Value.MutexOwner = newMutexOwner;
  555. if (newMutexOwner != null)
  556. {
  557. //New owner was already selected, re-insert on new owner list.
  558. newMutexOwner.AddToMutexWaitersList(currentNode.Value);
  559. }
  560. else
  561. {
  562. //New owner not selected yet, use current thread.
  563. newMutexOwner = currentNode.Value;
  564. }
  565. count++;
  566. currentNode = nextNode;
  567. }
  568. while (currentNode != null);
  569. if (newMutexOwner != null)
  570. {
  571. UpdatePriorityInheritance();
  572. newMutexOwner.UpdatePriorityInheritance();
  573. }
  574. return newMutexOwner;
  575. }
  576. private void UpdatePriorityInheritance()
  577. {
  578. //If any of the threads waiting for the mutex has
  579. //higher priority than the current thread, then
  580. //the current thread inherits that priority.
  581. int highestPriority = BasePriority;
  582. if (_mutexWaiters.First != null)
  583. {
  584. int waitingDynamicPriority = _mutexWaiters.First.Value.DynamicPriority;
  585. if (waitingDynamicPriority < highestPriority)
  586. {
  587. highestPriority = waitingDynamicPriority;
  588. }
  589. }
  590. if (highestPriority != DynamicPriority)
  591. {
  592. int oldPriority = DynamicPriority;
  593. DynamicPriority = highestPriority;
  594. AdjustSchedulingForNewPriority(oldPriority);
  595. if (MutexOwner != null)
  596. {
  597. //Remove and re-insert to ensure proper sorting based on new priority.
  598. MutexOwner._mutexWaiters.Remove(_mutexWaiterNode);
  599. MutexOwner.AddToMutexWaitersList(this);
  600. MutexOwner.UpdatePriorityInheritance();
  601. }
  602. }
  603. }
  604. private void AddToMutexWaitersList(KThread thread)
  605. {
  606. LinkedListNode<KThread> nextPrio = _mutexWaiters.First;
  607. int currentPriority = thread.DynamicPriority;
  608. while (nextPrio != null && nextPrio.Value.DynamicPriority <= currentPriority)
  609. {
  610. nextPrio = nextPrio.Next;
  611. }
  612. if (nextPrio != null)
  613. {
  614. thread._mutexWaiterNode = _mutexWaiters.AddBefore(nextPrio, thread);
  615. }
  616. else
  617. {
  618. thread._mutexWaiterNode = _mutexWaiters.AddLast(thread);
  619. }
  620. }
  621. private void AdjustScheduling(ThreadSchedState oldFlags)
  622. {
  623. if (oldFlags == SchedFlags)
  624. {
  625. return;
  626. }
  627. if (oldFlags == ThreadSchedState.Running)
  628. {
  629. //Was running, now it's stopped.
  630. if (CurrentCore >= 0)
  631. {
  632. _schedulingData.Unschedule(DynamicPriority, CurrentCore, this);
  633. }
  634. for (int core = 0; core < KScheduler.CpuCoresCount; core++)
  635. {
  636. if (core != CurrentCore && ((AffinityMask >> core) & 1) != 0)
  637. {
  638. _schedulingData.Unsuggest(DynamicPriority, core, this);
  639. }
  640. }
  641. }
  642. else if (SchedFlags == ThreadSchedState.Running)
  643. {
  644. //Was stopped, now it's running.
  645. if (CurrentCore >= 0)
  646. {
  647. _schedulingData.Schedule(DynamicPriority, CurrentCore, this);
  648. }
  649. for (int core = 0; core < KScheduler.CpuCoresCount; core++)
  650. {
  651. if (core != CurrentCore && ((AffinityMask >> core) & 1) != 0)
  652. {
  653. _schedulingData.Suggest(DynamicPriority, core, this);
  654. }
  655. }
  656. }
  657. _scheduler.ThreadReselectionRequested = true;
  658. }
  659. private void AdjustSchedulingForNewPriority(int oldPriority)
  660. {
  661. if (SchedFlags != ThreadSchedState.Running)
  662. {
  663. return;
  664. }
  665. //Remove thread from the old priority queues.
  666. if (CurrentCore >= 0)
  667. {
  668. _schedulingData.Unschedule(oldPriority, CurrentCore, this);
  669. }
  670. for (int core = 0; core < KScheduler.CpuCoresCount; core++)
  671. {
  672. if (core != CurrentCore && ((AffinityMask >> core) & 1) != 0)
  673. {
  674. _schedulingData.Unsuggest(oldPriority, core, this);
  675. }
  676. }
  677. //Add thread to the new priority queues.
  678. KThread currentThread = _scheduler.GetCurrentThread();
  679. if (CurrentCore >= 0)
  680. {
  681. if (currentThread == this)
  682. {
  683. _schedulingData.SchedulePrepend(DynamicPriority, CurrentCore, this);
  684. }
  685. else
  686. {
  687. _schedulingData.Schedule(DynamicPriority, CurrentCore, this);
  688. }
  689. }
  690. for (int core = 0; core < KScheduler.CpuCoresCount; core++)
  691. {
  692. if (core != CurrentCore && ((AffinityMask >> core) & 1) != 0)
  693. {
  694. _schedulingData.Suggest(DynamicPriority, core, this);
  695. }
  696. }
  697. _scheduler.ThreadReselectionRequested = true;
  698. }
  699. private void AdjustSchedulingForNewAffinity(long oldAffinityMask, int oldCore)
  700. {
  701. if (SchedFlags != ThreadSchedState.Running || DynamicPriority >= KScheduler.PrioritiesCount)
  702. {
  703. return;
  704. }
  705. //Remove thread from the old priority queues.
  706. for (int core = 0; core < KScheduler.CpuCoresCount; core++)
  707. {
  708. if (((oldAffinityMask >> core) & 1) != 0)
  709. {
  710. if (core == oldCore)
  711. {
  712. _schedulingData.Unschedule(DynamicPriority, core, this);
  713. }
  714. else
  715. {
  716. _schedulingData.Unsuggest(DynamicPriority, core, this);
  717. }
  718. }
  719. }
  720. //Add thread to the new priority queues.
  721. for (int core = 0; core < KScheduler.CpuCoresCount; core++)
  722. {
  723. if (((AffinityMask >> core) & 1) != 0)
  724. {
  725. if (core == CurrentCore)
  726. {
  727. _schedulingData.Schedule(DynamicPriority, core, this);
  728. }
  729. else
  730. {
  731. _schedulingData.Suggest(DynamicPriority, core, this);
  732. }
  733. }
  734. }
  735. _scheduler.ThreadReselectionRequested = true;
  736. }
  737. public void SetEntryArguments(long argsPtr, int threadHandle)
  738. {
  739. Context.ThreadState.X0 = (ulong)argsPtr;
  740. Context.ThreadState.X1 = (ulong)threadHandle;
  741. }
  742. public void ClearExclusive()
  743. {
  744. Owner.CpuMemory.ClearExclusive(CurrentCore);
  745. }
  746. public void TimeUp()
  747. {
  748. ReleaseAndResume();
  749. }
  750. public void PrintGuestStackTrace()
  751. {
  752. Owner.Debugger.PrintGuestStackTrace(Context.ThreadState);
  753. }
  754. private void ThreadFinishedHandler(object sender, EventArgs e)
  755. {
  756. System.Scheduler.ExitThread(this);
  757. System.Scheduler.RemoveThread(this);
  758. }
  759. public override bool IsSignaled()
  760. {
  761. return _hasExited;
  762. }
  763. protected override void Destroy()
  764. {
  765. if (_hasBeenInitialized)
  766. {
  767. FreeResources();
  768. bool released = Owner != null || _hasBeenReleased;
  769. if (Owner != null)
  770. {
  771. Owner.ResourceLimit?.Release(LimitableResource.Thread, 1, released ? 0 : 1);
  772. Owner.DecrementReferenceCount();
  773. }
  774. else
  775. {
  776. System.ResourceLimit.Release(LimitableResource.Thread, 1, released ? 0 : 1);
  777. }
  778. }
  779. }
  780. private void FreeResources()
  781. {
  782. Owner?.RemoveThread(this);
  783. if (_tlsAddress != 0 && Owner.FreeThreadLocalStorage(_tlsAddress) != KernelResult.Success)
  784. {
  785. throw new InvalidOperationException("Unexpected failure freeing thread local storage.");
  786. }
  787. System.CriticalSection.Enter();
  788. //Wake up all threads that may be waiting for a mutex being held by this thread.
  789. foreach (KThread thread in _mutexWaiters)
  790. {
  791. thread.MutexOwner = null;
  792. thread._preferredCoreOverride = 0;
  793. thread.ObjSyncResult = KernelResult.InvalidState;
  794. thread.ReleaseAndResume();
  795. }
  796. System.CriticalSection.Leave();
  797. Owner?.DecrementThreadCountAndTerminateIfZero();
  798. }
  799. }
  800. }