status

statusbar program for dwm
git clone anongit@rnpnr.xyz:status.git
Log | Files | Refs | Feed | README | LICENSE

Commit: 14800b7b382676f2e8e8760ff99145124337f8b3
Parent: 7ea779050b0a9e71c8d95cf1c8e085c0c49c8d43
Author: Randy Palamar
Date:   Mon, 23 Dec 2024 22:21:55 -0700

status rewrite

We no longer use signals to update blocks. They update on an
interval or based on a file watch via inotify. This may be
expanded to include arbitrary file descriptors as well. This has
already lead to lower runtime memory usage despite a big arena
alloc at startup that isn't being fully utilized yet. The binary
size has also been reduced.

There is a potential problem with the X macro producing long lines
but this will be addressed when necessary.

Otherwise this gives blocks much more control over their
individual updates while also producing better code.

Diffstat:
Mblocks/date.c | 26+++++++++++++++++++++-----
Ablocks/linux/backlight.c | 39+++++++++++++++++++++++++++++++++++++++
Dblocks/linux/battery.c | 56--------------------------------------------------------
Ablocks/linux/battery_info.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dblocks/linux/blight.c | 24------------------------
Mbuild.sh | 2+-
Mconfig.def.h | 42++++++++++++++++--------------------------
Mstatus.c | 408++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
8 files changed, 420 insertions(+), 252 deletions(-)

