Mirror of :pserver:cvs@cvs.fefe.de:/cvs libowfat https://www.fefe.de/libowfat/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

125 lines
3.3 KiB

  1. #include "io_internal.h"
  2. #ifdef HAVE_EPOLL
  3. #include <sys/epoll.h>
  4. #endif
  5. #ifdef HAVE_KQUEUE
  6. #include <sys/types.h>
  7. #include <sys/event.h>
  8. #include <sys/time.h>
  9. #endif
  10. #include <errno.h>
  11. int iom_wait(iomux_t* c,int64* s,unsigned int* revents,unsigned long timeout) {
  12. for (;;) {
  13. /* If we have an event in the queue, use that one */
  14. int r;
  15. if (c->working==-2) return -2; /* iomux was aborted */
  16. for (;;) {
  17. unsigned int f=c->l;
  18. if (f == c->h)
  19. break; /* no elements in queue */
  20. int n=(f+1)%SLOTS;
  21. if (__sync_bool_compare_and_swap(&c->l,f,n)) {
  22. /* we got one, and its index is in f */
  23. *s=c->q[f].fd;
  24. *revents=c->q[f].events;
  25. }
  26. /* collided with another thread, try again */
  27. }
  28. /* The queue was empty. If someone else is already calling
  29. * epoll_wait/kevent, then use the semaphore */
  30. if (__sync_bool_compare_and_swap(&c->working,0,1)) {
  31. /* we have the job to fill the struct. */
  32. int freeslots = (c->h - c->l);
  33. if (!freeslots) freeslots=SLOTS;
  34. #ifdef HAVE_EPOLL
  35. struct epoll_event ee[SLOTS];
  36. int i;
  37. r=epoll_wait(c->ctx, ee, freeslots, timeout);
  38. if (r<=0) {
  39. /* we ran into a timeout, so let someone else take over */
  40. c->working=0;
  41. #ifdef __dietlibc__
  42. cnd_broadcast(&c->sem);
  43. #else
  44. sem_post(&c->sem);
  45. #endif
  46. return r;
  47. }
  48. for (i=0; i<r; ++i) {
  49. /* convert events */
  50. int e = ((ee[i].events & (EPOLLIN|EPOLLHUP|EPOLLERR)) ? IOM_READ : 0) |
  51. ((ee[i].events & (EPOLLOUT|EPOLLHUP|EPOLLERR)) ? IOM_WRITE : 0) |
  52. ((ee[i].events & EPOLLERR) ? IOM_ERROR : 0);
  53. if (i+1==r) {
  54. /* return last event instead of enqueueing it */
  55. *s=ee[i].data.fd;
  56. *revents=e;
  57. } else {
  58. c->q[c->h].fd=ee[i].data.fd;
  59. c->q[c->h].events=e;
  60. c->h = (c->h + 1) % SLOTS;
  61. }
  62. }
  63. #elif defined(HAVE_KQUEUE)
  64. struct kevent kev[SLOTS];
  65. struct timespec ts = { .tv_sec=timeout/1000, .tv_nsec=(timeout%1000)*1000000 };
  66. int r=kevent(c->ctx, 0, 0, &kev, freeslots, &ts);
  67. if (r<=0) {
  68. /* we ran into a timeout, so let someone else take over */
  69. c->working=0;
  70. #ifdef __dietlibc__
  71. cnd_broadcast(&c->sem);
  72. #else
  73. sem_post(&c->sem);
  74. #endif
  75. return r;
  76. }
  77. for (i=0; i<r; ++i) {
  78. /* convert events */
  79. int e = (kev[i].filter == EVFILT_READ ? IOM_READ : 0) |
  80. (kev[i].filter == EVFILT_WRITE ? IOM_WRITE : 0);
  81. if (i+1==r) {
  82. /* return last event instead of enqueueing it */
  83. *s=kev.ident;
  84. *revents=e;
  85. } else {
  86. c->q[c->h].fd=kev[i].ident;
  87. c->q[c->h].events=e;
  88. c->h = (c->h + 1) % SLOTS;
  89. }
  90. }
  91. #else
  92. #warning "only epoll and kqueue supported for now"
  93. #endif
  94. /* We need to signal the other threads.
  95. Either there are other events left, or we need one of them to
  96. wake up and call epoll_wait/kevent next, because we aren't
  97. doing it anymore */
  98. c->working=0;
  99. #ifdef __dietlibc__
  100. cnd_signal(&c->sem);
  101. #else
  102. sem_post(&c->sem);
  103. #endif
  104. return 1;
  105. } else {
  106. /* somebody else has the job to fill the queue */
  107. struct timespec ts;
  108. ts.tv_sec = timeout / 1000;
  109. ts.tv_nsec = (timeout % 1000) * 1000000;
  110. #ifdef __dietlibc__
  111. r=cnd_timedwait(&c->sem,&c->mtx,&ts);
  112. #else
  113. r=sem_timedwait(&c->sem,&ts);
  114. #endif
  115. if (r==-1) {
  116. if (errno==ETIMEDOUT) return 0;
  117. return -1;
  118. }
  119. /* fall through into next loop iteration */
  120. }
  121. }
  122. }