[118303] trunk/base/src/registry2.0/portimage.tcl
cal at macports.org
cal at macports.org
Sat Mar 29 12:20:00 PDT 2014
Revision: 118303
https://trac.macports.org/changeset/118303
Author: cal at macports.org
Date: 2014-03-29 12:20:00 -0700 (Sat, 29 Mar 2014)
Log Message:
-----------
base: prevent further race conditions with SIGINT and SIGTERM during activation and deactivation where possible
Modified Paths:
--------------
trunk/base/src/registry2.0/portimage.tcl
Modified: trunk/base/src/registry2.0/portimage.tcl
===================================================================
--- trunk/base/src/registry2.0/portimage.tcl 2014-03-29 16:41:17 UTC (rev 118302)
+++ trunk/base/src/registry2.0/portimage.tcl 2014-03-29 19:20:00 UTC (rev 118303)
@@ -134,7 +134,6 @@
ui_msg "$UI_PREFIX [format [msgcat::mc "Activating %s @%s"] $name $specifier]"
_activate_contents $requested
- $requested state installed
}
# takes a composite version spec rather than separate version,revision,variants
@@ -201,7 +200,6 @@
}
_deactivate_contents $requested [$requested files] $force
- $requested state imaged
}
proc _check_registry {name version revision variants} {
@@ -541,6 +539,11 @@
lappend rollback_filelist $file
}
}
+
+ # Recording that the port has been activated should be done
+ # here so that this information cannot be inconsistent with the
+ # state of the files on disk.
+ $port state installed
} catch {{POSIX SIG SIGINT} eCode eMessage} {
# Pressing ^C will (often?) print "^C" to the terminal; send
# a linebreak so our message appears after that.
@@ -563,30 +566,40 @@
}
} catch {*} {
# This code must run to completion, or the installation might be left
- # in an inconsistent state
- signal block {TERM INT}
+ # in an inconsistent state. We store the old signal handling state,
+ # block the critical signals and restore to the previous state instead
+ # of unblocking.
+ # Note that this still contains a race condition: A user could press ^C
+ # fast enough so that the second error arrives before the error is
+ # caught, re-thrown and re-caught here. As far as I can see, there's no
+ # easy way around this problem.
+ set osignals [signal get {TERM INT}]
+ try {
+ # Block signals to avoid inconsistiencies.
+ signal block {TERM INT}
- # roll back activation of this port
- if {[info exists deactivate_this]} {
- _deactivate_contents $port $rollback_filelist yes yes
- }
- # if any errors occurred, move backed-up files back to their original
- # locations, then rethrow the error. Transaction rollback will take care
- # of this in the registry.
- foreach file $backups {
- ::file rename -force -- "${file}${baksuffix}" $file
- }
- # reactivate deactivated ports
- foreach entry [array names todeactivate] {
- if {[$entry state] eq "imaged" && ($noexec || ![registry::run_target $entry activate ""])} {
- activate [$entry name] [$entry version] [$entry revision] [$entry variants] [list ports_activate_no-exec $noexec]
+ # roll back activation of this port
+ if {[info exists deactivate_this]} {
+ _deactivate_contents $port $rollback_filelist yes yes
}
+ # if any errors occurred, move backed-up files back to their original
+ # locations, then rethrow the error. Transaction rollback will take care
+ # of this in the registry.
+ foreach file $backups {
+ ::file rename -force -- "${file}${baksuffix}" $file
+ }
+ # reactivate deactivated ports
+ foreach entry [array names todeactivate] {
+ if {[$entry state] eq "imaged" && ($noexec || ![registry::run_target $entry activate ""])} {
+ activate [$entry name] [$entry version] [$entry revision] [$entry variants] [list ports_activate_no-exec $noexec]
+ }
+ }
+ } finally {
+ # We've completed all critical operations, re-enable the TERM and
+ # INT signals.
+ signal set $osignals
}
- # We've completed all critical operations, re-enable the TERM and INT
- # signals.
- signal unblock {TERM INT}
-
# remove temp image dir
::file delete -force $extracted_dir
throw
@@ -660,18 +673,38 @@
# are after their elements.
set files [lsort -decreasing -unique $files]
- # Remove all elements.
- if {!$rollback} {
- registry::write {
- $port deactivate $imagefiles
+ # Avoid interruptions while removing the files and updating the database to
+ # prevent inconsistencies from forming between filesystem and database.
+ set osignals [signal get {TERM INT}]
+
+ try {
+ # Block the TERM and INT signals to avoid being interrupted. Note that
+ # they might already be block at this point because
+ # _deactivate_contents might be called during rollback of
+ # _activate_contents, but because we're storing the old signal state
+ # and returning to that instead of unblocking it doesn't matter.
+ signal block {TERM INT}
+
+ # Remove all elements.
+ if {!$rollback} {
+ registry::write {
+ $port deactivate $imagefiles
+ foreach file $files {
+ _deactivate_file $file
+ }
+
+ # Update the port's state in the same transaction as the file
+ # delete operations.
+ $port state imaged
+ }
+ } else {
foreach file $files {
_deactivate_file $file
}
}
- } else {
- foreach file $files {
- _deactivate_file $file
- }
+ } finally {
+ # restore the signal block state
+ signal set $osignals
}
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20140329/00b7c7fd/attachment.html>
More information about the macports-changes
mailing list