Arquivos
chromium/base/file_descriptor_shuffle.h
agl@chromium.org d2a3ee5e5a POSIX: Add code for shuffling file descriptors.
When forking a child process, one often wants to move existing file
descriptors to well known locations (stdout, stderr etc). However,
this is a process bedeviled with corner cases. Consider the case where
you open two file descriptors, get assigned fds 1 and 0 for them and
wish to shuffle them so that they end up in slots 0 and 1. Our current
code fails in this case.

We also have a problem where we're currently trying to mark file
descriptors as close-on-exec rather than closing them in the child
process. This is inherently broken in a multithreaded process where
another thread can open a file descriptor and race the loop which is
trying to mark them.

Thus, on Linux we switch to close-after-fork where we known that no
other threads exist in the process. On Mac, the code is sufficiently
different that this simple fix isn't applicable and one of the Mac
folks will need to take a look.

http://codereview.chromium.org/100127
BUG=11174


git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14978 0039d316-1c4b-4281-b951-d872f2087c98
2009-04-30 19:40:03 +00:00

77 linhas
2.7 KiB
C++

// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_FILE_DESCRIPTOR_SHUFFLE_H_
#define BASE_FILE_DESCRIPTOR_SHUFFLE_H_
// This code exists to perform the shuffling of file descriptors which is
// commonly needed when forking subprocesses. The naive approve is very simple,
// just call dup2 to setup the desired descriptors, but wrong. It's tough to
// handle the edge cases (like mapping 0 -> 1, 1 -> 0) correctly.
//
// In order to unittest this code, it's broken into the abstract action (an
// injective multimap) and the concrete code for dealing with file descriptors.
// Users should use the code like this:
// base::InjectiveMultimap file_descriptor_map;
// file_descriptor_map.push_back(base::InjectionArc(devnull, 0, true));
// file_descriptor_map.push_back(base::InjectionArc(devnull, 2, true));
// file_descriptor_map.push_back(base::InjectionArc(pipe[1], 1, true));
// base::ShuffleFileDescriptors(file_descriptor_map);
//
// and trust the the Right Thing will get done.
#include <vector>
namespace base {
// A Delegate which performs the actions required to perform an injective
// multimapping in place.
class InjectionDelegate {
public:
// Duplicate |fd|, an element of the domain, and write a fresh element of the
// domain into |result|. Returns true iff successful.
virtual bool Duplicate(int* result, int fd) = 0;
// Destructively move |src| to |dest|, overwriting |dest|. Returns true iff
// successful.
virtual bool Move(int src, int dest) = 0;
// Delete an element of the domain.
virtual void Close(int fd) = 0;
};
// An implementation of the InjectionDelegate interface using the file
// descriptor table of the current process as the domain.
class FileDescriptorTableInjection : public InjectionDelegate {
bool Duplicate(int* result, int fd);
bool Move(int src, int dest);
void Close(int fd);
};
// A single arc of the directed graph which describes an injective multimapping.
struct InjectionArc {
InjectionArc(int in_source, int in_dest, bool in_close)
: source(in_source),
dest(in_dest),
close(in_close) {
}
int source;
int dest;
bool close; // if true, delete the source element after performing the
// mapping.
};
typedef std::vector<InjectionArc> InjectiveMultimap;
bool PerformInjectiveMultimap(const InjectiveMultimap& map,
InjectionDelegate* delegate);
static inline bool ShuffleFileDescriptors(const InjectiveMultimap& map) {
FileDescriptorTableInjection delegate;
return PerformInjectiveMultimap(map, &delegate);
}
} // namespace base
#endif // !BASE_FILE_DESCRIPTOR_SHUFFLE_H_