Example #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<named_thread<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_ctrl::notify(*thread);

		// Dirty hack for sound: confirm the creation of _mxr000 event queue
		if (thread->ppu_name.get() == "_cellsurMixerMain"sv)
		{
			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);
			}))
			{
				if (ppu.is_stopped())
				{
					return 0;
				}

				thread_ctrl::wait_for(50000);
			}

			if (ppu.test_stopped())
			{
				return 0;
			}
		}
	}

	return CELL_OK;
}
Example #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<named_thread<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.ptr)();

	if (ppu.test_stopped())
	{
		return 0;
	}

	// Cleanup
	idm::remove<named_thread<ppu_thread>>(thread->id);

	if (!vptr)
	{
		return CELL_EFAULT;
	}

	// Get the exit status from the register
	*vptr = thread->gpr[3];
	return CELL_OK;
}