lio_listio.c 2.6 KB

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