[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