Пример #1
0
error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id)
{
	sys_ppu_thread.trace("sys_ppu_thread_start(thread_id=0x%x)", thread_id);

	const auto thread = idm::get<ppu_thread>(thread_id, [&](ppu_thread& thread)
	{
		lv2_obj::awake(thread, -2);
	});

	if (!thread)
	{
		return CELL_ESRCH;
	}

	if (!thread->state.test_and_reset(cpu_flag::stop))
	{
		// TODO: what happens there?
		return CELL_EPERM;
	}
	else
	{
		thread->notify();

		// Dirty hack for sound: confirm the creation of _mxr000 event queue
		if (thread->m_name == "_cellsurMixerMain")
		{
			lv2_obj::sleep(ppu);

			while (!idm::select<lv2_obj, lv2_event_queue>([](u32, lv2_event_queue& eq)
			{
				//some games do not set event queue name, though key seems constant for them
				return (eq.name == "_mxr000\0"_u64) || (eq.key == 0x8000cafe02460300);
			}))
			{
				thread_ctrl::wait_for(50000);
			}

			ppu.test_state();
		}
	}

	return CELL_OK;
}
Пример #2
0
error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr)
{
	vm::temporary_unlock(ppu);

	sys_ppu_thread.trace("sys_ppu_thread_join(thread_id=0x%x, vptr=*0x%x)", thread_id, vptr);

	const auto thread = idm::get<ppu_thread>(thread_id, [&](ppu_thread& thread) -> CellError
	{
		CellError result = thread.joiner.atomic_op([&](u32& value) -> CellError
		{
			if (value == -3)
			{
				value = -2;
				return CELL_EBUSY;
			}

			if (value == -2)
			{
				return CELL_ESRCH;
			}

			if (value)
			{
				return CELL_EINVAL;
			}

			// TODO: check precedence?
			if (&ppu == &thread)
			{
				return CELL_EDEADLK;
			}

			value = ppu.id;
			return {};
		});

		if (!result)
		{
			lv2_obj::sleep(ppu);
		}

		return result;
	});

	if (!thread)
	{
		return CELL_ESRCH;
	}

	if (thread.ret && thread.ret != CELL_EBUSY)
	{
		return thread.ret;
	}

	// Wait for cleanup
	thread->join();

	// Get the exit status from the register
	if (vptr)
	{
		ppu.test_state();
		*vptr = thread->gpr[3];
	}

	// Cleanup
	idm::remove<ppu_thread>(thread->id);
	return CELL_OK;
}