/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.HLE.kernel.types;
import jpcsp.Memory;
import jpcsp.HLE.Modules;
import jpcsp.HLE.kernel.managers.MsgPipeManager;
import jpcsp.HLE.kernel.managers.SceUidManager;
import jpcsp.HLE.kernel.managers.ThreadWaitingList;
import jpcsp.HLE.modules.SysMemUserForUser.SysMemInfo;
public class SceKernelMppInfo extends pspAbstractMemoryMappedStructureVariableLength {
// PSP info
public final String name;
public final int attr;
public final int bufSize;
public int freeSize;
public final ThreadWaitingList sendThreadWaitingList;
public final ThreadWaitingList receiveThreadWaitingList;
private final SysMemInfo sysMemInfo;
// Internal info
public final int uid;
public final int partitionid;
public final int address;
private int head; // relative to address
private int tail; // relative to address
private static final String uidPurpose = "ThreadMan-MsgPipe";
public int userAddress;
public int userSize;
public SceKernelMppInfo(String name, int partitionid, int attr, int size, int memType) {
this.name = name;
this.attr = attr;
bufSize = size;
freeSize = size;
if (size != 0) {
sysMemInfo = Modules.SysMemUserForUserModule.malloc(partitionid, "ThreadMan-MsgPipe", memType, size, 0);
address = sysMemInfo.addr;
} else {
sysMemInfo = null;
address = 0;
}
uid = SceUidManager.getNewUid(uidPurpose);
sendThreadWaitingList = ThreadWaitingList.createThreadWaitingList(SceKernelThreadInfo.PSP_WAIT_MSGPIPE, uid, attr, MsgPipeManager.PSP_MPP_ATTR_SEND_PRIORITY);
receiveThreadWaitingList = ThreadWaitingList.createThreadWaitingList(SceKernelThreadInfo.PSP_WAIT_MSGPIPE, uid, attr, MsgPipeManager.PSP_MPP_ATTR_RECEIVE_PRIORITY);
this.partitionid = partitionid;
head = 0;
tail = 0;
}
public boolean isMemoryAllocated() {
return bufSize == 0 || sysMemInfo != null;
}
public void delete() {
if (sysMemInfo != null) {
Modules.SysMemUserForUserModule.free(sysMemInfo);
}
SceUidManager.releaseUid(uid, uidPurpose);
}
@Override
protected void write() {
super.write();
writeStringNZ(32, name);
write32(attr);
write32(bufSize);
write32(freeSize);
write32(getNumSendWaitThreads());
write32(getNumReceiveWaitThreads());
}
public int availableReadSize() {
if (bufSize == 0) {
return getUserSize();
}
return bufSize - freeSize;
}
public int availableWriteSize() {
return freeSize;
}
// this will clobber itself if used carelessly but won't overflow outside of its allocated memory
public void append(Memory mem, int src, int size) {
int copySize;
freeSize -= size;
while (size > 0) {
copySize = Math.min(bufSize - tail, size);
mem.memcpy(address + tail, src, copySize);
src += copySize;
size -= copySize;
tail = (tail + copySize) % bufSize;
}
}
public void consume(Memory mem, int dst, int size) {
if (bufSize == 0) {
mem.memcpy(dst, userAddress, size);
userAddress += size;
userSize -= size;
} else {
freeSize += size;
while (size > 0) {
int copySize = Math.min(bufSize - head, size);
mem.memcpy(dst, address + head, copySize);
dst += copySize;
size -= copySize;
head = (head + copySize) % bufSize;
}
}
}
public int getNumSendWaitThreads() {
return sendThreadWaitingList.getNumWaitingThreads();
}
public int getNumReceiveWaitThreads() {
return receiveThreadWaitingList.getNumWaitingThreads();
}
public void setUserData(int address, int size) {
userAddress = address;
userSize = size;
}
public int getUserSize() {
return userSize;
}
@Override
public String toString() {
return String.format("SceKernelMppInfo(uid=0x%X, name='%s', attr=0x%X, bufSize=0x%X, freeSize=0x%X, numSendWaitThreads=%d, numReceiveWaitThreads=%d)", uid, name, attr, bufSize, freeSize, getNumSendWaitThreads(), getNumReceiveWaitThreads());
}
}