int sys_semaphore_trywait(u32 sem_id) { sys_sem.Log("sys_semaphore_trywait(sem_id=%d)", sem_id); Semaphore* sem; if (!Emu.GetIdManager().GetIDData(sem_id, sem)) { return CELL_ESRCH; } std::lock_guard<std::mutex> lock(sem->m_mutex); if (sem->m_value > 0) { sem->m_value--; return CELL_OK; } else { return CELL_EBUSY; } }
//175 s32 sys_spu_thread_group_resume(u32 id) { sc_spu.Log("sys_spu_thread_group_resume(id=%d)", id); SpuGroupInfo* group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; } // TODO: check group state for (u32 i = 0; i < group_info->list.size(); i++) { if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) { t->Resume(); } } return CELL_OK; }
//166 int sys_spu_thread_set_argument(u32 id, mem_ptr_t<sys_spu_thread_argument> arg) { sc_spu.Warning("sys_spu_thread_set_argument(id=0x%x, arg_addr=0x%x)", id, arg.GetAddr()); CPUThread* thr = Emu.GetCPU().GetThread(id); if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) { return CELL_ESRCH; } if(!arg.IsGood()) { return CELL_EFAULT; } thr->SetArg(0, arg->arg1); thr->SetArg(1, arg->arg2); thr->SetArg(2, arg->arg3); thr->SetArg(3, arg->arg4); return CELL_OK; }
s32 sys_interrupt_tag_destroy(u32 intrtag) { sys_interrupt.Warning("sys_interrupt_tag_destroy(intrtag=0x%x)", intrtag); LV2_LOCK; const auto tag = idm::get<lv2_int_tag_t>(intrtag); if (!tag) { return CELL_ESRCH; } if (tag->handler) { return CELL_EBUSY; } idm::remove<lv2_int_tag_t>(intrtag); return CELL_OK; }
s32 _sys_lwmutex_destroy(u32 lwmutex_id) { sys_lwmutex.Warning("_sys_lwmutex_destroy(lwmutex_id=0x%x)", lwmutex_id); LV2_LOCK; const auto mutex = Emu.GetIdManager().get<lv2_lwmutex_t>(lwmutex_id); if (!mutex) { return CELL_ESRCH; } if (!mutex->sq.empty()) { return CELL_EBUSY; } Emu.GetIdManager().remove<lv2_lwmutex_t>(lwmutex_id); return CELL_OK; }
s32 sys_cond_signal(u32 cond_id) { sys_cond.Log("sys_cond_signal(cond_id=%d)", cond_id); LV2_LOCK; std::shared_ptr<cond_t> cond; if (!Emu.GetIdManager().GetIDData(cond_id, cond)) { return CELL_ESRCH; } if (cond->waiters) { cond->signaled++; cond->waiters--; cond->cv.notify_one(); } return CELL_OK; }
s32 sys_cond_destroy(u32 cond_id) { sys_cond.Warning("sys_cond_destroy(cond_id=%d)", cond_id); LV2_LOCK(0); Cond* cond; if (!Emu.GetIdManager().GetIDData(cond_id, cond)) { return CELL_ESRCH; } if (!cond->m_queue.finalize()) { return CELL_EBUSY; } cond->mutex->cond_count--; Emu.GetIdManager().RemoveID(cond_id); Emu.GetSyncPrimManager().EraseSyncPrimData(TYPE_COND, cond_id); return CELL_OK; }
s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask) { sys_spu.Log("sys_raw_spu_set_int_mask(id=%d, class_id=%d, mask=0x%llx)", id, class_id, mask); if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } const auto thread = Emu.GetCPU().GetRawSPUThread(id); if (!thread) { return CELL_ESRCH; } auto& tag = class_id ? thread->int2 : thread->int0; tag.mask.exchange(mask); return CELL_OK; }
s32 sys_event_port_destroy(u32 eport_id) { sys_event.warning("sys_event_port_destroy(eport_id=0x%x)", eport_id); LV2_LOCK; const auto port = idm::get<lv2_event_port_t>(eport_id); if (!port) { return CELL_ESRCH; } if (!port->queue.expired()) { return CELL_EISCONN; } idm::remove<lv2_event_port_t>(eport_id); return CELL_OK; }
s32 _sys_lwmutex_trylock(u32 lwmutex_id) { sys_lwmutex.Log("_sys_lwmutex_trylock(lwmutex_id=0x%x)", lwmutex_id); LV2_LOCK; const auto mutex = Emu.GetIdManager().get<lv2_lwmutex_t>(lwmutex_id); if (!mutex) { return CELL_ESRCH; } if (!mutex->sq.empty() || !mutex->signaled) { return CELL_EBUSY; } mutex->signaled--; return CELL_OK; }
s32 sys_rwlock_destroy(u32 rw_lock_id) { sys_rwlock.Warning("sys_rwlock_destroy(rw_lock_id=0x%x)", rw_lock_id); LV2_LOCK; const auto rwlock = idm::get<lv2_rwlock_t>(rw_lock_id); if (!rwlock) { return CELL_ESRCH; } if (rwlock->readers || rwlock->writer || rwlock->rsq.size() || rwlock->wsq.size()) { return CELL_EBUSY; } idm::remove<lv2_rwlock_t>(rw_lock_id); return CELL_OK; }
s32 sys_event_flag_destroy(u32 id) { sys_event_flag.Warning("sys_event_flag_destroy(id=0x%x)", id); LV2_LOCK; const auto eflag = idm::get<lv2_event_flag_t>(id); if (!eflag) { return CELL_ESRCH; } if (!eflag->sq.empty()) { return CELL_EBUSY; } idm::remove<lv2_event_flag_t>(id); return CELL_OK; }
s32 sys_cond_signal(u32 cond_id) { sys_cond.Log("sys_cond_signal(cond_id=0x%x)", cond_id); LV2_LOCK; const auto cond = Emu.GetIdManager().get<lv2_cond_t>(cond_id); if (!cond) { return CELL_ESRCH; } // signal one waiting thread; protocol is ignored in current implementation if (!cond->sq.empty()) { cond->notify(lv2_lock, cond->sq.begin()); cond->sq.pop_front(); } return CELL_OK; }
s32 sys_timer_usleep(u64 sleep_time) { sys_timer.trace("sys_timer_usleep(sleep_time=0x%llx)", sleep_time); const u64 start_time = get_system_time(); u64 passed; while (sleep_time > (passed = get_system_time() - start_time) + 1000) { CHECK_EMU_STATUS; std::this_thread::sleep_for(std::chrono::milliseconds(1)); } if (sleep_time > passed) { std::this_thread::sleep_for(std::chrono::microseconds(sleep_time - passed)); } return CELL_OK; }
s32 sys_timer_destroy(u32 timer_id) { sys_timer.warning("sys_timer_destroy(timer_id=0x%x)", timer_id); LV2_LOCK; const auto timer = idm::get<lv2_timer_t>(timer_id); if (!timer) { return CELL_ESRCH; } if (!timer->port.expired()) { return CELL_EISCONN; } idm::remove<lv2_timer_t>(timer_id); return CELL_OK; }
s32 sys_raw_spu_set_int_stat(u32 id, u32 class_id, u64 stat) { sys_spu.Log("sys_raw_spu_set_int_stat(id=%d, class_id=%d, stat=0x%llx)", id, class_id, stat); if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } const auto thread = Emu.GetCPU().GetRawSPUThread(id); if (!thread) { return CELL_ESRCH; } auto& tag = class_id ? thread->int2 : thread->int0; tag.clear(stat); return CELL_OK; }
s32 sys_raw_spu_get_int_stat(u32 id, u32 class_id, vm::ptr<u64> stat) { sys_spu.Log("sys_raw_spu_get_int_stat(id=%d, class_id=%d, stat=*0x%x)", id, class_id, stat); if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } const auto thread = Emu.GetCPU().GetRawSPUThread(id); if (!thread) { return CELL_ESRCH; } auto& tag = class_id ? thread->int2 : thread->int0; *stat = tag.stat.load(); return CELL_OK; }
s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array, s32 size, vm::ptr<u32> number) { sys_event.Log("sys_event_queue_tryreceive(equeue_id=0x%x, event_array=*0x%x, size=%d, number=*0x%x)", equeue_id, event_array, size, number); LV2_LOCK; const auto queue = idm::get<lv2_event_queue_t>(equeue_id); if (!queue) { return CELL_ESRCH; } if (size < 0) { throw EXCEPTION("Negative size"); } if (queue->type != SYS_PPU_QUEUE) { return CELL_EINVAL; } s32 count = 0; while (queue->sq.empty() && count < size && queue->events.size()) { auto& dest = event_array[count++]; std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front(); queue->events.pop_front(); } *number = count; return CELL_OK; }
//178 s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status) { sc_spu.Warning("sys_spu_thread_group_join(id=%d, cause_addr=0x%x, status_addr=0x%x)", id, cause.GetAddr(), status.GetAddr()); SpuGroupInfo* group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; } if (group_info->lock.exchange(1)) // acquire lock { return CELL_EBUSY; } cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT; status = 0; //unspecified because of ALL_THREADS_EXIT for (u32 i = 0; i < group_info->list.size(); i++) { while (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) { if (!t->IsRunning()) { break; } if (Emu.IsStopped()) { LOG_WARNING(Log::SPU, "sys_spu_thread_group_join(id=%d, ...) aborted", id); return CELL_OK; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } group_info->lock = 0; // release lock return CELL_OK; }
s32 sys_interrupt_thread_establish(vm::ptr<be_t<u32>> ih, u32 intrtag, u64 intrthread, u64 arg) { sys_interrupt.Warning("sys_interrupt_thread_establish(ih_addr=0x%x, intrtag=%d, intrthread=%lld, arg=0x%llx)", ih.addr(), intrtag, intrthread, arg); u32 id = intrtag & 0xff; u32 class_id = intrtag >> 8; RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); if (!t || class_id > 2 || class_id == 1) { return CELL_ESRCH; } if (!t->m_intrtag[class_id].enabled) { return CELL_ESRCH; } if (t->m_intrtag[class_id].thread) // ??? { return CELL_ESTAT; } CPUThread* it = Emu.GetCPU().GetThread(intrthread); if (!it) { return CELL_ESRCH; } if (it->m_has_interrupt || !it->m_is_interrupt) { return CELL_EAGAIN; } *ih = (t->m_intrtag[class_id].thread = intrthread); it->m_interrupt_arg = arg; return CELL_OK; }
s32 sys_event_queue_destroy(u32 equeue_id, s32 mode) { sys_event.Warning("sys_event_queue_destroy(equeue_id=0x%x, mode=%d)", equeue_id, mode); LV2_LOCK; const auto queue = Emu.GetIdManager().get<lv2_event_queue_t>(equeue_id); if (!queue) { return CELL_ESRCH; } if (mode && mode != SYS_EVENT_QUEUE_DESTROY_FORCE) { return CELL_EINVAL; } if (!mode && queue->waiters) { return CELL_EBUSY; } if (queue->cancelled.exchange(true)) { throw EXCEPTION("Unexpected value"); } if (queue->waiters) { queue->cv.notify_all(); } Emu.GetEventManager().UnregisterKey(queue->key); Emu.GetIdManager().remove<lv2_event_queue_t>(equeue_id); return CELL_OK; }
s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_data> event_array, int size, vm::ptr<be_t<u32>> number) { sys_event.Todo("sys_event_queue_tryreceive(equeue_id=%d, event_array_addr=0x%x, size=%d, number_addr=0x%x)", equeue_id, event_array.addr(), size, number.addr()); EventQueue* eq; if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) { return CELL_ESRCH; } if (eq->type != SYS_PPU_QUEUE) { return CELL_EINVAL; } if (size == 0) { *number = 0; return CELL_OK; } u32 tid = GetCurrentPPUThread().GetId(); eq->sq.m_mutex.lock(); eq->owner.lock(tid); if (eq->sq.list.size()) { *number = 0; eq->owner.unlock(tid); eq->sq.m_mutex.unlock(); return CELL_OK; } *number = eq->events.pop_all(event_array.get_ptr(), size); eq->owner.unlock(tid); eq->sq.m_mutex.unlock(); return CELL_OK; }
//173 int sys_spu_thread_group_start(u32 id) { sc_spu.Warning("sys_spu_thread_group_start(id=0x%x)", id); if(!Emu.GetIdManager().CheckID(id)) { return CELL_ESRCH; } ID& id_data = Emu.GetIdManager().GetIDData(id); SpuGroupInfo& group_info = *(SpuGroupInfo*)id_data.m_data; //Emu.Pause(); for(int i=0; i<g_spu_group_thr_count; i++) { if(group_info.threads[i]) { group_info.threads[i]->Exec(); } } return CELL_OK; }
s32 sys_raw_spu_get_int_stat(u32 id, u32 class_id, mem64_t stat) { sc_spu.Log("sys_raw_spu_get_int_stat(id=%d, class_id=%d, stat_addr=0xx)", id, class_id, stat.GetAddr()); if (!stat.IsGood()) { return CELL_EFAULT; } RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); if (!t) { return CELL_ESRCH; } if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } stat = t->m_intrtag[class_id].stat; return CELL_OK; }
s32 sys_raw_spu_get_int_mask(u32 id, u32 class_id, mem64_t mask) { sc_spu.Log("sys_raw_spu_get_int_mask(id=%d, class_id=%d, mask_addr=0x%x)", id, class_id, mask.GetAddr()); if (!mask.IsGood()) { return CELL_EFAULT; } RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); if (!t) { return CELL_ESRCH; } if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } mask = t->m_intrtag[class_id].mask; return CELL_OK; }
//173 int sys_spu_thread_group_start(u32 id) { sc_spu.Warning("sys_spu_thread_group_start(id=%d)", id); SpuGroupInfo* group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; } // TODO: check group state for (u32 i = 0; i < group_info->list.size(); i++) { CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]); if (t) { t->Exec(); } } return CELL_OK; }
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond) { sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.addr()); LV2_LOCK(0); u32 id = lwcond->lwcond_queue; Lwcond* lw; if (!Emu.GetIdManager().GetIDData(id, lw)) { return CELL_ESRCH; } if (!lw->m_queue.finalize()) { return CELL_EBUSY; } Emu.GetIdManager().RemoveID(id); Emu.GetSyncPrimManager().EraseSyncPrimData(TYPE_LWCOND, id); return CELL_OK; }
s32 sys_timer_disconnect_event_queue(u32 timer_id) { sys_timer.Warning("sys_timer_disconnect_event_queue(timer_id=0x%x)", timer_id); LV2_LOCK; const auto timer = idm::get<lv2_timer_t>(timer_id); if (!timer) { return CELL_ESRCH; } if (timer->port.expired()) { return CELL_ENOTCONN; } timer->port.reset(); // disconnect event queue timer->state = SYS_TIMER_STATE_STOP; // stop timer return CELL_OK; }
//171 int sys_spu_thread_group_destroy(u32 id) { sc_spu.Warning("sys_spu_thread_group_destroy(id=%d)", id); SpuGroupInfo* group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; } if (group_info->lock) // ??? { return CELL_EBUSY; } for (u32 i = 0; i < group_info->list.GetCount(); i++) { Emu.GetCPU().RemoveThread(group_info->list[i]); } Emu.GetIdManager().RemoveID(id); return CELL_OK; }
s32 sys_cond_signal_all(u32 cond_id) { sys_cond.Log("sys_cond_signal_all(cond_id=0x%x)", cond_id); LV2_LOCK; const auto cond = Emu.GetIdManager().get<lv2_cond_t>(cond_id); if (!cond) { return CELL_ESRCH; } // signal all waiting threads; protocol is ignored in current implementation for (auto it = cond->sq.begin(); it != cond->sq.end(); it++) { cond->notify(lv2_lock, it); } cond->sq.clear(); return CELL_OK; }