1
1

Merge branch '1500_segfault_on_bg_copy'

* 1500_segfault_on_bg_copy:
  Fixed problems:
  Ticket #1500: Segmentation fault while background copying
Этот коммит содержится в:
Slava Zanko 2009-10-28 12:05:36 +02:00
родитель 720eca3fa3 936727622d
Коммит 9c854e73d4
6 изменённых файлов: 149 добавлений и 30 удалений

Просмотреть файл

@ -61,6 +61,9 @@ int we_are_background = 0;
/* File descriptor for talking to our parent */ /* File descriptor for talking to our parent */
static int parent_fd; static int parent_fd;
/* File descriptor for messages from our parent */
static int from_parent_fd;
#define MAXCALLARGS 4 /* Number of arguments supported */ #define MAXCALLARGS 4 /* Number of arguments supported */
struct TaskList *task_list = NULL; struct TaskList *task_list = NULL;
@ -68,7 +71,8 @@ struct TaskList *task_list = NULL;
static int background_attention (int fd, void *closure); static int background_attention (int fd, void *closure);
static void static void
register_task_running (FileOpContext *ctx, pid_t pid, int fd, char *info) register_task_running (FileOpContext *ctx, pid_t pid, int fd, int to_child,
char *info)
{ {
TaskList *new; TaskList *new;
@ -78,13 +82,14 @@ register_task_running (FileOpContext *ctx, pid_t pid, int fd, char *info)
new->state = Task_Running; new->state = Task_Running;
new->next = task_list; new->next = task_list;
new->fd = fd; new->fd = fd;
new->to_child_fd = to_child;
task_list = new; task_list = new;
add_select_channel (fd, background_attention, ctx); add_select_channel (fd, background_attention, ctx);
} }
void int
unregister_task_running (pid_t pid, int fd) destroy_task_and_return_fd (pid_t pid)
{ {
TaskList *p = task_list; TaskList *p = task_list;
TaskList *prev = 0; TaskList *prev = 0;
@ -97,11 +102,28 @@ unregister_task_running (pid_t pid, int fd)
task_list = p->next; task_list = p->next;
g_free (p->info); g_free (p->info);
g_free (p); g_free (p);
break; return p->fd;
} }
prev = p; prev = p;
p = p->next; 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); delete_select_channel (fd);
} }
@ -117,15 +139,21 @@ int
do_background (struct FileOpContext *ctx, char *info) do_background (struct FileOpContext *ctx, char *info)
{ {
int comm[2]; /* control connection stream */ int comm[2]; /* control connection stream */
int back_comm[2]; /* back connection */
pid_t pid; pid_t pid;
if (pipe (comm) == -1) if (pipe (comm) == -1)
return -1; return -1;
if (pipe (back_comm) == -1)
return -1;
if ((pid = fork ()) == -1) { if ((pid = fork ()) == -1) {
int saved_errno = errno; int saved_errno = errno;
(void) close (comm[0]); (void) close (comm[0]);
(void) close (comm[1]); (void) close (comm[1]);
(void) close (back_comm[0]);
(void) close (back_comm[1]);
errno = saved_errno; errno = saved_errno;
return -1; return -1;
} }
@ -133,8 +161,9 @@ do_background (struct FileOpContext *ctx, char *info)
if (pid == 0) { if (pid == 0) {
int nullfd; int nullfd;
close (comm[0]);
parent_fd = comm[1]; parent_fd = comm[1];
from_parent_fd = back_comm[0];
we_are_background = 1; we_are_background = 1;
current_dlg = NULL; current_dlg = NULL;
@ -151,9 +180,8 @@ do_background (struct FileOpContext *ctx, char *info)
return 0; return 0;
} else { } else {
close (comm[1]);
ctx->pid = pid; ctx->pid = pid;
register_task_running (ctx, pid, comm[0], info); register_task_running (ctx, pid, comm[0], back_comm[1], info);
return 1; return 1;
} }
} }
@ -205,16 +233,19 @@ background_attention (int fd, void *closure)
int have_ctx; int have_ctx;
union union
{ {
int (*have_ctx0)(int);
int (*have_ctx1)(int, char *); int (*have_ctx1)(int, char *);
int (*have_ctx2)(int, char *, char *); int (*have_ctx2)(int, char *, char *);
int (*have_ctx3)(int, char *, char *, char *); int (*have_ctx3)(int, char *, char *, char *);
int (*have_ctx4)(int, char *, 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_ctx1)(FileOpContext *, int, char *);
int (*non_have_ctx2)(FileOpContext *, int, char *, char *); int (*non_have_ctx2)(FileOpContext *, int, char *, char *);
int (*non_have_ctx3)(FileOpContext *, int, char *, char *, char *); int (*non_have_ctx3)(FileOpContext *, int, char *, char *, char *);
int (*non_have_ctx4)(FileOpContext *, int, char *, char *, char *, char *); int (*non_have_ctx4)(FileOpContext *, int, char *, char *, char *, char *);
char * (*ret_str0)();
char * (*ret_str1)(char *); char * (*ret_str1)(char *);
char * (*ret_str2)(char *, char *); char * (*ret_str2)(char *, char *);
char * (*ret_str3)(char *, char *, char *); char * (*ret_str3)(char *, char *, char *);
@ -226,6 +257,8 @@ background_attention (int fd, void *closure)
int argc, i, result, status; int argc, i, result, status;
char *data [MAXCALLARGS]; char *data [MAXCALLARGS];
ssize_t bytes; ssize_t bytes;
struct TaskList *p;
int to_child_fd = -1;
enum ReturnType type; enum ReturnType type;
ctx = closure; ctx = closure;
@ -272,10 +305,25 @@ background_attention (int fd, void *closure)
data [i][size] = 0; /* NULL terminate the blocks (they could be strings) */ 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 */ /* Handle the call */
if (type == Return_Integer){ if (type == Return_Integer){
if (!have_ctx) if (!have_ctx)
switch (argc){ switch (argc){
case 0:
result = routine.have_ctx0 (Background);
break;
case 1: case 1:
result = routine.have_ctx1 (Background, data [0]); result = routine.have_ctx1 (Background, data [0]);
break; break;
@ -291,6 +339,9 @@ background_attention (int fd, void *closure)
} }
else else
switch (argc){ switch (argc){
case 0:
result = routine.non_have_ctx0 (ctx, Background);
break;
case 1: case 1:
result = routine.non_have_ctx1 (ctx, Background, data [0]); result = routine.non_have_ctx1 (ctx, Background, data [0]);
break; break;
@ -306,9 +357,9 @@ background_attention (int fd, void *closure)
} }
/* Send the result code and the value for shared variables */ /* Send the result code and the value for shared variables */
write (fd, &result, sizeof (int)); write (to_child_fd, &result, sizeof (int));
if (have_ctx) if (have_ctx && to_child_fd != -1)
write (fd, ctx, sizeof (FileOpContext)); write (to_child_fd, ctx, sizeof (FileOpContext));
} else if (type == Return_String) { } else if (type == Return_String) {
int len; int len;
char *resstr = NULL; char *resstr = NULL;
@ -317,6 +368,9 @@ background_attention (int fd, void *closure)
* parameter. Currently, this is not used here * parameter. Currently, this is not used here
*/ */
switch (argc){ switch (argc){
case 0:
resstr = routine.ret_str0 ();
break;
case 1: case 1:
resstr = routine.ret_str1 (data [0]); resstr = routine.ret_str1 (data [0]);
break; break;
@ -333,14 +387,14 @@ background_attention (int fd, void *closure)
} }
if (resstr){ if (resstr){
len = strlen (resstr); len = strlen (resstr);
write (fd, &len, sizeof (len)); write (to_child_fd, &len, sizeof (len));
if (len){ if (len){
write (fd, resstr, len); write (to_child_fd, resstr, len);
g_free (resstr); g_free (resstr);
} }
} else { } else {
len = 0; len = 0;
write (fd, &len, sizeof (len)); write (to_child_fd, &len, sizeof (len));
} }
} }
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
@ -392,9 +446,10 @@ parent_call (void *routine, struct FileOpContext *ctx, int argc, ...)
write (parent_fd, &len, sizeof (int)); write (parent_fd, &len, sizeof (int));
write (parent_fd, value, len); write (parent_fd, value, len);
} }
read (parent_fd, &i, sizeof (int));
read (from_parent_fd, &i, sizeof (int));
if (ctx) if (ctx)
read (parent_fd, ctx, sizeof (FileOpContext)); read (from_parent_fd, ctx, sizeof (FileOpContext));
return i; return i;
} }
@ -417,11 +472,11 @@ parent_call_string (void *routine, int argc, ...)
write (parent_fd, &len, sizeof (int)); write (parent_fd, &len, sizeof (int));
write (parent_fd, value, len); write (parent_fd, value, len);
} }
read (parent_fd, &i, sizeof (int)); read (from_parent_fd, &i, sizeof (int));
if (!i) if (!i)
return NULL; return NULL;
str = g_malloc (i + 1); str = g_malloc (i + 1);
read (parent_fd, str, i); read (from_parent_fd, str, i);
str [i] = 0; str [i] = 0;
return str; return str;
} }

