Fixed deadlocks in background processing
This commit is contained in:
parent
6a91b2fa52
commit
f428888dd9
2 changed files with 42 additions and 49 deletions
|
@ -74,6 +74,7 @@ use Slic3r::Print::SupportMaterial;
|
||||||
use Slic3r::Surface;
|
use Slic3r::Surface;
|
||||||
use Slic3r::TriangleMesh;
|
use Slic3r::TriangleMesh;
|
||||||
our $build = eval "use Slic3r::Build; 1";
|
our $build = eval "use Slic3r::Build; 1";
|
||||||
|
use Thread::Semaphore;
|
||||||
|
|
||||||
use constant SCALING_FACTOR => 0.000001;
|
use constant SCALING_FACTOR => 0.000001;
|
||||||
use constant RESOLUTION => 0.0125;
|
use constant RESOLUTION => 0.0125;
|
||||||
|
@ -86,11 +87,25 @@ use constant INSET_OVERLAP_TOLERANCE => 0.2;
|
||||||
|
|
||||||
# keep track of threads we created
|
# keep track of threads we created
|
||||||
my @threads : shared = ();
|
my @threads : shared = ();
|
||||||
|
my $sema = Thread::Semaphore->new;
|
||||||
|
my $paused = 0;
|
||||||
|
|
||||||
sub spawn_thread {
|
sub spawn_thread {
|
||||||
my ($cb) = @_;
|
my ($cb) = @_;
|
||||||
|
|
||||||
my $thread = threads->create($cb);
|
@_ = ();
|
||||||
|
my $thread = threads->create(sub {
|
||||||
|
local $SIG{'KILL'} = sub {
|
||||||
|
Slic3r::debugf "Exiting thread...\n";
|
||||||
|
Slic3r::thread_cleanup();
|
||||||
|
threads->exit();
|
||||||
|
};
|
||||||
|
local $SIG{'STOP'} = sub {
|
||||||
|
$sema->down;
|
||||||
|
$sema->up;
|
||||||
|
};
|
||||||
|
$cb->();
|
||||||
|
});
|
||||||
push @threads, $thread->tid;
|
push @threads, $thread->tid;
|
||||||
return $thread;
|
return $thread;
|
||||||
}
|
}
|
||||||
|
@ -104,12 +119,6 @@ sub parallelize {
|
||||||
$q->enqueue(@items, (map undef, 1..$params{threads}));
|
$q->enqueue(@items, (map undef, 1..$params{threads}));
|
||||||
|
|
||||||
my $thread_cb = sub {
|
my $thread_cb = sub {
|
||||||
local $SIG{'KILL'} = sub {
|
|
||||||
Slic3r::debugf "Exiting child thread...\n";
|
|
||||||
Slic3r::thread_cleanup();
|
|
||||||
threads->exit;
|
|
||||||
};
|
|
||||||
|
|
||||||
# execute thread callback
|
# execute thread callback
|
||||||
$params{thread_cb}->($q);
|
$params{thread_cb}->($q);
|
||||||
|
|
||||||
|
@ -188,17 +197,38 @@ sub thread_cleanup {
|
||||||
return undef; # this prevents a "Scalars leaked" warning
|
return undef; # this prevents a "Scalars leaked" warning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub get_running_threads {
|
||||||
|
return grep defined($_), map threads->object($_), @threads;
|
||||||
|
}
|
||||||
|
|
||||||
sub kill_all_threads {
|
sub kill_all_threads {
|
||||||
# detach any running thread created in the current one
|
# detach any running thread created in the current one
|
||||||
my @killed = ();
|
my @killed = ();
|
||||||
foreach my $thread (grep defined($_), map threads->object($_), @threads) {
|
foreach my $thread (get_running_threads()) {
|
||||||
$thread->kill('KILL');
|
$thread->kill('KILL');
|
||||||
push @killed, $thread;
|
push @killed, $thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# unlock semaphore before we block on wait
|
||||||
|
# otherwise we'd get a deadlock if threads were paused
|
||||||
|
resume_threads();
|
||||||
$_->join for @killed; # block until threads are killed
|
$_->join for @killed; # block until threads are killed
|
||||||
@threads = ();
|
@threads = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub pause_threads {
|
||||||
|
return if $paused;
|
||||||
|
$paused = 1;
|
||||||
|
$sema->down;
|
||||||
|
$_->kill('STOP') for get_running_threads();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub resume_threads {
|
||||||
|
return unless $paused;
|
||||||
|
$paused = 0;
|
||||||
|
$sema->up;
|
||||||
|
}
|
||||||
|
|
||||||
sub encode_path {
|
sub encode_path {
|
||||||
my ($filename) = @_;
|
my ($filename) = @_;
|
||||||
return encode('locale_fs', $filename);
|
return encode('locale_fs', $filename);
|
||||||
|
|
|
@ -7,7 +7,6 @@ use File::Basename qw(basename dirname);
|
||||||
use List::Util qw(sum first);
|
use List::Util qw(sum first);
|
||||||
use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale deg2rad);
|
use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale deg2rad);
|
||||||
use threads::shared qw(shared_clone);
|
use threads::shared qw(shared_clone);
|
||||||
use Thread::Semaphore;
|
|
||||||
use Wx qw(:button :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc
|
use Wx qw(:button :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc
|
||||||
:panel :sizer :toolbar :window wxTheApp);
|
:panel :sizer :toolbar :window wxTheApp);
|
||||||
use Wx::Event qw(EVT_BUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED
|
use Wx::Event qw(EVT_BUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED
|
||||||
|
@ -43,8 +42,6 @@ use constant PROCESS_DELAY => 0.5 * 1000; # milliseconds
|
||||||
|
|
||||||
my $PreventListEvents = 0;
|
my $PreventListEvents = 0;
|
||||||
|
|
||||||
my $sema = Thread::Semaphore->new;
|
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
my ($parent) = @_;
|
my ($parent) = @_;
|
||||||
|
@ -810,7 +807,7 @@ sub async_apply_config {
|
||||||
|
|
||||||
# pause process thread before applying new config
|
# pause process thread before applying new config
|
||||||
# since we don't want to touch data that is being used by the threads
|
# since we don't want to touch data that is being used by the threads
|
||||||
$self->suspend_background_process;
|
Slic3r::pause_threads();
|
||||||
|
|
||||||
# apply new config
|
# apply new config
|
||||||
my $invalidated = $self->{print}->apply_config($self->GetFrame->config);
|
my $invalidated = $self->{print}->apply_config($self->GetFrame->config);
|
||||||
|
@ -820,9 +817,8 @@ sub async_apply_config {
|
||||||
if ($invalidated) {
|
if ($invalidated) {
|
||||||
# kill current thread if any
|
# kill current thread if any
|
||||||
$self->stop_background_process;
|
$self->stop_background_process;
|
||||||
$self->resume_background_process;
|
|
||||||
} else {
|
} else {
|
||||||
$self->resume_background_process;
|
Slic3r::resume_threads();
|
||||||
}
|
}
|
||||||
|
|
||||||
# schedule a new process thread in case it wasn't running
|
# schedule a new process thread in case it wasn't running
|
||||||
|
@ -857,16 +853,6 @@ sub start_background_process {
|
||||||
# start thread
|
# start thread
|
||||||
@_ = ();
|
@_ = ();
|
||||||
$self->{process_thread} = Slic3r::spawn_thread(sub {
|
$self->{process_thread} = Slic3r::spawn_thread(sub {
|
||||||
local $SIG{'KILL'} = sub {
|
|
||||||
Slic3r::debugf "Background process cancelled; exiting thread...\n";
|
|
||||||
Slic3r::thread_cleanup();
|
|
||||||
threads->exit();
|
|
||||||
};
|
|
||||||
local $SIG{'STOP'} = sub {
|
|
||||||
$sema->down;
|
|
||||||
$sema->up;
|
|
||||||
};
|
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
$self->{print}->process;
|
$self->{print}->process;
|
||||||
};
|
};
|
||||||
|
@ -906,18 +892,6 @@ sub stop_background_process {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub suspend_background_process {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
$sema->down;
|
|
||||||
$_->kill('STOP') for grep $_, $self->{process_thread}, $self->{export_thread};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub resume_background_process {
|
|
||||||
my ($self) = @_;
|
|
||||||
$sema->up;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub export_gcode {
|
sub export_gcode {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
@ -1011,16 +985,6 @@ sub on_process_completed {
|
||||||
our $_thread_self = $self;
|
our $_thread_self = $self;
|
||||||
|
|
||||||
$self->{export_thread} = Slic3r::spawn_thread(sub {
|
$self->{export_thread} = Slic3r::spawn_thread(sub {
|
||||||
local $SIG{'KILL'} = sub {
|
|
||||||
Slic3r::debugf "Export process cancelled; exiting thread...\n";
|
|
||||||
Slic3r::thread_cleanup();
|
|
||||||
threads->exit();
|
|
||||||
};
|
|
||||||
local $SIG{'STOP'} = sub {
|
|
||||||
$sema->down;
|
|
||||||
$sema->up;
|
|
||||||
};
|
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
$_thread_self->{print}->export_gcode(output_file => $_thread_self->{export_gcode_output_file});
|
$_thread_self->{print}->export_gcode(output_file => $_thread_self->{export_gcode_output_file});
|
||||||
};
|
};
|
||||||
|
@ -1278,7 +1242,7 @@ sub object_settings_dialog {
|
||||||
object => $self->{objects}[$obj_idx],
|
object => $self->{objects}[$obj_idx],
|
||||||
model_object => $model_object,
|
model_object => $model_object,
|
||||||
);
|
);
|
||||||
$self->suspend_background_process;
|
Slic3r::pause_threads();
|
||||||
$dlg->ShowModal;
|
$dlg->ShowModal;
|
||||||
|
|
||||||
# update thumbnail since parts may have changed
|
# update thumbnail since parts may have changed
|
||||||
|
@ -1289,11 +1253,10 @@ sub object_settings_dialog {
|
||||||
# update print
|
# update print
|
||||||
if ($dlg->PartsChanged || $dlg->PartSettingsChanged) {
|
if ($dlg->PartsChanged || $dlg->PartSettingsChanged) {
|
||||||
$self->stop_background_process;
|
$self->stop_background_process;
|
||||||
$self->resume_background_process;
|
|
||||||
$self->{print}->reload_object($obj_idx);
|
$self->{print}->reload_object($obj_idx);
|
||||||
$self->schedule_background_process;
|
$self->schedule_background_process;
|
||||||
} else {
|
} else {
|
||||||
$self->resume_background_process;
|
Slic3r::resume_threads();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue