public virtual int sceKernelCreateMsgPipe(string name, int partitionid, int attr, int size, TPointer option) { if (option.NotNull) { int optionSize = option.getValue32(); Console.WriteLine(string.Format("sceKernelCreateMsgPipe option at {0}, size={1:D}", option, optionSize)); } int memType = PSP_SMEM_Low; if ((attr & PSP_MPP_ATTR_ADDR_HIGH) == PSP_MPP_ATTR_ADDR_HIGH) { memType = PSP_SMEM_High; } SceKernelMppInfo info = new SceKernelMppInfo(name, partitionid, attr, size, memType); if (!info.MemoryAllocated) { Console.WriteLine(string.Format("sceKernelCreateMsgPipe name='{0}', partitionId={1:D}, attr=0x{2:X}, size=0x{3:X}, option={4} not enough memory", name, partitionid, attr, size, option)); info.delete(); return(SceKernelErrors.ERROR_KERNEL_NO_MEMORY); } //if (log.DebugEnabled) { Console.WriteLine(string.Format("sceKernelCreateMsgPipe returning {0}", info)); } msgMap[info.uid] = info; return(info.uid); }
public virtual int sceKernelReferMsgPipeStatus(int uid, TPointer infoAddr) { SceKernelMppInfo info = msgMap[uid]; info.write(infoAddr); return(0); }
public virtual int sceKernelDeleteMsgPipe(int uid) { SceKernelMppInfo info = msgMap.Remove(uid); info.delete(); onMsgPipeDeleted(uid); return(0); }
public virtual int sceKernelCancelMsgPipe(int uid, TPointer32 sendAddr, TPointer32 recvAddr) { SceKernelMppInfo info = msgMap[uid]; sendAddr.setValue(info.NumSendWaitThreads); recvAddr.setValue(info.NumReceiveWaitThreads); info.sendThreadWaitingList.removeAllWaitingThreads(); info.receiveThreadWaitingList.removeAllWaitingThreads(); onMsgPipeCancelled(uid); return(0); }
private int hleKernelReceiveMsgPipe(int uid, TPointer msgAddr, int size, int waitMode, TPointer32 resultSizeAddr, TPointer32 timeoutAddr, bool doCallbacks, bool poll) { SceKernelMppInfo info = msgMap[uid]; if (info.bufSize != 0 && size > info.bufSize) { Console.WriteLine(string.Format("hleKernelReceiveMsgPipe illegal size 0x{0:X}, max 0x{1:X}", size, info.bufSize)); return(ERROR_KERNEL_ILLEGAL_SIZE); } ThreadManForUser threadMan = Modules.ThreadManForUserModule; if (!tryReceiveMsgPipe(info, msgAddr, size, waitMode, resultSizeAddr)) { if (!poll) { // Failed, but it's ok, just wait a little //if (log.DebugEnabled) { Console.WriteLine(string.Format("hleKernelReceiveMsgPipe {0} waiting for 0x{1:X} bytes to become available", info, size)); } SceKernelThreadInfo currentThread = threadMan.CurrentThread; info.receiveThreadWaitingList.addWaitingThread(currentThread); // Wait on a specific MsgPipe. currentThread.wait.MsgPipe_isSend = false; currentThread.wait.MsgPipe_id = uid; currentThread.wait.MsgPipe_address = msgAddr; currentThread.wait.MsgPipe_size = size; currentThread.wait.MsgPipe_resultSize_addr = resultSizeAddr; threadMan.hleKernelThreadEnterWaitState(PSP_WAIT_MSGPIPE, uid, msgPipeReceiveWaitStateChecker, timeoutAddr.Address, doCallbacks); } else { //if (log.DebugEnabled) { Console.WriteLine(string.Format("hleKernelReceiveMsgPipe trying to read more than is available size 0x{0:X}, available 0x{1:X}", size, info.bufSize - info.freeSize)); } return(ERROR_KERNEL_MESSAGE_PIPE_EMPTY); } } else { // Success, do not reschedule the current thread. //if (log.DebugEnabled) { Console.WriteLine(string.Format("hleKernelReceiveMsgPipe {0} fast check succeeded", info)); } onMsgPipeSendModified(info); } return(0); }
private bool trySendMsgPipe(SceKernelMppInfo info, TPointer addr, int size, int waitMode, TPointer32 resultSizeAddr) { if (size > 0) { // When the bufSize is 0, the data is transfered directly // from the sender to the receiver without being buffered. if (info.bufSize == 0) { info.setUserData(addr.Address, size); onMsgPipeReceiveModified(info); if (info.UserSize > 0) { // wait if nothing has been sent or // if we have to wait to send everything if (size == info.UserSize || waitMode == PSP_MPP_WAIT_MODE_COMPLETE) { return(false); } } } else { int availableSize = info.availableWriteSize(); if (availableSize == 0) { return(false); } // Trying to send more than available? if (size > availableSize) { // Do we need to send the complete size? if (waitMode == PSP_MPP_WAIT_MODE_COMPLETE) { return(false); } // We can just send the available size. size = availableSize; } info.append(addr.Memory, addr.Address, size); } } resultSizeAddr.setValue(size); return(true); }
private bool tryReceiveMsgPipe(SceKernelMppInfo info, TPointer addr, int size, int waitMode, TPointer32 resultSizeAddr) { if (size > 0) { int availableSize = info.availableReadSize(); if (availableSize == 0) { return(false); } // Trying to receive more than available? if (size > availableSize) { // Do we need to receive the complete size? if (waitMode == PSP_MPP_WAIT_MODE_COMPLETE) { return(false); } // We can just receive the available size. size = availableSize; } info.consume(addr.Memory, addr.Address, size); if (info.bufSize == 0 && info.availableReadSize() == 0 && info.NumSendWaitThreads > 0) { SceKernelThreadInfo thread = info.sendThreadWaitingList.FirstWaitingThread; if (thread.wait.MsgPipe_isSend) { //if (log.DebugEnabled) { Console.WriteLine(string.Format("tryReceiveMsgPipe waking thread {0}", thread)); } ThreadManForUser threadMan = Modules.ThreadManForUserModule; info.sendThreadWaitingList.removeWaitingThread(thread); thread.cpuContext._v0 = 0; threadMan.hleChangeThreadState(thread, PSP_THREAD_READY); threadMan.hleRescheduleCurrentThread(); } } } resultSizeAddr.setValue(size); return(true); }
private bool removeWaitingThread(SceKernelThreadInfo thread) { SceKernelMppInfo info = msgMap[thread.wait.MsgPipe_id]; if (info == null) { return(false); } if (thread.wait.MsgPipe_isSend) { info.sendThreadWaitingList.removeWaitingThread(thread); } else { info.receiveThreadWaitingList.removeWaitingThread(thread); } return(true); }
public virtual bool continueWaitState(SceKernelThreadInfo thread, ThreadWaitInfo wait) { // Check if the thread has to continue its wait state or if the msgpipe // has been sent a new message during the callback execution. SceKernelMppInfo info = outerInstance.msgMap[wait.MsgPipe_id]; if (info == null) { thread.cpuContext._v0 = ERROR_KERNEL_NOT_FOUND_MESSAGE_PIPE; return(false); } if (outerInstance.tryReceiveMsgPipe(info, wait.MsgPipe_address, wait.MsgPipe_size, wait.MsgPipe_waitMode, wait.MsgPipe_resultSize_addr)) { info.receiveThreadWaitingList.removeWaitingThread(thread); thread.cpuContext._v0 = 0; return(false); } return(true); }
private void onMsgPipeReceiveModified(SceKernelMppInfo info) { ThreadManForUser threadMan = Modules.ThreadManForUserModule; bool reschedule = false; SceKernelThreadInfo checkedThread = null; while (true) { SceKernelThreadInfo thread = info.receiveThreadWaitingList.getNextWaitingThread(checkedThread); if (thread == null) { break; } if (!thread.wait.MsgPipe_isSend && tryReceiveMsgPipe(info, thread.wait.MsgPipe_address, thread.wait.MsgPipe_size, thread.wait.MsgPipe_waitMode, thread.wait.MsgPipe_resultSize_addr)) { //if (log.DebugEnabled) { Console.WriteLine(string.Format("onMsgPipeReceiveModified waking thread {0}", thread)); } info.receiveThreadWaitingList.removeWaitingThread(thread); thread.cpuContext._v0 = 0; threadMan.hleChangeThreadState(thread, PSP_THREAD_READY); reschedule = true; } else { checkedThread = thread; } } // Reschedule only if threads waked up. if (reschedule) { threadMan.hleRescheduleCurrentThread(); } }