@@ -4453,6 +4453,39 @@ job_free(job_T *job)
44534453 }
44544454}
44554455
4456+ static void
4457+ job_cleanup (job_T * job )
4458+ {
4459+ if (job -> jv_status != JOB_ENDED )
4460+ return ;
4461+
4462+ if (job -> jv_exit_cb != NULL )
4463+ {
4464+ typval_T argv [3 ];
4465+ typval_T rettv ;
4466+ int dummy ;
4467+
4468+ /* invoke the exit callback; make sure the refcount is > 0 */
4469+ ++ job -> jv_refcount ;
4470+ argv [0 ].v_type = VAR_JOB ;
4471+ argv [0 ].vval .v_job = job ;
4472+ argv [1 ].v_type = VAR_NUMBER ;
4473+ argv [1 ].vval .v_number = job -> jv_exitval ;
4474+ call_func (job -> jv_exit_cb , (int )STRLEN (job -> jv_exit_cb ),
4475+ & rettv , 2 , argv , NULL , 0L , 0L , & dummy , TRUE,
4476+ job -> jv_exit_partial , NULL );
4477+ clear_tv (& rettv );
4478+ -- job -> jv_refcount ;
4479+ channel_need_redraw = TRUE;
4480+ }
4481+ if (job -> jv_refcount == 0 )
4482+ {
4483+ /* The job was already unreferenced, now that it ended it can be
4484+ * freed. Careful: caller must not use "job" after this! */
4485+ job_free (job );
4486+ }
4487+ }
4488+
44564489#if defined(EXITFREE ) || defined(PROTO )
44574490 void
44584491job_free_all (void )
@@ -4470,10 +4503,15 @@ job_free_all(void)
44704503 static int
44714504job_still_useful (job_T * job )
44724505{
4473- return job -> jv_status == JOB_STARTED
4474- && (job -> jv_stoponexit != NULL || job -> jv_exit_cb != NULL
4475- || (job -> jv_channel != NULL
4476- && channel_still_useful (job -> jv_channel )));
4506+ return (job -> jv_stoponexit != NULL || job -> jv_exit_cb != NULL
4507+ || (job -> jv_channel != NULL
4508+ && channel_still_useful (job -> jv_channel )));
4509+ }
4510+
4511+ static int
4512+ job_still_alive (job_T * job )
4513+ {
4514+ return (job -> jv_status == JOB_STARTED ) && job_still_useful (job );
44774515}
44784516
44794517/*
@@ -4487,7 +4525,7 @@ set_ref_in_job(int copyID)
44874525 typval_T tv ;
44884526
44894527 for (job = first_job ; job != NULL ; job = job -> jv_next )
4490- if (job_still_useful (job ))
4528+ if (job_still_alive (job ))
44914529 {
44924530 tv .v_type = VAR_JOB ;
44934531 tv .vval .v_job = job ;
@@ -4503,7 +4541,7 @@ job_unref(job_T *job)
45034541 {
45044542 /* Do not free the job when it has not ended yet and there is a
45054543 * "stoponexit" flag or an exit callback. */
4506- if (!job_still_useful (job ))
4544+ if (!job_still_alive (job ))
45074545 {
45084546 job_free (job );
45094547 }
@@ -4528,7 +4566,7 @@ free_unused_jobs_contents(int copyID, int mask)
45284566
45294567 for (job = first_job ; job != NULL ; job = job -> jv_next )
45304568 if ((job -> jv_copyID & mask ) != (copyID & mask )
4531- && !job_still_useful (job ))
4569+ && !job_still_alive (job ))
45324570 {
45334571 /* Free the channel and ordinary items it contains, but don't
45344572 * recurse into Lists, Dictionaries etc. */
@@ -4548,7 +4586,7 @@ free_unused_jobs(int copyID, int mask)
45484586 {
45494587 job_next = job -> jv_next ;
45504588 if ((job -> jv_copyID & mask ) != (copyID & mask )
4551- && !job_still_useful (job ))
4589+ && !job_still_alive (job ))
45524590 {
45534591 /* Free the job struct itself. */
45544592 job_free_job (job );
@@ -4639,34 +4677,31 @@ has_pending_job(void)
46394677 job_T * job ;
46404678
46414679 for (job = first_job ; job != NULL ; job = job -> jv_next )
4642- if (job -> jv_status == JOB_STARTED && job_still_useful (job ))
4680+ if (job_still_alive (job ))
46434681 return TRUE;
46444682 return FALSE;
46454683}
46464684
4685+ #define MAX_CHECK_ENDED 8
4686+
46474687/*
46484688 * Called once in a while: check if any jobs that seem useful have ended.
46494689 */
46504690 void
46514691job_check_ended (void )
46524692{
4653- static time_t last_check = 0 ;
4654- time_t now ;
4655- job_T * job ;
4656- job_T * next ;
4693+ int i ;
46574694
4658- /* Only do this once in 10 seconds. */
4659- now = time (NULL );
4660- if (last_check + 10 < now )
4695+ for (i = 0 ; i < MAX_CHECK_ENDED ; ++ i )
46614696 {
4662- last_check = now ;
4663- for (job = first_job ; job != NULL ; job = next )
4664- {
4665- next = job -> jv_next ;
4666- if (job -> jv_status == JOB_STARTED && job_still_useful (job ))
4667- job_status (job ); /* may free "job" */
4668- }
4697+ job_T * job = mch_detect_ended_job (first_job );
4698+
4699+ if (job == NULL )
4700+ break ;
4701+ if (job_still_useful (job ))
4702+ job_cleanup (job ); /* may free "job" */
46694703 }
4704+
46704705 if (channel_need_redraw )
46714706 {
46724707 channel_need_redraw = FALSE;
@@ -4887,32 +4922,7 @@ job_status(job_T *job)
48874922 {
48884923 result = mch_job_status (job );
48894924 if (job -> jv_status == JOB_ENDED )
4890- ch_log (job -> jv_channel , "Job ended" );
4891- if (job -> jv_status == JOB_ENDED && job -> jv_exit_cb != NULL )
4892- {
4893- typval_T argv [3 ];
4894- typval_T rettv ;
4895- int dummy ;
4896-
4897- /* invoke the exit callback; make sure the refcount is > 0 */
4898- ++ job -> jv_refcount ;
4899- argv [0 ].v_type = VAR_JOB ;
4900- argv [0 ].vval .v_job = job ;
4901- argv [1 ].v_type = VAR_NUMBER ;
4902- argv [1 ].vval .v_number = job -> jv_exitval ;
4903- call_func (job -> jv_exit_cb , (int )STRLEN (job -> jv_exit_cb ),
4904- & rettv , 2 , argv , NULL , 0L , 0L , & dummy , TRUE,
4905- job -> jv_exit_partial , NULL );
4906- clear_tv (& rettv );
4907- -- job -> jv_refcount ;
4908- channel_need_redraw = TRUE;
4909- }
4910- if (job -> jv_status == JOB_ENDED && job -> jv_refcount == 0 )
4911- {
4912- /* The job was already unreferenced, now that it ended it can be
4913- * freed. Careful: caller must not use "job" after this! */
4914- job_free (job );
4915- }
4925+ job_cleanup (job );
49164926 }
49174927 return result ;
49184928}
0 commit comments