Avoid collisions between parallel installations of Cygwin

Charles Wilson cygwin@cwilson.fastmail.fm
Wed Oct 21 22:03:00 GMT 2009


[Consolidated reply]:
Corinna wrote:
> On Oct 21 14:15, Charles Wilson wrote:
>> To sum up: I think Corinna's approach is fine -- one big struct
>> containing all the resources, and a single magic string, so long as
>> 
>> (1) the script or binary tool that modifies the properties checks the
>> version of the properties structure, and prints an error if doesn't
>> match the specific version that the script knows about.
> 
> IMHO too complicated again.  Think of some Windows structures.  They
> don't have a version number, just a sizeof member.  
> 
> Same here.  Assume the struct looks like this:
> 
>   struct props {
>     char magic[PROPS_MAGIG_LEN];
>     size_t cb;
>     ulong disable_key;
>     [...]
>   };
> 
> If the cb value is 4, we only support the disable_key value.  The tool
> script of the same age only supports the disable_key value either.  So
> no worry.
> 
> If the cb value is 8, we also support the foo_bar value.  The old tool
> script version ...
> 
> If the cb value is 12, ... 

The limitation of this approach -- which might be acceptable, but it IS
a limitation -- is that you are not allowed to change the semantics of
any existing values, or ever replace old members with new names of the
same size ("member #2 is a 32 bit value representing "disable_key" if cb
is less than 36, but if cb is greater than 36 it tells the console
handler to enable the cursor blink behavior..."  Not just no, but hell no.):

   struct props {
     char magic[PROPS_MAGIG_LEN];
     size_t cb;
     ulong disable_key; ---------->   ulong use_blinking_cursor;
     [...]
   };

You can never /change/, you can only /extend/.  Related: if your struct
use char arrays (as opposed to pointers to dynamically allocated char*,
which are not practical for this sort of thing), you can't ever change
the size of those, unless it's the last member of the struct.  Dunno if
that would ever be an issue.  But with explicit versioning, rather than
size-based implied versioning, all things are possible.

Of course, that comes at a cost.  You way, old tools will always be able
to manipulate the members they know about, for any new DLL -- doing so
may not have any effect if a particular struct member no longer has any
realistic use in the new DLL, but that's ok.  With explicit versioning
there are no guarantees about the stability of members between versions.

It's just a choice.  You da boss, pick one (but please don't use windows
as the gold standard of all things excellent in API design.)

> Well, maybe.  In that case the tool just creates a copy with changed
> settings and asks the user to "stop all Cygwin processes and rename
> /bin/cygwin1.dll.NEW to /bin/cygwni1.dll to activate the new setting".

Ack.

> However, I don't think there are lots of people out there who really use
> this tool, let alone understand the setting.

Agree.

>> Newer tools would need to know which elements were safe to touch, in
>> older DLLs.
> 
> It's really simple, IMHO.  See above.  There should never be a reason to
> change the layout of the props.

While we only have one, or at best a small handful, I agree -- and I
think that should continue to be the case.  MOST configuration settings
should go somewhere else (/etc/*, $CYGWIN, ...); it's the rare bird
indeed that really needs to be treated like enable_unique_object_names.

So the following scenario may be totally unrealistic: suppose there are
thirty different properties (the HORROR!).  Say...there's one
controlling the amount of memory allowed for spawned processes.  We use
a 32bit value.  In ten years, 4GB is going to be peanuts, and we'll want
a 64bit number here.  So, since we can't change the layout (that is, the
size of each element) and we can't change the semantics (otherwise,
tools won't be able to modify older dlls), we have to leave
   int32_t   process_stacksize;
alone.  Maybe we rename it
   int32_t   old_process_stacksize;
and add to the end of the struct
   int64_t   new_process_stacksize;
or something.  But these are the kind of games you have to play ---

IF the API changes "much" or is likely to need these sorts of mods.

Which is an argument for not putting very much in there; which was the
plan anyway, I think.  The less you put there, the fewer "opportunities"
for changes...

>> Right. We don't need it now; but it could be something to think about
>> for later just in general (XDR is a fairly useful facility; I'd like to
>> see it in newlib someday).
> 
> Nothing really keeps you from providing a newlib patch adding this
> functionality ;)

What worries me about that is trying to get it validated on all 392
different newlib platforms all at once (and I'm not going to do anything
before 1.7.x is released).  Is there a way to add general functionality
to newlib, so that it only has immediate effect on one platform but can
later -- one at a time? -- be enabled on additional ones after
verification (and need) by the users of those platforms?

Corinna also wrote:
> On Oct 21 13:13, Charles Wilson wrote:
>> Well, that's true too. You complain though about the time involved in
>> the whole FindResource/LockResource deal. But, is that really a problem?
>> Unless these items are explicitly immutable (and, in the case of the
>> disable-unique-object-names, it pretty well SHOULD be immutable!), you'd
>> still need to manage a lock when accessing the global struct that holds
>> their values, right?
> 
> Why?  The external tool changes the binary data on disk.  It does not
> change the representation within a DLL in memory.

Well, the FindResource/LockResource has no meaningful time impact on the
standalone tool; it's instantaneous as far as the user who invoked it is
concerned.  So, if we're worried about the runtime effects, then we're
talking about the in-kernel accesses to the struct or variables which
hold the values.

Since you're inside cygwin, and these are just variables, then they can
conceivably be modified -- especially if their values are obtained
(populated) from the persistent storage in the .rsrc section: the
variables themselves must be mutable in order to load their values at
early startup.  If something CAN be changed at runtime, you can bet that
it WILL be changed when you did not originally plan for it -- unless you
take explicit steps to obfuscate (private file-scope static members,
with only read-only accessors that return copies; private members of a
wrapper class that expose only const references, etc). That's the sort
of thing I meant when I said "make them explicitly immutable".

Now, if it's just a *const* struct populated by the OS when it loads
.rdata into memory, that's a whole 'nother thing -- and again, they'd be
explicitly immutable in that case.

--
Chuck



More information about the Cygwin-developers mailing list