KThread.cs 30 KB

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