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. /// Exits the service API.
void srvExit(void); 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. * @brief Gets the current service API session handle.
* @return 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. * @brief Retrieves a service handle, retrieving from the environment handle list if possible.
* @param out Pointer to write the handle to. * @param out Pointer to write the handle to.
* @param name Name of the service. * @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); Result srvGetServiceHandle(Handle* out, const char* name);
@ -50,6 +61,9 @@ Result srvUnregisterService(const char* name);
* @brief Retrieves a service handle. * @brief Retrieves a service handle.
* @param out Pointer to output the handle to. * @param out Pointer to output the handle to.
* @param name Name of the service. * @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); Result srvGetServiceHandleDirect(Handle* out, const char* name);
@ -73,6 +87,12 @@ Result srvUnregisterPort(const char* name);
*/ */
Result srvGetPort(Handle* out, 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. * @brief Subscribes to a notification.
* @param notificationId ID of the 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. * @param name Name of the service to check.
*/ */
Result srvIsServiceRegistered(bool* registeredOut, const char* name); 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 // FS session override
u32 fs_magic; u32 fs_magic;
Handle fs_session; Handle fs_session;
// Whether srvGetServiceHandle is non-blocking in case of full service ports.
bool srv_blocking_policy;
} ThreadVars; } ThreadVars;
static inline ThreadVars* getThreadVars(void) static inline ThreadVars* getThreadVars(void)

View File

@ -14,9 +14,17 @@
#include <3ds/os.h> #include <3ds/os.h>
#include <3ds/services/srvpm.h> #include <3ds/services/srvpm.h>
#include "internal.h"
static Handle srvHandle; static Handle srvHandle;
static int srvRefCount; static int srvRefCount;
static bool srvGetBlockingPolicy(void)
{
ThreadVars *tv = getThreadVars();
return tv->magic == THREADVARS_MAGIC && tv->srv_blocking_policy;
}
Result srvInit(void) Result srvInit(void)
{ {
Result rc = 0; Result rc = 0;
@ -43,6 +51,12 @@ void srvExit(void)
srvHandle = 0; srvHandle = 0;
} }
void srvSetBlockingPolicy(bool nonBlocking)
{
ThreadVars *tv = getThreadVars();
tv->srv_blocking_policy = nonBlocking;
}
Handle *srvGetSessionHandle(void) Handle *srvGetSessionHandle(void)
{ {
return &srvHandle; return &srvHandle;
@ -128,7 +142,7 @@ Result srvGetServiceHandleDirect(Handle* out, const char* name)
cmdbuf[0] = IPC_MakeHeader(0x5,4,0); // 0x50100 cmdbuf[0] = IPC_MakeHeader(0x5,4,0); // 0x50100
strncpy((char*) &cmdbuf[1], name,8); strncpy((char*) &cmdbuf[1], name,8);
cmdbuf[3] = strnlen(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; if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc;
@ -184,6 +198,20 @@ Result srvGetPort(Handle* out, const char* name)
return cmdbuf[1]; 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 srvSubscribe(u32 notificationId)
{ {
Result rc = 0; Result rc = 0;
@ -269,3 +297,21 @@ Result srvIsServiceRegistered(bool* registeredOut, const char* name)
return cmdbuf[1]; 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->reent = _impure_ptr;
tv->thread_ptr = NULL; tv->thread_ptr = NULL;
tv->tls_tp = __tls_start-8; // ARM ELF TLS ABI mandates an 8-byte header 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; u32 tls_size = __tdata_lma_end - __tdata_lma;
if (tls_size) if (tls_size)

View File

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