Homebrew Homebrew Development

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
Is it normal that accept function blocks main thread even if it's called in a secondary thread?

Here's the code:
Code:
// Globals
volatile bool accepted = false;
volatile bool initialized = false;
Handle update;
Handle acceptThread;
u32* threadStack;
volatile Socket* acceptResult = NULL;

// Secondary thread func
static void acceptAsync(void* arg){
   Socket* my_socket = (Socket*)arg;
   while(1) {
     svcWaitSynchronization(update, U64_MAX);
     svcClearEvent(update);
     u32 bytesRead;
     u32 control;
     u32 sockClient = accept(my_socket->sock, (struct sockaddr*)NULL, NULL);
     acceptResult = (Socket*)malloc(sizeof(Socket));
     acceptResult->sock = sockClient;
     acceptResult->serverSocket = false;   
     acceptResult->magic = 0xDEADDEAD;
     svcExitThread();
   }     
}


// This is executed in main thread
static int lua_accept(lua_State *L)
{
   int argc = lua_gettop(L);
   if (argc != 1) return luaL_error(L, "wrong number of arguments");

   Socket* my_socket = (Socket*)luaL_checkinteger(L, 1);
   
   if (initialized){
     if (acceptResult != NULL){
       lua_pushinteger(L, (u32)acceptResult);
       initialized = false;
       return 1;
     }else return 0;
   }else{
     svcCreateEvent(&update,0);
     threadStack = (u32*)memalign(32, 8192);
     svcSignalEvent(update);
     Result ret = svcCreateThread(&acceptThread, acceptAsync, (u32)my_socket, &threadStack[2048], 0x18, 1);
     initialized = true;
     return 0;
   }
}
 

Tjessx

Well-Known Member
Member
Joined
Dec 3, 2014
Messages
1,160
Trophies
0
Age
27
XP
952
Country
Belgium
Is it normal that accept function blocks main thread even if it's called in a secondary thread?

Here's the code:
Code:
// Globals
volatile bool accepted = false;
volatile bool initialized = false;
Handle update;
Handle acceptThread;
u32* threadStack;
volatile Socket* acceptResult = NULL;

// Secondary thread func
static void acceptAsync(void* arg){
   Socket* my_socket = (Socket*)arg;
   while(1) {
     svcWaitSynchronization(update, U64_MAX);
     svcClearEvent(update);
     u32 bytesRead;
     u32 control;
     u32 sockClient = accept(my_socket->sock, (struct sockaddr*)NULL, NULL);
     acceptResult = (Socket*)malloc(sizeof(Socket));
     acceptResult->sock = sockClient;
     acceptResult->serverSocket = false;  
     acceptResult->magic = 0xDEADDEAD;
     svcExitThread();
   }    
}


// This is executed in main thread
static int lua_accept(lua_State *L)
{
   int argc = lua_gettop(L);
   if (argc != 1) return luaL_error(L, "wrong number of arguments");

   Socket* my_socket = (Socket*)luaL_checkinteger(L, 1);
  
   if (initialized){
     if (acceptResult != NULL){
       lua_pushinteger(L, (u32)acceptResult);
       initialized = false;
       return 1;
     }else return 0;
   }else{
     svcCreateEvent(&update,0);
     threadStack = (u32*)memalign(32, 8192);
     svcSignalEvent(update);
     Result ret = svcCreateThread(&acceptThread, acceptAsync, (u32)my_socket, &threadStack[2048], 0x18, 1);
     initialized = true;
     return 0;
   }
}
Usingg any socket function that involves connection with a client or server (read, write, accept, and their variants) makes the socket wait untill the entire action is done.
You can fix this by using non_blocking mode, i provided tou the function to set the socket on nonblocking mode a few pages back.
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
Usingg any socket function that involves connection with a client or server (read, write, accept, and their variants) makes the socket wait untill the entire action is done.
You can fix this by using non_blocking mode, i provided tou the function to set the socket on nonblocking mode a few pages back.

All sockets provided from lpp-3ds are set to NON_BLOCKING:

