less
less copied to clipboard
Allow highlight to be interrupted by C-c
In the following run, try searching for :
ie. type /:
(and press Enter), (I also pressed q
during the search, to show how many seconds it takes of 100% CPU aka 1 core, on my system)
$ time seq 1 32109|tr '\n' ':'| less
real 0m24.743s
user 0m24.011s
sys 0m0.026s
During the search for :
in the above, pressing C-c
(aka Ctrl+C
) doesn't stop the highlight operation.
I naively tried to patch in this functionality but while it seems to work and breaks the operation, something keeps restarting it indefinitely and I'm thus forced to allow the high cpu usage to finish to regain any input control(unless ofc I kill
the less
process):
Index: less-551/search.c
===================================================================
--- less-551.orig/search.c
+++ less-551/search.c
@@ -1021,6 +1025,8 @@ hilite_line(linepos, line, line_len, chp
searchp++;
else /* end of line */
break;
+ if (ABORT_SIGS())
+ break;
} while (match_pattern(info_compiled(&search_info), search_info.text,
searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type));
}
Thanks.
EDIT: To give an idea (of maybe)what's restarting it:
(gdb) bt2
executing: 'frame apply all -q frame'
#0 0x00007f0d5a032143 in ?? () from /usr/lib/libpcre.so.1
#1 0x00007f0d5a006f14 in pcre_exec () from /usr/lib/libpcre.so.1
#2 0x0000557129cd2927 in match_pattern (pattern=<optimized out>, tpattern=<optimized out>, line=line@entry=0x55712ab0e836 "7526:7527:7528:7529:7530:7531:7532:7533:7534:7535:7536:7537:7538:7539:7540:7541:7542:7543:7544:7545:7546:7547:7548:7549:7550:7551:7552:7553:7554:7555:7556:7557:7558:7559:7560:7561:7562:7563:7564:7565:"..., line_len=line_len@entry=145030, sp=sp@entry=0x7ffdd7f6eb58, ep=ep@entry=0x7ffdd7f6eb50, notbol=1, search_type=1) at pattern.c:373
373 matched = pcre_exec(pattern, NULL, line, line_len,
#3 0x0000557129cd40e9 in hilite_line (linepos=linepos@entry=0, line=line@entry=0x55712ab05990 "1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30:31:32:33:34:35:36:37:38:39:40:41:42:43:44:45:46:47:48:49:50:51:52:53:54:55:56:57:58:59:60:61:62:63:64:65:66:67:68:69:70"..., line_len=<optimized out>, chpos=chpos@entry=0x55712abb6e50, sp=<optimized out>, ep=<optimized out>, cvt_ops=<optimized out>) at search.c:1026
1026 } while (match_pattern(info_compiled(&search_info), search_info.text,
#4 0x0000557129cd4a7e in search_range (pos=181548, pos@entry=0, endpos=endpos@entry=1835008, search_type=search_type@entry=17, matches=matches@entry=0, maxlines=maxlines@entry=-1, plinepos=plinepos@entry=0x0, pendpos=0x7ffdd7f6eca0) at search.c:1316
1316 hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
#5 0x0000557129cd4f67 in prep_hilite (spos=spos@entry=0, epos=1835008, maxlines=-1) at search.c:1670
1670 result = search_range(spos, epos, search_type, 0, maxlines, (POSITION*)NULL, &new_epos);
#6 0x0000557129ccae28 in forw (n=35, pos=0, force=1, only_last=0, nblank=0) at forwback.c:153
153 prep_hilite(pos, pos + 4*size_linebuf, ignore_eoi ? 1 : -1);
#7 0x0000557129cc5feb in prompt () at command.c:740
740 make_display();
#8 commands () at command.c:1158
1158 prompt();
#9 0x0000557129cbf7be in main (argc=<optimized out>, argv=0x7ffdd7f6eef0) at main.c:285
285 commands();
(gdb)
For some reason, the first time less
is started and a search is performed for say :
(ie. /:
) then the hilite_line
function is called twice. But for any subsequent searches, even for other patterns, hilite_line
is called only once as it should.
If an interruption of the only-once called hilite_line
happens however, such as by C-c with the above(or below) patch, then hilite_line
is restarted each time C-c happens.
To showcase the above, the below patch can be used to better see when stuff happens:
just run tail -F /tmp/blah.log
in one terminal and seq 1 32109|tr '\n' ':' >/tmp/a ; less /tmp/a
in another then start a search by /:
and watch it say
called hilite_line (1 times thus far)
called hilite_line (2 times thus far)
and then the control is returned to user, then try searching (/:
or another pattern: /4
) again and see only:
called hilite_line (3 times thus far)
, also try interrupting a search via C-c, just as mentioned above and notice the output, then keep pressing C-c, even the in-less
output changes.
The first ever C-c
yields: Line numbers turned off (press RETURN)
(here, it's the only chance you have to press q
to quit), then if you press RETURN(aka Enter key), then hilite_line
gets called and if you C-c before it finishes, you can repeat C-c-ing it and you keep getting:
/tmp/a byte 181548/181548 (END)...skipping...
/tmp/a byte 181548/181548 (END)...skipping...
/tmp/a byte 181548/181548 (END)...skipping...
/tmp/a byte 181548/181548 (END)...skipping...
/tmp/a byte 181548/181548 (END)...skipping...
/tmp/a byte 181548/181548 (END)...skipping...
/tmp/a byte 181548/181548 (END)...skipping...
/tmp/a byte 181548/181548 (END)...skipping...
/tmp/a byte 181548/181548 (END)
and you thus cannot quit less
until you let it finish, after which you have control(so can press q
)
diff --git a/search.c b/search.c
index 1761a6a..de4c137 100644
--- a/search.c
+++ b/search.c
@@ -999,9 +999,16 @@ hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops)
* (currently POSIX, PCRE and V8-with-regexec2). }}
*/
searchp = line;
+ static int called=0;
+ called++;
+ FILE *f=fopen("/tmp/blah.log","a");
+ if (NULL == f) {
+ f=stderr;
+ }
+ fprintf(f, "called hilite_line (%d times thus far)\n",called); fflush(f);
do {
if (sp == NULL || ep == NULL)
- return;
+ goto ret;
create_hilites(linepos, sp-line, ep-line, chpos);
/*
* If we matched more than zero characters,
@@ -1014,8 +1021,19 @@ hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops)
searchp++;
else /* end of line */
break;
+ if (ABORT_SIGS()) {
+ static int times=0;
+ times++;
+ fprintf(f,"interrupted (so far %d times)\n", times); fflush(f);
+ break;
+ }
} while (match_pattern(info_compiled(&search_info), search_info.text,
- searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type));
+ searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type));
+ret:
+ if (stderr != f) {
+ fclose(f);
+ sync();
+ }
}
#endif
I have some ideas but I'd like to be able to reproduce this and haven't had much luck. I don't understand why you see so much CPU usage to highlight this file. On my aged MacBook, your time command shows much lower user space CPU usage:
time seq 1 32109|tr '\n' ':' |less
real 0m2.473s
user 0m0.094s
sys 0m0.012s
What type of machine are you using?