diff options
| author | Paul Eggert | 2017-02-01 15:18:44 -0800 |
|---|---|---|
| committer | Paul Eggert | 2017-02-01 15:23:19 -0800 |
| commit | b01ac672be1277833964d2d53f6dd26560c70343 (patch) | |
| tree | 31b886a5084f20135bec50fe831dcfeed229c619 /src/fns.c | |
| parent | 33be50037c2b4cdb002538534e9915c6bad253b7 (diff) | |
| download | emacs-b01ac672be1277833964d2d53f6dd26560c70343.tar.gz emacs-b01ac672be1277833964d2d53f6dd26560c70343.zip | |
Revamp quitting and fix infloops
This fixes some infinite loops that cannot be quitted out of,
e.g., (defun foo () (nth most-positive-fixnum '#1=(1 . #1#)))
when byte-compiled and when run under X. See:
http://lists.gnu.org/archive/html/emacs-devel/2017-01/msg00577.html
This also attempts to keep the performance improvements I recently
added, as much as possible under the constraint that the infloops
must be caught. In some cases this fixes infloop bugs recently
introduced when I removed immediate_quit.
* src/alloc.c (Fmake_list):
Use rarely_quit, not maybe_quit, for speed in the usual case.
* src/bytecode.c (exec_byte_code):
* src/editfns.c (Fcompare_buffer_substrings):
* src/fns.c (Fnthcdr):
* src/syntax.c (scan_words, skip_chars, skip_syntaxes)
(Fbackward_prefix_chars):
Use rarely_quit so that users can C-g out of long loops.
* src/callproc.c (call_process_cleanup, call_process):
* src/fileio.c (read_non_regular, Finsert_file_contents):
* src/indent.c (compute_motion):
* src/syntax.c (scan_words, Fforward_comment):
Remove now-unnecessary maybe_quit calls.
* src/callproc.c (call_process):
* src/doc.c (get_doc_string, Fsnarf_documentation):
* src/fileio.c (Fcopy_file, read_non_regular, Finsert_file_contents):
* src/lread.c (safe_to_load_version):
* src/sysdep.c (system_process_attributes) [GNU_LINUX]:
Use emacs_read_quit instead of emacs_read in places where
C-g handling is safe.
* src/eval.c (maybe_quit): Move comment here from lisp.h.
* src/fileio.c (Fcopy_file, e_write):
Use emacs_write_quit instead of emacs_write_sig in places where
C-g handling is safe.
* src/filelock.c (create_lock_file): Use emacs_write, not
plain write, as emacs_write no longer has a problem.
(read_lock_data): Use emacs_read, not read, as emacs_read
no longer has a problem.
* src/fns.c (rarely_quit): Move to lisp.h and rename to
incr_rarely_quit. All uses changed..
* src/fns.c (Fmemq, Fmemql, Fassq, Frassq, Fplist_put, Fplist_member):
* src/indent.c (compute_motion):
* src/syntax.c (find_defun_start, back_comment, forw_comment)
(Fforward_comment, scan_lists, scan_sexps_forward):
Use incr_rarely_quit so that users can C-g out of long loops.
* src/fns.c (Fnconc): Move incr_rarely_quit call to within
inner loop, so that it catches C-g there too.
* src/keyboard.c (tty_read_avail_input): Remove commented-out
and now-obsolete code dealing with interrupts.
* src/lisp.h (rarely_quit, incr_rarely_quit): New functions,
the latter moved here from fns.c and renamed from rarely_quit.
(emacs_read_quit, emacs_write_quit): New decls.
* src/search.c (find_newline, search_buffer, find_newline1):
Add maybe_quit to catch C-g.
* src/sysdep.c (get_child_status): Always invoke maybe_quit
if interruptible, so that the caller need not bother.
(emacs_nointr_read, emacs_read_quit, emacs_write_quit):
New functions.
(emacs_read): Rewrite in terms of emacs_nointr_read.
Do not handle C-g or signals; that is now for emacs_read_quit.
(emacs_full_write): Replace PROCESS_SIGNALS two-way arg
with INTERRUPTIBLE three-way arg. All uses changed.
Diffstat (limited to 'src/fns.c')
| -rw-r--r-- | src/fns.c | 53 |
1 files changed, 24 insertions, 29 deletions
| @@ -84,22 +84,6 @@ See Info node `(elisp)Random Numbers' for more details. */) | |||
| 84 | return make_number (val); | 84 | return make_number (val); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | /* Heuristic on how many iterations of a tight loop can be safely done | ||
| 88 | before it's time to do a quit. This must be a power of 2. It | ||
| 89 | is nice but not necessary for it to equal USHRT_MAX + 1. */ | ||
| 90 | enum { QUIT_COUNT_HEURISTIC = 1 << 16 }; | ||
| 91 | |||
| 92 | /* Process a quit, but do it only rarely, for efficiency. "Rarely" | ||
| 93 | means once per QUIT_COUNT_HEURISTIC or per USHRT_MAX + 1 times, | ||
| 94 | whichever is smaller. Use *QUIT_COUNT to count this. */ | ||
| 95 | |||
| 96 | static void | ||
| 97 | rarely_quit (unsigned short int *quit_count) | ||
| 98 | { | ||
| 99 | if (! (++*quit_count & (QUIT_COUNT_HEURISTIC - 1))) | ||
| 100 | maybe_quit (); | ||
| 101 | } | ||
| 102 | |||
| 103 | /* Random data-structure functions. */ | 87 | /* Random data-structure functions. */ |
| 104 | 88 | ||
| 105 | DEFUN ("length", Flength, Slength, 1, 1, 0, | 89 | DEFUN ("length", Flength, Slength, 1, 1, 0, |
| @@ -1359,9 +1343,8 @@ DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0, | |||
| 1359 | (Lisp_Object n, Lisp_Object list) | 1343 | (Lisp_Object n, Lisp_Object list) |
| 1360 | { | 1344 | { |
| 1361 | CHECK_NUMBER (n); | 1345 | CHECK_NUMBER (n); |
| 1362 | EMACS_INT num = XINT (n); | ||
| 1363 | Lisp_Object tail = list; | 1346 | Lisp_Object tail = list; |
| 1364 | for (EMACS_INT i = 0; i < num; i++) | 1347 | for (EMACS_INT num = XINT (n); 0 < num; num--) |
| 1365 | { | 1348 | { |
| 1366 | if (! CONSP (tail)) | 1349 | if (! CONSP (tail)) |
| 1367 | { | 1350 | { |
| @@ -1369,6 +1352,7 @@ DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0, | |||
| 1369 | return Qnil; | 1352 | return Qnil; |
| 1370 | } | 1353 | } |
| 1371 | tail = XCDR (tail); | 1354 | tail = XCDR (tail); |
| 1355 | rarely_quit (num); | ||
| 1372 | } | 1356 | } |
| 1373 | return tail; | 1357 | return tail; |
| 1374 | } | 1358 | } |
| @@ -1405,7 +1389,7 @@ The value is actually the tail of LIST whose car is ELT. */) | |||
| 1405 | { | 1389 | { |
| 1406 | if (! NILP (Fequal (elt, XCAR (tail)))) | 1390 | if (! NILP (Fequal (elt, XCAR (tail)))) |
| 1407 | return tail; | 1391 | return tail; |
| 1408 | rarely_quit (&quit_count); | 1392 | incr_rarely_quit (&quit_count); |
| 1409 | } | 1393 | } |
| 1410 | CHECK_LIST_END (tail, list); | 1394 | CHECK_LIST_END (tail, list); |
| 1411 | return Qnil; | 1395 | return Qnil; |
| @@ -1416,11 +1400,13 @@ DEFUN ("memq", Fmemq, Smemq, 2, 2, 0, | |||
| 1416 | The value is actually the tail of LIST whose car is ELT. */) | 1400 | The value is actually the tail of LIST whose car is ELT. */) |
| 1417 | (Lisp_Object elt, Lisp_Object list) | 1401 | (Lisp_Object elt, Lisp_Object list) |
| 1418 | { | 1402 | { |
| 1403 | unsigned short int quit_count = 0; | ||
| 1419 | Lisp_Object tail; | 1404 | Lisp_Object tail; |
| 1420 | for (tail = list; CONSP (tail); tail = XCDR (tail)) | 1405 | for (tail = list; CONSP (tail); tail = XCDR (tail)) |
| 1421 | { | 1406 | { |
| 1422 | if (EQ (XCAR (tail), elt)) | 1407 | if (EQ (XCAR (tail), elt)) |
| 1423 | return tail; | 1408 | return tail; |
| 1409 | incr_rarely_quit (&quit_count); | ||
| 1424 | } | 1410 | } |
| 1425 | CHECK_LIST_END (tail, list); | 1411 | CHECK_LIST_END (tail, list); |
| 1426 | return Qnil; | 1412 | return Qnil; |
| @@ -1434,12 +1420,14 @@ The value is actually the tail of LIST whose car is ELT. */) | |||
| 1434 | if (!FLOATP (elt)) | 1420 | if (!FLOATP (elt)) |
| 1435 | return Fmemq (elt, list); | 1421 | return Fmemq (elt, list); |
| 1436 | 1422 | ||
| 1423 | unsigned short int quit_count = 0; | ||
| 1437 | Lisp_Object tail; | 1424 | Lisp_Object tail; |
| 1438 | for (tail = list; CONSP (tail); tail = XCDR (tail)) | 1425 | for (tail = list; CONSP (tail); tail = XCDR (tail)) |
| 1439 | { | 1426 | { |
| 1440 | Lisp_Object tem = XCAR (tail); | 1427 | Lisp_Object tem = XCAR (tail); |
| 1441 | if (FLOATP (tem) && internal_equal (elt, tem, 0, 0, Qnil)) | 1428 | if (FLOATP (tem) && internal_equal (elt, tem, 0, 0, Qnil)) |
| 1442 | return tail; | 1429 | return tail; |
| 1430 | incr_rarely_quit (&quit_count); | ||
| 1443 | } | 1431 | } |
| 1444 | CHECK_LIST_END (tail, list); | 1432 | CHECK_LIST_END (tail, list); |
| 1445 | return Qnil; | 1433 | return Qnil; |
| @@ -1451,11 +1439,13 @@ The value is actually the first element of LIST whose car is KEY. | |||
| 1451 | Elements of LIST that are not conses are ignored. */) | 1439 | Elements of LIST that are not conses are ignored. */) |
| 1452 | (Lisp_Object key, Lisp_Object list) | 1440 | (Lisp_Object key, Lisp_Object list) |
| 1453 | { | 1441 | { |
| 1442 | unsigned short int quit_count = 0; | ||
| 1454 | Lisp_Object tail; | 1443 | Lisp_Object tail; |
| 1455 | for (tail = list; CONSP (tail); tail = XCDR (tail)) | 1444 | for (tail = list; CONSP (tail); tail = XCDR (tail)) |
| 1456 | { | 1445 | { |
| 1457 | if (CONSP (XCAR (tail)) && EQ (XCAR (XCAR (tail)), key)) | 1446 | if (CONSP (XCAR (tail)) && EQ (XCAR (XCAR (tail)), key)) |
| 1458 | return XCAR (tail); | 1447 | return XCAR (tail); |
| 1448 | incr_rarely_quit (&quit_count); | ||
| 1459 | } | 1449 | } |
| 1460 | CHECK_LIST_END (tail, list); | 1450 | CHECK_LIST_END (tail, list); |
| 1461 | return Qnil; | 1451 | return Qnil; |
| @@ -1486,7 +1476,7 @@ The value is actually the first element of LIST whose car equals KEY. */) | |||
| 1486 | if (CONSP (car) | 1476 | if (CONSP (car) |
| 1487 | && (EQ (XCAR (car), key) || !NILP (Fequal (XCAR (car), key)))) | 1477 | && (EQ (XCAR (car), key) || !NILP (Fequal (XCAR (car), key)))) |
| 1488 | return car; | 1478 | return car; |
| 1489 | rarely_quit (&quit_count); | 1479 | incr_rarely_quit (&quit_count); |
| 1490 | } | 1480 | } |
| 1491 | CHECK_LIST_END (tail, list); | 1481 | CHECK_LIST_END (tail, list); |
| 1492 | return Qnil; | 1482 | return Qnil; |
| @@ -1513,11 +1503,13 @@ DEFUN ("rassq", Frassq, Srassq, 2, 2, 0, | |||
| 1513 | The value is actually the first element of LIST whose cdr is KEY. */) | 1503 | The value is actually the first element of LIST whose cdr is KEY. */) |
| 1514 | (Lisp_Object key, Lisp_Object list) | 1504 | (Lisp_Object key, Lisp_Object list) |
| 1515 | { | 1505 | { |
| 1506 | unsigned short int quit_count = 0; | ||
| 1516 | Lisp_Object tail; | 1507 | Lisp_Object tail; |
| 1517 | for (tail = list; CONSP (tail); tail = XCDR (tail)) | 1508 | for (tail = list; CONSP (tail); tail = XCDR (tail)) |
| 1518 | { | 1509 | { |
| 1519 | if (CONSP (XCAR (tail)) && EQ (XCDR (XCAR (tail)), key)) | 1510 | if (CONSP (XCAR (tail)) && EQ (XCDR (XCAR (tail)), key)) |
| 1520 | return XCAR (tail); | 1511 | return XCAR (tail); |
| 1512 | incr_rarely_quit (&quit_count); | ||
| 1521 | } | 1513 | } |
| 1522 | CHECK_LIST_END (tail, list); | 1514 | CHECK_LIST_END (tail, list); |
| 1523 | return Qnil; | 1515 | return Qnil; |
| @@ -1536,7 +1528,7 @@ The value is actually the first element of LIST whose cdr equals KEY. */) | |||
| 1536 | if (CONSP (car) | 1528 | if (CONSP (car) |
| 1537 | && (EQ (XCDR (car), key) || !NILP (Fequal (XCDR (car), key)))) | 1529 | && (EQ (XCDR (car), key) || !NILP (Fequal (XCDR (car), key)))) |
| 1538 | return car; | 1530 | return car; |
| 1539 | rarely_quit (&quit_count); | 1531 | incr_rarely_quit (&quit_count); |
| 1540 | } | 1532 | } |
| 1541 | CHECK_LIST_END (tail, list); | 1533 | CHECK_LIST_END (tail, list); |
| 1542 | return Qnil; | 1534 | return Qnil; |
| @@ -1692,7 +1684,7 @@ changing the value of a sequence `foo'. */) | |||
| 1692 | } | 1684 | } |
| 1693 | else | 1685 | else |
| 1694 | prev = tail; | 1686 | prev = tail; |
| 1695 | rarely_quit (&quit_count); | 1687 | incr_rarely_quit (&quit_count); |
| 1696 | } | 1688 | } |
| 1697 | CHECK_LIST_END (tail, seq); | 1689 | CHECK_LIST_END (tail, seq); |
| 1698 | } | 1690 | } |
| @@ -1717,10 +1709,10 @@ This function may destructively modify SEQ to produce the value. */) | |||
| 1717 | 1709 | ||
| 1718 | for (prev = Qnil, tail = seq; CONSP (tail); tail = next) | 1710 | for (prev = Qnil, tail = seq; CONSP (tail); tail = next) |
| 1719 | { | 1711 | { |
| 1720 | rarely_quit (&quit_count); | ||
| 1721 | next = XCDR (tail); | 1712 | next = XCDR (tail); |
| 1722 | Fsetcdr (tail, prev); | 1713 | Fsetcdr (tail, prev); |
| 1723 | prev = tail; | 1714 | prev = tail; |
| 1715 | incr_rarely_quit (&quit_count); | ||
| 1724 | } | 1716 | } |
| 1725 | CHECK_LIST_END (tail, seq); | 1717 | CHECK_LIST_END (tail, seq); |
| 1726 | seq = prev; | 1718 | seq = prev; |
| @@ -1766,8 +1758,8 @@ See also the function `nreverse', which is used more often. */) | |||
| 1766 | unsigned short int quit_count = 0; | 1758 | unsigned short int quit_count = 0; |
| 1767 | for (new = Qnil; CONSP (seq); seq = XCDR (seq)) | 1759 | for (new = Qnil; CONSP (seq); seq = XCDR (seq)) |
| 1768 | { | 1760 | { |
| 1769 | rarely_quit (&quit_count); | ||
| 1770 | new = Fcons (XCAR (seq), new); | 1761 | new = Fcons (XCAR (seq), new); |
| 1762 | incr_rarely_quit (&quit_count); | ||
| 1771 | } | 1763 | } |
| 1772 | CHECK_LIST_END (seq, seq); | 1764 | CHECK_LIST_END (seq, seq); |
| 1773 | } | 1765 | } |
| @@ -2058,6 +2050,7 @@ use `(setq x (plist-put x prop val))' to be sure to use the new value. | |||
| 2058 | The PLIST is modified by side effects. */) | 2050 | The PLIST is modified by side effects. */) |
| 2059 | (Lisp_Object plist, Lisp_Object prop, Lisp_Object val) | 2051 | (Lisp_Object plist, Lisp_Object prop, Lisp_Object val) |
| 2060 | { | 2052 | { |
| 2053 | unsigned short int quit_count = 0; | ||
| 2061 | Lisp_Object prev = Qnil; | 2054 | Lisp_Object prev = Qnil; |
| 2062 | for (Lisp_Object tail = plist; CONSP (tail) && CONSP (XCDR (tail)); | 2055 | for (Lisp_Object tail = plist; CONSP (tail) && CONSP (XCDR (tail)); |
| 2063 | tail = XCDR (XCDR (tail))) | 2056 | tail = XCDR (XCDR (tail))) |
| @@ -2069,6 +2062,7 @@ The PLIST is modified by side effects. */) | |||
| 2069 | } | 2062 | } |
| 2070 | 2063 | ||
| 2071 | prev = tail; | 2064 | prev = tail; |
| 2065 | incr_rarely_quit (&quit_count); | ||
| 2072 | } | 2066 | } |
| 2073 | Lisp_Object newcell | 2067 | Lisp_Object newcell |
| 2074 | = Fcons (prop, Fcons (val, NILP (prev) ? plist : XCDR (XCDR (prev)))); | 2068 | = Fcons (prop, Fcons (val, NILP (prev) ? plist : XCDR (XCDR (prev)))); |
| @@ -2106,7 +2100,7 @@ one of the properties on the list. */) | |||
| 2106 | { | 2100 | { |
| 2107 | if (! NILP (Fequal (prop, XCAR (tail)))) | 2101 | if (! NILP (Fequal (prop, XCAR (tail)))) |
| 2108 | return XCAR (XCDR (tail)); | 2102 | return XCAR (XCDR (tail)); |
| 2109 | rarely_quit (&quit_count); | 2103 | incr_rarely_quit (&quit_count); |
| 2110 | } | 2104 | } |
| 2111 | 2105 | ||
| 2112 | CHECK_LIST_END (tail, prop); | 2106 | CHECK_LIST_END (tail, prop); |
| @@ -2136,7 +2130,7 @@ The PLIST is modified by side effects. */) | |||
| 2136 | } | 2130 | } |
| 2137 | 2131 | ||
| 2138 | prev = tail; | 2132 | prev = tail; |
| 2139 | rarely_quit (&quit_count); | 2133 | incr_rarely_quit (&quit_count); |
| 2140 | } | 2134 | } |
| 2141 | Lisp_Object newcell = list2 (prop, val); | 2135 | Lisp_Object newcell = list2 (prop, val); |
| 2142 | if (NILP (prev)) | 2136 | if (NILP (prev)) |
| @@ -2216,7 +2210,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, | |||
| 2216 | 2210 | ||
| 2217 | unsigned short int quit_count = 0; | 2211 | unsigned short int quit_count = 0; |
| 2218 | tail_recurse: | 2212 | tail_recurse: |
| 2219 | rarely_quit (&quit_count); | 2213 | incr_rarely_quit (&quit_count); |
| 2220 | if (EQ (o1, o2)) | 2214 | if (EQ (o1, o2)) |
| 2221 | return 1; | 2215 | return 1; |
| 2222 | if (XTYPE (o1) != XTYPE (o2)) | 2216 | if (XTYPE (o1) != XTYPE (o2)) |
| @@ -2425,11 +2419,10 @@ usage: (nconc &rest LISTS) */) | |||
| 2425 | { | 2419 | { |
| 2426 | tail = tem; | 2420 | tail = tem; |
| 2427 | tem = XCDR (tail); | 2421 | tem = XCDR (tail); |
| 2422 | incr_rarely_quit (&quit_count); | ||
| 2428 | } | 2423 | } |
| 2429 | while (CONSP (tem)); | 2424 | while (CONSP (tem)); |
| 2430 | 2425 | ||
| 2431 | rarely_quit (&quit_count); | ||
| 2432 | |||
| 2433 | tem = args[argnum + 1]; | 2426 | tem = args[argnum + 1]; |
| 2434 | Fsetcdr (tail, tem); | 2427 | Fsetcdr (tail, tem); |
| 2435 | if (NILP (tem)) | 2428 | if (NILP (tem)) |
| @@ -2850,10 +2843,12 @@ property and a property with the value nil. | |||
| 2850 | The value is actually the tail of PLIST whose car is PROP. */) | 2843 | The value is actually the tail of PLIST whose car is PROP. */) |
| 2851 | (Lisp_Object plist, Lisp_Object prop) | 2844 | (Lisp_Object plist, Lisp_Object prop) |
| 2852 | { | 2845 | { |
| 2846 | unsigned short int quit_count = 0; | ||
| 2853 | while (CONSP (plist) && !EQ (XCAR (plist), prop)) | 2847 | while (CONSP (plist) && !EQ (XCAR (plist), prop)) |
| 2854 | { | 2848 | { |
| 2855 | plist = XCDR (plist); | 2849 | plist = XCDR (plist); |
| 2856 | plist = CDR (plist); | 2850 | plist = CDR (plist); |
| 2851 | incr_rarely_quit (&quit_count); | ||
| 2857 | } | 2852 | } |
| 2858 | return plist; | 2853 | return plist; |
| 2859 | } | 2854 | } |