This is the mail archive of the cygwin-apps mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

More fault tolerant rebase (was Re: libtcl8.5.dll collides with Cygwin DLL by default)


On Mar  8 10:12, Corinna Vinschen wrote:
> What rebase *should* do is to mark the DLLs as blocked, and keep them in
> the list together with their current address and size, so it can arrange
> the addresses of the other DLLs, taking the blocked address space into
> account, just like it does with the Cygwin DLL.  And of course, the DLL
> should not be removed from the database.
> 
> Is there anybody here who would like to tackle this?

After the roaring silence died down, I thought I should try myself.
Here's my idea how to handfle that problem.  It's not even much code.

I would be really grateful if somebody (Chuck? Jason? Yaakov?) could have a 
look if the idea is ok and maybe even test it.  With this code, the
DLLs are tested if they allow writing at the time, and if not, are
marked as not rebaseable.  If so, rebase will not try to move them,
and they are kept in the database nevertheless.


Corinna


Index: rebase-db.h
===================================================================
RCS file: /sourceware/projects/cygwin-apps-home/cvsfiles/rebase/rebase-db.h,v
retrieving revision 1.3
diff -u -p -r1.3 rebase-db.h
--- rebase-db.h	5 Aug 2011 14:21:11 -0000	1.3
+++ rebase-db.h	9 Mar 2012 20:26:11 -0000
@@ -63,8 +63,10 @@ typedef struct _img_info
   ULONG   size;		/* Size of the DLL at rebased time.                  */
   ULONG   slot_size;	/* Size of the DLL rounded to allocation granularity.*/
   struct {		/* Flags                                             */
-    unsigned needs_rebasing : 1; /* Set to 0 in the database.  Used only     */
-				 /* while rebasing.                          */
+    ULONG needs_rebasing : 1; /* Set to 0 in the database.  Used only        */
+			      /* while rebasing.                             */
+    ULONG cannot_rebase  : 1; /* Set to 0 in the database.  Used only        */
+			      /* while rebasing.                             */
   } flag;
 } img_info_t;
 
Index: rebase.c
===================================================================
RCS file: /sourceware/projects/cygwin-apps-home/cvsfiles/rebase/rebase.c,v
retrieving revision 1.12
diff -u -p -r1.12 rebase.c
--- rebase.c	9 Aug 2011 09:32:47 -0000	1.12
+++ rebase.c	9 Mar 2012 20:26:11 -0000
@@ -269,8 +269,11 @@ save_image_info ()
   /* Remove all DLLs which couldn't be rebased from the list before storing
      it in the database file. */
   for (i = 0; i < img_info_size; ++i)
-    if (img_info_list[i].flag.needs_rebasing)
-      img_info_list[i--] = img_info_list[--img_info_size];
+    {
+      img_info_list[i].flag.cannot_rebase = 0;
+      if (img_info_list[i].flag.needs_rebasing)
+	img_info_list[i--] = img_info_list[--img_info_size];
+    }
   /* Create a temporary file to write to. */
   fd = mkstemp (tmp_file);
   if (fd < 0)
@@ -509,6 +512,17 @@ load_image_info ()
   return ret;
 }
 