Code:
int setSockNoBlock(u32 s, u32 val)
{
   return setsockopt(s, SOL_SOCKET, 0x1009, (const char*)&val, sizeof(u32));
}

static int lua_createServerSocket(lua_State *L)
{
   int argc = lua_gettop(L);
   if (argc != 1)
   return luaL_error(L, "Socket.createServerSocket(port) takes one argument.");
   int port = luaL_checkinteger(L, 1);

   Socket* my_socket = (Socket*) malloc(sizeof(Socket));
   my_socket->serverSocket = true;

   my_socket->sock = socket(AF_INET, SOCK_STREAM, 0);
   if (my_socket->sock <= 0) {
     return luaL_error(L, "invalid socket.");
   }

   my_socket->addrTo.sin_family = AF_INET;
   my_socket->addrTo.sin_port = htons(port);
   my_socket->addrTo.sin_addr.s_addr = 0;

   int err = bind(my_socket->sock, (struct sockaddr*)&my_socket->addrTo, sizeof(my_socket->addrTo));
   if (err != 0) {
     return luaL_error(L, "bind error.");
   }

   setSockNoBlock(my_socket->sock, 1);

   err = listen(my_socket->sock, 1);
   if (err != 0) {
     return luaL_error(L, "listen error.");
   }
   
   my_socket->magic = 0xDEADDEAD;
   lua_pushinteger(L,(u32)my_socket);
   return 1;
}
 

Tjessx

Well-Known Member
Member
Joined
Dec 3, 2014
Messages
1,160
Trophies
0
Age
27
XP
952
Country
Belgium
Also, when in non blocking mode all the socket functions give their return variable imediatly.
The accept function for example will immediatly return wheter or not it accepted someone.
The recv function will give you the ammount of bytes it read.
 

Tjessx

Well-Known Member
Member
Joined
Dec 3, 2014
Messages
1,160
Trophies
0
Age
27
XP
952
Country
Belgium
All sockets provided from lpp-3ds are set to NON_BLOCKING:

Code:
int setSockNoBlock(u32 s, u32 val)
{
   return setsockopt(s, SOL_SOCKET, 0x1009, (const char*)&val, sizeof(u32));
}

static int lua_createServerSocket(lua_State *L)
{
   int argc = lua_gettop(L);
   if (argc != 1)
   return luaL_error(L, "Socket.createServerSocket(port) takes one argument.");
   int port = luaL_checkinteger(L, 1);

   Socket* my_socket = (Socket*) malloc(sizeof(Socket));
   my_socket->serverSocket = true;

   my_socket->sock = socket(AF_INET, SOCK_STREAM, 0);
   if (my_socket->sock <= 0) {
     return luaL_error(L, "invalid socket.");
   }

   my_socket->addrTo.sin_family = AF_INET;
   my_socket->addrTo.sin_port = htons(port);
   my_socket->addrTo.sin_addr.s_addr = 0;

   int err = bind(my_socket->sock, (struct sockaddr*)&my_socket->addrTo, sizeof(my_socket->addrTo));
   if (err != 0) {
     return luaL_error(L, "bind error.");
   }

   setSockNoBlock(my_socket->sock, 1);

   err = listen(my_socket->sock, 1);
   if (err != 0) {
     return luaL_error(L, "listen error.");
   }
  
   my_socket->magic = 0xDEADDEAD;
   lua_pushinteger(L,(u32)my_socket);
   return 1;
}
I don't think that your setSockNoBlock server works, if it would work then it wouldn't stop doing anything while waiting for a connection.
Try this one:
Code:
static int setSockNoBlock(int sock) {
    int flags = fcntl(sock, F_GETFL);
    return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}
 

Rinnegatamante

Well-Known Member
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
I don't think that your setSockNoBlock server works, if it would work then it wouldn't stop doing anything while waiting for a connection.
Try this one:
Code:
static int setSockNoBlock(int sock) {
    int flags = fcntl(sock, F_GETFL);
    return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}

