rpcsx/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp

281 lines
5.6 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
2015-03-06 23:58:42 +01:00
#include "Emu/IdManager.h"
#include "Emu/SysCalls/SysCalls.h"
2014-08-23 16:51:51 +02:00
2015-03-08 16:25:31 +01:00
#include "Utilities/Thread.h"
#include "sys_time.h"
2015-03-06 23:24:04 +01:00
#include "sys_event.h"
2015-03-08 16:25:31 +01:00
#include "sys_process.h"
#include "sys_timer.h"
SysCallBase sys_timer("sys_timer");
2014-10-11 19:20:01 +02:00
s32 sys_timer_create(vm::ptr<u32> timer_id)
{
2015-03-08 16:25:31 +01:00
sys_timer.Warning("sys_timer_create(timer_id=*0x%x)", timer_id);
2015-03-09 03:05:53 +01:00
std::shared_ptr<lv2_timer_t> timer(new lv2_timer_t);
2015-03-08 16:25:31 +01:00
thread_t(fmt::format("Timer[%d] Thread", (*timer_id = Emu.GetIdManager().GetNewID(timer, TYPE_TIMER))), [timer]()
{
LV2_LOCK;
while (!timer.unique() && !Emu.IsStopped())
{
if (timer->state == SYS_TIMER_STATE_RUN)
{
if (get_system_time() >= timer->start)
{
std::shared_ptr<event_queue_t> queue = timer->port.lock();
if (queue)
{
2015-03-11 16:30:50 +01:00
queue->push(timer->source, timer->data1, timer->data2, timer->start);
2015-03-08 16:25:31 +01:00
}
if (timer->period && queue)
{
timer->start += timer->period; // set next expiration time
continue; // hack: check again
}
else
{
timer->state = SYS_TIMER_STATE_STOP; // stop if oneshot or the event port was disconnected (TODO: is it correct?)
}
}
}
timer->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
}).detach();
return CELL_OK;
}
s32 sys_timer_destroy(u32 timer_id)
{
2015-03-08 16:25:31 +01:00
sys_timer.Warning("sys_timer_destroy(timer_id=%d)", timer_id);
LV2_LOCK;
2015-03-09 03:05:53 +01:00
std::shared_ptr<lv2_timer_t> timer;
2015-03-11 16:30:50 +01:00
2015-03-08 16:25:31 +01:00
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{
return CELL_ESRCH;
}
2015-03-08 16:25:31 +01:00
if (!timer->port.expired())
{
return CELL_EISCONN;
}
2015-03-10 15:42:08 +01:00
Emu.GetIdManager().RemoveID<lv2_timer_t>(timer_id);
2015-03-08 16:25:31 +01:00
return CELL_OK;
}
2014-09-02 03:05:13 +02:00
s32 sys_timer_get_information(u32 timer_id, vm::ptr<sys_timer_information_t> info)
{
2015-03-08 16:25:31 +01:00
sys_timer.Warning("sys_timer_get_information(timer_id=%d, info=*0x%x)", timer_id, info);
LV2_LOCK;
2015-03-09 03:05:53 +01:00
std::shared_ptr<lv2_timer_t> timer;
2015-03-11 16:30:50 +01:00
2015-03-08 16:25:31 +01:00
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{
return CELL_ESRCH;
}
info->next_expiration_time = timer->start;
info->period = timer->period;
info->timer_state = timer->state;
return CELL_OK;
}
2015-03-08 16:25:31 +01:00
s32 _sys_timer_start(u32 timer_id, u64 base_time, u64 period)
{
2015-03-08 16:25:31 +01:00
sys_timer.Warning("_sys_timer_start(timer_id=%d, base_time=0x%llx, period=0x%llx)", timer_id, base_time, period);
2015-03-08 16:25:31 +01:00
const u64 start_time = get_system_time();
2015-03-08 16:25:31 +01:00
LV2_LOCK;
2015-03-09 03:05:53 +01:00
std::shared_ptr<lv2_timer_t> timer;
2015-03-11 16:30:50 +01:00
2015-03-08 16:25:31 +01:00
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{
return CELL_ESRCH;
}
if (timer->state != SYS_TIMER_STATE_STOP)
{
return CELL_EBUSY;
}
if (!period)
{
// oneshot timer (TODO: what will happen if both args are 0?)
if (start_time >= base_time)
{
return CELL_ETIMEDOUT;
}
}
else
{
// periodic timer
if (period < 100)
{
return CELL_EINVAL;
}
}
if (timer->port.expired())
{
return CELL_ENOTCONN;
}
// sys_timer_start_periodic() will use current time (TODO: is it correct?)
timer->start = base_time ? base_time : start_time + period;
timer->period = period;
timer->state = SYS_TIMER_STATE_RUN;
timer->cv.notify_one();
2014-07-11 13:59:13 +02:00
return CELL_OK;
}
s32 sys_timer_stop(u32 timer_id)
{
2015-03-08 16:25:31 +01:00
sys_timer.Warning("sys_timer_stop()");
LV2_LOCK;
2015-03-09 03:05:53 +01:00
std::shared_ptr<lv2_timer_t> timer;
2015-03-11 16:30:50 +01:00
2015-03-08 16:25:31 +01:00
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{
return CELL_ESRCH;
}
2015-03-08 16:25:31 +01:00
timer->state = SYS_TIMER_STATE_STOP; // stop timer
return CELL_OK;
}
s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data1, u64 data2)
{
2015-03-08 16:25:31 +01:00
sys_timer.Warning("sys_timer_connect_event_queue(timer_id=%d, queue_id=%d, name=0x%llx, data1=0x%llx, data2=0x%llx)", timer_id, queue_id, name, data1, data2);
2015-03-08 16:25:31 +01:00
LV2_LOCK;
2015-03-09 03:05:53 +01:00
std::shared_ptr<lv2_timer_t> timer;
2015-03-08 16:25:31 +01:00
std::shared_ptr<event_queue_t> queue;
if (!Emu.GetIdManager().GetIDData(timer_id, timer) || !Emu.GetIdManager().GetIDData(queue_id, queue))
{
return CELL_ESRCH;
}
if (!timer->port.expired())
{
return CELL_EISCONN;
}
timer->port = queue; // connect event queue
timer->source = name ? name : ((u64)process_getpid() << 32) | timer_id;
timer->data1 = data1;
timer->data2 = data2;
return CELL_OK;
}
s32 sys_timer_disconnect_event_queue(u32 timer_id)
{
2015-03-08 16:25:31 +01:00
sys_timer.Warning("sys_timer_disconnect_event_queue(timer_id=%d)", timer_id);
2015-03-08 16:25:31 +01:00
LV2_LOCK;
2015-03-09 03:05:53 +01:00
std::shared_ptr<lv2_timer_t> timer;
2015-03-11 16:30:50 +01:00
2015-03-08 16:25:31 +01:00
if (!Emu.GetIdManager().GetIDData(timer_id, timer))
{
return CELL_ESRCH;
}
if (timer->port.expired())
{
return CELL_ENOTCONN;
}
timer->port.reset(); // disconnect event queue
timer->state = SYS_TIMER_STATE_STOP; // stop timer
return CELL_OK;
}
s32 sys_timer_sleep(u32 sleep_time)
{
2014-07-14 11:24:10 +02:00
sys_timer.Log("sys_timer_sleep(sleep_time=%d)", sleep_time);
2015-03-08 16:25:31 +01:00
const u64 start_time = get_system_time();
const u64 useconds = sleep_time * 1000000ull;
u64 passed;
while (useconds > (passed = get_system_time() - start_time) + 1000)
2014-07-13 20:55:14 +02:00
{
2015-03-08 16:25:31 +01:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2014-07-13 20:55:14 +02:00
if (Emu.IsStopped())
{
2014-07-14 21:15:30 +02:00
sys_timer.Warning("sys_timer_sleep(sleep_time=%d) aborted", sleep_time);
2014-07-13 20:55:14 +02:00
return CELL_OK;
}
}
2015-03-08 16:25:31 +01:00
if (useconds > passed)
{
std::this_thread::sleep_for(std::chrono::microseconds(useconds - passed));
}
return CELL_OK;
}
s32 sys_timer_usleep(u64 sleep_time)
{
2015-03-08 16:25:31 +01:00
sys_timer.Log("sys_timer_usleep(sleep_time=0x%llx)", sleep_time);
const u64 start_time = get_system_time();
u64 passed;
while (sleep_time > (passed = get_system_time() - start_time) + 1000)
2014-07-13 20:55:14 +02:00
{
2015-03-08 16:25:31 +01:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
2014-07-13 20:55:14 +02:00
if (Emu.IsStopped())
{
2015-03-08 16:25:31 +01:00
sys_timer.Warning("sys_timer_usleep(sleep_time=0x%llx) aborted", sleep_time);
2014-07-13 20:55:14 +02:00
return CELL_OK;
}
}
2015-03-08 16:25:31 +01:00
if (sleep_time > passed)
{
std::this_thread::sleep_for(std::chrono::microseconds(sleep_time - passed));
}
return CELL_OK;
2014-07-11 13:59:13 +02:00
}