Commit 7ba267ce by Serge Hallyn Committed by Stéphane Graber

use poll instead of select

Particularly when using the go-lxc api with lots of threads, it happens that if the open files limit is > 1024, we will try to select on fd > 1024 which breaks on glibc. So use poll instead of select. Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent d1679d60
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <sys/mount.h> #include <sys/mount.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <net/if.h> #include <net/if.h>
#include <poll.h>
#include "error.h" #include "error.h"
#include "commands.h" #include "commands.h"
...@@ -347,6 +348,7 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path, ...@@ -347,6 +348,7 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path,
{ {
int sv[2] = {-1, -1}, optval = 1, ret = -1; int sv[2] = {-1, -1}, optval = 1, ret = -1;
char buf[1]; char buf[1];
struct pollfd fds;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) { if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
SYSERROR("Error creating socketpair"); SYSERROR("Error creating socketpair");
...@@ -370,10 +372,10 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path, ...@@ -370,10 +372,10 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path,
} }
/* now send credentials */ /* now send credentials */
fd_set rfds; fds.fd = sv[0];
FD_ZERO(&rfds); fds.events = POLLIN;
FD_SET(sv[0], &rfds); fds.revents = 0;
if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) { if (poll(&fds, 1, -1) <= 0) {
ERROR("Error getting go-ahead from server: %s", strerror(errno)); ERROR("Error getting go-ahead from server: %s", strerror(errno));
goto out; goto out;
} }
...@@ -385,9 +387,10 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path, ...@@ -385,9 +387,10 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path,
SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__); SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
goto out; goto out;
} }
FD_ZERO(&rfds); fds.fd = sv[0];
FD_SET(sv[0], &rfds); fds.events = POLLIN;
if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) { fds.revents = 0;
if (poll(&fds, 1, -1) <= 0) {
ERROR("Error getting go-ahead from server: %s", strerror(errno)); ERROR("Error getting go-ahead from server: %s", strerror(errno));
goto out; goto out;
} }
...@@ -399,9 +402,10 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path, ...@@ -399,9 +402,10 @@ static int do_chown_cgroup(const char *controller, const char *cgroup_path,
SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__); SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
goto out; goto out;
} }
FD_ZERO(&rfds); fds.fd = sv[0];
FD_SET(sv[0], &rfds); fds.events = POLLIN;
if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) { fds.revents = 0;
if (poll(&fds, 1, -1) <= 0) {
ERROR("Error getting go-ahead from server: %s", strerror(errno)); ERROR("Error getting go-ahead from server: %s", strerror(errno));
goto out; goto out;
} }
......
...@@ -64,44 +64,6 @@ extern int lxc_execute(const char *name, char *const argv[], int quiet, ...@@ -64,44 +64,6 @@ extern int lxc_execute(const char *name, char *const argv[], int quiet,
struct lxc_conf *conf, const char *lxcpath); struct lxc_conf *conf, const char *lxcpath);
/* /*
* Open the monitoring mechanism for a specific container
* The function will return an fd corresponding to the events
* Returns a file descriptor on success, < 0 otherwise
*/
extern int lxc_monitor_open(const char *lxcpath);
/*
* Blocking read for the next container state change
* @fd : the file descriptor provided by lxc_monitor_open
* @msg : the variable which will be filled with the state
* Returns 0 if the monitored container has exited, > 0 if
* data was read, < 0 otherwise
*/
extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
/*
* Blocking read for the next container state change with timeout
* @fd : the file descriptor provided by lxc_monitor_open
* @msg : the variable which will be filled with the state
* @timeout : the timeout in seconds to wait for a state change
* Returns 0 if the monitored container has exited, > 0 if
* data was read, < 0 otherwise
*/
extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
/*
* Blocking read from multiple monitors for the next container state
* change with timeout
* @rfds : an fd_set of file descriptors provided by lxc_monitor_open
* @nfds : the maximum fd number in rfds + 1
* @msg : the variable which will be filled with the state
* @timeout : the timeout in seconds to wait for a state change
* Returns 0 if the monitored container has exited, > 0 if
* data was read, < 0 otherwise
*/
extern int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, int timeout);
/*
* Close the fd associated with the monitoring * Close the fd associated with the monitoring
* @fd : the file descriptor provided by lxc_monitor_open * @fd : the file descriptor provided by lxc_monitor_open
* Returns 0 on success, < 0 otherwise * Returns 0 on success, < 0 otherwise
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <errno.h> #include <errno.h>
#include <poll.h>
#include "lxc.h" #include "lxc.h"
#include "log.h" #include "log.h"
...@@ -75,8 +76,9 @@ int main(int argc, char *argv[]) ...@@ -75,8 +76,9 @@ int main(int argc, char *argv[])
char *regexp; char *regexp;
struct lxc_msg msg; struct lxc_msg msg;
regex_t preg; regex_t preg;
fd_set rfds, rfds_save; struct pollfd *fds;
int len, rc, i, nfds = -1; nfds_t nfds;
int len, rc, i;
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
return 1; return 1;
...@@ -131,13 +133,14 @@ int main(int argc, char *argv[]) ...@@ -131,13 +133,14 @@ int main(int argc, char *argv[])
} }
free(regexp); free(regexp);
if (my_args.lxcpath_cnt > FD_SETSIZE) { fds = malloc(my_args.lxcpath_cnt * sizeof(struct pollfd));
ERROR("too many paths requested, only the first %d will be monitored", FD_SETSIZE); if (!fds) {
my_args.lxcpath_cnt = FD_SETSIZE; SYSERROR("out of memory");
return -1;
} }
FD_ZERO(&rfds); nfds = my_args.lxcpath_cnt;
for (i = 0; i < my_args.lxcpath_cnt; i++) { for (i = 0; i < nfds; i++) {
int fd; int fd;
lxc_monitord_spawn(my_args.lxcpath[i]); lxc_monitord_spawn(my_args.lxcpath[i]);
...@@ -147,19 +150,15 @@ int main(int argc, char *argv[]) ...@@ -147,19 +150,15 @@ int main(int argc, char *argv[])
regfree(&preg); regfree(&preg);
return 1; return 1;
} }
FD_SET(fd, &rfds); fds[i].fd = fd;
if (fd > nfds) fds[i].events = POLLIN;
nfds = fd; fds[i].revents = 0;
} }
memcpy(&rfds_save, &rfds, sizeof(rfds_save));
nfds++;
setlinebuf(stdout); setlinebuf(stdout);
for (;;) { for (;;) {
memcpy(&rfds, &rfds_save, sizeof(rfds)); if (lxc_monitor_read_fdset(fds, nfds, &msg, -1) < 0) {
if (lxc_monitor_read_fdset(&rfds, nfds, &msg, -1) < 0) {
regfree(&preg); regfree(&preg);
return 1; return 1;
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <net/if.h> #include <net/if.h>
#include <poll.h>
#include "error.h" #include "error.h"
#include "af_unix.h" #include "af_unix.h"
...@@ -219,19 +220,13 @@ err1: ...@@ -219,19 +220,13 @@ err1:
return ret; return ret;
} }
int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg,
int timeout) int timeout)
{ {
struct timeval tval,*tv = NULL; long i;
int ret,i; int ret;
if (timeout != -1) {
tv = &tval;
tv->tv_sec = timeout;
tv->tv_usec = 0;
}
ret = select(nfds, rfds, NULL, NULL, tv); ret = poll(fds, nfds, timeout * 1000);
if (ret == -1) if (ret == -1)
return -1; return -1;
else if (ret == 0) else if (ret == 0)
...@@ -241,8 +236,9 @@ int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, ...@@ -241,8 +236,9 @@ int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg,
* for when this routine is called again * for when this routine is called again
*/ */
for (i = 0; i < nfds; i++) { for (i = 0; i < nfds; i++) {
if (FD_ISSET(i, rfds)) { if (fds[i].revents != 0) {
ret = recv(i, msg, sizeof(*msg), 0); fds[i].revents = 0;
ret = recv(fds[i].fd, msg, sizeof(*msg), 0);
if (ret <= 0) { if (ret <= 0) {
SYSERROR("client failed to recv (monitord died?) %s", SYSERROR("client failed to recv (monitord died?) %s",
strerror(errno)); strerror(errno));
...@@ -257,12 +253,13 @@ int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, ...@@ -257,12 +253,13 @@ int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg,
int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout) int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
{ {
fd_set rfds; struct pollfd fds;
FD_ZERO(&rfds); fds.fd = fd;
FD_SET(fd, &rfds); fds.events = POLLIN | POLLPRI;
fds.revents = 0;
return lxc_monitor_read_fdset(&rfds, fd+1, msg, timeout); return lxc_monitor_read_fdset(&fds, 1, msg, timeout);
} }
int lxc_monitor_read(int fd, struct lxc_msg *msg) int lxc_monitor_read(int fd, struct lxc_msg *msg)
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <limits.h> #include <limits.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/un.h> #include <sys/un.h>
#include <poll.h>
#include "conf.h" #include "conf.h"
...@@ -41,7 +42,6 @@ struct lxc_msg { ...@@ -41,7 +42,6 @@ struct lxc_msg {
int value; int value;
}; };
extern int lxc_monitor_open(const char *lxcpath);
extern int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr); extern int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr);
extern int lxc_monitor_fifo_name(const char *lxcpath, char *fifo_path, extern int lxc_monitor_fifo_name(const char *lxcpath, char *fifo_path,
size_t fifo_path_sz, int do_mkdirp); size_t fifo_path_sz, int do_mkdirp);
...@@ -51,4 +51,44 @@ extern void lxc_monitor_send_exit_code(const char *name, int exit_code, ...@@ -51,4 +51,44 @@ extern void lxc_monitor_send_exit_code(const char *name, int exit_code,
const char *lxcpath); const char *lxcpath);
extern int lxc_monitord_spawn(const char *lxcpath); extern int lxc_monitord_spawn(const char *lxcpath);
/*
* Open the monitoring mechanism for a specific container
* The function will return an fd corresponding to the events
* Returns a file descriptor on success, < 0 otherwise
*/
extern int lxc_monitor_open(const char *lxcpath);
/*
* Blocking read for the next container state change
* @fd : the file descriptor provided by lxc_monitor_open
* @msg : the variable which will be filled with the state
* Returns 0 if the monitored container has exited, > 0 if
* data was read, < 0 otherwise
*/
extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
/*
* Blocking read for the next container state change with timeout
* @fd : the file descriptor provided by lxc_monitor_open
* @msg : the variable which will be filled with the state
* @timeout : the timeout in seconds to wait for a state change
* Returns 0 if the monitored container has exited, > 0 if
* data was read, < 0 otherwise
*/
extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
/*
* Blocking read from multiple monitors for the next container state
* change with timeout
* @fds : struct pollfd descripting the fds to use
* @nfds : the number of entries in fds
* @msg : the variable which will be filled with the state
* @timeout : the timeout in seconds to wait for a state change
* Returns 0 if the monitored container has exited, > 0 if
* data was read, < 0 otherwise
*/
extern int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg,
int timeout);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment