rjx-mirror/Ryujinx.HLE/OsHle/Handles/ThreadQueue.cs
gdkchan 3e6afeb513
Fix some thread sync issues (#172)
* Fix some thread sync issues

* Remove some debug stuff

* Ensure that writes to the mutex address clears the exclusive monitor
2018-06-21 23:05:42 -03:00

158 lines
No EOL
3.7 KiB
C#

namespace Ryujinx.HLE.OsHle.Handles
{
class ThreadQueue
{
private const int LowestPriority = 0x3f;
private SchedulerThread Head;
private object ListLock;
public ThreadQueue()
{
ListLock = new object();
}
public void Push(SchedulerThread Wait)
{
lock (ListLock)
{
//Ensure that we're not creating circular references
//by adding a thread that is already on the list.
if (HasThread(Wait))
{
return;
}
if (Head == null || Head.Thread.ActualPriority >= Wait.Thread.ActualPriority)
{
Wait.Next = Head;
Head = Wait;
return;
}
SchedulerThread Curr = Head;
while (Curr.Next != null)
{
if (Curr.Next.Thread.ActualPriority >= Wait.Thread.ActualPriority)
{
break;
}
Curr = Curr.Next;
}
Wait.Next = Curr.Next;
Curr.Next = Wait;
}
}
public SchedulerThread Pop(int Core, int MinPriority = LowestPriority)
{
lock (ListLock)
{
int CoreMask = 1 << Core;
SchedulerThread Prev = null;
SchedulerThread Curr = Head;
while (Curr != null)
{
KThread Thread = Curr.Thread;
if (Thread.ActualPriority <= MinPriority && (Thread.CoreMask & CoreMask) != 0)
{
if (Prev != null)
{
Prev.Next = Curr.Next;
}
else
{
Head = Head.Next;
}
break;
}
Prev = Curr;
Curr = Curr.Next;
}
return Curr;
}
}
public bool Remove(SchedulerThread Thread)
{
lock (ListLock)
{
if (Head == null)
{
return false;
}
else if (Head == Thread)
{
Head = Head.Next;
return true;
}
SchedulerThread Prev = Head;
SchedulerThread Curr = Head.Next;
while (Curr != null)
{
if (Curr == Thread)
{
Prev.Next = Curr.Next;
return true;
}
Prev = Curr;
Curr = Curr.Next;
}
return false;
}
}
public bool Resort(SchedulerThread Thread)
{
lock (ListLock)
{
if (Remove(Thread))
{
Push(Thread);
return true;
}
return false;
}
}
public bool HasThread(SchedulerThread Thread)
{
lock (ListLock)
{
SchedulerThread Curr = Head;
while (Curr != null)
{
if (Curr == Thread)
{
return true;
}
Curr = Curr.Next;
}
return false;
}
}
}
}