comparison src/terminal.c @ 15675:01890a3caefd v8.1.0845

patch 8.1.0845: having job_status() free the job causes problems commit https://github.com/vim/vim/commit/2a4857a1fcf1d188e5b985ac21bcfc532eddde94 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jan 29 22:29:07 2019 +0100 patch 8.1.0845: having job_status() free the job causes problems Problem: Having job_status() free the job causes problems. Solution: Do not actually free the job or terminal yet, put it in a list and free it a bit later. Do not use a terminal after checking the job status. (closes #3873)
author Bram Moolenaar <Bram@vim.org>
date Tue, 29 Jan 2019 22:30:06 +0100
parents d4a6d575e910
children d8b4cbb14e1e
comparison
equal deleted inserted replaced
15674:9045c248e9eb 15675:01890a3caefd
801 for (i = 0; i < term->tl_scrollback.ga_len; ++i) 801 for (i = 0; i < term->tl_scrollback.ga_len; ++i)
802 vim_free(((sb_line_T *)term->tl_scrollback.ga_data + i)->sb_cells); 802 vim_free(((sb_line_T *)term->tl_scrollback.ga_data + i)->sb_cells);
803 ga_clear(&term->tl_scrollback); 803 ga_clear(&term->tl_scrollback);
804 } 804 }
805 805
806
807 // Terminals that need to be freed soon.
808 term_T *terminals_to_free = NULL;
809
806 /* 810 /*
807 * Free a terminal and everything it refers to. 811 * Free a terminal and everything it refers to.
808 * Kills the job if there is one. 812 * Kills the job if there is one.
809 * Called when wiping out a buffer. 813 * Called when wiping out a buffer.
814 * The actual terminal structure is freed later in free_unused_terminals(),
815 * because callbacks may wipe out a buffer while the terminal is still
816 * referenced.
810 */ 817 */
811 void 818 void
812 free_terminal(buf_T *buf) 819 free_terminal(buf_T *buf)
813 { 820 {
814 term_T *term = buf->b_term; 821 term_T *term = buf->b_term;
815 term_T *tp; 822 term_T *tp;
816 823
817 if (term == NULL) 824 if (term == NULL)
818 return; 825 return;
826
827 // Unlink the terminal form the list of terminals.
819 if (first_term == term) 828 if (first_term == term)
820 first_term = term->tl_next; 829 first_term = term->tl_next;
821 else 830 else
822 for (tp = first_term; tp->tl_next != NULL; tp = tp->tl_next) 831 for (tp = first_term; tp->tl_next != NULL; tp = tp->tl_next)
823 if (tp->tl_next == term) 832 if (tp->tl_next == term)
832 && term->tl_job->jv_status != JOB_FINISHED 841 && term->tl_job->jv_status != JOB_FINISHED
833 && term->tl_job->jv_status != JOB_FAILED) 842 && term->tl_job->jv_status != JOB_FAILED)
834 job_stop(term->tl_job, NULL, "kill"); 843 job_stop(term->tl_job, NULL, "kill");
835 job_unref(term->tl_job); 844 job_unref(term->tl_job);
836 } 845 }
837 846 term->tl_next = terminals_to_free;
838 free_scrollback(term); 847 terminals_to_free = term;
839 848
840 term_free_vterm(term);
841 vim_free(term->tl_title);
842 #ifdef FEAT_SESSION
843 vim_free(term->tl_command);
844 #endif
845 vim_free(term->tl_kill);
846 vim_free(term->tl_status_text);
847 vim_free(term->tl_opencmd);
848 vim_free(term->tl_eof_chars);
849 #ifdef WIN3264
850 if (term->tl_out_fd != NULL)
851 fclose(term->tl_out_fd);
852 #endif
853 vim_free(term->tl_cursor_color);
854 vim_free(term);
855 buf->b_term = NULL; 849 buf->b_term = NULL;
856 if (in_terminal_loop == term) 850 if (in_terminal_loop == term)
857 in_terminal_loop = NULL; 851 in_terminal_loop = NULL;
852 }
853
854 void
855 free_unused_terminals()
856 {
857 while (terminals_to_free != NULL)
858 {
859 term_T *term = terminals_to_free;
860
861 terminals_to_free = term->tl_next;
862
863 free_scrollback(term);
864
865 term_free_vterm(term);
866 vim_free(term->tl_title);
867 #ifdef FEAT_SESSION
868 vim_free(term->tl_command);
869 #endif
870 vim_free(term->tl_kill);
871 vim_free(term->tl_status_text);
872 vim_free(term->tl_opencmd);
873 vim_free(term->tl_eof_chars);
874 #ifdef WIN3264
875 if (term->tl_out_fd != NULL)
876 fclose(term->tl_out_fd);
877 #endif
878 vim_free(term->tl_cursor_color);
879 vim_free(term);
880 }
858 } 881 }
859 882
860 /* 883 /*
861 * Get the part that is connected to the tty. Normally this is PART_IN, but 884 * Get the part that is connected to the tty. Normally this is PART_IN, but
862 * when writing buffer lines to the job it can be another. This makes it 885 * when writing buffer lines to the job it can be another. This makes it
1273 } 1296 }
1274 1297
1275 /* 1298 /*
1276 * Return TRUE if the job for "term" is still running. 1299 * Return TRUE if the job for "term" is still running.
1277 * If "check_job_status" is TRUE update the job status. 1300 * If "check_job_status" is TRUE update the job status.
1301 * NOTE: "term" may be freed by callbacks.
1278 */ 1302 */
1279 static int 1303 static int
1280 term_job_running_check(term_T *term, int check_job_status) 1304 term_job_running_check(term_T *term, int check_job_status)
1281 { 1305 {
1282 /* Also consider the job finished when the channel is closed, to avoid a 1306 /* Also consider the job finished when the channel is closed, to avoid a
1283 * race condition when updating the title. */ 1307 * race condition when updating the title. */
1284 if (term != NULL 1308 if (term != NULL
1285 && term->tl_job != NULL 1309 && term->tl_job != NULL
1286 && channel_is_open(term->tl_job->jv_channel)) 1310 && channel_is_open(term->tl_job->jv_channel))
1287 { 1311 {
1312 job_T *job = term->tl_job;
1313
1314 // Careful: Checking the job status may invoked callbacks, which close
1315 // the buffer and terminate "term". However, "job" will not be freed
1316 // yet.
1288 if (check_job_status) 1317 if (check_job_status)
1289 job_status(term->tl_job); 1318 job_status(job);
1290 return (term->tl_job->jv_status == JOB_STARTED 1319 return (job->jv_status == JOB_STARTED
1291 || term->tl_job->jv_channel->ch_keep_open); 1320 || (job->jv_channel != NULL && job->jv_channel->ch_keep_open));
1292 } 1321 }
1293 return FALSE; 1322 return FALSE;
1294 } 1323 }
1295 1324
1296 /* 1325 /*
2149 while (blocking || vpeekc_nomap() != NUL) 2178 while (blocking || vpeekc_nomap() != NUL)
2150 { 2179 {
2151 #ifdef FEAT_GUI 2180 #ifdef FEAT_GUI
2152 if (!curbuf->b_term->tl_system) 2181 if (!curbuf->b_term->tl_system)
2153 #endif 2182 #endif
2154 /* TODO: skip screen update when handling a sequence of keys. */ 2183 // TODO: skip screen update when handling a sequence of keys.
2155 /* Repeat redrawing in case a message is received while redrawing. 2184 // Repeat redrawing in case a message is received while redrawing.
2156 */
2157 while (must_redraw != 0) 2185 while (must_redraw != 0)
2158 if (update_screen(0) == FAIL) 2186 if (update_screen(0) == FAIL)
2159 break; 2187 break;
2160 if (!term_use_loop_check(TRUE) || in_terminal_loop != curbuf->b_term) 2188 if (!term_use_loop_check(TRUE) || in_terminal_loop != curbuf->b_term)
2161 /* job finished while redrawing */ 2189 /* job finished while redrawing */