int sceKernelCancelReceiveMbx(SceUID id, u32 numWaitingThreadsAddr) { u32 error; Mbx *m = kernelObjects.Get<Mbx>(id, error); if (!m) { ERROR_LOG(HLE, "sceKernelCancelReceiveMbx(%i, %08x): invalid mbx id", id, numWaitingThreadsAddr); return error; } u32 count = (u32) m->waitingThreads.size(); DEBUG_LOG(HLE, "sceKernelCancelReceiveMbx(%i, %08x): cancelling %d threads", id, numWaitingThreadsAddr, count); bool wokeThreads = false; for (size_t i = 0; i < m->waitingThreads.size(); i++) __KernelUnlockMbxForThread(m, m->waitingThreads[i], error, SCE_KERNEL_ERROR_WAIT_CANCEL, wokeThreads); m->waitingThreads.clear(); if (wokeThreads) hleReSchedule("mbx canceled"); if (numWaitingThreadsAddr) Memory::Write_U32(count, numWaitingThreadsAddr); return 0; }
static bool __KernelUnlockMbxForThreadCheck(Mbx *m, MbxWaitingThread &waitData, u32 &error, int result, bool &wokeThreads) { if (m->nmb.numMessages > 0 && __KernelUnlockMbxForThread(m, waitData, error, 0, wokeThreads)) { m->ReceiveMessage(waitData.packetAddr); return true; } return false; }
int sceKernelDeleteMbx(SceUID id) { u32 error; Mbx *m = kernelObjects.Get<Mbx>(id, error); if (m) { DEBUG_LOG(HLE, "sceKernelDeleteMbx(%i)", id); bool wokeThreads = false; for (size_t i = 0; i < m->waitingThreads.size(); i++) __KernelUnlockMbxForThread(m, m->waitingThreads[i], error, SCE_KERNEL_ERROR_WAIT_DELETE, wokeThreads); m->waitingThreads.clear(); if (wokeThreads) hleReSchedule("mbx deleted"); } else { ERROR_LOG(HLE, "sceKernelDeleteMbx(%i): invalid mbx id", id); } return kernelObjects.Destroy<Mbx>(id); }
int sceKernelSendMbx(SceUID id, u32 packetAddr) { u32 error; Mbx *m = kernelObjects.Get<Mbx>(id, error); if (!m) { ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): invalid mbx id", id, packetAddr); return error; } NativeMbxPacket *addPacket = (NativeMbxPacket*)Memory::GetPointer(packetAddr); if (addPacket == 0) { ERROR_LOG(HLE, "sceKernelSendMbx(%i, %08x): invalid packet address", id, packetAddr); return -1; } // If the queue is empty, maybe someone is waiting. // We have to check them first, they might've timed out. if (m->nmb.numMessages == 0) { bool wokeThreads = false; std::vector<MbxWaitingThread>::iterator iter; while (!wokeThreads && !m->waitingThreads.empty()) { if ((m->nmb.attr & SCE_KERNEL_MBA_THPRI) != 0) iter = __KernelMbxFindPriority(m->waitingThreads); else iter = m->waitingThreads.begin(); MbxWaitingThread t = *iter; __KernelUnlockMbxForThread(m, t, error, 0, wokeThreads); m->waitingThreads.erase(iter); if (wokeThreads) { DEBUG_LOG(HLE, "sceKernelSendMbx(%i, %08x): threads waiting, resuming %d", id, packetAddr, t.first); Memory::Write_U32(packetAddr, t.second); hleReSchedule("mbx sent"); // We don't need to do anything else, finish here. return 0; } } } DEBUG_LOG(HLE, "sceKernelSendMbx(%i, %08x): no threads currently waiting, adding message to queue", id, packetAddr); if (m->nmb.numMessages == 0) m->AddInitialMessage(packetAddr); else { u32 next = m->nmb.packetListHead, prev; for (int i = 0, n = m->nmb.numMessages; i < n; i++) { if (next == packetAddr) return PSP_MBX_ERROR_DUPLICATE_MSG; if (!Memory::IsValidAddress(next)) return SCE_KERNEL_ERROR_ILLEGAL_ADDR; prev = next; next = Memory::Read_U32(next); } bool inserted = false; if (m->nmb.attr & SCE_KERNEL_MBA_MSPRI) { NativeMbxPacket p; for (int i = 0, n = m->nmb.numMessages; i < n; i++) { Memory::ReadStruct<NativeMbxPacket>(next, &p); if (addPacket->priority < p.priority) { if (i == 0) m->AddFirstMessage(prev, packetAddr); else m->AddMessage(prev, next, packetAddr); inserted = true; break; } prev = next; next = Memory::Read_U32(next); } } if (!inserted) m->AddLastMessage(prev, packetAddr); } return 0; }