123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- #include "il2cpp-config.h"
- #include "gc/GarbageCollector.h"
- #include "mono/ThreadPool/threadpool-ms-io-poll.h"
- #include "os/Socket.h"
- #include "utils/Memory.h"
- #include "vm/Thread.h"
- #include <vector>
- static std::vector<il2cpp::os::PollRequest> *poll_fds;
- static unsigned int poll_fds_capacity;
- static unsigned int poll_fds_size;
- static inline void
- POLL_INIT_FD(il2cpp::os::PollRequest *poll_fd, int fd, il2cpp::os::PollFlags events)
- {
- poll_fd->fd = fd;
- poll_fd->events = events;
- poll_fd->revents = il2cpp::os::kPollFlagsNone;
- }
- bool poll_init(int wakeup_pipe_fd)
- {
- IL2CPP_ASSERT(wakeup_pipe_fd >= 0);
- poll_fds_size = 1;
- poll_fds_capacity = 64;
- poll_fds = new std::vector<il2cpp::os::PollRequest>(poll_fds_capacity);
- POLL_INIT_FD(&(*poll_fds)[0], wakeup_pipe_fd, il2cpp::os::kPollFlagsIn);
- return true;
- }
- void poll_register_fd(int fd, int events, bool is_new)
- {
- unsigned int i;
- il2cpp::os::PollFlags poll_event;
- IL2CPP_ASSERT(fd >= 0);
- IL2CPP_ASSERT(poll_fds_size <= poll_fds_capacity);
- IL2CPP_ASSERT((events & ~(EVENT_IN | EVENT_OUT)) == 0);
- poll_event = il2cpp::os::kPollFlagsNone;
- if (events & EVENT_IN)
- poll_event |= il2cpp::os::kPollFlagsIn;
- if (events & EVENT_OUT)
- poll_event |= il2cpp::os::kPollFlagsOut;
- for (i = 0; i < poll_fds_size; ++i)
- {
- if ((*poll_fds)[i].fd == fd)
- {
- IL2CPP_ASSERT(!is_new);
- POLL_INIT_FD(&(*poll_fds)[i], fd, poll_event);
- return;
- }
- }
- IL2CPP_ASSERT(is_new);
- for (i = 0; i < poll_fds_size; ++i)
- {
- if ((*poll_fds)[i].fd == -1)
- {
- POLL_INIT_FD(&(*poll_fds)[i], fd, poll_event);
- return;
- }
- }
- poll_fds_size += 1;
- if (poll_fds_size > poll_fds_capacity)
- {
- poll_fds_capacity *= 2;
- IL2CPP_ASSERT(poll_fds_size <= poll_fds_capacity);
- poll_fds->resize(poll_fds_capacity, il2cpp::os::PollRequest(-1));
- }
- POLL_INIT_FD(&(*poll_fds)[poll_fds_size - 1], fd, poll_event);
- }
- void poll_remove_fd(int fd)
- {
- unsigned int i;
- IL2CPP_ASSERT(fd >= 0);
- for (i = 0; i < poll_fds_size; ++i)
- {
- if ((*poll_fds)[i].fd == fd)
- {
- POLL_INIT_FD(&(*poll_fds)[i], -1, il2cpp::os::kPollFlagsNone);
- break;
- }
- }
- /* if we don't find the fd in poll_fds,
- * it means we try to delete it twice */
- IL2CPP_ASSERT(i < poll_fds_size);
- /* if we find it again, it means we added
- * it twice */
- for (; i < poll_fds_size; ++i)
- IL2CPP_ASSERT((*poll_fds)[i].fd != fd);
- /* reduce the value of poll_fds_size so we
- * do not keep it too big */
- while (poll_fds_size > 1 && (*poll_fds)[poll_fds_size - 1].fd == -1)
- poll_fds_size -= 1;
- }
- static inline int
- poll_mark_bad_fds(std::vector<il2cpp::os::PollRequest> *poll_fds, int poll_fds_size)
- {
- int i, ready = 0;
- int32_t result, error = 0;
- for (i = 0; i < poll_fds_size; i++)
- {
- if ((*poll_fds)[i].fd == -1)
- continue;
- il2cpp::os::WaitStatus status = il2cpp::os::Socket::Poll((*poll_fds)[i], 0, &result, &error);
- if (status == kWaitStatusFailure)
- {
- if ((il2cpp::os::SocketError)error == il2cpp::os::kInvalidHandle)
- {
- (*poll_fds)[i].revents |= il2cpp::os::kPollFlagsNVal;
- ready++;
- }
- }
- else if (result > 0)
- ready++;
- }
- return ready;
- }
- int poll_event_wait(void (*callback)(int fd, int events, void* user_data), void* user_data)
- {
- unsigned int i;
- for (i = 0; i < poll_fds_size; ++i)
- (*poll_fds)[i].revents = il2cpp::os::kPollFlagsNone;
- il2cpp::gc::GarbageCollector::SetSkipThread(true);
- int32_t ready;
- int32_t error;
- il2cpp::os::WaitStatus status = il2cpp::os::Socket::Poll((*poll_fds), poll_fds_size , -1, &ready, &error);
- il2cpp::gc::GarbageCollector::SetSkipThread(false);
- if (ready == -1 || status == kWaitStatusFailure)
- {
- /*
- * Apart from EINTR, we only check EBADF, for the rest:
- * EINVAL: mono_poll() 'protects' us from descriptor
- * numbers above the limit if using select() by marking
- * then as POLLERR. If a system poll() is being
- * used, the number of descriptor we're passing will not
- * be over sysconf(_SC_OPEN_MAX), as the error would have
- * happened when opening.
- *
- * EFAULT: we own the memory pointed by pfds.
- * ENOMEM: we're doomed anyway
- *
- */
- if ((il2cpp::os::SocketError)error == il2cpp::os::kInterrupted)
- {
- il2cpp::vm::Thread::CheckCurrentThreadForInterruptAndThrowIfNecessary();
- ready = 0;
- }
- else if ((il2cpp::os::SocketError)error == il2cpp::os::kInvalidHandle)
- {
- ready = poll_mark_bad_fds(poll_fds, poll_fds_size);
- }
- }
- if (ready == -1)
- return -1;
- if (ready == 0)
- return 0;
- IL2CPP_ASSERT(ready > 0);
- for (i = 0; i < poll_fds_size; ++i)
- {
- int fd, events = 0;
- if ((*poll_fds)[i].fd == -1)
- continue;
- if ((*poll_fds)[i].revents == 0)
- continue;
- fd = (int)(*poll_fds)[i].fd;
- if ((*poll_fds)[i].revents & (il2cpp::os::kPollFlagsIn | il2cpp::os::kPollFlagsErr | il2cpp::os::kPollFlagsHup | il2cpp::os::kPollFlagsNVal))
- events |= EVENT_IN;
- if ((*poll_fds)[i].revents & (il2cpp::os::kPollFlagsOut | il2cpp::os::kPollFlagsErr | il2cpp::os::kPollFlagsHup | il2cpp::os::kPollFlagsNVal))
- events |= EVENT_OUT;
- if ((*poll_fds)[i].revents & (il2cpp::os::kPollFlagsErr | il2cpp::os::kPollFlagsHup | il2cpp::os::kPollFlagsNVal))
- events |= EVENT_ERR;
- callback(fd, events, user_data);
- if (--ready == 0)
- break;
- }
- return 0;
- }
|