From 8283adc28ff6a8cd33a6315b6317bb014db3aae0 Mon Sep 17 00:00:00 2001 From: nick black Date: Sat, 9 Jan 2021 23:22:36 -0500 Subject: [PATCH] Introduce src/compat/ for all bins I've created the new files src/compat/compat.{hc}. These are available to all binaries by adding src to the include directories, and src/compat/compat.c to the sources. Several functions are implemented here which one or more target operating systems are missing, right now all related to time. This includes clock_nanosleep(), which is missing on OS X and DragonFly BSD. Eliminate the other three definitions of timespec_to_ns() and friends. Standardize on NANOSECS_IN_SEC rather than the more opaque GIG. Progress on #1121. --- CMakeLists.txt | 11 +++++++++-- src/compat/compat.c | 28 ++++++++++++++++++++++++++++ src/compat/compat.h | 27 +++++++++++++++++++++++++++ src/demo/demo.c | 22 +++++++++++----------- src/demo/demo.h | 24 ++++++------------------ src/demo/hud.c | 12 ++++++------ src/demo/jungle.c | 2 +- src/demo/sliding.c | 4 ++-- src/demo/whiteout.c | 6 +++--- src/lib/internal.h | 15 +-------------- src/poc/blitters.c | 1 + src/poc/pixels.c | 1 + src/poc/rotator.c | 1 + src/poc/visual.cpp | 1 + src/view/view.cpp | 15 +-------------- 15 files changed, 99 insertions(+), 71 deletions(-) create mode 100644 src/compat/compat.c create mode 100644 src/compat/compat.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 14b7677f0..907ad6e30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,9 +115,11 @@ set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND qrcodegen) endif() find_library(LIBRT rt) +file(GLOB COMPATSRC CONFIGURE_DEPENDS src/compat/compat.c) + # libnotcurses (core shared library, core static library) file(GLOB NCSRCS CONFIGURE_DEPENDS src/lib/*.c src/lib/*.cpp) -add_library(notcurses SHARED ${NCSRCS}) +add_library(notcurses SHARED ${NCSRCS} ${COMPATSRC}) if(${USE_STATIC}) add_library(notcurses-static STATIC ${NCSRCS}) else() @@ -140,6 +142,7 @@ set_target_properties(notcurses-static PROPERTIES target_include_directories(notcurses PRIVATE include + src "${PROJECT_BINARY_DIR}/include" "${TERMINFO_INCLUDE_DIRS}" "${READLINE_INCLUDE_DIRS}" @@ -147,6 +150,7 @@ target_include_directories(notcurses target_include_directories(notcurses-static PRIVATE include + src "${PROJECT_BINARY_DIR}/include" "${TERMINFO_STATIC_INCLUDE_DIRS}" "${READLINE_STATIC_INCLUDE_DIRS}" @@ -379,6 +383,7 @@ target_compile_definitions(notcurses-demo target_include_directories(notcurses-demo PRIVATE include + src "${PROJECT_BINARY_DIR}/include" PUBLIC "${AVCODEC_INCLUDE_DIRS}" @@ -400,7 +405,7 @@ foreach(f ${POCSRCS}) get_filename_component(fe "${f}" NAME_WE) add_executable(${fe} ${f}) target_include_directories(${fe} - PRIVATE include "${TERMINFO_INCLUDE_DIRS}" + PRIVATE include src "${TERMINFO_INCLUDE_DIRS}" "${PROJECT_BINARY_DIR}/include" ) target_link_libraries(${fe} @@ -548,6 +553,7 @@ add_executable(notcurses-view ${VIEWSRCS}) target_include_directories(notcurses-view PRIVATE include + src "${PROJECT_BINARY_DIR}/include" ) target_link_libraries(notcurses-view @@ -565,6 +571,7 @@ add_executable(notcurses-tester ${TESTSRCS}) target_include_directories(notcurses-tester PRIVATE include + src "${PROJECT_BINARY_DIR}/include" src/lib ) diff --git a/src/compat/compat.c b/src/compat/compat.c new file mode 100644 index 000000000..3a60fcd23 --- /dev/null +++ b/src/compat/compat.c @@ -0,0 +1,28 @@ +#ifndef __linux__ +#ifndef __FreeBSD__ +#include +// clock_nanosleep is unavailable on DragonFly BSD and Mac OS X +int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *request, + struct timespec *remain){ + struct timespec now; + if(clock_gettime(clockid, &now)){ + return -1; + } + uint64_t nowns = timespec_to_ns(&now); + uint64_t targns = timespec_to_ns(&request); + if(flags != TIMER_ABSTIME){ + targns += nowns; + } + if(nowns < targns){ + uint64_t waitns = targns - nowns; + struct timespec waitts = { + .tv_sec = waitns / 1000000000, + .tv_nsec = waitns % 1000000000, + }; + return nanosleep(&waitts, remain); + } + return 0; + +} +#endif +#endif diff --git a/src/compat/compat.h b/src/compat/compat.h new file mode 100644 index 000000000..90dfdf2b3 --- /dev/null +++ b/src/compat/compat.h @@ -0,0 +1,27 @@ +#ifndef NOTCURSES_COMPAT +#define NOTCURSES_COMPAT + +#include + +#define NANOSECS_IN_SEC 1000000000ul + +static inline uint64_t +timespec_to_ns(const struct timespec* ts){ + return ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec; +} + +static inline struct timespec* +ns_to_timespec(uint64_t ns, struct timespec* ts){ + ts->tv_sec = ns / NANOSECS_IN_SEC; + ts->tv_nsec = ns % NANOSECS_IN_SEC; + return ts; +} + +// compatibility wrappers for code available only on certain operating systems. +// this file is not installed, but only consumed during compilation. if we're +// on an operating system which implements a given function, it won't be built. +int clock_nanosleep(clockid_t clockid, int flags, + const struct timespec *request, + struct timespec *remain); + +#endif diff --git a/src/demo/demo.c b/src/demo/demo.c index da1f10259..fd189e4fa 100644 --- a/src/demo/demo.c +++ b/src/demo/demo.c @@ -332,9 +332,9 @@ handle_opts(int argc, char** argv, notcurses_options* opts, usage(*argv, EXIT_FAILURE); } delaymultiplier = f; - uint64_t ns = f * GIG; - demodelay.tv_sec = ns / GIG; - demodelay.tv_nsec = ns % GIG; + uint64_t ns = f * NANOSECS_IN_SEC; + demodelay.tv_sec = ns / NANOSECS_IN_SEC; + demodelay.tv_nsec = ns % NANOSECS_IN_SEC; break; }default: usage(*argv, EXIT_FAILURE); @@ -424,15 +424,15 @@ summary_table(struct ncdirect* nc, const char* spec, bool canimage, bool canvide uint64_t nsdelta = 0; for(size_t i = 0 ; i < strlen(spec) ; ++i){ nsdelta += results[i].timens; - qprefix(results[i].timens, GIG, timebuf, 0); - qprefix(results[i].stats.render_ns, GIG, rtimebuf, 0); + qprefix(results[i].timens, NANOSECS_IN_SEC, timebuf, 0); + qprefix(results[i].stats.render_ns, NANOSECS_IN_SEC, rtimebuf, 0); bprefix(results[i].stats.render_bytes, 1, totalbuf, 0); if(results[i].stats.renders){ - qprefix((uintmax_t)results[i].stats.renders * GIG * 1000 / + qprefix((uintmax_t)results[i].stats.renders * NANOSECS_IN_SEC * 1000 / (results[i].stats.render_ns + results[i].stats.writeout_ns), 1000, tfpsbuf, 0); }else{ - qprefix(0, GIG, tfpsbuf, 0); + qprefix(0, NANOSECS_IN_SEC, tfpsbuf, 0); } uint32_t rescolor; if(results[i].result < 0){ @@ -455,7 +455,7 @@ summary_table(struct ncdirect* nc, const char* spec, bool canimage, bool canvide PREFIXFMT(timebuf), (uintmax_t)(results[i].stats.renders), BPREFIXFMT(totalbuf), PREFIXFMT(rtimebuf), results[i].timens ? - results[i].stats.renders / ((double)results[i].timens / GIG) : 0.0, + results[i].stats.renders / ((double)results[i].timens / NANOSECS_IN_SEC) : 0.0, (uintmax_t)(results[i].timens ? results[i].stats.render_ns * 100 / results[i].timens : 0), (uintmax_t)(results[i].timens ? @@ -473,16 +473,16 @@ summary_table(struct ncdirect* nc, const char* spec, bool canimage, bool canvide totalrenderns += results[i].stats.render_ns; totalwriteoutns += results[i].stats.writeout_ns; } - qprefix(nsdelta, GIG, timebuf, 0); + qprefix(nsdelta, NANOSECS_IN_SEC, timebuf, 0); bprefix(totalbytes, 1, totalbuf, 0); - qprefix(totalrenderns, GIG, rtimebuf, 0); + qprefix(totalrenderns, NANOSECS_IN_SEC, rtimebuf, 0); table_segment(nc, "", "══╧════════╧════════╪═══════╪═════════╪═════════╪═══════╪══╧══╧═══════╝\n"); printf(" "); table_printf(nc, "│", "%*ss", PREFIXFMT(timebuf)); table_printf(nc, "│", "%7lu", totalframes); table_printf(nc, "│", "%*s", BPREFIXFMT(totalbuf)); table_printf(nc, "│", " %*ss", PREFIXFMT(rtimebuf)); - table_printf(nc, "│", "%7.1f", nsdelta ? totalframes / ((double)nsdelta / GIG) : 0); + table_printf(nc, "│", "%7.1f", nsdelta ? totalframes / ((double)nsdelta / NANOSECS_IN_SEC) : 0); printf("\n"); ncdirect_set_fg_rgb8(nc, 0xff, 0xb0, 0xb0); fflush(stdout); // in case we print to stderr below, we want color from above diff --git a/src/demo/demo.h b/src/demo/demo.h index a05ecc55d..b8c0a2c09 100644 --- a/src/demo/demo.h +++ b/src/demo/demo.h @@ -9,6 +9,7 @@ #include #include #include +#include "compat/compat.h" #ifdef __cplusplus extern "C" { @@ -88,20 +89,7 @@ demo_getc_blocking(struct notcurses* nc, ncinput* ni){ /*----------------------------- end demo input API -------------------------*/ /*-------------------------------time helpers----------------------------*/ -#define GIG 1000000000ul -#define MAXSLEEP (GIG / 80) // nanoseconds - -static inline uint64_t -timespec_to_ns(const struct timespec* ts){ - return ts->tv_sec * GIG + ts->tv_nsec; -} - -static inline struct timespec* -ns_to_timespec(uint64_t ns, struct timespec* ts){ - ts->tv_sec = ns / GIG; - ts->tv_nsec = ns % GIG; - return ts; -} +#define MAXSLEEP (NANOSECS_IN_SEC / 80) // nanoseconds static inline int64_t timespec_subtract_ns(const struct timespec* time1, const struct timespec* time0){ @@ -130,8 +118,8 @@ static inline void timespec_div(const struct timespec* ts, unsigned divisor, struct timespec* quots){ uint64_t ns = timespec_to_ns(ts); ns /= divisor; - quots->tv_nsec = ns % GIG; - quots->tv_sec = ns / GIG; + quots->tv_nsec = ns % NANOSECS_IN_SEC; + quots->tv_sec = ns / NANOSECS_IN_SEC; } // divide the provided timespec 'ts' by 'multiplier' into 'product' @@ -139,8 +127,8 @@ static inline void timespec_mul(const struct timespec* ts, unsigned multiplier, struct timespec* product){ uint64_t ns = timespec_to_ns(ts); ns *= multiplier; - product->tv_nsec = ns % GIG; - product->tv_sec = ns / GIG; + product->tv_nsec = ns % NANOSECS_IN_SEC; + product->tv_sec = ns / NANOSECS_IN_SEC; } /*-------------------------------time helpers----------------------------*/ diff --git a/src/demo/hud.c b/src/demo/hud.c index 4e917e1b0..b27019092 100644 --- a/src/demo/hud.c +++ b/src/demo/hud.c @@ -374,8 +374,8 @@ hud_print_finished(elem* list){ if(ncplane_printf_yx(hud, line, 1, "%d", e->frames) < 0){ return -1; } - if(ncplane_printf_yx(hud, line, 7, "%ju.%03jus", e->totalns / GIG, - (e->totalns % GIG) / 1000000) < 0){ + if(ncplane_printf_yx(hud, line, 7, "%ju.%03jus", e->totalns / NANOSECS_IN_SEC, + (e->totalns % NANOSECS_IN_SEC) / 1000000) < 0){ return -1; } if(ncplane_putstr_yx(hud, line, 16, e->name) < 0){ @@ -516,7 +516,7 @@ demo_nanosleep_abstime_ns(struct notcurses* nc, uint64_t deadline){ while(deadline > timespec_to_ns(&now)){ fsleep.tv_sec = 0; fsleep.tv_nsec = MAXSLEEP; - if(deadline - timespec_to_ns(&now) < GIG / 100){ + if(deadline - timespec_to_ns(&now) < NANOSECS_IN_SEC / 100){ fsleep.tv_nsec = deadline - timespec_to_ns(&now); } ncinput ni; @@ -565,7 +565,7 @@ int demo_render(struct notcurses* nc){ if(!plot_hidden){ ncplane_move_top(ncuplot_plane(plot)); } - uint64_t ns = (timespec_to_ns(&ts) - plottimestart) / (GIG / FPSHZ); + uint64_t ns = (timespec_to_ns(&ts) - plottimestart) / (NANOSECS_IN_SEC / FPSHZ); ncuplot_add_sample(plot, ns, 1); } if(menu){ @@ -588,8 +588,8 @@ int demo_render(struct notcurses* nc){ if(ncplane_printf_yx(hud, 1, 1, "%d", elems->frames) < 0){ return -1; } - if(ncplane_printf_yx(hud, 1, 7, "%ju.%03jus", ns / GIG, - (ns % GIG) / 1000000) < 0){ + if(ncplane_printf_yx(hud, 1, 7, "%ju.%03jus", ns / NANOSECS_IN_SEC, + (ns % NANOSECS_IN_SEC) / 1000000) < 0){ return -1; } if(ncplane_putstr_yx(hud, 1, 16, elems->name) < 0){ diff --git a/src/demo/jungle.c b/src/demo/jungle.c index 52673989f..b2faf59e2 100644 --- a/src/demo/jungle.c +++ b/src/demo/jungle.c @@ -26634,7 +26634,7 @@ int jungle_demo(struct notcurses* nc){ free(buf); clock_gettime(CLOCK_MONOTONIC_RAW, &start); int iter = 0; - int64_t iterns = GIG / 30; + int64_t iterns = NANOSECS_IN_SEC / 30; int64_t nsrunning; do{ DEMO_RENDER(nc); diff --git a/src/demo/sliding.c b/src/demo/sliding.c index d48010f1e..11e0d7366 100644 --- a/src/demo/sliding.c +++ b/src/demo/sliding.c @@ -59,7 +59,7 @@ play(struct notcurses* nc, struct ncplane** chunks){ int lastdir = -1; for(m = 0 ; m < MOVES ; ++m){ clock_gettime(CLOCK_MONOTONIC, &cur); - uint64_t now = cur.tv_sec * GIG + cur.tv_nsec; + uint64_t now = cur.tv_sec * NANOSECS_IN_SEC + cur.tv_nsec; if(now >= deadline_ns){ break; } @@ -189,7 +189,7 @@ int sliding_puzzle_demo(struct notcurses* nc){ goto done; } DEMO_RENDER(nc); - struct timespec ts = { .tv_sec = 0, .tv_nsec = GIG, }; + struct timespec ts = { .tv_sec = 0, .tv_nsec = NANOSECS_IN_SEC, }; // fade out each of the chunks in succession /*for(cy = 0 ; cy < CHUNKS_VERT ; ++cy){ for(cx = 0 ; cx < CHUNKS_HORZ ; ++cx){ diff --git a/src/demo/whiteout.c b/src/demo/whiteout.c index bcc68cc43..351335830 100644 --- a/src/demo/whiteout.c +++ b/src/demo/whiteout.c @@ -210,7 +210,7 @@ message(struct ncplane* n, int maxy, int maxx, int num, int total, ncplane_printf_yx(n, 1, 4, " %03dx%03d (%d/%d) ", maxx, maxy, num + 1, total); ncplane_off_styles(n, NCSTYLE_ITALIC); ncplane_set_fg_rgb8(n, 224, 128, 224); - ncplane_putstr_yx(n, 3, 1, " 🔥 unicode 13, resize awareness, 24b truecolor…🔥 "); + ncplane_putstr_yx(n, 3, 1, " 🎆🔥 unicode 13, resize awareness, 24b truecolor…🔥🎆 "); ncplane_set_fg_rgb8(n, 255, 255, 255); return 0; } @@ -555,8 +555,8 @@ int witherworm_demo(struct notcurses* nc){ uint64_t delay = timespec_to_ns(&demodelay); delay /= screens; struct timespec tv; - if(delay > GIG){ - ns_to_timespec(GIG, &tv); + if(delay > NANOSECS_IN_SEC){ + ns_to_timespec(NANOSECS_IN_SEC, &tv); }else{ ns_to_timespec(delay, &tv); } diff --git a/src/lib/internal.h b/src/lib/internal.h index 6dbf460c9..e2b6833e1 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -38,6 +38,7 @@ const char* oiio_version(void); #include #include #include "notcurses/notcurses.h" +#include "compat/compat.h" #include "egcpool.h" struct esctrie; @@ -606,20 +607,6 @@ ncplane_cell_ref_yx(ncplane* n, int y, int x){ return &n->fb[nfbcellidx(n, y, x)]; } -#define NANOSECS_IN_SEC 1000000000 - -static inline uint64_t -timespec_to_ns(const struct timespec* t){ - return t->tv_sec * NANOSECS_IN_SEC + t->tv_nsec; -} - -static inline struct timespec* -ns_to_timespec(uint64_t ns, struct timespec* ts){ - ts->tv_sec = ns / NANOSECS_IN_SEC; - ts->tv_nsec = ns % NANOSECS_IN_SEC; - return ts; -} - static inline void cell_debug(const egcpool* p, const nccell* c){ fprintf(stderr, "gcluster: %u %s style: 0x%04x chan: 0x%016jx\n", diff --git a/src/poc/blitters.c b/src/poc/blitters.c index f4dc4e361..e4c13edfa 100644 --- a/src/poc/blitters.c +++ b/src/poc/blitters.c @@ -2,6 +2,7 @@ #include #include #include +#include "compat/compat.h" int main(int argc, char** argv){ if(setlocale(LC_ALL, "") == NULL){ diff --git a/src/poc/pixels.c b/src/poc/pixels.c index ed87ec48a..975190077 100644 --- a/src/poc/pixels.c +++ b/src/poc/pixels.c @@ -1,5 +1,6 @@ #include #include +#include "compat/compat.h" int main(void){ setlocale(LC_ALL, ""); diff --git a/src/poc/rotator.c b/src/poc/rotator.c index 24c3be733..5a09cc947 100644 --- a/src/poc/rotator.c +++ b/src/poc/rotator.c @@ -3,6 +3,7 @@ #include #include #include +#include "compat/compat.h" static int rotate_grad(struct notcurses* nc){ diff --git a/src/poc/visual.cpp b/src/poc/visual.cpp index 9c3c427b6..464adbb1d 100644 --- a/src/poc/visual.cpp +++ b/src/poc/visual.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "compat/compat.h" int main(int argc, char** argv){ struct timespec ts = { diff --git a/src/view/view.cpp b/src/view/view.cpp index c08e6364d..3308f7343 100644 --- a/src/view/view.cpp +++ b/src/view/view.cpp @@ -10,6 +10,7 @@ #include #include #include +#include "compat/compat.h" using namespace ncpp; @@ -31,20 +32,6 @@ void usage(std::ostream& o, const char* name, int exitcode){ exit(exitcode); } -constexpr auto NANOSECS_IN_SEC = 1000000000ll; - -static inline auto -timespec_to_ns(const struct timespec* ts) -> uint64_t { - return ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec; -} - -static inline struct timespec* -ns_to_timespec(uint64_t ns, struct timespec* ts){ - ts->tv_sec = ns / NANOSECS_IN_SEC; - ts->tv_nsec = ns % NANOSECS_IN_SEC; - return ts; -} - struct marshal { struct ncplane* subtitle_plane; int framecount;