2828#include "stat.h"
2929#include "trie.h"
3030#include "xregex.h"
31+ #include "xtime.h"
3132
3233#include <errno.h>
3334#include <fcntl.h>
4243#include <string.h>
4344#include <strings.h>
4445#include <sys/resource.h>
46+ #include <sys/time.h>
4547#include <sys/types.h>
4648#include <time.h>
4749#include <unistd.h>
@@ -1146,20 +1148,7 @@ bool eval_comma(const struct bfs_expr *expr, struct bfs_eval *state) {
11461148}
11471149
11481150/** Update the status bar. */
1149- static void eval_status (struct bfs_eval * state , struct bfs_bar * bar , struct timespec * last_status , size_t count ) {
1150- struct timespec now ;
1151- if (eval_gettime (state , & now ) == 0 ) {
1152- struct timespec elapsed = {0 };
1153- timespec_elapsed (& elapsed , last_status , & now );
1154-
1155- // Update every 0.1s
1156- if (elapsed .tv_sec > 0 || elapsed .tv_nsec >= 100000000L ) {
1157- * last_status = now ;
1158- } else {
1159- return ;
1160- }
1161- }
1162-
1151+ static void eval_status (struct bfs_eval * state , struct bfs_bar * bar , size_t count ) {
11631152 size_t width = bfs_bar_width (bar );
11641153 if (width < 3 ) {
11651154 return ;
@@ -1389,9 +1378,13 @@ struct callback_args {
13891378
13901379 /** The status bar. */
13911380 struct bfs_bar * bar ;
1392- /** The time of the last status update. */
1393- struct timespec last_status ;
1394- /** Flag set by SIGINFO hook. */
1381+ /** The SIGALRM hook. */
1382+ struct sighook * alrm_hook ;
1383+ /** The interval timer. */
1384+ struct timer * timer ;
1385+ /** Flag set by SIGALRM. */
1386+ atomic bool alrm_flag ;
1387+ /** Flag set by SIGINFO. */
13951388 atomic bool info_flag ;
13961389
13971390 /** The number of files visited so far. */
@@ -1406,6 +1399,64 @@ struct callback_args {
14061399 int ret ;
14071400};
14081401
1402+ /** Update the status bar in response to SIGALRM. */
1403+ static void eval_sigalrm (int sig , siginfo_t * info , void * ptr ) {
1404+ struct callback_args * args = ptr ;
1405+ store (& args -> alrm_flag , true, relaxed );
1406+ }
1407+
1408+ /** Show/hide the bar in response to SIGINFO. */
1409+ static void eval_siginfo (int sig , siginfo_t * info , void * ptr ) {
1410+ struct callback_args * args = ptr ;
1411+ store (& args -> info_flag , true, relaxed );
1412+ }
1413+
1414+ /** Show the status bar. */
1415+ static void eval_show_bar (struct callback_args * args ) {
1416+ args -> alrm_hook = sighook (SIGALRM , eval_sigalrm , args , SH_CONTINUE );
1417+ if (!args -> alrm_hook ) {
1418+ goto fail ;
1419+ }
1420+
1421+ args -> bar = bfs_bar_show ();
1422+ if (!args -> bar ) {
1423+ goto fail ;
1424+ }
1425+
1426+ // Update the bar every 0.1s
1427+ struct timespec ival = { .tv_nsec = 100 * 1000 * 1000 };
1428+ args -> timer = xtimer_start (& ival );
1429+ if (!args -> timer ) {
1430+ goto fail ;
1431+ }
1432+
1433+ // Update the bar immediately
1434+ store (& args -> alrm_flag , true, relaxed );
1435+
1436+ return ;
1437+
1438+ fail :
1439+ bfs_warning (args -> ctx , "Couldn't show status bar: %s.\n\n" , errstr ());
1440+
1441+ bfs_bar_hide (args -> bar );
1442+ args -> bar = NULL ;
1443+
1444+ sigunhook (args -> alrm_hook );
1445+ args -> alrm_hook = NULL ;
1446+ }
1447+
1448+ /** Hide the status bar. */
1449+ static void eval_hide_bar (struct callback_args * args ) {
1450+ xtimer_stop (args -> timer );
1451+ args -> timer = NULL ;
1452+
1453+ sigunhook (args -> alrm_hook );
1454+ args -> alrm_hook = NULL ;
1455+
1456+ bfs_bar_hide (args -> bar );
1457+ args -> bar = NULL ;
1458+ }
1459+
14091460/**
14101461 * bftw() callback.
14111462 */
@@ -1426,18 +1477,14 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) {
14261477 // Check whether SIGINFO was delivered and show/hide the bar
14271478 if (exchange (& args -> info_flag , false, relaxed )) {
14281479 if (args -> bar ) {
1429- bfs_bar_hide (args -> bar );
1430- args -> bar = NULL ;
1480+ eval_hide_bar (args );
14311481 } else {
1432- args -> bar = bfs_bar_show ();
1433- if (!args -> bar ) {
1434- bfs_warning (ctx , "Couldn't show status bar: %s.\n" , errstr ());
1435- }
1482+ eval_show_bar (args );
14361483 }
14371484 }
14381485
1439- if (args -> bar ) {
1440- eval_status (& state , args -> bar , & args -> last_status , args -> count );
1486+ if (exchange ( & args -> alrm_flag , false, relaxed ) ) {
1487+ eval_status (& state , args -> bar , args -> count );
14411488 }
14421489
14431490 if (ftwbuf -> type == BFS_ERROR ) {
@@ -1509,12 +1556,6 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) {
15091556 return state .action ;
15101557}
15111558
1512- /** Show/hide the bar in response to SIGINFO. */
1513- static void eval_siginfo (int sig , siginfo_t * info , void * ptr ) {
1514- struct callback_args * args = ptr ;
1515- store (& args -> info_flag , true, relaxed );
1516- }
1517-
15181559/** Raise RLIMIT_NOFILE if possible, and return the new limit. */
15191560static int raise_fdlimit (struct bfs_ctx * ctx ) {
15201561 rlim_t cur = ctx -> orig_nofile .rlim_cur ;
@@ -1671,10 +1712,7 @@ int bfs_eval(struct bfs_ctx *ctx) {
16711712 };
16721713
16731714 if (ctx -> status ) {
1674- args .bar = bfs_bar_show ();
1675- if (!args .bar ) {
1676- bfs_warning (ctx , "Couldn't show status bar: %s.\n\n" , errstr ());
1677- }
1715+ eval_show_bar (& args );
16781716 }
16791717
16801718#ifdef SIGINFO
@@ -1752,7 +1790,9 @@ int bfs_eval(struct bfs_ctx *ctx) {
17521790 }
17531791
17541792 sigunhook (info_hook );
1755- bfs_bar_hide (args .bar );
1793+ if (args .bar ) {
1794+ eval_hide_bar (& args );
1795+ }
17561796
17571797 if (ctx -> ignore_errors && args .nerrors > 0 ) {
17581798 bfs_warning (ctx , "Suppressed errors: %zu\n" , args .nerrors );
0 commit comments