Merge pull request #80 from Nekotekina/master

Sync changes, simple file output for sound
This commit is contained in:
Alexandro Sánchez Bach 2014-02-18 20:57:32 +01:00
commit 51613df455
28 changed files with 853 additions and 412 deletions

1
.gitignore vendored
View File

@ -28,6 +28,7 @@
*.unsuccessfulbuild *.unsuccessfulbuild
*.res *.res
*.dump *.dump
*.wav
/libs /libs
/ipch /ipch

View File

@ -158,7 +158,7 @@ struct CellAudioOutConfiguration
u8 channel; u8 channel;
u8 encoder; u8 encoder;
u8 reserved[10]; u8 reserved[10];
u32 downMixer; be_t<u32> downMixer;
}; };
struct CellAudioOutSoundMode struct CellAudioOutSoundMode
@ -167,7 +167,7 @@ struct CellAudioOutSoundMode
u8 channel; u8 channel;
u8 fs; u8 fs;
u8 reserved; u8 reserved;
u32 layout; be_t<u32> layout;
}; };
struct CellAudioOutDeviceInfo struct CellAudioOutDeviceInfo
@ -175,9 +175,9 @@ struct CellAudioOutDeviceInfo
u8 portType; u8 portType;
u8 availableModeCount; u8 availableModeCount;
u8 state; u8 state;
u8 reserved[3]; u8 reserved[3];
u16 latency; be_t<u16> latency;
CellAudioOutSoundMode availableModes[16]; CellAudioOutSoundMode availableModes[16];
}; };
struct CellAudioOutState struct CellAudioOutState
@ -185,7 +185,7 @@ struct CellAudioOutState
u8 state; u8 state;
u8 encoder; u8 encoder;
u8 reserved[6]; u8 reserved[6];
u32 downMixer; be_t<u32> downMixer;
CellAudioOutSoundMode soundMode; CellAudioOutSoundMode soundMode;
}; };
@ -193,7 +193,7 @@ struct CellAudioOutSoundMode2
{ {
u8 type; u8 type;
u8 channel; u8 channel;
u16 fs; be_t<u16> fs;
u8 reserved[4]; u8 reserved[4];
}; };
@ -204,8 +204,8 @@ struct CellAudioOutDeviceInfo2
u8 state; u8 state;
u8 deviceNumber; u8 deviceNumber;
u8 reserved[12]; u8 reserved[12];
u64 deviceId; be_t<u64> deviceId;
u64 type; be_t<u64> type;
char name[64]; char name[64];
CellAudioOutSoundMode2 availableModes2[16]; CellAudioOutSoundMode2 availableModes2[16];
}; };
@ -229,7 +229,7 @@ struct CellAudioInSoundMode
{ {
u8 type; u8 type;
u8 channel; u8 channel;
u16 fs; be_t<u16> fs;
u8 reserved[4]; u8 reserved[4];
}; };
@ -240,8 +240,8 @@ struct CellAudioInDeviceInfo
u8 state; u8 state;
u8 deviceNumber; u8 deviceNumber;
u8 reserved[12]; u8 reserved[12];
u64 deviceId; be_t<u64> deviceId;
u64 type; be_t<u64> type;
char name[64]; char name[64];
CellAudioInSoundMode availableModes[16]; CellAudioInSoundMode availableModes[16];
}; };

View File

@ -111,7 +111,7 @@ int CPUThread::ThreadStatus()
return CPUThread_Step; return CPUThread_Step;
} }
if(Emu.IsPaused() || Sync()) if (Emu.IsPaused() || Sync())
{ {
return CPUThread_Sleeping; return CPUThread_Sleeping;
} }

View File

@ -32,8 +32,11 @@ private:
//0 - 10 //0 - 10
void STOP(u32 code) void STOP(u32 code)
{ {
ConLog.Warning("STOP: 0x%x (m_exit_status -> 0)", code); if (CPU.SPU.Out_MBox.GetCount()) // the real exit status is probably stored there
CPU.SetExitStatus(0); ConLog.Warning("STOP: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue());
else
ConLog.Warning("STOP: 0x%x (no message)", code);
CPU.SetExitStatus(code);
CPU.Stop(); CPU.Stop();
} }
void LNOP() void LNOP()

View File

@ -611,7 +611,7 @@ public:
case SPU_RdInMbox: case SPU_RdInMbox:
count = SPU.In_MBox.GetCount(); count = SPU.In_MBox.GetCount();
ConLog.Warning("GetChannelCount(%s) -> %d", wxString(spu_ch_name[ch]).wx_str(), count); //ConLog.Warning("GetChannelCount(%s) -> %d", wxString(spu_ch_name[ch]).wx_str(), count);
return count; return count;
case SPU_WrOutIntrMbox: case SPU_WrOutIntrMbox:

View File

@ -8,6 +8,8 @@ void cellAudio_load();
void cellAudio_unload(); void cellAudio_unload();
Module cellAudio(0x0011, cellAudio_init, cellAudio_load, cellAudio_unload); Module cellAudio(0x0011, cellAudio_init, cellAudio_load, cellAudio_unload);
extern u64 get_system_time();
enum enum
{ {
//libaudio Error Codes //libaudio Error Codes
@ -61,6 +63,56 @@ enum
CELL_SOUND_SYNTH2_ERROR_ALREADY_INITIALIZED = 0x80310203, CELL_SOUND_SYNTH2_ERROR_ALREADY_INITIALIZED = 0x80310203,
}; };
struct WAVHeader
{
struct RIFFHeader
{
u32 ID; // "RIFF"
u32 Size; // FileSize - 8
u32 WAVE; // "WAVE"
RIFFHeader(u32 size)
: ID(*(u32*)"RIFF")
, WAVE(*(u32*)"WAVE")
, Size(size)
{
}
} RIFF;
struct FMTHeader
{
u32 ID; // "fmt "
u32 Size; // 16
u16 AudioFormat; // 1 for PCM, 3 for IEEE Floating Point
u16 NumChannels; // 1, 2, 6, 8
u32 SampleRate; // 48000
u32 ByteRate; // SampleRate * NumChannels * BitsPerSample/8
u16 BlockAlign; // NumChannels * BitsPerSample/8
u16 BitsPerSample; // sizeof(float) * 8
FMTHeader(u8 ch)
: ID(*(u32*)"fmt ")
, Size(16)
, AudioFormat(3)
, NumChannels(ch)
, SampleRate(48000)
, ByteRate(SampleRate * ch * sizeof(float))
, BlockAlign(ch * sizeof(float))
, BitsPerSample(sizeof(float) * 8)
{
}
} FMT;
u32 ID; // "data"
u32 Size; // size of data (256 * NumChannels * sizeof(float))
WAVHeader(u8 ch)
: ID(*(u32*)"data")
, Size(0)
, FMT(ch)
, RIFF(sizeof(RIFFHeader) + sizeof(FMTHeader))
{
}
};
//libaudio datatypes //libaudio datatypes
struct CellAudioPortParam struct CellAudioPortParam
@ -84,6 +136,7 @@ struct CellAudioPortConfig
struct AudioPortConfig struct AudioPortConfig
{ {
bool m_is_audio_port_started; bool m_is_audio_port_started;
bool m_is_audio_port_stopped;
CellAudioPortParam m_param; CellAudioPortParam m_param;
const u32 m_buffer; // 64 KB or 128 KB with 8x16 config const u32 m_buffer; // 64 KB or 128 KB with 8x16 config
@ -91,7 +144,7 @@ struct AudioPortConfig
AudioPortConfig(); AudioPortConfig();
~AudioPortConfig(); void finalize();
}; };
struct AudioConfig //custom structure struct AudioConfig //custom structure
@ -127,15 +180,15 @@ struct AudioConfig //custom structure
AudioPortConfig::AudioPortConfig() AudioPortConfig::AudioPortConfig()
: m_is_audio_port_started(false) : m_is_audio_port_started(false)
, m_buffer(Memory.Alloc(1024 * 128, 1024)) , m_buffer(Memory.Alloc(1024 * 128, 1024)) // max 128K size
, m_index(Memory.Alloc(16, 16)) , m_index(Memory.Alloc(16, 16)) // allocation for u64 value "read index"
{ {
m_config.m_port_in_use++; m_config.m_port_in_use++;
mem64_t index(m_index); mem64_t index(m_index);
index = 0; index = 0;
} }
AudioPortConfig::~AudioPortConfig() void AudioPortConfig::finalize()
{ {
m_config.m_port_in_use--; m_config.m_port_in_use--;
Memory.Free(m_buffer); Memory.Free(m_buffer);
@ -330,12 +383,13 @@ int cellAudioGetPortConfig(u32 portNum, mem_ptr_t<CellAudioPortConfig> portConfi
portConfig->status = CELL_AUDIO_STATUS_READY; portConfig->status = CELL_AUDIO_STATUS_READY;
portConfig->nChannel = ref.nChannel; portConfig->nChannel = ref.nChannel;
portConfig->nBlock = ref.nBlock; portConfig->nBlock = ref.nBlock;
portConfig->portSize = ref.nChannel * ref.nBlock * 256; portConfig->portSize = ref.nChannel * ref.nBlock * 256 * sizeof(float);
portConfig->portAddr = m_config.m_ports[portNum]->m_buffer; // 0x20020000 portConfig->portAddr = m_config.m_ports[portNum]->m_buffer; // 0x20020000
portConfig->readIndexAddr = m_config.m_ports[portNum]->m_index; // 0x20010010 on ps3 portConfig->readIndexAddr = m_config.m_ports[portNum]->m_index; // 0x20010010 on ps3
ConLog.Write("*** nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x",
(u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr);
// portAddr - readIndexAddr == 0xFFF0 on ps3 // portAddr - readIndexAddr == 0xFFF0 on ps3
// Memory.Write64(portConfig->readIndexAddr, 1);
} }
return CELL_OK; return CELL_OK;
@ -361,6 +415,105 @@ int cellAudioPortStart(u32 portNum)
} }
m_config.m_ports[portNum]->m_is_audio_port_started = true; m_config.m_ports[portNum]->m_is_audio_port_started = true;
m_config.m_ports[portNum]->m_is_audio_port_stopped = false;
std::string t_name = "AudioPort0";
t_name[9] += portNum;
thread t(t_name, [portNum]()
{
AudioPortConfig& port = *m_config.m_ports[portNum];
mem64_t index(port.m_index); // index storage
if (port.m_param.nChannel > 8)
{
ConLog.Error("Port aborted: invalid channel count (%d)", port.m_param.nChannel);
port.m_is_audio_port_stopped = true;
return;
}
WAVHeader header(port.m_param.nChannel); // WAV file header
wxString output_name = "audioport0.wav";
output_name[9] = '0' + portNum;
wxFile output(output_name, wxFile::write); // create output file
if (!output.IsOpened())
{
ConLog.Error("Port aborted: cannot create %s", output_name.wx_str());
port.m_is_audio_port_stopped = true;
return;
}
ConLog.Write("Port started");
u64 start_time = get_system_time();
u64 counter = 0;
output.Write(&header, sizeof(header)); // write file header
const u32 block_size = port.m_param.nChannel * 256 * sizeof(float);
float buffer[32*256]; // buffer for max channel count (8)
while (port.m_is_audio_port_started)
{
if (Emu.IsStopped())
{
ConLog.Warning("Port aborted");
goto abort;
}
// TODO: send beforemix event (in ~2,6 ms before mixing)
// Sleep(5); // precise time of sleeping: 5,(3) ms (or 256/48000 sec)
if (counter * 256000000 / 48000 >= get_system_time() - start_time)
{
Sleep(1);
continue;
}
counter++;
if (Emu.IsPaused())
{
continue;
}
u32 position = index.GetValue(); // get old value
memcpy(buffer, Memory + port.m_buffer + position * block_size, block_size);
memset(Memory + port.m_buffer + position * block_size, 0, block_size);
index = (position + 1) % port.m_param.nBlock; // write new value
// TODO: send aftermix event (normal audio event)
for (u32 i = 0; i < block_size; i++)
{
// reverse byte order (TODO: use port.m_param.level)
buffer[i] = re(buffer[i]);
}
if (output.Write(&buffer, block_size) != (size_t)block_size) // write file data
{
ConLog.Error("Port aborted: cannot write %s", output_name.wx_str());
goto abort;
}
header.Size += block_size; // update file header
header.RIFF.Size += block_size;
}
ConLog.Write("Port finished");
abort:
output.Seek(0);
output.Write(&header, sizeof(header)); // write fixed file header
output.Close();
port.m_is_audio_port_stopped = true;
});
t.detach();
return CELL_OK; return CELL_OK;
} }
@ -378,8 +531,8 @@ int cellAudioPortClose(u32 portNum)
return CELL_AUDIO_ERROR_PORT_NOT_OPEN; return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
} }
delete m_config.m_ports[portNum]; m_config.m_ports[portNum]->finalize();
m_config.m_ports[portNum] = nullptr; safe_delete(m_config.m_ports[portNum]);
return CELL_OK; return CELL_OK;
} }
@ -403,6 +556,15 @@ int cellAudioPortStop(u32 portNum)
} }
m_config.m_ports[portNum]->m_is_audio_port_started = false; m_config.m_ports[portNum]->m_is_audio_port_started = false;
while (!m_config.m_ports[portNum]->m_is_audio_port_stopped)
{
Sleep(1);
if (Emu.IsStopped())
{
ConLog.Warning("cellAudioPortStop(%d) aborted", portNum);
break;
}
}
return CELL_OK; return CELL_OK;
} }
@ -428,6 +590,7 @@ int cellAudioSetPortLevel(u32 portNum, float level)
int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key) int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key)
{ {
cellAudio.Error("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.GetAddr(), key.GetAddr()); cellAudio.Error("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.GetAddr(), key.GetAddr());
key = 0x123456789ABCDEF0;
return CELL_OK; return CELL_OK;
} }
@ -446,11 +609,11 @@ int cellAudioSetNotifyEventQueue(u64 key)
EventQueue* eq; EventQueue* eq;
if (!Emu.GetEventManager().GetEventQueue(key, eq)) if (!Emu.GetEventManager().GetEventQueue(key, eq))
{ {
return CELL_AUDIO_ERROR_PARAM; //return CELL_AUDIO_ERROR_PARAM;
return CELL_OK;
} }
eq->events.push(0, 0, 0, 0); // eq->events.push(0, 0, 0, 0);
eq->events.push(0, 0, 0, 0);
return CELL_OK; return CELL_OK;
} }

