3ds: Various fixes, optimizations.

rockbox-gerrit-noreply--- via rockbox-cvs <[email protected]>
Newsgroups gmane.comp.systems.archos.rockbox.cvs
Message-ID <[email protected]>
commit 752467dee4e2cda61c605a7b4a615e76817f28ba
Author: Mauricio Garrido <[email protected]>
Date:   Fri Jan 9 17:20:29 2026 -0600

    3ds: Various fixes, optimizations.
    
    This commit does the following changes:
    
    - Fix mkdir implementation not reporting EEXIST error.
    - Fix database build feature.
    - Small speed-up when parsing directories and files.
    - Fix buffering thread hogging cpu and preventing other threads to run.
    - Fix sdl plugins not compiling by re-adding ctru specific cflags in sdl.make.
    
    Change-Id: I507c0dcc85cdbcc607ab9c9c6d0b42e6a80caa5a

diff --git a/apps/plugins/sdl/sdl.make b/apps/plugins/sdl/sdl.make
index 3b3bf819cf..9d666bd732 100644
--- a/apps/plugins/sdl/sdl.make
+++ b/apps/plugins/sdl/sdl.make
@@ -39,6 +39,12 @@ SDLFLAGS = -I$(SDL_SRCDIR)/include $(filter-out -O%,$(PLUGINFLAGS))		\
 #-ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations	\
 #-D_GNU_SOURCE=1 -D_REENTRANT -DSDL -DELF
 
+# CTRU does need these to avoid compiler errors
+ifeq ($(APP_TYPE),ctru-app)
+SDLFLAGS += -Wno-int-conversion -Wno-incompatible-pointer-types        \
+-Wno-implicit-function-declaration -Wno-implicit-int
+endif
+
 ifndef APP_TYPE
     ### no target has a big enough plugin buffer
     ROCKS += $(SDL_OBJDIR)/duke3d.ovl
diff --git a/firmware/target/hosted/ctru/lib/bfile/bfile.c b/firmware/target/hosted/ctru/lib/bfile/bfile.c
index e63ecf008b..e7a8625e71 100644
--- a/firmware/target/hosted/ctru/lib/bfile/bfile.c
+++ b/firmware/target/hosted/ctru/lib/bfile/bfile.c
@@ -6,6 +6,12 @@
 
 #include "bfile.h"
 
