Thread-safe FileUtils.cd

  • Follow


[Note:  parts of this message were removed to make it a legal post.]

Hi all,

I have a build tool that I've written in Ruby that uses this construct to
enter a directory, perform some long-running (several seconds) tasks then
exit back to the original working directory:

FileUtils.cd(dir) do
  # expensive operations
end

Now I'm trying to write another tool that uses this build library to run
several builds at once in different Threads. Problem is, the FileUtils.cd
commands overlap and conflict with each other, causing the builds to fail. I
have a lot of code already out in production that relies on this directory
being set correctly (users can write hooks into the build system, and these
hooks assume a certain working directory), so I can't remove the cd() call.

My question is, is there a way of setting the working directory on a
per-thread basis, or is it a global property of the Ruby process that cannot
be made thread-safe?

Cheers,
James

-- 
James Coglan
http://jcoglan.com

0
Reply jcoglan (199) 9/20/2009 5:50:30 PM

The current working process is a global property of the underlaying 
system process.

A system Process has one currency working directory, not two, or more.

You can do your directory / filename calculations, using the absolute 
directory path, without any race conditions.

--

Markus


James Coglan wrote:
> Hi all,
> 
> I have a build tool that I've written in Ruby that uses this construct to
> enter a directory, perform some long-running (several seconds) tasks then
> exit back to the original working directory:
> 
> FileUtils.cd(dir) do
>   # expensive operations
> end
> 
> Now I'm trying to write another tool that uses this build library to run
> several builds at once in different Threads. Problem is, the FileUtils.cd
> commands overlap and conflict with each other, causing the builds to fail. I
> have a lot of code already out in production that relies on this directory
> being set correctly (users can write hooks into the build system, and these
> hooks assume a certain working directory), so I can't remove the cd() call.
> 
> My question is, is there a way of setting the working directory on a
> per-thread basis, or is it a global property of the Ruby process that cannot
> be made thread-safe?
> 
> Cheers,
> James
> 

0
Reply mbj1 (28) 9/20/2009 5:57:38 PM


[Note:  parts of this message were removed to make it a legal post.]

2009/9/20 Markus Schirp <mbj@seonic.net>

> The current working process is a global property of the underlaying system
> process.
>
> A system Process has one currency working directory, not two, or more.
>
> You can do your directory / filename calculations, using the absolute
> directory path, without any race conditions.


Yes, I realise now I should have forced users to use absolute paths, but as
it stands there's code out in the wild with stuff like:

hook :after_build do |build|
  FileUtils.cp 'README', File.join(build.build_dir, 'README')
end

So the working directory needs to be set so that 'README' can be found
correctly. Internally the tool uses absolute paths, so e.g.
`build.build_dir` is an absolute path, but code written by users is likely
to use relative paths.

0
Reply jcoglan (199) 9/20/2009 6:03:26 PM

Forcing the users to use absolute paths may just hides the problem. 
Maybe you should expand the users "relative" paths before using them.

Or monkeypatch FileUtils, and maybe dozens ruby core classes to support 
a "thread-safe" cwd.





James Coglan wrote:
> 2009/9/20 Markus Schirp <mbj@seonic.net>
> 
>> The current working process is a global property of the underlaying system
>> process.
>>
>> A system Process has one currency working directory, not two, or more.
>>
>> You can do your directory / filename calculations, using the absolute
>> directory path, without any race conditions.
> 
> 
> Yes, I realise now I should have forced users to use absolute paths, but as
> it stands there's code out in the wild with stuff like:
> 
> hook :after_build do |build|
>   FileUtils.cp 'README', File.join(build.build_dir, 'README')
> end
> 
> So the working directory needs to be set so that 'README' can be found
> correctly. Internally the tool uses absolute paths, so e.g.
> `build.build_dir` is an absolute path, but code written by users is likely
> to use relative paths.
> 

0
Reply mbj1 (28) 9/20/2009 6:10:49 PM

2009/9/20 Markus Schirp <mbj@seonic.net>:
> Forcing the users to use absolute paths may just hides the problem. Maybe
> you should expand the users "relative" paths before using them.
>
> Or monkeypatch FileUtils, and maybe dozens ruby core classes to support a
> "thread-safe" cwd.

That would be an option but IMHO it would be tedious and error prone.
You can easily miss a class and introduce unwanted effects.

As far as I can see the only way to make cwd thread safe would be to
use the block form and synchronize access, i.e. one thread changes
cwd, does its work and returns cwd to the old status.  For obvious
reasons this is not really a good idea.  IMHO the only reasonable way
to go is to

a) use cwd only in single threaded programs or with explicit
synchronization guards
b) do not change cwd and use absolute path names, even if that means
converting user input / method arguments

Kind regards

robert

-- 
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

0
Reply shortcutter (5766) 9/22/2009 8:41:18 AM

4 Replies
24 Views

(page loaded in 0.059 seconds)


Reply: