diff options
| author | Dmitry Gutov | 2023-09-24 01:19:14 +0300 |
|---|---|---|
| committer | Dmitry Gutov | 2024-06-09 02:44:19 +0300 |
| commit | bbc18031aff6f22a1f2b63355f18f294fbdeb797 (patch) | |
| tree | 821536d84a47d3abc01490038e970c1bc53f8447 /src/process.c | |
| parent | e2527dd9fd376b15d2f59ae440858b442b069577 (diff) | |
| download | emacs-bbc18031aff6f22a1f2b63355f18f294fbdeb797.tar.gz emacs-bbc18031aff6f22a1f2b63355f18f294fbdeb797.zip | |
Go around calling the default process filter (reducing GC churn)
Instead of allocating strings and passing them to the filter, pass
the char buffer to a C function implementing the same logic.
* src/process.c (read_process_output_before_insert)
(read_process_output_after_insert):
New functions, extracted from internal-default-process-filter.
(Finternal_default_process_filter): Use them.
(read_and_insert_process_output): New function. Use them.
(read_process_output_fast): New variable.
(read_process_output): Use it to choose how to insert (bug#66020).
* etc/NEWS: Mention the change.
Diffstat (limited to 'src/process.c')
| -rw-r--r-- | src/process.c | 198 |
1 files changed, 143 insertions, 55 deletions
diff --git a/src/process.c b/src/process.c index d716453631e..2e8dd758b3c 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -6146,6 +6146,11 @@ read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars, | |||
| 6146 | ssize_t nbytes, | 6146 | ssize_t nbytes, |
| 6147 | struct coding_system *coding); | 6147 | struct coding_system *coding); |
| 6148 | 6148 | ||
| 6149 | static void | ||
| 6150 | read_and_insert_process_output (struct Lisp_Process *p, char *buf, | ||
| 6151 | ssize_t nread, | ||
| 6152 | struct coding_system *process_coding); | ||
| 6153 | |||
| 6149 | /* Read pending output from the process channel, | 6154 | /* Read pending output from the process channel, |
| 6150 | starting with our buffered-ahead character if we have one. | 6155 | starting with our buffered-ahead character if we have one. |
| 6151 | Yield number of decoded characters read, | 6156 | Yield number of decoded characters read, |
| @@ -6261,7 +6266,10 @@ read_process_output (Lisp_Object proc, int channel) | |||
| 6261 | friends don't expect current-buffer to be changed from under them. */ | 6266 | friends don't expect current-buffer to be changed from under them. */ |
| 6262 | record_unwind_current_buffer (); | 6267 | record_unwind_current_buffer (); |
| 6263 | 6268 | ||
| 6264 | read_and_dispose_of_process_output (p, chars, nbytes, coding); | 6269 | if (read_process_output_fast && p->filter == Qinternal_default_process_filter) |
| 6270 | read_and_insert_process_output (p, chars, nbytes, coding); | ||
| 6271 | else | ||
| 6272 | read_and_dispose_of_process_output (p, chars, nbytes, coding); | ||
| 6265 | 6273 | ||
| 6266 | /* Handling the process output should not deactivate the mark. */ | 6274 | /* Handling the process output should not deactivate the mark. */ |
| 6267 | Vdeactivate_mark = odeactivate; | 6275 | Vdeactivate_mark = odeactivate; |
| @@ -6271,6 +6279,128 @@ read_process_output (Lisp_Object proc, int channel) | |||
| 6271 | } | 6279 | } |
| 6272 | 6280 | ||
| 6273 | static void | 6281 | static void |
| 6282 | read_process_output_before_insert (struct Lisp_Process *p, Lisp_Object *old_read_only, | ||
| 6283 | ptrdiff_t *old_begv, ptrdiff_t *old_zv, | ||
| 6284 | ptrdiff_t *before, ptrdiff_t *before_byte, | ||
| 6285 | ptrdiff_t *opoint, ptrdiff_t *opoint_byte) | ||
| 6286 | { | ||
| 6287 | Fset_buffer (p->buffer); | ||
| 6288 | *opoint = PT; | ||
| 6289 | *opoint_byte = PT_BYTE; | ||
| 6290 | *old_read_only = BVAR (current_buffer, read_only); | ||
| 6291 | *old_begv = BEGV; | ||
| 6292 | *old_zv = ZV; | ||
| 6293 | |||
| 6294 | bset_read_only (current_buffer, Qnil); | ||
| 6295 | |||
| 6296 | /* Insert new output into buffer at the current end-of-output | ||
| 6297 | marker, thus preserving logical ordering of input and output. */ | ||
| 6298 | if (XMARKER (p->mark)->buffer) | ||
| 6299 | set_point_from_marker (p->mark); | ||
| 6300 | else | ||
| 6301 | SET_PT_BOTH (ZV, ZV_BYTE); | ||
| 6302 | *before = PT; | ||
| 6303 | *before_byte = PT_BYTE; | ||
| 6304 | |||
| 6305 | /* If the output marker is outside of the visible region, save | ||
| 6306 | the restriction and widen. */ | ||
| 6307 | if (! (BEGV <= PT && PT <= ZV)) | ||
| 6308 | Fwiden (); | ||
| 6309 | } | ||
| 6310 | |||
| 6311 | static void | ||
| 6312 | read_process_output_after_insert (struct Lisp_Process *p, Lisp_Object *old_read_only, | ||
| 6313 | ptrdiff_t old_begv, ptrdiff_t old_zv, | ||
| 6314 | ptrdiff_t before, ptrdiff_t before_byte, | ||
| 6315 | ptrdiff_t opoint, ptrdiff_t opoint_byte) | ||
| 6316 | { | ||
| 6317 | struct buffer *b; | ||
| 6318 | |||
| 6319 | /* Make sure the process marker's position is valid when the | ||
| 6320 | process buffer is changed in the signal_after_change above. | ||
| 6321 | W3 is known to do that. */ | ||
| 6322 | if (BUFFERP (p->buffer) | ||
| 6323 | && (b = XBUFFER (p->buffer), b != current_buffer)) | ||
| 6324 | set_marker_both (p->mark, p->buffer, BUF_PT (b), BUF_PT_BYTE (b)); | ||
| 6325 | else | ||
| 6326 | set_marker_both (p->mark, p->buffer, PT, PT_BYTE); | ||
| 6327 | |||
| 6328 | update_mode_lines = 23; | ||
| 6329 | |||
| 6330 | /* Make sure opoint and the old restrictions | ||
| 6331 | float ahead of any new text just as point would. */ | ||
| 6332 | if (opoint >= before) | ||
| 6333 | { | ||
| 6334 | opoint += PT - before; | ||
| 6335 | opoint_byte += PT_BYTE - before_byte; | ||
| 6336 | } | ||
| 6337 | if (old_begv > before) | ||
| 6338 | old_begv += PT - before; | ||
| 6339 | if (old_zv >= before) | ||
| 6340 | old_zv += PT - before; | ||
| 6341 | |||
| 6342 | /* If the restriction isn't what it should be, set it. */ | ||
| 6343 | if (old_begv != BEGV || old_zv != ZV) | ||
| 6344 | Fnarrow_to_region (make_fixnum (old_begv), make_fixnum (old_zv)); | ||
| 6345 | |||
| 6346 | bset_read_only (current_buffer, *old_read_only); | ||
| 6347 | SET_PT_BOTH (opoint, opoint_byte); | ||
| 6348 | } | ||
| 6349 | |||
| 6350 | static void read_and_insert_process_output (struct Lisp_Process *p, char *buf, | ||
| 6351 | ssize_t nread, | ||
| 6352 | struct coding_system *process_coding) | ||
| 6353 | { | ||
| 6354 | if (!nread || NILP (p->buffer) || !BUFFER_LIVE_P (XBUFFER (p->buffer))) | ||
| 6355 | return; | ||
| 6356 | |||
| 6357 | Lisp_Object old_read_only; | ||
| 6358 | ptrdiff_t old_begv, old_zv; | ||
| 6359 | ptrdiff_t before, before_byte; | ||
| 6360 | ptrdiff_t opoint, opoint_byte; | ||
| 6361 | |||
| 6362 | read_process_output_before_insert (p, &old_read_only, &old_begv, &old_zv, | ||
| 6363 | &before, &before_byte, &opoint, &opoint_byte); | ||
| 6364 | |||
| 6365 | /* Adapted from call_process. */ | ||
| 6366 | if (NILP (BVAR (XBUFFER(p->buffer), enable_multibyte_characters)) | ||
| 6367 | && ! CODING_MAY_REQUIRE_DECODING (process_coding)) | ||
| 6368 | { | ||
| 6369 | insert_1_both (buf, nread, nread, 0, 0, 0); | ||
| 6370 | signal_after_change (PT - nread, 0, nread); | ||
| 6371 | } | ||
| 6372 | else | ||
| 6373 | { /* We have to decode the input. */ | ||
| 6374 | Lisp_Object curbuf; | ||
| 6375 | int carryover = 0; | ||
| 6376 | specpdl_ref count1 = SPECPDL_INDEX (); | ||
| 6377 | |||
| 6378 | XSETBUFFER (curbuf, current_buffer); | ||
| 6379 | /* We cannot allow after-change-functions be run | ||
| 6380 | during decoding, because that might modify the | ||
| 6381 | buffer, while we rely on process_coding.produced to | ||
| 6382 | faithfully reflect inserted text until we | ||
| 6383 | TEMP_SET_PT_BOTH below. */ | ||
| 6384 | specbind (Qinhibit_modification_hooks, Qt); | ||
| 6385 | decode_coding_c_string (process_coding, | ||
| 6386 | (unsigned char *) buf, nread, curbuf); | ||
| 6387 | unbind_to (count1, Qnil); | ||
| 6388 | |||
| 6389 | TEMP_SET_PT_BOTH (PT + process_coding->produced_char, | ||
| 6390 | PT_BYTE + process_coding->produced); | ||
| 6391 | signal_after_change (PT - process_coding->produced_char, | ||
| 6392 | 0, process_coding->produced_char); | ||
| 6393 | carryover = process_coding->carryover_bytes; | ||
| 6394 | if (carryover > 0) | ||
| 6395 | memcpy (buf, process_coding->carryover, | ||
| 6396 | process_coding->carryover_bytes); | ||
| 6397 | } | ||
| 6398 | |||
| 6399 | read_process_output_after_insert (p, &old_read_only, old_begv, old_zv, | ||
| 6400 | before, before_byte, opoint, opoint_byte); | ||
| 6401 | } | ||
| 6402 | |||
| 6403 | static void | ||
| 6274 | read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars, | 6404 | read_and_dispose_of_process_output (struct Lisp_Process *p, char *chars, |
| 6275 | ssize_t nbytes, | 6405 | ssize_t nbytes, |
| 6276 | struct coding_system *coding) | 6406 | struct coding_system *coding) |
| @@ -6373,7 +6503,6 @@ Otherwise it discards the output. */) | |||
| 6373 | (Lisp_Object proc, Lisp_Object text) | 6503 | (Lisp_Object proc, Lisp_Object text) |
| 6374 | { | 6504 | { |
| 6375 | struct Lisp_Process *p; | 6505 | struct Lisp_Process *p; |
| 6376 | ptrdiff_t opoint; | ||
| 6377 | 6506 | ||
| 6378 | CHECK_PROCESS (proc); | 6507 | CHECK_PROCESS (proc); |
| 6379 | p = XPROCESS (proc); | 6508 | p = XPROCESS (proc); |
| @@ -6384,31 +6513,10 @@ Otherwise it discards the output. */) | |||
| 6384 | Lisp_Object old_read_only; | 6513 | Lisp_Object old_read_only; |
| 6385 | ptrdiff_t old_begv, old_zv; | 6514 | ptrdiff_t old_begv, old_zv; |
| 6386 | ptrdiff_t before, before_byte; | 6515 | ptrdiff_t before, before_byte; |
| 6387 | ptrdiff_t opoint_byte; | 6516 | ptrdiff_t opoint, opoint_byte; |
| 6388 | struct buffer *b; | ||
| 6389 | |||
| 6390 | Fset_buffer (p->buffer); | ||
| 6391 | opoint = PT; | ||
| 6392 | opoint_byte = PT_BYTE; | ||
| 6393 | old_read_only = BVAR (current_buffer, read_only); | ||
| 6394 | old_begv = BEGV; | ||
| 6395 | old_zv = ZV; | ||
| 6396 | |||
| 6397 | bset_read_only (current_buffer, Qnil); | ||
| 6398 | |||
| 6399 | /* Insert new output into buffer at the current end-of-output | ||
| 6400 | marker, thus preserving logical ordering of input and output. */ | ||
| 6401 | if (XMARKER (p->mark)->buffer) | ||
| 6402 | set_point_from_marker (p->mark); | ||
| 6403 | else | ||
| 6404 | SET_PT_BOTH (ZV, ZV_BYTE); | ||
| 6405 | before = PT; | ||
| 6406 | before_byte = PT_BYTE; | ||
| 6407 | 6517 | ||
| 6408 | /* If the output marker is outside of the visible region, save | 6518 | read_process_output_before_insert (p, &old_read_only, &old_begv, &old_zv, |
| 6409 | the restriction and widen. */ | 6519 | &before, &before_byte, &opoint, &opoint_byte); |
| 6410 | if (! (BEGV <= PT && PT <= ZV)) | ||
| 6411 | Fwiden (); | ||
| 6412 | 6520 | ||
| 6413 | /* Adjust the multibyteness of TEXT to that of the buffer. */ | 6521 | /* Adjust the multibyteness of TEXT to that of the buffer. */ |
| 6414 | if (NILP (BVAR (current_buffer, enable_multibyte_characters)) | 6522 | if (NILP (BVAR (current_buffer, enable_multibyte_characters)) |
| @@ -6421,35 +6529,8 @@ Otherwise it discards the output. */) | |||
| 6421 | insert_from_string_before_markers (text, 0, 0, | 6529 | insert_from_string_before_markers (text, 0, 0, |
| 6422 | SCHARS (text), SBYTES (text), 0); | 6530 | SCHARS (text), SBYTES (text), 0); |
| 6423 | 6531 | ||
| 6424 | /* Make sure the process marker's position is valid when the | 6532 | read_process_output_after_insert (p, &old_read_only, old_begv, old_zv, |
| 6425 | process buffer is changed in the signal_after_change above. | 6533 | before, before_byte, opoint, opoint_byte); |
| 6426 | W3 is known to do that. */ | ||
| 6427 | if (BUFFERP (p->buffer) | ||
| 6428 | && (b = XBUFFER (p->buffer), b != current_buffer)) | ||
| 6429 | set_marker_both (p->mark, p->buffer, BUF_PT (b), BUF_PT_BYTE (b)); | ||
| 6430 | else | ||
| 6431 | set_marker_both (p->mark, p->buffer, PT, PT_BYTE); | ||
| 6432 | |||
| 6433 | update_mode_lines = 23; | ||
| 6434 | |||
| 6435 | /* Make sure opoint and the old restrictions | ||
| 6436 | float ahead of any new text just as point would. */ | ||
| 6437 | if (opoint >= before) | ||
| 6438 | { | ||
| 6439 | opoint += PT - before; | ||
| 6440 | opoint_byte += PT_BYTE - before_byte; | ||
| 6441 | } | ||
| 6442 | if (old_begv > before) | ||
| 6443 | old_begv += PT - before; | ||
| 6444 | if (old_zv >= before) | ||
| 6445 | old_zv += PT - before; | ||
| 6446 | |||
| 6447 | /* If the restriction isn't what it should be, set it. */ | ||
| 6448 | if (old_begv != BEGV || old_zv != ZV) | ||
| 6449 | Fnarrow_to_region (make_fixnum (old_begv), make_fixnum (old_zv)); | ||
| 6450 | |||
| 6451 | bset_read_only (current_buffer, old_read_only); | ||
| 6452 | SET_PT_BOTH (opoint, opoint_byte); | ||
| 6453 | } | 6534 | } |
| 6454 | return Qnil; | 6535 | return Qnil; |
| 6455 | } | 6536 | } |
| @@ -8799,6 +8880,13 @@ On GNU/Linux systems, the value should not exceed | |||
| 8799 | /proc/sys/fs/pipe-max-size. See pipe(7) manpage for details. */); | 8880 | /proc/sys/fs/pipe-max-size. See pipe(7) manpage for details. */); |
| 8800 | read_process_output_max = 4096; | 8881 | read_process_output_max = 4096; |
| 8801 | 8882 | ||
| 8883 | DEFVAR_BOOL ("read-process-output-fast", read_process_output_fast, | ||
| 8884 | doc: /* Non-nil to optimize the insertion of process output. | ||
| 8885 | We skip calling `internal-default-process-filter' and don't allocate | ||
| 8886 | the Lisp string that would be used as its argument. Only affects the | ||
| 8887 | case of asynchronous process with the default filter. */); | ||
| 8888 | read_process_output_fast = Qt; | ||
| 8889 | |||
| 8802 | DEFVAR_INT ("process-error-pause-time", process_error_pause_time, | 8890 | DEFVAR_INT ("process-error-pause-time", process_error_pause_time, |
| 8803 | doc: /* The number of seconds to pause after handling process errors. | 8891 | doc: /* The number of seconds to pause after handling process errors. |
| 8804 | This isn't used for all process-related errors, but is used when a | 8892 | This isn't used for all process-related errors, but is used when a |