+static BOOL
+set_cannot_rebase (img_info_t *img)
+{
+  int fd = open (img->name, O_WRONLY);
+  if (fd < 0)
+    img->flag.cannot_rebase = 1;
+  else
+    close (fd);
+  return img->flag.cannot_rebase;
+}
+
 int
 merge_image_info ()
 {
@@ -541,6 +555,9 @@ merge_image_info ()
     {
       for (i = img_info_rebase_start; i < img_info_size; ++i)
 	{
+	  /* First test if we can open the DLL for writing.  If not, it's
+	     probably blocked by another process. */
+	  set_cannot_rebase (&img_info_list[i]);
 	  match = bsearch (&img_info_list[i], img_info_list,
 			   img_info_rebase_start, sizeof (img_info_t),
 			   img_info_name_cmp);
@@ -551,8 +568,10 @@ merge_image_info ()
 		 of the old file.  If so, screw the new file into the old slot.
 		 Otherwise set base to 0 to indicate that this DLL needs a new
 		 base address. */
-	      if (match->base != img_info_list[i].base
-		  || match->slot_size < img_info_list[i].slot_size)
+	      if (img_info_list[i].flag.cannot_rebase)
+		match->base = img_info_list[i].base;
+	      else if (match->base != img_info_list[i].base
+		       || match->slot_size < img_info_list[i].slot_size)
 		{
 		  /* Reuse the old address if possible. */
 		  if (match->slot_size < img_info_list[i].slot_size)
@@ -566,23 +585,24 @@ merge_image_info ()
 	      free (img_info_list[i].name);
 	      img_info_list[i--] = img_info_list[--img_info_size];
 	    }
-	  else
+	  else if (!img_info_list[i].flag.cannot_rebase)
 	    /* Not in database yet.  Set base to 0 to choose a new one. */
 	    img_info_list[i].base = 0;
 	}
-      /* After eliminating the duplicates, check if the user requested
-	 a new base address on the command line.  If so, overwrite all
-	 base addresses with 0 and set img_info_rebase_start to 0, to
-	 skip any further test. */
-      if (force_rebase_flag)
-	img_info_rebase_start = 0;
     }
-  if (!img_info_rebase_start)
+  if (!img_info_rebase_start || force_rebase_flag)
     {
       /* No database yet or enforcing a new base address.  Set base of all
-	 DLLs to 0. */
+	 DLLs to 0, if possible. */
       for (i = 0; i < img_info_size; ++i)
-	img_info_list[i].base = 0;
+	{
+	  /* Test DLLs already in database for writability. */
+	  if (i < img_info_rebase_start)
+	    set_cannot_rebase (&img_info_list[i]);
+	  if (!img_info_list[i].flag.cannot_rebase)
+	    img_info_list[i].base = 0;
+	}
+      img_info_rebase_start = 0;
     }
 
   /* Now sort the old part of the list by base address. */
@@ -596,8 +616,10 @@ merge_image_info ()
       ULONG64 cur_base;
       ULONG cur_size, slot_size;
 
-      /* Files with the needs_rebasing flag set have been checked already. */
-      if (img_info_list[i].flag.needs_rebasing)
+      /* Files with the needs_rebasing or cannot_rebase flags set have been
+	 checked already. */
+      if (img_info_list[i].flag.needs_rebasing
+      	  || img_info_list[i].flag.cannot_rebase)
 	continue;
       /* Check if the files in the old list still exist.  Drop non-existant
 	 or unaccessible files. */
@@ -613,24 +635,34 @@ merge_image_info ()
 	  continue;
 	}
       slot_size = roundup2 (cur_size, ALLOCATION_SLOT);
-      /* If the file has been reinstalled, try to rebase to the same address
-	 in the first place. */
-      if (cur_base != img_info_list[i].base)
+      if (set_cannot_rebase (&img_info_list[i]))
+	img_info_list[i].base = cur_base;
+      else
 	{
-	  img_info_list[i].flag.needs_rebasing = 1;
-	  /* Set cur_base to the old base to simplify subsequent tests. */
-	  cur_base = img_info_list[i].base;
+	  /* If the file has been reinstalled, try to rebase to the same address
+	     in the first place. */
+	  if (cur_base != img_info_list[i].base)
+	    {
+	      img_info_list[i].flag.needs_rebasing = 1;
+	      /* Set cur_base to the old base to simplify subsequent tests. */
+	      cur_base = img_info_list[i].base;
+	    }
+	  /* However, if the DLL got bigger and doesn't fit into its slot
+	     anymore, rebase this DLL from scratch. */
+	  if (i + 1 < img_info_rebase_start
+	      && cur_base + slot_size + offset >= img_info_list[i + 1].base)
+	    img_info_list[i].base = 0;
+	  /* Does the previous DLL reach into the address space of this
+	     DLL?  This happens if the previous DLL is not rebaseable. */
+	  else if (i > 0 && cur_base < img_info_list[i - 1].base
+				       + img_info_list[i + 1].slot_size)
+	    img_info_list[i].base = 0;
+	  /* Does the file match the base address requirements?  If not,
+	     rebase from scratch. */
+	  else if ((down_flag && cur_base + slot_size + offset >= image_base)
+		   || (!down_flag && cur_base < image_base))
+	    img_info_list[i].base = 0;
 	}
-      /* However, if the DLL got bigger and doesn't fit into its slot
-	 anymore, rebase this DLL from scratch. */
-      if (i + 1 < img_info_rebase_start
-	  && cur_base + slot_size + offset >= img_info_list[i + 1].base)
-	img_info_list[i].base = 0;
-      /* Does the file match the base address requirements?  If not,
-	 rebase from scratch. */
-      else if ((down_flag && cur_base + slot_size + offset >= image_base)
-	       || (!down_flag && cur_base < image_base))
-	img_info_list[i].base = 0;
       /* Unconditionally overwrite old with new size. */
       img_info_list[i].size = cur_size;
       img_info_list[i].slot_size = slot_size;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]