Ejemplo n.º 1
0
int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond)
{
	sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr());

	if (!lwcond.IsGood())
	{
		return CELL_EFAULT;
	}

	SleepQueue* sq;
	if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
	{
		return CELL_ESRCH;
	}

	mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
	be_t<u32> tid = GetCurrentPPUThread().GetId();

	if (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop()))
	{
		if (mutex->mutex.owner.trylock(target) != SMR_OK)
		{
			mutex->mutex.owner.lock(tid);
			mutex->recursive_count = 1;
			mutex->mutex.owner.unlock(tid, target);
		}
	}

	if (Emu.IsStopped())
	{
		ConLog.Warning("sys_lwcond_signal(sq=%d) aborted", (u32)lwcond->lwcond_queue);
	}

	return CELL_OK;
}
Ejemplo n.º 2
0
int sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout)
{
	switch (int res = trylock(tid))
	{
	case static_cast<int>(CELL_EBUSY): break;
	default: return res;
	}

	SleepQueue* sq;
	if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH;

	switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK))
	{
	case se32(SYS_SYNC_PRIORITY):
	case se32(SYS_SYNC_FIFO):
		sq->push(tid);
	default: break;
	}

	switch (mutex.lock(tid, timeout))
	{
	case SMR_OK:
		sq->invalidate(tid);
	case SMR_SIGNAL:
		recursive_count = 1; return CELL_OK;
	case SMR_TIMEOUT:
		sq->invalidate(tid); return CELL_ETIMEDOUT;
	case SMR_ABORT:
		if (Emu.IsStopped()) ConLog.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue);
	default:
		sq->invalidate(tid); return CELL_EINVAL;
	}
}
Ejemplo n.º 3
0
int sys_lwcond_destroy(mem_ptr_t<sys_lwcond_t> lwcond)
{
	sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.GetAddr());

	if (!lwcond.IsGood())
	{
		return CELL_EFAULT;
	}

	u32 lwc = lwcond->lwcond_queue;

	SleepQueue* sq;
	if (!Emu.GetIdManager().GetIDData(lwc, sq))
	{
		return CELL_ESRCH;
	}

	if (!sq->finalize())
	{
		return CELL_EBUSY;
	}

	Emu.GetIdManager().RemoveID(lwc);
	return CELL_OK;
}
Ejemplo n.º 4
0
int sys_lwmutex_t::unlock(be_t<u32> tid)
{
	if (mutex.unlock(tid, tid) != SMR_OK)
	{
		return CELL_EPERM;
	}
	else
	{
		if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE))))
		{
			sc_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)recursive_count);
			recursive_count = 1;
		}
		recursive_count -= 1;
		if (!recursive_count.ToBE())
		{
			be_t<u32> target = 0;
			switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK))
			{
			case se32(SYS_SYNC_FIFO):
			case se32(SYS_SYNC_PRIORITY):
				SleepQueue* sq;
				if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH;
				target = attribute & SYS_SYNC_FIFO ? sq->pop() : sq->pop_prio();
			case se32(SYS_SYNC_RETRY): break;
			}
			if (target) mutex.unlock(tid, target);
			else mutex.unlock(tid);
		}
		return CELL_OK;
	}
}
Ejemplo n.º 5
0
u32 EventFlag::check()
{
	SleepQueue sq; // TODO: implement without SleepQueue

	u32 target = 0;

	for (u32 i = 0; i < waiters.size(); i++)
	{
		if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & waiters[i].bitptn) == waiters[i].bitptn) ||
			((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & waiters[i].bitptn)))
		{
			if (m_protocol == SYS_SYNC_FIFO)
			{
				target = waiters[i].tid;
				break;
			}
			sq.list.push_back(waiters[i].tid);
		}
	}

	if (m_protocol == SYS_SYNC_PRIORITY)
		target = sq.pop_prio();

	return target;
}
Ejemplo n.º 6
0
int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
{
	sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.GetAddr(), timeout);

	if (!lwcond.IsGood())
	{
		return CELL_EFAULT;
	}

	SleepQueue* sq;
	if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
	{
		return CELL_ESRCH;
	}

	mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
	u32 tid_le = GetCurrentPPUThread().GetId();
	be_t<u32> tid = tid_le;

	if (mutex->mutex.owner.GetOwner() != tid)
	{
		return CELL_EPERM; // caller must own this lwmutex
	}

	sq->push(tid_le);

	mutex->recursive_count = 0;
	mutex->mutex.owner.unlock(tid);

	u32 counter = 0;
	const u32 max_counter = timeout ? (timeout / 1000) : ~0;
	while (true)
	{
		/* switch (mutex->trylock(tid))
		{
		case SMR_OK: mutex->unlock(tid); break;
		case SMR_SIGNAL: return CELL_OK;
		} */
		if (mutex->mutex.owner.GetOwner() == tid)
		{
			_mm_mfence();
			mutex->recursive_count = 1;
			return CELL_OK;
		}

		Sleep(1);

		if (counter++ > max_counter)
		{
			sq->invalidate(tid_le);
			return CELL_ETIMEDOUT;
		}
		if (Emu.IsStopped())
		{
			ConLog.Warning("sys_lwcond_wait(sq=%d) aborted", (u32)lwcond->lwcond_queue);
			return CELL_OK;
		}
	}
}
Ejemplo n.º 7
0
int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
{
	sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.GetAddr(), ppu_thread_id);

	if (!lwcond.IsGood())
	{
		return CELL_EFAULT;
	}

	SleepQueue* sq;
	if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
	{
		return CELL_ESRCH;
	}

	if (!sq->invalidate(ppu_thread_id))
	{
		return CELL_EPERM;
	}

	mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
	be_t<u32> tid = GetCurrentPPUThread().GetId();

	be_t<u32> target = ppu_thread_id;

	if (mutex->mutex.owner.trylock(target) != SMR_OK)
	{
		mutex->mutex.owner.lock(tid);
		mutex->recursive_count = 1;
		mutex->mutex.owner.unlock(tid, target);
	}

	if (Emu.IsStopped())
	{
		ConLog.Warning("sys_lwcond_signal_to(sq=%d, to=%d) aborted", (u32)lwcond->lwcond_queue, ppu_thread_id);
	}

	return CELL_OK;
}
Ejemplo n.º 8
0
s32 sys_lwcond_wait(vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
{
	sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout);

	Lwcond* lw;
	if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
	{
		return CELL_ESRCH;
	}

	auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr());
	u32 tid_le = GetCurrentPPUThread().GetId();
	be_t<u32> tid = be_t<u32>::make(tid_le);

	SleepQueue* sq = nullptr;
	Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq);

	if (mutex->mutex.GetOwner() != tid)
	{
		sys_lwcond.Warning("sys_lwcond_wait(id=%d) failed (EPERM)", (u32)lwcond->lwcond_queue);
		return CELL_EPERM; // caller must own this lwmutex
	}

	lw->m_queue.push(tid_le);

	if (mutex->recursive_count.ToBE() != se32(1))
	{
		sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had wrong recursive value (%d)",
			(u32)lwcond->lwcond_queue, (u32)mutex->recursive_count);
	}
	mutex->recursive_count = 0;

	if (sq)
	{
		mutex->mutex.unlock(tid, be_t<u32>::make(mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop()));
	}
	else if (mutex->attribute.ToBE() == se32(SYS_SYNC_RETRY))
	{
		mutex->mutex.unlock(tid); // SYS_SYNC_RETRY
	}
	else
	{
		sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)",
			(u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
	}

	u64 counter = 0;
	const u64 max_counter = timeout ? (timeout / 1000) : ~0;

	while (true)
	{
		if (lw->signal.unlock(tid, tid) == SMR_OK)
		{
			switch (mutex->lock(tid, 0))
			{
			case CELL_OK: break;
			case static_cast<int>(CELL_EDEADLK): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex was locked",
								   (u32)lwcond->lwcond_queue); return CELL_OK;
			case static_cast<int>(CELL_ESRCH): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex not found (%d)",
								 (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); return CELL_ESRCH;
			case static_cast<int>(CELL_EINVAL): goto abort;
			}

			mutex->recursive_count = 1;
			lw->signal.unlock(tid);
			return CELL_OK;
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(1));

		if (counter++ > max_counter)
		{
			lw->m_queue.invalidate(tid_le);
			return CELL_ETIMEDOUT;
		}
		if (Emu.IsStopped())
		{
			goto abort;
		}
	}

abort:
	sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue);
	return CELL_OK;
}