Exemplo n.º 1
0
// Resume all waiting threads (for delete / cancel.)
// Returns true if it woke any threads.
bool __KernelClearSemaThreads(Semaphore *s, int reason)
{
	u32 error;
	bool wokeThreads = false;
	std::vector<SceUID>::iterator iter, end;
	for (iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter)
		__KernelUnlockSemaForThread(s, *iter, error, reason, wokeThreads);
	s->waitingThreads.clear();

	return wokeThreads;
}
Exemplo n.º 2
0
void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId, u32 &returnValue)
{
	SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId;

	// Note: Cancel does not affect suspended semaphore waits.

	u32 error;
	SceUID semaID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);
	u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
	Semaphore *s = semaID == 0 ? NULL : kernelObjects.Get<Semaphore>(semaID, error);
	if (!s || s->pausedWaitTimeouts.find(pauseKey) == s->pausedWaitTimeouts.end())
	{
		// TODO: Since it was deleted, we don't know how long was actually left.
		// For now, we just say the full time was taken.
		if (timeoutPtr != 0 && semaWaitTimer != -1)
			Memory::Write_U32(0, timeoutPtr);

		__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_DELETE);
		return;
	}

	u64 waitDeadline = s->pausedWaitTimeouts[pauseKey];
	s->pausedWaitTimeouts.erase(pauseKey);

	// TODO: Don't wake up if __KernelCurHasReadyCallbacks()?

	bool wokeThreads;
	// Attempt to unlock.
	if (__KernelUnlockSemaForThread(s, threadID, error, 0, wokeThreads))
		return;

	// We only check if it timed out if it couldn't unlock.
	s64 cyclesLeft = waitDeadline - CoreTiming::GetTicks();
	if (cyclesLeft < 0 && waitDeadline != 0)
	{
		if (timeoutPtr != 0 && semaWaitTimer != -1)
			Memory::Write_U32(0, timeoutPtr);

		__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
	}
	else
	{
		if (timeoutPtr != 0 && semaWaitTimer != -1)
			CoreTiming::ScheduleEvent(cyclesLeft, semaWaitTimer, __KernelGetCurThread());

		// TODO: Should this not go at the end?
		s->waitingThreads.push_back(threadID);

		DEBUG_LOG(HLE, "sceKernelWaitSemaCB: Resuming sema wait for callback");
	}
}
int sceKernelSignalSema(SceUID id, int signal)
{
	u32 error;
	Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
	if (s)
	{
		if (s->ns.currentCount + signal - (int) s->waitingThreads.size() > s->ns.maxCount)
		{
			VERBOSE_LOG(SCEKERNEL, "sceKernelSignalSema(%i, %i): overflow (at %i)", id, signal, s->ns.currentCount);
			return SCE_KERNEL_ERROR_SEMA_OVF;
		}

		int oldval = s->ns.currentCount;
		s->ns.currentCount += signal;
		DEBUG_LOG(SCEKERNEL, "sceKernelSignalSema(%i, %i) (count: %i -> %i)", id, signal, oldval, s->ns.currentCount);

		if ((s->ns.attr & PSP_SEMA_ATTR_PRIORITY) != 0)
			std::stable_sort(s->waitingThreads.begin(), s->waitingThreads.end(), __KernelThreadSortPriority);

		bool wokeThreads = false;
retry:
		for (auto iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter)
		{
			if (__KernelUnlockSemaForThread(s, *iter, error, 0, wokeThreads))
			{
				s->waitingThreads.erase(iter);
				goto retry;
			}
		}

		if (wokeThreads)
			hleReSchedule("semaphore signaled");

		hleEatCycles(900);
		return 0;
	}
	else
	{
		DEBUG_LOG(SCEKERNEL, "sceKernelSignalSema(%i, %i): invalid semaphore", id, signal);
		return error;
	}
}
Exemplo n.º 4
0
void __KernelSemaTimeout(u64 userdata, int cycleslate)
{
	SceUID threadID = (SceUID)userdata;
	u32 error;
	SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);

	HLEKernel::WaitExecTimeout<Semaphore, WAITTYPE_SEMA>(threadID);

	// If in FIFO mode, that may have cleared another thread to wake up.
	Semaphore *s = kernelObjects.Get<Semaphore>(uid, error);
	if (s && (s->ns.attr & PSP_SEMA_ATTR_PRIORITY) == PSP_SEMA_ATTR_FIFO) {
		bool wokeThreads;
		std::vector<SceUID>::iterator iter = s->waitingThreads.begin();
		// Unlock every waiting thread until the first that must still wait.
		while (iter != s->waitingThreads.end() && __KernelUnlockSemaForThread(s, *iter, error, 0, wokeThreads)) {
			s->waitingThreads.erase(iter);
			iter = s->waitingThreads.begin();
		}
	}
}
Exemplo n.º 5
0
//int sceKernelSignalSema(SceUID semaid, int signal);
int sceKernelSignalSema(SceUID id, int signal)
{
	u32 error;
	Semaphore *s = kernelObjects.Get<Semaphore>(id, error);
	if (s)
	{
		if (s->ns.currentCount + signal - s->ns.numWaitThreads > s->ns.maxCount)
			return SCE_KERNEL_ERROR_SEMA_OVF;

		int oldval = s->ns.currentCount;
		s->ns.currentCount += signal;
		DEBUG_LOG(HLE, "sceKernelSignalSema(%i, %i) (old: %i, new: %i)", id, signal, oldval, s->ns.currentCount);

		bool wokeThreads = false;
		std::vector<SceUID>::iterator iter, end, best;
retry:
		for (iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter)
		{
			if ((s->ns.attr & PSP_SEMA_ATTR_PRIORITY) != 0)
				best = __KernelSemaFindPriority(s->waitingThreads, iter);
			else
				best = iter;

			if (__KernelUnlockSemaForThread(s, *best, error, 0, wokeThreads))
			{
				s->waitingThreads.erase(best);
				goto retry;
			}
		}

		if (wokeThreads)
			hleReSchedule("semaphore signaled");

		return 0;
	}
	else
	{
		ERROR_LOG(HLE, "sceKernelSignalSema : Trying to signal invalid semaphore %i", id);
		return error;
	}
}