From cb23d5cb871d593af20f74a2a6742b8b29c2da81 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Sun, 10 Jun 2018 01:33:15 +0200 Subject: [PATCH] Interface with FBInk for visual feedback --- .gitignore | 2 ++ .gitmodules | 3 +++ FBInk | 1 + Makefile | 23 ++++++++++++++++++--- kfmon.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++-- kfmon.h | 23 +++++++++++++++++++++ 6 files changed, 105 insertions(+), 5 deletions(-) create mode 160000 FBInk diff --git a/.gitignore b/.gitignore index 892a7c7..58a5fb9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ Kobo/ # Same, for our vendored SQLite SQLiteBuild/ sqlite.built +# As well as FBInk +fbink.built # KDevelop kfmon.kdev4 .kdev4/ diff --git a/.gitmodules b/.gitmodules index bb90ec8..b73dbf1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ path = sqlite url = git://repo.or.cz/sqlite.git ignore = untracked +[submodule "FBInk"] + path = FBInk + url = https://github.com/NiLuJe/FBInk.git diff --git a/FBInk b/FBInk new file mode 160000 index 0000000..eb6bdf5 --- /dev/null +++ b/FBInk @@ -0,0 +1 @@ +Subproject commit eb6bdf56f057ba1f294739ef29e4420f1094f6d6 diff --git a/Makefile b/Makefile index 8f1f3e6..2de29ba 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,8 @@ ifdef NILUJE else # We want to link to sqlite3 explicitly statically LIBS=-l:libsqlite3.a + # We also want FBInk when targeting real devices ;). + LIBS+=-l:libfbink.a endif # NOTE: Remember to use gdb -ex 'set follow-fork-mode child' to debug, since we fork like wild bunnies... @@ -77,6 +79,11 @@ ifeq "$(SQLITE)" "true" EXTRA_LDFLAGS+=-static-libgcc endif +# And pick up FBInk, too. +ifndef NILUJE + EXTRA_LDFLAGS+=-LFBInk/Release +endif + # We use pthreads, let GCC do its thing to do it right (c.f., gcc -dumpspecs | grep pthread). # NOTE: It mostly consists of passing -D_REENTRANT to the preprocessor, -lpthread to the linker, # and setting -fprofile-update to prefer-atomic instead of single. @@ -152,12 +159,22 @@ sqlite.built: $(MAKE) SHELL_OPT="" touch sqlite.built -release: sqlite.built +fbink.built: + cd FBInk && \ + $(MAKE) strip + touch fbink.built + +release: sqlite.built fbink.built $(MAKE) strip SQLITE=true -distclean: clean +fbinkclean: + cd FBInk && \ + $(MAKE) clean + +distclean: clean fbinkclean rm -rf SQLiteBuild rm -rf sqlite/manifest sqlite/manifest.uuid rm -rf sqlite.built + rm -rf fbink.built -.PHONY: default outdir all kfmon strip kobo debug niluje nilujed clean release distclean +.PHONY: default outdir all kfmon strip kobo debug niluje nilujed clean release fbinkclean distclean diff --git a/kfmon.c b/kfmon.c index 006b889..66599b5 100644 --- a/kfmon.c +++ b/kfmon.c @@ -18,6 +18,25 @@ #include "kfmon.h" +// Fake FBInk in my sandbox... +#ifdef NILUJE +const char* fbink_version(void) { + return "N/A"; +} + +int fbink_open(void) { + return EXIT_SUCCESS; +} + +int fbink_init(int) { + return EXIT_SUCCESS; +} + +int fbink_print(int, char*, FBInkConfig*) { + return EXIT_SUCCESS; +} +#endif + // Because daemon() only appeared in glibc 2.21 (and doesn't double-fork anyway) static int daemonize(void) @@ -923,6 +942,7 @@ static pid_t if (pid < 0) { // Fork failed? perror("[KFMon] [ERR!] Aborting: fork"); + fbink_print(-1, "fork failed ?!", &fbink_config); exit(EXIT_FAILURE); } else if (pid == 0) { // Sweet child o' mine! @@ -964,6 +984,7 @@ static pid_t LOG(LOG_ERR, "Failed to find an available entry in our process table for pid %ld, aborting!", (long) pid); + fbink_print(-1, "Can't spawn any more processes", &fbink_config); exit(EXIT_FAILURE); } else { pthread_mutex_lock(&ptlock); @@ -989,6 +1010,7 @@ static pid_t int* arg = malloc(sizeof(*arg)); if (arg == NULL) { LOG(LOG_ERR, "Couldn't allocate memory for thread arg, aborting!"); + fbink_print(-1, "OOM ?!", &fbink_config); exit(EXIT_FAILURE); } *arg = i; @@ -999,10 +1021,12 @@ static pid_t pthread_attr_t attr; if (pthread_attr_init(&attr) != 0) { perror("[KFMon] [ERR!] Aborting: pthread_attr_init"); + fbink_print(-1, "pthread_attr_init failed ?!", &fbink_config); exit(EXIT_FAILURE); } if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) { perror("[KFMon] [ERR!] Aborting: pthread_attr_setdetachstate"); + fbink_print(-1, "pthread_attr_setdetachstate failed ?!", &fbink_config); exit(EXIT_FAILURE); } @@ -1013,10 +1037,12 @@ static pid_t if (pthread_attr_setstacksize(&attr, MAX(1 * 1024 * 1024 / 2, sizeof(void*) * 1024 * 1024 / 8)) != 0) { perror("[KFMon] [ERR!] Aborting: pthread_attr_setstacksize"); + fbink_print(-1, "pthread_attr_setstacksize failed ?!", &fbink_config); exit(EXIT_FAILURE); } if (pthread_create(&rthread, &attr, reaper_thread, arg) != 0) { perror("[KFMon] [ERR!] Aborting: pthread_create"); + fbink_print(-1, "pthread_create failed ?!", &fbink_config); exit(EXIT_FAILURE); } @@ -1025,11 +1051,13 @@ static pid_t snprintf(thname, sizeof(thname), "Reaper:%ld", (long) pid); if (pthread_setname_np(rthread, thname) != 0) { perror("[KFMon] [ERR!] Aborting: pthread_setname_np"); + fbink_print(-1, "pthread_setname_np failed ?!", &fbink_config); exit(EXIT_FAILURE); } if (pthread_attr_destroy(&attr) != 0) { perror("[KFMon] [ERR!] Aborting: pthread_attr_destroy"); + fbink_print(-1, "pthread_attr_destroy failed ?!", &fbink_config); exit(EXIT_FAILURE); } } @@ -1115,6 +1143,7 @@ static bool len = read(fd, buf, sizeof buf); if (len == -1 && errno != EAGAIN) { perror("[KFMon] [ERR!] Aborting: read"); + fbink_print(-1, "read failed ?!", &fbink_config); exit(EXIT_FAILURE); } @@ -1200,6 +1229,7 @@ static bool "%s is flagged as a spawn blocker, it will prevent *any* event from triggering a spawn while it is still running!", watch_config[watch_idx].action); } + fbink_print(-1, "Spawning something . . .", &fbink_config); // We're using execvp()... char* const cmd[] = { watch_config[watch_idx].action, NULL }; spawn(cmd, watch_idx); @@ -1207,6 +1237,7 @@ static bool LOG(LOG_NOTICE, "Target icon '%s' might not have been fully processed by Nickel yet, don't launch anything.", watch_config[watch_idx].filename); + fbink_print(-1, "Not spawning: still processing!", &fbink_config); // NOTE: That, or we hit a SQLITE_BUSY timeout on OPEN, // which tripped our 'pending processing' check. } @@ -1223,9 +1254,11 @@ static bool watch_config[watch_idx].filename, (long) spid, watch_config[watch_idx].action); + fbink_print(-1, "Not spawning: still running!", &fbink_config); } else if (is_reader_spawned) { LOG(LOG_INFO, "As a spawn blocker process is currently running, we won't be spawning anything else to prevent unwanted behavior!"); + fbink_print(-1, "Not spawning: blocked!", &fbink_config); } } } @@ -1331,13 +1364,15 @@ int // Say hello :) LOG(LOG_INFO, - "[PID: %ld] Initializing KFMon %s | Built on %s @ %s | Using SQLite %s (built against version %s)", + "[PID: %ld] Initializing KFMon %s | Built on %s @ %s | Using SQLite %s (built against version %s) | With FBInk %s", (long) getpid(), KFMON_VERSION, __DATE__, __TIME__, sqlite3_libversion(), - SQLITE_VERSION); + SQLITE_VERSION, + fbink_version() + ); // Load our configs if (load_config() == -1) { @@ -1366,6 +1401,22 @@ int // Initialize the process table, to track our spawns init_process_table(); + // Initialize FBInk + fbink_config.row = 1; + fbink_config.col = -5; + fbink_config.is_inverted = false; + fbink_config.is_flashing = false; + fbink_config.is_cleared = false; + fbink_config.is_centered = true; + fbink_config.is_padded = true; + // Consider not being able to print on screen a hard pass... + // (Mostly, it's to avoid blowing up later in fbink_print). + if (fbink_init(-1) == EXIT_FAILURE) { + LOG(LOG_ERR, "Failed to initialize FBInk, aborting!"); + exit(EXIT_FAILURE); + } + fbink_print(-1, "KFMon is starting up", &fbink_config); + // We pretty much want to loop forever... while (1) { LOG(LOG_INFO, "Beginning the main loop."); @@ -1375,6 +1426,7 @@ int fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); if (fd == -1) { perror("[KFMon] [ERR!] Aborting: inotify_init1"); + fbink_print(-1, "Failed to initialize inotify", &fbink_config); exit(EXIT_FAILURE); } @@ -1407,6 +1459,7 @@ int if (watch_config[watch_idx].inotify_wd == -1) { perror("[KFMon] [CRIT] inotify_add_watch"); LOG(LOG_ERR, "Cannot watch '%s', aborting!", watch_config[watch_idx].filename); + fbink_print(-1, "Failed to setup a watch", &fbink_config); exit(EXIT_FAILURE); // NOTE: This effectively means we exit when any one of our target file cannot be found, // which is not a bad thing, per se... @@ -1432,6 +1485,7 @@ int continue; } perror("[KFMon] [ERR!] Aborting: poll"); + fbink_print(-1, "poll failed ?!", &fbink_config); exit(EXIT_FAILURE); } diff --git a/kfmon.h b/kfmon.h index aa41f61..5a76df4 100644 --- a/kfmon.h +++ b/kfmon.h @@ -25,6 +25,9 @@ #endif #include "inih/ini.h" +#ifndef NILUJE +#include "FBInk/fbink.h" +#endif #include #include #include @@ -71,6 +74,25 @@ # define KFMON_CONFIGPATH "/home/niluje/Kindle/Staging/kfmon" #endif +// We also have to fake the FBInk API in my sandbox... +#ifdef NILUJE +typedef struct +{ + short int row; + short int col; + bool is_inverted; + bool is_flashing; + bool is_cleared; + bool is_centered; + bool is_padded; +} FBInkConfig; + +const char* fbink_version(void); +int fbink_open(void); +int fbink_init(int); +int fbink_print(int, const char*, FBInkConfig*); +#endif + // Log everything to stderr (which actually points to our logfile) #define LOG(prio, fmt, ...) \ ({ \ @@ -196,6 +218,7 @@ unsigned int watch_count = 0; // Make our config global, because I'm terrible at C. DaemonConfig daemon_config = { 0 }; WatchConfig watch_config[WATCH_MAX] = { 0 }; +FBInkConfig fbink_config = { 0 }; static unsigned int qhash(const unsigned char*, size_t); static bool is_target_processed(unsigned int, bool);