Chromium Code Reviews| Index: native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc |
| diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc |
| index 1a0542c12d62f23628ee7add15ff3fe39c094aab..cf47d287d229caea20609a0f46d638aef2a3c4a0 100644 |
| --- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc |
| +++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc |
| @@ -14,10 +14,12 @@ |
| #include <stdio.h> |
| #include <string.h> |
| #include <sys/time.h> |
| +#include <unistd.h> |
| #include <iterator> |
| #include <string> |
| +#include "nacl_io/dbgprint.h" |
| #include "nacl_io/host_resolver.h" |
| #include "nacl_io/kernel_handle.h" |
| #include "nacl_io/kernel_wrap_real.h" |
| @@ -45,7 +47,8 @@ |
| namespace nacl_io { |
| -KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL) { |
| +KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL), |
| + sigwinch_handler_(SIG_IGN) { |
| } |
| KernelProxy::~KernelProxy() { |
| @@ -710,11 +713,78 @@ int KernelProxy::tcsetattr(int fd, int optional_actions, |
| return 0; |
| } |
| +int KernelProxy::kill(pid_t pid, int sig) { |
| + // Currently we don't even pretend that other processes exist |
| + // so we can only send a signal to outselves. For kill(2) |
| + // pid 0 means the current process group and -1 means all the |
| + // processes we have permission to send signals to. |
| + if (pid != getpid() && pid != -1 && pid != 0) { |
| + errno = ESRCH; |
| + return -1; |
| + } |
| + |
| + dbgprintf("raising event ...\n"); |
| + // Raise an event so that select/poll get interrupted. |
| + RaiseEvent(POLLERR); |
| + switch (sig) { |
| + case SIGWINCH: |
| + if (sigwinch_handler_ != SIG_IGN) |
| + sigwinch_handler_(SIGWINCH); |
| + break; |
| + |
| + case SIGUSR1: |
| + case SIGUSR2: |
| + break; |
| + |
| + default: |
| + errno = EINVAL; |
| + return -1; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +sighandler_t KernelProxy::sigset(int signum, sighandler_t handler) { |
| + switch (signum) { |
| + // Handled signals. |
| + case SIGWINCH: { |
| + sighandler_t old_value = sigwinch_handler_; |
| + if (handler == SIG_DFL) |
| + handler = SIG_IGN; |
| + sigwinch_handler_ = handler; |
| + return old_value; |
| + } |
| + |
| + // Known signals |
| + case SIGHUP: |
| + case SIGINT: |
| + case SIGKILL: |
| + case SIGPIPE: |
| + case SIGPOLL: |
| + case SIGPROF: |
| + case SIGTERM: |
| + case SIGCHLD: |
| + case SIGURG: |
| + case SIGFPE: |
| + case SIGILL: |
| + case SIGQUIT: |
| + case SIGSEGV: |
| + case SIGTRAP: |
| + if (handler == SIG_DFL) |
| + return SIG_DFL; |
| + break; |
| + } |
| + |
| + errno = EINVAL; |
| + return SIG_ERR; |
| +} |
| + |
| #ifdef PROVIDES_SOCKET_API |
| int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds, |
| fd_set* exceptfds, struct timeval* timeout) { |
| ScopedEventListener listener(new EventListener); |
| + |
| std::vector<struct pollfd> fds; |
| fd_set readout, writeout, exceptout; |
| @@ -800,9 +870,24 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds, |
| ms_timeout = static_cast<int>(ms); |
| } |
| + // Add a special node to listen for events |
| + // coming from the KernelProxy itself (kill will |
| + // generated a SIGERR event). |
| + listener->Track(-1, ScopedKernelProxy(this), POLLERR, -1); |
|
binji
2013/08/22 18:09:36
OK, I see why you want to use the kernel proxy for
Sam Clegg
2013/08/22 19:52:25
Done.
|
| + event_track += 1; |
| + |
| events.resize(event_track); |
| + |
| + bool interrupted = false; |
| listener->Wait(events.data(), event_track, ms_timeout, &ready_cnt); |
| for (fd = 0; static_cast<int>(fd) < ready_cnt; fd++) { |
| + if (events[fd].user_data == static_cast<uint64_t>(-1)) { |
| + if (events[fd].events & POLLERR) { |
| + interrupted = true; |
| + } |
| + continue; |
| + } |
| + |
| if (events[fd].events & POLLIN) { |
| FD_SET(events[fd].user_data, &readout); |
| event_cnt++; |
| @@ -818,6 +903,11 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds, |
| event_cnt++; |
| } |
| } |
| + |
| + if (0 == event_cnt && interrupted) { |
| + errno = EINTR; |
| + return -1; |
| + } |
| } |
| // Copy out the results |
| @@ -835,10 +925,11 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds, |
| int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) { |
| ScopedEventListener listener(new EventListener); |
| + listener->Track(-1, ScopedKernelProxy(this), POLLERR, 0); |
| int index; |
| size_t event_cnt = 0; |
| - size_t event_track = 0; |
| + size_t event_track = 1; |
| for (index = 0; static_cast<nfds_t>(index) < nfds; index++) { |
| ScopedKernelHandle handle; |
| struct pollfd* info = &fds[index]; |
| @@ -873,14 +964,23 @@ int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) { |
| std::vector<EventData> events; |
| int ready_cnt; |
| + bool interrupted = false; |
| events.resize(event_track); |
| listener->Wait(events.data(), event_track, timeout, &ready_cnt); |
| for (index = 0; index < ready_cnt; index++) { |
| struct pollfd* info = &fds[events[index].user_data]; |
| + if (!info) { |
| + interrupted = true; |
| + continue; |
| + } |
| info->revents = events[index].events; |
| event_cnt++; |
| } |
| + if (0 == event_cnt && interrupted) { |
| + errno = EINTR; |
| + return -1; |
| + } |
| } |
| return event_cnt; |