From 936727622d19041e702e2c14b15cf1e69d82d319 Mon Sep 17 00:00:00 2001 From: Alexander Moiseenko Date: Sat, 24 Oct 2009 15:47:16 +0300 Subject: [PATCH] Fixed problems: * When try to replace existing file in background operation assertion raised (created operations for initialization ctx->ui for background): ** (mc:25716): CRITICAL **: file_progress_real_query_replace: assertion `ctx->ui != NULL' failed * Process has been already done, but still draw in list (C-x j) * Process is stopped or worked, remove operation don't hide process from list, but kill it Signed-off-by: Slava Zanko --- src/background.c | 59 +++++++++++++++++++++++++++++++++++++++++++------------- src/background.h | 1 + src/boxes.c | 2 +- src/file.c | 28 ++++++++++++++++++++++----- src/filegui.c | 14 +++++++++++++- src/fileopctx.h | 1 + 6 files changed, 85 insertions(+), 20 deletions(-) diff --git a/src/background.c b/src/background.c index 2ec345bc2..6dff3211c 100644 --- a/src/background.c +++ b/src/background.c @@ -88,8 +88,8 @@ register_task_running (FileOpContext *ctx, pid_t pid, int fd, int to_child, add_select_channel (fd, background_attention, ctx); } -void -unregister_task_running (pid_t pid, int fd) +int +destroy_task_and_return_fd (pid_t pid) { TaskList *p = task_list; TaskList *prev = 0; @@ -102,14 +102,31 @@ unregister_task_running (pid_t pid, int fd) task_list = p->next; g_free (p->info); g_free (p); - break; + return p->fd; } prev = p; p = p->next; } + + /* pid not found */ + return -1; +} + +void +unregister_task_running (pid_t pid, int fd) +{ + destroy_task_and_return_fd(pid); delete_select_channel (fd); } +void +unregister_task_with_pid (pid_t pid) +{ + int fd = destroy_task_and_return_fd(pid); + if (fd != -1) + delete_select_channel (fd); +} + /* * Try to make the Midnight Commander a background job * @@ -216,16 +233,19 @@ background_attention (int fd, void *closure) int have_ctx; union { + int (*have_ctx0)(int); int (*have_ctx1)(int, char *); int (*have_ctx2)(int, char *, char *); int (*have_ctx3)(int, char *, char *, char *); int (*have_ctx4)(int, char *, char *, char *, char *); + int (*non_have_ctx0)(FileOpContext *, int); int (*non_have_ctx1)(FileOpContext *, int, char *); int (*non_have_ctx2)(FileOpContext *, int, char *, char *); int (*non_have_ctx3)(FileOpContext *, int, char *, char *, char *); int (*non_have_ctx4)(FileOpContext *, int, char *, char *, char *, char *); + char * (*ret_str0)(); char * (*ret_str1)(char *); char * (*ret_str2)(char *, char *); char * (*ret_str3)(char *, char *, char *); @@ -238,7 +258,7 @@ background_attention (int fd, void *closure) char *data [MAXCALLARGS]; ssize_t bytes; struct TaskList *p; - int to_child_fd; + int to_child_fd = -1; enum ReturnType type; ctx = closure; @@ -285,10 +305,25 @@ background_attention (int fd, void *closure) data [i][size] = 0; /* NULL terminate the blocks (they could be strings) */ } + /* Find child task info by descriptor */ + /* Find before call, because process can destroy self after */ + for (p = task_list; p; p = p->next) { + if (p->fd == fd) + break; + } + + if (p) to_child_fd = p->to_child_fd; + + if (to_child_fd == -1) + message (D_ERROR, _(" Background process error "), _(" Unknown error in child ")); + /* Handle the call */ if (type == Return_Integer){ if (!have_ctx) switch (argc){ + case 0: + result = routine.have_ctx0 (Background); + break; case 1: result = routine.have_ctx1 (Background, data [0]); break; @@ -304,6 +339,9 @@ background_attention (int fd, void *closure) } else switch (argc){ + case 0: + result = routine.non_have_ctx0 (ctx, Background); + break; case 1: result = routine.non_have_ctx1 (ctx, Background, data [0]); break; @@ -318,17 +356,9 @@ background_attention (int fd, void *closure) break; } - /* Find child task info by descriptor */ - for (p = task_list; p; p = p->next) { - if (p->fd == fd) - break; - } - - to_child_fd = p->to_child_fd; - /* Send the result code and the value for shared variables */ write (to_child_fd, &result, sizeof (int)); - if (have_ctx) + if (have_ctx && to_child_fd != -1) write (to_child_fd, ctx, sizeof (FileOpContext)); } else if (type == Return_String) { int len; @@ -338,6 +368,9 @@ background_attention (int fd, void *closure) * parameter. Currently, this is not used here */ switch (argc){ + case 0: + resstr = routine.ret_str0 (); + break; case 1: resstr = routine.ret_str1 (data [0]); break; diff --git a/src/background.h b/src/background.h index 8ad4d54a9..2dc4bf4af 100644 --- a/src/background.h +++ b/src/background.h @@ -32,6 +32,7 @@ int parent_call (void *routine, struct FileOpContext *ctx, int argc, ...); char *parent_call_string (void *routine, int argc, ...); void unregister_task_running (pid_t pid, int fd); +void unregister_task_with_pid (pid_t pid); extern int we_are_background; #endif /* !WITH_BACKGROUND */ diff --git a/src/boxes.c b/src/boxes.c index 80944e6a8..e6db6bd9b 100644 --- a/src/boxes.c +++ b/src/boxes.c @@ -883,7 +883,7 @@ task_cb (int action) sig = SIGKILL; } - if (sig == SIGINT) + if (sig == SIGKILL) unregister_task_running (tl->pid, tl->fd); kill (tl->pid, sig); diff --git a/src/file.c b/src/file.c index 909c8cdea..b9649f483 100644 --- a/src/file.c +++ b/src/file.c @@ -1787,6 +1787,17 @@ panel_operate_generate_prompt (const WPanel *panel, const int operation, return g_strdup (format_string); } +#ifdef WITH_BACKGROUND +int end_bg_process (FileOpContext *ctx, enum OperationMode mode) { + int pid = ctx->pid; + ctx->pid = 0; + + unregister_task_with_pid(pid); +// file_op_context_destroy(ctx); + return 1; +} +#endif + /** * panel_operate: * @@ -1931,6 +1942,12 @@ panel_operate (void *source_panel, FileOperation operation, } } + /* Background also need ctx->ui, but not full */ + if (do_bg) + file_op_context_create_ui_without_init (ctx, 1); + else + file_op_context_create_ui (ctx, 1); + #ifdef WITH_BACKGROUND /* Did the user select to do a background operation? */ if (do_bg) { @@ -1969,11 +1986,6 @@ panel_operate (void *source_panel, FileOperation operation, /* Now, let's do the job */ - if (do_bg) - ctx->ui = NULL; - else - file_op_context_create_ui (ctx, 1); - /* This code is only called by the tree and panel code */ if (single_entry) { /* We now have ETA in all cases */ @@ -2201,6 +2213,12 @@ panel_operate (void *source_panel, FileOperation operation, #ifdef WITH_BACKGROUND /* Let our parent know we are saying bye bye */ if (we_are_background) { + int cur_pid = getpid(); + /* Send pid to parent with child context, it is fork and + don't modify real parent ctx */ + ctx->pid = cur_pid; + parent_call ((void *) end_bg_process, ctx, 0); + vfs_shut (); _exit (0); } diff --git a/src/filegui.c b/src/filegui.c index 15b3872d8..5dd209df3 100644 --- a/src/filegui.c +++ b/src/filegui.c @@ -250,7 +250,7 @@ check_progress_buttons (FileOpContext *ctx) /* {{{ File progress display routines */ void -file_op_context_create_ui (FileOpContext *ctx, int with_eta) +file_op_context_create_ui_without_init (FileOpContext *ctx, int with_eta) { FileOpContextUI *ui; int x_size; @@ -321,6 +321,18 @@ file_op_context_create_ui (FileOpContext *ctx, int with_eta) label_new (3, FCOPY_GAUGE_X, sixty)); add_widget (ui->op_dlg, ui->file_label[0] = label_new (3, FCOPY_LABEL_X, fifteen)); +} + +void +file_op_context_create_ui (FileOpContext *ctx, int with_eta) +{ + FileOpContextUI *ui; + + g_return_if_fail (ctx != NULL); + g_return_if_fail (ctx->ui == NULL); + + file_op_context_create_ui_without_init(ctx, with_eta); + ui = ctx->ui; /* We will manage the dialog without any help, that's why we have to call init_dlg */ diff --git a/src/fileopctx.h b/src/fileopctx.h index 4943e28e0..305fe6389 100644 --- a/src/fileopctx.h +++ b/src/fileopctx.h @@ -144,6 +144,7 @@ enum OperationMode { /* The following functions are implemented separately by each port */ void file_op_context_create_ui (FileOpContext *ctx, int with_eta); +void file_op_context_create_ui_without_init (FileOpContext *ctx, int with_eta); void file_op_context_destroy_ui (FileOpContext *ctx); FileProgressStatus file_progress_show (FileOpContext *ctx, off_t done, off_t total); -- 2.11.4.GIT