View File

@ -118,8 +118,8 @@ int cellPamfGetHeaderSize(mem_ptr_t<PamfHeader> pAddr, u64 fileSize, mem64_t pSi
cellPamf.Warning("cellPamfGetHeaderSize(pAddr=0x%x, fileSize=%d, pSize_addr=0x%x)", cellPamf.Warning("cellPamfGetHeaderSize(pAddr=0x%x, fileSize=%d, pSize_addr=0x%x)",
pAddr.GetAddr(), fileSize, pSize.GetAddr()); pAddr.GetAddr(), fileSize, pSize.GetAddr());
//if ((u32)pAddr->magic != 0x464d4150) if ((u32)pAddr->magic != 0x464d4150)
//return CELL_PAMF_ERROR_UNKNOWN_TYPE; return CELL_PAMF_ERROR_UNKNOWN_TYPE;
const u64 offset = (u64)pAddr->data_offset << 11; const u64 offset = (u64)pAddr->data_offset << 11;
pSize = offset /*? offset : 2048*/; //hack pSize = offset /*? offset : 2048*/; //hack

View File

@ -713,7 +713,7 @@ int cellRescSetConvertAndFlip(mem_ptr_t<CellGcmContextData> cntxt, s32 idx)
int cellRescSetWaitFlip() int cellRescSetWaitFlip()
{ {
cellResc.Log("cellRescSetWaitFlip()"); cellResc.Log("cellRescSetWaitFlip()");
GSLockCurrent lock(GS_LOCK_WAIT_FLIP); GSLockCurrent lock(GS_LOCK_WAIT_FLIP); // could stall on exit
return CELL_OK; return CELL_OK;
} }

View File

@ -95,15 +95,13 @@ int cellSyncMutexLock(mem_ptr_t<CellSyncMutex> mutex)
} }
} }
int counter = 0; while (old_order != Memory.Read16(mutex.GetAddr()))
while (*(u16*)&old_order != *(u16*)&mutex->m_freed)
{ {
Sleep(1); Sleep(1);
if (++counter >= 5000) if (Emu.IsStopped())
{ {
counter = 0; ConLog.Warning("cellSyncMutexLock(mutex=0x%x) aborted", mutex.GetAddr());
cellSync.Warning("cellSyncMutexLock(mutex=0x%x, old_order=%d, order=%d, freed=%d): TIMEOUT", break;
mutex.GetAddr(), (u16)old_order, (u16)mutex->m_order, (u16)mutex->m_freed);
} }
} }
_mm_mfence(); _mm_mfence();

View File

@ -472,12 +472,20 @@ int cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 as
int cellSysutilCheckCallback() int cellSysutilCheckCallback()
{ {
cellSysutil.Log("cellSysutilCheckCallback()"); cellSysutil.Log("cellSysutilCheckCallback()");
Emu.GetCallbackManager().m_exit_callback.Check(); Emu.GetCallbackManager().m_exit_callback.Check();
CPUThread& thr = Emu.GetCallbackThread(); CPUThread& thr = Emu.GetCallbackThread();
while(Emu.IsRunning() && thr.IsAlive()) while (thr.IsAlive())
{
Sleep(1); Sleep(1);
if (Emu.IsStopped())
{
ConLog.Warning("cellSysutilCheckCallback() aborted");
break;
}
}
return CELL_OK; return CELL_OK;
} }
@ -485,6 +493,7 @@ int cellSysutilCheckCallback()
int cellSysutilRegisterCallback(int slot, u64 func_addr, u64 userdata) int cellSysutilRegisterCallback(int slot, u64 func_addr, u64 userdata)
{ {
cellSysutil.Warning("cellSysutilRegisterCallback(slot=%d, func_addr=0x%llx, userdata=0x%llx)", slot, func_addr, userdata); cellSysutil.Warning("cellSysutilRegisterCallback(slot=%d, func_addr=0x%llx, userdata=0x%llx)", slot, func_addr, userdata);
Emu.GetCallbackManager().m_exit_callback.Register(slot, func_addr, userdata); Emu.GetCallbackManager().m_exit_callback.Register(slot, func_addr, userdata);
wxGetApp().SendDbgCommand(DID_REGISTRED_CALLBACK); wxGetApp().SendDbgCommand(DID_REGISTRED_CALLBACK);
@ -495,6 +504,7 @@ int cellSysutilRegisterCallback(int slot, u64 func_addr, u64 userdata)
int cellSysutilUnregisterCallback(int slot) int cellSysutilUnregisterCallback(int slot)
{ {
cellSysutil.Warning("cellSysutilUnregisterCallback(slot=%d)", slot); cellSysutil.Warning("cellSysutilUnregisterCallback(slot=%d)", slot);
Emu.GetCallbackManager().m_exit_callback.Unregister(slot); Emu.GetCallbackManager().m_exit_callback.Unregister(slot);
wxGetApp().SendDbgCommand(DID_UNREGISTRED_CALLBACK); wxGetApp().SendDbgCommand(DID_UNREGISTRED_CALLBACK);
@ -655,11 +665,13 @@ int cellMsgDialogOpenErrorCode(u32 errorCode, mem_func_ptr_t<CellMsgDialogCallba
int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option) int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
{ {
cellSysutil.Warning("cellAudioOutGetSoundAvailability(audioOut=%d,type=%d,fs=%d,option=%d)", cellSysutil.Warning("cellAudioOutGetSoundAvailability(audioOut=%d, type=%d, fs=0x%x, option=%d)",
audioOut,type,fs,option); audioOut, type, fs, option);
option = 0; option = 0;
int available = 2; // should be at least 2
switch(fs) switch(fs)
{ {
case CELL_AUDIO_OUT_FS_32KHZ: case CELL_AUDIO_OUT_FS_32KHZ:
@ -676,17 +688,16 @@ int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
switch(type) switch(type)
{ {
case CELL_AUDIO_OUT_CODING_TYPE_LPCM: case CELL_AUDIO_OUT_CODING_TYPE_LPCM: break;
case CELL_AUDIO_OUT_CODING_TYPE_AC3: case CELL_AUDIO_OUT_CODING_TYPE_AC3: available = 0; break;
case CELL_AUDIO_OUT_CODING_TYPE_DTS: case CELL_AUDIO_OUT_CODING_TYPE_DTS: available = 0; break;
break;
default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE; default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE;
} }
switch(audioOut) switch(audioOut)
{ {
case CELL_AUDIO_OUT_PRIMARY: return 2; case CELL_AUDIO_OUT_PRIMARY: return available;
case CELL_AUDIO_OUT_SECONDARY: return 0; case CELL_AUDIO_OUT_SECONDARY: return 0;
} }
@ -695,11 +706,13 @@ int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
int cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32 ch, u32 option) int cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32 ch, u32 option)
{ {
cellSysutil.Warning("cellAudioOutGetSoundAvailability(audioOut=%d,type=%d,fs=%d,ch=%d,option=%d)", cellSysutil.Warning("cellAudioOutGetSoundAvailability2(audioOut=%d, type=%d, fs=0x%x, ch=%d, option=%d)",
audioOut,type,fs,ch,option); audioOut, type, fs, ch, option);
option = 0; option = 0;
int available = 2; // should be at least 2
switch(fs) switch(fs)
{ {
case CELL_AUDIO_OUT_FS_32KHZ: case CELL_AUDIO_OUT_FS_32KHZ:
@ -716,27 +729,25 @@ int cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32 ch, u3
switch(ch) switch(ch)
{ {
case 2: case 2: break;
case 6: case 6: available = 0; break;
case 8: case 8: available = 0; break;
break;
default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE; default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE;
} }
switch(type) switch(type)
{ {
case CELL_AUDIO_OUT_CODING_TYPE_LPCM: case CELL_AUDIO_OUT_CODING_TYPE_LPCM: break;
case CELL_AUDIO_OUT_CODING_TYPE_AC3: case CELL_AUDIO_OUT_CODING_TYPE_AC3: available = 0; break;
case CELL_AUDIO_OUT_CODING_TYPE_DTS: case CELL_AUDIO_OUT_CODING_TYPE_DTS: available = 0; break;
break;
default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE; default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE;
} }
switch(audioOut) switch(audioOut)
{ {
case CELL_AUDIO_OUT_PRIMARY: return 1; case CELL_AUDIO_OUT_PRIMARY: return available;
case CELL_AUDIO_OUT_SECONDARY: return 0; case CELL_AUDIO_OUT_SECONDARY: return 0;
} }
@ -775,31 +786,29 @@ int cellAudioOutGetState(u32 audioOut, u32 deviceIndex, u32 state_addr)
return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_AUDIO_OUT; return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_AUDIO_OUT;
} }
int cellAudioOutConfigure(u32 audioOut, u32 config_addr, u32 option_addr, u32 waitForEvent) int cellAudioOutConfigure(u32 audioOut, mem_ptr_t<CellAudioOutConfiguration> config, mem_ptr_t<CellAudioOutOption> option, u32 waitForEvent)
{ {
cellSysutil.Warning("cellAudioOutConfigure(audioOut=%d, config_addr=0x%x, option_addr=0x%x, waitForEvent=0x%x)", cellSysutil.Warning("cellAudioOutConfigure(audioOut=%d, config_addr=0x%x, option_addr=0x%x, (!)waitForEvent=%d)",
audioOut, config_addr, option_addr, waitForEvent); audioOut, config.GetAddr(), option.GetAddr(), waitForEvent);
if(!Memory.IsGoodAddr(config_addr, sizeof(CellAudioOutConfiguration))) if (!config.IsGood())
{ {
return CELL_EFAULT; return CELL_EFAULT;
} }
CellAudioOutConfiguration& config = (CellAudioOutConfiguration&)Memory[config_addr];
switch(audioOut) switch(audioOut)
{ {
case CELL_AUDIO_OUT_PRIMARY: case CELL_AUDIO_OUT_PRIMARY:
if(config.channel) if (config->channel)
{ {
Emu.GetAudioManager().GetInfo().mode.channel = config.channel; Emu.GetAudioManager().GetInfo().mode.channel = config->channel;
} }
Emu.GetAudioManager().GetInfo().mode.encoder = config.encoder; Emu.GetAudioManager().GetInfo().mode.encoder = config->encoder;
if(config.downMixer) if(config->downMixer)
{ {
Emu.GetAudioManager().GetInfo().mode.downMixer = config.downMixer; Emu.GetAudioManager().GetInfo().mode.downMixer = config->downMixer;
} }
return CELL_AUDIO_OUT_SUCCEEDED; return CELL_AUDIO_OUT_SUCCEEDED;

View File

@ -5,8 +5,6 @@
void sys_fs_init(); void sys_fs_init();
Module sys_fs(0x000e, sys_fs_init); Module sys_fs(0x000e, sys_fs_init);
std::atomic<u32> g_FsAioReadID = 0;
bool sdata_check(u32 version, u32 flags, u64 filesizeInput, u64 filesizeTmp) bool sdata_check(u32 version, u32 flags, u64 filesizeInput, u64 filesizeTmp)
{ {
if (version > 4 || flags & 0x7EFFFFC0){ if (version > 4 || flags & 0x7EFFFFC0){
@ -131,8 +129,22 @@ int cellFsSdataOpen(u32 path_addr, int flags, mem32_t fd, mem32_t arg, u64 size)
return CELL_OK; return CELL_OK;
} }
std::atomic<u32> g_FsAioReadID = 0;
std::atomic<u32> g_FsAioReadCur = 0;
bool aio_init;
void fsAioRead(u32 fd, mem_ptr_t<CellFsAio> aio, int xid, mem_func_ptr_t<void (*)(mem_ptr_t<CellFsAio> xaio, u32 error, int xid, u64 size)> func) void fsAioRead(u32 fd, mem_ptr_t<CellFsAio> aio, int xid, mem_func_ptr_t<void (*)(mem_ptr_t<CellFsAio> xaio, u32 error, int xid, u64 size)> func)
{ {
while (g_FsAioReadCur != xid)
{
Sleep(1);
if (Emu.IsStopped())
{
ConLog.Warning("fsAioRead() aborted");
return;
}
}
vfsFileBase* orig_file; vfsFileBase* orig_file;
if(!sys_fs.CheckId(fd, orig_file)) return; if(!sys_fs.CheckId(fd, orig_file)) return;
@ -169,30 +181,43 @@ void fsAioRead(u32 fd, mem_ptr_t<CellFsAio> aio, int xid, mem_func_ptr_t<void (*
error = CELL_EFAULT; error = CELL_EFAULT;
} }
ConLog.Warning("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, res=0x%x, xid=0x%x [%s])",
fd, (u64)aio->offset, buf_addr, (u64)aio->size, res, xid, path.wx_str());
//start callback thread //start callback thread
if(func) if(func)
func.async(aio, error, xid, res); func.async(aio, error, xid, res);
ConLog.Warning("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, res=0x%x, xid=0x%x [%s])", g_FsAioReadCur++;
fd, (u64)aio->offset, buf_addr, (u64)aio->size, res, xid, path.wx_str());
} }
int cellFsAioRead(mem_ptr_t<CellFsAio> aio, mem32_t aio_id, mem_func_ptr_t<void (*)(mem_ptr_t<CellFsAio> xaio, u32 error, int xid, u64 size)> func) int cellFsAioRead(mem_ptr_t<CellFsAio> aio, mem32_t aio_id, mem_func_ptr_t<void (*)(mem_ptr_t<CellFsAio> xaio, u32 error, int xid, u64 size)> func)
{ {
sys_fs.Warning("cellFsAioRead(aio_addr=0x%x, id_addr=0x%x, func_addr=0x%x)", aio.GetAddr(), aio_id.GetAddr(), func.GetAddr()); sys_fs.Warning("cellFsAioRead(aio_addr=0x%x, id_addr=0x%x, func_addr=0x%x)", aio.GetAddr(), aio_id.GetAddr(), func.GetAddr());
if (!aio.IsGood() || !aio_id.IsGood() || !func.IsGood())
{
return CELL_EFAULT;
}
if (!aio_init)
{
//return CELL_ENXIO;
}
vfsFileBase* orig_file; vfsFileBase* orig_file;
u32 fd = aio->fd; u32 fd = aio->fd;
if(!sys_fs.CheckId(fd, orig_file)) return CELL_ESRCH; if (!sys_fs.CheckId(fd, orig_file)) return CELL_EBADF;
//get a unique id for the callback (may be used by cellFsAioCancel) //get a unique id for the callback (may be used by cellFsAioCancel)
const u32 xid = g_FsAioReadID++; const u32 xid = g_FsAioReadID++;
thread t("fsAioRead", std::bind(fsAioRead, fd, aio, xid, func));
t.detach();
//fsAioRead(fd, aio, xid, func);
aio_id = xid; aio_id = xid;
{
thread t("fsAioRead", std::bind(fsAioRead, fd, aio, xid, func));
t.detach();
}
return CELL_OK; return CELL_OK;
} }
@ -200,6 +225,7 @@ int cellFsAioInit(mem8_ptr_t mount_point)
{ {
wxString mp = Memory.ReadString(mount_point.GetAddr()); wxString mp = Memory.ReadString(mount_point.GetAddr());
sys_fs.Warning("cellFsAioInit(mount_point_addr=0x%x (%s))", mount_point.GetAddr(), mp.wx_str()); sys_fs.Warning("cellFsAioInit(mount_point_addr=0x%x (%s))", mount_point.GetAddr(), mp.wx_str());
aio_init = true;
return CELL_OK; return CELL_OK;
} }
@ -234,4 +260,5 @@ void sys_fs_init()
sys_fs.AddFunc(0xdb869f20, cellFsAioInit); sys_fs.AddFunc(0xdb869f20, cellFsAioInit);
sys_fs.AddFunc(0x9f951810, cellFsAioFinish); sys_fs.AddFunc(0x9f951810, cellFsAioFinish);
sys_fs.AddFunc(0x1a108ab7, cellFsGetBlockSize); sys_fs.AddFunc(0x1a108ab7, cellFsGetBlockSize);
aio_init = false;
} }

View File

@ -74,7 +74,7 @@ static func_caller* sc_table[1024] =
bind_func(sys_cond_wait), //107 (0x06B) bind_func(sys_cond_wait), //107 (0x06B)
bind_func(sys_cond_signal), //108 (0x06C) bind_func(sys_cond_signal), //108 (0x06C)
bind_func(sys_cond_signal_all), //109 (0x06D) bind_func(sys_cond_signal_all), //109 (0x06D)
null_func, null_func, null_func, null_func, //113 (0x071) bind_func(sys_cond_signal_to), null_func, null_func, null_func, //113 (0x071)
bind_func(sys_semaphore_get_value), //114 (0x072) bind_func(sys_semaphore_get_value), //114 (0x072)
null_func, null_func, null_func, bind_func(sys_event_flag_clear), null_func, //119 (0x077) null_func, null_func, null_func, bind_func(sys_event_flag_clear), null_func, //119 (0x077)
bind_func(sys_rwlock_create), //120 (0x078) bind_func(sys_rwlock_create), //120 (0x078)

View File

@ -181,7 +181,7 @@ extern int sys_cond_signal_all(u32 cond_id);
extern int sys_cond_signal_to(u32 cond_id, u32 thread_id); extern int sys_cond_signal_to(u32 cond_id, u32 thread_id);
//sys_mutex //sys_mutex
extern int sys_mutex_create(u32 mutex_id_addr, u32 attr_addr); extern int sys_mutex_create(mem32_t mutex_id, mem_ptr_t<sys_mutex_attribute> attr);
extern int sys_mutex_destroy(u32 mutex_id); extern int sys_mutex_destroy(u32 mutex_id);
extern int sys_mutex_lock(u32 mutex_id, u64 timeout); extern int sys_mutex_lock(u32 mutex_id, u64 timeout);
extern int sys_mutex_trylock(u32 mutex_id); extern int sys_mutex_trylock(u32 mutex_id);

View File

@ -1,13 +1,12 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "SC_Mutex.h"
#include "Emu/SysCalls/lv2/SC_Condition.h" #include "Emu/SysCalls/lv2/SC_Condition.h"
SysCallBase sys_cond("sys_cond"); SysCallBase sys_cond("sys_cond");
int sys_cond_create(mem32_t cond_id, u32 mutex_id, mem_ptr_t<sys_cond_attribute> attr) int sys_cond_create(mem32_t cond_id, u32 mutex_id, mem_ptr_t<sys_cond_attribute> attr)
{ {
sys_cond.Warning("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=%d)", sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=%d)",
cond_id.GetAddr(), mutex_id, attr.GetAddr()); cond_id.GetAddr(), mutex_id, attr.GetAddr());
if (!cond_id.IsGood() || !attr.IsGood()) if (!cond_id.IsGood() || !attr.IsGood())
@ -21,102 +20,192 @@ int sys_cond_create(mem32_t cond_id, u32 mutex_id, mem_ptr_t<sys_cond_attribute>
return CELL_EINVAL; return CELL_EINVAL;
} }
mutex* mtx_data; Mutex* mutex;
if (!Emu.GetIdManager().GetIDData(mutex_id, mtx_data)) if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
cond_id = sys_cond.GetNewId(new condition(mtx_data->mtx, attr->name_u64)); if (mutex->is_recursive)
sys_cond.Warning("*** condition created [%s]: id = %d", wxString(attr->name, 8).wx_str(), cond_id.GetValue()); {
sys_cond.Warning("Recursive mutex(%d)", mutex_id);
}
Cond* cond = new Cond(mutex, attr->name_u64);
u32 id = sys_cond.GetNewId(cond);
cond_id = id;
mutex->cond_count++;
sys_cond.Warning("*** condition created [%s] (mutex_id=%d): id = %d", wxString(attr->name, 8).wx_str(), mutex_id, cond_id.GetValue());
return CELL_OK; return CELL_OK;
} }
int sys_cond_destroy(u32 cond_id) int sys_cond_destroy(u32 cond_id)
{ {
sys_cond.Error("sys_cond_destroy(cond_id=%d)", cond_id); sys_cond.Warning("sys_cond_destroy(cond_id=%d)", cond_id);
condition* cond; Cond* cond;
if (!Emu.GetIdManager().GetIDData(cond_id, cond)) if (!Emu.GetIdManager().GetIDData(cond_id, cond))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
if (true) // TODO if (!cond->m_queue.finalize())
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
cond->mutex->cond_count--;
Emu.GetIdManager().RemoveID(cond_id); Emu.GetIdManager().RemoveID(cond_id);
return CELL_OK; return CELL_OK;
} }
int sys_cond_wait(u32 cond_id, u64 timeout) int sys_cond_wait(u32 cond_id, u64 timeout)
{ {
sys_cond.Warning("sys_cond_wait(cond_id=%d, timeout=%lld)", cond_id, timeout); sys_cond.Log("sys_cond_wait(cond_id=%d, timeout=%lld)", cond_id, timeout);
condition* cond_data = nullptr; Cond* cond;
if(!sys_cond.CheckId(cond_id, cond_data)) return CELL_ESRCH; if (!Emu.GetIdManager().GetIDData(cond_id, cond))
{
return CELL_ESRCH;
}
Mutex* mutex = cond->mutex;
u32 tid = GetCurrentPPUThread().GetId();
if (mutex->m_mutex.GetOwner() != tid)
{
return CELL_EPERM;
}
cond->m_queue.push(tid);
mutex->recursive = 0;
mutex->m_mutex.unlock(tid);
u32 counter = 0; u32 counter = 0;
const u32 max_counter = timeout ? (timeout / 1000) : 20000; const u32 max_counter = timeout ? (timeout / 1000) : ~0;
do
while (true)
{ {
if (Emu.IsStopped()) /* switch (mutex->m_mutex.trylock(tid))
{ {
ConLog.Warning("sys_cond_wait(cond_id=%d, ...) aborted", cond_id); case SMR_OK: mutex->m_mutex.unlock(tid); break;
return CELL_ETIMEDOUT; case SMR_SIGNAL: mutex->recursive = 1; return CELL_OK;
} */
if (mutex->m_mutex.GetOwner() == tid)
{
_mm_mfence();
mutex->recursive = 1;
return CELL_OK;
} }
switch (cond_data->cond.WaitTimeout(1)) Sleep(1);
{
case wxCOND_NO_ERROR: return CELL_OK;
case wxCOND_TIMEOUT: break;
default: return CELL_EPERM;
}
if (counter++ > max_counter) if (counter++ > max_counter)
{ {
if (!timeout) cond->m_queue.invalidate(tid);
{ return CELL_ETIMEDOUT;
counter = 0; }
} if (Emu.IsStopped())
else {
{ ConLog.Warning("sys_cond_wait(id=%d) aborted", cond_id);
return CELL_ETIMEDOUT; return CELL_OK;
} }
} }
} while (true);
} }
int sys_cond_signal(u32 cond_id) int sys_cond_signal(u32 cond_id)
{ {
sys_cond.Warning("sys_cond_signal(cond_id=%d)", cond_id); sys_cond.Log("sys_cond_signal(cond_id=%d)", cond_id);
condition* cond_data = nullptr; Cond* cond;
if(!sys_cond.CheckId(cond_id, cond_data)) return CELL_ESRCH; if (!Emu.GetIdManager().GetIDData(cond_id, cond))
{
return CELL_ESRCH;
}
cond_data->cond.Signal(); Mutex* mutex = cond->mutex;
u32 tid = GetCurrentPPUThread().GetId();
if (u32 target = mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop())
{
if (mutex->m_mutex.trylock(target) != SMR_OK)
{
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target);
}
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_cond_signal(id=%d) aborted", cond_id);
}
return CELL_OK; return CELL_OK;
} }
int sys_cond_signal_all(u32 cond_id) int sys_cond_signal_all(u32 cond_id)
{ {
sys_cond.Warning("sys_cond_signal_all(cond_id=%d)", cond_id); sys_cond.Log("sys_cond_signal_all(cond_id=%d)", cond_id);
condition* cond_data = nullptr; Cond* cond;
if(!sys_cond.CheckId(cond_id, cond_data)) return CELL_ESRCH; if (!Emu.GetIdManager().GetIDData(cond_id, cond))
{
return CELL_ESRCH;
}
cond_data->cond.Broadcast(); Mutex* mutex = cond->mutex;
u32 tid = GetCurrentPPUThread().GetId();
while (u32 target = mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop())
{
if (mutex->m_mutex.trylock(target) != SMR_OK)
{
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target);
}
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_cond_signal_all(id=%d) aborted", cond_id);
}
return CELL_OK; return CELL_OK;
} }
int sys_cond_signal_to(u32 cond_id, u32 thread_id) int sys_cond_signal_to(u32 cond_id, u32 thread_id)
{ {
sys_cond.Error("sys_cond_signal_to(cond_id=%d, thread_id=%d)", cond_id, thread_id); sys_cond.Log("sys_cond_signal_to(cond_id=%d, thread_id=%d)", cond_id, thread_id);
Cond* cond;
if (!Emu.GetIdManager().GetIDData(cond_id, cond))
{
return CELL_ESRCH;
}
if (!cond->m_queue.invalidate(thread_id))
{
return CELL_EPERM;
}
Mutex* mutex = cond->mutex;
u32 tid = GetCurrentPPUThread().GetId();
if (mutex->m_mutex.trylock(thread_id) != SMR_OK)
{
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, thread_id);
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_cond_signal_to(id=%d, to=%d) aborted", cond_id, thread_id);
}
return CELL_OK; return CELL_OK;
} }

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "SC_Mutex.h"
struct sys_cond_attribute struct sys_cond_attribute
{ {
@ -12,14 +13,14 @@ struct sys_cond_attribute
}; };
}; };
struct condition struct Cond
{ {
wxCondition cond; Mutex* mutex; // associated with mutex
u64 name_u64; SleepQueue m_queue;
condition(wxMutex& mtx, u64 name) Cond(Mutex* mutex, u64 name)
: cond(mtx) : mutex(mutex)
, name_u64(name) , m_queue(name)
{ {
} }
}; };

View File

@ -59,7 +59,7 @@ int sys_event_queue_create(mem32_t equeue_id, mem_ptr_t<sys_event_queue_attr> at
int sys_event_queue_destroy(u32 equeue_id, int mode) int sys_event_queue_destroy(u32 equeue_id, int mode)
{ {
sys_event.Warning("sys_event_queue_destroy(equeue_id=%d, mode=0x%x)", equeue_id, mode); sys_event.Error("sys_event_queue_destroy(equeue_id=%d, mode=0x%x)", equeue_id, mode);
EventQueue* eq; EventQueue* eq;
if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) if (!Emu.GetIdManager().GetIDData(equeue_id, eq))

View File

@ -216,6 +216,13 @@ int cellFsStat(const u32 path_addr, mem_ptr_t<CellFsStat> sb)
} }
} }
if (path == "/dev_bdvd/PS3_GAME/USRDIR")
{
sys_fs.Warning("cellFsStat: /dev_bdvd/PS3_GAME/USRDIR mount point hack");
sb->st_mode |= CELL_FS_S_IFDIR;
return CELL_OK;
}
// TODO: Temporary solution until vfsDir is implemented // TODO: Temporary solution until vfsDir is implemented
wxString real_path; wxString real_path;
Emu.GetVFS().GetDevice(path, real_path); Emu.GetVFS().GetDevice(path, real_path);

View File

@ -7,16 +7,36 @@ SysCallBase sys_lwcond("sys_lwcond");
int sys_lwcond_create(mem_ptr_t<sys_lwcond_t> lwcond, mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwcond_attribute_t> attr) int sys_lwcond_create(mem_ptr_t<sys_lwcond_t> lwcond, mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwcond_attribute_t> attr)
{ {
sys_lwcond.Warning("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)", sys_lwcond.Log("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)",
lwcond.GetAddr(), lwmutex.GetAddr(), attr.GetAddr()); lwcond.GetAddr(), lwmutex.GetAddr(), attr.GetAddr());
if (!lwcond.IsGood() || !lwmutex.IsGood() || !attr.IsGood()) return CELL_EFAULT; if (!lwcond.IsGood() /*|| !lwmutex.IsGood()*/ || !attr.IsGood())
{
return CELL_EFAULT;
}
lwcond->lwmutex = lwmutex.GetAddr(); lwcond->lwmutex = lwmutex.GetAddr();
lwcond->lwcond_queue = sys_lwcond.GetNewId(new LWCond(attr->name_u64)); lwcond->lwcond_queue = sys_lwcond.GetNewId(new SleepQueue(attr->name_u64));
if (lwmutex.IsGood())
{
if (lwmutex->attribute.ToBE() & se32(SYS_SYNC_RETRY))
{
sys_lwcond.Warning("Unsupported SYS_SYNC_RETRY lwmutex protocol");
}
if (lwmutex->attribute.ToBE() & se32(SYS_SYNC_RECURSIVE))
{
sys_lwcond.Warning("Recursive lwmutex(sq=%d)", (u32)lwmutex->sleep_queue);
}
}
else
{
sys_lwcond.Warning("Invalid lwmutex address(0x%x)", lwmutex.GetAddr());
}
sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d",
wxString(attr->name, 8).wx_str(), lwmutex.GetAddr(), (u32)lwcond->lwcond_queue);
sys_lwcond.Warning("*** lwcond created [%s] (attr=0x%x, lwmutex.sq=0x%x): id = %d",
wxString(attr->name, 8).wx_str(), (u32)lwmutex->attribute, (u32)lwmutex->sleep_queue, (u32)lwcond->lwcond_queue);
return CELL_OK; return CELL_OK;
} }
@ -24,12 +44,25 @@ int sys_lwcond_destroy(mem_ptr_t<sys_lwcond_t> lwcond)
{ {
sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.GetAddr()); sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.GetAddr());
if (!lwcond.IsGood()) return CELL_EFAULT; if (!lwcond.IsGood())
LWCond* lwc; {
u32 id = (u32)lwcond->lwcond_queue; return CELL_EFAULT;
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; }
Emu.GetIdManager().RemoveID(id); u32 lwc = lwcond->lwcond_queue;
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData(lwc, sq))
{
return CELL_ESRCH;
}
if (!sq->finalize())
{
return CELL_EBUSY;
}
Emu.GetIdManager().RemoveID(lwc);
return CELL_OK; return CELL_OK;
} }
@ -37,12 +70,34 @@ int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond)
{ {
sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr()); sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.GetAddr());
if (!lwcond.IsGood()) return CELL_EFAULT; if (!lwcond.IsGood())
LWCond* lwc; {
u32 id = (u32)lwcond->lwcond_queue; return CELL_EFAULT;
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; }
lwc->signal(mem_ptr_t<sys_lwmutex_t>(lwcond->lwmutex)->attribute); SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
{
return CELL_ESRCH;
}
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
be_t<u32> tid = GetCurrentPPUThread().GetId();
if (be_t<u32> target = mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())
{
if (mutex->owner.trylock(target) != SMR_OK)
{
mutex->owner.lock(tid);
mutex->recursive_count = 1;
mutex->owner.unlock(tid, target);
}
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal(sq=%d) aborted", (u32)lwcond->lwcond_queue);
}
return CELL_OK; return CELL_OK;
} }
@ -51,12 +106,34 @@ int sys_lwcond_signal_all(mem_ptr_t<sys_lwcond_t> lwcond)
{ {
sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.GetAddr()); sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.GetAddr());
if (!lwcond.IsGood()) return CELL_EFAULT; if (!lwcond.IsGood())
LWCond* lwc; {
u32 id = (u32)lwcond->lwcond_queue; return CELL_EFAULT;
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; }
lwc->signal_all(); SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
{
return CELL_ESRCH;
}
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
be_t<u32> tid = GetCurrentPPUThread().GetId();
while (be_t<u32> target = mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())
{
if (mutex->owner.trylock(target) != SMR_OK)
{
mutex->owner.lock(tid);
mutex->recursive_count = 1;
mutex->owner.unlock(tid, target);
}
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal_all(sq=%d) aborted", (u32)lwcond->lwcond_queue);
}
return CELL_OK; return CELL_OK;
} }
@ -65,12 +142,38 @@ int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
{ {
sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.GetAddr(), ppu_thread_id); sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.GetAddr(), ppu_thread_id);
if (!lwcond.IsGood()) return CELL_EFAULT; if (!lwcond.IsGood())
LWCond* lwc; {
u32 id = (u32)lwcond->lwcond_queue; return CELL_EFAULT;
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; }
if (!lwc->signal_to(ppu_thread_id)) return CELL_EPERM; SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
{
return CELL_ESRCH;
}
if (!sq->invalidate(ppu_thread_id))
{
return CELL_EPERM;
}
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
be_t<u32> tid = GetCurrentPPUThread().GetId();
be_t<u32> target = ppu_thread_id;
if (mutex->owner.trylock(target) != SMR_OK)
{
mutex->owner.lock(tid);
mutex->recursive_count = 1;
mutex->owner.unlock(tid, target);
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal_to(sq=%d, to=%d) aborted", (u32)lwcond->lwcond_queue, ppu_thread_id);
}
return CELL_OK; return CELL_OK;
} }
@ -79,49 +182,58 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
{ {
sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.GetAddr(), timeout); sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.GetAddr(), timeout);
if (!lwcond.IsGood()) return CELL_EFAULT; if (!lwcond.IsGood())
LWCond* lwc; {
u32 id = (u32)lwcond->lwcond_queue; return CELL_EFAULT;
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH; }
const u32 tid = GetCurrentPPUThread().GetId();
mem_ptr_t<sys_lwmutex_t> lwmutex(lwcond->lwmutex); SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
{
return CELL_ESRCH;
}
if ((u32)lwmutex->owner.GetOwner() != tid) return CELL_EPERM; // caller must own this lwmutex mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
lwc->begin_waiting(tid); u32 tid_le = GetCurrentPPUThread().GetId();
be_t<u32> tid = tid_le;
if (mutex->owner.GetOwner() != tid)
{
return CELL_EPERM; // caller must own this lwmutex
}
sq->push(tid_le);
mutex->recursive_count = 0;
mutex->owner.unlock(tid);
u32 counter = 0; u32 counter = 0;
const u32 max_counter = timeout ? (timeout / 1000) : 20000; const u32 max_counter = timeout ? (timeout / 1000) : ~0;
bool was_locked = true; while (true)
do
{ {
if (Emu.IsStopped()) /* switch (mutex->trylock(tid))
{ {
ConLog.Warning("sys_lwcond_wait(sq id=%d, ...) aborted", id); case SMR_OK: mutex->unlock(tid); break;
return CELL_ETIMEDOUT; case SMR_SIGNAL: return CELL_OK;
} */
if (mutex->owner.GetOwner() == tid)
{
_mm_mfence();
mutex->recursive_count = 1;
return CELL_OK;
} }
if (was_locked) lwmutex->unlock(tid);
Sleep(1); Sleep(1);
if (was_locked = (lwmutex->trylock(tid) == CELL_OK))
{
if (lwc->check(tid))
{
return CELL_OK;
}
}
if (counter++ > max_counter) if (counter++ > max_counter)
{ {
if (!timeout) sq->invalidate(tid_le);
{ return CELL_ETIMEDOUT;
sys_lwcond.Warning("sys_lwcond_wait(lwcond_addr=0x%x): TIMEOUT", lwcond.GetAddr()); }
counter = 0; if (Emu.IsStopped())
} {
else ConLog.Warning("sys_lwcond_wait(sq=%d) aborted", (u32)lwcond->lwcond_queue);
{ return CELL_OK;
lwc->stop_waiting(tid); }
return CELL_ETIMEDOUT; }
}
}
} while (true);
} }

View File

@ -13,108 +13,4 @@ struct sys_lwcond_t
{ {
be_t<u32> lwmutex; be_t<u32> lwmutex;
be_t<u32> lwcond_queue; be_t<u32> lwcond_queue;
};
#pragma pack()
struct LWCond
{
std::mutex m_lock;
Array<u32> waiters; // list of waiting threads
Array<u32> signaled; // list of signaled threads
u64 m_name; // not used
LWCond(u64 name)
: m_name(name)
{
}
void signal(u32 _protocol)
{
std::lock_guard<std::mutex> lock(m_lock);
if (waiters.GetCount())
{
if ((_protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) == SYS_SYNC_PRIORITY)
{
u64 max_prio = 0;
u32 sel = 0;
for (u32 i = 0; i < waiters.GetCount(); i++)
{
CPUThread* t = Emu.GetCPU().GetThread(waiters[i]);
if (!t) continue;
u64 prio = t->GetPrio();
if (prio > max_prio)
{
max_prio = prio;
sel = i;
}
}
signaled.AddCpy(waiters[sel]);
waiters.RemoveAt(sel);
}
else // SYS_SYNC_FIFO
{
signaled.AddCpy(waiters[0]);
waiters.RemoveAt(0);
}
}
}
void signal_all()
{
std::lock_guard<std::mutex> lock(m_lock);
signaled.AppendFrom(waiters); // "nobody cares" protocol (!)
waiters.Clear();
}
bool signal_to(u32 id) // returns false if not found
{
std::lock_guard<std::mutex> lock(m_lock);
for (u32 i = waiters.GetCount() - 1; ~i; i--)
{
if (waiters[i] == id)
{
waiters.RemoveAt(i);
signaled.AddCpy(id);
return true;
}
}
return false;
}
void begin_waiting(u32 id)
{
std::lock_guard<std::mutex> lock(m_lock);
waiters.AddCpy(id);
}
void stop_waiting(u32 id)
{
std::lock_guard<std::mutex> lock(m_lock);
for (u32 i = waiters.GetCount() - 1; ~i; i--)
{
if (waiters[i] == id)
{
waiters.RemoveAt(i);
break;
}
}
}
bool check(u32 id) // returns true if signaled
{
std::lock_guard<std::mutex> lock(m_lock);
for (u32 i = signaled.GetCount() - 1; ~i; i--)
{
if (signaled[i] == id)
{
signaled.RemoveAt(i);
return true;
}
}
return false;
}
}; };

