Mercurial > vim
diff 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 |
line wrap: on
line diff
--- a/src/channel.c +++ b/src/channel.c @@ -4428,6 +4428,39 @@ job_free(job_T *job) } } + static void +job_cleanup(job_T *job) +{ + if (job->jv_status != JOB_ENDED) + return; + + if (job->jv_exit_cb != NULL) + { + typval_T argv[3]; + typval_T rettv; + int dummy; + + /* invoke the exit callback; make sure the refcount is > 0 */ + ++job->jv_refcount; + argv[0].v_type = VAR_JOB; + argv[0].vval.v_job = job; + argv[1].v_type = VAR_NUMBER; + argv[1].vval.v_number = job->jv_exitval; + call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb), + &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, + job->jv_exit_partial, NULL); + clear_tv(&rettv); + --job->jv_refcount; + channel_need_redraw = TRUE; + } + if (job->jv_refcount == 0) + { + /* The job was already unreferenced, now that it ended it can be + * freed. Careful: caller must not use "job" after this! */ + job_free(job); + } +} + #if defined(EXITFREE) || defined(PROTO) void job_free_all(void) @@ -4445,10 +4478,15 @@ job_free_all(void) static int job_still_useful(job_T *job) { - return job->jv_status == JOB_STARTED - && (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL - || (job->jv_channel != NULL - && channel_still_useful(job->jv_channel))); + return (job->jv_stoponexit != NULL || job->jv_exit_cb != NULL + || (job->jv_channel != NULL + && channel_still_useful(job->jv_channel))); +} + + static int +job_still_alive(job_T *job) +{ + return (job->jv_status == JOB_STARTED) && job_still_useful(job); } /* @@ -4462,7 +4500,7 @@ set_ref_in_job(int copyID) typval_T tv; for (job = first_job; job != NULL; job = job->jv_next) - if (job_still_useful(job)) + if (job_still_alive(job)) { tv.v_type = VAR_JOB; tv.vval.v_job = job; @@ -4478,7 +4516,7 @@ job_unref(job_T *job) { /* Do not free the job when it has not ended yet and there is a * "stoponexit" flag or an exit callback. */ - if (!job_still_useful(job)) + if (!job_still_alive(job)) { job_free(job); } @@ -4503,7 +4541,7 @@ free_unused_jobs_contents(int copyID, in for (job = first_job; job != NULL; job = job->jv_next) if ((job->jv_copyID & mask) != (copyID & mask) - && !job_still_useful(job)) + && !job_still_alive(job)) { /* Free the channel and ordinary items it contains, but don't * recurse into Lists, Dictionaries etc. */ @@ -4523,7 +4561,7 @@ free_unused_jobs(int copyID, int mask) { job_next = job->jv_next; if ((job->jv_copyID & mask) != (copyID & mask) - && !job_still_useful(job)) + && !job_still_alive(job)) { /* Free the job struct itself. */ job_free_job(job); @@ -4614,34 +4652,31 @@ has_pending_job(void) job_T *job; for (job = first_job; job != NULL; job = job->jv_next) - if (job->jv_status == JOB_STARTED && job_still_useful(job)) + if (job_still_alive(job)) return TRUE; return FALSE; } +#define MAX_CHECK_ENDED 8 + /* * Called once in a while: check if any jobs that seem useful have ended. */ void job_check_ended(void) { - static time_t last_check = 0; - time_t now; - job_T *job; - job_T *next; - - /* Only do this once in 10 seconds. */ - now = time(NULL); - if (last_check + 10 < now) + int i; + + for (i = 0; i < MAX_CHECK_ENDED; ++i) { - last_check = now; - for (job = first_job; job != NULL; job = next) - { - next = job->jv_next; - if (job->jv_status == JOB_STARTED && job_still_useful(job)) - job_status(job); /* may free "job" */ - } + job_T *job = mch_detect_ended_job(first_job); + + if (job == NULL) + break; + if (job_still_useful(job)) + job_cleanup(job); /* may free "job" */ } + if (channel_need_redraw) { channel_need_redraw = FALSE; @@ -4862,32 +4897,7 @@ job_status(job_T *job) { result = mch_job_status(job); if (job->jv_status == JOB_ENDED) - ch_log(job->jv_channel, "Job ended"); - if (job->jv_status == JOB_ENDED && job->jv_exit_cb != NULL) - { - typval_T argv[3]; - typval_T rettv; - int dummy; - - /* invoke the exit callback; make sure the refcount is > 0 */ - ++job->jv_refcount; - argv[0].v_type = VAR_JOB; - argv[0].vval.v_job = job; - argv[1].v_type = VAR_NUMBER; - argv[1].vval.v_number = job->jv_exitval; - call_func(job->jv_exit_cb, (int)STRLEN(job->jv_exit_cb), - &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, - job->jv_exit_partial, NULL); - clear_tv(&rettv); - --job->jv_refcount; - channel_need_redraw = TRUE; - } - if (job->jv_status == JOB_ENDED && job->jv_refcount == 0) - { - /* The job was already unreferenced, now that it ended it can be - * freed. Careful: caller must not use "job" after this! */ - job_free(job); - } + job_cleanup(job); } return result; }