Changeset 11027


Ignore:
Timestamp:
03/09/10 02:28:50 (2 years ago)
Author:
adamk
Message:

A second attempt at fixing the thread vs SQLite bug, this one appears much more likely to work. It may still potentially cause problems if any background thread uses Padre::DB (while database handles won't be copied, the DBD::Driver object will be, and that might cause a problem)

Location:
trunk/Padre/lib/Padre
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Padre/lib/Padre/SlaveDriver.pm

    r11023 r11027  
    4040our $VERSION = '0.58'; 
    4141 
    42 # According to Wx docs, 
    43 # this MUST be loaded before Wx, 
     42# According to Wx docs this MUST be loaded before Wx, 
    4443# so this also happens in the script. 
    4544use threads; 
     
    6160The constructor returns a C<Padre::SlaveDriver> object. 
    6261C<Padre::SlaveDriver> is a singleton. 
     62 
    6363An object is instantiated when the editor object is created. 
    6464 
     
    6969 
    7070    sub new { 
     71        return $SlaveDriver if defined $SlaveDriver; 
     72 
    7173        my $class = shift; 
    72         return $SlaveDriver if defined $SlaveDriver; 
    73         @_           = (); 
     74        @_ = (); 
     75 
    7476        $SlaveDriver = bless { 
    7577            cmd_queue  => Thread::Queue->new, 
     
    7779            task_queue => Thread::Queue->new, 
    7880        } => $class; 
    79         $SlaveDriver->_init_events; 
    80  
    81         # There is no database/locking protection 
    82         # here, so this must happen before we make 
    83         # a long-term connection to the database. 
     81 
     82        # Wx must be loaded before this code fires 
     83        require Padre::Wx; 
     84        $TASK_DONE_EVENT  = Wx::NewEventType() unless defined $TASK_DONE_EVENT; 
     85        $TASK_START_EVENT = Wx::NewEventType() unless defined $TASK_START_EVENT; 
     86 
     87        # Because the following code spawns the slave master, 
     88        # we need to wrap an database anti-lock around it. 
     89        my $locked = Padre::DB->can('connected') && Padre::DB->connected; 
     90        Padre::DB->commit if $locked; 
     91 
     92        # Create the "slave master" top level thread. 
    8493        $SlaveDriver->{master} = threads->create( 
    8594            \&_slave_driver_loop, 
     
    8897        ); 
    8998 
     99        # If we were previously in a database lock restore it 
     100        # so that lock management doesn't freak out. 
     101        Padre::DB->begin if $locked; 
     102 
    90103        return $SlaveDriver; 
    91104    } 
     
    99112} 
    100113 
    101 # done late so that the full Wx has been loaded for sure 
    102 sub _init_events { 
    103     $TASK_DONE_EVENT  = Wx::NewEventType() if not defined $TASK_DONE_EVENT; 
    104     $TASK_START_EVENT = Wx::NewEventType() if not defined $TASK_START_EVENT; 
    105 } 
    106  
    107114=pod 
    108115 
     
    119126    my $self         = shift; 
    120127    my $task_manager = shift; 
     128 
    121129    require Storable; 
    122     $self->{cmd_queue}->enqueue( Storable::freeze( [ $task_manager->task_queue ] ) ); 
    123     return threads->object( $self->{tid_queue}->dequeue ); 
     130    $self->{cmd_queue}->enqueue( 
     131        Storable::freeze( [ $task_manager->task_queue ] ) 
     132    ); 
     133 
     134    return threads->object( 
     135        $self->{tid_queue}->dequeue 
     136    ); 
    124137} 
    125138 
     
    152165sub cleanup { 
    153166    my $self = shift; 
     167 
    154168    if ( defined $self->{master} and defined $self->{cmd_queue} ) { 
    155169        $self->{cmd_queue}->enqueue('STOP'); 
     170 
    156171        require Time::HiRes; 
    157172        Time::HiRes::usleep(5000); # 5 milli-sec 
     173 
    158174        if ( $self->{master}->is_joinable ) { 
    159175            $self->{master}->join; 
     
    165181 
    166182sub DESTROY { 
    167     $_[0]->cleanup; 
    168 } 
    169  
    170 ########################## 
     183    shift->cleanup; 
     184} 
     185 
     186 
     187 
     188 
     189 
     190###################################################################### 
    171191# Worker thread main loop 
     192 
    172193sub _worker_loop { 
    173     my ($queue) = @_; 
    174     @_ = (); # hack to avoid "Scalars leaked" 
     194    my ( $queue ) = @_; 
     195    @_ = (); # Hack to avoid "Scalars leaked" 
    175196 
    176197    require Storable; 
     
    178199 
    179200    # Set the thread-specific main-window pointer 
    180     my $main = Padre->ide->wx; 
    181  
    182     #warn threads->tid() . " -- Hi, I'm a thread."; 
     201    my $wx = Padre->ide->wx; 
     202 
     203    # warn threads->tid() . " -- Hi, I'm a thread."; 
    183204 
    184205    while ( my $frozen_task = $queue->dequeue ) { 
    185206 
    186         #warn threads->tid() . " -- got task."; 
    187  
    188         #warn("THREAD TERMINATING"), return 1 if not ref($task) and $task eq 'STOP'; 
     207        # warn threads->tid() . " -- got task."; 
     208 
     209        # warn("THREAD TERMINATING"), return 1 if not ref($task) and $task eq 'STOP'; 
    189210        return 1 if not ref($frozen_task) and $frozen_task eq 'STOP'; 
    190211 
    191212        my $task = Padre::Task->deserialize( \$frozen_task ); 
    192         $task->{__thread_id} = threads->tid(); 
    193  
    194         my $thread_start_event = 
    195             Wx::PlThreadEvent->new( -1, $TASK_START_EVENT, $task->{__thread_id} . ";" . ref($task) ); 
    196         Wx::PostEvent( $main, $thread_start_event ); 
     213        $task->{__thread_id} = threads->tid; 
     214 
     215        my $thread_start_event = Wx::PlThreadEvent->new( 
     216            -1, 
     217            $TASK_START_EVENT, 
     218            $task->{__thread_id} . ";" . ref($task), 
     219        ); 
     220        Wx::PostEvent( $wx, $thread_start_event ); 
    197221 
    198222        # RUN 
     
    203227        $task->serialize( \$frozen_task ); 
    204228 
    205         my $thread_done_event = Wx::PlThreadEvent->new( -1, $TASK_DONE_EVENT, $frozen_task ); 
    206         Wx::PostEvent( $main, $thread_done_event ); 
    207  
    208         #warn threads->tid() . " -- done with task."; 
    209     } 
    210  
     229        my $thread_done_event = Wx::PlThreadEvent->new( 
     230            -1, 
     231            $TASK_DONE_EVENT, 
     232            $frozen_task, 
     233        ); 
     234        Wx::PostEvent( $wx, $thread_done_event ); 
     235 
     236        # warn threads->tid() . " -- done with task."; 
     237    } 
    211238} 
    212239 
     
    217244    while ( my $args = $inqueue->dequeue ) { # args is frozen [$main, $queue] 
    218245        last if $args eq 'STOP'; 
    219         my $task_queue = Padre::SlaveDriver->new->task_queue; 
    220  
    221         # Apply the database anti-lock, so there are no active DBI connection 
    222         # handles at the time we spawn the thread. 
    223         # If Padre::DB is not loaded at all, the following returns false and 
    224         # we never make the calls to the non-existant class. 
    225         my $locked = Padre::DB->can('connected') && Padre::DB->connected; 
    226         if ( $locked ) { 
    227             Padre::DB->commit; 
    228         } 
    229  
    230         # Do the actual thread spawn 
     246        my $task_queue    = Padre::SlaveDriver->new->task_queue; 
    231247        my $worker_thread = threads->create( \&_worker_loop, $task_queue ); 
    232  
    233         # Release the anti-lock on the database 
    234         if ( $locked ) { 
    235             Padre::DB->begin; 
    236         } 
    237  
    238         # Continue onwards with thready stuff 
    239248        $outqueue->enqueue($worker_thread->tid); 
    240249    } 
     250 
    241251    return 1; 
    242252} 
  • trunk/Padre/lib/Padre/TaskManager.pm

    r10997 r11027  
    9696# communicate to the main thread over the life of a service. 
    9797our $SERVICE_POLL_EVENT : shared; 
    98 BEGIN { $SERVICE_POLL_EVENT = Wx::NewEventType; } 
     98BEGIN { 
     99    $SERVICE_POLL_EVENT = Wx::NewEventType; 
     100} 
    99101 
    100102# remember whether the event handlers were initialized... 
     
    109111sub new { 
    110112    my $class = shift; 
     113    $DB::single = 1; 
    111114 
    112115    return $SINGLETON if defined $SINGLETON; 
     116 
     117    my $driver = Padre::SlaveDriver->new; 
    113118 
    114119    my $self = $SINGLETON = bless { 
     
    120125        workers => [], 
    121126 
    122         # grab a copy of the task_queue that's now handled by the slave driver 
    123         task_queue    => Padre::SlaveDriver->new()->task_queue, 
     127        # Grab a copy of the task_queue that's now handled by the slave driver 
     128        task_queue    => $driver->task_queue, 
    124129        running_tasks => {}, 
    125130    }, $class; 
     
    144149        $REAP_TIMER = Wx::Timer->new( $main, $timerid ); 
    145150        Wx::Event::EVT_TIMER( 
    146             $main, $timerid, sub { $SINGLETON->reap(); }, 
     151            $main, $timerid, sub { 
     152                $SINGLETON->reap; 
     153            }, 
    147154        ); 
    148         $REAP_TIMER->Start( $self->reap_interval, Wx::wxTIMER_CONTINUOUS ); 
     155        $REAP_TIMER->Start( 
     156            $self->reap_interval, 
     157            Wx::wxTIMER_CONTINUOUS, 
     158        ); 
    149159    } 
    150160 
     
    423433 
    424434    # cleanup master thread, too 
    425     Padre::SlaveDriver->new->cleanup(); 
     435    Padre::SlaveDriver->new->cleanup; 
    426436 
    427437    # didn't work the nice way? 
     
    503513 
    504514sub workers { 
    505     my $self = shift; 
    506     return @{ $self->{workers} }; 
     515    $_[0]->{workers}; 
    507516} 
    508517 
     
    522531 
    523532sub on_task_done_event { 
    524     my ( $main, $event ) = @_; @_ = (); # hack to avoid "Scalars leaked" 
     533    my ( $main, $event ) = @_; 
     534    @_ = (); # hack to avoid "Scalars leaked" 
    525535    my $frozen = $event->GetData; 
    526536 
Note: See TracChangeset for help on using the changeset viewer.