From: ljsebald <ljs...@us...> - 2024-01-29 00:42:11
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via b4f08e249a11a45bc25f7c824ce7f8d341ec37ea (commit) via 80890464370a53d81440d89d6a4f5a23657717f5 (commit) via ff85adae6f2f1078b5c3fbfe306adf6503f7395d (commit) via 78d530d389e8924a492b89fb522475465c8422b0 (commit) from 1162af57fab083584c7b6c0e553cbcb15723424a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b4f08e249a11a45bc25f7c824ce7f8d341ec37ea Author: Andy Barajas <and...@gm...> Date: Sun Jan 28 16:41:24 2024 -0800 Pull out sq fast path assembly to its own file (#475) * Pull out assembly function to its own file * Exit sq_cpy early if n is 0 * Removed use of extra register * One less cycle per loop commit 80890464370a53d81440d89d6a4f5a23657717f5 Author: Falco Girgis <gyr...@gm...> Date: Sun Jan 28 18:28:55 2024 -0600 Implement POSIX scandir() + alphasort() for dirent.h (#453) * Initial scandir implementation - Modified dirent.h to add RESTRICT keyword as in the standard, added declaration for alphasort(), made dirent::d_name[] a FAM, with DIR actually giving it a static size of NAME_MAX. - Modified readdir() to use the new FAM mechanism for dirent::d_name[] when copying over directory names - Added an initial implementation for POSIX scandir() and alphasort() * STILL TESTING AND WIP. * scandir() and alphasort() done and tested - added BSD/glibc dirent type #defines to dirent.h, so that we could stop using magic numbers within the source file - fixed a few issues with scandir() - documented scandir() and alphasort() - ensured proper error behavior for scandir() with directories that don't exist or non-directory file types - ensured no memory leaks via INIT_MALLOCSTATS - ensured scandir() handles out-of-memory errors gracefully, freeing resources, setting errno, and returning -1 correctly * Removed an unused include leftover from debugging. * Removed another leftover include from debugging. * Fixed doxygen comments on dirent.h types. commit ff85adae6f2f1078b5c3fbfe306adf6503f7395d Merge: 1162af57 78d530d3 Author: Lawrence Sebald <ljs...@us...> Date: Sun Jan 28 19:17:25 2024 -0500 Merge pull request #472 from KallistiOS/assert_doxygen Added doxygen category for assertion handlers commit 78d530d389e8924a492b89fb522475465c8422b0 Author: Falco Girgis <gyr...@gm...> Date: Sat Jan 27 02:19:29 2024 -0600 Added doxygen category for assertion handlers - Added custom assertion handling to the "Debugging" category under doxygen, because it's another useful thing users can do... ----------------------------------------------------------------------- Summary of changes: doc/CHANGELOG | 1 + include/assert.h | 24 +++- include/sys/dirent.h | 125 +++++++++++++++++---- kernel/arch/dreamcast/hardware/Makefile | 2 +- kernel/arch/dreamcast/hardware/sq.c | 43 ++----- kernel/arch/dreamcast/hardware/sq_fast_cpy.s | 46 ++++++++ kernel/arch/dreamcast/include/dc/sq.h | 33 +++++- kernel/libc/koslib/readdir.c | 14 +-- kernel/libc/koslib/scandir.c | 162 +++++++++++++++++++++++++-- 9 files changed, 363 insertions(+), 87 deletions(-) create mode 100644 kernel/arch/dreamcast/hardware/sq_fast_cpy.s diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 07a3840a..cc074cd6 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -215,6 +215,7 @@ KallistiOS version 2.1.0 ----------------------------------------------- - *** Increased resolution of clock() and CLOCKS_PER_SEC to microseconds [FG] - DC Created separate performance counter driver and enhanced API [FG] - *** Implemented _POSIX_CPUTIME in clock_gettime() using perf counter timer [FG] +- *** Implemented scandir() and alphasort() POSIX functions from dirent.h [FG] KallistiOS version 2.0.0 ----------------------------------------------- - DC Broadband Adapter driver fixes [Megan Potter == MP] diff --git a/include/assert.h b/include/assert.h index a1c9dff7..fc7e78ec 100644 --- a/include/assert.h +++ b/include/assert.h @@ -1,7 +1,7 @@ /* KallistiOS ##version## assert.h - Copyright (C)2002,2004 Megan Potter + Copyright (C) 2002, 2004 Megan Potter */ @@ -12,8 +12,9 @@ __BEGIN_DECLS /** - \file assert.h - \brief Standard C Assertions + \file assert.h + \brief Standard C Assertions + \ingroup assertions This file contains the standard C assertions to raise an assertion or to change the assertion handler. @@ -21,10 +22,25 @@ __BEGIN_DECLS \author Megan Potter */ +/** \defgroup assertions Assertions + \brief assert() management and custom handlers + \ingroup debugging + + KOS maps the standard C assert() mechanism to a default implementation + which logs the failed expression as well as the source code context. + A secondary assertion mechanism, assert_msg() is also provided for adding + a cusom message. You may also override KOS's assertion handler and replace + it with your own via assert_set_handler(). + + @{ +*/ + /* This is nice and simple, modeled after the BSD one like most of KOS; the addition here is assert_msg(), which allows you to provide an error message. */ +/** \cond */ #define _assert(e) assert(e) +/** \endcond */ #ifdef NDEBUG # define assert(e) ((void)0) @@ -105,6 +121,8 @@ typedef void (*assert_handler_t)(const char * file, int line, const char * expr, */ assert_handler_t assert_set_handler(assert_handler_t hnd); +/** @} */ + __END_DECLS #endif /* __ASSERT_H */ diff --git a/include/sys/dirent.h b/include/sys/dirent.h index f9e208f1..ec4bedec 100644 --- a/include/sys/dirent.h +++ b/include/sys/dirent.h @@ -2,6 +2,7 @@ dirent.h Copyright (C) 2003 Megan Potter + Copyright (C) 2024 Falco Girgis */ @@ -12,6 +13,7 @@ This partially implements the standard POSIX dirent.h functionality. \author Megan Potter + \author Falco Girgis */ #ifndef __SYS_DIRENT_H @@ -22,13 +24,36 @@ __BEGIN_DECLS #include <unistd.h> -#include <arch/types.h> +#include <stdint.h> #include <kos/fs.h> +#include <kos/limits.h> /** \addtogroup vfs_posix @{ */ +/** \name Directory File Types + \brief POSIX file types for dirent::d_name + + \remark + These directory entry types are not part of the POSIX specifican per-se, + but are used by BSD and glibc. + + \todo Ensure each VFS driver maps its directory types accordingly + + @{ +*/ +#define DT_UNKNOWN 0 /**< \brief Unknown */ +#define DT_FIFO 1 /**< \brief Named Pipe or FIFO */ +#define DT_CHR 2 /**< \brief Character Device */ +#define DT_DIR 4 /**< \brief Directory */ +#define DT_BLK 6 /**< \brief Block Device */ +#define DT_REG 8 /**< \brief Regular File */ +#define DT_LNK 10 /**< \brief Symbolic Link */ +#define DT_SOCK 12 /**< \brief Local-Domain Socket */ +#define DT_WHT 14 /**< \brief Whiteout (ignored) */ +/** @} */ + /** \brief POSIX directory entry structure. This structure contains information about a single entry in a directory in @@ -37,11 +62,11 @@ __BEGIN_DECLS \headerfile sys/dirent.h */ struct dirent { - int d_ino; /**< \brief File unique identifier. */ - off_t d_off; /**< \brief File offset */ - uint16 d_reclen; /**< \brief Record length */ - uint8 d_type; /**< \brief File type */ - char d_name[256]; /**< \brief Filename */ + int d_ino; /**< \brief File unique identifier. */ + off_t d_off; /**< \brief File offset */ + uint16_t d_reclen; /**< \brief Record length */ + uint8_t d_type; /**< \brief File type */ + char d_name[]; /**< \brief Filename */ }; /** \brief Type representing a directory stream. @@ -55,8 +80,9 @@ struct dirent { \headerfile sys/dirent.h */ typedef struct { - file_t fd; /**< \brief File descriptor for the directory */ - struct dirent d_ent; /**< \brief Current directory entry */ + file_t fd; /**< \brief File descriptor for the directory */ + struct dirent d_ent; /**< \brief Current directory entry */ + char d_name[NAME_MAX]; /**< \brief Filename */ } DIR; // Standard UNIX dir functions. Not all of these are fully functional @@ -67,12 +93,14 @@ typedef struct { The directory specified is opened if it exists. A directory stream object is returned for accessing the entries of the directory. - \param name The name of the directory to open. - \return A directory stream object to be used with readdir() on - success, NULL on failure. Sets errno as appropriate. \note As with other functions for opening files on the VFS, relative paths are permitted for the name parameter of this function. + + \param name The name of the directory to open. + + \return A directory stream object to be used with readdir() on + success, NULL on failure. Sets errno as appropriate. \see closedir \see readdir */ @@ -85,6 +113,7 @@ DIR *opendir(const char *name); associated with the directory stream. \param dir The directory stream to close. + \return 0 on success. -1 on error, setting errno as appropriate. */ int closedir(DIR *dir); @@ -95,13 +124,14 @@ int closedir(DIR *dir); returning the directory entry associated with the next object in the directory. + \warning Do not free the returned dirent! + \param dir The directory stream to read from. + \return A pointer to the next directory entry in the directory or NULL if there are no other entries in the directory. If an error is incurred, NULL will be returned and errno set to indicate the error. - - \note Do not free the returned dirent! */ struct dirent *readdir(DIR *dir); @@ -110,13 +140,14 @@ struct dirent *readdir(DIR *dir); This function retrieves the file descriptor of a directory stream that was previously opened with opendir(). + \warning Do not close() the returned file descriptor. It will be + closed when closedir() is called on the directory + stream. + \param dirp The directory stream to retrieve the descriptor of. + \return The file descriptor from the directory stream on success or -1 on failure (sets errno as appropriate). - - \note Do not close() the returned file descriptor. It will be - closed when closedir() is called on the directory - stream. */ int dirfd(DIR *dirp); @@ -125,21 +156,71 @@ int dirfd(DIR *dirp); This function rewinds the directory stream so that the next call to the readdir() function will return the first entry in the directory. - \param dir The directory stream to rewind. - - \note Some filesystems do not support this call. Notably, none + \warning Some filesystems do not support this call. Notably, none of the dcload filesystems support it. Error values will be returned in errno (so set errno to 0, then check after calling the function to see if there was a problem anywhere). + + \param dir The directory stream to rewind. */ void rewinddir(DIR *dir); -/** \brief Not implemented */ -int scandir(const char *dir, struct dirent ***namelist, +/** \brief Scan, filter, and sort files within a directory. + + This function scans through all files within the directory located at the + path given by \p dir, calling \p filter on each entry. Entries for which + \p filter returns nonzero are stored within \p namelist and are sorted + using qsort() with the comparison function, \p compar. The resulting + directory entries are accumulated and stored witin \p namelist. + + \note + \p filter and \p compar may be NULL, if you do not wish to filter or sort + the files. + + \warning + The entries within \p namelist are each independently heap-allocated, then + the list itself heap allocated, so each entry must be freed within the list + followed by the list itself. + + \param dir The path to the directory to scan + \param namelist A pointer through which the list of entries will be + returned. + \param filter The callback used to filter each directory entry + (returning 1 for inclusion, 0 for exclusion). + \param compar The callback passed to qsort() to sort \p namelist by + + \retval >=0 On success, the number of directory entries within \p + namelist is returned + \retval -1 On failure, -1 is returned and errno is set + + \sa alphasort +*/ +int scandir(const char *__RESTRICT dir, struct dirent ***__RESTRICT namelist, int(*filter)(const struct dirent *), int(*compar)(const struct dirent **, const struct dirent **)); + +/** \brief Comparison function for sorting directory entries alphabetically + + Sorts two directory entries, \p a and \p b in alphabetical order. + + \note + This function can be used as the comparison callback passed to scandir(), + to sort the returned list of entries in alphabetical order. + + \param a The first directory entry to sort + \param b The second directory entry to sort + + \retval Returns an integer value greater than, equal to, or less than + zero, depending on whether the name of the directory entry + pointed to by \p a is lexically greater than, equal to, or + less than the directory entry pointed to by \p b. + + \sa scandir() +*/ +int alphasort(const struct dirent **a, const struct dirent **b); + /** \brief Not implemented */ void seekdir(DIR *dir, off_t offset); diff --git a/kernel/arch/dreamcast/hardware/Makefile b/kernel/arch/dreamcast/hardware/Makefile index bd4627a5..460e6067 100644 --- a/kernel/arch/dreamcast/hardware/Makefile +++ b/kernel/arch/dreamcast/hardware/Makefile @@ -25,7 +25,7 @@ OBJS += asic.o g2bus.o OBJS += video.o vblank.o # CPU-related -OBJS += sq.o scif.o +OBJS += sq.o sq_fast_cpy.o scif.o # SPI device support OBJS += scif-spi.o sd.o diff --git a/kernel/arch/dreamcast/hardware/sq.c b/kernel/arch/dreamcast/hardware/sq.c index d8ebfe95..23d047cb 100644 --- a/kernel/arch/dreamcast/hardware/sq.c +++ b/kernel/arch/dreamcast/hardware/sq.c @@ -60,16 +60,15 @@ __attribute__((noinline)) void *sq_cpy(void *dest, const void *src, size_t n) { uint32_t *d = SQ_MASK_DEST(dest); const uint32_t *s = src; - _Complex float ds; - _Complex float ds2; - _Complex float ds3; - _Complex float ds4; - - sq_lock(dest); - /* Fill/write queues as many times necessary */ n >>= 5; + /* Exit early if we dont have enough data to copy */ + if(n == 0) + return dest; + + sq_lock(dest); + /* If src is not 8-byte aligned, slow path */ if ((uintptr_t)src & 7) { while(n--) { @@ -86,35 +85,7 @@ __attribute__((noinline)) void *sq_cpy(void *dest, const void *src, size_t n) { d += 8; } } else { /* If src is 8-byte aligned, fast path */ - /* Moop algorithm; Using the fpu we can fill the queue faster before - firing it out off */ - __asm__ __volatile__ ( - "fschg\n\t" - "clrs\n" - ".align 2\n" - "1:\n\t" - /* *d++ = *s++ */ - "fmov.d @%[in]+, %[scratch]\n\t" - "fmov.d @%[in]+, %[scratch2]\n\t" - "fmov.d @%[in]+, %[scratch3]\n\t" - "fmov.d @%[in]+, %[scratch4]\n\t" - "add #32, %[out]\n\t" - "pref @%[in]\n\t" /* Prefetch 32 bytes for next loop */ - "dt %[size]\n\t" /* while(n--) */ - "fmov.d %[scratch4], @-%[out]\n\t" - "fmov.d %[scratch3], @-%[out]\n\t" - "fmov.d %[scratch2], @-%[out]\n\t" - "fmov.d %[scratch], @-%[out]\n\t" - "pref @%[out]\n\t" /* Fire off store queue */ - "bf.s 1b\n\t" - "add #32, %[out]\n\t" - "fschg\n" - : [in] "+&r" ((uint32_t)s), [out] "+&r" ((uint32_t)d), - [size] "+&r" (n), [scratch] "=&d" (ds), [scratch2] "=&d" (ds2), - [scratch3] "=&d" (ds3), [scratch4] "=&d" (ds4) /* outputs */ - : /* inputs */ - : "t", "memory" /* clobbers */ - ); + sq_fast_cpy(d, s, n); } sq_unlock(); diff --git a/kernel/arch/dreamcast/hardware/sq_fast_cpy.s b/kernel/arch/dreamcast/hardware/sq_fast_cpy.s new file mode 100644 index 00000000..134ee374 --- /dev/null +++ b/kernel/arch/dreamcast/hardware/sq_fast_cpy.s @@ -0,0 +1,46 @@ +! KallistiOS ##version## +! +! arch/dreamcast/hardware/sq_fast_path.s +! Copyright (C) 2024 Andy Barajas +! +! Optimized SH4 assembler function for copying 32 bytes of data +! (8 bytes at a time) using pair single-precision data transfer +! specifically for store queues. +! + +.globl _sq_fast_cpy + +! +! void *sq_fast_cpy(uint32_t *dest, uint32_t *src, size_t n); +! +! r4: dest (should be 32-byte aligned store queue address) +! r5: src (should be 8-byte aligned address) +! r6: n (how many 32-byte blocks of data you want to copy) +! + .align 2 +_sq_fast_cpy: + fschg ! Change to pair single-precision data + tst r6, r6 + bt/s .exit ! Exit if size is 0 + mov r4, r0 +1: + fmov.d @r5+, dr0 + mov r4, r1 + fmov.d @r5+, dr2 + add #32, r1 + fmov.d @r5+, dr4 + fmov.d @r5+, dr6 + pref @r5 ! Prefetch 32 bytes for next loop + dt r6 ! while(n--) + fmov.d dr6, @-r1 + fmov.d dr4, @-r1 + fmov.d dr2, @-r1 + fmov.d dr0, @-r1 + add #32, r4 + bf.s 1b + pref @r1 ! Fire off store queue + +.exit: + rts + fschg + diff --git a/kernel/arch/dreamcast/include/dc/sq.h b/kernel/arch/dreamcast/include/dc/sq.h index a2f25880..89ff18bf 100644 --- a/kernel/arch/dreamcast/include/dc/sq.h +++ b/kernel/arch/dreamcast/include/dc/sq.h @@ -3,8 +3,8 @@ kernel/arch/dreamcast/include/dc/sq.h Copyright (C) 2000-2001 Andrew Kieschnick Copyright (C) 2023 Falco Girgis - Copyright (C) 2023 Andy Barajas Copyright (C) 2023 Ruslan Rostovtsev + Copyright (C) 2023-2024 Andy Barajas */ /** \file dc/sq.h @@ -128,9 +128,30 @@ void sq_wait(void); \param n The number of bytes to copy (multiple of 32). \return The original value of dest. - \sa sq_cpy_pvr() + \sa sq_fast_cpy() */ -void * sq_cpy(void *dest, const void *src, size_t n); +void *sq_cpy(void *dest, const void *src, size_t n); + +/** \brief Copy a block of memory. + \ingroup store_queues + + This function is similar to sq_cpy() but expects the user to lock/unlock + the store queues before and after as well as having different requirements + for the params. + + \warning + The dest pointer must be at least 32-byte aligned that already has been + masked by SQ_MASK_DEST(), the src pointer must be at least 8-byte aligned, + and n must be the number of 32-byte blocks you want to copy. + + \param dest The store queue address to copy to (32-byte aligned). + \param src The address to copy from (8-byte aligned). + \param n The number of 32-byte blocks to copy. + \return The original value of dest. + + \sa sq_cpy() + */ +void *sq_fast_cpy(void *dest, const void *src, size_t n); /** \brief Set a block of memory to an 8-bit value. \ingroup store_queues @@ -149,7 +170,7 @@ void * sq_cpy(void *dest, const void *src, size_t n); \sa sq_set16(), sq_set32(), sq_set_pvr() */ -void * sq_set(void *dest, uint32_t c, size_t n); +void *sq_set(void *dest, uint32_t c, size_t n); /** \brief Set a block of memory to a 16-bit value. \ingroup store_queues @@ -168,7 +189,7 @@ void * sq_set(void *dest, uint32_t c, size_t n); \sa sq_set(), sq_set32(), sq_set_pvr() */ -void * sq_set16(void *dest, uint32_t c, size_t n); +void *sq_set16(void *dest, uint32_t c, size_t n); /** \brief Set a block of memory to a 32-bit value. \ingroup store_queues @@ -186,7 +207,7 @@ void * sq_set16(void *dest, uint32_t c, size_t n); \sa sq_set(), sq_set16(), sq_set_pvr() */ -void * sq_set32(void *dest, uint32_t c, size_t n); +void *sq_set32(void *dest, uint32_t c, size_t n); /** \brief Clear a block of memory. ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |