From 67e074fbe6add1e930c22afa572f681dafbcd162 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 29 Apr 2026 21:47:24 -0700 Subject: [PATCH 1/5] qurt: fix type and definition inaccuracies against SDK headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compare Rust definitions against Hexagon SDK 6.4.0.2 computev69 POSIX headers and fix mismatches. Changes pthread_rwlock_t and pthread_rwlockattr_t to *mut c_void, sigval from struct to union, closedir param from *const to *mut DIR. Removes functions not provided by QuRT (fork, execve, kill, alarm, pause, sigprocmask, sigpending, creat). Adds sched_yield, SIGIOT, SIGPOLL; removes SIGVTALRM. Also adds test_qurt() ctest function (disabled — requires sched_yield stub), libc-test/semver/qurt.txt, and fixes the c_schar ambiguous glob re-export. --- libc-test/build.rs | 240 +++++++++++++++++++++- libc-test/semver/qurt.txt | 404 ++++++++++++++++++++++++++++++++++++++ src/new/mod.rs | 1 - src/new/qurt/fcntl.rs | 1 - src/new/qurt/limits.rs | 4 +- src/new/qurt/mod.rs | 114 +++++------ src/new/qurt/pthread.rs | 28 +-- src/new/qurt/signal.rs | 23 ++- src/new/qurt/sys/sched.rs | 3 + 9 files changed, 720 insertions(+), 98 deletions(-) create mode 100644 libc-test/semver/qurt.txt diff --git a/libc-test/build.rs b/libc-test/build.rs index 6879015d217fb..504bcc7ae109d 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -20,7 +20,7 @@ use std::{ fn do_cc() { let target = env::var("TARGET").unwrap(); if cfg!(unix) || target.contains("cygwin") { - let exclude = ["redox", "wasi", "wali"]; + let exclude = ["redox", "wasi", "wali", "qurt"]; if !exclude.iter().any(|x| target.contains(x)) { let mut cmsg = cc::Build::new(); @@ -76,6 +76,8 @@ fn do_ctest() { t if t.contains("windows") => test_windows(t), t if t.contains("vxworks") => test_vxworks(t), t if t.contains("nto-qnx") => test_neutrino(t), + // QuRT ctest requires a sched_yield stub (static inline in SDK). + t if t.contains("qurt") => return, t if t.contains("aix") => return test_aix(t), t => panic!("unknown target {t}"), } @@ -5641,6 +5643,242 @@ fn test_aix(target: &str) { ctest::generate_test(&mut cfg, "../src/lib.rs", "ctest_output.rs").unwrap(); } +// QuRT ctest is disabled: sched_yield is static inline in the SDK (no +// linkable symbol). A stub or --defsym is needed. The semver test works. +#[allow(dead_code)] +fn test_qurt(target: &str) { + assert!(target.contains("qurt")); + + let mut cfg = ctest_cfg(); + cfg.flag("-Wno-deprecated-declarations"); + + // QuRT POSIX headers are in the SDK, include paths are set via + // CFLAGS_hexagon_unknown_qurt in the test runner script. + headers!( + cfg, + "pthread.h", + "pthread_types.h", + "semaphore.h", + "signal.h", + "time.h", + "fcntl.h", + "sys/types.h", + "sys/sched.h", + "sys/errno.h", + "mqueue.h", + ); + + // QuRT doesn't have all the standard unix types/structs + cfg.skip_struct(|s| { + match s.ident() { + // These are compatibility stubs in libc, not from QuRT headers + "stat" | "tm" | "timespec" | "timeval" | "itimerspec" | "dirent" | "DIR" + | "termios" | "rlimit" | "rusage" | "flock" | "div_t" | "ldiv_t" | "lldiv_t" => true, + // sigaction: sa_handler/sa_sigaction are a union in C but separate fields in Rust + "sigaction" => true, + // sem_t is typedef of anonymous struct in C (no struct tag) + "sem_t" => true, + _ => false, + } + }); + + cfg.skip_alias(|ty| { + match ty.ident() { + // Skip types not defined in QuRT POSIX headers + "intptr_t" | "uintptr_t" | "ptrdiff_t" | "size_t" | "ssize_t" | "time_t" + | "suseconds_t" | "useconds_t" | "timer_t" | "dev_t" | "ino_t" | "mode_t" + | "nlink_t" | "off_t" | "blkcnt_t" | "blksize_t" | "uid_t" | "gid_t" | "socklen_t" + | "sa_family_t" | "in_addr_t" | "in_port_t" | "fpos_t" | "clock_t" | "nfds_t" + | "va_list" | "c_schar" | "wchar_t" | "errno_t" | "rlim_t" | "speed_t" | "tcflag_t" + | "sighandler_t" => true, + // fd_set is defined in mqueue.h as a struct, but libc has it as c_ulong + "fd_set" => true, + // sem_t is a struct in QuRT but an alias in libc + "sem_t" => true, + // Skip internal/compatibility types + "FILE" => true, + // These are libc internal types + t if t.starts_with("__c_anonymous_") => true, + t if t.starts_with("__uint") => true, + _ => false, + } + }); + + cfg.skip_const(|c| { + let name = c.ident(); + match name { + // Skip constants not from QuRT POSIX headers + "EOK" | "PAGESIZE" | "PAGE_SIZE" | "L_tmpnam" | "TMP_MAX" | "FOPEN_MAX" => true, + // Skip DT_* directory entry constants (not in QuRT POSIX headers) + _ if name.starts_with("DT_") => true, + // Skip CLOCK_* that aren't in the QuRT time.h directly + "CLOCK_MONOTONIC_RAW" + | "CLOCK_REALTIME_COARSE" + | "CLOCK_MONOTONIC_COARSE" + | "CLOCK_BOOTTIME" => true, + // Skip signal constants not defined in QuRT signal.h + _ if name.starts_with("SIG") + && !matches!( + name, + "SIGKILL" + | "SIGRTMIN" + | "SIGRTMAX" + | "SIGEV_NONE" + | "SIGEV_SIGNAL" + | "SIGEV_THREAD" + | "SIG_BLOCK" + | "SIG_UNBLOCK" + | "SIG_SETMASK" + ) => + { + true + } + "SA_SIGINFO" => false, + // Skip SIG_DFL, SIG_IGN, SIG_ERR (function pointers, not simple ints) + "SIG_DFL" | "SIG_IGN" | "SIG_ERR" => true, + // Skip POSIX_MSG/POSIX_NOTIF + "POSIX_MSG" | "POSIX_NOTIF" => true, + // Skip errno constants (they come from toolchain errno.h, not QuRT-specific) + _ if name.starts_with("E") + && name.len() > 1 + && name + .chars() + .all(|c| c.is_ascii_uppercase() || c.is_ascii_digit()) => + { + true + } + // Skip O_* constants that use POSIX_ prefix in QuRT + _ if name.starts_with("O_") => true, + // Skip F_* fcntl constants + _ if name.starts_with("F_") && !name.starts_with("FD_") => true, + "FD_CLOEXEC" => true, + // Skip limits constants not in QuRT headers + _ if name.starts_with("CHAR_") + || name.starts_with("SCHAR_") + || name.starts_with("UCHAR_") => + { + true + } + _ if name.starts_with("INT_") || name.starts_with("UINT_") => true, + _ if name.starts_with("LONG_") || name.starts_with("ULONG_") => true, + _ if name.starts_with("SHRT_") || name.starts_with("USHRT_") => true, + "CHAR_BIT" | "IOV_MAX" => true, + _ if name.starts_with("ARG_MAX") + || name.starts_with("CHILD_MAX") + || name.starts_with("LINK_MAX") + || name.starts_with("MAX_") + || name.starts_with("NAME_MAX") + || name.starts_with("OPEN_MAX") + || name.starts_with("PATH_MAX") + || name.starts_with("PIPE_BUF") + || name.starts_with("STREAM_MAX") + || name.starts_with("TZNAME_MAX") => + { + true + } + // Skip stdio constants + "BUFSIZ" | "FILENAME_MAX" | "EOF" => true, + // Skip stdlib constants + "EXIT_SUCCESS" | "EXIT_FAILURE" | "RAND_MAX" => true, + // Skip dlfcn constants + _ if name.starts_with("RTLD_") || name == "DL_LAZY" => true, + // Skip mman constants + _ if name.starts_with("PROT_") + || name.starts_with("MAP_") + || name.starts_with("MS_") + || name.starts_with("MCL_") => + { + true + } + // Skip stat constants + _ if name.starts_with("S_I") || name == "S_IFMT" => true, + // Skip unistd constants + _ if name.starts_with("_PC_") || name.starts_with("_SC_") => true, + "F_OK" | "X_OK" | "W_OK" | "R_OK" => true, + "SEEK_SET" | "SEEK_CUR" | "SEEK_END" => true, + "STDIN_FILENO" | "STDOUT_FILENO" | "STDERR_FILENO" => true, + // Skip TIME_CONV_SCLK_FREQ (QuRT-specific, not a standard C constant) + "TIME_CONV_SCLK_FREQ" => true, + // Skip SEM_FAILED (null pointer constant) + "SEM_FAILED" => true, + // Skip MAP_FAILED + "MAP_FAILED" => true, + _ => false, + } + }); + + cfg.skip_fn(|func| { + let name = func.ident(); + match name { + // Skip functions not from QuRT POSIX headers we're testing + "strlen" | "strcpy" | "strncpy" | "strcat" | "strncat" | "strcmp" | "strncmp" + | "strcoll" | "strxfrm" | "strchr" | "strrchr" | "strspn" | "strcspn" | "strpbrk" + | "strstr" | "strtok" | "strerror" | "memchr" | "memcmp" | "memcpy" | "memmove" + | "memset" => true, + // Skip ctype functions + "isalnum" | "isalpha" | "iscntrl" | "isdigit" | "isgraph" | "islower" | "isprint" + | "ispunct" | "isspace" | "isupper" | "isxdigit" | "tolower" | "toupper" => true, + // Skip stdio functions + "fopen" | "freopen" | "fclose" | "fflush" | "fread" | "fwrite" | "fgetc" | "fputc" + | "getchar" | "putchar" | "ungetc" | "fgets" | "fputs" | "gets" | "puts" | "printf" + | "fprintf" | "sprintf" | "snprintf" | "vprintf" | "vfprintf" | "vsprintf" + | "vsnprintf" | "scanf" | "fscanf" | "sscanf" | "fseek" | "ftell" | "rewind" + | "fgetpos" | "fsetpos" | "clearerr" | "feof" | "ferror" | "perror" | "remove" + | "rename" | "tmpfile" | "tmpnam" | "setvbuf" | "setbuf" => true, + // Skip stdlib functions + "malloc" | "calloc" | "realloc" | "free" | "abort" | "exit" | "atexit" | "getenv" + | "setenv" | "unsetenv" | "atoi" | "atol" | "atoll" | "strtol" | "strtoul" + | "strtoll" | "strtoull" | "strtod" | "strtof" | "rand" | "srand" | "qsort" + | "bsearch" | "abs" | "labs" | "llabs" | "div" | "ldiv" | "lldiv" => true, + // Skip unistd functions + "access" | "close" | "lseek" | "read" | "write" | "ftruncate" | "unlink" | "getcwd" + | "rmdir" | "getpid" | "sleep" | "sysconf" => true, + // Skip dlfcn functions + "dlopen" | "dlclose" | "dlsym" | "dlerror" => true, + // Skip mman functions + "mmap" | "munmap" | "mprotect" | "mlock" | "munlock" | "mlockall" | "munlockall" + | "msync" => true, + // Skip stat functions + "stat" | "fstat" => true, + // Skip time functions (some are in generic headers, not QuRT posix) + "time" | "clock" | "difftime" | "mktime" | "gmtime" | "gmtime_r" | "localtime" + | "localtime_r" | "asctime" | "asctime_r" | "ctime" | "ctime_r" | "strftime" + | "strptime" | "nanosleep" => true, + // Skip signal functions that use sigaction (it's a macro in QuRT) + "sigaction" => true, + // Skip signal functions from generic toolchain headers + "signal" | "raise" => true, + // Skip dir functions + "opendir" | "readdir" | "closedir" | "mkdir" => true, + // Skip aligned_alloc / posix_memalign + "aligned_alloc" | "posix_memalign" => true, + // Skip clock_getcpuclockid + "clock_getcpuclockid" => true, + // Skip sem_open/sem_close/sem_unlink + "sem_open" | "sem_close" | "sem_unlink" => true, + // Skip __errno_location (QuRT-specific) + "__errno_location" => true, + // Skip _sigaction (internal) + "_sigaction" => true, + // pthread_equal is a static inline in QuRT + "pthread_equal" => true, + // sigtimedwait is not in QuRT POSIX libraries + "sigtimedwait" => true, + _ => false, + } + }); + + // Skip field checks for opaque types + cfg.skip_struct_field(|s, f| { + // pthread_attr_t bitfield can't be checked directly + s.ident() == "pthread_attr_t" && f.ident() == "__bitfield" + }); + + cfg.skip_roundtrip(|_| true); + + ctest::generate_test(&mut cfg, "../src/lib.rs", "ctest_output.rs").unwrap(); +} + /// Attempt to execute a command and collect its output, If the command fails for whatever /// reason, return `None`. fn try_command_output(cmd: &str, args: &[&str]) -> Option { diff --git a/libc-test/semver/qurt.txt b/libc-test/semver/qurt.txt new file mode 100644 index 0000000000000..ed77dc99dde51 --- /dev/null +++ b/libc-test/semver/qurt.txt @@ -0,0 +1,404 @@ +ARG_MAX +BUFSIZ +CHAR_BIT +CHAR_MAX +CHAR_MIN +CHILD_MAX +CLOCK_BOOTTIME +CLOCK_MONOTONIC_COARSE +CLOCK_MONOTONIC_RAW +CLOCK_PROCESS_CPUTIME_ID +CLOCK_REALTIME_COARSE +CLOCK_THREAD_CPUTIME_ID +DL_LAZY +DT_UNKNOWN +EADV +EBADE +EBADFD +EBADR +EBADRQC +EBADSLT +EBFONT +ECHRNG +ECOMM +EDEADLOCK +EDOTDOT +EHWPOISON +EISNAM +EKEYEXPIRED +EKEYREJECTED +EKEYREVOKED +EL2HLT +EL2NSYNC +EL3HLT +EL3RST +ELIBACC +ELIBBAD +ELIBEXEC +ELIBMAX +ELIBSCN +ELNRNG +EMEDIUMTYPE +EMULTIHOP +ENAVAIL +ENOANO +ENOCSI +ENODATA +ENOKEY +ENOLINK +ENOMEDIUM +ENONET +ENOPKG +ENOSR +ENOSTR +ENOTBLK +ENOTNAM +ENOTRECOVERABLE +ENOTSUP +ENOTUNIQ +EOF +EOK +EOWNERDEAD +EREMCHG +EREMOTE +EREMOTEIO +ERESTART +ERFKILL +ESOCKTNOSUPPORT +ESRMNT +ESTRPIPE +ETIME +ETOOMANYREFS +EUCLEAN +EUNATCH +EUSERS +EXFULL +FILENAME_MAX +FOPEN_MAX +F_RDLCK +F_UNLCK +F_WRLCK +IOV_MAX +LINK_MAX +LONG_MAX +LONG_MIN +L_tmpnam +MAP_FILE +MAP_HASSEMAPHORE +MAP_INHERIT +MAP_NORESERVE +MAP_RENAME +MAP_TRYFIXED +MAP_WIRED +MAX_CANON +MAX_INPUT +MCL_CURRENT +MCL_FUTURE +NAME_MAX +NFDBITS +OPEN_MAX +O_DSYNC +O_FSYNC +O_NOCTTY +O_SYNC +PAGESIZE +PAGE_SIZE +PIPE_BUF +POSIX_MSG +POSIX_NOTIF +PTHREAD_CREATE_DETACHED +PTHREAD_CREATE_JOINABLE +PTHREAD_DEFAULT_PRIORITY +PTHREAD_DEFAULT_STACKSIZE +PTHREAD_EXPLICIT_SCHED +PTHREAD_INHERIT_SCHED +PTHREAD_MAX_PRIORITY +PTHREAD_MAX_STACKSIZE +PTHREAD_MAX_THREADS +PTHREAD_MIN_PRIORITY +PTHREAD_MIN_STACKSIZE +PTHREAD_MUTEX_DEFAULT +PTHREAD_MUTEX_ERRORCHECK +PTHREAD_NAME_LEN +PTHREAD_ONCE_INIT +PTHREAD_PRIO_INHERIT +PTHREAD_PRIO_NONE +PTHREAD_PRIO_PROTECT +PTHREAD_PROCESS_PRIVATE +PTHREAD_PROCESS_SHARED +PTHREAD_SCOPE_PROCESS +PTHREAD_SCOPE_SYSTEM +PTHREAD_SPINLOCK_LOCKED +PTHREAD_SPINLOCK_UNLOCKED +PTHREAD_STACK_MIN +RAND_MAX +RTLD_NEXT +RTLD_SELF +SCHAR_MAX +SCHAR_MIN +SCHED_FIFO +SCHED_OTHER +SCHED_RR +SCHED_SPORADIC +SEM_FAILED +SHRT_MAX +SHRT_MIN +SIGEV_NONE +SIGEV_SIGNAL +SIGEV_THREAD +SIGIO +SIGPOLL +SIGPWR +SIGRTMAX +SIGRTMIN +SIGSTKFLT +STREAM_MAX +TIME_CONV_SCLK_FREQ +TMP_MAX +TZNAME_MAX +UCHAR_MAX +UINT_MAX +ULONG_MAX +USHRT_MAX +_PC_2_SYMLINKS +_PC_ALLOC_SIZE_MIN +_PC_ASYNC_IO +_PC_FILESIZEBITS +_PC_PRIO_IO +_PC_REC_INCR_XFER_SIZE +_PC_REC_MAX_XFER_SIZE +_PC_REC_MIN_XFER_SIZE +_PC_REC_XFER_ALIGN +_PC_SOCK_MAXBUF +_PC_SYMLINK_MAX +_PC_SYNC_IO +_SC_2_CHAR_TERM +_SC_2_C_BIND +_SC_2_C_DEV +_SC_2_C_VERSION +_SC_2_FORT_DEV +_SC_2_FORT_RUN +_SC_2_LOCALEDEF +_SC_2_PBS +_SC_2_PBS_ACCOUNTING +_SC_2_PBS_CHECKPOINT +_SC_2_PBS_LOCATE +_SC_2_PBS_MESSAGE +_SC_2_PBS_TRACK +_SC_2_SW_DEV +_SC_2_UPE +_SC_2_VERSION +_SC_ADVISORY_INFO +_SC_AIO_LISTIO_MAX +_SC_AIO_MAX +_SC_AIO_PRIO_DELTA_MAX +_SC_ASYNCHRONOUS_IO +_SC_ATEXIT_MAX +_SC_AVPHYS_PAGES +_SC_BARRIERS +_SC_BC_BASE_MAX +_SC_BC_DIM_MAX +_SC_BC_SCALE_MAX +_SC_BC_STRING_MAX +_SC_CHARCLASS_NAME_MAX +_SC_CHAR_BIT +_SC_CHAR_MAX +_SC_CHAR_MIN +_SC_CLOCK_SELECTION +_SC_COLL_WEIGHTS_MAX +_SC_CPUTIME +_SC_DELAYTIMER_MAX +_SC_EQUIV_CLASS_MAX +_SC_EXPR_NEST_MAX +_SC_FSYNC +_SC_GETGR_R_SIZE_MAX +_SC_GETPW_R_SIZE_MAX +_SC_INT_MAX +_SC_INT_MIN +_SC_IOV_MAX +_SC_IPV6 +_SC_JOB_CONTROL +_SC_LINE_MAX +_SC_LOGIN_NAME_MAX +_SC_LONG_BIT +_SC_MAPPED_FILES +_SC_MB_LEN_MAX +_SC_MEMLOCK +_SC_MEMLOCK_RANGE +_SC_MEMORY_PROTECTION +_SC_MESSAGE_PASSING +_SC_MONOTONIC_CLOCK +_SC_MQ_OPEN_MAX +_SC_MQ_PRIO_MAX +_SC_NL_ARGMAX +_SC_NL_LANGMAX +_SC_NL_MSGMAX +_SC_NL_NMAX +_SC_NL_SETMAX +_SC_NL_TEXTMAX +_SC_NPROCESSORS_CONF +_SC_NPROCESSORS_ONLN +_SC_NZERO +_SC_PASS_MAX +_SC_PHYS_PAGES +_SC_PII +_SC_PII_INTERNET +_SC_PII_INTERNET_DGRAM +_SC_PII_INTERNET_STREAM +_SC_PII_OSI +_SC_PII_OSI_CLTS +_SC_PII_OSI_COTS +_SC_PII_OSI_M +_SC_PII_SOCKET +_SC_PII_XTI +_SC_POLL +_SC_PRIORITIZED_IO +_SC_PRIORITY_SCHEDULING +_SC_RAW_SOCKETS +_SC_READER_WRITER_LOCKS +_SC_REALTIME_SIGNALS +_SC_REGEXP +_SC_RE_DUP_MAX +_SC_RTSIG_MAX +_SC_SAVED_IDS +_SC_SCHAR_MAX +_SC_SCHAR_MIN +_SC_SELECT +_SC_SEMAPHORES +_SC_SEM_NSEMS_MAX +_SC_SEM_VALUE_MAX +_SC_SHARED_MEMORY_OBJECTS +_SC_SHELL +_SC_SHRT_MAX +_SC_SHRT_MIN +_SC_SIGQUEUE_MAX +_SC_SPAWN +_SC_SPIN_LOCKS +_SC_SPORADIC_SERVER +_SC_SSIZE_MAX +_SC_SS_REPL_MAX +_SC_SYNCHRONIZED_IO +_SC_THREADS +_SC_THREAD_ATTR_STACKADDR +_SC_THREAD_ATTR_STACKSIZE +_SC_THREAD_CPUTIME +_SC_THREAD_DESTRUCTOR_ITERATIONS +_SC_THREAD_KEYS_MAX +_SC_THREAD_PRIORITY_SCHEDULING +_SC_THREAD_PRIO_INHERIT +_SC_THREAD_PRIO_PROTECT +_SC_THREAD_PROCESS_SHARED +_SC_THREAD_ROBUST_PRIO_INHERIT +_SC_THREAD_ROBUST_PRIO_PROTECT +_SC_THREAD_SAFE_FUNCTIONS +_SC_THREAD_SPORADIC_SERVER +_SC_THREAD_STACK_MIN +_SC_THREAD_THREADS_MAX +_SC_TIMEOUTS +_SC_TIMERS +_SC_TIMER_MAX +_SC_TRACE +_SC_TRACE_EVENT_FILTER +_SC_TRACE_EVENT_NAME_MAX +_SC_TRACE_INHERIT +_SC_TRACE_LOG +_SC_TRACE_NAME_MAX +_SC_TRACE_SYS_MAX +_SC_TRACE_USER_EVENT_MAX +_SC_TYPED_MEMORY_OBJECTS +_SC_T_IOV_MAX +_SC_UCHAR_MAX +_SC_UINT_MAX +_SC_UIO_MAXIOV +_SC_ULONG_MAX +_SC_USHRT_MAX +_SC_V6_ILP32_OFF32 +_SC_V6_ILP32_OFFBIG +_SC_V6_LP64_OFF64 +_SC_V6_LPBIG_OFFBIG +_SC_V7_ILP32_OFF32 +_SC_V7_ILP32_OFFBIG +_SC_V7_LP64_OFF64 +_SC_V7_LPBIG_OFFBIG +_SC_WORD_BIT +_SC_XBS5_ILP32_OFF32 +_SC_XBS5_ILP32_OFFBIG +_SC_XBS5_LP64_OFF64 +_SC_XBS5_LPBIG_OFFBIG +_SC_XOPEN_CRYPT +_SC_XOPEN_ENH_I18N +_SC_XOPEN_LEGACY +_SC_XOPEN_REALTIME +_SC_XOPEN_REALTIME_THREADS +_SC_XOPEN_SHM +_SC_XOPEN_STREAMS +_SC_XOPEN_UNIX +_SC_XOPEN_VERSION +_SC_XOPEN_XCU_VERSION +_SC_XOPEN_XPG2 +_SC_XOPEN_XPG3 +_SC_XOPEN_XPG4 +__errno_location +_sigaction +abs +asctime +asctime_r +bsearch +clearerr +clock +clock_getcpuclockid +cpu_set_t +ctime +ctime_r +difftime +div +div_t +errno_t +gets +itimerspec +labs +ldiv +ldiv_t +llabs +lldiv +lldiv_t +mqd_t +pthread_attr_getaffinity_np +pthread_attr_getdetachstate +pthread_attr_getstack +pthread_attr_setaffinity_np +pthread_attr_setstack +pthread_barrier_t +pthread_barrierattr_t +pthread_condattr_setclock +pthread_getname_np +pthread_mutexattr_gettype +pthread_once +pthread_once_t +pthread_spinlock_t +qsort +rand +sched_get_priority_max +sched_get_priority_min +sched_param +sem_close +sem_destroy +sem_getvalue +sem_init +sem_open +sem_unlink +sigevent +siginfo_t +sigsuspend +sigtimedwait +sigwait +srand +strftime +strptime +timer_t +useconds_t +va_list +vfprintf +vprintf +vsnprintf +vsprintf diff --git a/src/new/mod.rs b/src/new/mod.rs index 1c5d6a6e17c25..63686ca3a2566 100644 --- a/src/new/mod.rs +++ b/src/new/mod.rs @@ -104,7 +104,6 @@ cfg_if! { pub(crate) use openbsd::*; } else if #[cfg(target_os = "qurt")] { pub mod qurt; - pub use qurt::*; } else if #[cfg(target_os = "redox")] { mod redox; // pub(crate) use redox::*; diff --git a/src/new/qurt/fcntl.rs b/src/new/qurt/fcntl.rs index 0287292ad2f8e..615a7128cc507 100644 --- a/src/new/qurt/fcntl.rs +++ b/src/new/qurt/fcntl.rs @@ -47,6 +47,5 @@ pub const F_UNLCK: c_int = 2; // Functions extern "C" { pub fn open(pathname: *const c_char, flags: c_int, ...) -> c_int; - pub fn creat(pathname: *const c_char, mode: mode_t) -> c_int; pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int; } diff --git a/src/new/qurt/limits.rs b/src/new/qurt/limits.rs index ae1a007ff1c66..fefe069c1c19f 100644 --- a/src/new/qurt/limits.rs +++ b/src/new/qurt/limits.rs @@ -7,8 +7,8 @@ use crate::prelude::*; pub const CHAR_BIT: c_uint = 8; pub const CHAR_MAX: c_char = 255; // unsigned char on Hexagon pub const CHAR_MIN: c_char = 0; -pub const SCHAR_MAX: c_schar = 127; -pub const SCHAR_MIN: c_schar = -128; +pub const SCHAR_MAX: i8 = 127; +pub const SCHAR_MIN: i8 = -128; pub const UCHAR_MAX: c_uchar = 255; // Integer properties diff --git a/src/new/qurt/mod.rs b/src/new/qurt/mod.rs index 52d7ae04881e1..03665cb20dc3c 100644 --- a/src/new/qurt/mod.rs +++ b/src/new/qurt/mod.rs @@ -39,15 +39,18 @@ pub type pthread_t = c_uint; pub type pthread_key_t = c_int; pub type pthread_once_t = c_int; pub type pthread_mutex_t = c_uint; -pub type pthread_mutexattr_t = c_uint; +// QuRT pthread_mutexattr_t is a struct with 4 ints (is_initialized, type, pshared, protocol) +pub type pthread_mutexattr_t = [c_uint; 4]; pub type pthread_cond_t = c_uint; -pub type pthread_condattr_t = c_uint; -pub type pthread_attr_t = c_uint; -pub type pthread_rwlock_t = c_uint; -pub type pthread_rwlockattr_t = c_uint; +// QuRT pthread_condattr_t is a struct with 3 ints (is_initialized, pshared, clock_id) +pub type pthread_condattr_t = [c_uint; 3]; +// pthread_attr_t is defined as a struct in the s! block below +pub type pthread_rwlock_t = *mut c_void; +pub type pthread_rwlockattr_t = *mut c_void; pub type pthread_spinlock_t = c_uint; pub type pthread_barrier_t = c_uint; -pub type pthread_barrierattr_t = c_uint; +// QuRT pthread_barrierattr_t is a struct with 2 ints (is_initialized, pshared) +pub type pthread_barrierattr_t = [c_uint; 2]; // Network types pub type socklen_t = c_uint; @@ -55,8 +58,8 @@ pub type sa_family_t = c_ushort; pub type in_addr_t = c_uint; pub type in_port_t = c_ushort; -// File descriptor types -pub type fd_set = c_ulong; +// File descriptor types - QuRT defines fd_set as a struct in mqueue.h +// FD_SETSIZE = 256, NFDBITS = 32, so fds_bits has 8 elements // Standard C library types extern_ty! { @@ -65,8 +68,7 @@ extern_ty! { pub type fpos_t = c_long; pub type clock_t = c_long; -// POSIX semaphore types -pub type sem_t = c_uint; +// POSIX semaphore types - QuRT sem_t is a struct with an opaque pointer // Message queue types pub type mqd_t = c_int; @@ -80,22 +82,12 @@ pub type sigset_t = c_ulong; // Variadic argument list type pub type va_list = *mut c_char; -// Additional missing types -pub type c_schar = i8; - -// Wide character type (hexagon-specific) -pub type wchar_t = u32; +// Wide character type (hexagon uses signed wchar_t) +pub type wchar_t = i32; // Error type (compatible with std expectations) pub type errno_t = c_int; -// Resource limit type (for compatibility, not fully supported on QuRT) -pub type rlim_t = c_ulong; - -// Terminal types (for compatibility, not fully supported on QuRT) -pub type speed_t = c_uint; -pub type tcflag_t = c_uint; - // Division result types and structures s! { pub struct div_t { @@ -164,43 +156,7 @@ s! { pub entry: dirent, } - // Terminal I/O structure (for compatibility, limited support on QuRT) - pub struct termios { - pub c_iflag: tcflag_t, - pub c_oflag: tcflag_t, - pub c_cflag: tcflag_t, - pub c_lflag: tcflag_t, - pub c_cc: [c_uchar; 32], - pub c_ispeed: speed_t, - pub c_ospeed: speed_t, - } - - // Resource limit structures (for compatibility, limited support on QuRT) - pub struct rlimit { - pub rlim_cur: rlim_t, - pub rlim_max: rlim_t, - } - - pub struct rusage { - pub ru_utime: timeval, - pub ru_stime: timeval, - pub ru_maxrss: c_long, - pub ru_ixrss: c_long, - pub ru_idrss: c_long, - pub ru_isrss: c_long, - pub ru_minflt: c_long, - pub ru_majflt: c_long, - pub ru_nswap: c_long, - pub ru_inblock: c_long, - pub ru_oublock: c_long, - pub ru_msgsnd: c_long, - pub ru_msgrcv: c_long, - pub ru_nsignals: c_long, - pub ru_nvcsw: c_long, - pub ru_nivcsw: c_long, - } - - // File lock structure (for compatibility) + // File lock structure (from toolchain generic fcntl.h) pub struct flock { pub l_type: c_short, pub l_whence: c_short, @@ -208,6 +164,30 @@ s! { pub l_len: off_t, pub l_pid: pid_t, } + + // QuRT fd_set from mqueue.h: FD_SETSIZE=256, NFDBITS=32 (sizeof(fd_mask)*8) + pub struct fd_set { + pub fds_bits: [c_ulong; 8], + } + + // QuRT sem_t from semaphore.h: struct with opaque pointer + pub struct sem_t { + pub opaque: *mut c_uint, + } + + // QuRT pthread_attr_t - matches pthread_types.h struct layout + pub struct pthread_attr_t { + pub stackaddr: *mut c_void, + pub internal_stack: c_int, + pub stacksize: size_t, + pub priority: c_int, + pub timetest_id: c_ushort, + __bitfield: c_ushort, + pub cpumask: cpu_set_t, + pub name: [c_char; 16], + pub ext_context: c_int, + pub detachstate: c_int, + } } // Additional pthread constants @@ -238,6 +218,10 @@ pub const EOK: c_int = 0; // Semaphore constants pub const SEM_FAILED: *mut sem_t = 0 as *mut sem_t; +// fd_set constants from mqueue.h +pub const FD_SETSIZE: c_uint = 256; +pub const NFDBITS: c_uint = 32; + // Page size constants (hexagon-specific) pub const PAGESIZE: size_t = 4096; pub const PAGE_SIZE: size_t = 4096; @@ -256,7 +240,7 @@ pub const DT_SOCK: c_uchar = 12; extern "C" { pub fn opendir(name: *const c_char) -> *mut DIR; pub fn readdir(dirp: *mut DIR) -> *mut dirent; - pub fn closedir(dirp: *const DIR) -> c_int; + pub fn closedir(dirp: *mut DIR) -> c_int; pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int; } @@ -317,16 +301,6 @@ extern "C" { pub fn memset(s: *mut c_void, c: c_int, n: size_t) -> *mut c_void; } -// Additional unistd functions -extern "C" { - pub fn fork() -> pid_t; - pub fn execve( - filename: *const c_char, - argv: *const *const c_char, - envp: *const *const c_char, - ) -> c_int; -} - // Character classification functions (ctype.h) extern "C" { pub fn isalnum(c: c_int) -> c_int; diff --git a/src/new/qurt/pthread.rs b/src/new/qurt/pthread.rs index 543f7874c3dc6..d068eaf2f56e2 100644 --- a/src/new/qurt/pthread.rs +++ b/src/new/qurt/pthread.rs @@ -5,15 +5,19 @@ use super::*; use crate::prelude::*; -// Thread creation attributes -pub const PTHREAD_CREATE_JOINABLE: c_int = 0; -pub const PTHREAD_CREATE_DETACHED: c_int = 1; +// Thread creation attributes (QuRT values differ from POSIX/Linux defaults) +pub const PTHREAD_CREATE_DETACHED: c_int = 0; +pub const PTHREAD_CREATE_JOINABLE: c_int = 1; -// Mutex types -pub const PTHREAD_MUTEX_NORMAL: c_int = 0; -pub const PTHREAD_MUTEX_RECURSIVE: c_int = 1; -pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 2; -pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL; +// Mutex types (QuRT values differ from POSIX/Linux defaults) +pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 0; +pub const PTHREAD_MUTEX_NORMAL: c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: c_int = 3; + +// Process sharing +pub const PTHREAD_PROCESS_PRIVATE: c_int = 0; +pub const PTHREAD_PROCESS_SHARED: c_int = 1; // Mutex protocol pub const PTHREAD_PRIO_NONE: c_int = 0; @@ -27,6 +31,7 @@ pub const PTHREAD_MAX_PRIORITY: c_int = 255; // Initializer constants pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0xFFFFFFFF; pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0xFFFFFFFF; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = !0usize as pthread_rwlock_t; pub const PTHREAD_ONCE_INIT: pthread_once_t = 0; // Stack size @@ -36,8 +41,9 @@ pub const PTHREAD_STACK_MIN: size_t = 8192; pub const PTHREAD_SCOPE_SYSTEM: c_int = 0; pub const PTHREAD_SCOPE_PROCESS: c_int = 1; -pub const PTHREAD_INHERIT_SCHED: c_int = 0; -pub const PTHREAD_EXPLICIT_SCHED: c_int = 1; +// Scheduler inheritance (QuRT values differ from POSIX/Linux defaults) +pub const PTHREAD_EXPLICIT_SCHED: c_int = 0; +pub const PTHREAD_INHERIT_SCHED: c_int = 1; extern "C" { // Thread management @@ -51,7 +57,7 @@ extern "C" { pub fn pthread_detach(thread: pthread_t) -> c_int; pub fn pthread_exit(retval: *mut c_void) -> !; pub fn pthread_self() -> pthread_t; - pub fn pthread_equal(t1: pthread_t, t2: pthread_t) -> c_int; + // Note: pthread_equal is static inline in QuRT pthread.h, no linkable symbol // Thread attributes pub fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; diff --git a/src/new/qurt/signal.rs b/src/new/qurt/signal.rs index f525fa15ff29e..e5a219af5881b 100644 --- a/src/new/qurt/signal.rs +++ b/src/new/qurt/signal.rs @@ -3,13 +3,14 @@ use super::*; use crate::prelude::*; -// Standard signal numbers +// Signal numbers from toolchain signal.h (non-_LINUX_C_LIB_H_ path) pub const SIGHUP: c_int = 1; pub const SIGINT: c_int = 2; pub const SIGQUIT: c_int = 3; pub const SIGILL: c_int = 4; pub const SIGTRAP: c_int = 5; pub const SIGABRT: c_int = 6; +pub const SIGIOT: c_int = 6; pub const SIGBUS: c_int = 7; pub const SIGFPE: c_int = 8; pub const SIGKILL: c_int = 9; @@ -29,9 +30,9 @@ pub const SIGTTOU: c_int = 22; pub const SIGURG: c_int = 23; pub const SIGXCPU: c_int = 24; pub const SIGXFSZ: c_int = 25; -pub const SIGVTALRM: c_int = 26; pub const SIGPROF: c_int = 27; pub const SIGWINCH: c_int = 28; +pub const SIGPOLL: c_int = 29; pub const SIGIO: c_int = 29; pub const SIGPWR: c_int = 30; pub const SIGSYS: c_int = 31; @@ -61,12 +62,16 @@ pub const SA_SIGINFO: c_int = 1; pub type sighandler_t = size_t; // Signal structures based on QuRT SDK headers -s! { - pub struct sigval { + +// sigval is a union in C (4 bytes on 32-bit hexagon) +s_no_extra_traits! { + pub union sigval { pub sival_int: c_int, pub sival_ptr: *mut c_void, } +} +s! { pub struct sigevent { pub sigev_notify: c_int, pub sigev_signo: c_int, @@ -90,23 +95,17 @@ s! { } extern "C" { + // From generic signal.h (toolchain) pub fn signal(sig: c_int, handler: sighandler_t) -> sighandler_t; - pub fn kill(pid: pid_t, sig: c_int) -> c_int; pub fn raise(sig: c_int) -> c_int; - pub fn alarm(seconds: c_uint) -> c_uint; - pub fn pause() -> c_int; - // Signal mask functions + // QuRT POSIX signal functions pub fn sigemptyset(set: *mut sigset_t) -> c_int; pub fn sigfillset(set: *mut sigset_t) -> c_int; pub fn sigaddset(set: *mut sigset_t, signum: c_int) -> c_int; pub fn sigdelset(set: *mut sigset_t, signum: c_int) -> c_int; pub fn sigismember(set: *const sigset_t, signum: c_int) -> c_int; - pub fn sigprocmask(how: c_int, set: *const sigset_t, oldset: *mut sigset_t) -> c_int; - pub fn sigpending(set: *mut sigset_t) -> c_int; pub fn sigsuspend(mask: *const sigset_t) -> c_int; - - // QuRT-specific signal functions pub fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int; pub fn _sigaction(sig: c_int, act: *const sigaction, oact: *mut sigaction) -> c_int; pub fn sigtimedwait( diff --git a/src/new/qurt/sys/sched.rs b/src/new/qurt/sys/sched.rs index 56fed5ba00890..d56a4bc65e64f 100644 --- a/src/new/qurt/sys/sched.rs +++ b/src/new/qurt/sys/sched.rs @@ -18,6 +18,9 @@ s! { } extern "C" { + // Note: sched_yield is static inline in QuRT sys/sched.h, so there is no + // linkable symbol in the SDK libraries. Programs must provide their own + // implementation or use --defsym=sched_yield=abort at link time. pub fn sched_yield() -> c_int; pub fn sched_get_priority_max(policy: c_int) -> c_int; pub fn sched_get_priority_min(policy: c_int) -> c_int; From c7b6b7be8da9ea5e95eaaf4568143a17b23677fa Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 29 Apr 2026 21:47:32 -0700 Subject: [PATCH 2/5] qurt: add missing pthread functions from QuRT SDK headers Add all pthread functions declared in the QuRT SDK pthread.h and pthread_types.h: thread cancellation, scheduling, spinlocks, barriers, rwlocks, and various attribute get/set functions. Moves pthread_attr_{get,set}stack from mod.rs to pthread.rs. --- libc-test/semver/qurt.txt | 48 ++++++++++++ src/new/qurt/mod.rs | 14 ---- src/new/qurt/pthread.rs | 150 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 193 insertions(+), 19 deletions(-) diff --git a/libc-test/semver/qurt.txt b/libc-test/semver/qurt.txt index ed77dc99dde51..4f263cd0142ca 100644 --- a/libc-test/semver/qurt.txt +++ b/libc-test/semver/qurt.txt @@ -365,16 +365,64 @@ lldiv_t mqd_t pthread_attr_getaffinity_np pthread_attr_getdetachstate +pthread_attr_getguardsize +pthread_attr_getinheritsched +pthread_attr_getschedparam +pthread_attr_getscope pthread_attr_getstack +pthread_attr_getstackaddr +pthread_attr_getthreadname +pthread_attr_gettimetestid pthread_attr_setaffinity_np +pthread_attr_setautostack +pthread_attr_setbuspriority +pthread_attr_setinheritsched +pthread_attr_setschedparam +pthread_attr_setscope pthread_attr_setstack +pthread_attr_setstackaddr +pthread_attr_setthreadname +pthread_attr_settimetestid +pthread_barrier_destroy +pthread_barrier_init pthread_barrier_t +pthread_barrier_wait +pthread_barrierattr_destroy +pthread_barrierattr_getpshared +pthread_barrierattr_init +pthread_barrierattr_setpshared pthread_barrierattr_t +pthread_cancel +pthread_condattr_getclock +pthread_condattr_getpshared pthread_condattr_setclock +pthread_condattr_setpshared +pthread_getattr_np pthread_getname_np +pthread_getschedparam +pthread_kill +pthread_mutex_getprioceiling +pthread_mutex_setprioceiling +pthread_mutexattr_getprioceiling +pthread_mutexattr_getprotocol +pthread_mutexattr_getpshared pthread_mutexattr_gettype +pthread_mutexattr_setprioceiling +pthread_mutexattr_setprotocol +pthread_mutexattr_setpshared pthread_once pthread_once_t +pthread_rwlockattr_getpshared +pthread_rwlockattr_setpshared +pthread_setcancelstate +pthread_setcanceltype +pthread_setschedparam +pthread_setschedprio +pthread_spin_destroy +pthread_spin_init +pthread_spin_lock +pthread_spin_trylock +pthread_spin_unlock pthread_spinlock_t qsort rand diff --git a/src/new/qurt/mod.rs b/src/new/qurt/mod.rs index 03665cb20dc3c..872a6d15e6411 100644 --- a/src/new/qurt/mod.rs +++ b/src/new/qurt/mod.rs @@ -244,20 +244,6 @@ extern "C" { pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int; } -// Additional pthread functions -extern "C" { - pub fn pthread_attr_getstack( - attr: *const pthread_attr_t, - stackaddr: *mut *mut c_void, - stacksize: *mut size_t, - ) -> c_int; - pub fn pthread_attr_setstack( - attr: *mut pthread_attr_t, - stackaddr: *mut c_void, - stacksize: size_t, - ) -> c_int; -} - // Additional time functions extern "C" { pub fn clock_getcpuclockid(pid: pid_t, clock_id: *mut clockid_t) -> c_int; diff --git a/src/new/qurt/pthread.rs b/src/new/qurt/pthread.rs index d068eaf2f56e2..80ae47f495ea8 100644 --- a/src/new/qurt/pthread.rs +++ b/src/new/qurt/pthread.rs @@ -37,7 +37,7 @@ pub const PTHREAD_ONCE_INIT: pthread_once_t = 0; // Stack size pub const PTHREAD_STACK_MIN: size_t = 8192; -// Additional pthread types and attributes +// Contention scope pub const PTHREAD_SCOPE_SYSTEM: c_int = 0; pub const PTHREAD_SCOPE_PROCESS: c_int = 1; @@ -58,17 +58,65 @@ extern "C" { pub fn pthread_exit(retval: *mut c_void) -> !; pub fn pthread_self() -> pthread_t; // Note: pthread_equal is static inline in QuRT pthread.h, no linkable symbol + pub fn pthread_cancel(thread: pthread_t) -> c_int; + pub fn pthread_kill(thread: pthread_t, sig: c_int) -> c_int; + pub fn pthread_setcancelstate(state: c_int, oldstate: *mut c_int) -> c_int; + pub fn pthread_setcanceltype(r#type: c_int, oldtype: *mut c_int) -> c_int; + + // Thread scheduling + pub fn pthread_getschedparam( + thread: pthread_t, + policy: *mut c_int, + param: *mut sched_param, + ) -> c_int; + pub fn pthread_setschedparam( + thread: pthread_t, + policy: c_int, + param: *const sched_param, + ) -> c_int; + pub fn pthread_setschedprio(thread: pthread_t, prio: c_int) -> c_int; // Thread attributes pub fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> c_int; pub fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, stacksize: size_t) -> c_int; pub fn pthread_attr_getstacksize(attr: *const pthread_attr_t, stacksize: *mut size_t) -> c_int; + pub fn pthread_attr_setstackaddr(attr: *mut pthread_attr_t, stackaddr: *mut c_void) -> c_int; + pub fn pthread_attr_getstackaddr( + attr: *const pthread_attr_t, + stackaddr: *mut *mut c_void, + ) -> c_int; + pub fn pthread_attr_setstack( + attr: *mut pthread_attr_t, + stackaddr: *mut c_void, + stacksize: size_t, + ) -> c_int; + pub fn pthread_attr_getstack( + attr: *const pthread_attr_t, + stackaddr: *mut *mut c_void, + stacksize: *mut size_t, + ) -> c_int; pub fn pthread_attr_setdetachstate(attr: *mut pthread_attr_t, detachstate: c_int) -> c_int; pub fn pthread_attr_getdetachstate( attr: *const pthread_attr_t, detachstate: *mut c_int, ) -> c_int; + pub fn pthread_attr_setscope(attr: *mut pthread_attr_t, scope: c_int) -> c_int; + pub fn pthread_attr_getscope(attr: *const pthread_attr_t, scope: *mut c_int) -> c_int; + pub fn pthread_attr_setinheritsched(attr: *mut pthread_attr_t, inheritsched: c_int) -> c_int; + pub fn pthread_attr_getinheritsched( + attr: *const pthread_attr_t, + inheritsched: *mut c_int, + ) -> c_int; + pub fn pthread_attr_setschedparam( + attr: *mut pthread_attr_t, + param: *const sched_param, + ) -> c_int; + pub fn pthread_attr_getschedparam( + attr: *const pthread_attr_t, + param: *mut sched_param, + ) -> c_int; + pub fn pthread_attr_getguardsize(attr: *const pthread_attr_t, guardsize: *mut size_t) -> c_int; // Mutex operations pub fn pthread_mutex_init( @@ -79,12 +127,39 @@ extern "C" { pub fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int; pub fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int; pub fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int; + pub fn pthread_mutex_getprioceiling( + mutex: *const pthread_mutex_t, + prioceiling: *mut c_int, + ) -> c_int; + pub fn pthread_mutex_setprioceiling( + mutex: *mut pthread_mutex_t, + prioceiling: c_int, + old_ceiling: *mut c_int, + ) -> c_int; // Mutex attributes pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int; pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> c_int; pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, kind: c_int) -> c_int; pub fn pthread_mutexattr_gettype(attr: *const pthread_mutexattr_t, kind: *mut c_int) -> c_int; + pub fn pthread_mutexattr_setprotocol(attr: *mut pthread_mutexattr_t, protocol: c_int) -> c_int; + pub fn pthread_mutexattr_getprotocol( + attr: *const pthread_mutexattr_t, + protocol: *mut c_int, + ) -> c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, pshared: c_int) -> c_int; + pub fn pthread_mutexattr_getpshared( + attr: *const pthread_mutexattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_mutexattr_setprioceiling( + attr: *mut pthread_mutexattr_t, + prioceiling: c_int, + ) -> c_int; + pub fn pthread_mutexattr_getprioceiling( + attr: *const pthread_mutexattr_t, + prioceiling: *mut c_int, + ) -> c_int; // Condition variables pub fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *const pthread_condattr_t) -> c_int; @@ -102,6 +177,60 @@ extern "C" { pub fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int; pub fn pthread_condattr_destroy(attr: *mut pthread_condattr_t) -> c_int; pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, clock_id: clockid_t) -> c_int; + pub fn pthread_condattr_getclock( + attr: *const pthread_condattr_t, + clock_id: *mut clockid_t, + ) -> c_int; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, pshared: c_int) -> c_int; + pub fn pthread_condattr_getpshared( + attr: *const pthread_condattr_t, + pshared: *mut c_int, + ) -> c_int; + + // Spinlocks + pub fn pthread_spin_init(lock: *mut pthread_spinlock_t, pshared: c_int) -> c_int; + pub fn pthread_spin_destroy(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_lock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_trylock(lock: *mut pthread_spinlock_t) -> c_int; + pub fn pthread_spin_unlock(lock: *mut pthread_spinlock_t) -> c_int; + + // Barriers + pub fn pthread_barrier_init( + barrier: *mut pthread_barrier_t, + attr: *const pthread_barrierattr_t, + count: c_uint, + ) -> c_int; + pub fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int; + pub fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int; + pub fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int; + pub fn pthread_barrierattr_destroy(attr: *mut pthread_barrierattr_t) -> c_int; + pub fn pthread_barrierattr_getpshared( + attr: *const pthread_barrierattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_barrierattr_setpshared( + attr: *mut pthread_barrierattr_t, + pshared: c_int, + ) -> c_int; + + // Read-write locks + pub fn pthread_rwlock_init( + rwlock: *mut pthread_rwlock_t, + attr: *const pthread_rwlockattr_t, + ) -> c_int; + pub fn pthread_rwlock_destroy(rwlock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_rdlock(rwlock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_tryrdlock(rwlock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_wrlock(rwlock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_trywrlock(rwlock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlock_unlock(rwlock: *mut pthread_rwlock_t) -> c_int; + pub fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int; + pub fn pthread_rwlockattr_destroy(attr: *mut pthread_rwlockattr_t) -> c_int; + pub fn pthread_rwlockattr_getpshared( + attr: *const pthread_rwlockattr_t, + pshared: *mut c_int, + ) -> c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, pshared: c_int) -> c_int; // Thread-local storage pub fn pthread_key_create( @@ -115,21 +244,32 @@ extern "C" { // One-time initialization pub fn pthread_once(once_control: *mut pthread_once_t, init_routine: extern "C" fn()) -> c_int; - // GNU extensions + // GNU/QuRT non-portable extensions pub fn pthread_getname_np(thread: pthread_t, name: *mut c_char, len: size_t) -> c_int; - + pub fn pthread_getattr_np(thread: pthread_t, attr: *mut pthread_attr_t) -> c_int; pub fn pthread_attr_setaffinity_np( attr: *mut pthread_attr_t, cpusetsize: size_t, cpuset: *const cpu_set_t, ) -> c_int; - pub fn pthread_attr_getaffinity_np( attr: *mut pthread_attr_t, cpusetsize: size_t, cpuset: *mut cpu_set_t, ) -> c_int; - // POSIX standard + // QuRT-specific thread attribute extensions + pub fn pthread_attr_setthreadname(attr: *mut pthread_attr_t, name: *const c_char) -> c_int; + pub fn pthread_attr_getthreadname( + attr: *const pthread_attr_t, + name: *mut c_char, + size: c_int, + ) -> c_int; + pub fn pthread_attr_settimetestid(attr: *mut pthread_attr_t, tid: c_uint) -> c_int; + pub fn pthread_attr_gettimetestid(attr: *const pthread_attr_t, tid: *mut c_uint) -> c_int; + pub fn pthread_attr_setautostack(attr: *mut pthread_attr_t) -> c_int; + pub fn pthread_attr_setbuspriority(attr: *mut pthread_attr_t, bus_priority: c_ushort) -> c_int; + + // POSIX standard (declared in QuRT pthread.h) pub fn posix_memalign(memptr: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int; } From f4e27a89168acf734aee0525d59bfcf4b3928739 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 29 Apr 2026 21:47:40 -0700 Subject: [PATCH 3/5] qurt: add mqueue subsystem (message queues, select/pselect) Add POSIX message queue bindings from QuRT's mqueue.h: mq_attr struct, mq_open/close/send/receive and friends, select, pselect. --- libc-test/semver/qurt.txt | 12 +++++++ src/new/qurt/mod.rs | 2 ++ src/new/qurt/mqueue.rs | 74 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/new/qurt/mqueue.rs diff --git a/libc-test/semver/qurt.txt b/libc-test/semver/qurt.txt index 4f263cd0142ca..f0a691e1bb4e6 100644 --- a/libc-test/semver/qurt.txt +++ b/libc-test/semver/qurt.txt @@ -94,7 +94,9 @@ MAX_CANON MAX_INPUT MCL_CURRENT MCL_FUTURE +MQ_PRIO_DEFAULT NAME_MAX +NBBY NFDBITS OPEN_MAX O_DSYNC @@ -362,6 +364,16 @@ ldiv_t llabs lldiv lldiv_t +mq_attr +mq_close +mq_getattr +mq_open +mq_receive +mq_send +mq_setattr +mq_timedreceive +mq_timedsend +mq_unlink mqd_t pthread_attr_getaffinity_np pthread_attr_getdetachstate diff --git a/src/new/qurt/mod.rs b/src/new/qurt/mod.rs index 872a6d15e6411..fddf2d971a32b 100644 --- a/src/new/qurt/mod.rs +++ b/src/new/qurt/mod.rs @@ -308,6 +308,7 @@ pub(crate) mod dlfcn; pub(crate) mod errno; pub(crate) mod fcntl; pub(crate) mod limits; +pub(crate) mod mqueue; pub(crate) mod pthread; pub(crate) mod semaphore; pub(crate) mod signal; @@ -322,6 +323,7 @@ pub use dlfcn::*; pub use errno::*; pub use fcntl::*; pub use limits::*; +pub use mqueue::*; pub use pthread::*; pub use semaphore::*; pub use signal::*; diff --git a/src/new/qurt/mqueue.rs b/src/new/qurt/mqueue.rs new file mode 100644 index 0000000000000..88ecef584f674 --- /dev/null +++ b/src/new/qurt/mqueue.rs @@ -0,0 +1,74 @@ +//! Header: `mqueue.h` +//! +//! QuRT POSIX message queue API. Also provides select/pselect and fd_set +//! operations since these are declared in QuRT's mqueue.h. + +use super::*; +use crate::prelude::*; + +// Message queue priority constants +pub const MQ_PRIO_DEFAULT: c_int = 0; + +// Bits per byte +pub const NBBY: c_uint = 8; + +s! { + pub struct mq_attr { + pub mq_flags: c_long, + pub mq_maxmsg: c_long, + pub mq_msgsize: c_long, + pub mq_curmsgs: c_long, + } +} + +extern "C" { + // Message queue operations + pub fn mq_open(name: *const c_char, oflag: c_int, ...) -> mqd_t; + pub fn mq_close(mq_desc: mqd_t) -> c_int; + pub fn mq_unlink(name: *const c_char) -> c_int; + pub fn mq_send( + mqdes: mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + ) -> c_int; + pub fn mq_timedsend( + mqdes: mqd_t, + msg_ptr: *const c_char, + msg_len: size_t, + msg_prio: c_uint, + abs_timeout: *const timespec, + ) -> c_int; + pub fn mq_receive( + mqdes: mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + ) -> ssize_t; + pub fn mq_timedreceive( + mqdes: mqd_t, + msg_ptr: *mut c_char, + msg_len: size_t, + msg_prio: *mut c_uint, + abs_timeout: *const timespec, + ) -> ssize_t; + pub fn mq_getattr(mqdes: mqd_t, mqstat: *mut mq_attr) -> c_int; + pub fn mq_setattr(mqdes: mqd_t, mqstat: *const mq_attr, omqstat: *mut mq_attr) -> c_int; + + // select/pselect (declared in QuRT mqueue.h) + pub fn select( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timeval, + ) -> c_int; + pub fn pselect( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *const timespec, + sigmask: *const sigset_t, + ) -> c_int; +} From 3502bb1c223dabb0c115b3ec69f6905696f38f8d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 29 Apr 2026 21:48:03 -0700 Subject: [PATCH 4/5] qurt: add POSIX timer functions Add timer_create, timer_delete, timer_gettime, and timer_settime from QuRT's time.h POSIX timer API. --- libc-test/semver/qurt.txt | 4 ++++ src/new/qurt/time.rs | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/libc-test/semver/qurt.txt b/libc-test/semver/qurt.txt index f0a691e1bb4e6..7d8b15a70261f 100644 --- a/libc-test/semver/qurt.txt +++ b/libc-test/semver/qurt.txt @@ -455,6 +455,10 @@ sigwait srand strftime strptime +timer_create +timer_delete +timer_gettime +timer_settime timer_t useconds_t va_list diff --git a/src/new/qurt/time.rs b/src/new/qurt/time.rs index ab6f4453dbeab..732297ecbd64e 100644 --- a/src/new/qurt/time.rs +++ b/src/new/qurt/time.rs @@ -31,4 +31,15 @@ extern "C" { pub fn strptime(s: *const c_char, format: *const c_char, tm: *mut tm) -> *mut c_char; pub fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> c_int; pub fn nanosleep(req: *const timespec, rem: *mut timespec) -> c_int; + + // POSIX timer functions (from QuRT time.h) + pub fn timer_create(clockid: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> c_int; + pub fn timer_delete(timerid: timer_t) -> c_int; + pub fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> c_int; + pub fn timer_settime( + timerid: timer_t, + flags: c_int, + value: *const itimerspec, + ovalue: *mut itimerspec, + ) -> c_int; } From 4552bee6a17c0670ac6acad10752c35017c79d1d Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Wed, 29 Apr 2026 21:48:03 -0700 Subject: [PATCH 5/5] qurt: add missing unistd process and file functions Add process/file functions from QuRT's hooks/unistd.h: getppid, getpgid, getpgrp, setsid, get/set uid/gid variants, fsync, pathconf. --- libc-test/build.rs | 8 ++++++-- libc-test/semver/qurt.txt | 1 + src/new/qurt/unistd.rs | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/libc-test/build.rs b/libc-test/build.rs index 504bcc7ae109d..8e296fa18aef8 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -5830,9 +5830,13 @@ fn test_qurt(target: &str) { | "setenv" | "unsetenv" | "atoi" | "atol" | "atoll" | "strtol" | "strtoul" | "strtoll" | "strtoull" | "strtod" | "strtof" | "rand" | "srand" | "qsort" | "bsearch" | "abs" | "labs" | "llabs" | "div" | "ldiv" | "lldiv" => true, - // Skip unistd functions + // Skip unistd functions: QuRT has no standard unistd.h in its POSIX + // headers; these are declared via sys/types.h -> hooks/unistd.h or the + // toolchain's own sys/unistd.h, neither of which ctest traverses. "access" | "close" | "lseek" | "read" | "write" | "ftruncate" | "unlink" | "getcwd" - | "rmdir" | "getpid" | "sleep" | "sysconf" => true, + | "rmdir" | "getpid" | "getppid" | "getpgid" | "getpgrp" | "getuid" | "geteuid" + | "getgid" | "getegid" | "seteuid" | "setuid" | "setpgid" | "setpgrp" | "setsid" + | "fsync" | "pathconf" | "sleep" | "sysconf" => true, // Skip dlfcn functions "dlopen" | "dlclose" | "dlsym" | "dlerror" => true, // Skip mman functions diff --git a/libc-test/semver/qurt.txt b/libc-test/semver/qurt.txt index 7d8b15a70261f..289874aa3e35a 100644 --- a/libc-test/semver/qurt.txt +++ b/libc-test/semver/qurt.txt @@ -447,6 +447,7 @@ sem_getvalue sem_init sem_open sem_unlink +setpgrp sigevent siginfo_t sigsuspend diff --git a/src/new/qurt/unistd.rs b/src/new/qurt/unistd.rs index b973b60e66761..654d02a38a9d5 100644 --- a/src/new/qurt/unistd.rs +++ b/src/new/qurt/unistd.rs @@ -239,10 +239,26 @@ extern "C" { // Process operations pub fn getpid() -> pid_t; + pub fn getppid() -> pid_t; + pub fn getpgid(pid: pid_t) -> pid_t; + pub fn getpgrp() -> pid_t; + pub fn getuid() -> uid_t; + pub fn geteuid() -> uid_t; + pub fn getgid() -> gid_t; + pub fn getegid() -> gid_t; + pub fn seteuid(uid: uid_t) -> c_int; + pub fn setuid(uid: uid_t) -> c_int; + pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int; + pub fn setpgrp() -> pid_t; + pub fn setsid() -> pid_t; // Sleep functions pub fn sleep(seconds: c_uint) -> c_uint; + // Sync operations + pub fn fsync(fd: c_int) -> c_int; + // System configuration pub fn sysconf(name: c_int) -> c_long; + pub fn pathconf(path: *const c_char, name: c_int) -> c_long; }