Mercurial > vim
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 */ |