aboutsummaryrefslogtreecommitdiffstats
path: root/src/fns.c
diff options
context:
space:
mode:
authorPaul Eggert2017-02-01 15:18:44 -0800
committerPaul Eggert2017-02-01 15:23:19 -0800
commitb01ac672be1277833964d2d53f6dd26560c70343 (patch)
tree31b886a5084f20135bec50fe831dcfeed229c619 /src/fns.c
parent33be50037c2b4cdb002538534e9915c6bad253b7 (diff)
downloademacs-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.c53
1 files changed, 24 insertions, 29 deletions
diff --git a/src/fns.c b/src/fns.c
index 444339c5259..41c0c5856b4 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -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. */
90enum { 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
96static void
97rarely_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
105DEFUN ("length", Flength, Slength, 1, 1, 0, 89DEFUN ("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,
1416The value is actually the tail of LIST whose car is ELT. */) 1400The 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.
1451Elements of LIST that are not conses are ignored. */) 1439Elements 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,
1513The value is actually the first element of LIST whose cdr is KEY. */) 1503The 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.
2058The PLIST is modified by side effects. */) 2050The 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.
2850The value is actually the tail of PLIST whose car is PROP. */) 2843The 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}