2014-08-08 17:55:12 +02:00
# include "stdafx.h"
# include "Emu/Memory/Memory.h"
# include "Emu/System.h"
# include "Emu/SysCalls/SysCalls.h"
2014-12-24 17:09:32 +01:00
# include "Emu/CPU/CPUThreadManager.h"
2014-08-23 16:51:51 +02:00
# include "Emu/Cell/PPUThread.h"
2015-03-02 22:09:20 +01:00
# include "sleep_queue.h"
2014-08-08 17:55:12 +02:00
# include "sys_event_flag.h"
SysCallBase sys_event_flag ( " sys_event_flag " ) ;
2014-08-23 02:16:54 +02:00
u32 EventFlag : : check ( )
{
u32 target = 0 ;
2014-12-24 17:09:32 +01:00
u64 highest_prio = ~ 0ull ;
2014-12-23 00:31:11 +01:00
const u64 flag_set = flags . read_sync ( ) ;
2014-08-23 02:16:54 +02:00
for ( u32 i = 0 ; i < waiters . size ( ) ; i + + )
{
2014-12-23 00:31:11 +01:00
if ( ( ( waiters [ i ] . mode & SYS_EVENT_FLAG_WAIT_AND ) & & ( flag_set & waiters [ i ] . bitptn ) = = waiters [ i ] . bitptn ) | |
( ( waiters [ i ] . mode & SYS_EVENT_FLAG_WAIT_OR ) & & ( flag_set & waiters [ i ] . bitptn ) ) )
2014-08-23 02:16:54 +02:00
{
2014-12-23 00:31:11 +01:00
if ( protocol = = SYS_SYNC_FIFO )
2014-08-23 02:16:54 +02:00
{
target = waiters [ i ] . tid ;
break ;
}
2014-12-24 17:09:32 +01:00
else if ( protocol = = SYS_SYNC_PRIORITY )
{
if ( std : : shared_ptr < CPUThread > t = Emu . GetCPU ( ) . GetThread ( waiters [ i ] . tid ) )
{
const u64 prio = t - > GetPrio ( ) ;
if ( prio < highest_prio )
{
highest_prio = prio ;
target = waiters [ i ] . tid ;
}
}
else
{
assert ( ! " EventFlag::check(): waiter not found " ) ;
}
}
2015-01-02 00:41:29 +01:00
else
{
assert ( ! " EventFlag::check(): unknown protocol " ) ;
}
2014-08-23 02:16:54 +02:00
}
}
return target ;
}
2014-10-11 19:20:01 +02:00
s32 sys_event_flag_create ( vm : : ptr < u32 > eflag_id , vm : : ptr < sys_event_flag_attr > attr , u64 init )
2014-08-08 17:55:12 +02:00
{
2015-01-02 00:41:29 +01:00
sys_event_flag . Warning ( " sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx) " , eflag_id . addr ( ) , attr . addr ( ) , init ) ;
2014-08-08 17:55:12 +02:00
2014-11-29 18:01:04 +01:00
if ( ! eflag_id )
2014-11-16 20:48:22 +01:00
{
sys_event_flag . Error ( " sys_event_flag_create(): invalid memory access (eflag_id_addr=0x%x) " , eflag_id . addr ( ) ) ;
return CELL_EFAULT ;
}
2014-11-29 18:01:04 +01:00
if ( ! attr )
2014-11-16 20:48:22 +01:00
{
sys_event_flag . Error ( " sys_event_flag_create(): invalid memory access (attr_addr=0x%x) " , attr . addr ( ) ) ;
return CELL_EFAULT ;
}
2015-01-13 15:54:36 +01:00
switch ( attr - > protocol . data ( ) )
2014-08-08 17:55:12 +02:00
{
case se32 ( SYS_SYNC_PRIORITY ) : break ;
2015-01-13 15:54:36 +01:00
case se32 ( SYS_SYNC_RETRY ) : sys_event_flag . Todo ( " SYS_SYNC_RETRY " ) ; break ;
case se32 ( SYS_SYNC_PRIORITY_INHERIT ) : sys_event_flag . Todo ( " SYS_SYNC_PRIORITY_INHERIT " ) ; break ;
2014-08-08 17:55:12 +02:00
case se32 ( SYS_SYNC_FIFO ) : break ;
2015-01-13 15:54:36 +01:00
default : sys_event_flag . Error ( " Unknown protocol (0x%x) " , attr - > protocol ) ; return CELL_EINVAL ;
2014-08-08 17:55:12 +02:00
}
2015-01-13 15:54:36 +01:00
if ( attr - > pshared . data ( ) ! = se32 ( 0x200 ) )
2015-01-02 00:41:29 +01:00
{
2015-01-13 15:54:36 +01:00
sys_event_flag . Error ( " Unknown pshared attribute (0x%x) " , attr - > pshared ) ;
2014-08-08 17:55:12 +02:00
return CELL_EINVAL ;
2015-01-02 00:41:29 +01:00
}
2014-08-08 17:55:12 +02:00
2015-01-13 15:54:36 +01:00
switch ( attr - > type . data ( ) )
2014-08-08 17:55:12 +02:00
{
case se32 ( SYS_SYNC_WAITER_SINGLE ) : break ;
case se32 ( SYS_SYNC_WAITER_MULTIPLE ) : break ;
2015-01-13 15:54:36 +01:00
default : sys_event_flag . Error ( " Unknown event flag type (0x%x) " , attr - > type ) ; return CELL_EINVAL ;
2014-08-08 17:55:12 +02:00
}
2015-01-13 15:54:36 +01:00
std : : shared_ptr < EventFlag > ef ( new EventFlag ( init , attr - > protocol , attr - > type , attr - > name_u64 ) ) ;
2014-12-24 00:38:13 +01:00
u32 id = sys_event_flag . GetNewId ( ef , TYPE_EVENT_FLAG ) ;
2014-09-01 02:51:48 +02:00
* eflag_id = id ;
2015-01-13 15:54:36 +01:00
sys_event_flag . Warning ( " *** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d " , std : : string ( attr - > name , 8 ) . c_str ( ) , attr - > protocol , attr - > type , id ) ;
2014-08-08 17:55:12 +02:00
return CELL_OK ;
}
s32 sys_event_flag_destroy ( u32 eflag_id )
{
sys_event_flag . Warning ( " sys_event_flag_destroy(eflag_id=%d) " , eflag_id ) ;
2014-12-24 00:38:13 +01:00
std : : shared_ptr < EventFlag > ef ;
2014-08-08 17:55:12 +02:00
if ( ! sys_event_flag . CheckId ( eflag_id , ef ) ) return CELL_ESRCH ;
if ( ef - > waiters . size ( ) ) // ???
{
return CELL_EBUSY ;
}
Emu . GetIdManager ( ) . RemoveID ( eflag_id ) ;
return CELL_OK ;
}
2014-10-11 19:20:01 +02:00
s32 sys_event_flag_wait ( u32 eflag_id , u64 bitptn , u32 mode , vm : : ptr < u64 > result , u64 timeout )
2014-08-08 17:55:12 +02:00
{
sys_event_flag . Log ( " sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld) " ,
2014-09-01 00:58:08 +02:00
eflag_id , bitptn , mode , result . addr ( ) , timeout ) ;
2014-08-08 17:55:12 +02:00
2014-09-01 00:58:08 +02:00
if ( result ) * result = 0 ;
2014-08-08 17:55:12 +02:00
switch ( mode & 0xf )
{
case SYS_EVENT_FLAG_WAIT_AND : break ;
case SYS_EVENT_FLAG_WAIT_OR : break ;
default : return CELL_EINVAL ;
}
switch ( mode & ~ 0xf )
{
case 0 : break ; // ???
case SYS_EVENT_FLAG_WAIT_CLEAR : break ;
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL : break ;
default : return CELL_EINVAL ;
}
2014-12-24 00:38:13 +01:00
std : : shared_ptr < EventFlag > ef ;
2014-08-08 17:55:12 +02:00
if ( ! sys_event_flag . CheckId ( eflag_id , ef ) ) return CELL_ESRCH ;
2014-09-15 00:17:24 +02:00
const u32 tid = GetCurrentPPUThread ( ) . GetId ( ) ;
2014-08-08 17:55:12 +02:00
{
2014-12-23 00:31:11 +01:00
std : : lock_guard < std : : mutex > lock ( ef - > mutex ) ;
if ( ef - > type = = SYS_SYNC_WAITER_SINGLE & & ef - > waiters . size ( ) > 0 )
2014-08-08 17:55:12 +02:00
{
return CELL_EPERM ;
}
2014-12-23 00:31:11 +01:00
2014-08-08 17:55:12 +02:00
EventFlagWaiter rec ;
rec . bitptn = bitptn ;
rec . mode = mode ;
rec . tid = tid ;
ef - > waiters . push_back ( rec ) ;
if ( ef - > check ( ) = = tid )
{
2014-12-23 00:31:11 +01:00
const u64 flag_set = ef - > flags . read_sync ( ) ;
2014-08-08 17:55:12 +02:00
ef - > waiters . erase ( ef - > waiters . end ( ) - 1 ) ;
if ( mode & SYS_EVENT_FLAG_WAIT_CLEAR )
{
ef - > flags & = ~ bitptn ;
}
else if ( mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL )
{
2014-12-23 00:31:11 +01:00
ef - > flags & = 0 ;
2014-08-08 17:55:12 +02:00
}
2014-12-23 00:31:11 +01:00
if ( result )
{
* result = flag_set ;
}
2014-08-08 17:55:12 +02:00
return CELL_OK ;
}
}
2014-08-30 20:35:18 +02:00
u64 counter = 0 ;
const u64 max_counter = timeout ? ( timeout / 1000 ) : ~ 0 ;
2014-08-08 17:55:12 +02:00
while ( true )
{
2014-12-23 00:31:11 +01:00
u32 signaled ;
2014-12-24 23:24:17 +01:00
if ( ef - > signal . try_peek ( signaled ) & & signaled = = tid )
2014-08-08 17:55:12 +02:00
{
2014-12-23 00:31:11 +01:00
std : : lock_guard < std : : mutex > lock ( ef - > mutex ) ;
const u64 flag_set = ef - > flags . read_sync ( ) ;
2014-12-24 23:24:17 +01:00
ef - > signal . pop ( signaled ) ;
2014-08-08 17:55:12 +02:00
for ( u32 i = 0 ; i < ef - > waiters . size ( ) ; i + + )
{
if ( ef - > waiters [ i ] . tid = = tid )
{
ef - > waiters . erase ( ef - > waiters . begin ( ) + i ) ;
if ( mode & SYS_EVENT_FLAG_WAIT_CLEAR )
{
ef - > flags & = ~ bitptn ;
}
else if ( mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL )
{
2014-12-23 00:31:11 +01:00
ef - > flags & = 0 ;
2014-08-08 17:55:12 +02:00
}
if ( u32 target = ef - > check ( ) )
{
2014-12-24 23:24:17 +01:00
ef - > signal . push ( target ) ;
2014-08-08 17:55:12 +02:00
}
2014-12-23 00:31:11 +01:00
if ( result )
2014-08-08 17:55:12 +02:00
{
2014-12-23 00:31:11 +01:00
* result = flag_set ;
2014-08-08 17:55:12 +02:00
}
return CELL_OK ;
}
}
return CELL_ECANCELED ;
}
2014-12-23 00:31:11 +01:00
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1 ) ) ; // hack
2014-08-08 17:55:12 +02:00
if ( counter + + > max_counter )
{
2014-12-23 00:31:11 +01:00
std : : lock_guard < std : : mutex > lock ( ef - > mutex ) ;
2014-08-08 17:55:12 +02:00
for ( u32 i = 0 ; i < ef - > waiters . size ( ) ; i + + )
{
if ( ef - > waiters [ i ] . tid = = tid )
{
ef - > waiters . erase ( ef - > waiters . begin ( ) + i ) ;
break ;
}
}
return CELL_ETIMEDOUT ;
}
2014-12-23 00:31:11 +01:00
2014-08-08 17:55:12 +02:00
if ( Emu . IsStopped ( ) )
{
2014-08-23 16:51:51 +02:00
sys_event_flag . Warning ( " sys_event_flag_wait(id=%d) aborted " , eflag_id ) ;
2014-08-08 17:55:12 +02:00
return CELL_OK ;
}
}
}
2014-10-11 19:20:01 +02:00
s32 sys_event_flag_trywait ( u32 eflag_id , u64 bitptn , u32 mode , vm : : ptr < u64 > result )
2014-08-08 17:55:12 +02:00
{
sys_event_flag . Log ( " sys_event_flag_trywait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x) " ,
2014-09-01 00:58:08 +02:00
eflag_id , bitptn , mode , result . addr ( ) ) ;
2014-08-08 17:55:12 +02:00
2014-09-01 00:58:08 +02:00
if ( result ) * result = 0 ;
2014-08-08 17:55:12 +02:00
switch ( mode & 0xf )
{
case SYS_EVENT_FLAG_WAIT_AND : break ;
case SYS_EVENT_FLAG_WAIT_OR : break ;
default : return CELL_EINVAL ;
}
switch ( mode & ~ 0xf )
{
case 0 : break ; // ???
case SYS_EVENT_FLAG_WAIT_CLEAR : break ;
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL : break ;
default : return CELL_EINVAL ;
}
2014-12-24 00:38:13 +01:00
std : : shared_ptr < EventFlag > ef ;
2014-08-08 17:55:12 +02:00
if ( ! sys_event_flag . CheckId ( eflag_id , ef ) ) return CELL_ESRCH ;
2014-12-23 00:31:11 +01:00
std : : lock_guard < std : : mutex > lock ( ef - > mutex ) ;
2014-08-08 17:55:12 +02:00
2014-12-23 00:31:11 +01:00
const u64 flag_set = ef - > flags . read_sync ( ) ;
2014-08-08 17:55:12 +02:00
2014-12-23 00:31:11 +01:00
if ( ( ( mode & SYS_EVENT_FLAG_WAIT_AND ) & & ( flag_set & bitptn ) = = bitptn ) | |
( ( mode & SYS_EVENT_FLAG_WAIT_OR ) & & ( flag_set & bitptn ) ) )
2014-08-08 17:55:12 +02:00
{
if ( mode & SYS_EVENT_FLAG_WAIT_CLEAR )
{
ef - > flags & = ~ bitptn ;
}
else if ( mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL )
{
2014-12-23 00:31:11 +01:00
ef - > flags & = 0 ;
2014-08-08 17:55:12 +02:00
}
2014-12-23 00:31:11 +01:00
if ( result )
{
* result = flag_set ;
}
2014-08-08 17:55:12 +02:00
return CELL_OK ;
}
return CELL_EBUSY ;
}
s32 sys_event_flag_set ( u32 eflag_id , u64 bitptn )
{
sys_event_flag . Log ( " sys_event_flag_set(eflag_id=%d, bitptn=0x%llx) " , eflag_id , bitptn ) ;
2014-12-24 00:38:13 +01:00
std : : shared_ptr < EventFlag > ef ;
2014-08-08 17:55:12 +02:00
if ( ! sys_event_flag . CheckId ( eflag_id , ef ) ) return CELL_ESRCH ;
2014-12-23 00:31:11 +01:00
std : : lock_guard < std : : mutex > lock ( ef - > mutex ) ;
2014-08-08 17:55:12 +02:00
ef - > flags | = bitptn ;
if ( u32 target = ef - > check ( ) )
{
2014-12-24 23:24:17 +01:00
ef - > signal . push ( target ) ;
2014-08-08 17:55:12 +02:00
}
return CELL_OK ;
}
s32 sys_event_flag_clear ( u32 eflag_id , u64 bitptn )
{
sys_event_flag . Log ( " sys_event_flag_clear(eflag_id=%d, bitptn=0x%llx) " , eflag_id , bitptn ) ;
2014-12-24 00:38:13 +01:00
std : : shared_ptr < EventFlag > ef ;
2014-08-08 17:55:12 +02:00
if ( ! sys_event_flag . CheckId ( eflag_id , ef ) ) return CELL_ESRCH ;
2014-12-23 00:31:11 +01:00
std : : lock_guard < std : : mutex > lock ( ef - > mutex ) ;
2014-08-08 17:55:12 +02:00
ef - > flags & = bitptn ;
return CELL_OK ;
}
2014-10-11 19:20:01 +02:00
s32 sys_event_flag_cancel ( u32 eflag_id , vm : : ptr < u32 > num )
2014-08-08 17:55:12 +02:00
{
2014-09-01 02:51:48 +02:00
sys_event_flag . Log ( " sys_event_flag_cancel(eflag_id=%d, num_addr=0x%x) " , eflag_id , num . addr ( ) ) ;
2014-08-08 17:55:12 +02:00
2014-12-24 00:38:13 +01:00
std : : shared_ptr < EventFlag > ef ;
2014-08-08 17:55:12 +02:00
if ( ! sys_event_flag . CheckId ( eflag_id , ef ) ) return CELL_ESRCH ;
std : : vector < u32 > tids ;
{
2014-12-23 00:31:11 +01:00
std : : lock_guard < std : : mutex > lock ( ef - > mutex ) ;
2014-08-08 17:55:12 +02:00
tids . resize ( ef - > waiters . size ( ) ) ;
for ( u32 i = 0 ; i < ef - > waiters . size ( ) ; i + + )
{
tids [ i ] = ef - > waiters [ i ] . tid ;
}
ef - > waiters . clear ( ) ;
}
2014-12-24 23:24:17 +01:00
for ( auto & v : tids )
2014-08-08 17:55:12 +02:00
{
2014-12-24 23:24:17 +01:00
ef - > signal . push ( v ) ;
2014-08-08 17:55:12 +02:00
}
if ( Emu . IsStopped ( ) )
{
2014-08-23 16:51:51 +02:00
sys_event_flag . Warning ( " sys_event_flag_cancel(id=%d) aborted " , eflag_id ) ;
2014-08-08 17:55:12 +02:00
return CELL_OK ;
}
2014-12-23 00:31:11 +01:00
if ( num )
{
* num = ( u32 ) tids . size ( ) ;
}
2014-08-08 17:55:12 +02:00
return CELL_OK ;
}
2014-10-11 19:20:01 +02:00
s32 sys_event_flag_get ( u32 eflag_id , vm : : ptr < u64 > flags )
2014-08-08 17:55:12 +02:00
{
2014-09-01 00:58:08 +02:00
sys_event_flag . Log ( " sys_event_flag_get(eflag_id=%d, flags_addr=0x%x) " , eflag_id , flags . addr ( ) ) ;
2014-08-08 17:55:12 +02:00
2014-11-29 18:01:04 +01:00
if ( ! flags )
2014-11-16 20:48:22 +01:00
{
sys_event_flag . Error ( " sys_event_flag_create(): invalid memory access (flags_addr=0x%x) " , flags . addr ( ) ) ;
return CELL_EFAULT ;
}
2014-12-24 00:38:13 +01:00
std : : shared_ptr < EventFlag > ef ;
2014-08-08 17:55:12 +02:00
if ( ! sys_event_flag . CheckId ( eflag_id , ef ) ) return CELL_ESRCH ;
2014-12-23 00:31:11 +01:00
* flags = ef - > flags . read_sync ( ) ;
2014-08-08 17:55:12 +02:00
return CELL_OK ;
}