diff options
| author | Troels Nielsen | 2012-06-17 17:00:37 +0800 |
|---|---|---|
| committer | Chong Yidong | 2012-06-17 17:00:37 +0800 |
| commit | 20ca2e9451e7dbae9b24bf759c4374a674c9270a (patch) | |
| tree | 869520c949ccfcf28c3d480de8007937363c816c /src | |
| parent | 48d1354eb8e8e7dc759400a2f001d02587f15be2 (diff) | |
| download | emacs-20ca2e9451e7dbae9b24bf759c4374a674c9270a.tar.gz emacs-20ca2e9451e7dbae9b24bf759c4374a674c9270a.zip | |
Ensure correct ordering of process writes.
* process.c (make_process): Initialize write_queue.
(write_queue_push, write_queue_pop): New functions.
(send_process): Use them to maintain correct ordering of process writes.
Fixes: debbugs:10815
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 7 | ||||
| -rw-r--r-- | src/process.c | 134 | ||||
| -rw-r--r-- | src/process.h | 2 |
3 files changed, 113 insertions, 30 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 84be53f43d6..ba029611cdb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | 2012-06-17 Troels Nielsen <bn.troels@gmail.com> | ||
| 2 | |||
| 3 | * process.c (make_process): Initialize write_queue. | ||
| 4 | (write_queue_push, write_queue_pop): New functions. | ||
| 5 | (send_process): Use them to maintain correct ordering of process | ||
| 6 | writes (Bug#10815). | ||
| 7 | |||
| 1 | 2012-06-17 Paul Eggert <eggert@cs.ucla.edu> | 8 | 2012-06-17 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 9 | ||
| 3 | * lisp.h (eassert): Assume C89 or later. | 10 | * lisp.h (eassert): Assume C89 or later. |
diff --git a/src/process.c b/src/process.c index 6e454db6b4c..0434caf7574 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -638,6 +638,7 @@ make_process (Lisp_Object name) | |||
| 638 | p->status = Qrun; | 638 | p->status = Qrun; |
| 639 | p->mark = Fmake_marker (); | 639 | p->mark = Fmake_marker (); |
| 640 | p->kill_without_query = 0; | 640 | p->kill_without_query = 0; |
| 641 | p->write_queue = Qnil; | ||
| 641 | 642 | ||
| 642 | #ifdef ADAPTIVE_READ_BUFFERING | 643 | #ifdef ADAPTIVE_READ_BUFFERING |
| 643 | p->adaptive_read_buffering = 0; | 644 | p->adaptive_read_buffering = 0; |
| @@ -5371,6 +5372,78 @@ send_process_trap (int ignore) | |||
| 5371 | longjmp (send_process_frame, 1); | 5372 | longjmp (send_process_frame, 1); |
| 5372 | } | 5373 | } |
| 5373 | 5374 | ||
| 5375 | /* In send_process, when a write fails temporarily, | ||
| 5376 | wait_reading_process_output is called. It may execute user code, | ||
| 5377 | e.g. timers, that attempts to write new data to the same process. | ||
| 5378 | We must ensure that data is sent in the right order, and not | ||
| 5379 | interspersed half-completed with other writes (Bug#10815). This is | ||
| 5380 | handled by the write_queue element of struct process. It is a list | ||
| 5381 | with each entry having the form | ||
| 5382 | |||
| 5383 | (string . (offset . length)) | ||
| 5384 | |||
| 5385 | where STRING is a lisp string, OFFSET is the offset into the | ||
| 5386 | string's byte sequence from which we should begin to send, and | ||
| 5387 | LENGTH is the number of bytes left to send. */ | ||
| 5388 | |||
| 5389 | /* Create a new entry in write_queue. | ||
| 5390 | INPUT_OBJ should be a buffer, string Qt, or Qnil. | ||
| 5391 | BUF is a pointer to the string sequence of the input_obj or a C | ||
| 5392 | string in case of Qt or Qnil. */ | ||
| 5393 | |||
| 5394 | static void | ||
| 5395 | write_queue_push (struct Lisp_Process *p, Lisp_Object input_obj, | ||
| 5396 | const char *buf, int len, int front) | ||
| 5397 | { | ||
| 5398 | EMACS_INT offset; | ||
| 5399 | Lisp_Object entry, obj; | ||
| 5400 | |||
| 5401 | if (STRINGP (input_obj)) | ||
| 5402 | { | ||
| 5403 | offset = buf - SSDATA (input_obj); | ||
| 5404 | obj = input_obj; | ||
| 5405 | } | ||
| 5406 | else | ||
| 5407 | { | ||
| 5408 | offset = 0; | ||
| 5409 | obj = make_unibyte_string (buf, len); | ||
| 5410 | } | ||
| 5411 | |||
| 5412 | entry = Fcons (obj, Fcons (make_number (offset), make_number (len))); | ||
| 5413 | |||
| 5414 | if (front) | ||
| 5415 | p->write_queue = Fcons (entry, p->write_queue); | ||
| 5416 | else | ||
| 5417 | p->write_queue = nconc2 (p->write_queue, Fcons (entry, Qnil)); | ||
| 5418 | } | ||
| 5419 | |||
| 5420 | /* Remove the first element in the write_queue of process P, put its | ||
| 5421 | contents in OBJ, BUF and LEN, and return non-zero. If the | ||
| 5422 | write_queue is empty, return zero. */ | ||
| 5423 | |||
| 5424 | static int | ||
| 5425 | write_queue_pop (struct Lisp_Process *p, Lisp_Object *obj, | ||
| 5426 | const char **buf, EMACS_INT *len) | ||
| 5427 | { | ||
| 5428 | Lisp_Object entry, offset_length; | ||
| 5429 | EMACS_INT offset; | ||
| 5430 | |||
| 5431 | if (NILP (p->write_queue)) | ||
| 5432 | return 0; | ||
| 5433 | |||
| 5434 | entry = XCAR (p->write_queue); | ||
| 5435 | p->write_queue = XCDR (p->write_queue); | ||
| 5436 | |||
| 5437 | *obj = XCAR (entry); | ||
| 5438 | offset_length = XCDR (entry); | ||
| 5439 | |||
| 5440 | *len = XINT (XCDR (offset_length)); | ||
| 5441 | offset = XINT (XCAR (offset_length)); | ||
| 5442 | *buf = SDATA (*obj) + offset; | ||
| 5443 | |||
| 5444 | return 1; | ||
| 5445 | } | ||
| 5446 | |||
| 5374 | /* Send some data to process PROC. | 5447 | /* Send some data to process PROC. |
| 5375 | BUF is the beginning of the data; LEN is the number of characters. | 5448 | BUF is the beginning of the data; LEN is the number of characters. |
| 5376 | OBJECT is the Lisp object that the data comes from. If OBJECT is | 5449 | OBJECT is the Lisp object that the data comes from. If OBJECT is |
| @@ -5389,11 +5462,8 @@ send_process (volatile Lisp_Object proc, const char *volatile buf, | |||
| 5389 | struct Lisp_Process *p = XPROCESS (proc); | 5462 | struct Lisp_Process *p = XPROCESS (proc); |
| 5390 | ssize_t rv; | 5463 | ssize_t rv; |
| 5391 | struct coding_system *coding; | 5464 | struct coding_system *coding; |
| 5392 | struct gcpro gcpro1; | ||
| 5393 | void (*volatile old_sigpipe) (int); | 5465 | void (*volatile old_sigpipe) (int); |
| 5394 | 5466 | ||
| 5395 | GCPRO1 (object); | ||
| 5396 | |||
| 5397 | if (p->raw_status_new) | 5467 | if (p->raw_status_new) |
| 5398 | update_status (p); | 5468 | update_status (p); |
| 5399 | if (! EQ (p->status, Qrun)) | 5469 | if (! EQ (p->status, Qrun)) |
| @@ -5505,22 +5575,37 @@ send_process (volatile Lisp_Object proc, const char *volatile buf, | |||
| 5505 | if (!setjmp (send_process_frame)) | 5575 | if (!setjmp (send_process_frame)) |
| 5506 | { | 5576 | { |
| 5507 | p = XPROCESS (proc); /* Repair any setjmp clobbering. */ | 5577 | p = XPROCESS (proc); /* Repair any setjmp clobbering. */ |
| 5508 | |||
| 5509 | process_sent_to = proc; | 5578 | process_sent_to = proc; |
| 5510 | while (len > 0) | 5579 | |
| 5580 | /* If there is already data in the write_queue, put the new data | ||
| 5581 | in the back of queue. Otherwise, ignore it. */ | ||
| 5582 | if (!NILP (p->write_queue)) | ||
| 5583 | write_queue_push (p, object, buf, len, 0); | ||
| 5584 | |||
| 5585 | do /* while !NILP (p->write_queue) */ | ||
| 5511 | { | 5586 | { |
| 5512 | ptrdiff_t this = len; | 5587 | EMACS_INT cur_len = -1; |
| 5588 | const char *cur_buf; | ||
| 5589 | Lisp_Object cur_object; | ||
| 5590 | |||
| 5591 | /* If write_queue is empty, ignore it. */ | ||
| 5592 | if (!write_queue_pop (p, &cur_object, &cur_buf, &cur_len)) | ||
| 5593 | { | ||
| 5594 | cur_len = len; | ||
| 5595 | cur_buf = buf; | ||
| 5596 | cur_object = object; | ||
| 5597 | } | ||
| 5513 | 5598 | ||
| 5514 | /* Send this batch, using one or more write calls. */ | 5599 | while (cur_len > 0) |
| 5515 | while (this > 0) | ||
| 5516 | { | 5600 | { |
| 5601 | /* Send this batch, using one or more write calls. */ | ||
| 5517 | ptrdiff_t written = 0; | 5602 | ptrdiff_t written = 0; |
| 5518 | int outfd = p->outfd; | 5603 | int outfd = p->outfd; |
| 5519 | old_sigpipe = (void (*) (int)) signal (SIGPIPE, send_process_trap); | 5604 | old_sigpipe = (void (*) (int)) signal (SIGPIPE, send_process_trap); |
| 5520 | #ifdef DATAGRAM_SOCKETS | 5605 | #ifdef DATAGRAM_SOCKETS |
| 5521 | if (DATAGRAM_CHAN_P (outfd)) | 5606 | if (DATAGRAM_CHAN_P (outfd)) |
| 5522 | { | 5607 | { |
| 5523 | rv = sendto (outfd, buf, this, | 5608 | rv = sendto (outfd, cur_buf, cur_len, |
| 5524 | 0, datagram_address[outfd].sa, | 5609 | 0, datagram_address[outfd].sa, |
| 5525 | datagram_address[outfd].len); | 5610 | datagram_address[outfd].len); |
| 5526 | if (0 <= rv) | 5611 | if (0 <= rv) |
| @@ -5537,10 +5622,10 @@ send_process (volatile Lisp_Object proc, const char *volatile buf, | |||
| 5537 | { | 5622 | { |
| 5538 | #ifdef HAVE_GNUTLS | 5623 | #ifdef HAVE_GNUTLS |
| 5539 | if (p->gnutls_p) | 5624 | if (p->gnutls_p) |
| 5540 | written = emacs_gnutls_write (p, buf, this); | 5625 | written = emacs_gnutls_write (p, cur_buf, cur_len); |
| 5541 | else | 5626 | else |
| 5542 | #endif | 5627 | #endif |
| 5543 | written = emacs_write (outfd, buf, this); | 5628 | written = emacs_write (outfd, cur_buf, cur_len); |
| 5544 | rv = (written ? 0 : -1); | 5629 | rv = (written ? 0 : -1); |
| 5545 | #ifdef ADAPTIVE_READ_BUFFERING | 5630 | #ifdef ADAPTIVE_READ_BUFFERING |
| 5546 | if (p->read_output_delay > 0 | 5631 | if (p->read_output_delay > 0 |
| @@ -5595,35 +5680,26 @@ send_process (volatile Lisp_Object proc, const char *volatile buf, | |||
| 5595 | } | 5680 | } |
| 5596 | #endif /* BROKEN_PTY_READ_AFTER_EAGAIN */ | 5681 | #endif /* BROKEN_PTY_READ_AFTER_EAGAIN */ |
| 5597 | 5682 | ||
| 5598 | /* Running filters might relocate buffers or strings. | 5683 | /* Put what we should have written in |
| 5599 | Arrange to relocate BUF. */ | 5684 | wait_queue */ |
| 5600 | if (BUFFERP (object)) | 5685 | write_queue_push (p, cur_object, cur_buf, cur_len, 1); |
| 5601 | offset = BUF_PTR_BYTE_POS (XBUFFER (object), | ||
| 5602 | (unsigned char *) buf); | ||
| 5603 | else if (STRINGP (object)) | ||
| 5604 | offset = buf - SSDATA (object); | ||
| 5605 | |||
| 5606 | #ifdef EMACS_HAS_USECS | 5686 | #ifdef EMACS_HAS_USECS |
| 5607 | wait_reading_process_output (0, 20000, 0, 0, Qnil, NULL, 0); | 5687 | wait_reading_process_output (0, 20000, 0, 0, Qnil, NULL, 0); |
| 5608 | #else | 5688 | #else |
| 5609 | wait_reading_process_output (1, 0, 0, 0, Qnil, NULL, 0); | 5689 | wait_reading_process_output (1, 0, 0, 0, Qnil, NULL, 0); |
| 5610 | #endif | 5690 | #endif |
| 5611 | 5691 | /* reread queue, to see what is left */ | |
| 5612 | if (BUFFERP (object)) | 5692 | break; |
| 5613 | buf = (char *) BUF_BYTE_ADDRESS (XBUFFER (object), | ||
| 5614 | offset); | ||
| 5615 | else if (STRINGP (object)) | ||
| 5616 | buf = offset + SSDATA (object); | ||
| 5617 | } | 5693 | } |
| 5618 | else | 5694 | else |
| 5619 | /* This is a real error. */ | 5695 | /* This is a real error. */ |
| 5620 | report_file_error ("writing to process", Fcons (proc, Qnil)); | 5696 | report_file_error ("writing to process", Fcons (proc, Qnil)); |
| 5621 | } | 5697 | } |
| 5622 | buf += written; | 5698 | cur_buf += written; |
| 5623 | len -= written; | 5699 | cur_len -= written; |
| 5624 | this -= written; | ||
| 5625 | } | 5700 | } |
| 5626 | } | 5701 | } |
| 5702 | while (!NILP (p->write_queue)); | ||
| 5627 | } | 5703 | } |
| 5628 | else | 5704 | else |
| 5629 | { | 5705 | { |
| @@ -5636,8 +5712,6 @@ send_process (volatile Lisp_Object proc, const char *volatile buf, | |||
| 5636 | deactivate_process (proc); | 5712 | deactivate_process (proc); |
| 5637 | error ("SIGPIPE raised on process %s; closed it", SDATA (p->name)); | 5713 | error ("SIGPIPE raised on process %s; closed it", SDATA (p->name)); |
| 5638 | } | 5714 | } |
| 5639 | |||
| 5640 | UNGCPRO; | ||
| 5641 | } | 5715 | } |
| 5642 | 5716 | ||
| 5643 | DEFUN ("process-send-region", Fprocess_send_region, Sprocess_send_region, | 5717 | DEFUN ("process-send-region", Fprocess_send_region, Sprocess_send_region, |
diff --git a/src/process.h b/src/process.h index edb937893b0..ae4b6b61c94 100644 --- a/src/process.h +++ b/src/process.h | |||
| @@ -77,6 +77,8 @@ struct Lisp_Process | |||
| 77 | Lisp_Object encode_coding_system; | 77 | Lisp_Object encode_coding_system; |
| 78 | /* Working buffer for encoding. */ | 78 | /* Working buffer for encoding. */ |
| 79 | Lisp_Object encoding_buf; | 79 | Lisp_Object encoding_buf; |
| 80 | /* Queue for storing waiting writes */ | ||
| 81 | Lisp_Object write_queue; | ||
| 80 | 82 | ||
| 81 | #ifdef HAVE_GNUTLS | 83 | #ifdef HAVE_GNUTLS |
| 82 | Lisp_Object gnutls_cred_type; | 84 | Lisp_Object gnutls_cred_type; |