@ -57,6 +57,33 @@ void ServerSession::Acquire(Thread* thread) {
pending_requesting_threads . pop_back ( ) ;
}
ResultCode ServerSession : : HandleDomainSyncRequest ( Kernel : : HLERequestContext & context ) {
auto & domain_message_header = context . GetDomainMessageHeader ( ) ;
if ( domain_message_header ) {
// If there is a DomainMessageHeader, then this is CommandType "Request"
const u32 object_id { context . GetDomainMessageHeader ( ) - > object_id } ;
switch ( domain_message_header - > command ) {
case IPC : : DomainMessageHeader : : CommandType : : SendMessage :
return domain_request_handlers [ object_id - 1 ] - > HandleSyncRequest ( context ) ;
case IPC : : DomainMessageHeader : : CommandType : : CloseVirtualHandle : {
LOG_DEBUG ( IPC , " CloseVirtualHandle, object_id=0x%08X " , object_id ) ;
domain_request_handlers [ object_id - 1 ] = nullptr ;
IPC : : ResponseBuilder rb { context , 2 } ;
rb . Push ( RESULT_SUCCESS ) ;
return RESULT_SUCCESS ;
}
}
LOG_CRITICAL ( IPC , " Unknown domain command=%d " , domain_message_header - > command . Value ( ) ) ;
ASSERT ( false ) ;
}
return RESULT_SUCCESS ;
}
ResultCode ServerSession : : HandleSyncRequest ( SharedPtr < Thread > thread ) {
// The ServerSession received a sync request, this means that there's new data available
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
@ -67,46 +94,39 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
context . PopulateFromIncomingCommandBuffer ( cmd_buf , * Kernel : : g_current_process ,
Kernel : : g_handle_table ) ;
// If the session has been converted to a domain, handle the doomain request
ResultCode result = RESULT_SUCCESS ;
// If the session has been converted to a domain, handle the domain request
if ( IsDomain ( ) ) {
auto & domain_message_header = context . GetDomainMessageHeader ( ) ;
if ( domain_message_header ) {
// If there is a DomainMessageHeader, then this is CommandType "Request"
const u32 object_id { context . GetDomainMessageHeader ( ) - > object_id } ;
switch ( domain_message_header - > command ) {
case IPC : : DomainMessageHeader : : CommandType : : SendMessage :
return domain_request_handlers [ object_id - 1 ] - > HandleSyncRequest ( context ) ;
case IPC : : DomainMessageHeader : : CommandType : : CloseVirtualHandle : {
LOG_DEBUG ( IPC , " CloseVirtualHandle, object_id=0x%08X " , object_id ) ;
domain_request_handlers [ object_id - 1 ] = nullptr ;
IPC : : ResponseBuilder rb { context , 2 } ;
rb . Push ( RESULT_SUCCESS ) ;
return RESULT_SUCCESS ;
}
}
LOG_CRITICAL ( IPC , " Unknown domain command=%d " , domain_message_header - > command . Value ( ) ) ;
ASSERT ( false ) ;
}
result = HandleDomainSyncRequest ( context ) ;
// If there is no domain header, the regular session handler is used
} else if ( hle_handler ! = nullptr ) {
// If this ServerSession has an associated HLE handler, forward the request to it.
result = hle_handler - > HandleSyncRequest ( context ) ;
}
// If this ServerSession has an associated HLE handler, forward the request to it.
ResultCode result { RESULT_SUCCESS } ;
if ( hle_handler ! = nullptr ) {
// Attempt to translate the incoming request's command buffer.
ResultCode translate_result = TranslateHLERequest ( this ) ;
if ( translate_result . IsError ( ) )
return translate_result ;
if ( thread - > status = = THREADSTATUS_RUNNING ) {
// Put the thread to sleep until the server replies, it will be awoken in
// svcReplyAndReceive for LLE servers.
thread - > status = THREADSTATUS_WAIT_IPC ;
result = hle_handler - > HandleSyncRequest ( context ) ;
} else {
// Add the thread to the list of threads that have issued a sync request with this
// server.
pending_requesting_threads . push_back ( std : : move ( thread ) ) ;
if ( hle_handler ! = nullptr ) {
// For HLE services, we put the request threads to sleep for a short duration to
// simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for
// other reasons like an async callback. The IPC overhead is needed to prevent
// starvation when a thread only does sync requests to HLE services while a
// lower-priority thread is waiting to run.
// This delay was approximated in a homebrew application by measuring the average time
// it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC
// request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have
// a high variance and vary between models.
static constexpr u64 IPCDelayNanoseconds = 39000 ;
thread - > WakeAfterDelay ( IPCDelayNanoseconds ) ;
} else {
// Add the thread to the list of threads that have issued a sync request with this
// server.
pending_requesting_threads . push_back ( std : : move ( thread ) ) ;
}
}
// If this ServerSession does not have an HLE implementation, just wake up the threads waiting
@ -140,9 +160,4 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& n
return std : : make_tuple ( std : : move ( server_session ) , std : : move ( client_session ) ) ;
}
ResultCode TranslateHLERequest ( ServerSession * server_session ) {
// TODO(Subv): Implement this function once multiple concurrent processes are supported.
return RESULT_SUCCESS ;
}
} // namespace Kernel