mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	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
		Add a link
		
	
		Reference in a new issue
	
	 Alessandro Ranellucci
						Alessandro Ranellucci