mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-14 10:21:21 +00:00
Merge pull request #80 from Nekotekina/master
Sync changes, simple file output for sound
This commit is contained in:
commit
51613df455
1
.gitignore
vendored
1
.gitignore
vendored
@ -28,6 +28,7 @@
|
||||
*.unsuccessfulbuild
|
||||
*.res
|
||||
*.dump
|
||||
*.wav
|
||||
|
||||
/libs
|
||||
/ipch
|
||||
|
@ -158,7 +158,7 @@ struct CellAudioOutConfiguration
|
||||
u8 channel;
|
||||
u8 encoder;
|
||||
u8 reserved[10];
|
||||
u32 downMixer;
|
||||
be_t<u32> downMixer;
|
||||
};
|
||||
|
||||
struct CellAudioOutSoundMode
|
||||
@ -167,7 +167,7 @@ struct CellAudioOutSoundMode
|
||||
u8 channel;
|
||||
u8 fs;
|
||||
u8 reserved;
|
||||
u32 layout;
|
||||
be_t<u32> layout;
|
||||
};
|
||||
|
||||
struct CellAudioOutDeviceInfo
|
||||
@ -175,9 +175,9 @@ struct CellAudioOutDeviceInfo
|
||||
u8 portType;
|
||||
u8 availableModeCount;
|
||||
u8 state;
|
||||
u8 reserved[3];
|
||||
u16 latency;
|
||||
CellAudioOutSoundMode availableModes[16];
|
||||
u8 reserved[3];
|
||||
be_t<u16> latency;
|
||||
CellAudioOutSoundMode availableModes[16];
|
||||
};
|
||||
|
||||
struct CellAudioOutState
|
||||
@ -185,7 +185,7 @@ struct CellAudioOutState
|
||||
u8 state;
|
||||
u8 encoder;
|
||||
u8 reserved[6];
|
||||
u32 downMixer;
|
||||
be_t<u32> downMixer;
|
||||
CellAudioOutSoundMode soundMode;
|
||||
};
|
||||
|
||||
@ -193,7 +193,7 @@ struct CellAudioOutSoundMode2
|
||||
{
|
||||
u8 type;
|
||||
u8 channel;
|
||||
u16 fs;
|
||||
be_t<u16> fs;
|
||||
u8 reserved[4];
|
||||
};
|
||||
|
||||
@ -204,8 +204,8 @@ struct CellAudioOutDeviceInfo2
|
||||
u8 state;
|
||||
u8 deviceNumber;
|
||||
u8 reserved[12];
|
||||
u64 deviceId;
|
||||
u64 type;
|
||||
be_t<u64> deviceId;
|
||||
be_t<u64> type;
|
||||
char name[64];
|
||||
CellAudioOutSoundMode2 availableModes2[16];
|
||||
};
|
||||
@ -229,7 +229,7 @@ struct CellAudioInSoundMode
|
||||
{
|
||||
u8 type;
|
||||
u8 channel;
|
||||
u16 fs;
|
||||
be_t<u16> fs;
|
||||
u8 reserved[4];
|
||||
};
|
||||
|
||||
@ -240,8 +240,8 @@ struct CellAudioInDeviceInfo
|
||||
u8 state;
|
||||
u8 deviceNumber;
|
||||
u8 reserved[12];
|
||||
u64 deviceId;
|
||||
u64 type;
|
||||
be_t<u64> deviceId;
|
||||
be_t<u64> type;
|
||||
char name[64];
|
||||
CellAudioInSoundMode availableModes[16];
|
||||
};
|
||||
|
@ -111,7 +111,7 @@ int CPUThread::ThreadStatus()
|
||||
return CPUThread_Step;
|
||||
}
|
||||
|
||||
if(Emu.IsPaused() || Sync())
|
||||
if (Emu.IsPaused() || Sync())
|
||||
{
|
||||
return CPUThread_Sleeping;
|
||||
}
|
||||
|
@ -32,8 +32,11 @@ private:
|
||||
//0 - 10
|
||||
void STOP(u32 code)
|
||||
{
|
||||
ConLog.Warning("STOP: 0x%x (m_exit_status -> 0)", code);
|
||||
CPU.SetExitStatus(0);
|
||||
if (CPU.SPU.Out_MBox.GetCount()) // the real exit status is probably stored there
|
||||
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();
|
||||
}
|
||||
void LNOP()
|
||||
|
@ -611,7 +611,7 @@ public:
|
||||
|
||||
case SPU_RdInMbox:
|
||||
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;
|
||||
|
||||
case SPU_WrOutIntrMbox:
|
||||
|
@ -8,6 +8,8 @@ void cellAudio_load();
|
||||
void cellAudio_unload();
|
||||
Module cellAudio(0x0011, cellAudio_init, cellAudio_load, cellAudio_unload);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
enum
|
||||
{
|
||||
//libaudio Error Codes
|
||||
@ -61,6 +63,56 @@ enum
|
||||
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
|
||||
struct CellAudioPortParam
|
||||
@ -84,6 +136,7 @@ struct CellAudioPortConfig
|
||||
struct AudioPortConfig
|
||||
{
|
||||
bool m_is_audio_port_started;
|
||||
bool m_is_audio_port_stopped;
|
||||
CellAudioPortParam m_param;
|
||||
|
||||
const u32 m_buffer; // 64 KB or 128 KB with 8x16 config
|
||||
@ -91,7 +144,7 @@ struct AudioPortConfig
|
||||
|
||||
AudioPortConfig();
|
||||
|
||||
~AudioPortConfig();
|
||||
void finalize();
|
||||
};
|
||||
|
||||
struct AudioConfig //custom structure
|
||||
@ -127,15 +180,15 @@ struct AudioConfig //custom structure
|
||||
|
||||
AudioPortConfig::AudioPortConfig()
|
||||
: m_is_audio_port_started(false)
|
||||
, m_buffer(Memory.Alloc(1024 * 128, 1024))
|
||||
, m_index(Memory.Alloc(16, 16))
|
||||
, m_buffer(Memory.Alloc(1024 * 128, 1024)) // max 128K size
|
||||
, m_index(Memory.Alloc(16, 16)) // allocation for u64 value "read index"
|
||||
{
|
||||
m_config.m_port_in_use++;
|
||||
mem64_t index(m_index);
|
||||
index = 0;
|
||||
}
|
||||
|
||||
AudioPortConfig::~AudioPortConfig()
|
||||
void AudioPortConfig::finalize()
|
||||
{
|
||||
m_config.m_port_in_use--;
|
||||
Memory.Free(m_buffer);
|
||||
@ -330,12 +383,13 @@ int cellAudioGetPortConfig(u32 portNum, mem_ptr_t<CellAudioPortConfig> portConfi
|
||||
portConfig->status = CELL_AUDIO_STATUS_READY;
|
||||
portConfig->nChannel = ref.nChannel;
|
||||
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->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
|
||||
// Memory.Write64(portConfig->readIndexAddr, 1);
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
@ -378,8 +531,8 @@ int cellAudioPortClose(u32 portNum)
|
||||
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
|
||||
}
|
||||
|
||||
delete m_config.m_ports[portNum];
|
||||
m_config.m_ports[portNum] = nullptr;
|
||||
m_config.m_ports[portNum]->finalize();
|
||||
safe_delete(m_config.m_ports[portNum]);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -403,6 +556,15 @@ int cellAudioPortStop(u32 portNum)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -428,6 +590,7 @@ int cellAudioSetPortLevel(u32 portNum, float level)
|
||||
int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key)
|
||||
{
|
||||
cellAudio.Error("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.GetAddr(), key.GetAddr());
|
||||
key = 0x123456789ABCDEF0;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -446,11 +609,11 @@ int cellAudioSetNotifyEventQueue(u64 key)
|
||||
EventQueue* 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;
|
||||
}
|
||||
|
@ -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)",
|
||||
pAddr.GetAddr(), fileSize, pSize.GetAddr());
|
||||
|
||||
//if ((u32)pAddr->magic != 0x464d4150)
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
if ((u32)pAddr->magic != 0x464d4150)
|
||||
return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
pSize = offset /*? offset : 2048*/; //hack
|
||||
|
@ -713,7 +713,7 @@ int cellRescSetConvertAndFlip(mem_ptr_t<CellGcmContextData> cntxt, s32 idx)
|
||||
int cellRescSetWaitFlip()
|
||||
{
|
||||
cellResc.Log("cellRescSetWaitFlip()");
|
||||
GSLockCurrent lock(GS_LOCK_WAIT_FLIP);
|
||||
GSLockCurrent lock(GS_LOCK_WAIT_FLIP); // could stall on exit
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -95,15 +95,13 @@ int cellSyncMutexLock(mem_ptr_t<CellSyncMutex> mutex)
|
||||
}
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
while (*(u16*)&old_order != *(u16*)&mutex->m_freed)
|
||||
while (old_order != Memory.Read16(mutex.GetAddr()))
|
||||
{
|
||||
Sleep(1);
|
||||
if (++counter >= 5000)
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
counter = 0;
|
||||
cellSync.Warning("cellSyncMutexLock(mutex=0x%x, old_order=%d, order=%d, freed=%d): TIMEOUT",
|
||||
mutex.GetAddr(), (u16)old_order, (u16)mutex->m_order, (u16)mutex->m_freed);
|
||||
ConLog.Warning("cellSyncMutexLock(mutex=0x%x) aborted", mutex.GetAddr());
|
||||
break;
|
||||
}
|
||||
}
|
||||
_mm_mfence();
|
||||
|
@ -472,12 +472,20 @@ int cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 as
|
||||
int cellSysutilCheckCallback()
|
||||
{
|
||||
cellSysutil.Log("cellSysutilCheckCallback()");
|
||||
|
||||
Emu.GetCallbackManager().m_exit_callback.Check();
|
||||
|
||||
CPUThread& thr = Emu.GetCallbackThread();
|
||||
|
||||
while(Emu.IsRunning() && thr.IsAlive())
|
||||
while (thr.IsAlive())
|
||||
{
|
||||
Sleep(1);
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("cellSysutilCheckCallback() aborted");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -485,6 +493,7 @@ int cellSysutilCheckCallback()
|
||||
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);
|
||||
|
||||
Emu.GetCallbackManager().m_exit_callback.Register(slot, func_addr, userdata);
|
||||
|
||||
wxGetApp().SendDbgCommand(DID_REGISTRED_CALLBACK);
|
||||
@ -495,6 +504,7 @@ int cellSysutilRegisterCallback(int slot, u64 func_addr, u64 userdata)
|
||||
int cellSysutilUnregisterCallback(int slot)
|
||||
{
|
||||
cellSysutil.Warning("cellSysutilUnregisterCallback(slot=%d)", slot);
|
||||
|
||||
Emu.GetCallbackManager().m_exit_callback.Unregister(slot);
|
||||
|
||||
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)
|
||||
{
|
||||
cellSysutil.Warning("cellAudioOutGetSoundAvailability(audioOut=%d,type=%d,fs=%d,option=%d)",
|
||||
audioOut,type,fs,option);
|
||||
cellSysutil.Warning("cellAudioOutGetSoundAvailability(audioOut=%d, type=%d, fs=0x%x, option=%d)",
|
||||
audioOut, type, fs, option);
|
||||
|
||||
option = 0;
|
||||
|
||||
int available = 2; // should be at least 2
|
||||
|
||||
switch(fs)
|
||||
{
|
||||
case CELL_AUDIO_OUT_FS_32KHZ:
|
||||
@ -676,17 +688,16 @@ int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option)
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_LPCM:
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_AC3:
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_DTS:
|
||||
break;
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_LPCM: break;
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_AC3: available = 0; break;
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_DTS: available = 0; break;
|
||||
|
||||
default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE;
|
||||
}
|
||||
|
||||
switch(audioOut)
|
||||
{
|
||||
case CELL_AUDIO_OUT_PRIMARY: return 2;
|
||||
case CELL_AUDIO_OUT_PRIMARY: return available;
|
||||
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)
|
||||
{
|
||||
cellSysutil.Warning("cellAudioOutGetSoundAvailability(audioOut=%d,type=%d,fs=%d,ch=%d,option=%d)",
|
||||
audioOut,type,fs,ch,option);
|
||||
cellSysutil.Warning("cellAudioOutGetSoundAvailability2(audioOut=%d, type=%d, fs=0x%x, ch=%d, option=%d)",
|
||||
audioOut, type, fs, ch, option);
|
||||
|
||||
option = 0;
|
||||
|
||||
int available = 2; // should be at least 2
|
||||
|
||||
switch(fs)
|
||||
{
|
||||
case CELL_AUDIO_OUT_FS_32KHZ:
|
||||
@ -716,27 +729,25 @@ int cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32 ch, u3
|
||||
|
||||
switch(ch)
|
||||
{
|
||||
case 2:
|
||||
case 6:
|
||||
case 8:
|
||||
break;
|
||||
case 2: break;
|
||||
case 6: available = 0; break;
|
||||
case 8: available = 0; break;
|
||||
|
||||
default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE;
|
||||
}
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_LPCM:
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_AC3:
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_DTS:
|
||||
break;
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_LPCM: break;
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_AC3: available = 0; break;
|
||||
case CELL_AUDIO_OUT_CODING_TYPE_DTS: available = 0; break;
|
||||
|
||||
default: return CELL_AUDIO_OUT_ERROR_UNSUPPORTED_SOUND_MODE;
|
||||
}
|
||||
|
||||
switch(audioOut)
|
||||
{
|
||||
case CELL_AUDIO_OUT_PRIMARY: return 1;
|
||||
case CELL_AUDIO_OUT_PRIMARY: return available;
|
||||
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;
|
||||
}
|
||||
|
||||
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)",
|
||||
audioOut, config_addr, option_addr, waitForEvent);
|
||||
cellSysutil.Warning("cellAudioOutConfigure(audioOut=%d, config_addr=0x%x, option_addr=0x%x, (!)waitForEvent=%d)",
|
||||
audioOut, config.GetAddr(), option.GetAddr(), waitForEvent);
|
||||
|
||||
if(!Memory.IsGoodAddr(config_addr, sizeof(CellAudioOutConfiguration)))
|
||||
if (!config.IsGood())
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
CellAudioOutConfiguration& config = (CellAudioOutConfiguration&)Memory[config_addr];
|
||||
|
||||
switch(audioOut)
|
||||
{
|
||||
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;
|
||||
|
@ -5,8 +5,6 @@
|
||||
void 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
while (g_FsAioReadCur != xid)
|
||||
{
|
||||
Sleep(1);
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("fsAioRead() aborted");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vfsFileBase* orig_file;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
if(func)
|
||||
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])",
|
||||
fd, (u64)aio->offset, buf_addr, (u64)aio->size, res, xid, path.wx_str());
|
||||
g_FsAioReadCur++;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
if (!aio.IsGood() || !aio_id.IsGood() || !func.IsGood())
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
if (!aio_init)
|
||||
{
|
||||
//return CELL_ENXIO;
|
||||
}
|
||||
|
||||
vfsFileBase* orig_file;
|
||||
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)
|
||||
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;
|
||||
|
||||
{
|
||||
thread t("fsAioRead", std::bind(fsAioRead, fd, aio, xid, func));
|
||||
t.detach();
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -200,6 +225,7 @@ int cellFsAioInit(mem8_ptr_t mount_point)
|
||||
{
|
||||
wxString mp = Memory.ReadString(mount_point.GetAddr());
|
||||
sys_fs.Warning("cellFsAioInit(mount_point_addr=0x%x (%s))", mount_point.GetAddr(), mp.wx_str());
|
||||
aio_init = true;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -234,4 +260,5 @@ void sys_fs_init()
|
||||
sys_fs.AddFunc(0xdb869f20, cellFsAioInit);
|
||||
sys_fs.AddFunc(0x9f951810, cellFsAioFinish);
|
||||
sys_fs.AddFunc(0x1a108ab7, cellFsGetBlockSize);
|
||||
aio_init = false;
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ static func_caller* sc_table[1024] =
|
||||
bind_func(sys_cond_wait), //107 (0x06B)
|
||||
bind_func(sys_cond_signal), //108 (0x06C)
|
||||
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)
|
||||
null_func, null_func, null_func, bind_func(sys_event_flag_clear), null_func, //119 (0x077)
|
||||
bind_func(sys_rwlock_create), //120 (0x078)
|
||||
|
@ -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);
|
||||
|
||||
//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_lock(u32 mutex_id, u64 timeout);
|
||||
extern int sys_mutex_trylock(u32 mutex_id);
|
||||
|
@ -1,13 +1,12 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "SC_Mutex.h"
|
||||
#include "Emu/SysCalls/lv2/SC_Condition.h"
|
||||
|
||||
SysCallBase sys_cond("sys_cond");
|
||||
|
||||
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());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mutex* mtx_data;
|
||||
if (!Emu.GetIdManager().GetIDData(mutex_id, mtx_data))
|
||||
Mutex* mutex;
|
||||
if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
cond_id = sys_cond.GetNewId(new condition(mtx_data->mtx, attr->name_u64));
|
||||
sys_cond.Warning("*** condition created [%s]: id = %d", wxString(attr->name, 8).wx_str(), cond_id.GetValue());
|
||||
if (mutex->is_recursive)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (true) // TODO
|
||||
if (!cond->m_queue.finalize())
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
cond->mutex->cond_count--;
|
||||
Emu.GetIdManager().RemoveID(cond_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
if(!sys_cond.CheckId(cond_id, cond_data)) return CELL_ESRCH;
|
||||
Cond* cond;
|
||||
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;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
|
||||
do
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
/* switch (mutex->m_mutex.trylock(tid))
|
||||
{
|
||||
ConLog.Warning("sys_cond_wait(cond_id=%d, ...) aborted", cond_id);
|
||||
return CELL_ETIMEDOUT;
|
||||
case SMR_OK: mutex->m_mutex.unlock(tid); break;
|
||||
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))
|
||||
{
|
||||
case wxCOND_NO_ERROR: return CELL_OK;
|
||||
case wxCOND_TIMEOUT: break;
|
||||
default: return CELL_EPERM;
|
||||
}
|
||||
Sleep(1);
|
||||
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
if (!timeout)
|
||||
{
|
||||
counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
cond->m_queue.invalidate(tid);
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_cond_wait(id=%d) aborted", cond_id);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if(!sys_cond.CheckId(cond_id, cond_data)) return CELL_ESRCH;
|
||||
Cond* cond;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
if(!sys_cond.CheckId(cond_id, cond_data)) return CELL_ESRCH;
|
||||
Cond* cond;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "SC_Mutex.h"
|
||||
|
||||
struct sys_cond_attribute
|
||||
{
|
||||
@ -12,14 +13,14 @@ struct sys_cond_attribute
|
||||
};
|
||||
};
|
||||
|
||||
struct condition
|
||||
struct Cond
|
||||
{
|
||||
wxCondition cond;
|
||||
u64 name_u64;
|
||||
Mutex* mutex; // associated with mutex
|
||||
SleepQueue m_queue;
|
||||
|
||||
condition(wxMutex& mtx, u64 name)
|
||||
: cond(mtx)
|
||||
, name_u64(name)
|
||||
Cond(Mutex* mutex, u64 name)
|
||||
: mutex(mutex)
|
||||
, m_queue(name)
|
||||
{
|
||||
}
|
||||
};
|
@ -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)
|
||||
{
|
||||
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;
|
||||
if (!Emu.GetIdManager().GetIDData(equeue_id, eq))
|
||||
|
@ -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
|
||||
wxString real_path;
|
||||
Emu.GetVFS().GetDevice(path, real_path);
|
||||
|
@ -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)
|
||||
{
|
||||
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());
|
||||
|
||||
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->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;
|
||||
}
|
||||
|
||||
@ -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());
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
if (!lwcond.IsGood())
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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());
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
if (!lwcond.IsGood())
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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());
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
if (!lwcond.IsGood())
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
if (!lwcond.IsGood())
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
if (!lwcond.IsGood()) return CELL_EFAULT;
|
||||
LWCond* lwc;
|
||||
u32 id = (u32)lwcond->lwcond_queue;
|
||||
if (!sys_lwcond.CheckId(id, lwc)) return CELL_ESRCH;
|
||||
const u32 tid = GetCurrentPPUThread().GetId();
|
||||
if (!lwcond.IsGood())
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
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
|
||||
lwc->begin_waiting(tid);
|
||||
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
|
||||
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;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
|
||||
bool was_locked = true;
|
||||
do
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
/* switch (mutex->trylock(tid))
|
||||
{
|
||||
ConLog.Warning("sys_lwcond_wait(sq id=%d, ...) aborted", id);
|
||||
return CELL_ETIMEDOUT;
|
||||
case SMR_OK: mutex->unlock(tid); break;
|
||||
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);
|
||||
if (was_locked = (lwmutex->trylock(tid) == CELL_OK))
|
||||
{
|
||||
if (lwc->check(tid))
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter++ > max_counter)
|
||||
{
|
||||
if (!timeout)
|
||||
{
|
||||
sys_lwcond.Warning("sys_lwcond_wait(lwcond_addr=0x%x): TIMEOUT", lwcond.GetAddr());
|
||||
counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lwc->stop_waiting(tid);
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
sq->invalidate(tid_le);
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("sys_lwcond_wait(sq=%d) aborted", (u32)lwcond->lwcond_queue);
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,108 +13,4 @@ struct sys_lwcond_t
|
||||
{
|
||||
be_t<u32> lwmutex;
|
||||
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;
|
||||
}
|
||||
};
|
@ -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_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())
|
||||
@ -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_PRIORITY_INHERIT): sc_lwmutex.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL;
|
||||
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;
|
||||
@ -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));
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
@ -67,6 +67,9 @@ int sys_lwmutex_lock(mem_ptr_t<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -85,6 +88,9 @@ int sys_lwmutex_unlock(mem_ptr_t<sys_lwmutex_t> lwmutex)
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@ -160,18 +166,38 @@ u32 SleepQueue::pop_prio_inherit() // (TODO)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SleepQueue::invalidate(u32 tid)
|
||||
bool SleepQueue::invalidate(u32 tid)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -8,7 +8,7 @@ enum
|
||||
SYS_SYNC_FIFO = 1,
|
||||
// Priority Order
|
||||
SYS_SYNC_PRIORITY = 2,
|
||||
// Basic Priority Inheritance Protocol
|
||||
// Basic Priority Inheritance Protocol (probably not implemented)
|
||||
SYS_SYNC_PRIORITY_INHERIT = 3,
|
||||
// Not selected while unlocking
|
||||
SYS_SYNC_RETRY = 4,
|
||||
@ -59,7 +59,8 @@ struct SleepQueue
|
||||
u32 pop(); // SYS_SYNC_FIFO
|
||||
u32 pop_prio(); // SYS_SYNC_PRIORITY
|
||||
u32 pop_prio_inherit(); // (TODO)
|
||||
void invalidate(u32 tid);
|
||||
bool invalidate(u32 tid);
|
||||
bool finalize();
|
||||
};
|
||||
|
||||
struct sys_lwmutex_t
|
||||
@ -84,26 +85,4 @@ struct sys_lwmutex_t
|
||||
int trylock(be_t<u32> tid);
|
||||
int unlock(be_t<u32> tid);
|
||||
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);
|
||||
}
|
||||
};*/
|
||||
};
|
@ -5,97 +5,192 @@
|
||||
|
||||
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)",
|
||||
mutex_id_addr, attr_addr);
|
||||
sys_mtx.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id.GetAddr(), attr.GetAddr());
|
||||
|
||||
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];
|
||||
attr.protocol = re(attr.protocol);
|
||||
attr.recursive = re(attr.recursive);
|
||||
attr.pshared = re(attr.pshared);
|
||||
attr.adaptive = re(attr.adaptive);
|
||||
attr.ipc_key = re(attr.ipc_key);
|
||||
attr.flags = re(attr.flags);
|
||||
|
||||
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);
|
||||
switch (attr->protocol.ToBE())
|
||||
{
|
||||
case se32(SYS_SYNC_FIFO): break;
|
||||
case se32(SYS_SYNC_PRIORITY): break;
|
||||
case se32(SYS_SYNC_PRIORITY_INHERIT): sys_mtx.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT protocol"); break;
|
||||
case se32(SYS_SYNC_RETRY): sys_mtx.Error("Invalid SYS_SYNC_RETRY protocol"); return CELL_EINVAL;
|
||||
default: sys_mtx.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
if(!sys_mtx.CheckId(mutex_id, mtx_data)) return CELL_ESRCH;
|
||||
|
||||
u32 counter = 0;
|
||||
const u32 max_counter = timeout ? (timeout / 1000) : 20000;
|
||||
do
|
||||
Mutex* mutex;
|
||||
if (!Emu.GetIdManager().GetIDData(mutex_id, mutex))
|
||||
{
|
||||
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);
|
||||
return CELL_ETIMEDOUT;
|
||||
if (++mutex->recursive == 0)
|
||||
{
|
||||
return CELL_EKRESOURCE;
|
||||
}
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (mtx_data->mtx.TryLock() == wxMUTEX_NO_ERROR) return CELL_OK;
|
||||
Sleep(1);
|
||||
|
||||
if (counter++ > max_counter)
|
||||
else
|
||||
{
|
||||
if (!timeout)
|
||||
{
|
||||
counter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mutex->m_mutex.trylock(tid))
|
||||
{
|
||||
case SMR_OK: mutex->recursive = 1; return CELL_OK;
|
||||
case SMR_FAILED: break;
|
||||
default: goto abort;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
if(!sys_mtx.CheckId(mutex_id, mtx_data)) return CELL_ESRCH;
|
||||
Mutex* mutex;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
if(!sys_mtx.CheckId(mutex_id, mtx_data)) return CELL_ESRCH;
|
||||
Mutex* mutex;
|
||||
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;
|
||||
}
|
||||
|
@ -1,25 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
struct mutex_attr
|
||||
struct sys_mutex_attribute
|
||||
{
|
||||
u32 protocol;
|
||||
u32 recursive;
|
||||
u32 pshared;
|
||||
u32 adaptive;
|
||||
u64 ipc_key;
|
||||
int flags;
|
||||
u32 pad;
|
||||
char name[8];
|
||||
be_t<u32> protocol; // SYS_SYNC_FIFO, SYS_SYNC_PRIORITY or SYS_SYNC_PRIORITY_INHERIT
|
||||
be_t<u32> recursive; // SYS_SYNC_RECURSIVE or SYS_SYNC_NOT_RECURSIVE
|
||||
be_t<u32> pshared; // always 0x200 (not shared)
|
||||
be_t<u32> adaptive;
|
||||
be_t<u64> ipc_key;
|
||||
be_t<int> flags;
|
||||
be_t<u32> pad;
|
||||
union
|
||||
{
|
||||
char name[8];
|
||||
u64 name_u64;
|
||||
};
|
||||
};
|
||||
|
||||
struct mutex
|
||||
struct Mutex
|
||||
{
|
||||
wxMutex mtx;
|
||||
mutex_attr attr;
|
||||
SMutex m_mutex;
|
||||
SleepQueue m_queue;
|
||||
u32 recursive; // recursive locks count
|
||||
std::atomic<u32> cond_count; // count of condition variables associated
|
||||
|
||||
mutex(const mutex_attr& attr)
|
||||
: mtx()
|
||||
, attr(attr)
|
||||
const u32 protocol;
|
||||
const bool is_recursive;
|
||||
|
||||
Mutex(u32 protocol, bool is_recursive, u64 name)
|
||||
: protocol(protocol)
|
||||
, is_recursive(is_recursive)
|
||||
, m_queue(name)
|
||||
, cond_count(0)
|
||||
{
|
||||
}
|
||||
};
|
@ -32,7 +32,8 @@ void sys_ppu_thread_exit(int errorcode)
|
||||
|
||||
int sys_ppu_thread_yield()
|
||||
{
|
||||
sysPrxForUser.Log("sys_ppu_thread_yield()");
|
||||
sysPrxForUser.Log("sys_ppu_thread_yield()");
|
||||
Sleep(1);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -247,12 +247,12 @@ int cellPadSetPortSetting(u32 port_no, u32 port_setting)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
@ -625,7 +625,6 @@ int sys_spu_thread_connect_event(u32 id, u32 eq, u32 et, u8 spup)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
/*
|
||||
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_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;
|
||||
}
|
||||
|
@ -10,7 +10,8 @@
|
||||
#include <sys/timeb.h>
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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(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()
|
||||
{
|
||||
sys_time.Log("sys_time_get_system_time()");
|
||||
#ifdef _WIN32
|
||||
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
|
||||
return get_system_time();
|
||||
}
|
||||
|
||||
u64 sys_time_get_timebase_frequency()
|
||||
{
|
||||
sys_time.Log("sys_time_get_timebase_frequency()");
|
||||
return 1000000;
|
||||
|
||||
/*
|
||||
#ifdef _WIN32
|
||||
static LARGE_INTEGER frequency = {0ULL};
|
||||
|
||||
@ -60,6 +70,7 @@ u64 sys_time_get_timebase_frequency()
|
||||
|
||||
return frequency.QuadPart;
|
||||
#else
|
||||
return 10000000;
|
||||
return 10000000;
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ void LogFrame::Task()
|
||||
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.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);
|
||||
|
||||
::SendMessage((HWND)m_log.GetHWND(), WM_VSCROLL, SB_BOTTOM, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user