View File

@ -15,7 +15,7 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
{ {
case se32(SYS_SYNC_RECURSIVE): break; case se32(SYS_SYNC_RECURSIVE): break;
case se32(SYS_SYNC_NOT_RECURSIVE): break; case se32(SYS_SYNC_NOT_RECURSIVE): break;
default: sc_lwmutex.Error("Unknown 0x%x recursive attr", (u32)attr->attr_recursive); return CELL_EINVAL; default: sc_lwmutex.Error("Unknown recursive attribute(0x%x)", (u32)attr->attr_recursive); return CELL_EINVAL;
} }
switch (attr->attr_protocol.ToBE()) switch (attr->attr_protocol.ToBE())
@ -24,7 +24,7 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
case se32(SYS_SYNC_RETRY): break; case se32(SYS_SYNC_RETRY): break;
case se32(SYS_SYNC_PRIORITY_INHERIT): sc_lwmutex.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL; case se32(SYS_SYNC_PRIORITY_INHERIT): sc_lwmutex.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL;
case se32(SYS_SYNC_FIFO): break; case se32(SYS_SYNC_FIFO): break;
default: sc_lwmutex.Error("Unknown 0x%x protocol attr", (u32)attr->attr_protocol); return CELL_EINVAL; default: sc_lwmutex.Error("Unknown protocol attribute(0x%x)", (u32)attr->attr_protocol); return CELL_EINVAL;
} }
lwmutex->attribute = attr->attr_protocol | attr->attr_recursive; lwmutex->attribute = attr->attr_protocol | attr->attr_recursive;
@ -35,7 +35,7 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
u32 sq_id = sc_lwmutex.GetNewId(new SleepQueue(attr->name_u64)); u32 sq_id = sc_lwmutex.GetNewId(new SleepQueue(attr->name_u64));
lwmutex->sleep_queue = sq_id; lwmutex->sleep_queue = sq_id;
sc_lwmutex.Log("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", sc_lwmutex.Warning("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d",
wxString(attr->name, 8).wx_str(), (u32)lwmutex->attribute, sq_id); wxString(attr->name, 8).wx_str(), (u32)lwmutex->attribute, sq_id);
return CELL_OK; return CELL_OK;
@ -43,7 +43,7 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex) int sys_lwmutex_destroy(mem_ptr_t<sys_lwmutex_t> lwmutex)
{ {
sc_lwmutex.Log("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr()); sc_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.GetAddr());
if (!lwmutex.IsGood()) return CELL_EFAULT; if (!lwmutex.IsGood()) return CELL_EFAULT;
@ -67,6 +67,9 @@ int sys_lwmutex_lock(mem_ptr_t<sys_lwmutex_t> lwmutex, u64 timeout)
if (!lwmutex.IsGood()) return CELL_EFAULT; if (!lwmutex.IsGood()) return CELL_EFAULT;
//ConLog.Write("*** lock mutex (addr=0x%x, attr=0x%x, Nrec=%d, owner=%d, waiter=%d)",
//lwmutex.GetAddr(), (u32)lwmutex->attribute, (u32)lwmutex->recursive_count, lwmutex->owner.GetOwner(), (u32)lwmutex->waiter);
return lwmutex->lock(GetCurrentPPUThread().GetId(), timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0); return lwmutex->lock(GetCurrentPPUThread().GetId(), timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0);
} }
@ -85,6 +88,9 @@ int sys_lwmutex_unlock(mem_ptr_t<sys_lwmutex_t> lwmutex)
if (!lwmutex.IsGood()) return CELL_EFAULT; if (!lwmutex.IsGood()) return CELL_EFAULT;
//ConLog.Write("*** unlocking mutex (addr=0x%x, attr=0x%x, Nrec=%d, owner=%d, waiter=%d)",
//lwmutex.GetAddr(), (u32)lwmutex->attribute, (u32)lwmutex->recursive_count, (u32)lwmutex->owner.GetOwner(), (u32)lwmutex->waiter);
return lwmutex->unlock(GetCurrentPPUThread().GetId()); return lwmutex->unlock(GetCurrentPPUThread().GetId());
} }
@ -160,18 +166,38 @@ u32 SleepQueue::pop_prio_inherit() // (TODO)
return 0; return 0;
} }
void SleepQueue::invalidate(u32 tid) bool SleepQueue::invalidate(u32 tid)
{ {
SMutexLocker lock(m_mutex); SMutexLocker lock(m_mutex);
for (u32 i = 0; i < list.GetCount(); i++) if (tid) for (u32 i = 0; i < list.GetCount(); i++)
{ {
if (list[i] = tid) if (list[i] = tid)
{ {
list[i] = 0; list[i] = 0;
return; return true;
} }
} }
return false;
}
bool SleepQueue::finalize()
{
u32 tid = GetCurrentPPUThread().GetId();
m_mutex.lock(tid);
for (u32 i = 0; i < list.GetCount(); i++)
{
if (list[i])
{
m_mutex.unlock(tid);
return false;
}
}
return true;
} }
int sys_lwmutex_t::trylock(be_t<u32> tid) int sys_lwmutex_t::trylock(be_t<u32> tid)

