@@ -4428,6 +4428,39 @@ job_free(job_T *job)
44284428 }
44294429}
44304430
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+
44314464#if defined(EXITFREE ) || defined(PROTO )
44324465 void
44334466job_free_all (void )
@@ -4445,10 +4478,15 @@ job_free_all(void)
44454478 static int
44464479job_still_useful (job_T * job )
44474480{
4448- return job -> jv_status == JOB_STARTED
4449- && (job -> jv_stoponexit != NULL || job -> jv_exit_cb != NULL
4450- || (job -> jv_channel != NULL
4451- && channel_still_useful (job -> jv_channel )));
4481+ return (job -> jv_stoponexit != NULL || job -> jv_exit_cb != NULL
4482+ || (job -> jv_channel != NULL
4483+ && 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 );
44524490}
44534491
44544492/*
@@ -4462,7 +4500,7 @@ set_ref_in_job(int copyID)
44624500 typval_T tv ;
44634501
44644502 for (job = first_job ; job != NULL ; job = job -> jv_next )
4465- if (job_still_useful (job ))
4503+ if (job_still_alive (job ))
44664504 {
44674505 tv .v_type = VAR_JOB ;
44684506 tv .vval .v_job = job ;
@@ -4478,7 +4516,7 @@ job_unref(job_T *job)
44784516 {
44794517 /* Do not free the job when it has not ended yet and there is a
44804518 * "stoponexit" flag or an exit callback. */
4481- if (!job_still_useful (job ))
4519+ if (!job_still_alive (job ))
44824520 {
44834521 job_free (job );
44844522 }
@@ -4503,7 +4541,7 @@ free_unused_jobs_contents(int copyID, int mask)
45034541
45044542 for (job = first_job ; job != NULL ; job = job -> jv_next )
45054543 if ((job -> jv_copyID & mask ) != (copyID & mask )
4506- && !job_still_useful (job ))
4544+ && !job_still_alive (job ))
45074545 {
45084546 /* Free the channel and ordinary items it contains, but don't
45094547 * recurse into Lists, Dictionaries etc. */
@@ -4523,7 +4561,7 @@ free_unused_jobs(int copyID, int mask)
45234561 {
45244562 job_next = job -> jv_next ;
45254563 if ((job -> jv_copyID & mask ) != (copyID & mask )
4526- && !job_still_useful (job ))
4564+ && !job_still_alive (job ))
45274565 {
45284566 /* Free the job struct itself. */
45294567 job_free_job (job );
@@ -4614,34 +4652,31 @@ has_pending_job(void)
46144652 job_T * job ;
46154653
46164654 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 ))
46184656 return TRUE;
46194657 return FALSE;
46204658}
46214659
4660+ #define MAX_CHECK_ENDED 8
4661+
46224662/*
46234663 * Called once in a while: check if any jobs that seem useful have ended.
46244664 */
46254665 void
46264666job_check_ended (void )
46274667{
4628- static time_t last_check = 0 ;
4629- time_t now ;
4630- job_T * job ;
4631- job_T * next ;
4668+ int i ;
46324669
4633- /* Only do this once in 10 seconds. */
4634- now = time (NULL );
4635- if (last_check + 10 < now )
4670+ for (i = 0 ; i < MAX_CHECK_ENDED ; ++ i )
46364671 {
4637- last_check = now ;
4638- for (job = first_job ; job != NULL ; job = next )
4639- {
4640- next = job -> jv_next ;
4641- if (job -> jv_status == JOB_STARTED && job_still_useful (job ))
4642- job_status (job ); /* may free "job" */
4643- }
4672+ job_T * job = mch_detect_ended_job (first_job );
4673+
4674+ if (job == NULL )
4675+ break ;
4676+ if (job_still_useful (job ))
4677+ job_cleanup (job ); /* may free "job" */
46444678 }
4679+
46454680 if (channel_need_redraw )
46464681 {
46474682 channel_need_redraw = FALSE;
@@ -4862,32 +4897,7 @@ job_status(job_T *job)
48624897 {
48634898 result = mch_job_status (job );
48644899 if (job -> jv_status == JOB_ENDED )
4865- ch_log (job -> jv_channel , "Job ended" );
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- }
4900+ job_cleanup (job );
48914901 }
48924902 return result ;
48934903}
0 commit comments