Implement per-thread non-blocking behavior for srvGetServiceHandle...

implement srvWaitForPortRegistered and srvIsPortRegistered as well.
This commit is contained in:
TuxSH 2018-01-14 03:00:30 +01:00 committed by fincs
parent abf8064771
commit c598c445cd
5 changed files with 79 additions and 1 deletions

View File

@ -10,6 +10,14 @@ Result srvInit(void);
/// Exits the service API.
void srvExit(void);
/**
* @brief Makes srvGetServiceHandle non-blocking for the current thread (or blocking, the default), in case of unavailable (full) requested services.
* @param blocking Whether srvGetServiceHandle should be non-blocking.
* srvGetServiceHandle will always block if the service hasn't been registered yet,
* use srvIsServiceRegistered to check whether that is the case or not.
*/
void srvSetBlockingPolicy(bool nonBlocking);
/**
* @brief Gets the current service API session handle.
* @return The current service API session handle.
@ -20,6 +28,9 @@ Handle *srvGetSessionHandle(void);
* @brief Retrieves a service handle, retrieving from the environment handle list if possible.
* @param out Pointer to write the handle to.
* @param name Name of the service.
* @return 0 if no error occured,
* 0xD8E06406 if the caller has no right to access the service,
* 0xD0401834 if the requested service port is full and srvGetServiceHandle is non-blocking (see @ref srvSetBlockingPolicy).
*/
Result srvGetServiceHandle(Handle* out, const char* name);
@ -50,6 +61,9 @@ Result srvUnregisterService(const char* name);
* @brief Retrieves a service handle.
* @param out Pointer to output the handle to.
* @param name Name of the service.
* * @return 0 if no error occured,
* 0xD8E06406 if the caller has no right to access the service,
* 0xD0401834 if the requested service port is full and srvGetServiceHandle is non-blocking (see @ref srvSetBlockingPolicy).
*/
Result srvGetServiceHandleDirect(Handle* out, const char* name);
@ -73,6 +87,12 @@ Result srvUnregisterPort(const char* name);
*/
Result srvGetPort(Handle* out, const char* name);
/**
* @brief Waits for a port to be registered.
* @param name Name of the port to wait for registration.
*/
Result srvWaitForPortRegistered(const char* name);
/**
* @brief Subscribes to a notification.
* @param notificationId ID of the notification.
@ -112,3 +132,10 @@ Result srvPublishAndGetSubscriber(u32* processIdCountOut, u32* processIdsOut, u3
* @param name Name of the service to check.
*/
Result srvIsServiceRegistered(bool* registeredOut, const char* name);
/**
* @brief Checks whether a port is registered.
* @param registeredOut Pointer to output the registration status to.
* @param name Name of the port to check.
*/
Result srvIsPortRegistered(bool* registeredOut, const char* name);

View File

@ -26,6 +26,9 @@ typedef struct
// FS session override
u32 fs_magic;
Handle fs_session;
// Whether srvGetServiceHandle is non-blocking in case of full service ports.
bool srv_blocking_policy;
} ThreadVars;
static inline ThreadVars* getThreadVars(void)

View File

@ -14,9 +14,17 @@
#include <3ds/os.h>
#include <3ds/services/srvpm.h>
#include "internal.h"
static Handle srvHandle;
static int srvRefCount;
static bool srvGetBlockingPolicy(void)
{
ThreadVars *tv = getThreadVars();
return tv->magic == THREADVARS_MAGIC && tv->srv_blocking_policy;
}
Result srvInit(void)
{
Result rc = 0;
@ -43,6 +51,12 @@ void srvExit(void)
srvHandle = 0;
}
void srvSetBlockingPolicy(bool nonBlocking)
{
ThreadVars *tv = getThreadVars();
tv->srv_blocking_policy = nonBlocking;
}
Handle *srvGetSessionHandle(void)
{
return &srvHandle;
@ -128,7 +142,7 @@ Result srvGetServiceHandleDirect(Handle* out, const char* name)
cmdbuf[0] = IPC_MakeHeader(0x5,4,0); // 0x50100
strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strnlen(name, 8);
cmdbuf[4] = 0x0;
cmdbuf[4] = (u32)srvGetBlockingPolicy(); // per-thread setting, default is blocking
if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
@ -184,6 +198,20 @@ Result srvGetPort(Handle* out, const char* name)
return cmdbuf[1];
}
Result srvWaitForPortRegistered(const char* name)
{
Result rc = 0;
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x8,4,0); // 0x80100
strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strnlen(name, 8);
cmdbuf[4] = 0x1;
if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
return cmdbuf[1];
}
Result srvSubscribe(u32 notificationId)
{
Result rc = 0;
@ -269,3 +297,21 @@ Result srvIsServiceRegistered(bool* registeredOut, const char* name)
return cmdbuf[1];
}
Result srvIsPortRegistered(bool* registeredOut, const char* name)
{
Handle port;
Result rc = srvGetPort(&port, name);
if(rc == 0xD8801BFA)
{
if(registeredOut) *registeredOut = false;
return 0;
}
else if(R_SUCCEEDED(rc))
{
if(registeredOut) *registeredOut = true;
svcCloseHandle(port);
}
return rc;
}

View File

@ -51,6 +51,7 @@ void __system_initSyscalls(void)
tv->reent = _impure_ptr;
tv->thread_ptr = NULL;
tv->tls_tp = __tls_start-8; // ARM ELF TLS ABI mandates an 8-byte header
tv->srv_blocking_policy = false;
u32 tls_size = __tdata_lma_end - __tdata_lma;
if (tls_size)

View File

@ -33,6 +33,7 @@ static void _thread_begin(void* arg)
tv->reent = &t->reent;
tv->thread_ptr = t;
tv->tls_tp = (u8*)t->stacktop-8; // ARM ELF TLS ABI mandates an 8-byte header
tv->srv_blocking_policy = false;
t->ep(t->arg);
threadExit(0);
}