View File

@ -8,7 +8,7 @@ enum
SYS_SYNC_FIFO = 1, SYS_SYNC_FIFO = 1,
// Priority Order // Priority Order
SYS_SYNC_PRIORITY = 2, SYS_SYNC_PRIORITY = 2,
// Basic Priority Inheritance Protocol // Basic Priority Inheritance Protocol (probably not implemented)
SYS_SYNC_PRIORITY_INHERIT = 3, SYS_SYNC_PRIORITY_INHERIT = 3,
// Not selected while unlocking // Not selected while unlocking
SYS_SYNC_RETRY = 4, SYS_SYNC_RETRY = 4,
@ -59,7 +59,8 @@ struct SleepQueue
u32 pop(); // SYS_SYNC_FIFO u32 pop(); // SYS_SYNC_FIFO
u32 pop_prio(); // SYS_SYNC_PRIORITY u32 pop_prio(); // SYS_SYNC_PRIORITY
u32 pop_prio_inherit(); // (TODO) u32 pop_prio_inherit(); // (TODO)
void invalidate(u32 tid); bool invalidate(u32 tid);
bool finalize();
}; };
struct sys_lwmutex_t struct sys_lwmutex_t
@ -84,26 +85,4 @@ struct sys_lwmutex_t
int trylock(be_t<u32> tid); int trylock(be_t<u32> tid);
int unlock(be_t<u32> tid); int unlock(be_t<u32> tid);
int lock(be_t<u32> tid, u64 timeout); int lock(be_t<u32> tid, u64 timeout);
}; };
/*
class lwmutex_locker
{
mem_ptr_t<sys_lwmutex_t> m_mutex;
be_t<u32> m_id;
lwmutex_locker(mem_ptr_t<sys_lwmutex_t> lwmutex, be_t<u32> tid, u64 timeout = 0)
: m_id(tid)
, m_mutex(lwmutex)
{
if (int res = m_mutex->lock(m_id, timeout))
{
ConLog.Error("lwmutex_locker: m_mutex->lock failed(res=0x%x)", res);
Emu.Pause();
}
}
~lwmutex_locker()
{
m_mutex->unlock(m_id);
}
};*/

