lio_listio.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #include <aio.h>
  2. #include <errno.h>
  3. #include "pthread_impl.h"
  4. struct lio_state {
  5. struct sigevent *sev;
  6. int cnt;
  7. struct aiocb *cbs[];
  8. };
  9. static int lio_wait(struct lio_state *st)
  10. {
  11. int i, err, got_err;
  12. int cnt = st->cnt;
  13. struct aiocb **cbs = st->cbs;
  14. for (;;) {
  15. for (i=0; i<cnt; i++) {
  16. if (!cbs[i]) continue;
  17. err = aio_error(cbs[i]);
  18. if (err==EINPROGRESS)
  19. break;
  20. if (err) got_err=1;
  21. cbs[i] = 0;
  22. }
  23. if (i==cnt) {
  24. if (got_err) {
  25. errno = EIO;
  26. return -1;
  27. }
  28. return 0;
  29. }
  30. if (aio_suspend((void *)cbs, cnt, 0))
  31. return -1;
  32. }
  33. }
  34. static void notify_signal(struct sigevent *sev)
  35. {
  36. siginfo_t si = {
  37. .si_signo = sev->sigev_signo,
  38. .si_value = sev->sigev_value,
  39. .si_code = SI_ASYNCIO,
  40. .si_pid = __pthread_self()->pid,
  41. .si_uid = getuid()
  42. };
  43. __syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si);
  44. }
  45. static void *wait_thread(void *p)
  46. {
  47. struct lio_state *st = p;
  48. struct sigevent *sev = st->sev;
  49. lio_wait(st);
  50. free(st);
  51. switch (sev->sigev_notify) {
  52. case SIGEV_SIGNAL:
  53. notify_signal(sev);
  54. break;
  55. case SIGEV_THREAD:
  56. sev->sigev_notify_function(sev->sigev_value);
  57. break;
  58. }
  59. return 0;
  60. }
  61. int lio_listio(int mode, struct aiocb *const cbs[], int cnt, struct sigevent *sev)
  62. {
  63. int i, ret;
  64. struct lio_state *st=0;
  65. if (cnt < 0) {
  66. errno = EINVAL;
  67. return -1;
  68. }
  69. if (mode == LIO_WAIT || (sev && sev->sigev_notify != SIGEV_NONE)) {
  70. if (!(st = malloc(sizeof *st + cnt*sizeof *cbs))) {
  71. errno = EAGAIN;
  72. return -1;
  73. }
  74. st->cnt = cnt;
  75. st->sev = sev;
  76. memcpy(st->cbs, cbs, cnt*sizeof *cbs);
  77. }
  78. for (i=0; i<cnt; i++) {
  79. if (!cbs[i]) continue;
  80. switch (cbs[i]->aio_lio_opcode) {
  81. case LIO_READ:
  82. ret = aio_read(cbs[i]);
  83. break;
  84. case LIO_WRITE:
  85. ret = aio_write(cbs[i]);
  86. break;
  87. default:
  88. continue;
  89. }
  90. if (ret) {
  91. free(st);
  92. errno = EAGAIN;
  93. return -1;
  94. }
  95. }
  96. if (mode == LIO_WAIT) {
  97. ret = lio_wait(st);
  98. free(st);
  99. return 0;
  100. }
  101. if (st) {
  102. pthread_attr_t a;
  103. sigset_t set;
  104. pthread_t td;
  105. if (sev->sigev_notify == SIGEV_THREAD) {
  106. if (sev->sigev_notify_attributes)
  107. a = *sev->sigev_notify_attributes;
  108. else
  109. pthread_attr_init(&a);
  110. } else {
  111. pthread_attr_init(&a);
  112. pthread_attr_setstacksize(&a, PAGE_SIZE);
  113. pthread_attr_setguardsize(&a, 0);
  114. }
  115. pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
  116. sigfillset(&set);
  117. pthread_sigmask(SIG_BLOCK, &set, &set);
  118. if (pthread_create(&td, &a, wait_thread, st)) {
  119. free(st);
  120. errno = EAGAIN;
  121. return -1;
  122. }
  123. pthread_sigmask(SIG_SETMASK, &set, 0);
  124. }
  125. return 0;
  126. }