threadpool-ms-io-poll.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include "il2cpp-config.h"
  2. #include "gc/GarbageCollector.h"
  3. #include "mono/ThreadPool/threadpool-ms-io-poll.h"
  4. #include "os/Socket.h"
  5. #include "utils/Memory.h"
  6. #include "vm/Thread.h"
  7. #include <vector>
  8. static std::vector<il2cpp::os::PollRequest> *poll_fds;
  9. static unsigned int poll_fds_capacity;
  10. static unsigned int poll_fds_size;
  11. static inline void
  12. POLL_INIT_FD(il2cpp::os::PollRequest *poll_fd, int fd, il2cpp::os::PollFlags events)
  13. {
  14. poll_fd->fd = fd;
  15. poll_fd->events = events;
  16. poll_fd->revents = il2cpp::os::kPollFlagsNone;
  17. }
  18. bool poll_init(int wakeup_pipe_fd)
  19. {
  20. IL2CPP_ASSERT(wakeup_pipe_fd >= 0);
  21. poll_fds_size = 1;
  22. poll_fds_capacity = 64;
  23. poll_fds = new std::vector<il2cpp::os::PollRequest>(poll_fds_capacity);
  24. POLL_INIT_FD(&(*poll_fds)[0], wakeup_pipe_fd, il2cpp::os::kPollFlagsIn);
  25. return true;
  26. }
  27. void poll_register_fd(int fd, int events, bool is_new)
  28. {
  29. unsigned int i;
  30. il2cpp::os::PollFlags poll_event;
  31. IL2CPP_ASSERT(fd >= 0);
  32. IL2CPP_ASSERT(poll_fds_size <= poll_fds_capacity);
  33. IL2CPP_ASSERT((events & ~(EVENT_IN | EVENT_OUT)) == 0);
  34. poll_event = il2cpp::os::kPollFlagsNone;
  35. if (events & EVENT_IN)
  36. poll_event |= il2cpp::os::kPollFlagsIn;
  37. if (events & EVENT_OUT)
  38. poll_event |= il2cpp::os::kPollFlagsOut;
  39. for (i = 0; i < poll_fds_size; ++i)
  40. {
  41. if ((*poll_fds)[i].fd == fd)
  42. {
  43. IL2CPP_ASSERT(!is_new);
  44. POLL_INIT_FD(&(*poll_fds)[i], fd, poll_event);
  45. return;
  46. }
  47. }
  48. IL2CPP_ASSERT(is_new);
  49. for (i = 0; i < poll_fds_size; ++i)
  50. {
  51. if ((*poll_fds)[i].fd == -1)
  52. {
  53. POLL_INIT_FD(&(*poll_fds)[i], fd, poll_event);
  54. return;
  55. }
  56. }
  57. poll_fds_size += 1;
  58. if (poll_fds_size > poll_fds_capacity)
  59. {
  60. poll_fds_capacity *= 2;
  61. IL2CPP_ASSERT(poll_fds_size <= poll_fds_capacity);
  62. poll_fds->resize(poll_fds_capacity, il2cpp::os::PollRequest(-1));
  63. }
  64. POLL_INIT_FD(&(*poll_fds)[poll_fds_size - 1], fd, poll_event);
  65. }
  66. void poll_remove_fd(int fd)
  67. {
  68. unsigned int i;
  69. IL2CPP_ASSERT(fd >= 0);
  70. for (i = 0; i < poll_fds_size; ++i)
  71. {
  72. if ((*poll_fds)[i].fd == fd)
  73. {
  74. POLL_INIT_FD(&(*poll_fds)[i], -1, il2cpp::os::kPollFlagsNone);
  75. break;
  76. }
  77. }
  78. /* if we don't find the fd in poll_fds,
  79. * it means we try to delete it twice */
  80. IL2CPP_ASSERT(i < poll_fds_size);
  81. /* if we find it again, it means we added
  82. * it twice */
  83. for (; i < poll_fds_size; ++i)
  84. IL2CPP_ASSERT((*poll_fds)[i].fd != fd);
  85. /* reduce the value of poll_fds_size so we
  86. * do not keep it too big */
  87. while (poll_fds_size > 1 && (*poll_fds)[poll_fds_size - 1].fd == -1)
  88. poll_fds_size -= 1;
  89. }
  90. static inline int
  91. poll_mark_bad_fds(std::vector<il2cpp::os::PollRequest> *poll_fds, int poll_fds_size)
  92. {
  93. int i, ready = 0;
  94. int32_t result, error = 0;
  95. for (i = 0; i < poll_fds_size; i++)
  96. {
  97. if ((*poll_fds)[i].fd == -1)
  98. continue;
  99. il2cpp::os::WaitStatus status = il2cpp::os::Socket::Poll((*poll_fds)[i], 0, &result, &error);
  100. if (status == kWaitStatusFailure)
  101. {
  102. if ((il2cpp::os::SocketError)error == il2cpp::os::kInvalidHandle)
  103. {
  104. (*poll_fds)[i].revents |= il2cpp::os::kPollFlagsNVal;
  105. ready++;
  106. }
  107. }
  108. else if (result > 0)
  109. ready++;
  110. }
  111. return ready;
  112. }
  113. int poll_event_wait(void (*callback)(int fd, int events, void* user_data), void* user_data)
  114. {
  115. unsigned int i;
  116. for (i = 0; i < poll_fds_size; ++i)
  117. (*poll_fds)[i].revents = il2cpp::os::kPollFlagsNone;
  118. il2cpp::gc::GarbageCollector::SetSkipThread(true);
  119. int32_t ready;
  120. int32_t error;
  121. il2cpp::os::WaitStatus status = il2cpp::os::Socket::Poll((*poll_fds), poll_fds_size , -1, &ready, &error);
  122. il2cpp::gc::GarbageCollector::SetSkipThread(false);
  123. if (ready == -1 || status == kWaitStatusFailure)
  124. {
  125. /*
  126. * Apart from EINTR, we only check EBADF, for the rest:
  127. * EINVAL: mono_poll() 'protects' us from descriptor
  128. * numbers above the limit if using select() by marking
  129. * then as POLLERR. If a system poll() is being
  130. * used, the number of descriptor we're passing will not
  131. * be over sysconf(_SC_OPEN_MAX), as the error would have
  132. * happened when opening.
  133. *
  134. * EFAULT: we own the memory pointed by pfds.
  135. * ENOMEM: we're doomed anyway
  136. *
  137. */
  138. if ((il2cpp::os::SocketError)error == il2cpp::os::kInterrupted)
  139. {
  140. il2cpp::vm::Thread::CheckCurrentThreadForInterruptAndThrowIfNecessary();
  141. ready = 0;
  142. }
  143. else if ((il2cpp::os::SocketError)error == il2cpp::os::kInvalidHandle)
  144. {
  145. ready = poll_mark_bad_fds(poll_fds, poll_fds_size);
  146. }
  147. }
  148. if (ready == -1)
  149. return -1;
  150. if (ready == 0)
  151. return 0;
  152. IL2CPP_ASSERT(ready > 0);
  153. for (i = 0; i < poll_fds_size; ++i)
  154. {
  155. int fd, events = 0;
  156. if ((*poll_fds)[i].fd == -1)
  157. continue;
  158. if ((*poll_fds)[i].revents == 0)
  159. continue;
  160. fd = (int)(*poll_fds)[i].fd;
  161. if ((*poll_fds)[i].revents & (il2cpp::os::kPollFlagsIn | il2cpp::os::kPollFlagsErr | il2cpp::os::kPollFlagsHup | il2cpp::os::kPollFlagsNVal))
  162. events |= EVENT_IN;
  163. if ((*poll_fds)[i].revents & (il2cpp::os::kPollFlagsOut | il2cpp::os::kPollFlagsErr | il2cpp::os::kPollFlagsHup | il2cpp::os::kPollFlagsNVal))
  164. events |= EVENT_OUT;
  165. if ((*poll_fds)[i].revents & (il2cpp::os::kPollFlagsErr | il2cpp::os::kPollFlagsHup | il2cpp::os::kPollFlagsNVal))
  166. events |= EVENT_ERR;
  167. callback(fd, events, user_data);
  168. if (--ready == 0)
  169. break;
  170. }
  171. return 0;
  172. }