View File

@ -5,97 +5,192 @@
SysCallBase sys_mtx("sys_mutex"); SysCallBase sys_mtx("sys_mutex");
int sys_mutex_create(u32 mutex_id_addr, u32 attr_addr) int sys_mutex_create(mem32_t mutex_id, mem_ptr_t<sys_mutex_attribute> attr)
{ {
sys_mtx.Warning("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", sys_mtx.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id.GetAddr(), attr.GetAddr());
mutex_id_addr, attr_addr);
if(!Memory.IsGoodAddr(mutex_id_addr) || !Memory.IsGoodAddr(attr_addr)) return CELL_EFAULT; if (!mutex_id.IsGood() || !attr.IsGood())
{
return CELL_EFAULT;
}
mutex_attr attr = (mutex_attr&)Memory[attr_addr]; switch (attr->protocol.ToBE())
attr.protocol = re(attr.protocol); {
attr.recursive = re(attr.recursive); case se32(SYS_SYNC_FIFO): break;
attr.pshared = re(attr.pshared); case se32(SYS_SYNC_PRIORITY): break;
attr.adaptive = re(attr.adaptive); case se32(SYS_SYNC_PRIORITY_INHERIT): sys_mtx.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT protocol"); break;
attr.ipc_key = re(attr.ipc_key); case se32(SYS_SYNC_RETRY): sys_mtx.Error("Invalid SYS_SYNC_RETRY protocol"); return CELL_EINVAL;
attr.flags = re(attr.flags); default: sys_mtx.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL;
}
sys_mtx.Log("*** protocol = %d", attr.protocol);
sys_mtx.Log("*** recursive = %d", attr.recursive);
sys_mtx.Log("*** pshared = %d", attr.pshared);
sys_mtx.Log("*** ipc_key = 0x%llx", attr.ipc_key);
sys_mtx.Log("*** flags = 0x%x", attr.flags);
sys_mtx.Log("*** name = %s", attr.name);
Memory.Write32(mutex_id_addr, sys_mtx.GetNewId(new mutex(attr))); bool is_recursive;
switch (attr->recursive.ToBE())
{
case se32(SYS_SYNC_RECURSIVE): is_recursive = true; break;
case se32(SYS_SYNC_NOT_RECURSIVE): is_recursive = false; break;
default: sys_mtx.Error("Unknown recursive attribute(0x%x)", (u32)attr->recursive); return CELL_EINVAL;
}
if (attr->pshared.ToBE() != se32(0x200))
{
sys_mtx.Error("Unknown pshared attribute(0x%x)", (u32)attr->pshared);
return CELL_EINVAL;
}
mutex_id = sys_mtx.GetNewId(new Mutex((u32)attr->protocol, is_recursive, attr->name_u64));
sys_mtx.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d",
wxString(attr->name, 8).wx_str(), (u32)attr->protocol,
wxString(is_recursive ? "true" : "false").wx_str(), mutex_id.GetValue());
// TODO: unlock mutex when owner thread does exit
return CELL_OK; return CELL_OK;
} }
int sys_mutex_destroy(u32 mutex_id) int sys_mutex_destroy(u32 mutex_id)
{ {
sys_mtx.Log("sys_mutex_destroy(mutex_id=0x%x)", mutex_id); sys_mtx.Warning("sys_mutex_destroy(mutex_id=%d)", mutex_id);
if(!sys_mtx.CheckId(mutex_id)) return CELL_ESRCH; Mutex* mutex;
if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
{
return CELL_ESRCH;
}
if ((u32&)mutex->cond_count) // check if associated condition variable exists
{
return CELL_EPERM;
}
u32 tid = GetCurrentPPUThread().GetId();
if (mutex->m_mutex.trylock(tid)) // check if locked
{
return CELL_EBUSY;
}
if (!mutex->m_queue.finalize())
{
mutex->m_mutex.unlock(tid);
return CELL_EBUSY;
}
mutex->m_mutex.unlock(tid, ~0);
Emu.GetIdManager().RemoveID(mutex_id); Emu.GetIdManager().RemoveID(mutex_id);
return CELL_OK; return CELL_OK;
} }
int sys_mutex_lock(u32 mutex_id, u64 timeout) int sys_mutex_lock(u32 mutex_id, u64 timeout)
{ {
sys_mtx.Log("sys_mutex_lock(mutex_id=0x%x, timeout=0x%llx)", mutex_id, timeout); sys_mtx.Log("sys_mutex_lock(mutex_id=%d, timeout=0x%llx)", mutex_id, timeout);
mutex* mtx_data = nullptr; Mutex* mutex;
if(!sys_mtx.CheckId(mutex_id, mtx_data)) return CELL_ESRCH; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
u32 counter = 0;
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
do
{ {
if (Emu.IsStopped()) return CELL_ESRCH;
}
u32 tid = GetCurrentPPUThread().GetId();
if (mutex->m_mutex.GetOwner() == tid)
{
if (mutex->is_recursive)
{ {
ConLog.Warning("sys_mutex_lock(mutex_id=%d, ...) aborted", mutex_id); if (++mutex->recursive == 0)
return CELL_ETIMEDOUT; {
return CELL_EKRESOURCE;
}
return CELL_OK;
} }
else
if (mtx_data->mtx.TryLock() == wxMUTEX_NO_ERROR) return CELL_OK;
Sleep(1);
if (counter++ > max_counter)
{ {
if (!timeout) return CELL_EDEADLK;
{ }
counter = 0; }
}
else switch (mutex->m_mutex.trylock(tid))
{ {
return CELL_ETIMEDOUT; case SMR_OK: mutex->recursive = 1; return CELL_OK;
} case SMR_FAILED: break;
} default: goto abort;
} while (true); }
mutex->m_queue.push(tid);
switch (mutex->m_mutex.lock(tid, timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0))
{
case SMR_OK: mutex->m_queue.invalidate(tid);
case SMR_SIGNAL: mutex->recursive = 1; return CELL_OK;
case SMR_TIMEOUT: return CELL_ETIMEDOUT;
default: goto abort;
}
abort:
if (Emu.IsStopped())
{
ConLog.Warning("sys_mutex_lock(id=%d) aborted", mutex_id);
return CELL_OK;
}
return CELL_ESRCH;
} }
int sys_mutex_trylock(u32 mutex_id) int sys_mutex_trylock(u32 mutex_id)
{ {
sys_mtx.Log("sys_mutex_trylock(mutex_id=0x%x)", mutex_id); sys_mtx.Log("sys_mutex_trylock(mutex_id=%d)", mutex_id);
mutex* mtx_data = nullptr; Mutex* mutex;
if(!sys_mtx.CheckId(mutex_id, mtx_data)) return CELL_ESRCH; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
{
return CELL_ESRCH;
}
if (mtx_data->mtx.TryLock() != wxMUTEX_NO_ERROR) return CELL_EBUSY; u32 tid = GetCurrentPPUThread().GetId();
return CELL_OK; if (mutex->m_mutex.GetOwner() == tid)
{
if (mutex->is_recursive)
{
if (++mutex->recursive == 0)
{
return CELL_EKRESOURCE;
}
return CELL_OK;
}
else
{
return CELL_EDEADLK;
}
}
switch (mutex->m_mutex.trylock(tid))
{
case SMR_OK: mutex->recursive = 1; return CELL_OK;
}
return CELL_EBUSY;
} }
int sys_mutex_unlock(u32 mutex_id) int sys_mutex_unlock(u32 mutex_id)
{ {
sys_mtx.Log("sys_mutex_unlock(mutex_id=0x%x)", mutex_id); sys_mtx.Log("sys_mutex_unlock(mutex_id=%d)", mutex_id);
mutex* mtx_data = nullptr; Mutex* mutex;
if(!sys_mtx.CheckId(mutex_id, mtx_data)) return CELL_ESRCH; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
{
return CELL_ESRCH;
}
mtx_data->mtx.Unlock(); u32 tid = GetCurrentPPUThread().GetId();
return CELL_OK; if (mutex->m_mutex.GetOwner() == tid)
{
mutex->recursive--;
if (!mutex->recursive)
{
mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop());
}
return CELL_OK;
}
return CELL_EPERM;
} }