diff --git a/blocks/date.c b/blocks/date.c @@ -1,9 +1,25 @@ /* See LICENSE for license details. */ -static size_t -date(struct Block *b) +struct date_arg { + char *fmt; /* Time Format String (ex: %R) */ + f32 interval; /* Update Interval [s] */ +}; + +static BLOCK_UPDATE_FN(date_update) { - time_t t = time(NULL); - strftime(buf, sizeof(buf), b->arg, localtime(&t)); + struct date_arg *da = b->arg; + + b32 result = timer_update(b->user_data, da->interval, dt); + if (result) { + time_t t = time(NULL); + strftime(buffer, sizeof(buffer), da->fmt, localtime(&t)); + b->len = snprintf(b->data, sizeof(b->data), b->fmt, buffer); + } - return snprintf(b->curstr, LEN(b->curstr), b->fmt, buf); + return result; +} + +static BLOCK_INIT_FN(date_init) +{ + b->user_data = alloc(a, f32, 1); + date_update(b, 1); } diff --git a/blocks/linux/backlight.c b/blocks/linux/backlight.c @@ -0,0 +1,39 @@ +/* See LICENSE for license details. */ +struct linux_backlight_data {i64 max_brightness; char *brightness_path;}; + +static BLOCK_UPDATE_FN(backlight_update) +{ + if (dt > 0) + return 0; + + struct linux_backlight_data *lbd = b->user_data; + i64 current; + if (pscanf(lbd->brightness_path, "%ld", &current) != 1) + current = 0; + + f32 percent = 100 * current / (f32)lbd->max_brightness + 0.5; + i64 len = snprintf(buffer, sizeof(buffer), "%d%%", (i32)percent); + buffer[len] = 0; + b->len = snprintf(b->data, sizeof(b->data), b->fmt, buffer); + + return 1; +} + +static BLOCK_INIT_FN(backlight_init) +{ + struct linux_backlight_data *lbd; + b->user_data = lbd = push_struct(a, struct linux_backlight_data); + + Arena tmp = *a; + char *path = alloc(&tmp, char, 4096); + snprintf(path, 4096, "/sys/class/backlight/%s/max_brightness", (char *)b->arg); + if (pscanf(path, "%ld", &lbd->max_brightness) != 1) + die("backlight_init: failed to read max brightness\n"); + + i64 len = snprintf(path, 4096, "/sys/class/backlight/%s/brightness", (char *)b->arg); + lbd->brightness_path = path; + a->beg += len; + + backlight_update(b, 0); + add_file_watch(a, lbd->brightness_path, block_index, backlight_update); +} diff --git a/blocks/linux/battery.c b/blocks/linux/battery.c @@ -1,56 +0,0 @@ -/* See LICENSE for license details. */ -#include <limits.h> - -struct bat_arg { - char *bat; /* BAT name (ex. BAT0) */ - char *pre; /* prefix for percentages less than thres */ - char *suf; /* suffix for percentages less than thres */ - int thres; /* % threshold to consider low (-1 to disable) */ -}; - -static size_t -batinfo(struct Block *b) -{ - struct bat_arg *ba = b->arg; - char *pre = ba->pre ? ba->pre : ""; - char *suf = ba->suf ? ba->suf : ""; - char path[PATH_MAX], state[12]; - int s, perc, h, m; - long power_now, energy_now, energy_full; - double timeleft; - - snprintf(path, sizeof(path), "/sys/class/power_supply/%s/energy_full", ba->bat); - if (pscanf(path, "%ld", &energy_full) != 1) - energy_full = 1; - - snprintf(path, sizeof(path), "/sys/class/power_supply/%s/energy_now", ba->bat); - if (pscanf(path, "%ld", &energy_now) != 1) - energy_now = 0; - - perc = (100 * energy_now / (double)energy_full); - s = perc < ba->thres; - - snprintf(path, sizeof(path), "/sys/class/power_supply/%s/status", ba->bat); - if (pscanf(path, "%12s", &state) != 1) - snprintf(state, sizeof(state), "Unknown"); - - /* NOTE(rnp): proper devices use negative power to indicate discharging but that - * is not always the case. The status string can mostly be trusted */ - if (!strcmp(state, "Discharging")) { - snprintf(path, sizeof(path), "/sys/class/power_supply/%s/power_now", ba->bat); - if (pscanf(path, "%ld", &power_now) != 1) - power_now = 1; - - timeleft = (double)energy_now / (double)ABS(power_now); - h = timeleft; - m = (timeleft - (double)h) * 60; - - snprintf(buf, sizeof(buf), "%s%d%% (%d:%02d)%s", s ? pre : "", - perc, h, m, s ? suf : ""); - } else { - snprintf(buf, sizeof(buf), "%s%d%% (%s)%s", s ? pre : "", perc, - state, s ? suf : ""); - } - - return snprintf(b->curstr, LEN(b->curstr), b->fmt, buf); -} diff --git a/blocks/linux/battery_info.c b/blocks/linux/battery_info.c @@ -0,0 +1,75 @@ +/* See LICENSE for license details. */ +struct bat_arg { + char *bat; /* BAT name (ex. BAT0) */ + char *pre; /* prefix for percentages less than thres */ + char *suf; /* suffix for percentages less than thres */ + i32 thres; /* % threshold to consider low (-1 to disable) */ + f32 interval; /* [s] */ +}; + +struct linux_battery_data { i64 energy_full; f32 timer; }; + +static BLOCK_UPDATE_FN(battery_info_update) +{ + struct bat_arg *ba = b->arg; + struct linux_battery_data *lbd = b->user_data; + + if (!timer_update(&lbd->timer, ba->interval, dt)) + return 0; + + char *pre = ba->pre ? ba->pre : ""; + char *suf = ba->suf ? ba->suf : ""; + char path[4096], state[12]; + + i32 h, m; + i64 power_now, energy_now; + f64 timeleft; + + snprintf(path, sizeof(path), "/sys/class/power_supply/%s/energy_now", ba->bat); + if (pscanf(path, "%ld", &energy_now) != 1) + energy_now = 0; + + f32 percent = (100 * energy_now / (f64)lbd->energy_full) + 0.5; + b32 warn = percent < ba->thres; + + snprintf(path, sizeof(path), "/sys/class/power_supply/%s/status", ba->bat); + if (pscanf(path, "%12s", &state) != 1) + snprintf(state, sizeof(state), "Unknown"); + + /* NOTE(rnp): proper devices use negative power to indicate discharging but that + * is not always the case. The status string can mostly be trusted */ + if (!strcmp(state, "Discharging")) { + snprintf(path, sizeof(path), "/sys/class/power_supply/%s/power_now", ba->bat); + if (pscanf(path, "%ld", &power_now) != 1) + power_now = 1; + + timeleft = energy_now / (f64)ABS(power_now); + h = timeleft; + m = (timeleft - (f64)h) * 60; + + i64 len = snprintf(buffer, sizeof(buffer), "%s%d%% (%d:%02d)%s", warn? pre : "", + (i32)percent, h, m, warn? suf : ""); + buffer[len] = 0; + } else { + i64 len = snprintf(buffer, sizeof(buffer), "%s%d%% (%s)%s", warn? pre : "", + (i32)percent, state, warn? suf : ""); + buffer[len] = 0; + } + b->len = snprintf(b->data, sizeof(b->data), b->fmt, buffer); + + return 1; +} + +static BLOCK_INIT_FN(battery_info_init) +{ + struct bat_arg *ba = b->arg; + struct linux_battery_data *lbd; + b->user_data = lbd = push_struct(a, struct linux_battery_data); + + char path[4096]; + snprintf(path, sizeof(path), "/sys/class/power_supply/%s/energy_full", ba->bat); + if (pscanf(path, "%ld", &lbd->energy_full) != 1) + die("battery_info_init: failed to read battery capacity\n"); + + battery_info_update(b, 1); +} diff --git a/blocks/linux/blight.c b/blocks/linux/blight.c @@ -1,24 +0,0 @@ -/* See LICENSE for license details. */ -#include <limits.h> - -static size_t -blight(struct Block *b) -{ - char path[PATH_MAX]; - int perc; - unsigned long max, now; - - snprintf(path, sizeof(path), "/sys/class/backlight/%s/brightness", (char *)b->arg); - if (pscanf(path, "%lu", &now) != 1) - now = 0; - - snprintf(path, sizeof(path), "/sys/class/backlight/%s/max_brightness", (char *)b->arg); - if (pscanf(path, "%lu", &max) != 1) - /* avoid divison by 0 */ - max = 1; - - perc = 100 * now / max; - snprintf(buf, sizeof(buf), "%d%%", perc); - - return snprintf(b->curstr, LEN(b->curstr), b->fmt, buf); -} diff --git a/build.sh b/build.sh @@ -1,6 +1,6 @@ #!/bin/sh -cflags="-O3 -std=c99 -Wall -pedantic" +cflags="-march=native -O3 -std=c11 -Wall -pedantic" cflags="$cflags -D_XOPEN_SOURCE=500" cflags="$cflags -I /usr/X11R6/include" diff --git a/config.def.h b/config.def.h @@ -1,15 +1,10 @@ #include "blocks/date.c" -#include "blocks/linux/battery.c" -//#include "blocks/linux/blight.c" +#include "blocks/linux/battery_info.c" +//#include "blocks/linux/backlight.c" //#include "blocks/linux/volume.c" //#include "blocks/mpd.c" //#include "blocks/script.c" -/* update intervals: SEC+NANO gives sleep interval */ -/* SEC must be >= 0 and 0 <= NANO <= 999999999 */ -#define INTERVAL_SEC 1 -#define INTERVAL_NANO 0 - /* mpd_arg.host can be NULL to use the MPD_HOST env variable */ // static enum mpd_tag_type tags[] = { MPD_TAG_TITLE, MPD_TAG_ARTIST }; // static struct mpd_arg ma = { "localhost", "|", tags, 2 }; @@ -18,27 +13,22 @@ /* card is found with 'aplay -L', default is probably correct */ // static struct vol_arg va = { "default", "Speaker" }; -/* check battery.h for info */ -static struct bat_arg ba = { "BAT0", NULL, NULL, -1 }; +/* check blocks/xxx/battery_info.c for info */ +static struct bat_arg ba = {.bat = "BAT0", .interval = 30}; + +/* check blocks/date.c for info */ +static struct date_arg da = {.fmt = "%R", .interval = 30}; /* status block definitions * - * function description arg (ex) - * - * batinfo battery percentage and status (struct bat_arg *) - * blight backlight percentage (char *) backlight name (intel_backlight) - * date date and time (char *) time fmt string (%R) - * volume ALSA volume percentage (struct vol_arg *) - * mpd_tag reads tag from current song (struct mpd_arg *) - * script run specified script (char *) full script (echo foo | bar) + * block description arg (ex) * - * - * interval * INTERVAL above gives actual update interval, 0 only updates - * at the start and when signaled, -1 only updates when signaled + * battery_info battery percentage and status (struct bat_arg *) + * backlight percentage (char *) backlight name (intel_backlight) + * date date and time (struct date_arg *) */ -struct Block blks[] = { -/* fn fmt interval signal arg */ - { batinfo, "[ %s ]", 30, 0, &ba }, - { date, "[ %s ]", 20, 0, "%R" }, - { NULL }, -}; + +/* NOTE: X(name, statusline_format, argument) */ +#define BLOCKS \ + X(battery_info, "[ %s ]", &ba) \ + X(date, "[ %s ]", &da) diff --git a/status.c b/status.c @@ -1,35 +1,102 @@ /* See LICENSE for license details. */ #include <signal.h> #include <stdarg.h> +#include <stddef.h> +#include <stdint.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> +#include <sys/inotify.h> +#include <sys/select.h> #include <time.h> #include <unistd.h> #include <X11/Xlib.h> -#define ABS(a) ((a) < 0 ? -(a) : (a)) -#define LEN(a) (sizeof(a) / sizeof(*a)) +#define ABS(a) ((a) < 0 ? -(a) : (a)) +#define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a)) #define BLOCKLEN 128 -#define BLOCKPAD 4 -#define STATUSLEN ((LEN(blks) - 1) * BLOCKLEN + 1) - -struct Block { - size_t (*fn)(struct Block *b); - const char *fmt; - int interval; - int signal; - void *arg; - char curstr[BLOCKLEN]; - char prevstr[BLOCKLEN]; - size_t len; -}; -static char buf[BLOCKLEN - BLOCKPAD]; -static Display *dpy; -static int dflag = 0; -static sigset_t blocksigmask; -static struct Block *dirty; +#define TICK_RATE_SECONDS 1 +#define TICK_RATE_NANOSECONDS 0 + +#define SLLPush(sll, new) do { \ + (new)->next = (sll)->next; \ + (sll)->next = (new); \ +} while(0) + +#define KB(n) ((n) << 10ULL) + +#ifndef asm +#define asm __asm__ +#endif + +#ifndef typeof +#define typeof __typeof__ +#endif + +#ifdef __ARM_ARCH_ISA_A64 +#define debugbreak() asm volatile ("brk 0xf000") +#elif __x86_64__ +#define debugbreak() asm volatile ("int3; nop") +#else +#error Unsupported Platform! +#endif + +#ifdef _DEBUG +#define ASSERT(c) do { if (!(c)) debugbreak(); } while (0) +#define DEBUG_EXPORT +#else +#define ASSERT(c) do { (void)(c); } while (0) +#define DEBUG_EXPORT static +#endif + +typedef float f32; +typedef double f64; +typedef uint8_t u8; +typedef uint32_t b32; +typedef uint32_t u32; +typedef int32_t i32; +typedef uint64_t u64; +typedef int64_t i64; +typedef ptrdiff_t size; +typedef size_t usize; + +typedef struct { u8 *beg, *end; } Arena; + +typedef struct { + u8 *buffer; + i32 capacity; + i32 write_index; + b32 errors; +} Stream; + +typedef struct { + void *user_data; + void *arg; + char *fmt; + char data[BLOCKLEN]; + size len; +} Block; + +#define BLOCK_INIT_FN(name) void name(Block *b, i32 block_index, Arena *a) +#define BLOCK_UPDATE_FN(name) b32 name(Block *b, f32 dt) +typedef BLOCK_UPDATE_FN(block_update_fn); + +typedef struct FileWatch { + struct FileWatch *next; + block_update_fn *update_fn; + char *path; + i32 block_index; + i32 wd; +} FileWatch; + +/* TODO(rnp): replace this with arena usage */ +static char buffer[KB(1)]; +static Stream statusline; +static void *display; +static i32 dirty_block_index = -1; +static FileWatch file_watches; + +static i32 dflag; static void die(const char *errstr, ...) @@ -39,7 +106,26 @@ die(const char *errstr, ...) va_start(ap, errstr); vfprintf(stderr, errstr, ap); va_end(ap); - exit(1); + + _exit(1); +} + +static f64 +get_time(void) +{ + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + f64 result = t.tv_sec + ((f64)t.tv_nsec) * 1e-9; + return result; +} + +static b32 +timer_update(f32 *timer, f32 interval, f32 dt) +{ + b32 result = 0; + *timer -= dt; + while (*timer < 0) { *timer += interval; result = 1; } + return result; } static int @@ -60,163 +146,206 @@ pscanf(const char *path, const char *fmt, ...) return (ret == EOF) ? -1 : ret; } +static void * +mem_clear(void *_p, u8 c, usize size) +{ + u8 *p = _p; + for (usize i = 0; i < size; i++) + p[i] = c; + return p; +} + +#define push_struct(a, t) alloc(a, t, 1) +#define alloc(a, t, n) (t *)alloc_(a, sizeof(t), _Alignof(t), n) +static void * +alloc_(Arena *a, size len, size align, size count) +{ + size padding = -(uintptr_t)a->beg & (align - 1); + size available = a->end - a->beg - padding; + if (available <= 0 || available / len < count) { + ASSERT(0); + } + + void *p = a->beg + padding; + a->beg += padding + count * len; + return mem_clear(p, 0, count * len); +} + +static Stream +stream_alloc(Arena *a, size capacity) +{ + Stream result = {0}; + result.buffer = alloc(a, u8, capacity); + result.capacity = capacity; + return result; +} + +static void +add_file_watch(Arena *a, char *path, i32 block_index, block_update_fn *update_fn) +{ + i32 wd = inotify_add_watch(file_watches.wd, path, IN_CLOSE_WRITE|IN_MODIFY); + if (wd != -1) { + /* TODO(rnp): we will need to include inodes if we are expecting to watch + * files that could be removed */ + FileWatch *fw = push_struct(a, FileWatch); + fw->wd = wd; + fw->path = path; + fw->block_index = block_index; + fw->update_fn = update_fn; + SLLPush(&file_watches, fw); + } +} + #include "config.h" +#define X(name, format, argument) {.fmt = format, .arg = argument}, +static Block blocks[] = { + BLOCKS +}; +#undef X + +#if TICK_RATE_NANOSECONDS > 999999999 +#error TICK_RATE_NANOSECONDS must not exceed 999 999 999 +#endif + static void terminate(int signo) { if (!dflag) { - XStoreName(dpy, DefaultRootWindow(dpy), NULL); - XCloseDisplay(dpy); + XStoreName(display, DefaultRootWindow(display), 0); + XCloseDisplay(display); } - - exit(0); + _exit(0); } static void -updateblock(struct Block *b) -{ - b->len = b->fn(b); - if ((b->len == 0 && b->prevstr[0] != 0) || - memcmp(b->curstr, b->prevstr, b->len)) { - if (b->len == 0) - b->prevstr[0] = b->curstr[0] = 0; - else - memcpy(b->prevstr, b->curstr, b->len); - if (!dirty || b < dirty) - dirty = b; +dispatch_file_watch_events(Arena a) +{ + u8 *mem = alloc_(&a, 4096, 64, 1); + for (;;) { + size rlen = read(file_watches.wd, mem, 4096); + if (rlen <= 0) + break; + + struct inotify_event *ie; + for (u8 *data = mem; data < mem + rlen; data += sizeof(*ie) + ie->len) { + ie = (void *)data; + for (FileWatch *fw = file_watches.next; fw; fw = fw->next) { + if (fw->wd != ie->wd) + continue; + + b32 file_changed = (ie->mask & IN_CLOSE_WRITE) != 0; + file_changed |= (ie->mask & IN_MODIFY) != 0; + /* TODO(rnp): it seems like this hits multiple times per update */ + if (file_changed && fw->update_fn(blocks + fw->block_index, 0)) { + /* TODO(rnp): there might be an ordering issue here */ + if (dirty_block_index == -1 || fw->block_index < dirty_block_index) + dirty_block_index = fw->block_index; + } + } + } } } static void -updatestatus(void) +update_status(void) { - static char status[STATUSLEN]; - struct Block *b; - char *s = status; - - for (b = blks; b < dirty; b++) - s += b->len; - - for (; b->fn; b++) { - memcpy(s, b->curstr, b->len); - s += b->len; + statusline.write_index = 0; + i32 block_index; + for (block_index = 0; block_index < dirty_block_index; block_index++) + statusline.write_index += blocks[block_index].len; + + for (; block_index < ARRAY_COUNT(blocks); block_index++) { + Block *b = blocks + block_index; + memcpy(statusline.buffer + statusline.write_index, b->data, b->len); + statusline.write_index += b->len; } - s[0] = '\0'; - dirty = NULL; + statusline.buffer[statusline.write_index] = 0; if (dflag) { - puts(status); - return; + puts((char *)statusline.buffer); + } else { + XStoreName(display, DefaultRootWindow(display), (char *)statusline.buffer); + XSync(display, 0); } - - XStoreName(dpy, DefaultRootWindow(dpy), status); - XSync(dpy, False); } static void -sighandler(int signo, siginfo_t *info, void *context) +update_blocks(f32 dt) { - struct Block *b; - - signo -= SIGRTMIN; - for (b = blks; b->fn; b++) - if (b->signal == signo) - updateblock(b); - if (dirty) - updatestatus(); + i32 count = 0; + #define X(name, fmt, args) if (name ##_update(blocks + count++, dt)) dirty_block_index = count - 1; + BLOCKS + #undef X } static void -setupsigs(void) +status_init(Arena *a) { - int i; - struct Block *b; - struct sigaction sa; + if (!dflag && !(display = XOpenDisplay(0))) + die("XOpenDisplay: can't open display\n"); - /* add signals to blocksigmask */ - sigemptyset(&blocksigmask); - for (b = blks; b->fn; b++) { - if (b->signal <= 0) - continue; + statusline = stream_alloc(a, 4096); - if (b->signal > SIGRTMAX - SIGRTMIN) - die("SIGRTMIN + %d exceeds SIGRTMAX\n", b->signal); + file_watches.wd = inotify_init1(O_NONBLOCK|O_CLOEXEC); - sigaddset(&blocksigmask, SIGRTMIN + b->signal); - } + i32 count = 0; + #define X(name, fmt, arg) name ##_init(blocks + count, count, a); count++; + BLOCKS + #undef X - /* handle terminating signals */ + struct sigaction sa; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sa.sa_handler = terminate; - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGTERM, &sa, 0); - /* ignore unused realtime signals */ - sa.sa_handler = SIG_IGN; - for (i = SIGRTMIN + 1; i <= SIGRTMAX; i++) - sigaction(i, &sa, NULL); - - /* handle update signals for blocks */ - sa.sa_flags = SA_NODEFER | SA_RESTART | SA_SIGINFO; - sa.sa_mask = blocksigmask; - sa.sa_sigaction = sighandler; - for (b = blks; b->fn; b++) - if (b->signal > 0) - sigaction(SIGRTMIN + b->signal, &sa, NULL); - - /* start with signals blocked */ - sigprocmask(SIG_BLOCK, &blocksigmask, NULL); + update_status(); } static void -statusinit(void) +status_loop(Arena a) { - struct Block *b; + fd_set rfd; + f64 last_time = get_time(); - setupsigs(); - - if (!dflag && !(dpy = XOpenDisplay(NULL))) - die("XOpenDisplay: can't open display\n"); - - /* initialize blocks before first print */ - for (b = blks; b->fn; b++) - if (b->interval != -1) - updateblock(b); - updatestatus(); + for (;;) { + dirty_block_index = -1; + struct timespec t = {.tv_sec = TICK_RATE_SECONDS, .tv_nsec = TICK_RATE_NANOSECONDS}; + FD_ZERO(&rfd); + FD_SET(file_watches.wd, &rfd); + + pselect(file_watches.wd + 1, &rfd, 0, 0, &t, 0); + if (FD_ISSET(file_watches.wd, &rfd)) + dispatch_file_watch_events(a); + + f64 current_time = get_time(); + f32 dt = current_time - last_time; + last_time = current_time; + + update_blocks(dt); + if (dirty_block_index >= 0) + update_status(); + } } -static void -statusloop(void) +static Arena +get_arena(void) { - unsigned int i = 0; - struct Block *b; - struct timespec t; - - for (;;) { - sigprocmask(SIG_UNBLOCK, &blocksigmask, NULL); - t.tv_sec = INTERVAL_SEC; - t.tv_nsec = INTERVAL_NANO; - while (nanosleep(&t, &t) == -1); - sigprocmask(SIG_BLOCK, &blocksigmask, NULL); - - for (b = blks; b->fn; b++) - if (b->interval > 0 && i % b->interval == 0) - updateblock(b); - if (dirty) - updatestatus(); - i++; - } + static u8 memory[KB(64)]; + Arena a = {0}; + a.beg = memory; + asm("" : "+r"(a.beg)); + a.end = a.beg + sizeof(memory); + return a; } -int -main(int argc, char *argv[]) +i32 +main(i32 argc, char *argv[]) { - int i; char *argv0 = *argv; - for (argv++; --argc && *argv && argv[0][0] == '-' && argv[0][1]; argv++) { if (argv[0][1] == '-' && argv[0][2] == '\0') { argv++; @@ -224,18 +353,17 @@ main(int argc, char *argv[]) break; } - for (i = 1; argv[0][i]; i++) + for (i32 i = 1; argv[0][i]; i++) { switch (argv[0][i]) { - case 'd': - dflag = 1; - break; - default: - die("usage: %s [-d]\n", argv0); + case 'd': dflag = 1; break; + default: die("usage: %s [-d]\n", argv0); } + } } - statusinit(); - statusloop(); + Arena memory = get_arena(); + status_init(&memory); + status_loop(memory); return 0; }