Solved with a similar function. (Really strange the one i was using wasn't working cause i used it on lpp-c++ for PSP without any problems.)
 

Tjessx

Well-Known Member
Member
Joined
Dec 3, 2014
Messages
1,160
Trophies
0
Age
27
XP
952
Country
Belgium
Solved with a similar function. (Really strange the one i was using wasn't working cause i used it on lpp-c++ for PSP without any problems.)
some of the socket functions doesn't work, i have had trouble with write, read and send too, (instead of send i use sendto, and instead of read i use recv)
 

Tjessx

Well-Known Member
Member
Joined
Dec 3, 2014
Messages
1,160
Trophies
0
Age
27
XP
952
Country
Belgium
I'm trying to use an homebrew application that uses files on the sd card.
Can i test this homebrew with citra? and where should i put the files in?
 

daxtsu

Well-Known Member
Member
Joined
Jun 9, 2007
Messages
5,627
Trophies
2
XP
5,194
Country
Antarctica
Does the 3DS' OS have a watchdog on the LCD backlights or something? I wrote a small piece of homebrew that turns the touch screen backlight on and off when it's pressed, and if I just leave the bottom screen's backlight off for a while, it comes back on on its own. Here's the test program I'm using:

Code:
#include <3ds.h>
#include <stdio.h>

#ifndef REG_LCDBACKLIGHTSUB
#define REG_LCDBACKLIGHTSUB (u32)(0x1ED02A40 - 0x1EB00000)
#endif

static u32 brightnessSub;

static void disableBacklight() {
    u32 off = 0;

    GSPGPU_ReadHWRegs(NULL, REG_LCDBACKLIGHTSUB, &brightnessSub, 4);
    GSPGPU_WriteHWRegs(NULL, REG_LCDBACKLIGHTSUB, &off, 4);
}

static void enableBacklight() {
    GSPGPU_WriteHWRegs(NULL, REG_LCDBACKLIGHTSUB, &brightnessSub, 4);
}

int main(int argc, char **argv) {
    gfxInitDefault();
    consoleInit(GFX_TOP, NULL);

    printf("Hello, world!\n");

    // bad assumption: backlight is already on
    // should read the state first, but whatever, this is just a test.
    bool toggle = true;

    while(aptMainLoop()) {
        gspWaitForVBlank();
        hidScanInput();

        touchPosition touch;
        hidTouchRead(&touch);

        if (hidKeysDown() & KEY_TOUCH)
        {
            printf("touch screen pressed\n");
            if (!toggle)
            {
                enableBacklight();
            }
            else
            {
                disableBacklight();
            }

            toggle = !toggle;
        }

        if (hidKeysDown() & KEY_START)
        {
            enableBacklight();
            break;
        }

        gfxFlushBuffers();
        gfxSwapBuffers();
    }

    gfxExit();
    return 0;
}

I could probably just keep turning it off every frame while it's off, but that seems a bit silly.

Edit: Hm..it seems like I'm getting stray touch input events, or something, but my touch printf isn't triggered when the screen turns back on... That's weird. When I put the toggle on one of the face buttons (e.g. A), the problem seems to vanish.
 
Last edited by daxtsu,

daxtsu

Well-Known Member
Member
Joined
Jun 9, 2007
Messages
5,627
Trophies
2
XP
5,194
Country
Antarctica
Is anyone able to get a handle for the gsp::Lcd service on any CFW via a CIA homebrew (gsp::Lcd is already in the RSF file)? I've been trying different things for a few hours (such as trying to patch the services access list while running emuNAND) and I always get an access denied error from srv (0xd8e06406). Apparently getting a handle to it works on ninjhax 1.1b with service access patching, but I can't get it to work on Reinand 9.5.

Code:
static Handle lcdHandle = 0;
static Result lcdResult = 0;

Result lcdInit()
{
    return srvGetServiceHandle(&lcdHandle, "gsp::Lcd");
}

Result lcdExit()
{
    return svcCloseHandle(lcdHandle);
}

Result lcdPowerOffBacklight(int screen)
{
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00120040;
    cmdbuf[1] = screen;

    Result ret = svcSendSyncRequest(lcdHandle);

    return ret;
}

Result lcdPowerOnBacklight(int screen)
{
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00110040;
    cmdbuf[1] = screen;

    Result ret = svcSendSyncRequest(lcdHandle);

    return ret;
}


int main(int argc, char **argv) {
    gfxInitDefault();
    consoleInit(GFX_TOP, NULL);

    lcdResult = lcdInit();
    printf("Hello, world!\n");
    printf("lcdInit: %08x, handle %08x\n", lcdResult, lcdHandle);

    while(aptMainLoop()) {
        gspWaitForVBlank();
        hidScanInput();

        if (hidKeysDown() & KEY_START)
        {
            break;
        }

        gfxFlushBuffers();
        gfxSwapBuffers();
    }
    lcdExit();
    gfxExit();
    return 0;
}
 
Last edited by daxtsu,
D

Deleted User

Guest
Is anyone able to get a handle for the gsp::Lcd service on any CFW via a CIA homebrew? I've been trying different things for a few hours (such as trying to patch the services access list while running emuNAND) and I always get an access denied error from srv (0xd8e06406). Apparently getting a handle to it works on ninjhax 1.1b with service access patching, but I can't get it to work on Reinand 9.5.

Code:
static Handle lcdHandle = 0;
static Result lcdResult = 0;

Result lcdInit()
{
    return srvGetServiceHandle(&lcdHandle, "gsp::Gpu");
}

Result lcdExit()
{
    return svcCloseHandle(lcdHandle);
}

Result lcdPowerOffBacklight(int screen)
{
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00120040;
    cmdbuf[1] = screen;

    Result ret = svcSendSyncRequest(lcdHandle);

    return ret;
}

Result lcdPowerOnBacklight(int screen)
{
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00110040;
    cmdbuf[1] = screen;

    Result ret = svcSendSyncRequest(lcdHandle);

    return ret;
}


int main(int argc, char **argv) {
    gfxInitDefault();
    consoleInit(GFX_TOP, NULL);

    lcdResult = lcdInit();
    printf("Hello, world!\n");
    printf("lcdInit: %08x, handle %08x\n", lcdResult, lcdHandle);

    while(aptMainLoop()) {
        gspWaitForVBlank();
        hidScanInput();

        if (hidKeysDown() & KEY_START)
        {
            break;
        }

        gfxFlushBuffers();
        gfxSwapBuffers();
    }
    lcdExit();
    gfxExit();
    return 0;
}
Your code says "gsp::Gpu", but you're trying to use "gsp::Lcd". :P
 

daxtsu

Well-Known Member
Member
Joined
Jun 9, 2007
Messages
5,627
Trophies
2
XP
5,194
Country
Antarctica
Your code says "gsp::Gpu", but you're trying to use "gsp::Lcd". :P

Yeah, I just noticed that, but that's not the problem, I was just making sure I had access to Gpu when I was testing a second ago (I was getting some odd access denied errors a while back before I rebooted..), but forgot to change it back for pasting.
 
Last edited by daxtsu,

daxtsu

Well-Known Member
Member
Joined
Jun 9, 2007
Messages
5,627
Trophies
2
XP
5,194
Country
Antarctica
Sorry for the double post, but I got it to work: I had to boot NTR on top of Reinand, since gsp::Lcd is denied by default. It'd be nice if we could come up with a simple and clean way of patching service access checks on emuNANDs sort of like Myria's libkhax.

Here's my new code for anyone interested:
Code:
#include <3ds.h>
#include <stdio.h>

#define LCD_TOP 1
#define LCD_BOTTOM 2
#define LCD_BOTH 3

static Handle lcdHandle = 0;
static Result lcdResult = 0;

Result lcdInit()
{
    return srvGetServiceHandle(&lcdHandle, "gsp::Lcd");
}

Result lcdExit()
{
    return svcCloseHandle(lcdHandle);
}

Result GSPLCD_PowerOffBacklight(int screen)
{
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00120040;
    cmdbuf[1] = screen;

    Result ret = svcSendSyncRequest(lcdHandle);

    return ret;
}

Result GSPLCD_PowerOnBacklight(int screen)
{
    u32 *cmdbuf = getThreadCommandBuffer();

    cmdbuf[0] = 0x00110040;
    cmdbuf[1] = screen;

    Result ret = svcSendSyncRequest(lcdHandle);

    return ret;
}

void ControlLCDBacklight(int screen, bool off)
{
    lcdResult = lcdInit();
    if (lcdResult == 0)
    {
        if (off)
            GSPLCD_PowerOffBacklight(screen);
        else
            GSPLCD_PowerOnBacklight(screen);

        lcdExit();
    }
}

int main(int argc, char **argv) {
    gfxInitDefault();
    consoleInit(GFX_BOTTOM, NULL);
    printf("Backlight on/off test\n");

    while(aptMainLoop()) {
        gspWaitForVBlank();
        hidScanInput();

        if (hidKeysDown() & KEY_A)
        {
            ControlLCDBacklight(LCD_BOTTOM, false);
        }

        if (hidKeysDown() & KEY_B)
        {
            ControlLCDBacklight(LCD_BOTTOM, true);
        }

        if (hidKeysDown() & KEY_START)
        {
            break;
        }

        gfxFlushBuffers();
        gfxSwapBuffers();
    }

    gfxExit();
    return 0;
}


Edit: There seems to be one caveat with using gsp::Lcd..when you press Home, the 3DS will freeze. I guess the handle has to be released before the Home Menu can come back up..

Edit 2: Confirmed, yeah, if you release the handle before the home menu is invoked, it'll work fine. So I guess the best way to deal with turning the backlights on and off is to immediately get the handle, turn it on or off, then release the handle, all in one fell swoop.

Edit 3: Got rid of the old version and cleaned it up, it seems to be working without hangs now, but I'm still testing.

Edit 4: I've had my bottom LCD off for over 10 minutes now with no random hiccups, such as it turning back on by itself. For 9.2 and below, this seems to be the way to go.

Edit 5: I opened a pull request on Github, so hopefully they will accept it. https://github.com/smealum/ctrulib/pull/176
 
Last edited by daxtsu,

daxtsu

Well-Known Member
Member
Joined
Jun 9, 2007
Messages
5,627
Trophies
2
XP
5,194
Country
Antarctica
Has anyone figured out how APT:Reboot works? http://3dbrew.org/wiki/APT:Reboot

I'm trying to figure out how to launch AGB_FIRM titles with it, but I just get a Japanese error screen that tells me to turn the power off and read the manual. 3DBrew doesn't really explain what the "0x10 byte struct" is (it just has some vague info about titleID high/low, but not all of the components needed).

Edit: Got it, thanks to some help on #3dsdev. You pass in a struct like this:

Code:
typedef struct
{
    u32 programID_Lower;
    u32 programID_Upper;
    u32 mediaType;
    u32 padding;
}APT_ProgramLaunchInfo;

Basically, fill in the struct with your GBA game's title ID, put mediaType to 1 (SD card), and set padding to zero since it's ignored. After that, give APT_Reboot your struct, and the ID of AGB_FIRM (0x202, even for New 3DS!), or TWL_FIRM (0x102, even for New 3DS!), and it should reboot the console into your desired GBA game installed on sysNAND.

Edit 2: Seems like the game still has to be installed on emuNAND too, darn it. I wish there was a way around that. If we could find a way around that, we could probably use APT:Reboot as a "forwarder" space-saver CIA instead of needing twice the space for GBA games..
 
Last edited by daxtsu,

MichiS97

"Leftist snowflake milennial"
Member
Joined
Jun 14, 2011
Messages
1,817
Trophies
2
Age
26
Location
Munich
XP
3,604
Country
Germany
Out of curiosity, can you somehow use SQL databases with ctrulib? I'd like to make an online leaderboard for the Snake game I've coded
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
  • No one is chatting at the moment.
    Veho @ Veho: It's how we used to cheat at Pokewalker.