Skip to content

Commit

Permalink
Catch attempts to fork from a multithreaded bazel launcher process.
Browse files Browse the repository at this point in the history
This is prone to deadlock.

--
PiperOrigin-RevId: 150263255
MOS_MIGRATED_REVID=150263255
  • Loading branch information
Googler authored and meteorcloudy committed Mar 16, 2017
1 parent d43d7cd commit 0302155
Showing 1 changed file with 34 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/main/cpp/blaze_util_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h> // PATH_MAX
Expand Down Expand Up @@ -39,6 +40,7 @@ namespace blaze {

using blaze_util::die;
using blaze_util::pdie;
using blaze_exit_code::INTERNAL_ERROR;

using std::string;
using std::vector;
Expand Down Expand Up @@ -170,6 +172,35 @@ bool SymlinkDirectories(const string &target, const string &link) {
return symlink(target.c_str(), link.c_str()) == 0;
}

static void CheckSingleThreaded() {
#ifdef __linux__
DIR *dir = opendir("/proc/self/task");
if (!dir) pdie(INTERNAL_ERROR, "can't list /proc/self/task");
vector<string> tids;
while (dirent *dent = readdir(dir)) {
if (dent->d_name[0] != '.') tids.push_back(dent->d_name);
}
closedir(dir);
if (tids.size() == 1) return;

// If there are multiple threads, show their names as a debugging aid.
fprintf(stderr, "Trying to fork, but found %zu threads:\n", tids.size());
for (const string &t : tids) {
string path = string("/proc/self/task/") + t + "/comm";
if (FILE *f = fopen(path.c_str(), "r")) {
char comm[4096];
int len = fread(comm, 1, sizeof comm, f);
fprintf(stderr, " Thread %s: %.*s", t.c_str(), len, comm);
fclose(f);
} else {
fprintf(stderr, "can't open %s", path.c_str());
}
}
die(INTERNAL_ERROR, "can't fork() after creating threads");
#endif
// This can probably be checked on darwin via <sys/proc_info.h>.
}

// Causes the current process to become a daemon (i.e. a child of
// init, detached from the terminal, in its own session.) We don't
// change cwd, though.
Expand All @@ -179,6 +210,7 @@ static void Daemonize(const string& daemon_output) {
// anything that can possibly fail. :)

signal(SIGHUP, SIG_IGN);
CheckSingleThreaded();
if (fork() > 0) {
// This second fork is required iff there's any chance cmd will
// open an specific tty explicitly, e.g., open("/dev/tty23"). If
Expand Down Expand Up @@ -238,6 +270,7 @@ void ExecuteDaemon(const string& exe,
if (pipe(fds)) {
pdie(blaze_exit_code::INTERNAL_ERROR, "pipe creation failed");
}
CheckSingleThreaded();
int child = fork();
if (child == -1) {
pdie(blaze_exit_code::INTERNAL_ERROR, "fork() failed");
Expand Down Expand Up @@ -276,6 +309,7 @@ static string RunProgram(const string& exe,
int recv_socket = fds[0];
int send_socket = fds[1];

CheckSingleThreaded();
int child = fork();
if (child == -1) {
pdie(blaze_exit_code::INTERNAL_ERROR, "fork() failed");
Expand Down

0 comments on commit 0302155

Please sign in to comment.