Introduce service_manager, also fix hb:ldr pm/pm race condition
This commit is contained in:
parent
f72d99d9b0
commit
474eb3001b
@ -27,8 +27,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <3ds/types.h>
|
#include <3ds/types.h>
|
||||||
#include "MyThread.h"
|
|
||||||
|
|
||||||
MyThread *errDispCreateThread(void);
|
void ERRF_HandleCommands(void *ctx);
|
||||||
|
|
||||||
void errDispThreadMain(void);
|
|
||||||
|
@ -33,6 +33,4 @@
|
|||||||
#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL
|
#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL
|
||||||
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
|
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
|
||||||
|
|
||||||
MyThread *hbldrCreateThread(void);
|
void HBLDR_HandleCommands(void *ctx);
|
||||||
|
|
||||||
void hbldrThreadMain(void);
|
|
||||||
|
48
sysmodules/rosalina/include/service_manager.h
Normal file
48
sysmodules/rosalina/include/service_manager.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||||
|
* * Requiring preservation of specified reasonable legal notices or
|
||||||
|
* author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
* * Prohibiting misrepresentation of the origin of that material,
|
||||||
|
* or requiring that modified versions of such material be marked in
|
||||||
|
* reasonable ways as different from the original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
typedef struct ServiceManagerServiceEntry {
|
||||||
|
const char *name;
|
||||||
|
u32 maxSessions;
|
||||||
|
void (*handler)(void *ctx);
|
||||||
|
bool isGlobalPort;
|
||||||
|
} ServiceManagerServiceEntry;
|
||||||
|
|
||||||
|
typedef struct ServiceManagerNotificationEntry {
|
||||||
|
u32 id;
|
||||||
|
void (*handler)(u32 id);
|
||||||
|
} ServiceManagerNotificationEntry;
|
||||||
|
|
||||||
|
typedef struct ServiceManagerContextAllocator {
|
||||||
|
void* (*newSessionContext)(u8 serviceId);
|
||||||
|
void (*freeSessionContext)(void *ctx);
|
||||||
|
} ServiceManagerContextAllocator;
|
||||||
|
|
||||||
|
Result ServiceManager_Run(const ServiceManagerServiceEntry *services, const ServiceManagerNotificationEntry *notifications, const ServiceManagerContextAllocator *allocator);
|
@ -38,18 +38,8 @@ static inline void assertSuccess(Result res)
|
|||||||
svcBreak(USERBREAK_PANIC);
|
svcBreak(USERBREAK_PANIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MyThread errDispThread;
|
|
||||||
static u8 ALIGN(8) errDispThreadStack[0x2000];
|
|
||||||
|
|
||||||
static char userString[0x100 + 1] = {0};
|
static char userString[0x100 + 1] = {0};
|
||||||
|
|
||||||
MyThread *errDispCreateThread(void)
|
|
||||||
{
|
|
||||||
if(R_FAILED(MyThread_Create(&errDispThread, errDispThreadMain, errDispThreadStack, 0x2000, 0x18, CORE_SYSTEM)))
|
|
||||||
svcBreak(USERBREAK_PANIC);
|
|
||||||
return &errDispThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 ERRF_DisplayRegisterValue(u32 posX, u32 posY, const char *name, u32 value)
|
static inline u32 ERRF_DisplayRegisterValue(u32 posX, u32 posY, const char *name, u32 value)
|
||||||
{
|
{
|
||||||
return Draw_DrawFormattedString(posX, posY, COLOR_WHITE, "%-9s %08lx", name, value);
|
return Draw_DrawFormattedString(posX, posY, COLOR_WHITE, "%-9s %08lx", name, value);
|
||||||
@ -235,8 +225,9 @@ static Result ERRF_SaveErrorToFile(ERRF_FatalErrInfo *info)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ERRF_HandleCommands(void)
|
void ERRF_HandleCommands(void *ctx)
|
||||||
{
|
{
|
||||||
|
(void)ctx;
|
||||||
u32 *cmdbuf = getThreadCommandBuffer();
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
switch(cmdbuf[0] >> 16)
|
switch(cmdbuf[0] >> 16)
|
||||||
@ -289,64 +280,3 @@ static void ERRF_HandleCommands(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void errDispThreadMain(void)
|
|
||||||
{
|
|
||||||
Handle handles[2];
|
|
||||||
Handle serverHandle, clientHandle, sessionHandle = 0;
|
|
||||||
|
|
||||||
u32 replyTarget = 0;
|
|
||||||
s32 index;
|
|
||||||
|
|
||||||
Result res;
|
|
||||||
u32 *cmdbuf = getThreadCommandBuffer();
|
|
||||||
|
|
||||||
assertSuccess(svcCreatePort(&serverHandle, &clientHandle, "err:f", 1));
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
handles[0] = serverHandle;
|
|
||||||
handles[1] = sessionHandle;
|
|
||||||
|
|
||||||
if(replyTarget == 0) // k11
|
|
||||||
cmdbuf[0] = 0xFFFF0000;
|
|
||||||
res = svcReplyAndReceive(&index, handles, sessionHandle == 0 ? 1 : 2, replyTarget);
|
|
||||||
|
|
||||||
if(R_FAILED(res))
|
|
||||||
{
|
|
||||||
if((u32)res == 0xC920181A) // session closed by remote
|
|
||||||
{
|
|
||||||
svcCloseHandle(sessionHandle);
|
|
||||||
sessionHandle = 0;
|
|
||||||
replyTarget = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
svcBreak(USERBREAK_PANIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(index == 0)
|
|
||||||
{
|
|
||||||
Handle session;
|
|
||||||
assertSuccess(svcAcceptSession(&session, serverHandle));
|
|
||||||
|
|
||||||
if(sessionHandle == 0)
|
|
||||||
sessionHandle = session;
|
|
||||||
else
|
|
||||||
svcCloseHandle(session);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERRF_HandleCommands();
|
|
||||||
replyTarget = sessionHandle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(!terminationRequest);
|
|
||||||
|
|
||||||
svcCloseHandle(sessionHandle);
|
|
||||||
svcCloseHandle(clientHandle);
|
|
||||||
svcCloseHandle(serverHandle);
|
|
||||||
}
|
|
||||||
|
@ -122,16 +122,8 @@ static inline void assertSuccess(Result res)
|
|||||||
svcBreak(USERBREAK_PANIC);
|
svcBreak(USERBREAK_PANIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MyThread hbldrThread;
|
|
||||||
static u8 ALIGN(8) hbldrThreadStack[THREAD_STACK_SIZE];
|
|
||||||
static u16 hbldrTarget[PATH_MAX+1];
|
static u16 hbldrTarget[PATH_MAX+1];
|
||||||
|
|
||||||
MyThread *hbldrCreateThread(void)
|
|
||||||
{
|
|
||||||
assertSuccess(MyThread_Create(&hbldrThread, hbldrThreadMain, hbldrThreadStack, THREAD_STACK_SIZE, 0x18, CORE_SYSTEM));
|
|
||||||
return &hbldrThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void error(u32* cmdbuf, Result rc)
|
static inline void error(u32* cmdbuf, Result rc)
|
||||||
{
|
{
|
||||||
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
|
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
|
||||||
@ -149,8 +141,9 @@ static u16 *u16_strncpy(u16 *dest, const u16 *src, u32 size)
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HBLDR_HandleCommands(void)
|
void HBLDR_HandleCommands(void *ctx)
|
||||||
{
|
{
|
||||||
|
(void)ctx;
|
||||||
Result res;
|
Result res;
|
||||||
IFile file;
|
IFile file;
|
||||||
u32 *cmdbuf = getThreadCommandBuffer();
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
@ -347,72 +340,3 @@ static void HBLDR_HandleCommands(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hbldrThreadMain(void)
|
|
||||||
{
|
|
||||||
Handle handles[2];
|
|
||||||
Handle serverHandle, clientHandle, sessionHandle = 0;
|
|
||||||
|
|
||||||
u32 replyTarget = 0;
|
|
||||||
s32 index;
|
|
||||||
|
|
||||||
char ipcBuf[PATH_MAX+1];
|
|
||||||
u32* bufPtrs = getThreadStaticBuffers();
|
|
||||||
memset(bufPtrs, 0, 16*2*4);
|
|
||||||
bufPtrs[0] = IPC_Desc_StaticBuffer(sizeof(ipcBuf), 0);
|
|
||||||
bufPtrs[1] = (u32)ipcBuf;
|
|
||||||
bufPtrs[2] = IPC_Desc_StaticBuffer(sizeof(ldrArgvBuf), 1);
|
|
||||||
bufPtrs[3] = (u32)ldrArgvBuf;
|
|
||||||
|
|
||||||
Result res;
|
|
||||||
u32 *cmdbuf = getThreadCommandBuffer();
|
|
||||||
|
|
||||||
assertSuccess(svcCreatePort(&serverHandle, &clientHandle, "hb:ldr", 1));
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
handles[0] = serverHandle;
|
|
||||||
handles[1] = sessionHandle;
|
|
||||||
|
|
||||||
if(replyTarget == 0) // k11
|
|
||||||
cmdbuf[0] = 0xFFFF0000;
|
|
||||||
res = svcReplyAndReceive(&index, handles, sessionHandle == 0 ? 1 : 2, replyTarget);
|
|
||||||
|
|
||||||
if(R_FAILED(res))
|
|
||||||
{
|
|
||||||
if((u32)res == 0xC920181A) // session closed by remote
|
|
||||||
{
|
|
||||||
svcCloseHandle(sessionHandle);
|
|
||||||
sessionHandle = 0;
|
|
||||||
replyTarget = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
svcBreak(USERBREAK_PANIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(index == 0)
|
|
||||||
{
|
|
||||||
Handle session;
|
|
||||||
assertSuccess(svcAcceptSession(&session, serverHandle));
|
|
||||||
|
|
||||||
if(sessionHandle == 0)
|
|
||||||
sessionHandle = session;
|
|
||||||
else
|
|
||||||
svcCloseHandle(session);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HBLDR_HandleCommands();
|
|
||||||
replyTarget = sessionHandle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(!terminationRequest);
|
|
||||||
|
|
||||||
svcCloseHandle(sessionHandle);
|
|
||||||
svcCloseHandle(clientHandle);
|
|
||||||
svcCloseHandle(serverHandle);
|
|
||||||
}
|
|
||||||
|
@ -29,8 +29,10 @@
|
|||||||
#include "services.h"
|
#include "services.h"
|
||||||
#include "fsreg.h"
|
#include "fsreg.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
|
#include "service_manager.h"
|
||||||
#include "errdisp.h"
|
#include "errdisp.h"
|
||||||
#include "hbloader.h"
|
#include "hbloader.h"
|
||||||
|
#include "3dsx.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "MyThread.h"
|
#include "MyThread.h"
|
||||||
#include "menus/process_patches.h"
|
#include "menus/process_patches.h"
|
||||||
@ -67,7 +69,6 @@ void __ctru_exit()
|
|||||||
__libc_fini_array();
|
__libc_fini_array();
|
||||||
__appExit();
|
__appExit();
|
||||||
__sync_fini();
|
__sync_fini();
|
||||||
for(;;) svcSleepThread(0); // kernel-loaded sysmodules except PXI are not supposed to terminate anyways
|
|
||||||
svcExitProcess();
|
svcExitProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,46 +106,48 @@ void initSystem()
|
|||||||
bool terminationRequest = false;
|
bool terminationRequest = false;
|
||||||
Handle terminationRequestEvent;
|
Handle terminationRequestEvent;
|
||||||
|
|
||||||
|
static void handleTermNotification(u32 notificationId)
|
||||||
|
{
|
||||||
|
(void)notificationId;
|
||||||
|
// Termination request
|
||||||
|
terminationRequest = true;
|
||||||
|
svcSignalEvent(terminationRequestEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ServiceManagerServiceEntry services[] = {
|
||||||
|
{ "err:f", 1, ERRF_HandleCommands, true },
|
||||||
|
{ "hb:ldr", 2, HBLDR_HandleCommands, true },
|
||||||
|
{ NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ServiceManagerNotificationEntry notifications[] = {
|
||||||
|
{ 0x100, handleTermNotification },
|
||||||
|
{ 0x000, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
Result res = 0;
|
static u8 ipcBuf[0x100] = {0}; // used by both err:f and hb:ldr
|
||||||
Handle notificationHandle;
|
|
||||||
|
|
||||||
if(R_FAILED(srvEnableNotification(¬ificationHandle)))
|
// Set up static buffers for IPC
|
||||||
svcBreak(USERBREAK_ASSERT);
|
u32* bufPtrs = getThreadStaticBuffers();
|
||||||
|
memset(bufPtrs, 0, 16 * 2 * 4);
|
||||||
|
bufPtrs[0] = IPC_Desc_StaticBuffer(sizeof(ipcBuf), 0);
|
||||||
|
bufPtrs[1] = (u32)ipcBuf;
|
||||||
|
bufPtrs[2] = IPC_Desc_StaticBuffer(sizeof(ldrArgvBuf), 1);
|
||||||
|
bufPtrs[3] = (u32)ldrArgvBuf;
|
||||||
|
|
||||||
if(R_FAILED(svcCreateEvent(&terminationRequestEvent, RESET_STICKY)))
|
if(R_FAILED(svcCreateEvent(&terminationRequestEvent, RESET_STICKY)))
|
||||||
svcBreak(USERBREAK_ASSERT);
|
svcBreak(USERBREAK_ASSERT);
|
||||||
|
|
||||||
MyThread *menuThread = menuCreateThread(), *errDispThread = errDispCreateThread(), *hbldrThread = hbldrCreateThread();
|
MyThread *menuThread = menuCreateThread();
|
||||||
MyThread *shellOpenThread = shellOpenCreateThread();
|
MyThread *shellOpenThread = shellOpenCreateThread();
|
||||||
|
|
||||||
do
|
if (R_FAILED(ServiceManager_Run(services, notifications, NULL)))
|
||||||
{
|
svcBreak(USERBREAK_PANIC);
|
||||||
res = svcWaitSynchronization(notificationHandle, -1LL);
|
|
||||||
|
|
||||||
if(R_FAILED(res))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
u32 notifId = 0;
|
|
||||||
|
|
||||||
if(R_FAILED(srvReceiveNotification(¬ifId)))
|
|
||||||
svcBreak(USERBREAK_ASSERT);
|
|
||||||
|
|
||||||
if(notifId == 0x100)
|
|
||||||
{
|
|
||||||
// Termination request
|
|
||||||
terminationRequest = true;
|
|
||||||
svcSignalEvent(terminationRequestEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while(!terminationRequest);
|
|
||||||
|
|
||||||
MyThread_Join(menuThread, -1LL);
|
MyThread_Join(menuThread, -1LL);
|
||||||
MyThread_Join(errDispThread, -1LL);
|
|
||||||
MyThread_Join(hbldrThread, -1LL);
|
|
||||||
MyThread_Join(shellOpenThread, -1LL);
|
MyThread_Join(shellOpenThread, -1LL);
|
||||||
|
|
||||||
svcCloseHandle(notificationHandle);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
166
sysmodules/rosalina/source/service_manager.c
Normal file
166
sysmodules/rosalina/source/service_manager.c
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||||
|
* * Requiring preservation of specified reasonable legal notices or
|
||||||
|
* author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
* * Prohibiting misrepresentation of the origin of that material,
|
||||||
|
* or requiring that modified versions of such material be marked in
|
||||||
|
* reasonable ways as different from the original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
#include "service_manager.h"
|
||||||
|
|
||||||
|
#define TRY(expr) if(R_FAILED(res = (expr))) goto cleanup;
|
||||||
|
|
||||||
|
Result ServiceManager_Run(const ServiceManagerServiceEntry *services, const ServiceManagerNotificationEntry *notifications, const ServiceManagerContextAllocator *allocator)
|
||||||
|
{
|
||||||
|
Result res = 0;
|
||||||
|
|
||||||
|
u32 numServices = 0;
|
||||||
|
u32 maxSessionsTotal = 0;
|
||||||
|
u32 numActiveSessions = 0;
|
||||||
|
bool terminationRequested = false;
|
||||||
|
|
||||||
|
for (u32 i = 0; services[i].name != NULL; i++) {
|
||||||
|
numServices++;
|
||||||
|
maxSessionsTotal += services[i].maxSessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle waitHandles[1 + numServices + maxSessionsTotal];
|
||||||
|
void *ctxs[maxSessionsTotal];
|
||||||
|
u8 handlerIds[maxSessionsTotal];
|
||||||
|
|
||||||
|
Handle replyTarget = 0;
|
||||||
|
s32 id = -1;
|
||||||
|
u32 *cmdbuf = getThreadCommandBuffer();
|
||||||
|
|
||||||
|
TRY(srvEnableNotification(&waitHandles[0]));
|
||||||
|
|
||||||
|
for (u32 i = 0; i < numServices; i++) {
|
||||||
|
if (!services[i].isGlobalPort) {
|
||||||
|
TRY(srvRegisterService(&waitHandles[1 + i], services[i].name, (s32)services[i].maxSessions));
|
||||||
|
} else {
|
||||||
|
Handle clientPort;
|
||||||
|
TRY(svcCreatePort(&waitHandles[1 + i], &clientPort, services[i].name, (s32)services[i].maxSessions));
|
||||||
|
svcCloseHandle(clientPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!terminationRequested) {
|
||||||
|
if (replyTarget == 0) {
|
||||||
|
cmdbuf[0] = 0xFFFF0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = -1;
|
||||||
|
res = svcReplyAndReceive(&id, waitHandles, 1 + numServices + numActiveSessions, replyTarget);
|
||||||
|
|
||||||
|
if (res == (Result)0xC920181A) {
|
||||||
|
// Session has been closed
|
||||||
|
u32 off;
|
||||||
|
if (id == -1) {
|
||||||
|
for (off = 0; off < numActiveSessions && waitHandles[1 + numServices + off] != replyTarget; off++);
|
||||||
|
if (off >= numActiveSessions) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = 1 + numServices + off;
|
||||||
|
} else if ((u32)id < 1 + numServices) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
off = id - 1 - numServices;
|
||||||
|
|
||||||
|
Handle h = waitHandles[id];
|
||||||
|
void *ctx = ctxs[off];
|
||||||
|
waitHandles[id] = waitHandles[1 + numServices + --numActiveSessions];
|
||||||
|
handlerIds[off] = handlerIds[numActiveSessions];
|
||||||
|
ctxs[off] = ctxs[numActiveSessions];
|
||||||
|
|
||||||
|
svcCloseHandle(h);
|
||||||
|
if (allocator != NULL) {
|
||||||
|
allocator->freeSessionContext(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
replyTarget = 0;
|
||||||
|
res = 0;
|
||||||
|
} else if (R_FAILED(res)) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// Ok, no session closed and no error
|
||||||
|
replyTarget = 0;
|
||||||
|
if (id == 0) {
|
||||||
|
// Notification
|
||||||
|
u32 notificationId = 0;
|
||||||
|
TRY(srvReceiveNotification(¬ificationId));
|
||||||
|
terminationRequested = notificationId == 0x100;
|
||||||
|
|
||||||
|
for (u32 i = 0; notifications[i].handler != NULL; i++) {
|
||||||
|
if (notifications[i].id == notificationId) {
|
||||||
|
notifications[i].handler(notificationId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((u32)id < 1 + numServices) {
|
||||||
|
// New session
|
||||||
|
Handle session;
|
||||||
|
void *ctx = NULL;
|
||||||
|
TRY(svcAcceptSession(&session, waitHandles[id]));
|
||||||
|
|
||||||
|
if (allocator) {
|
||||||
|
ctx = allocator->newSessionContext((u8)(id - 1));
|
||||||
|
if (ctx == NULL) {
|
||||||
|
svcCloseHandle(session);
|
||||||
|
return 0xDEAD0000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitHandles[1 + numServices + numActiveSessions] = session;
|
||||||
|
handlerIds[numActiveSessions] = (u8)(id - 1);
|
||||||
|
ctxs[numActiveSessions++] = ctx;
|
||||||
|
} else {
|
||||||
|
// Service command
|
||||||
|
u32 off = id - 1 - numServices;
|
||||||
|
services[handlerIds[off]].handler(ctxs[off]);
|
||||||
|
replyTarget = waitHandles[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
for (u32 i = 0; i < 1 + numServices + numActiveSessions; i++) {
|
||||||
|
svcCloseHandle(waitHandles[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < numServices; i++) {
|
||||||
|
if (!services[i].isGlobalPort) {
|
||||||
|
srvUnregisterService(services[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allocator) {
|
||||||
|
for (u32 i = 0; i < numActiveSessions; i++) {
|
||||||
|
allocator->freeSessionContext(ctxs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
Reference in New Issue
Block a user