Changeset 118303


Ignore:
Timestamp:
Mar 29, 2014, 7:20:00 PM (6 years ago)
Author:
cal@…
Message:

base: prevent further race conditions with SIGINT and SIGTERM during activation and deactivation where possible

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/base/src/registry2.0/portimage.tcl

    r118302 r118303  
    135135
    136136    _activate_contents $requested
    137     $requested state installed
    138137}
    139138
     
    202201
    203202    _deactivate_contents $requested [$requested files] $force
    204     $requested state imaged
    205203}
    206204
     
    542540                    }
    543541                }
     542
     543                # Recording that the port has been activated should be done
     544                # here so that this information cannot be inconsistent with the
     545                # state of the files on disk.
     546                $port state installed
    544547            } catch {{POSIX SIG SIGINT} eCode eMessage} {
    545548                # Pressing ^C will (often?) print "^C" to the terminal; send
     
    564567    } catch {*} {
    565568        # This code must run to completion, or the installation might be left
    566         # in an inconsistent state
    567         signal block {TERM INT}
    568 
    569         # roll back activation of this port
    570         if {[info exists deactivate_this]} {
    571             _deactivate_contents $port $rollback_filelist yes yes
    572         }
    573         # if any errors occurred, move backed-up files back to their original
    574         # locations, then rethrow the error. Transaction rollback will take care
    575         # of this in the registry.
    576         foreach file $backups {
    577             ::file rename -force -- "${file}${baksuffix}" $file
    578         }
    579         # reactivate deactivated ports
    580         foreach entry [array names todeactivate] {
    581             if {[$entry state] eq "imaged" && ($noexec || ![registry::run_target $entry activate ""])} {
    582                 activate [$entry name] [$entry version] [$entry revision] [$entry variants] [list ports_activate_no-exec $noexec]
    583             }
    584         }
    585 
    586         # We've completed all critical operations, re-enable the TERM and INT
    587         # signals.
    588         signal unblock {TERM INT}
     569        # in an inconsistent state. We store the old signal handling state,
     570        # block the critical signals and restore to the previous state instead
     571        # of unblocking.
     572        # Note that this still contains a race condition: A user could press ^C
     573        # fast enough so that the second error arrives before the error is
     574        # caught, re-thrown and re-caught here. As far as I can see, there's no
     575        # easy way around this problem.
     576        set osignals [signal get {TERM INT}]
     577        try {
     578            # Block signals to avoid inconsistiencies.
     579            signal block {TERM INT}
     580
     581            # roll back activation of this port
     582            if {[info exists deactivate_this]} {
     583                _deactivate_contents $port $rollback_filelist yes yes
     584            }
     585            # if any errors occurred, move backed-up files back to their original
     586            # locations, then rethrow the error. Transaction rollback will take care
     587            # of this in the registry.
     588            foreach file $backups {
     589                ::file rename -force -- "${file}${baksuffix}" $file
     590            }
     591            # reactivate deactivated ports
     592            foreach entry [array names todeactivate] {
     593                if {[$entry state] eq "imaged" && ($noexec || ![registry::run_target $entry activate ""])} {
     594                    activate [$entry name] [$entry version] [$entry revision] [$entry variants] [list ports_activate_no-exec $noexec]
     595                }
     596            }
     597        } finally {
     598            # We've completed all critical operations, re-enable the TERM and
     599            # INT signals.
     600            signal set $osignals
     601        }
    589602
    590603        # remove temp image dir
     
    661674    set files [lsort -decreasing -unique $files]
    662675
    663     # Remove all elements.
    664     if {!$rollback} {
    665         registry::write {
    666             $port deactivate $imagefiles
     676    # Avoid interruptions while removing the files and updating the database to
     677    # prevent inconsistencies from forming between filesystem and database.
     678    set osignals [signal get {TERM INT}]
     679
     680    try {
     681        # Block the TERM and INT signals to avoid being interrupted. Note that
     682        # they might already be block at this point because
     683        # _deactivate_contents might be called during rollback of
     684        # _activate_contents, but because we're storing the old signal state
     685        # and returning to that instead of unblocking it doesn't matter.
     686        signal block {TERM INT}
     687
     688        # Remove all elements.
     689        if {!$rollback} {
     690            registry::write {
     691                $port deactivate $imagefiles
     692                foreach file $files {
     693                    _deactivate_file $file
     694                }
     695
     696                # Update the port's state in the same transaction as the file
     697                # delete operations.
     698                $port state imaged
     699            }
     700        } else {
    667701            foreach file $files {
    668702                _deactivate_file $file
    669703            }
    670704        }
    671     } else {
    672         foreach file $files {
    673             _deactivate_file $file
    674         }
     705    } finally {
     706        # restore the signal block state
     707        signal set $osignals
    675708    }
    676709}
Note: See TracChangeset for help on using the changeset viewer.