mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 11:26:16 +01:00
Merge branch '1014-gspawn-linux-threadsafety' into 'master'
gspawn: Fix g_spawn deadlock in a multi-threaded program on Linux Closes #1014 and #945 See merge request GNOME/glib!490
This commit is contained in:
commit
8c9c9d92cc
@ -47,6 +47,10 @@
|
||||
#include <sys/resource.h>
|
||||
#endif /* HAVE_SYS_RESOURCE_H */
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/syscall.h> /* for syscall and SYS_getdents64 */
|
||||
#endif
|
||||
|
||||
#include "gspawn.h"
|
||||
#include "gspawn-private.h"
|
||||
#include "gthread.h"
|
||||
@ -1125,6 +1129,44 @@ set_cloexec (void *data, gint fd)
|
||||
}
|
||||
|
||||
#ifndef HAVE_FDWALK
|
||||
#ifdef __linux__
|
||||
struct linux_dirent64
|
||||
{
|
||||
guint64 d_ino; /* 64-bit inode number */
|
||||
guint64 d_off; /* 64-bit offset to next structure */
|
||||
unsigned short d_reclen; /* Size of this dirent */
|
||||
unsigned char d_type; /* File type */
|
||||
char d_name[]; /* Filename (null-terminated) */
|
||||
};
|
||||
|
||||
static gint
|
||||
filename_to_fd (const char *p)
|
||||
{
|
||||
char c;
|
||||
int fd = 0;
|
||||
const int cutoff = G_MAXINT / 10;
|
||||
const int cutlim = G_MAXINT % 10;
|
||||
|
||||
if (*p == '\0')
|
||||
return -1;
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
{
|
||||
if (!g_ascii_isdigit (c))
|
||||
return -1;
|
||||
c -= '0';
|
||||
|
||||
/* Check for overflow. */
|
||||
if (fd > cutoff || (fd == cutoff && c > cutlim))
|
||||
return -1;
|
||||
|
||||
fd = fd * 10 + c;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
fdwalk (int (*cb)(void *data, int fd), void *data)
|
||||
{
|
||||
@ -1136,45 +1178,39 @@ fdwalk (int (*cb)(void *data, int fd), void *data)
|
||||
struct rlimit rl;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
DIR *d;
|
||||
#ifdef __linux__
|
||||
/* Avoid use of opendir/closedir since these are not async-signal-safe. */
|
||||
int dir_fd = open ("/proc/self/fd", O_RDONLY | O_DIRECTORY);
|
||||
if (dir_fd >= 0)
|
||||
{
|
||||
char buf[4096];
|
||||
int pos, nread;
|
||||
struct linux_dirent64 *de;
|
||||
|
||||
if ((d = opendir("/proc/self/fd"))) {
|
||||
struct dirent *de;
|
||||
while ((nread = syscall (SYS_getdents64, dir_fd, buf, sizeof(buf))) > 0)
|
||||
{
|
||||
for (pos = 0; pos < nread; pos += de->d_reclen)
|
||||
{
|
||||
de = (struct linux_dirent64 *)(buf + pos);
|
||||
|
||||
while ((de = readdir(d))) {
|
||||
glong l;
|
||||
gchar *e = NULL;
|
||||
fd = filename_to_fd (de->d_name);
|
||||
if (fd < 0 || fd == dir_fd)
|
||||
continue;
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(de->d_name, &e, 10);
|
||||
if (errno != 0 || !e || *e)
|
||||
continue;
|
||||
|
||||
fd = (gint) l;
|
||||
|
||||
if ((glong) fd != l)
|
||||
continue;
|
||||
|
||||
if (fd == dirfd(d))
|
||||
continue;
|
||||
|
||||
if ((res = cb (data, fd)) != 0)
|
||||
break;
|
||||
if ((res = cb (data, fd)) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
close (dir_fd);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* If /proc is not mounted or not accessible we fall back to the old
|
||||
* rlimit trick */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
|
||||
|
Loading…
Reference in New Issue
Block a user