View File

@ -1,25 +1,36 @@
#pragma once #pragma once
struct mutex_attr struct sys_mutex_attribute
{ {
u32 protocol; be_t<u32> protocol; // SYS_SYNC_FIFO, SYS_SYNC_PRIORITY or SYS_SYNC_PRIORITY_INHERIT
u32 recursive; be_t<u32> recursive; // SYS_SYNC_RECURSIVE or SYS_SYNC_NOT_RECURSIVE
u32 pshared; be_t<u32> pshared; // always 0x200 (not shared)
u32 adaptive; be_t<u32> adaptive;
u64 ipc_key; be_t<u64> ipc_key;
int flags; be_t<int> flags;
u32 pad; be_t<u32> pad;
char name[8]; union
{
char name[8];
u64 name_u64;
};
}; };
struct mutex struct Mutex
{ {
wxMutex mtx; SMutex m_mutex;
mutex_attr attr; SleepQueue m_queue;
u32 recursive; // recursive locks count
std::atomic<u32> cond_count; // count of condition variables associated
mutex(const mutex_attr& attr) const u32 protocol;
: mtx() const bool is_recursive;
, attr(attr)
Mutex(u32 protocol, bool is_recursive, u64 name)
: protocol(protocol)
, is_recursive(is_recursive)
, m_queue(name)
, cond_count(0)
{ {
} }
}; };

View File

@ -32,7 +32,8 @@ void sys_ppu_thread_exit(int errorcode)
int sys_ppu_thread_yield() int sys_ppu_thread_yield()
{ {
sysPrxForUser.Log("sys_ppu_thread_yield()"); sysPrxForUser.Log("sys_ppu_thread_yield()");
Sleep(1);
return CELL_OK; return CELL_OK;
} }

View File

@ -247,12 +247,12 @@ int cellPadSetPortSetting(u32 port_no, u32 port_setting)
int cellPadInfoPressMode(u32 port_no) int cellPadInfoPressMode(u32 port_no)
{ {
sys_io.Log("cellPadInfoPressMode(port_no=%d)", port_no); sys_io.Error("cellPadInfoPressMode(port_no=%d)", port_no);
return CELL_OK; return CELL_OK;
} }
int cellPadInfoSensorMode(u32 port_no) int cellPadInfoSensorMode(u32 port_no)
{ {
sys_io.Log("cellPadInfoSensorMode(port_no=%d)", port_no); sys_io.Error("cellPadInfoSensorMode(port_no=%d)", port_no);
return CELL_OK; return CELL_OK;
} }

View File

@ -625,7 +625,6 @@ int sys_spu_thread_connect_event(u32 id, u32 eq, u32 et, u8 spup)
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
/* /*
for(int j=0; j<equeue->pos; ++j) for(int j=0; j<equeue->pos; ++j)
{ {
@ -656,9 +655,22 @@ int sys_spu_thread_throw_event(u8 spup, u24 data0, u32 data1);
int sys_spu_thread_tryreceive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3); int sys_spu_thread_tryreceive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3);
*/ */
int sys_spu_thread_bind_queue(u32 id, u32 equeue_id, u32 spuq_num) int sys_spu_thread_bind_queue(u32 id, u32 eq, u32 spuq_num)
{ {
sc_spu.Error("sys_spu_thread_bind_queue(id=%d, equeue_id=%d, spuq_num=%d)", id, equeue_id, spuq_num); sc_spu.Error("sys_spu_thread_bind_queue(id=%d, equeue_id=%d, spuq_num=%d)", id, eq, spuq_num);
EventQueue* equeue;
if(!sys_event.CheckId(eq, equeue))
{
return CELL_ESRCH;
}
CPUThread* thr = Emu.GetCPU().GetThread(id);
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
{
return CELL_ESRCH;
}
return CELL_OK; return CELL_OK;
} }

View File

@ -10,7 +10,8 @@
#include <sys/timeb.h> #include <sys/timeb.h>
SysCallBase sys_time("sys_time"); SysCallBase sys_time("sys_time");
static const u64 timebase_frequency = 79800000;
//static const u64 timebase_frequency = 79800000;
extern int cellSysutilGetSystemParamInt(int id, mem32_t value); extern int cellSysutilGetSystemParamInt(int id, mem32_t value);
int sys_time_get_timezone(mem32_t timezone, mem32_t summertime) int sys_time_get_timezone(mem32_t timezone, mem32_t summertime)
@ -23,11 +24,26 @@ int sys_time_get_timezone(mem32_t timezone, mem32_t summertime)
return CELL_OK; return CELL_OK;
} }
u64 get_system_time()
{
#ifdef _WIN32
LARGE_INTEGER cycle;
LARGE_INTEGER freq;
QueryPerformanceCounter(&cycle);
QueryPerformanceFrequency(&freq);
return cycle.QuadPart * 1000000 / freq.QuadPart;
#else
struct timespec ts;
if (!clock_gettime(CLOCK_MONOTONIC, &ts))
return ts.tv_sec * (s64)10000000 + (s64)ts.tv_nsec / (s64)100;
#endif
}
int sys_time_get_current_time(u32 sec_addr, u32 nsec_addr) int sys_time_get_current_time(u32 sec_addr, u32 nsec_addr)
{ {
sys_time.Log("sys_time_get_current_time(sec_addr=0x%x, nsec_addr=0x%x)", sec_addr, nsec_addr); sys_time.Log("sys_time_get_current_time(sec_addr=0x%x, nsec_addr=0x%x)", sec_addr, nsec_addr);
u64 time = sys_time_get_system_time(); u64 time = get_system_time();
Memory.Write64(sec_addr, time / 1000000); Memory.Write64(sec_addr, time / 1000000);
Memory.Write64(nsec_addr, time % 1000000); Memory.Write64(nsec_addr, time % 1000000);
@ -38,21 +54,15 @@ int sys_time_get_current_time(u32 sec_addr, u32 nsec_addr)
s64 sys_time_get_system_time() s64 sys_time_get_system_time()
{ {
sys_time.Log("sys_time_get_system_time()"); sys_time.Log("sys_time_get_system_time()");
#ifdef _WIN32 return get_system_time();
LARGE_INTEGER cycle;
QueryPerformanceCounter(&cycle);
return cycle.QuadPart;
#else
struct timespec ts;
if (!clock_gettime(CLOCK_MONOTONIC, &ts))
return ts.tv_sec * (s64)10000000 + (s64)ts.tv_nsec / (s64)100;
#endif
} }
u64 sys_time_get_timebase_frequency() u64 sys_time_get_timebase_frequency()
{ {
sys_time.Log("sys_time_get_timebase_frequency()"); sys_time.Log("sys_time_get_timebase_frequency()");
return 1000000;
/*
#ifdef _WIN32 #ifdef _WIN32
static LARGE_INTEGER frequency = {0ULL}; static LARGE_INTEGER frequency = {0ULL};
@ -60,6 +70,7 @@ u64 sys_time_get_timebase_frequency()
return frequency.QuadPart; return frequency.QuadPart;
#else #else
return 10000000; return 10000000;
#endif #endif
*/
} }

View File

@ -265,7 +265,7 @@ void LogFrame::Task()
m_log.InsertItem(cur_item, wxString(item.m_prefix).wx_str()); m_log.InsertItem(cur_item, wxString(item.m_prefix).wx_str());
m_log.SetItem(cur_item, 1, wxString(item.m_text).wx_str()); m_log.SetItem(cur_item, 1, wxString(item.m_text).wx_str());
m_log.SetItemTextColour(cur_item, wxString(item.m_colour).wx_str()); m_log.SetItemTextColour(cur_item, wxString(item.m_colour).wx_str());
m_log.SetColumnWidth(0, -1); m_log.SetColumnWidth(0, -1); // crashes on exit
m_log.SetColumnWidth(1, -1); m_log.SetColumnWidth(1, -1);
::SendMessage((HWND)m_log.GetHWND(), WM_VSCROLL, SB_BOTTOM, 0); ::SendMessage((HWND)m_log.GetHWND(), WM_VSCROLL, SB_BOTTOM, 0);