From 985f4d1f53bd4d028e3f99a5434eeaf1a2276530 Mon Sep 17 00:00:00 2001 From: David Timber Date: Mon, 6 Jan 2025 03:46:13 +0100 Subject: Add writeups/pthread-timedwait --- writeups/pthread-timedwait/.gitignore | 1 + writeups/pthread-timedwait/Makefile | 2 + writeups/pthread-timedwait/pthread-timedwait.c | 150 +++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 writeups/pthread-timedwait/.gitignore create mode 100644 writeups/pthread-timedwait/Makefile create mode 100644 writeups/pthread-timedwait/pthread-timedwait.c diff --git a/writeups/pthread-timedwait/.gitignore b/writeups/pthread-timedwait/.gitignore new file mode 100644 index 0000000..67eb7e0 --- /dev/null +++ b/writeups/pthread-timedwait/.gitignore @@ -0,0 +1 @@ +pthread-timedwait \ No newline at end of file diff --git a/writeups/pthread-timedwait/Makefile b/writeups/pthread-timedwait/Makefile new file mode 100644 index 0000000..03d0b53 --- /dev/null +++ b/writeups/pthread-timedwait/Makefile @@ -0,0 +1,2 @@ +pthread-timedwait: pthread-timedwait.c + cc -std=c11 -Wall -Wextra -O0 -g -opthread-timedwait pthread-timedwait.c diff --git a/writeups/pthread-timedwait/pthread-timedwait.c b/writeups/pthread-timedwait/pthread-timedwait.c new file mode 100644 index 0000000..9b6e7b5 --- /dev/null +++ b/writeups/pthread-timedwait/pthread-timedwait.c @@ -0,0 +1,150 @@ +/** + * @file pthread-timedwait.c + * @brief Demonstrates the effects on pthread_timedwait upon system wall clock + * change + */ +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include +#include + +#define ARG0 "pthread_timedwait" + + +struct { + // desired sleep time + struct timespec t; +} opts; + +/** + * @brief Raise nanosecond fraction part + * @details "05" -> 50000000, "123" -> 123000000, "005" -> 5000000 + * @note used to preserve precision + * + * @param str fraction part, excluding the leading decimal point + * @param len length of \param str + * @return long the fraction part raised to nanosecond scale + */ +long raise_nsec_frac (const char *str, const size_t len) { + char m[] = { '0', '0', '0', '0', '0', '0', '0', '0', '0', 0 }; + char *p; + long ret = -1; + + memcpy(m, str, len > 9 ? 9 : len); + + for (p = m; *p != 0 && *p == '0'; p += 1); + + if (*p == 0 && m[0] == '0') { + return 0; + } + if (sscanf(p, "%ld", &ret) != 1) { + return -1; + } + + return ret; +} + +/** + * @brief Parse timespec from string, preserving precision + * + * @param str string to parse + * @param ts_out (optional) pointer to timespec struct + * @return true if parsed successfully and \param ts_out is set if non-null + * @return false otherwise. errno set to EINVAL if \param str is NULL. errno set + * to EBADMSG on format error + */ +bool parse_ts (const char *str, struct timespec *ts_out) { + long long sec = 0; + long nsec = 0; + int fr; + const char *frac, *ipart; + + if (str == NULL) { + errno = EINVAL; + return false; + } + + if (str[0] == '.' || str[0] == ',') { + ipart = NULL; + frac = str + 1; + } + else { + ipart = str; + frac = strchr(str, '.'); + if (frac == NULL) { + frac = strchr(str, ','); + } + } + + if (ipart != NULL) { + fr = sscanf(ipart, "%lld", &sec); + if (fr < 1) { + errno = EBADMSG; + return false; + } + } + if (frac != NULL) { + frac += 1; + nsec = raise_nsec_frac(frac, strlen(frac)); + if (nsec < 0) { + errno = EBADMSG; + return false; + } + } + + if (ts_out != NULL) { + ts_out->tv_sec = sec; + ts_out->tv_nsec = nsec; + } + + return true; +} + +bool parse_args (const int argc, const char **argv) { + if (argc <= 1) { + fprintf(stderr, ARG0"