Mercurial > vim
comparison src/channel.c @ 10279:c5c15c818bda v8.0.0036
commit https://github.com/vim/vim/commit/97792de2762cc79cc365a8a0b858f27753179577
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Oct 15 18:36:49 2016 +0200
patch 8.0.0036
Problem: Detecting that a job has finished may take a while.
Solution: Check for a finished job more often (Ozaki Kiichi)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 15 Oct 2016 18:45:04 +0200 |
parents | a09db7a4afe0 |
children | 88331ee68367 |
comparison
equal
deleted
inserted
replaced
10278:abb9c83e2b7c | 10279:c5c15c818bda |
---|---|
4426 job_free_contents(job); | 4426 job_free_contents(job); |
4427 job_free_job(job); | 4427 job_free_job(job); |
4428 } | 4428 } |
4429 } | 4429 } |
4430 | 4430 |
4431 static void | |
4432 job_cleanup(job_T *job) | |
4433 { | |
4434 if (job->jv_status != JOB_ENDED) | |
4435 return; | |
4436 | |
4437 if (job->jv_exit_cb != NULL) | |
4438 { | |
4439 typval_T argv[3]; | |
4440 typval_T rettv; | |
4441 int dummy; | |
4442 | |
4443 /* invoke the exit callback; make sure the refcount is > 0 */ | |
4444 ++job->jv_refcount; | |
4445 argv[0].v_type = VAR_JOB; | |
4446 argv[0].vval.v_job = job; | |
4447 argv[1].v_type = VAR_NUMBER; | |
4448 argv[1].vval.v_number = job->jv_exitval; | |
4449 call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb), | |
4450 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, | |
4451 job->jv_exit_partial, NULL); | |
4452 clear_tv(&rettv); | |
4453 --job->jv_refcount; | |
4454 channel_need_redraw = TRUE; | |
4455 } | |
4456 if (job->jv_refcount == 0) | |
4457 { | |
4458 /* The job was already unreferenced, now that it ended it can be | |
4459 * freed. Careful: caller must not use "job" after this! */ | |
4460 job_free(job); | |
4461 } | |
4462 } | |
4463 | |
4431 #if defined(EXITFREE) || defined(PROTO) | 4464 #if defined(EXITFREE) || defined(PROTO) |
4432 void | 4465 void |
4433 job_free_all(void) | 4466 job_free_all(void) |
4434 { | 4467 { |
4435 while (first_job != NULL) | 4468 while (first_job != NULL) |
4443 * or when the associated channel will do something with the job output. | 4476 * or when the associated channel will do something with the job output. |
4444 */ | 4477 */ |
4445 static int | 4478 static int |
4446 job_still_useful(job_T *job) | 4479 job_still_useful(job_T *job) |
4447 { | 4480 { |
4448 return job->jv_status == JOB_STARTED | 4481 return (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL |
4449 && (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL | 4482 || (job->jv_channel != NULL |
4450 || (job->jv_channel != NULL | 4483 && channel_still_useful(job->jv_channel))); |
4451 && channel_still_useful(job->jv_channel))); | 4484 } |
4485 | |
4486 static int | |
4487 job_still_alive(job_T *job) | |
4488 { | |
4489 return (job->jv_status == JOB_STARTED) && job_still_useful(job); | |
4452 } | 4490 } |
4453 | 4491 |
4454 /* | 4492 /* |
4455 * Mark references in jobs that are still useful. | 4493 * Mark references in jobs that are still useful. |
4456 */ | 4494 */ |
4460 int abort = FALSE; | 4498 int abort = FALSE; |
4461 job_T *job; | 4499 job_T *job; |
4462 typval_T tv; | 4500 typval_T tv; |
4463 | 4501 |
4464 for (job = first_job; job != NULL; job = job->jv_next) | 4502 for (job = first_job; job != NULL; job = job->jv_next) |
4465 if (job_still_useful(job)) | 4503 if (job_still_alive(job)) |
4466 { | 4504 { |
4467 tv.v_type = VAR_JOB; | 4505 tv.v_type = VAR_JOB; |
4468 tv.vval.v_job = job; | 4506 tv.vval.v_job = job; |
4469 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); | 4507 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); |
4470 } | 4508 } |
4476 { | 4514 { |
4477 if (job != NULL && --job->jv_refcount <= 0) | 4515 if (job != NULL && --job->jv_refcount <= 0) |
4478 { | 4516 { |
4479 /* Do not free the job when it has not ended yet and there is a | 4517 /* Do not free the job when it has not ended yet and there is a |
4480 * "stoponexit" flag or an exit callback. */ | 4518 * "stoponexit" flag or an exit callback. */ |
4481 if (!job_still_useful(job)) | 4519 if (!job_still_alive(job)) |
4482 { | 4520 { |
4483 job_free(job); | 4521 job_free(job); |
4484 } | 4522 } |
4485 else if (job->jv_channel != NULL | 4523 else if (job->jv_channel != NULL |
4486 && !channel_still_useful(job->jv_channel)) | 4524 && !channel_still_useful(job->jv_channel)) |
4501 int did_free = FALSE; | 4539 int did_free = FALSE; |
4502 job_T *job; | 4540 job_T *job; |
4503 | 4541 |
4504 for (job = first_job; job != NULL; job = job->jv_next) | 4542 for (job = first_job; job != NULL; job = job->jv_next) |
4505 if ((job->jv_copyID & mask) != (copyID & mask) | 4543 if ((job->jv_copyID & mask) != (copyID & mask) |
4506 && !job_still_useful(job)) | 4544 && !job_still_alive(job)) |
4507 { | 4545 { |
4508 /* Free the channel and ordinary items it contains, but don't | 4546 /* Free the channel and ordinary items it contains, but don't |
4509 * recurse into Lists, Dictionaries etc. */ | 4547 * recurse into Lists, Dictionaries etc. */ |
4510 job_free_contents(job); | 4548 job_free_contents(job); |
4511 did_free = TRUE; | 4549 did_free = TRUE; |
4521 | 4559 |
4522 for (job = first_job; job != NULL; job = job_next) | 4560 for (job = first_job; job != NULL; job = job_next) |
4523 { | 4561 { |
4524 job_next = job->jv_next; | 4562 job_next = job->jv_next; |
4525 if ((job->jv_copyID & mask) != (copyID & mask) | 4563 if ((job->jv_copyID & mask) != (copyID & mask) |
4526 && !job_still_useful(job)) | 4564 && !job_still_alive(job)) |
4527 { | 4565 { |
4528 /* Free the job struct itself. */ | 4566 /* Free the job struct itself. */ |
4529 job_free_job(job); | 4567 job_free_job(job); |
4530 } | 4568 } |
4531 } | 4569 } |
4612 has_pending_job(void) | 4650 has_pending_job(void) |
4613 { | 4651 { |
4614 job_T *job; | 4652 job_T *job; |
4615 | 4653 |
4616 for (job = first_job; job != NULL; job = job->jv_next) | 4654 for (job = first_job; job != NULL; job = job->jv_next) |
4617 if (job->jv_status == JOB_STARTED && job_still_useful(job)) | 4655 if (job_still_alive(job)) |
4618 return TRUE; | 4656 return TRUE; |
4619 return FALSE; | 4657 return FALSE; |
4620 } | 4658 } |
4621 | 4659 |
4660 #define MAX_CHECK_ENDED 8 | |
4661 | |
4622 /* | 4662 /* |
4623 * Called once in a while: check if any jobs that seem useful have ended. | 4663 * Called once in a while: check if any jobs that seem useful have ended. |
4624 */ | 4664 */ |
4625 void | 4665 void |
4626 job_check_ended(void) | 4666 job_check_ended(void) |
4627 { | 4667 { |
4628 static time_t last_check = 0; | 4668 int i; |
4629 time_t now; | 4669 |
4630 job_T *job; | 4670 for (i = 0; i < MAX_CHECK_ENDED; ++i) |
4631 job_T *next; | 4671 { |
4632 | 4672 job_T *job = mch_detect_ended_job(first_job); |
4633 /* Only do this once in 10 seconds. */ | 4673 |
4634 now = time(NULL); | 4674 if (job == NULL) |
4635 if (last_check + 10 < now) | 4675 break; |
4636 { | 4676 if (job_still_useful(job)) |
4637 last_check = now; | 4677 job_cleanup(job); /* may free "job" */ |
4638 for (job = first_job; job != NULL; job = next) | 4678 } |
4639 { | 4679 |
4640 next = job->jv_next; | |
4641 if (job->jv_status == JOB_STARTED && job_still_useful(job)) | |
4642 job_status(job); /* may free "job" */ | |
4643 } | |
4644 } | |
4645 if (channel_need_redraw) | 4680 if (channel_need_redraw) |
4646 { | 4681 { |
4647 channel_need_redraw = FALSE; | 4682 channel_need_redraw = FALSE; |
4648 redraw_after_callback(); | 4683 redraw_after_callback(); |
4649 } | 4684 } |
4860 result = "fail"; | 4895 result = "fail"; |
4861 else | 4896 else |
4862 { | 4897 { |
4863 result = mch_job_status(job); | 4898 result = mch_job_status(job); |
4864 if (job->jv_status == JOB_ENDED) | 4899 if (job->jv_status == JOB_ENDED) |
4865 ch_log(job->jv_channel, "Job ended"); | 4900 job_cleanup(job); |
4866 if (job->jv_status == JOB_ENDED && job->jv_exit_cb != NULL) | |
4867 { | |
4868 typval_T argv[3]; | |
4869 typval_T rettv; | |
4870 int dummy; | |
4871 | |
4872 /* invoke the exit callback; make sure the refcount is > 0 */ | |
4873 ++job->jv_refcount; | |
4874 argv[0].v_type = VAR_JOB; | |
4875 argv[0].vval.v_job = job; | |
4876 argv[1].v_type = VAR_NUMBER; | |
4877 argv[1].vval.v_number = job->jv_exitval; | |
4878 call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb), | |
4879 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, | |
4880 job->jv_exit_partial, NULL); | |
4881 clear_tv(&rettv); | |
4882 --job->jv_refcount; | |
4883 channel_need_redraw = TRUE; | |
4884 } | |
4885 if (job->jv_status == JOB_ENDED && job->jv_refcount == 0) | |
4886 { | |
4887 /* The job was already unreferenced, now that it ended it can be | |
4888 * freed. Careful: caller must not use "job" after this! */ | |
4889 job_free(job); | |
4890 } | |
4891 } | 4901 } |
4892 return result; | 4902 return result; |
4893 } | 4903 } |
4894 | 4904 |
4895 /* | 4905 /* |