+/* Define LOGF_ENABLE to enable logf output in this file */
+#if 0
+#define LOGF_ENABLE
+#endif
+#include "logf.h"
+
 // rw mutex implementation
 void sync_RWMutexInit(sync_RWMutex *m) {
     LightLock_Init(&m->shared);
@@ -63,12 +69,14 @@ void sync_RWMutexUnlock(sync_RWMutex *m) {
 file_error_t readPage(PageReader *p, u64 offset)
 {
     u32 read_bytes = 0;
-    if (R_FAILED(FSFILE_Read(p->file, 
-                            &read_bytes,
-                             offset,
-                             p->buffer,
-                             p->size))) {
-        printf("readPage: FSFILE_Read failed (I/O Error)\n");
+    Result res;
+    res = FSFILE_Read(p->file, 
+                      &read_bytes,
+                      offset,
+                      p->buffer,
+                      p->size);
+    if (R_FAILED(res)) {
+        logf("readPage: 0x%lx\n", R_DESCRIPTION(res));
         return "I/O Error";
     }
 
@@ -81,7 +89,7 @@ file_error_t readPage(PageReader *p, u64 offset)
     p->start = offset;
     p->end = offset + p->size;
 
-    /* printf("page: 0x%llx, 0x%llx, %lld (last_page: %s)\n", p->start, p->end, p->size, p->isLastPage == true ? "true": "false"); */
+    logf("page: 0x%llx, 0x%llx, %lld (last_page: %s)\n", p->start, p->end, p->size, p->isLastPage == true ? "true": "false");
     return NULL;
 }
 
@@ -89,18 +97,18 @@ PageReader* NewPageReader(Handle file, s64 pageSize)
 {
     PageReader *p = (PageReader *) malloc(sizeof(PageReader));
     if (p == NULL) {
-        printf("NewPageReader: memory error\n");
+        logf("NewPageReader: memory error\n");
         return NULL;
     }
 
-    p->buffer = (u8 *) malloc(sizeof(u8) * pageSize);
+    p->buffer = malloc(sizeof(u8) * pageSize);
     if (p->buffer == NULL) {
-        printf("NewPagereader: memory error (buffer)\n");
+        logf("NewPagereader: memory error (buffer)\n");
         return NULL;
     }
 
     // clear buffer data  
-    memset(p->buffer, 0x0, sizeof(u8) + pageSize);
+    memset(p->buffer, 0x0, sizeof(u8) * pageSize);
 
     p->start = 0;
     p->end = 0;
@@ -140,6 +148,27 @@ int_error_t PageReader_ReadAt(PageReader *p, u8 *buffer, size_t size, off_t offs
 {
     bool eof = false;
 
+    // only use page_reader if buffer size is smaller than page size
+    if (size > p->size) {
+        // direct file access (fs.h)
+        u32 bytes_read = 0;
+        Result res = FSFILE_Read(p->file,
+                                &bytes_read,
+                                offset,
+                                buffer,
+                                size);
+        if (R_FAILED(res)) {
+            return (int_error_t) { R_DESCRIPTION(res), "I/O Error" };
+        }
+
+        // io.EOF
+        if (bytes_read == 0) {
+            return (int_error_t) { 0, "io.EOF" };
+        }
+
+        return (int_error_t) { bytes_read, NULL };
+    }
+
     // higher probability, buffer is in cached page range
     if ((offset >= p->start) && ((offset + size) < p->end)) {
         copyPage(p, buffer, size, offset);
@@ -147,16 +176,14 @@ int_error_t PageReader_ReadAt(PageReader *p, u8 *buffer, size_t size, off_t offs
     }
 
     // less higher probability, read new page at offset
-    if (p->isLastPage == false) {
-        file_error_t err = readPage(p, offset);
-        if (err != NULL) {
-            return (int_error_t) { -1, "I/O Error" };
-        }
-
-        // we could have reached last page here so continue to
-        // last page handling
+    file_error_t err = readPage(p, offset);
+    if (err != NULL) {
+        return (int_error_t) { -1, "I/O Error" };
     }
 
+    // we could have reached last page here so continue to
+    // last page handling
+
     // lower probability, we are at the last page
 
     // trying to read past end of file
@@ -173,3 +200,130 @@ int_error_t PageReader_ReadAt(PageReader *p, u8 *buffer, size_t size, off_t offs
     copyPage(p, buffer, size, offset);
     return (int_error_t) { size, eof == true ? "io.EOF" : NULL };
 }
+
+int_error_t PageReader_WriteAt(PageReader *p, u8 *buffer, size_t size, off_t offset, bool flush_cache)
+{
+    // we will use direct file access for writing (fs.h)
+    u32 written = 0;
+    Result res = FSFILE_Write(p->file,
+                              &written,
+                              offset,
+                              buffer,
+                              size,
+                              FS_WRITE_FLUSH);
+    if (R_FAILED(res)) {
+        return (int_error_t) { -1, "I/O Error" };
+    }
+
+    if (flush_cache) {
+        /* logf("PageReader_WriteAt: flush cache\n"); */
+        // reload current page for O_RDWR files
+        // read ahead first page buffer from file
+        file_error_t err =  readPage(p, p->start);
+        if (err != NULL) {
+            return (int_error_t) { -1, "I/O Error" };
+        }
+    }
+
+    return (int_error_t) { written, NULL };
+}
+
+// page reader implementation for directory entries
+file_error_t readPageDirectory(PageReader *p)
+{
+    u32 entries_read = 0;
+    FS_DirectoryEntry *dirEntries = (FS_DirectoryEntry *) p->buffer;
+    Result result = FSDIR_Read(p->file,
+                               &entries_read,
+                               p->size,
+                               dirEntries);
+
+    if (R_FAILED(result)) {
+        logf("FSDIR_Read: 0x%lx\n", R_DESCRIPTION(result));
+        return "I/O Error";
+    }
+
+    // we reached directory end
+    if (entries_read == 0) {
+        return "io.EOF";
+    }
+
+    if (entries_read < p->size) {
+         p->isLastPage = true;
+    }
+
+    p->size = entries_read;
+    p->start = 0;
+    p->end = p->size;
+
+    /* logf("page: 0x%llx, 0x%llx, %lld (last_page: %s)\n", p->start, p->end, p->size, p->isLastPage == true ? "true": "false"); */
+    return NULL;
+}
+
+PageReader *NewPageReaderDirectory(Handle file, s64 pageSize)
+{
+    PageReader *p = (PageReader *) malloc(sizeof(PageReader));
+    if (p == NULL) {
+        logf("NewPageReaderDirectory: memory error\n");
+        return NULL;
+    }
+
+    // round buffer size to sizeof(FS_DirectoryEntry)
+    int maxDirEntries = pageSize / sizeof(FS_DirectoryEntry);
+
+    p->buffer = malloc(sizeof(FS_DirectoryEntry) * maxDirEntries);
+    if (p->buffer == NULL) {
+        logf("NewPageReaderDirectory: memory error (buffer)\n");
+        return NULL;
+    }
+
+    // clear buffer data  
+    memset(p->buffer, 0x0, sizeof(FS_DirectoryEntry) * maxDirEntries);
+
+    p->start = 0;
+    p->end = 0;
+    p->isLastPage = false;
+    p->size = maxDirEntries;
+    p->file = file;
+
+    // read ahead first page buffer from file
+    file_error_t err =  readPageDirectory(p);
+    if (err != NULL) {
+        free(p);
+        return NULL;
+    }
+
+    return p;
+}
+
+static inline void copyEntry(PageReader *p, FS_DirectoryEntry *entry)
+{
+    const FS_DirectoryEntry *dirEntries = (FS_DirectoryEntry *) p->buffer;
+    memcpy(entry, &dirEntries[p->start], sizeof(FS_DirectoryEntry));
+    p->start ++;
+}
+
+int_error_t PageReader_ReadDir(PageReader *p, FS_DirectoryEntry *entry)
+{
+    // higher probability, entry is in cached page range
+    if (p->start < p->end) {
+        copyEntry(p, entry);
+        return (int_error_t) { 1, NULL};
+    }
+
+    // less higher probability, read a new page
+    file_error_t err = readPageDirectory(p);
+
+    // end of directory?
+    if (err != NULL) {
+        if (!strcmp(err, "io.EOF")) {
+            return (int_error_t) { 0, "io.EOF" };
+        }
+        else {
+            return (int_error_t) { -1, "I/O Error" };
+        }
+    }
+
+    copyEntry(p, entry);
+    return (int_error_t) { 1, NULL};
+}
diff --git a/firmware/target/hosted/ctru/lib/bfile/bfile.h b/firmware/target/hosted/ctru/lib/bfile/bfile.h
index dab6c69309..bdaeb3810e 100644
--- a/firmware/target/hosted/ctru/lib/bfile/bfile.h
+++ b/firmware/target/hosted/ctru/lib/bfile/bfile.h
@@ -3,15 +3,24 @@
 
 #include "bfile-internal.h"
 
-static const int defaultPageSize   = 0x80000;  // default page buffer size, 512 kB
+static const int defaultPageSize   = 0x20000;  // default page buffer size, 128 kB
 
-// NewPageReader creates a new PageReader struct with pageSize
+// NewPageReader creates a new PageReader struct with pageSize.
 PageReader *NewPageReader(Handle file, s64 pageSize);
 
-// Free all memory associated to the PageReader pointer
+// Free all memory associated to the PageReader pointer.
 void PageReader_Free(PageReader *p);
 
 // ReadAt reads size bytes from the PageReader starting at offset.
 int_error_t PageReader_ReadAt(PageReader *p, u8 *buffer, size_t size, off_t offset);
 
+// WriteAt writes size bytes from the PageReader starting at offset.
+int_error_t PageReader_WriteAt(PageReader *p, u8 *buffer, size_t size, off_t offset, bool flush_cache);
+
+// NewPageReader creates a new PageReader struct with pageSize, for directory use.
+PageReader *NewPageReaderDirectory(Handle file, s64 pageSize);
+
+// ReadAt reads one directory entry from memory.
+int_error_t PageReader_ReadDir(PageReader *p, FS_DirectoryEntry *entry);
+
 #endif /* _B_FILE_H_ */
diff --git a/firmware/target/hosted/ctru/lib/sys_dir.c b/firmware/target/hosted/ctru/lib/sys_dir.c
index 5571d40c8e..b997178900 100644
--- a/firmware/target/hosted/ctru/lib/sys_dir.c
+++ b/firmware/target/hosted/ctru/lib/sys_dir.c
@@ -46,7 +46,7 @@ static struct dirstr_desc
     struct dirent       entry;  /* current parsed entry information */
 } open_streams[MAX_OPEN_DIRS] =
 {
-    [0 ... MAX_OPEN_FILES-1] = { .stream = { .handle = 0 } }
+    [0 ... MAX_OPEN_FILES-1] = { .stream = { .cache = NULL } }
 };
 
 extern FS_Archive sdmcArchive;
@@ -58,7 +58,7 @@ static struct dirstr_desc * get_dirstr(DIR *dirp)
 
     if (!PTR_IN_ARRAY(open_streams, dir, MAX_OPEN_DIRS))
         dir = NULL;
-    else if (dir->stream.handle != 0)
+    else if (dir->stream.cache != NULL)
         return dir;
 
     int errnum;
@@ -103,7 +103,7 @@ static struct dirstr_desc * alloc_dirstr(void)
     for (unsigned int dd = 0; dd < MAX_OPEN_DIRS; dd++)
     {
         struct dirstr_desc *dir = &open_streams[dd];
-        if (dir->stream.handle == 0)
+        if (dir->stream.cache == NULL)
             return dir;
     }
 
@@ -151,6 +151,11 @@ DIR * ctru_opendir(const char *dirname)
         FILE_ERROR(EMFILE, -1);
     }
 
+    dir->stream.cache = NewPageReaderDirectory(dir->stream.handle, defaultPageSize);
+    if (dir->stream.cache == NULL) {
+        FILE_ERROR(ERRNO, -2);
+    }
+
     dir->stream.size = 0;
     dir->stream.flags = 0;
 
@@ -159,6 +164,10 @@ DIR * ctru_opendir(const char *dirname)
 
     dirp = (DIR *)dir;
 file_error:
+    if (dir->stream.handle != 0) {
+        FSDIR_Close(dir->stream.handle);
+        dir->stream.handle = 0;
+    }
     file_internal_unlock_WRITER();
     return dirp;
 }
@@ -177,12 +186,15 @@ int ctru_closedir(DIR *dirp)
 
     logf("closedir(dirname=\"%s\")\n", dir->stream.path);
 
-    if (dir->stream.handle == 0)
+    if (dir->stream.cache == NULL)
     {
         logf("dir #%d: dir not open\n", (int)(dir - open_streams));
         FILE_ERROR(EBADF, -2);
     }
 
+    PageReader_Free(dir->stream.cache);
+    dir->stream.cache = NULL;
+
     Result res = FSDIR_Close(dir->stream.handle);
     if (R_FAILED(res))
         FILE_ERROR(ERRNO, -3);
@@ -233,16 +245,12 @@ struct dirent * ctru_readdir(DIR *dirp)
 
     logf("readdir(dirname=\"%s\")\n", dir->stream.path);
 
-    u32 dataRead = 0;
     FS_DirectoryEntry dirEntry;
-    Result result = FSDIR_Read(dir->stream.handle,
-                               &dataRead,
-                               1,
-                               &dirEntry);
-    if (R_FAILED(result))
+    int_error_t n_err = PageReader_ReadDir(dir->stream.cache, &dirEntry);
+    if (n_err.n < 0)
         FILE_ERROR(EIO, _RC);
 
-    if (dataRead == 0) {
+    if (n_err.n == 0) {
         /* directory end. return NULL value, no errno */
         res = NULL;
         goto file_error;
@@ -274,6 +282,15 @@ file_error:
     return res;
 }
 
+/* libctru result.h description values appear to be missing
+   FSUSER_CreateDirectory return values */
+
+enum
+{
+    RD_DIRECTORY_ALREADY_EXISTS     = 0xBE,
+    RD_MISSING_PARENT_DIRECTORY     = 0x78,
+};
+
 /* make a directory */
 int ctru_mkdir(const char *path)
 {
@@ -286,8 +303,14 @@ int ctru_mkdir(const char *path)
     Result res = FSUSER_CreateDirectory(sdmcArchive,
                                         fsMakePath(PATH_ASCII, path),
                                         0);
-    if (R_FAILED(res))
+    if (R_FAILED(res)) {
+        if (R_DESCRIPTION(res) == RD_DIRECTORY_ALREADY_EXISTS)
+            FILE_ERROR(ERRNO, EEXIST);
+        if (R_DESCRIPTION(res) == RD_MISSING_PARENT_DIRECTORY)
+            FILE_ERROR(ERRNO, ENOENT);
+        /* Unknown error */
         FILE_ERROR(ERRNO, -1);
+    }
 
     rc = 0;
 file_error:
diff --git a/firmware/target/hosted/ctru/lib/sys_file.c b/firmware/target/hosted/ctru/lib/sys_file.c
index fe884b2531..4370627362 100644
--- a/firmware/target/hosted/ctru/lib/sys_file.c
+++ b/firmware/target/hosted/ctru/lib/sys_file.c
@@ -235,46 +235,17 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte,
     int_error_t n_err;
 
     if (write) {
-        // we will use direct file access for writing
-        u32 written = 0;
-        Result res = FSFILE_Write(file->stream.handle,
-                                  &written,
-                                  AtomicLoad(&file->offset),
-                                  buf,
-                                  nbyte,
-                                  FS_WRITE_FLUSH);
-        if (R_FAILED(res)) {
-            n_err.err = "I/O error";
-        }
-
-        n_err.n = written;
+        n_err = PageReader_WriteAt(file->stream.cache,
+                                   buf,
+                                   nbyte,
+                                   AtomicLoad(&file->offset),
+                                   file->stream.flags & O_RDWR ? true : false);
     }
     else {
-        // only use page_reader if buffer size is smaller than page size
-        if (nbyte < file->stream.cache->size) {
-            n_err = PageReader_ReadAt(file->stream.cache,
-                                      (u8 *) buf,
-                                      nbyte,
-                                      AtomicLoad(&file->offset));
-        }
-        else {
-            u32 bytes_read = 0;
-            Result res = FSFILE_Read(file->stream.handle,
-                                    &bytes_read,
-                                    AtomicLoad(&file->offset),
-                                    buf,
-                                    nbyte);
-            if (R_FAILED(res)) {
-                n_err.err = "I/O error";
-            }
-
-            // io.EOF
-            if (bytes_read == 0) {
-                n_err.err = "io.EOF";
-            }
-
-            n_err.n = bytes_read;
-        }
+        n_err = PageReader_ReadAt(file->stream.cache,
+                                  buf,
+                                  nbyte,
+                                  AtomicLoad(&file->offset));
     }
 
     if ((n_err.err != NULL) && strcmp(n_err.err, "io.EOF")) {
diff --git a/firmware/target/hosted/ctru/lib/sys_thread.c b/firmware/target/hosted/ctru/lib/sys_thread.c
index 4d6ba2ff99..04e80b75ac 100644
--- a/firmware/target/hosted/ctru/lib/sys_thread.c
+++ b/firmware/target/hosted/ctru/lib/sys_thread.c
@@ -78,12 +78,12 @@ int get_ctru_thread_priority(int priority)
         (priority == PRIORITY_REALTIME))
         return 0x18;
     else if (priority == PRIORITY_BUFFERING)
-        return 0x18; /* Highest */
+        return 0x2F;
     else if ((priority == PRIORITY_USER_INTERFACE) || (priority == PRIORITY_RECORDING) ||
              (priority == PRIORITY_PLAYBACK))
-        return 0x30;
-    else if (priority == PRIORITY_PLAYBACK_MAX)
         return 0x2F;
+    else if (priority == PRIORITY_PLAYBACK_MAX)
+        return 0x20;
     else if (priority == PRIORITY_SYSTEM)
         return 0x30;
     else if (priority == PRIORITY_BACKGROUND)
@@ -208,8 +208,8 @@ sysThread *sys_create_thread(int(*fn)(void *), const char *name, const size_t st
     thread->userdata = data;
     thread->stacksize = stacksize;
     
-    int cpu = -1;
-    if (name && (strncmp(name, "tagcache", 8) == 0) && R_SUCCEEDED(APT_SetAppCpuTimeLimit(30))) {
+    int cpu = 0;
+    if (name && (strncmp(name, "buffering", 9) == 0) && R_SUCCEEDED(APT_SetAppCpuTimeLimit(30))) {
         cpu = 1;
         printf("thread: %s, running in cpu 1\n", name);
     }
@@ -400,4 +400,3 @@ int sys_cond_wait(sysCond *cond, RecursiveLock *mutex)
 
     return 0;
 }
-
-- 
rockbox-cvs mailing list
[email protected]
https://lists.haxx.se/mailman/listinfo/rockbox-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.