Mercurial > vim
comparison src/os_unix.c @ 9205:c19eb05b19df v7.4.1886
commit https://github.com/vim/vim/commit/cda7764d8e65325d4524e5d6c3174121eeb12cad
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Jun 4 13:32:35 2016 +0200
patch 7.4.1886
Problem: When waiting for a character is interrupted by receiving channel
data and the first character of a mapping was typed, the mapping
times out. (Ramel Eshed)
Solution: When dealing with channel data don't return from mch_inchar().
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 04 Jun 2016 13:45:05 +0200 |
parents | 4b55d8e162d4 |
children | 61e669c5da6f |
comparison
equal
deleted
inserted
replaced
9204:61b9dfe91682 | 9205:c19eb05b19df |
---|---|
173 #else | 173 #else |
174 typedef int waitstatus; | 174 typedef int waitstatus; |
175 #endif | 175 #endif |
176 static pid_t wait4pid(pid_t, waitstatus *); | 176 static pid_t wait4pid(pid_t, waitstatus *); |
177 | 177 |
178 static int WaitForChar(long); | 178 static int WaitForChar(long msec, int *interrupted); |
179 static int WaitForCharOrMouse(long, int *break_loop); | 179 static int WaitForCharOrMouse(long msec, int *interrupted); |
180 #if defined(__BEOS__) || defined(VMS) | 180 #if defined(__BEOS__) || defined(VMS) |
181 int RealWaitForChar(int, long, int *, int *break_loop); | 181 int RealWaitForChar(int, long, int *, int *interrupted); |
182 #else | 182 #else |
183 static int RealWaitForChar(int, long, int *, int *break_loop); | 183 static int RealWaitForChar(int, long, int *, int *interrupted); |
184 #endif | 184 #endif |
185 | 185 |
186 #ifdef FEAT_XCLIPBOARD | 186 #ifdef FEAT_XCLIPBOARD |
187 static int do_xterm_trace(void); | 187 static int do_xterm_trace(void); |
188 # define XT_TRACE_DELAY 50 /* delay for xterm tracing */ | 188 # define XT_TRACE_DELAY 50 /* delay for xterm tracing */ |
383 int maxlen, | 383 int maxlen, |
384 long wtime, /* don't use "time", MIPS cannot handle it */ | 384 long wtime, /* don't use "time", MIPS cannot handle it */ |
385 int tb_change_cnt) | 385 int tb_change_cnt) |
386 { | 386 { |
387 int len; | 387 int len; |
388 int interrupted = FALSE; | |
388 | 389 |
389 #ifdef MESSAGE_QUEUE | 390 #ifdef MESSAGE_QUEUE |
390 parse_queued_messages(); | 391 parse_queued_messages(); |
391 #endif | 392 #endif |
392 | 393 |
395 while (do_resize) | 396 while (do_resize) |
396 handle_resize(); | 397 handle_resize(); |
397 | 398 |
398 if (wtime >= 0) | 399 if (wtime >= 0) |
399 { | 400 { |
400 while (!WaitForChar(wtime)) /* no character available */ | 401 /* TODO: when looping reduce wtime by the elapsed time. */ |
401 { | 402 while (!WaitForChar(wtime, &interrupted)) |
403 { | |
404 /* no character available */ | |
402 if (do_resize) | 405 if (do_resize) |
406 { | |
403 handle_resize(); | 407 handle_resize(); |
408 continue; | |
409 } | |
404 #ifdef FEAT_CLIENTSERVER | 410 #ifdef FEAT_CLIENTSERVER |
405 else if (!server_waiting()) | 411 if (server_waiting()) |
406 #else | 412 { |
407 else | 413 parse_queued_messages(); |
408 #endif | 414 continue; |
409 /* return if not interrupted by resize or server */ | 415 } |
410 return 0; | 416 #endif |
411 #ifdef MESSAGE_QUEUE | 417 #ifdef MESSAGE_QUEUE |
412 parse_queued_messages(); | 418 if (interrupted) |
413 #endif | 419 { |
420 parse_queued_messages(); | |
421 continue; | |
422 } | |
423 #endif | |
424 /* return if not interrupted by resize or server */ | |
425 return 0; | |
414 } | 426 } |
415 } | 427 } |
416 else /* wtime == -1 */ | 428 else /* wtime == -1 */ |
417 { | 429 { |
418 /* | 430 /* |
419 * If there is no character available within 'updatetime' seconds | 431 * If there is no character available within 'updatetime' seconds |
420 * flush all the swap files to disk. | 432 * flush all the swap files to disk. |
421 * Also done when interrupted by SIGWINCH. | 433 * Also done when interrupted by SIGWINCH. |
422 */ | 434 */ |
423 if (!WaitForChar(p_ut)) | 435 if (!WaitForChar(p_ut, &interrupted)) |
424 { | 436 { |
437 /* TODO: if interrupted is set loop to wait the remaining time. */ | |
425 #ifdef FEAT_AUTOCMD | 438 #ifdef FEAT_AUTOCMD |
426 if (trigger_cursorhold() && maxlen >= 3 | 439 if (trigger_cursorhold() && maxlen >= 3 |
427 && !typebuf_changed(tb_change_cnt)) | 440 && !typebuf_changed(tb_change_cnt)) |
428 { | 441 { |
429 buf[0] = K_SPECIAL; | 442 buf[0] = K_SPECIAL; |
434 #endif | 447 #endif |
435 before_blocking(); | 448 before_blocking(); |
436 } | 449 } |
437 } | 450 } |
438 | 451 |
439 for (;;) /* repeat until we got a character */ | 452 /* repeat until we got a character */ |
453 for (;;) | |
440 { | 454 { |
441 long wtime_now = -1L; | 455 long wtime_now = -1L; |
442 | 456 |
443 while (do_resize) /* window changed size */ | 457 while (do_resize) /* window changed size */ |
444 handle_resize(); | 458 handle_resize(); |
460 #endif | 474 #endif |
461 /* | 475 /* |
462 * We want to be interrupted by the winch signal | 476 * We want to be interrupted by the winch signal |
463 * or by an event on the monitored file descriptors. | 477 * or by an event on the monitored file descriptors. |
464 */ | 478 */ |
465 if (!WaitForChar(wtime_now)) | 479 if (!WaitForChar(wtime_now, &interrupted)) |
466 { | 480 { |
467 if (do_resize) /* interrupted by SIGWINCH signal */ | 481 if (do_resize) /* interrupted by SIGWINCH signal */ |
468 handle_resize(); | 482 continue; |
483 #ifdef MESSAGE_QUEUE | |
484 if (interrupted || wtime_now > 0) | |
485 { | |
486 parse_queued_messages(); | |
487 continue; | |
488 } | |
489 #endif | |
469 return 0; | 490 return 0; |
470 } | 491 } |
471 | 492 |
472 /* If input was put directly in typeahead buffer bail out here. */ | 493 /* If input was put directly in typeahead buffer bail out here. */ |
473 if (typebuf_changed(tb_change_cnt)) | 494 if (typebuf_changed(tb_change_cnt)) |
480 * For some other terminals this is quite slow, that's why we don't do | 501 * For some other terminals this is quite slow, that's why we don't do |
481 * it. | 502 * it. |
482 */ | 503 */ |
483 len = read_from_input_buf(buf, (long)maxlen); | 504 len = read_from_input_buf(buf, (long)maxlen); |
484 if (len > 0) | 505 if (len > 0) |
485 { | |
486 return len; | 506 return len; |
487 } | |
488 } | 507 } |
489 } | 508 } |
490 | 509 |
491 static void | 510 static void |
492 handle_resize(void) | 511 handle_resize(void) |
499 * Return non-zero if a character is available. | 518 * Return non-zero if a character is available. |
500 */ | 519 */ |
501 int | 520 int |
502 mch_char_avail(void) | 521 mch_char_avail(void) |
503 { | 522 { |
504 return WaitForChar(0L); | 523 return WaitForChar(0L, NULL); |
505 } | 524 } |
506 | 525 |
507 #if defined(HAVE_TOTAL_MEM) || defined(PROTO) | 526 #if defined(HAVE_TOTAL_MEM) || defined(PROTO) |
508 # ifdef HAVE_SYS_RESOURCE_H | 527 # ifdef HAVE_SYS_RESOURCE_H |
509 # include <sys/resource.h> | 528 # include <sys/resource.h> |
689 | 708 |
690 settmode(old_tmode); | 709 settmode(old_tmode); |
691 in_mch_delay = FALSE; | 710 in_mch_delay = FALSE; |
692 } | 711 } |
693 else | 712 else |
694 WaitForChar(msec); | 713 WaitForChar(msec, NULL); |
695 } | 714 } |
696 | 715 |
697 #if defined(HAVE_STACK_LIMIT) \ | 716 #if defined(HAVE_STACK_LIMIT) \ |
698 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK)) | 717 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK)) |
699 # define HAVE_CHECK_STACK_GROWTH | 718 # define HAVE_CHECK_STACK_GROWTH |
5227 /* See above for type of argv. */ | 5246 /* See above for type of argv. */ |
5228 execvp(argv[0], argv); | 5247 execvp(argv[0], argv); |
5229 | 5248 |
5230 if (stderr_works) | 5249 if (stderr_works) |
5231 perror("executing job failed"); | 5250 perror("executing job failed"); |
5251 #ifdef EXITFREE | |
5252 /* calling free_all_mem() here causes problems. Ignore valgrind | |
5253 * reporting possibly leaked memory. */ | |
5254 #endif | |
5232 _exit(EXEC_FAILED); /* exec failed, return failure code */ | 5255 _exit(EXEC_FAILED); /* exec failed, return failure code */ |
5233 } | 5256 } |
5234 | 5257 |
5235 /* parent */ | 5258 /* parent */ |
5236 job->jv_pid = pid; | 5259 job->jv_pid = pid; |
5374 /* | 5397 /* |
5375 * Wait "msec" msec until a character is available from the mouse, keyboard, | 5398 * Wait "msec" msec until a character is available from the mouse, keyboard, |
5376 * from inbuf[]. | 5399 * from inbuf[]. |
5377 * "msec" == -1 will block forever. | 5400 * "msec" == -1 will block forever. |
5378 * Invokes timer callbacks when needed. | 5401 * Invokes timer callbacks when needed. |
5402 * "interrupted" (if not NULL) is set to TRUE when no character is available | |
5403 * but something else needs to be done. | |
5404 * Returns TRUE when a character is available. | |
5379 * When a GUI is being used, this will never get called -- webb | 5405 * When a GUI is being used, this will never get called -- webb |
5380 * Returns TRUE when a character is available. | |
5381 */ | 5406 */ |
5382 static int | 5407 static int |
5383 WaitForChar(long msec) | 5408 WaitForChar(long msec, int *interrupted) |
5384 { | 5409 { |
5385 #ifdef FEAT_TIMERS | 5410 #ifdef FEAT_TIMERS |
5386 long due_time; | 5411 long due_time; |
5387 long remaining = msec; | 5412 long remaining = msec; |
5388 int break_loop = FALSE; | |
5389 int tb_change_cnt = typebuf.tb_change_cnt; | 5413 int tb_change_cnt = typebuf.tb_change_cnt; |
5390 | 5414 |
5391 /* When waiting very briefly don't trigger timers. */ | 5415 /* When waiting very briefly don't trigger timers. */ |
5392 if (msec >= 0 && msec < 10L) | 5416 if (msec >= 0 && msec < 10L) |
5393 return WaitForCharOrMouse(msec, NULL); | 5417 return WaitForCharOrMouse(msec, NULL); |
5402 /* timer may have used feedkeys() */ | 5426 /* timer may have used feedkeys() */ |
5403 return FALSE; | 5427 return FALSE; |
5404 } | 5428 } |
5405 if (due_time <= 0 || (msec > 0 && due_time > remaining)) | 5429 if (due_time <= 0 || (msec > 0 && due_time > remaining)) |
5406 due_time = remaining; | 5430 due_time = remaining; |
5407 if (WaitForCharOrMouse(due_time, &break_loop)) | 5431 if (WaitForCharOrMouse(due_time, interrupted)) |
5408 return TRUE; | 5432 return TRUE; |
5409 if (break_loop) | 5433 if (interrupted != NULL && *interrupted) |
5410 /* Nothing available, but need to return so that side effects get | 5434 /* Nothing available, but need to return so that side effects get |
5411 * handled, such as handling a message on a channel. */ | 5435 * handled, such as handling a message on a channel. */ |
5412 return FALSE; | 5436 return FALSE; |
5413 if (msec > 0) | 5437 if (msec > 0) |
5414 remaining -= due_time; | 5438 remaining -= due_time; |
5415 } | 5439 } |
5416 return FALSE; | 5440 return FALSE; |
5417 #else | 5441 #else |
5418 return WaitForCharOrMouse(msec, NULL); | 5442 return WaitForCharOrMouse(msec, interrupted); |
5419 #endif | 5443 #endif |
5420 } | 5444 } |
5421 | 5445 |
5422 /* | 5446 /* |
5423 * Wait "msec" msec until a character is available from the mouse or keyboard | 5447 * Wait "msec" msec until a character is available from the mouse or keyboard |
5424 * or from inbuf[]. | 5448 * or from inbuf[]. |
5425 * "msec" == -1 will block forever. | 5449 * "msec" == -1 will block forever. |
5450 * "interrupted" (if not NULL) is set to TRUE when no character is available | |
5451 * but something else needs to be done. | |
5426 * When a GUI is being used, this will never get called -- webb | 5452 * When a GUI is being used, this will never get called -- webb |
5427 */ | 5453 */ |
5428 static int | 5454 static int |
5429 WaitForCharOrMouse(long msec, int *break_loop) | 5455 WaitForCharOrMouse(long msec, int *interrupted) |
5430 { | 5456 { |
5431 #ifdef FEAT_MOUSE_GPM | 5457 #ifdef FEAT_MOUSE_GPM |
5432 int gpm_process_wanted; | 5458 int gpm_process_wanted; |
5433 #endif | 5459 #endif |
5434 #ifdef FEAT_XCLIPBOARD | 5460 #ifdef FEAT_XCLIPBOARD |
5471 } | 5497 } |
5472 # endif | 5498 # endif |
5473 # ifdef FEAT_MOUSE_GPM | 5499 # ifdef FEAT_MOUSE_GPM |
5474 gpm_process_wanted = 0; | 5500 gpm_process_wanted = 0; |
5475 avail = RealWaitForChar(read_cmd_fd, msec, | 5501 avail = RealWaitForChar(read_cmd_fd, msec, |
5476 &gpm_process_wanted, break_loop); | 5502 &gpm_process_wanted, interrupted); |
5477 # else | 5503 # else |
5478 avail = RealWaitForChar(read_cmd_fd, msec, NULL, break_loop); | 5504 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted); |
5479 # endif | 5505 # endif |
5480 if (!avail) | 5506 if (!avail) |
5481 { | 5507 { |
5482 if (input_available()) | 5508 if (input_available()) |
5483 return 1; | 5509 return 1; |
5496 # endif | 5522 # endif |
5497 ) | 5523 ) |
5498 ; | 5524 ; |
5499 | 5525 |
5500 #else | 5526 #else |
5501 avail = RealWaitForChar(read_cmd_fd, msec, NULL, break_loop); | 5527 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted); |
5502 #endif | 5528 #endif |
5503 return avail; | 5529 return avail; |
5504 } | 5530 } |
5505 | 5531 |
5506 #ifndef VMS | 5532 #ifndef VMS |
5509 * "msec" == 0 will check for characters once. | 5535 * "msec" == 0 will check for characters once. |
5510 * "msec" == -1 will block until a character is available. | 5536 * "msec" == -1 will block until a character is available. |
5511 * When a GUI is being used, this will not be used for input -- webb | 5537 * When a GUI is being used, this will not be used for input -- webb |
5512 * Or when a Linux GPM mouse event is waiting. | 5538 * Or when a Linux GPM mouse event is waiting. |
5513 * Or when a clientserver message is on the queue. | 5539 * Or when a clientserver message is on the queue. |
5540 * "interrupted" (if not NULL) is set to TRUE when no character is available | |
5541 * but something else needs to be done. | |
5514 */ | 5542 */ |
5515 #if defined(__BEOS__) | 5543 #if defined(__BEOS__) |
5516 int | 5544 int |
5517 #else | 5545 #else |
5518 static int | 5546 static int |
5519 #endif | 5547 #endif |
5520 RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *break_loop) | 5548 RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted) |
5521 { | 5549 { |
5522 int ret; | 5550 int ret; |
5523 int result; | 5551 int result; |
5524 #if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME) | 5552 #if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME) |
5525 static int busy = FALSE; | 5553 static int busy = FALSE; |
5625 } | 5653 } |
5626 # endif | 5654 # endif |
5627 #ifdef FEAT_JOB_CHANNEL | 5655 #ifdef FEAT_JOB_CHANNEL |
5628 nfd = channel_poll_setup(nfd, &fds); | 5656 nfd = channel_poll_setup(nfd, &fds); |
5629 #endif | 5657 #endif |
5658 if (interrupted != NULL) | |
5659 *interrupted = FALSE; | |
5630 | 5660 |
5631 ret = poll(fds, nfd, towait); | 5661 ret = poll(fds, nfd, towait); |
5632 | 5662 |
5633 result = ret > 0 && (fds[0].revents & POLLIN); | 5663 result = ret > 0 && (fds[0].revents & POLLIN); |
5634 if (break_loop != NULL && ret > 0) | 5664 if (result == 0 && interrupted != NULL && ret > 0) |
5635 *break_loop = TRUE; | 5665 *interrupted = TRUE; |
5636 | 5666 |
5637 # ifdef FEAT_MZSCHEME | 5667 # ifdef FEAT_MZSCHEME |
5638 if (ret == 0 && mzquantum_used) | 5668 if (ret == 0 && mzquantum_used) |
5639 /* MzThreads scheduling is required and timeout occurred */ | 5669 /* MzThreads scheduling is required and timeout occurred */ |
5640 finished = FALSE; | 5670 finished = FALSE; |
5677 #ifdef FEAT_JOB_CHANNEL | 5707 #ifdef FEAT_JOB_CHANNEL |
5678 if (ret > 0) | 5708 if (ret > 0) |
5679 ret = channel_poll_check(ret, &fds); | 5709 ret = channel_poll_check(ret, &fds); |
5680 #endif | 5710 #endif |
5681 | 5711 |
5682 | |
5683 #else /* HAVE_SELECT */ | 5712 #else /* HAVE_SELECT */ |
5684 | 5713 |
5685 struct timeval tv; | 5714 struct timeval tv; |
5686 struct timeval *tvp; | 5715 struct timeval *tvp; |
5687 fd_set rfds, wfds, efds; | 5716 fd_set rfds, wfds, efds; |
5758 } | 5787 } |
5759 # endif | 5788 # endif |
5760 # ifdef FEAT_JOB_CHANNEL | 5789 # ifdef FEAT_JOB_CHANNEL |
5761 maxfd = channel_select_setup(maxfd, &rfds, &wfds); | 5790 maxfd = channel_select_setup(maxfd, &rfds, &wfds); |
5762 # endif | 5791 # endif |
5792 if (interrupted != NULL) | |
5793 *interrupted = FALSE; | |
5763 | 5794 |
5764 ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp); | 5795 ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp); |
5765 result = ret > 0 && FD_ISSET(fd, &rfds); | 5796 result = ret > 0 && FD_ISSET(fd, &rfds); |
5766 if (result) | 5797 if (result) |
5767 --ret; | 5798 --ret; |
5768 if (break_loop != NULL && ret > 0) | 5799 else if (interrupted != NULL && ret > 0) |
5769 *break_loop = TRUE; | 5800 *interrupted = TRUE; |
5770 | 5801 |
5771 # ifdef EINTR | 5802 # ifdef EINTR |
5772 if (ret == -1 && errno == EINTR) | 5803 if (ret == -1 && errno == EINTR) |
5773 { | 5804 { |
5774 /* Check whether window has been resized, EINTR may be caused by | 5805 /* Check whether window has been resized, EINTR may be caused by |