Просмотреть файл

@ -17,6 +17,7 @@ enum TaskState {
typedef struct TaskList { typedef struct TaskList {
int fd; int fd;
int to_child_fd;
pid_t pid; pid_t pid;
int state; int state;
char *info; char *info;
@ -31,6 +32,7 @@ int parent_call (void *routine, struct FileOpContext *ctx, int argc, ...);
char *parent_call_string (void *routine, int argc, ...); char *parent_call_string (void *routine, int argc, ...);
void unregister_task_running (pid_t pid, int fd); void unregister_task_running (pid_t pid, int fd);
void unregister_task_with_pid (pid_t pid);
extern int we_are_background; extern int we_are_background;
#endif /* !WITH_BACKGROUND */ #endif /* !WITH_BACKGROUND */

Просмотреть файл

@ -883,7 +883,7 @@ task_cb (int action)
sig = SIGKILL; sig = SIGKILL;
} }
if (sig == SIGINT) if (sig == SIGKILL)
unregister_task_running (tl->pid, tl->fd); unregister_task_running (tl->pid, tl->fd);
kill (tl->pid, sig); kill (tl->pid, sig);

Просмотреть файл

@ -381,12 +381,18 @@ enum {
}; };
static FileProgressStatus static FileProgressStatus
warn_same_file (const char *fmt, const char *a, const char *b) real_warn_same_file (enum OperationMode mode, const char *fmt,
const char *a, const char *b)
{ {
char *msg; char *msg;
int result = 0; int result = 0;
const char *head_msg;
head_msg = mode == Foreground ? MSG_ERROR :
_(" Background process error ");
msg = g_strdup_printf (fmt, a, b); msg = g_strdup_printf (fmt, a, b);
result = query_dialog (MSG_ERROR, msg, D_ERROR, 2, _("&Skip"), _("&Abort")); result = query_dialog (head_msg, msg, D_ERROR, 2, _("&Skip"), _("&Abort"));
g_free(msg); g_free(msg);
do_refresh (); do_refresh ();
if ( result ) { /* 1 == Abort */ if ( result ) { /* 1 == Abort */
@ -396,6 +402,31 @@ warn_same_file (const char *fmt, const char *a, const char *b)
} }
} }
#ifdef WITH_BACKGROUND
static FileProgressStatus
warn_same_file (const char *fmt, const char *a, const char *b)
{
union {
void *p;
FileProgressStatus (*f) (enum OperationMode, const char *fmt,
const char *a, const char *b);
} pntr;
pntr.f = real_warn_same_file;
if (we_are_background)
return parent_call (pntr.p, NULL, 3, strlen (fmt),
fmt, strlen(a), a, strlen(b), b);
else
return real_warn_same_file (Foreground, fmt, a, b);
}
#else
static FileProgressStatus
warn_same_file (const char *fmt, const char *a, const char *b)
{
return real_warn_same_file (Foreground, fmt, a, b);
}
#endif
FileProgressStatus FileProgressStatus
copy_file_file (FileOpContext *ctx, const char *src_path, const char *dst_path, copy_file_file (FileOpContext *ctx, const char *src_path, const char *dst_path,
int ask_overwrite, off_t *progress_count, int ask_overwrite, off_t *progress_count,
@ -1756,6 +1787,17 @@ panel_operate_generate_prompt (const WPanel *panel, const int operation,
return g_strdup (format_string); 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: * panel_operate:
* *
@ -1900,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 #ifdef WITH_BACKGROUND
/* Did the user select to do a background operation? */ /* Did the user select to do a background operation? */
if (do_bg) { if (do_bg) {
@ -1938,11 +1986,6 @@ panel_operate (void *source_panel, FileOperation operation,
/* Now, let's do the job */ /* 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 */ /* This code is only called by the tree and panel code */
if (single_entry) { if (single_entry) {
/* We now have ETA in all cases */ /* We now have ETA in all cases */
@ -2170,6 +2213,12 @@ panel_operate (void *source_panel, FileOperation operation,
#ifdef WITH_BACKGROUND #ifdef WITH_BACKGROUND
/* Let our parent know we are saying bye bye */ /* Let our parent know we are saying bye bye */
if (we_are_background) { 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 (); vfs_shut ();
_exit (0); _exit (0);
} }

Просмотреть файл

@ -250,7 +250,7 @@ check_progress_buttons (FileOpContext *ctx)
/* {{{ File progress display routines */ /* {{{ File progress display routines */
void 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; FileOpContextUI *ui;
int x_size; int x_size;
@ -321,6 +321,18 @@ file_op_context_create_ui (FileOpContext *ctx, int with_eta)
label_new (3, FCOPY_GAUGE_X, sixty)); label_new (3, FCOPY_GAUGE_X, sixty));
add_widget (ui->op_dlg, ui->file_label[0] = add_widget (ui->op_dlg, ui->file_label[0] =
label_new (3, FCOPY_LABEL_X, fifteen)); 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 will manage the dialog without any help, that's why
we have to call init_dlg */ we have to call init_dlg */

Просмотреть файл

@ -144,6 +144,7 @@ enum OperationMode {
/* The following functions are implemented separately by each port */ /* 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 (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); void file_op_context_destroy_ui (FileOpContext *ctx);
FileProgressStatus file_progress_show (FileOpContext *ctx, off_t done, off_t total); FileProgressStatus file_progress_show (FileOpContext *ctx, off_t done, off_t total);