Пример #1
0
s32 sys_event_flag_set(u32 eflag_id, u64 bitptn)
{
	sys_event_flag.Log("sys_event_flag_set(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn);

	EventFlag* ef;
	if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;

	u32 tid = GetCurrentPPUThread().GetId();

	ef->m_mutex.lock(tid);
	ef->flags |= bitptn;
	if (u32 target = ef->check())
	{
		// if signal, leave both mutexes locked...
		ef->signal.lock(target);
		ef->m_mutex.unlock(tid, target);
	}
	else
	{
		ef->m_mutex.unlock(tid);
	}

	return CELL_OK;
}
Пример #2
0
s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 timeout)
{
	sys_event_flag.Log("sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld)",
		eflag_id, bitptn, mode, result.addr(), timeout);

	if (result) *result = 0;

	switch (mode & 0xf)
	{
	case SYS_EVENT_FLAG_WAIT_AND: break;
	case SYS_EVENT_FLAG_WAIT_OR: break;
	default: return CELL_EINVAL;
	}

	switch (mode & ~0xf)
	{
	case 0: break; // ???
	case SYS_EVENT_FLAG_WAIT_CLEAR: break;
	case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
	default: return CELL_EINVAL;
	}

	EventFlag* ef;
	if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;

	const u32 tid = GetCurrentPPUThread().GetId();

	{
		ef->m_mutex.lock(tid);
		if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0)
		{
			ef->m_mutex.unlock(tid);
			return CELL_EPERM;
		}
		EventFlagWaiter rec;
		rec.bitptn = bitptn;
		rec.mode = mode;
		rec.tid = tid;
		ef->waiters.push_back(rec);

		if (ef->check() == tid)
		{
			u64 flags = ef->flags;

			ef->waiters.erase(ef->waiters.end() - 1);

			if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
			{
				ef->flags &= ~bitptn;
			}
			else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
			{
				ef->flags = 0;
			}

			if (result) *result = flags;

			ef->m_mutex.unlock(tid);
			return CELL_OK;
		}
		ef->m_mutex.unlock(tid);
	}

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

	while (true)
	{
		if (ef->signal.unlock(tid, tid) == SMR_OK)
		{
			ef->m_mutex.lock(tid);
			u64 flags = ef->flags;

			for (u32 i = 0; i < ef->waiters.size(); i++)
			{
				if (ef->waiters[i].tid == tid)
				{
					ef->waiters.erase(ef->waiters.begin() + i);

					if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
					{
						ef->flags &= ~bitptn;
					}
					else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
					{
						ef->flags = 0;
					}

					if (u32 target = ef->check())
					{
						// if signal, leave both mutexes locked...
						ef->signal.unlock(tid, target);
						ef->m_mutex.unlock(tid, target);
					}
					else
					{
						ef->signal.unlock(tid);
					}

					if (result) *result = flags;

					ef->m_mutex.unlock(tid);
					return CELL_OK;
				}
			}

			ef->signal.unlock(tid);
			ef->m_mutex.unlock(tid);
			return CELL_ECANCELED;
		}

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

		if (counter++ > max_counter)
		{
			ef->m_mutex.lock(tid);

			for (u32 i = 0; i < ef->waiters.size(); i++)
			{
				if (ef->waiters[i].tid == tid)
				{
					ef->waiters.erase(ef->waiters.begin() + i);
					break;
				}
			}

			ef->m_mutex.unlock(tid);
			return CELL_ETIMEDOUT;
		}
		if (Emu.IsStopped())
		{
			sys_event_flag.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id);
			return CELL_OK;
		}
	}
}
Пример #3
0
void SPUThread::WriteChannel(u32 ch, const u128& r)
{
	const u32 v = r._u32[3];

	switch (ch)
	{
	case SPU_WrOutIntrMbox:
	{
		if (!group) // if RawSPU
		{
			if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v);
			while (!SPU.Out_IntrMBox.Push(v))
			{
				std::this_thread::sleep_for(std::chrono::milliseconds(1));
				if (Emu.IsStopped())
				{
					LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
					return;
				}
			}
			m_intrtag[2].stat |= 1;
			if (CPUThread* t = Emu.GetCPU().GetThread(m_intrtag[2].thread))
			{
				if (t->GetType() == CPU_THREAD_PPU)
				{
					if (t->IsAlive())
					{
						LOG_ERROR(Log::SPU, "%s(%s): interrupt thread was alive", __FUNCTION__, spu_ch_name[ch]);
						Emu.Pause();
						return;
					}
					PPUThread& ppu = *(PPUThread*)t;
					ppu.GPR[3] = ppu.m_interrupt_arg;
					ppu.FastCall2(vm::read32(ppu.entry), vm::read32(ppu.entry + 4));
				}
			}
		}
		else
		{
			const u8 code = v >> 24;
			if (code < 64)
			{
				/* ===== sys_spu_thread_send_event (used by spu_printf) ===== */

				u8 spup = code & 63;

				u32 data;
				if (!SPU.Out_MBox.Pop(data))
				{
					LOG_ERROR(Log::SPU, "sys_spu_thread_send_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
					return;
				}

				if (Ini.HLELogging.GetValue())
				{
					LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
				}

				EventPort& port = SPUPs[spup];

				std::lock_guard<std::mutex> lock(port.m_mutex);

				if (!port.eq)
				{
					LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
					SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing
					return;
				}

				if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
				{
					SPU.In_MBox.PushUncond(CELL_EBUSY);
					return;
				}

				SPU.In_MBox.PushUncond(CELL_OK);
				return;
			}
			else if (code < 128)
			{
				/* ===== sys_spu_thread_throw_event ===== */

				const u8 spup = code & 63;

				u32 data;
				if (!SPU.Out_MBox.Pop(data))
				{
					LOG_ERROR(Log::SPU, "sys_spu_thread_throw_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
					return;
				}

				//if (Ini.HLELogging.GetValue())
				{
					LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
				}

				EventPort& port = SPUPs[spup];

				std::lock_guard<std::mutex> lock(port.m_mutex);

				if (!port.eq)
				{
					LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
					return;
				}

				// TODO: check passing spup value
				if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
				{
					LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data);
					return;
				}

				return;
			}
			else if (code == 128)
			{
				/* ===== sys_event_flag_set_bit ===== */
				u32 flag = v & 0xffffff;

				u32 data;
				if (!SPU.Out_MBox.Pop(data))
				{
					LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
					return;
				}

				if (flag > 63)
				{
					LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag);
					return;
				}

				//if (Ini.HLELogging.GetValue())
				{
					LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag);
				}

				EventFlag* ef;
				if (!Emu.GetIdManager().GetIDData(data, ef))
				{
					LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
					SPU.In_MBox.PushUncond(CELL_ESRCH);
					return;
				}

				u32 tid = GetCurrentCPUThread()->GetId();

				ef->m_mutex.lock(tid);
				ef->flags |= (u64)1 << flag;
				if (u32 target = ef->check())
				{
					// if signal, leave both mutexes locked...
					ef->signal.lock(target);
					ef->m_mutex.unlock(tid, target);
				}
				else
				{
					ef->m_mutex.unlock(tid);
				}

				SPU.In_MBox.PushUncond(CELL_OK);
				return;
			}
			else if (code == 192)
			{
				/* ===== sys_event_flag_set_bit_impatient ===== */
				u32 flag = v & 0xffffff;

				u32 data;
				if (!SPU.Out_MBox.Pop(data))
				{
					LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
					return;
				}

				if (flag > 63)
				{
					LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x): flag > 63", data, v, flag);
					return;
				}

				//if (Ini.HLELogging.GetValue())
				{
					LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag);
				}

				EventFlag* ef;
				if (!Emu.GetIdManager().GetIDData(data, ef))
				{
					LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
					return;
				}

				u32 tid = GetCurrentCPUThread()->GetId();

				ef->m_mutex.lock(tid);
				ef->flags |= (u64)1 << flag;
				if (u32 target = ef->check())
				{
					// if signal, leave both mutexes locked...
					ef->signal.lock(target);
					ef->m_mutex.unlock(tid, target);
				}
				else
				{
					ef->m_mutex.unlock(tid);
				}

				return;
			}
			else
			{
				u32 data;
				if (SPU.Out_MBox.Pop(data))
				{
					LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data);
				}
				else
				{
					LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x)", v);
				}
				SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
				return;
			}
		}
		break;
	}

	case SPU_WrOutMbox:
	{
		while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
		break;
	}

	case MFC_WrTagMask:
	{
		MFC1.QueryMask.SetValue(v);
		break;
	}

	case MFC_WrTagUpdate:
	{
		MFC1.TagStatus.PushUncond(MFC1.QueryMask.GetValue());
		break;
	}

	case MFC_LSA:
	{
		MFC1.LSA.SetValue(v);
		break;
	}

	case MFC_EAH:
	{
		MFC1.EAH.SetValue(v);
		break;
	}

	case MFC_EAL:
	{
		MFC1.EAL.SetValue(v);
		break;
	}

	case MFC_Size:
	{
		MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & 0xffff) | (v << 16));
		break;
	}

	case MFC_TagID:
	{
		MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff));
		break;
	}


	case MFC_Cmd:
	{
		MFC1.CMDStatus.SetValue(v);
		EnqMfcCmd(MFC1);
		break;
	}

	case MFC_WrListStallAck:
	{
		if (v >= 32)
		{
			LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: invalid tag(%d)", v);
			return;
		}
		StalledList temp = StallList[v];
		if (!temp.MFCArgs)
		{
			LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: empty tag(%d)", v);
			return;
		}
		StallList[v].MFCArgs = nullptr;
		ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs);
		break;
	}

	case SPU_WrDec:
	{
		m_dec_start = get_time();
		m_dec_value = v;
		break;
	}

	case SPU_WrEventMask:
	{
		m_event_mask = v;
		if (v & ~(SPU_EVENT_IMPLEMENTED)) LOG_ERROR(Log::SPU, "SPU_WrEventMask: unsupported event masked (0x%x)");
		break;
	}

	case SPU_WrEventAck:
	{
		m_events &= ~v;
		break;
	}

	default:
	{
		LOG_ERROR(Log::SPU, "%s error (v=0x%x): unknown/illegal channel (%d [%s]).", __FUNCTION__, v, ch, spu_ch_name[ch]);
		break;
	}
	}

	if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
}
Пример #4
0
int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 timeout)
{
	sys_event_flag.Warning("sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld)",
		eflag_id, bitptn, mode, result.GetAddr(), timeout);

	if (result.IsGood()) result = 0;

	switch (mode & 0xf)
	{
	case SYS_EVENT_FLAG_WAIT_AND: break;
	case SYS_EVENT_FLAG_WAIT_OR: break;
	default: return CELL_EINVAL;
	}

	switch (mode & ~0xf)
	{
	case 0: break; // ???
	case SYS_EVENT_FLAG_WAIT_CLEAR: break;
	case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
	default: return CELL_EINVAL;
	}

	EventFlag* ef;
	if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;

	u32 tid = GetCurrentPPUThread().GetId();

	{
		SMutexLocker lock(ef->m_mutex);
		if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.GetCount() > 0)
		{
			return CELL_EPERM;
		}
		EventFlagWaiter rec;
		rec.bitptn = bitptn;
		rec.mode = mode;
		rec.tid = tid;
		ef->waiters.AddCpy(rec);

		if (ef->check() == tid)
		{
			u64 flags = ef->flags;

			ef->waiters.RemoveAt(ef->waiters.GetCount() - 1);

			if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
			{
				ef->flags &= ~bitptn;
			}
			else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
			{
				ef->flags = 0;
			}

			if (result.IsGood())
			{
				result = flags;
				return CELL_OK;
			}

			if (!result.GetAddr())
			{
				return CELL_OK;
			}
			return CELL_EFAULT;
		}
	}

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

	while (true)
	{
		if (ef->signal.GetOwner() == tid)
		{
			SMutexLocker lock(ef->m_mutex);

			ef->signal.unlock(tid);

			u64 flags = ef->flags;

			for (u32 i = 0; i < ef->waiters.GetCount(); i++)
			{
				if (ef->waiters[i].tid == tid)
				{
					ef->waiters.RemoveAt(i);

					if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
					{
						ef->flags &= ~bitptn;
					}
					else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
					{
						ef->flags = 0;
					}

					if (result.IsGood())
					{
						result = flags;
						return CELL_OK;
					}

					if (!result.GetAddr())
					{
						return CELL_OK;
					}
					return CELL_EFAULT;
				}
			}

			return CELL_ECANCELED;
		}

		Sleep(1);

		if (counter++ > max_counter)
		{
			SMutexLocker lock(ef->m_mutex);

			for (u32 i = 0; i < ef->waiters.GetCount(); i++)
			{
				if (ef->waiters[i].tid == tid)
				{
					ef->waiters.RemoveAt(i);
					break;
				}
			}
			
			return CELL_ETIMEDOUT;
		}
		if (Emu.IsStopped())
		{
			ConLog.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id);
			return CELL_OK;
		}
	}
}