asyncengine 0.0.1.testing

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. data/README.markdown +0 -0
  2. data/asyncengine.gemspec +26 -0
  3. data/ext/asyncengine_ext/asyncengine_ruby.c +82 -0
  4. data/ext/asyncengine_ext/extconf.rb +47 -0
  5. data/ext/asyncengine_ext/libuv/AUTHORS +45 -0
  6. data/ext/asyncengine_ext/libuv/LICENSE +42 -0
  7. data/ext/asyncengine_ext/libuv/Makefile +119 -0
  8. data/ext/asyncengine_ext/libuv/README.md +88 -0
  9. data/ext/asyncengine_ext/libuv/build/gcc_version.py +20 -0
  10. data/ext/asyncengine_ext/libuv/common.gypi +176 -0
  11. data/ext/asyncengine_ext/libuv/config-mingw.mk +61 -0
  12. data/ext/asyncengine_ext/libuv/config-unix.mk +173 -0
  13. data/ext/asyncengine_ext/libuv/gyp_uv +60 -0
  14. data/ext/asyncengine_ext/libuv/include/ares.h +591 -0
  15. data/ext/asyncengine_ext/libuv/include/ares_version.h +24 -0
  16. data/ext/asyncengine_ext/libuv/include/uv-private/eio.h +403 -0
  17. data/ext/asyncengine_ext/libuv/include/uv-private/ev.h +838 -0
  18. data/ext/asyncengine_ext/libuv/include/uv-private/ngx-queue.h +106 -0
  19. data/ext/asyncengine_ext/libuv/include/uv-private/tree.h +768 -0
  20. data/ext/asyncengine_ext/libuv/include/uv-private/uv-unix.h +256 -0
  21. data/ext/asyncengine_ext/libuv/include/uv-private/uv-win.h +458 -0
  22. data/ext/asyncengine_ext/libuv/include/uv.h +1556 -0
  23. data/ext/asyncengine_ext/libuv/src/ares/AUTHORS +37 -0
  24. data/ext/asyncengine_ext/libuv/src/ares/CHANGES +1218 -0
  25. data/ext/asyncengine_ext/libuv/src/ares/CMakeLists.txt +22 -0
  26. data/ext/asyncengine_ext/libuv/src/ares/NEWS +21 -0
  27. data/ext/asyncengine_ext/libuv/src/ares/README +60 -0
  28. data/ext/asyncengine_ext/libuv/src/ares/README.cares +13 -0
  29. data/ext/asyncengine_ext/libuv/src/ares/README.msvc +142 -0
  30. data/ext/asyncengine_ext/libuv/src/ares/README.node +21 -0
  31. data/ext/asyncengine_ext/libuv/src/ares/RELEASE-NOTES +26 -0
  32. data/ext/asyncengine_ext/libuv/src/ares/TODO +23 -0
  33. data/ext/asyncengine_ext/libuv/src/ares/ares__close_sockets.c +66 -0
  34. data/ext/asyncengine_ext/libuv/src/ares/ares__get_hostent.c +263 -0
  35. data/ext/asyncengine_ext/libuv/src/ares/ares__read_line.c +71 -0
  36. data/ext/asyncengine_ext/libuv/src/ares/ares__timeval.c +111 -0
  37. data/ext/asyncengine_ext/libuv/src/ares/ares_cancel.c +63 -0
  38. data/ext/asyncengine_ext/libuv/src/ares/ares_data.c +190 -0
  39. data/ext/asyncengine_ext/libuv/src/ares/ares_data.h +65 -0
  40. data/ext/asyncengine_ext/libuv/src/ares/ares_destroy.c +105 -0
  41. data/ext/asyncengine_ext/libuv/src/ares/ares_dns.h +90 -0
  42. data/ext/asyncengine_ext/libuv/src/ares/ares_expand_name.c +200 -0
  43. data/ext/asyncengine_ext/libuv/src/ares/ares_expand_string.c +75 -0
  44. data/ext/asyncengine_ext/libuv/src/ares/ares_fds.c +63 -0
  45. data/ext/asyncengine_ext/libuv/src/ares/ares_free_hostent.c +42 -0
  46. data/ext/asyncengine_ext/libuv/src/ares/ares_free_string.c +25 -0
  47. data/ext/asyncengine_ext/libuv/src/ares/ares_getenv.c +30 -0
  48. data/ext/asyncengine_ext/libuv/src/ares/ares_getenv.h +26 -0
  49. data/ext/asyncengine_ext/libuv/src/ares/ares_gethostbyaddr.c +301 -0
  50. data/ext/asyncengine_ext/libuv/src/ares/ares_gethostbyname.c +523 -0
  51. data/ext/asyncengine_ext/libuv/src/ares/ares_getnameinfo.c +427 -0
  52. data/ext/asyncengine_ext/libuv/src/ares/ares_getopt.c +122 -0
  53. data/ext/asyncengine_ext/libuv/src/ares/ares_getopt.h +53 -0
  54. data/ext/asyncengine_ext/libuv/src/ares/ares_getsock.c +72 -0
  55. data/ext/asyncengine_ext/libuv/src/ares/ares_init.c +1809 -0
  56. data/ext/asyncengine_ext/libuv/src/ares/ares_iphlpapi.h +221 -0
  57. data/ext/asyncengine_ext/libuv/src/ares/ares_ipv6.h +78 -0
  58. data/ext/asyncengine_ext/libuv/src/ares/ares_library_init.c +142 -0
  59. data/ext/asyncengine_ext/libuv/src/ares/ares_library_init.h +42 -0
  60. data/ext/asyncengine_ext/libuv/src/ares/ares_llist.c +86 -0
  61. data/ext/asyncengine_ext/libuv/src/ares/ares_llist.h +42 -0
  62. data/ext/asyncengine_ext/libuv/src/ares/ares_mkquery.c +195 -0
  63. data/ext/asyncengine_ext/libuv/src/ares/ares_nowarn.c +181 -0
  64. data/ext/asyncengine_ext/libuv/src/ares/ares_nowarn.h +55 -0
  65. data/ext/asyncengine_ext/libuv/src/ares/ares_options.c +248 -0
  66. data/ext/asyncengine_ext/libuv/src/ares/ares_parse_a_reply.c +263 -0
  67. data/ext/asyncengine_ext/libuv/src/ares/ares_parse_aaaa_reply.c +259 -0
  68. data/ext/asyncengine_ext/libuv/src/ares/ares_parse_mx_reply.c +170 -0
  69. data/ext/asyncengine_ext/libuv/src/ares/ares_parse_ns_reply.c +182 -0
  70. data/ext/asyncengine_ext/libuv/src/ares/ares_parse_ptr_reply.c +217 -0
  71. data/ext/asyncengine_ext/libuv/src/ares/ares_parse_srv_reply.c +179 -0
  72. data/ext/asyncengine_ext/libuv/src/ares/ares_parse_txt_reply.c +201 -0
  73. data/ext/asyncengine_ext/libuv/src/ares/ares_platform.c +11035 -0
  74. data/ext/asyncengine_ext/libuv/src/ares/ares_platform.h +43 -0
  75. data/ext/asyncengine_ext/libuv/src/ares/ares_private.h +355 -0
  76. data/ext/asyncengine_ext/libuv/src/ares/ares_process.c +1295 -0
  77. data/ext/asyncengine_ext/libuv/src/ares/ares_query.c +183 -0
  78. data/ext/asyncengine_ext/libuv/src/ares/ares_rules.h +144 -0
  79. data/ext/asyncengine_ext/libuv/src/ares/ares_search.c +321 -0
  80. data/ext/asyncengine_ext/libuv/src/ares/ares_send.c +134 -0
  81. data/ext/asyncengine_ext/libuv/src/ares/ares_setup.h +199 -0
  82. data/ext/asyncengine_ext/libuv/src/ares/ares_strcasecmp.c +66 -0
  83. data/ext/asyncengine_ext/libuv/src/ares/ares_strcasecmp.h +30 -0
  84. data/ext/asyncengine_ext/libuv/src/ares/ares_strdup.c +42 -0
  85. data/ext/asyncengine_ext/libuv/src/ares/ares_strdup.h +26 -0
  86. data/ext/asyncengine_ext/libuv/src/ares/ares_strerror.c +56 -0
  87. data/ext/asyncengine_ext/libuv/src/ares/ares_timeout.c +80 -0
  88. data/ext/asyncengine_ext/libuv/src/ares/ares_version.c +11 -0
  89. data/ext/asyncengine_ext/libuv/src/ares/ares_writev.c +79 -0
  90. data/ext/asyncengine_ext/libuv/src/ares/ares_writev.h +36 -0
  91. data/ext/asyncengine_ext/libuv/src/ares/bitncmp.c +59 -0
  92. data/ext/asyncengine_ext/libuv/src/ares/bitncmp.h +26 -0
  93. data/ext/asyncengine_ext/libuv/src/ares/config_cygwin/ares_config.h +512 -0
  94. data/ext/asyncengine_ext/libuv/src/ares/config_darwin/ares_config.h +512 -0
  95. data/ext/asyncengine_ext/libuv/src/ares/config_freebsd/ares_config.h +512 -0
  96. data/ext/asyncengine_ext/libuv/src/ares/config_linux/ares_config.h +512 -0
  97. data/ext/asyncengine_ext/libuv/src/ares/config_netbsd/ares_config.h +512 -0
  98. data/ext/asyncengine_ext/libuv/src/ares/config_openbsd/ares_config.h +512 -0
  99. data/ext/asyncengine_ext/libuv/src/ares/config_sunos/ares_config.h +512 -0
  100. data/ext/asyncengine_ext/libuv/src/ares/config_win32/ares_config.h +369 -0
  101. data/ext/asyncengine_ext/libuv/src/ares/get_ver.awk +35 -0
  102. data/ext/asyncengine_ext/libuv/src/ares/inet_net_pton.c +451 -0
  103. data/ext/asyncengine_ext/libuv/src/ares/inet_net_pton.h +31 -0
  104. data/ext/asyncengine_ext/libuv/src/ares/inet_ntop.c +208 -0
  105. data/ext/asyncengine_ext/libuv/src/ares/inet_ntop.h +26 -0
  106. data/ext/asyncengine_ext/libuv/src/ares/nameser.h +203 -0
  107. data/ext/asyncengine_ext/libuv/src/ares/setup_once.h +504 -0
  108. data/ext/asyncengine_ext/libuv/src/ares/windows_port.c +22 -0
  109. data/ext/asyncengine_ext/libuv/src/unix/async.c +58 -0
  110. data/ext/asyncengine_ext/libuv/src/unix/cares.c +194 -0
  111. data/ext/asyncengine_ext/libuv/src/unix/check.c +80 -0
  112. data/ext/asyncengine_ext/libuv/src/unix/core.c +588 -0
  113. data/ext/asyncengine_ext/libuv/src/unix/cygwin.c +84 -0
  114. data/ext/asyncengine_ext/libuv/src/unix/darwin.c +341 -0
  115. data/ext/asyncengine_ext/libuv/src/unix/dl.c +91 -0
  116. data/ext/asyncengine_ext/libuv/src/unix/eio/Changes +63 -0
  117. data/ext/asyncengine_ext/libuv/src/unix/eio/LICENSE +36 -0
  118. data/ext/asyncengine_ext/libuv/src/unix/eio/Makefile.am +15 -0
  119. data/ext/asyncengine_ext/libuv/src/unix/eio/aclocal.m4 +8957 -0
  120. data/ext/asyncengine_ext/libuv/src/unix/eio/autogen.sh +3 -0
  121. data/ext/asyncengine_ext/libuv/src/unix/eio/config.h.in +86 -0
  122. data/ext/asyncengine_ext/libuv/src/unix/eio/config_cygwin.h +80 -0
  123. data/ext/asyncengine_ext/libuv/src/unix/eio/config_darwin.h +141 -0
  124. data/ext/asyncengine_ext/libuv/src/unix/eio/config_freebsd.h +81 -0
  125. data/ext/asyncengine_ext/libuv/src/unix/eio/config_linux.h +94 -0
  126. data/ext/asyncengine_ext/libuv/src/unix/eio/config_netbsd.h +81 -0
  127. data/ext/asyncengine_ext/libuv/src/unix/eio/config_openbsd.h +137 -0
  128. data/ext/asyncengine_ext/libuv/src/unix/eio/config_sunos.h +84 -0
  129. data/ext/asyncengine_ext/libuv/src/unix/eio/configure.ac +22 -0
  130. data/ext/asyncengine_ext/libuv/src/unix/eio/demo.c +194 -0
  131. data/ext/asyncengine_ext/libuv/src/unix/eio/ecb.h +370 -0
  132. data/ext/asyncengine_ext/libuv/src/unix/eio/eio.3 +3428 -0
  133. data/ext/asyncengine_ext/libuv/src/unix/eio/eio.c +2593 -0
  134. data/ext/asyncengine_ext/libuv/src/unix/eio/eio.pod +969 -0
  135. data/ext/asyncengine_ext/libuv/src/unix/eio/libeio.m4 +195 -0
  136. data/ext/asyncengine_ext/libuv/src/unix/eio/xthread.h +164 -0
  137. data/ext/asyncengine_ext/libuv/src/unix/error.c +98 -0
  138. data/ext/asyncengine_ext/libuv/src/unix/ev/Changes +388 -0
  139. data/ext/asyncengine_ext/libuv/src/unix/ev/LICENSE +36 -0
  140. data/ext/asyncengine_ext/libuv/src/unix/ev/Makefile.am +18 -0
  141. data/ext/asyncengine_ext/libuv/src/unix/ev/Makefile.in +771 -0
  142. data/ext/asyncengine_ext/libuv/src/unix/ev/README +58 -0
  143. data/ext/asyncengine_ext/libuv/src/unix/ev/aclocal.m4 +8957 -0
  144. data/ext/asyncengine_ext/libuv/src/unix/ev/autogen.sh +6 -0
  145. data/ext/asyncengine_ext/libuv/src/unix/ev/config.guess +1526 -0
  146. data/ext/asyncengine_ext/libuv/src/unix/ev/config.h.in +125 -0
  147. data/ext/asyncengine_ext/libuv/src/unix/ev/config.sub +1658 -0
  148. data/ext/asyncengine_ext/libuv/src/unix/ev/config_cygwin.h +123 -0
  149. data/ext/asyncengine_ext/libuv/src/unix/ev/config_darwin.h +122 -0
  150. data/ext/asyncengine_ext/libuv/src/unix/ev/config_freebsd.h +120 -0
  151. data/ext/asyncengine_ext/libuv/src/unix/ev/config_linux.h +141 -0
  152. data/ext/asyncengine_ext/libuv/src/unix/ev/config_netbsd.h +120 -0
  153. data/ext/asyncengine_ext/libuv/src/unix/ev/config_openbsd.h +126 -0
  154. data/ext/asyncengine_ext/libuv/src/unix/ev/config_sunos.h +122 -0
  155. data/ext/asyncengine_ext/libuv/src/unix/ev/configure +13037 -0
  156. data/ext/asyncengine_ext/libuv/src/unix/ev/configure.ac +18 -0
  157. data/ext/asyncengine_ext/libuv/src/unix/ev/depcomp +630 -0
  158. data/ext/asyncengine_ext/libuv/src/unix/ev/ev++.h +816 -0
  159. data/ext/asyncengine_ext/libuv/src/unix/ev/ev.3 +5311 -0
  160. data/ext/asyncengine_ext/libuv/src/unix/ev/ev.c +3921 -0
  161. data/ext/asyncengine_ext/libuv/src/unix/ev/ev.pod +5243 -0
  162. data/ext/asyncengine_ext/libuv/src/unix/ev/ev_epoll.c +266 -0
  163. data/ext/asyncengine_ext/libuv/src/unix/ev/ev_kqueue.c +235 -0
  164. data/ext/asyncengine_ext/libuv/src/unix/ev/ev_poll.c +148 -0
  165. data/ext/asyncengine_ext/libuv/src/unix/ev/ev_port.c +179 -0
  166. data/ext/asyncengine_ext/libuv/src/unix/ev/ev_select.c +310 -0
  167. data/ext/asyncengine_ext/libuv/src/unix/ev/ev_vars.h +203 -0
  168. data/ext/asyncengine_ext/libuv/src/unix/ev/ev_win32.c +153 -0
  169. data/ext/asyncengine_ext/libuv/src/unix/ev/ev_wrap.h +196 -0
  170. data/ext/asyncengine_ext/libuv/src/unix/ev/event.c +402 -0
  171. data/ext/asyncengine_ext/libuv/src/unix/ev/event.h +170 -0
  172. data/ext/asyncengine_ext/libuv/src/unix/ev/install-sh +294 -0
  173. data/ext/asyncengine_ext/libuv/src/unix/ev/libev.m4 +39 -0
  174. data/ext/asyncengine_ext/libuv/src/unix/ev/ltmain.sh +8413 -0
  175. data/ext/asyncengine_ext/libuv/src/unix/ev/missing +336 -0
  176. data/ext/asyncengine_ext/libuv/src/unix/ev/mkinstalldirs +111 -0
  177. data/ext/asyncengine_ext/libuv/src/unix/freebsd.c +312 -0
  178. data/ext/asyncengine_ext/libuv/src/unix/fs.c +707 -0
  179. data/ext/asyncengine_ext/libuv/src/unix/idle.c +79 -0
  180. data/ext/asyncengine_ext/libuv/src/unix/internal.h +161 -0
  181. data/ext/asyncengine_ext/libuv/src/unix/kqueue.c +127 -0
  182. data/ext/asyncengine_ext/libuv/src/unix/linux/core.c +474 -0
  183. data/ext/asyncengine_ext/libuv/src/unix/linux/inotify.c +211 -0
  184. data/ext/asyncengine_ext/libuv/src/unix/linux/syscalls.c +230 -0
  185. data/ext/asyncengine_ext/libuv/src/unix/linux/syscalls.h +87 -0
  186. data/ext/asyncengine_ext/libuv/src/unix/loop.c +58 -0
  187. data/ext/asyncengine_ext/libuv/src/unix/netbsd.c +108 -0
  188. data/ext/asyncengine_ext/libuv/src/unix/openbsd.c +295 -0
  189. data/ext/asyncengine_ext/libuv/src/unix/pipe.c +266 -0
  190. data/ext/asyncengine_ext/libuv/src/unix/prepare.c +79 -0
  191. data/ext/asyncengine_ext/libuv/src/unix/process.c +369 -0
  192. data/ext/asyncengine_ext/libuv/src/unix/stream.c +1033 -0
  193. data/ext/asyncengine_ext/libuv/src/unix/sunos.c +466 -0
  194. data/ext/asyncengine_ext/libuv/src/unix/tcp.c +327 -0
  195. data/ext/asyncengine_ext/libuv/src/unix/thread.c +154 -0
  196. data/ext/asyncengine_ext/libuv/src/unix/timer.c +127 -0
  197. data/ext/asyncengine_ext/libuv/src/unix/tty.c +146 -0
  198. data/ext/asyncengine_ext/libuv/src/unix/udp.c +670 -0
  199. data/ext/asyncengine_ext/libuv/src/unix/uv-eio.c +124 -0
  200. data/ext/asyncengine_ext/libuv/src/unix/uv-eio.h +13 -0
  201. data/ext/asyncengine_ext/libuv/src/uv-common.c +354 -0
  202. data/ext/asyncengine_ext/libuv/src/uv-common.h +87 -0
  203. data/ext/asyncengine_ext/libuv/src/win/async.c +127 -0
  204. data/ext/asyncengine_ext/libuv/src/win/cares.c +290 -0
  205. data/ext/asyncengine_ext/libuv/src/win/core.c +270 -0
  206. data/ext/asyncengine_ext/libuv/src/win/dl.c +82 -0
  207. data/ext/asyncengine_ext/libuv/src/win/error.c +132 -0
  208. data/ext/asyncengine_ext/libuv/src/win/fs-event.c +514 -0
  209. data/ext/asyncengine_ext/libuv/src/win/fs.c +1576 -0
  210. data/ext/asyncengine_ext/libuv/src/win/getaddrinfo.c +372 -0
  211. data/ext/asyncengine_ext/libuv/src/win/handle.c +225 -0
  212. data/ext/asyncengine_ext/libuv/src/win/internal.h +352 -0
  213. data/ext/asyncengine_ext/libuv/src/win/loop-watcher.c +131 -0
  214. data/ext/asyncengine_ext/libuv/src/win/pipe.c +1661 -0
  215. data/ext/asyncengine_ext/libuv/src/win/process.c +1140 -0
  216. data/ext/asyncengine_ext/libuv/src/win/req.c +174 -0
  217. data/ext/asyncengine_ext/libuv/src/win/stream.c +201 -0
  218. data/ext/asyncengine_ext/libuv/src/win/tcp.c +1282 -0
  219. data/ext/asyncengine_ext/libuv/src/win/thread.c +332 -0
  220. data/ext/asyncengine_ext/libuv/src/win/threadpool.c +73 -0
  221. data/ext/asyncengine_ext/libuv/src/win/timer.c +276 -0
  222. data/ext/asyncengine_ext/libuv/src/win/tty.c +1795 -0
  223. data/ext/asyncengine_ext/libuv/src/win/udp.c +709 -0
  224. data/ext/asyncengine_ext/libuv/src/win/util.c +719 -0
  225. data/ext/asyncengine_ext/libuv/src/win/winapi.c +117 -0
  226. data/ext/asyncengine_ext/libuv/src/win/winapi.h +4419 -0
  227. data/ext/asyncengine_ext/libuv/src/win/winsock.c +470 -0
  228. data/ext/asyncengine_ext/libuv/src/win/winsock.h +138 -0
  229. data/ext/asyncengine_ext/libuv/test/benchmark-ares.c +118 -0
  230. data/ext/asyncengine_ext/libuv/test/benchmark-getaddrinfo.c +94 -0
  231. data/ext/asyncengine_ext/libuv/test/benchmark-list.h +105 -0
  232. data/ext/asyncengine_ext/libuv/test/benchmark-ping-pongs.c +213 -0
  233. data/ext/asyncengine_ext/libuv/test/benchmark-pound.c +324 -0
  234. data/ext/asyncengine_ext/libuv/test/benchmark-pump.c +462 -0
  235. data/ext/asyncengine_ext/libuv/test/benchmark-sizes.c +40 -0
  236. data/ext/asyncengine_ext/libuv/test/benchmark-spawn.c +156 -0
  237. data/ext/asyncengine_ext/libuv/test/benchmark-tcp-write-batch.c +140 -0
  238. data/ext/asyncengine_ext/libuv/test/benchmark-thread.c +64 -0
  239. data/ext/asyncengine_ext/libuv/test/benchmark-udp-packet-storm.c +247 -0
  240. data/ext/asyncengine_ext/libuv/test/blackhole-server.c +118 -0
  241. data/ext/asyncengine_ext/libuv/test/dns-server.c +321 -0
  242. data/ext/asyncengine_ext/libuv/test/echo-server.c +370 -0
  243. data/ext/asyncengine_ext/libuv/test/fixtures/empty_file +0 -0
  244. data/ext/asyncengine_ext/libuv/test/fixtures/load_error.node +1 -0
  245. data/ext/asyncengine_ext/libuv/test/run-benchmarks.c +64 -0
  246. data/ext/asyncengine_ext/libuv/test/run-tests.c +108 -0
  247. data/ext/asyncengine_ext/libuv/test/runner-unix.c +315 -0
  248. data/ext/asyncengine_ext/libuv/test/runner-unix.h +36 -0
  249. data/ext/asyncengine_ext/libuv/test/runner-win.c +343 -0
  250. data/ext/asyncengine_ext/libuv/test/runner-win.h +42 -0
  251. data/ext/asyncengine_ext/libuv/test/runner.c +317 -0
  252. data/ext/asyncengine_ext/libuv/test/runner.h +159 -0
  253. data/ext/asyncengine_ext/libuv/test/task.h +117 -0
  254. data/ext/asyncengine_ext/libuv/test/test-async.c +216 -0
  255. data/ext/asyncengine_ext/libuv/test/test-callback-stack.c +203 -0
  256. data/ext/asyncengine_ext/libuv/test/test-connection-fail.c +148 -0
  257. data/ext/asyncengine_ext/libuv/test/test-counters-init.c +216 -0
  258. data/ext/asyncengine_ext/libuv/test/test-cwd-and-chdir.c +64 -0
  259. data/ext/asyncengine_ext/libuv/test/test-delayed-accept.c +197 -0
  260. data/ext/asyncengine_ext/libuv/test/test-dlerror.c +49 -0
  261. data/ext/asyncengine_ext/libuv/test/test-eio-overflow.c +90 -0
  262. data/ext/asyncengine_ext/libuv/test/test-error.c +59 -0
  263. data/ext/asyncengine_ext/libuv/test/test-fail-always.c +29 -0
  264. data/ext/asyncengine_ext/libuv/test/test-fs-event.c +442 -0
  265. data/ext/asyncengine_ext/libuv/test/test-fs.c +1731 -0
  266. data/ext/asyncengine_ext/libuv/test/test-get-currentexe.c +63 -0
  267. data/ext/asyncengine_ext/libuv/test/test-get-loadavg.c +36 -0
  268. data/ext/asyncengine_ext/libuv/test/test-get-memory.c +38 -0
  269. data/ext/asyncengine_ext/libuv/test/test-getaddrinfo.c +122 -0
  270. data/ext/asyncengine_ext/libuv/test/test-gethostbyname.c +189 -0
  271. data/ext/asyncengine_ext/libuv/test/test-getsockname.c +342 -0
  272. data/ext/asyncengine_ext/libuv/test/test-hrtime.c +51 -0
  273. data/ext/asyncengine_ext/libuv/test/test-idle.c +81 -0
  274. data/ext/asyncengine_ext/libuv/test/test-ipc-send-recv.c +209 -0
  275. data/ext/asyncengine_ext/libuv/test/test-ipc.c +614 -0
  276. data/ext/asyncengine_ext/libuv/test/test-list.h +371 -0
  277. data/ext/asyncengine_ext/libuv/test/test-loop-handles.c +359 -0
  278. data/ext/asyncengine_ext/libuv/test/test-multiple-listen.c +102 -0
  279. data/ext/asyncengine_ext/libuv/test/test-mutexes.c +63 -0
  280. data/ext/asyncengine_ext/libuv/test/test-pass-always.c +28 -0
  281. data/ext/asyncengine_ext/libuv/test/test-ping-pong.c +253 -0
  282. data/ext/asyncengine_ext/libuv/test/test-pipe-bind-error.c +140 -0
  283. data/ext/asyncengine_ext/libuv/test/test-pipe-connect-error.c +96 -0
  284. data/ext/asyncengine_ext/libuv/test/test-platform-output.c +87 -0
  285. data/ext/asyncengine_ext/libuv/test/test-process-title.c +42 -0
  286. data/ext/asyncengine_ext/libuv/test/test-ref.c +322 -0
  287. data/ext/asyncengine_ext/libuv/test/test-run-once.c +44 -0
  288. data/ext/asyncengine_ext/libuv/test/test-shutdown-close.c +103 -0
  289. data/ext/asyncengine_ext/libuv/test/test-shutdown-eof.c +183 -0
  290. data/ext/asyncengine_ext/libuv/test/test-spawn.c +499 -0
  291. data/ext/asyncengine_ext/libuv/test/test-stdio-over-pipes.c +256 -0
  292. data/ext/asyncengine_ext/libuv/test/test-tcp-bind-error.c +191 -0
  293. data/ext/asyncengine_ext/libuv/test/test-tcp-bind6-error.c +154 -0
  294. data/ext/asyncengine_ext/libuv/test/test-tcp-close.c +129 -0
  295. data/ext/asyncengine_ext/libuv/test/test-tcp-connect-error.c +70 -0
  296. data/ext/asyncengine_ext/libuv/test/test-tcp-connect6-error.c +68 -0
  297. data/ext/asyncengine_ext/libuv/test/test-tcp-flags.c +51 -0
  298. data/ext/asyncengine_ext/libuv/test/test-tcp-write-error.c +168 -0
  299. data/ext/asyncengine_ext/libuv/test/test-tcp-write-to-half-open-connection.c +135 -0
  300. data/ext/asyncengine_ext/libuv/test/test-tcp-writealot.c +195 -0
  301. data/ext/asyncengine_ext/libuv/test/test-thread.c +183 -0
  302. data/ext/asyncengine_ext/libuv/test/test-threadpool.c +57 -0
  303. data/ext/asyncengine_ext/libuv/test/test-timer-again.c +141 -0
  304. data/ext/asyncengine_ext/libuv/test/test-timer.c +130 -0
  305. data/ext/asyncengine_ext/libuv/test/test-tty.c +110 -0
  306. data/ext/asyncengine_ext/libuv/test/test-udp-dgram-too-big.c +86 -0
  307. data/ext/asyncengine_ext/libuv/test/test-udp-ipv6.c +156 -0
  308. data/ext/asyncengine_ext/libuv/test/test-udp-multicast-join.c +139 -0
  309. data/ext/asyncengine_ext/libuv/test/test-udp-multicast-ttl.c +86 -0
  310. data/ext/asyncengine_ext/libuv/test/test-udp-options.c +86 -0
  311. data/ext/asyncengine_ext/libuv/test/test-udp-send-and-recv.c +208 -0
  312. data/ext/asyncengine_ext/libuv/test/test-util.c +97 -0
  313. data/ext/asyncengine_ext/libuv/uv.gyp +435 -0
  314. data/ext/asyncengine_ext/libuv/vcbuild.bat +105 -0
  315. data/lib/asyncengine/version.rb +3 -0
  316. data/lib/asyncengine.rb +41 -0
  317. metadata +384 -0
@@ -0,0 +1,2593 @@
1
+ /*
2
+ * libeio implementation
3
+ *
4
+ * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libeio@schmorp.de>
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without modifica-
8
+ * tion, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ *
13
+ * 2. Redistributions in binary form must reproduce the above copyright
14
+ * notice, this list of conditions and the following disclaimer in the
15
+ * documentation and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ *
28
+ * Alternatively, the contents of this file may be used under the terms of
29
+ * the GNU General Public License ("GPL") version 2 or any later version,
30
+ * in which case the provisions of the GPL are applicable instead of
31
+ * the above. If you wish to allow the use of your version of this file
32
+ * only under the terms of the GPL and not to allow others to use your
33
+ * version of this file under the BSD license, indicate your decision
34
+ * by deleting the provisions above and replace them with the notice
35
+ * and other provisions required by the GPL. If you do not delete the
36
+ * provisions above, a recipient may use your version of this file under
37
+ * either the BSD or the GPL.
38
+ */
39
+
40
+ #ifdef EIO_CONFIG_H
41
+ # include EIO_CONFIG_H
42
+ #endif
43
+
44
+ /* Undone by libuv for easy build scripts.
45
+ * #ifndef _WIN32
46
+ * # include "config.h"
47
+ * #endif
48
+ */
49
+
50
+ #include "eio.h"
51
+ #include "ecb.h"
52
+
53
+ #ifdef EIO_STACKSIZE
54
+ # define X_STACKSIZE EIO_STACKSIZE
55
+ #endif
56
+ #include "xthread.h"
57
+
58
+ #include <errno.h>
59
+ #include <stddef.h>
60
+ #include <stdlib.h>
61
+ #include <string.h>
62
+ #include <errno.h>
63
+ #include <sys/types.h>
64
+ #include <sys/stat.h>
65
+ #include <limits.h>
66
+ #include <fcntl.h>
67
+ #include <assert.h>
68
+
69
+ /* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */
70
+ /* intptr_t only comes from stdint.h, says idiot openbsd coder */
71
+ #if HAVE_STDINT_H
72
+ # include <stdint.h>
73
+ #endif
74
+
75
+ #ifndef ECANCELED
76
+ # define ECANCELED EDOM
77
+ #endif
78
+ #ifndef ELOOP
79
+ # define ELOOP EDOM
80
+ #endif
81
+
82
+ #if !defined(ENOTSOCK) && defined(WSAENOTSOCK)
83
+ # define ENOTSOCK WSAENOTSOCK
84
+ #endif
85
+
86
+ static void eio_destroy (eio_req *req);
87
+
88
+ #ifndef EIO_FINISH
89
+ # define EIO_FINISH(req) ((req)->finish) && !EIO_CANCELLED (req) ? (req)->finish (req) : 0
90
+ #endif
91
+
92
+ #ifndef EIO_DESTROY
93
+ # define EIO_DESTROY(req) do { if ((req)->destroy) (req)->destroy (req); } while (0)
94
+ #endif
95
+
96
+ #ifndef EIO_FEED
97
+ # define EIO_FEED(req) do { if ((req)->feed ) (req)->feed (req); } while (0)
98
+ #endif
99
+
100
+ #ifndef EIO_FD_TO_WIN32_HANDLE
101
+ # define EIO_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd)
102
+ #endif
103
+ #ifndef EIO_WIN32_HANDLE_TO_FD
104
+ # define EIO_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0)
105
+ #endif
106
+
107
+ #define EIO_ERRNO(errval,retval) ((errno = errval), retval)
108
+
109
+ #define EIO_ENOSYS() EIO_ERRNO (ENOSYS, -1)
110
+
111
+ #ifdef __sun
112
+ # define futimes(fd, times) futimesat (fd, NULL, times)
113
+ #endif
114
+
115
+ #ifdef _WIN32
116
+
117
+ #include <direct.h>
118
+
119
+ #undef PAGESIZE
120
+ #define PAGESIZE 4096 /* GetSystemInfo? */
121
+
122
+ /* TODO: look at how perl does stat (non-sloppy), unlink (ro-files), utime, link */
123
+
124
+ #ifdef EIO_STRUCT_STATI64
125
+ /* look at perl's non-sloppy stat */
126
+ #define stat(path,buf) _stati64 (path,buf)
127
+ #define fstat(fd,buf) _fstati64 (fd,buf)
128
+ #endif
129
+ #define lstat(path,buf) stat (path,buf)
130
+ #define fsync(fd) (FlushFileBuffers ((HANDLE)EIO_FD_TO_WIN32_HANDLE (fd)) ? 0 : EIO_ERRNO (EBADF, -1))
131
+ #define mkdir(path,mode) _mkdir (path)
132
+ #define link(old,neu) (CreateHardLink (neu, old, 0) ? 0 : EIO_ERRNO (ENOENT, -1))
133
+
134
+ #define chmod(path,mode) _chmod (path, mode)
135
+ #define dup(fd) _dup (fd)
136
+ #define dup2(fd1,fd2) _dup2 (fd1, fd2)
137
+
138
+ #define fchmod(fd,mode) EIO_ENOSYS ()
139
+ #define chown(path,uid,gid) EIO_ENOSYS ()
140
+ #define fchown(fd,uid,gid) EIO_ENOSYS ()
141
+ #define truncate(path,offs) EIO_ENOSYS () /* far-miss: SetEndOfFile */
142
+ #define ftruncate(fd,offs) EIO_ENOSYS () /* near-miss: SetEndOfFile */
143
+ #define mknod(path,mode,dev) EIO_ENOSYS ()
144
+ #define sync() EIO_ENOSYS ()
145
+ #define readlink(path,buf,s) EIO_ENOSYS ()
146
+ #define statvfs(path,buf) EIO_ENOSYS ()
147
+ #define fstatvfs(fd,buf) EIO_ENOSYS ()
148
+
149
+ #define getcwd(buf,s) _getcwd(buf, s)
150
+ #define rmdir(path) _rmdir(path)
151
+
152
+ /* rename() uses MoveFile, which fails to overwrite */
153
+ #define rename(old,neu) eio__rename (old, neu)
154
+
155
+ static int
156
+ eio__rename (const char *old, const char *neu)
157
+ {
158
+ if (MoveFileEx (old, neu, MOVEFILE_REPLACE_EXISTING))
159
+ return 0;
160
+
161
+ /* should steal _dosmaperr */
162
+ switch (GetLastError ())
163
+ {
164
+ case ERROR_FILE_NOT_FOUND:
165
+ case ERROR_PATH_NOT_FOUND:
166
+ case ERROR_INVALID_DRIVE:
167
+ case ERROR_NO_MORE_FILES:
168
+ case ERROR_BAD_NETPATH:
169
+ case ERROR_BAD_NET_NAME:
170
+ case ERROR_BAD_PATHNAME:
171
+ case ERROR_FILENAME_EXCED_RANGE:
172
+ errno = ENOENT;
173
+ break;
174
+
175
+ default:
176
+ errno = EACCES;
177
+ break;
178
+ }
179
+
180
+ return -1;
181
+ }
182
+
183
+ /* we could even stat and see if it exists */
184
+ static int
185
+ symlink (const char *old, const char *neu)
186
+ {
187
+ #if WINVER >= 0x0600
188
+ if (CreateSymbolicLink (neu, old, 1))
189
+ return 0;
190
+
191
+ if (CreateSymbolicLink (neu, old, 0))
192
+ return 0;
193
+ #endif
194
+
195
+ return EIO_ERRNO (ENOENT, -1);
196
+ }
197
+
198
+ /* POSIX API only */
199
+ #ifndef CreateHardLink
200
+ # define CreateHardLink(neu,old,flags) 0
201
+ #endif
202
+ #define CreateSymbolicLink(neu,old,flags) 0
203
+
204
+ struct statvfs
205
+ {
206
+ int dummy;
207
+ };
208
+
209
+ #define DT_DIR EIO_DT_DIR
210
+ #define DT_REG EIO_DT_REG
211
+ #define D_NAME(entp) entp.cFileName
212
+ #define D_TYPE(entp) (entp.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? DT_DIR : DT_REG)
213
+
214
+ #include <sys/utime.h>
215
+ #define utime(path, times) _utime(path, times)
216
+ #define utimbuf _utimbuf
217
+
218
+ #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
219
+ #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
220
+ #else
221
+ #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
222
+ #endif
223
+
224
+ struct timezone
225
+ {
226
+ int tz_minuteswest; /* minutes W of Greenwich */
227
+ int tz_dsttime; /* type of dst correction */
228
+ };
229
+
230
+ static int gettimeofday(struct timeval *tv, struct timezone *tz)
231
+ {
232
+ FILETIME ft;
233
+ unsigned __int64 tmpres = 0;
234
+ static int tzflag;
235
+
236
+ if (NULL != tv)
237
+ {
238
+ GetSystemTimeAsFileTime(&ft);
239
+
240
+ tmpres |= ft.dwHighDateTime;
241
+ tmpres <<= 32;
242
+ tmpres |= ft.dwLowDateTime;
243
+
244
+ /*converting file time to unix epoch*/
245
+ tmpres -= DELTA_EPOCH_IN_MICROSECS;
246
+ tmpres /= 10; /*convert into microseconds*/
247
+ tv->tv_sec = (long)(tmpres / 1000000UL);
248
+ tv->tv_usec = (long)(tmpres % 1000000UL);
249
+ }
250
+
251
+ if (NULL != tz)
252
+ {
253
+ if (!tzflag)
254
+ {
255
+ _tzset();
256
+ tzflag++;
257
+ }
258
+ tz->tz_minuteswest = _timezone / 60;
259
+ tz->tz_dsttime = _daylight;
260
+ }
261
+
262
+ return 0;
263
+ }
264
+
265
+ #else
266
+
267
+ #include <sys/time.h>
268
+ #include <sys/select.h>
269
+ #include <sys/statvfs.h>
270
+ #include <unistd.h>
271
+ #include <signal.h>
272
+ #include <dirent.h>
273
+
274
+ #if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES
275
+ #include <sys/mman.h>
276
+ #endif
277
+
278
+ #define D_NAME(entp) entp->d_name
279
+
280
+ /* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */
281
+ #if __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
282
+ #define _DIRENT_HAVE_D_TYPE /* sigh */
283
+ #define D_INO(de) (de)->d_fileno
284
+ #define D_NAMLEN(de) (de)->d_namlen
285
+ #elif __linux || defined d_ino || _XOPEN_SOURCE >= 600
286
+ #define D_INO(de) (de)->d_ino
287
+ #endif
288
+
289
+ #ifdef _D_EXACT_NAMLEN
290
+ #undef D_NAMLEN
291
+ #define D_NAMLEN(de) _D_EXACT_NAMLEN (de)
292
+ #endif
293
+
294
+ #ifdef _DIRENT_HAVE_D_TYPE
295
+ #define D_TYPE(de) (de)->d_type
296
+ #endif
297
+
298
+ #ifndef EIO_STRUCT_DIRENT
299
+ #define EIO_STRUCT_DIRENT struct dirent
300
+ #endif
301
+
302
+ #endif
303
+
304
+ #if HAVE_UTIMES
305
+ # include <utime.h>
306
+ #endif
307
+
308
+ #if HAVE_SYS_SYSCALL_H
309
+ # include <sys/syscall.h>
310
+ #endif
311
+
312
+ #if HAVE_SYS_PRCTL_H
313
+ # include <sys/prctl.h>
314
+ #endif
315
+
316
+ #if HAVE_SENDFILE
317
+ # if __linux
318
+ # include <sys/sendfile.h>
319
+ # elif __FreeBSD__ || __DragonFly__ || defined __APPLE__
320
+ # include <sys/socket.h>
321
+ # include <sys/uio.h>
322
+ # elif __hpux
323
+ # include <sys/socket.h>
324
+ # elif __solaris
325
+ # include <sys/sendfile.h>
326
+ # else
327
+ # error sendfile support requested but not available
328
+ # endif
329
+ #endif
330
+
331
+ #ifndef D_TYPE
332
+ # define D_TYPE(de) 0
333
+ #endif
334
+ #ifndef D_INO
335
+ # define D_INO(de) 0
336
+ #endif
337
+ #ifndef D_NAMLEN
338
+ # define D_NAMLEN(entp) strlen (D_NAME (entp))
339
+ #endif
340
+
341
+ /* used for struct dirent, AIX doesn't provide it */
342
+ #ifndef NAME_MAX
343
+ # define NAME_MAX 4096
344
+ #endif
345
+
346
+ /* used for readlink etc. */
347
+ #ifndef PATH_MAX
348
+ # define PATH_MAX 4096
349
+ #endif
350
+
351
+ /* buffer size for various temporary buffers */
352
+ #define EIO_BUFSIZE 65536
353
+
354
+ #define dBUF \
355
+ char *eio_buf = malloc (EIO_BUFSIZE); \
356
+ errno = ENOMEM; \
357
+ if (!eio_buf) \
358
+ return -1
359
+
360
+ #define FUBd \
361
+ free (eio_buf)
362
+
363
+ #define EIO_TICKS ((1000000 + 1023) >> 10)
364
+
365
+ struct etp_worker;
366
+
367
+ #define ETP_DESTROY(req) eio_destroy (req)
368
+ static int eio_finish (eio_req *req);
369
+ #define ETP_FINISH(req) eio_finish (req)
370
+ static void eio_execute (struct etp_worker *self, eio_req *req);
371
+ #define ETP_EXECUTE(wrk,req) eio_execute (wrk,req)
372
+
373
+ /*****************************************************************************/
374
+
375
+ /* calculate time difference in ~1/EIO_TICKS of a second */
376
+ ecb_inline int
377
+ tvdiff (struct timeval *tv1, struct timeval *tv2)
378
+ {
379
+ return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS
380
+ + ((tv2->tv_usec - tv1->tv_usec) >> 10);
381
+ }
382
+
383
+ static unsigned int started, idle, wanted = 4;
384
+
385
+ static void (*want_poll_cb) (eio_channel *);
386
+ static void (*done_poll_cb) (eio_channel *);
387
+
388
+ static unsigned int max_poll_time; /* reslock */
389
+ static unsigned int max_poll_reqs; /* reslock */
390
+
391
+ static unsigned int nreqs; /* reqlock */
392
+ static unsigned int nready; /* reqlock */
393
+ static unsigned int npending; /* reqlock */
394
+ static unsigned int max_idle = 4; /* maximum number of threads that can idle indefinitely */
395
+ static unsigned int idle_timeout = 10; /* number of seconds after which an idle threads exit */
396
+
397
+ static xmutex_t wrklock;
398
+ static xmutex_t reslock;
399
+ static xmutex_t reqlock;
400
+ static xcond_t reqwait;
401
+
402
+ /* Fix for test-fs-sir-writes-alot */
403
+ /* Apple's OSX can't safely write() concurrently from 2 threads */
404
+ /* for more info see the thread "fs.write Data Munging" in the nodejs google group */
405
+ /* http://groups.google.com/group/nodejs/browse_thread/thread/c11f8b683f37cef/b18ad9e0a15314c5 */
406
+ /* And the thread "write()s and pwrite()s from multiple threads in OSX" in libev@lists.schmorp.de */
407
+ /* http://lists.schmorp.de/pipermail/libev/2010q4/001185.html */
408
+ #if defined (__APPLE__)
409
+ static xmutex_t apple_bug_writelock = X_MUTEX_INIT;
410
+ #endif
411
+
412
+ #if !HAVE_PREADWRITE
413
+ /*
414
+ * make our pread/pwrite emulation safe against themselves, but not against
415
+ * normal read/write by using a mutex. slows down execution a lot,
416
+ * but that's your problem, not mine.
417
+ */
418
+ static xmutex_t preadwritelock;
419
+ #endif
420
+
421
+ typedef struct etp_worker
422
+ {
423
+ /* locked by wrklock */
424
+ struct etp_worker *prev, *next;
425
+
426
+ xthread_t tid;
427
+
428
+ /* locked by reslock, reqlock or wrklock */
429
+ ETP_REQ *req; /* currently processed request */
430
+
431
+ #ifdef ETP_WORKER_COMMON
432
+ ETP_WORKER_COMMON
433
+ #endif
434
+ } etp_worker;
435
+
436
+ static etp_worker wrk_first; /* NOT etp */
437
+
438
+ #define ETP_WORKER_LOCK(wrk) X_LOCK (wrklock)
439
+ #define ETP_WORKER_UNLOCK(wrk) X_UNLOCK (wrklock)
440
+
441
+ /* worker threads management */
442
+
443
+ static void ecb_cold
444
+ etp_worker_clear (etp_worker *wrk)
445
+ {
446
+ }
447
+
448
+ static void ecb_cold
449
+ etp_worker_free (etp_worker *wrk)
450
+ {
451
+ wrk->next->prev = wrk->prev;
452
+ wrk->prev->next = wrk->next;
453
+
454
+ free (wrk);
455
+ }
456
+
457
+ static unsigned int
458
+ etp_nreqs (void)
459
+ {
460
+ int retval;
461
+ if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
462
+ retval = nreqs;
463
+ if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
464
+ return retval;
465
+ }
466
+
467
+ static unsigned int
468
+ etp_nready (void)
469
+ {
470
+ unsigned int retval;
471
+
472
+ if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
473
+ retval = nready;
474
+ if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
475
+
476
+ return retval;
477
+ }
478
+
479
+ static unsigned int
480
+ etp_npending (void)
481
+ {
482
+ unsigned int retval;
483
+
484
+ if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
485
+ retval = npending;
486
+ if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
487
+
488
+ return retval;
489
+ }
490
+
491
+ static unsigned int
492
+ etp_nthreads (void)
493
+ {
494
+ unsigned int retval;
495
+
496
+ if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
497
+ retval = started;
498
+ if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
499
+
500
+ return retval;
501
+ }
502
+
503
+ static etp_reqq req_queue;
504
+ static eio_channel default_channel;
505
+
506
+ static void ecb_noinline ecb_cold
507
+ reqq_init (etp_reqq *q)
508
+ {
509
+ int pri;
510
+
511
+ for (pri = 0; pri < ETP_NUM_PRI; ++pri)
512
+ q->qs[pri] = q->qe[pri] = 0;
513
+
514
+ q->size = 0;
515
+ }
516
+
517
+ static int ecb_noinline
518
+ reqq_push (etp_reqq *q, ETP_REQ *req)
519
+ {
520
+ int pri = req->pri;
521
+ req->next = 0;
522
+
523
+ if (q->qe[pri])
524
+ {
525
+ q->qe[pri]->next = req;
526
+ q->qe[pri] = req;
527
+ }
528
+ else
529
+ q->qe[pri] = q->qs[pri] = req;
530
+
531
+ return q->size++;
532
+ }
533
+
534
+ static ETP_REQ * ecb_noinline
535
+ reqq_shift (etp_reqq *q)
536
+ {
537
+ int pri;
538
+
539
+ if (!q->size)
540
+ return 0;
541
+
542
+ --q->size;
543
+
544
+ for (pri = ETP_NUM_PRI; pri--; )
545
+ {
546
+ eio_req *req = q->qs[pri];
547
+
548
+ if (req)
549
+ {
550
+ if (!(q->qs[pri] = (eio_req *)req->next))
551
+ q->qe[pri] = 0;
552
+
553
+ return req;
554
+ }
555
+ }
556
+
557
+ abort ();
558
+ }
559
+
560
+ static int ecb_cold
561
+ etp_init (void (*want_poll)(eio_channel *), void (*done_poll)(eio_channel *))
562
+ {
563
+ X_MUTEX_CREATE (wrklock);
564
+ X_MUTEX_CREATE (reslock);
565
+ X_MUTEX_CREATE (reqlock);
566
+ X_COND_CREATE (reqwait);
567
+
568
+ reqq_init (&req_queue);
569
+ eio_channel_init (&default_channel, 0);
570
+
571
+ wrk_first.next =
572
+ wrk_first.prev = &wrk_first;
573
+
574
+ started = 0;
575
+ idle = 0;
576
+ nreqs = 0;
577
+ nready = 0;
578
+ npending = 0;
579
+
580
+ want_poll_cb = want_poll;
581
+ done_poll_cb = done_poll;
582
+
583
+ return 0;
584
+ }
585
+
586
+ X_THREAD_PROC (etp_proc);
587
+
588
+ static void ecb_cold
589
+ etp_start_thread (void)
590
+ {
591
+ etp_worker *wrk = calloc (1, sizeof (etp_worker));
592
+
593
+ /*TODO*/
594
+ assert (("unable to allocate worker thread data", wrk));
595
+
596
+ X_LOCK (wrklock);
597
+
598
+ if (thread_create (&wrk->tid, etp_proc, (void *)wrk))
599
+ {
600
+ wrk->prev = &wrk_first;
601
+ wrk->next = wrk_first.next;
602
+ wrk_first.next->prev = wrk;
603
+ wrk_first.next = wrk;
604
+ ++started;
605
+ }
606
+ else
607
+ free (wrk);
608
+
609
+ X_UNLOCK (wrklock);
610
+ }
611
+
612
+ static void
613
+ etp_maybe_start_thread (void)
614
+ {
615
+ if (ecb_expect_true (etp_nthreads () >= wanted))
616
+ return;
617
+
618
+ /* todo: maybe use idle here, but might be less exact */
619
+ if (ecb_expect_true (0 <= (int)etp_nthreads () + (int)etp_npending () - (int)etp_nreqs ()))
620
+ return;
621
+
622
+ etp_start_thread ();
623
+ }
624
+
625
+ static void ecb_cold
626
+ etp_end_thread (void)
627
+ {
628
+ eio_req *req = calloc (1, sizeof (eio_req));
629
+
630
+ req->type = -1;
631
+ req->pri = ETP_PRI_MAX - ETP_PRI_MIN;
632
+
633
+ X_LOCK (reqlock);
634
+ reqq_push (&req_queue, req);
635
+ X_COND_SIGNAL (reqwait);
636
+ X_UNLOCK (reqlock);
637
+
638
+ X_LOCK (wrklock);
639
+ --started;
640
+ X_UNLOCK (wrklock);
641
+ }
642
+
643
+ void
644
+ eio_channel_init(eio_channel *channel, void *data) {
645
+ reqq_init(&channel->res_queue);
646
+ channel->data = data;
647
+ }
648
+
649
+ static int
650
+ etp_poll (eio_channel *channel)
651
+ {
652
+ unsigned int maxreqs;
653
+ unsigned int maxtime;
654
+ struct timeval tv_start, tv_now;
655
+ if(!channel) channel = &default_channel;
656
+
657
+ X_LOCK (reslock);
658
+ maxreqs = max_poll_reqs;
659
+ maxtime = max_poll_time;
660
+ X_UNLOCK (reslock);
661
+
662
+ if (maxtime)
663
+ gettimeofday (&tv_start, 0);
664
+
665
+ for (;;)
666
+ {
667
+ ETP_REQ *req;
668
+
669
+ etp_maybe_start_thread ();
670
+
671
+ X_LOCK (reslock);
672
+ req = reqq_shift (&channel->res_queue);
673
+
674
+ if (req)
675
+ {
676
+ --npending;
677
+
678
+ if (!channel->res_queue.size && done_poll_cb)
679
+ done_poll_cb (channel);
680
+ }
681
+
682
+ X_UNLOCK (reslock);
683
+
684
+ if (!req)
685
+ return 0;
686
+
687
+ X_LOCK (reqlock);
688
+ --nreqs;
689
+ X_UNLOCK (reqlock);
690
+
691
+ if (ecb_expect_false (req->type == EIO_GROUP && req->size))
692
+ {
693
+ req->int1 = 1; /* mark request as delayed */
694
+ continue;
695
+ }
696
+ else
697
+ {
698
+ int res = ETP_FINISH (req);
699
+ if (ecb_expect_false (res))
700
+ return res;
701
+ }
702
+
703
+ if (ecb_expect_false (maxreqs && !--maxreqs))
704
+ break;
705
+
706
+ if (maxtime)
707
+ {
708
+ gettimeofday (&tv_now, 0);
709
+
710
+ if (tvdiff (&tv_start, &tv_now) >= maxtime)
711
+ break;
712
+ }
713
+ }
714
+
715
+ errno = EAGAIN;
716
+ return -1;
717
+ }
718
+
719
+ static void
720
+ etp_cancel (ETP_REQ *req)
721
+ {
722
+ req->cancelled = 1;
723
+
724
+ eio_grp_cancel (req);
725
+ }
726
+
727
+ static void
728
+ etp_submit (ETP_REQ *req)
729
+ {
730
+ req->pri -= ETP_PRI_MIN;
731
+
732
+ if (ecb_expect_false (req->pri < ETP_PRI_MIN - ETP_PRI_MIN)) req->pri = ETP_PRI_MIN - ETP_PRI_MIN;
733
+ if (ecb_expect_false (req->pri > ETP_PRI_MAX - ETP_PRI_MIN)) req->pri = ETP_PRI_MAX - ETP_PRI_MIN;
734
+
735
+ if (ecb_expect_false (req->type == EIO_GROUP))
736
+ {
737
+ /* I hope this is worth it :/ */
738
+ X_LOCK (reqlock);
739
+ ++nreqs;
740
+ X_UNLOCK (reqlock);
741
+
742
+ X_LOCK (reslock);
743
+
744
+ ++npending;
745
+
746
+ if (!reqq_push (&req->channel->res_queue, req) && want_poll_cb)
747
+ want_poll_cb (req->channel);
748
+
749
+ X_UNLOCK (reslock);
750
+ }
751
+ else
752
+ {
753
+ X_LOCK (reqlock);
754
+ ++nreqs;
755
+ ++nready;
756
+ reqq_push (&req_queue, req);
757
+ X_COND_SIGNAL (reqwait);
758
+ X_UNLOCK (reqlock);
759
+
760
+ etp_maybe_start_thread ();
761
+ }
762
+ }
763
+
764
+ static void ecb_cold
765
+ etp_set_max_poll_time (double nseconds)
766
+ {
767
+ if (WORDACCESS_UNSAFE) X_LOCK (reslock);
768
+ max_poll_time = nseconds * EIO_TICKS;
769
+ if (WORDACCESS_UNSAFE) X_UNLOCK (reslock);
770
+ }
771
+
772
+ static void ecb_cold
773
+ etp_set_max_poll_reqs (unsigned int maxreqs)
774
+ {
775
+ if (WORDACCESS_UNSAFE) X_LOCK (reslock);
776
+ max_poll_reqs = maxreqs;
777
+ if (WORDACCESS_UNSAFE) X_UNLOCK (reslock);
778
+ }
779
+
780
+ static void ecb_cold
781
+ etp_set_max_idle (unsigned int nthreads)
782
+ {
783
+ if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
784
+ max_idle = nthreads;
785
+ if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
786
+ }
787
+
788
+ static void ecb_cold
789
+ etp_set_idle_timeout (unsigned int seconds)
790
+ {
791
+ if (WORDACCESS_UNSAFE) X_LOCK (reqlock);
792
+ idle_timeout = seconds;
793
+ if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock);
794
+ }
795
+
796
+ static void ecb_cold
797
+ etp_set_min_parallel (unsigned int nthreads)
798
+ {
799
+ if (wanted < nthreads)
800
+ wanted = nthreads;
801
+ }
802
+
803
+ static void ecb_cold
804
+ etp_set_max_parallel (unsigned int nthreads)
805
+ {
806
+ if (wanted > nthreads)
807
+ wanted = nthreads;
808
+
809
+ while (started > wanted)
810
+ etp_end_thread ();
811
+ }
812
+
813
+ /*****************************************************************************/
814
+
815
+ static void
816
+ grp_try_feed (eio_req *grp)
817
+ {
818
+ while (grp->size < grp->int2 && !EIO_CANCELLED (grp))
819
+ {
820
+ grp->flags &= ~EIO_FLAG_GROUPADD;
821
+
822
+ EIO_FEED (grp);
823
+
824
+ /* stop if no progress has been made */
825
+ if (!(grp->flags & EIO_FLAG_GROUPADD))
826
+ {
827
+ grp->feed = 0;
828
+ break;
829
+ }
830
+ }
831
+ }
832
+
833
+ static int
834
+ grp_dec (eio_req *grp)
835
+ {
836
+ --grp->size;
837
+
838
+ /* call feeder, if applicable */
839
+ grp_try_feed (grp);
840
+
841
+ /* finish, if done */
842
+ if (!grp->size && grp->int1)
843
+ return eio_finish (grp);
844
+ else
845
+ return 0;
846
+ }
847
+
848
+ static void
849
+ eio_destroy (eio_req *req)
850
+ {
851
+ if ((req)->flags & EIO_FLAG_PTR1_FREE) free (req->ptr1);
852
+ if ((req)->flags & EIO_FLAG_PTR2_FREE) free (req->ptr2);
853
+
854
+ EIO_DESTROY (req);
855
+ }
856
+
857
+ static int
858
+ eio_finish (eio_req *req)
859
+ {
860
+ int res = EIO_FINISH (req);
861
+
862
+ if (req->grp)
863
+ {
864
+ int res2;
865
+ eio_req *grp = req->grp;
866
+
867
+ /* unlink request */
868
+ if (req->grp_next) req->grp_next->grp_prev = req->grp_prev;
869
+ if (req->grp_prev) req->grp_prev->grp_next = req->grp_next;
870
+
871
+ if (grp->grp_first == req)
872
+ grp->grp_first = req->grp_next;
873
+
874
+ res2 = grp_dec (grp);
875
+
876
+ if (!res)
877
+ res = res2;
878
+ }
879
+
880
+ eio_destroy (req);
881
+
882
+ return res;
883
+ }
884
+
885
+ void
886
+ eio_grp_cancel (eio_req *grp)
887
+ {
888
+ for (grp = grp->grp_first; grp; grp = grp->grp_next)
889
+ eio_cancel (grp);
890
+ }
891
+
892
+ void
893
+ eio_cancel (eio_req *req)
894
+ {
895
+ etp_cancel (req);
896
+ }
897
+
898
+ void
899
+ eio_submit (eio_req *req)
900
+ {
901
+ etp_submit (req);
902
+ }
903
+
904
+ unsigned int
905
+ eio_nreqs (void)
906
+ {
907
+ return etp_nreqs ();
908
+ }
909
+
910
+ unsigned int
911
+ eio_nready (void)
912
+ {
913
+ return etp_nready ();
914
+ }
915
+
916
+ unsigned int
917
+ eio_npending (void)
918
+ {
919
+ return etp_npending ();
920
+ }
921
+
922
+ unsigned int ecb_cold
923
+ eio_nthreads (void)
924
+ {
925
+ return etp_nthreads ();
926
+ }
927
+
928
+ void ecb_cold
929
+ eio_set_max_poll_time (double nseconds)
930
+ {
931
+ etp_set_max_poll_time (nseconds);
932
+ }
933
+
934
+ void ecb_cold
935
+ eio_set_max_poll_reqs (unsigned int maxreqs)
936
+ {
937
+ etp_set_max_poll_reqs (maxreqs);
938
+ }
939
+
940
+ void ecb_cold
941
+ eio_set_max_idle (unsigned int nthreads)
942
+ {
943
+ etp_set_max_idle (nthreads);
944
+ }
945
+
946
+ void ecb_cold
947
+ eio_set_idle_timeout (unsigned int seconds)
948
+ {
949
+ etp_set_idle_timeout (seconds);
950
+ }
951
+
952
+ void ecb_cold
953
+ eio_set_min_parallel (unsigned int nthreads)
954
+ {
955
+ etp_set_min_parallel (nthreads);
956
+ }
957
+
958
+ void ecb_cold
959
+ eio_set_max_parallel (unsigned int nthreads)
960
+ {
961
+ etp_set_max_parallel (nthreads);
962
+ }
963
+
964
+ int eio_poll (eio_channel *channel)
965
+ {
966
+ return etp_poll (channel);
967
+ }
968
+
969
+ /*****************************************************************************/
970
+ /* work around various missing functions */
971
+
972
+ #if !HAVE_PREADWRITE
973
+ # undef pread
974
+ # undef pwrite
975
+ # define pread eio__pread
976
+ # define pwrite eio__pwrite
977
+
978
+ eio_ssize_t
979
+ eio__pread (int fd, void *buf, size_t count, off_t offset)
980
+ {
981
+ eio_ssize_t res;
982
+ off_t ooffset;
983
+
984
+ X_LOCK (preadwritelock);
985
+ ooffset = lseek (fd, 0, SEEK_CUR);
986
+ lseek (fd, offset, SEEK_SET);
987
+ res = read (fd, buf, count);
988
+ lseek (fd, ooffset, SEEK_SET);
989
+ X_UNLOCK (preadwritelock);
990
+
991
+ return res;
992
+ }
993
+
994
+ eio_ssize_t
995
+ eio__pwrite (int fd, void *buf, size_t count, off_t offset)
996
+ {
997
+ eio_ssize_t res;
998
+ off_t ooffset;
999
+
1000
+ X_LOCK (preadwritelock);
1001
+ ooffset = lseek (fd, 0, SEEK_CUR);
1002
+ lseek (fd, offset, SEEK_SET);
1003
+ res = write (fd, buf, count);
1004
+ lseek (fd, ooffset, SEEK_SET);
1005
+ X_UNLOCK (preadwritelock);
1006
+
1007
+ return res;
1008
+ }
1009
+ #endif
1010
+
1011
+ #ifndef HAVE_UTIMES
1012
+
1013
+ # undef utimes
1014
+ # define utimes(path,times) eio__utimes (path, times)
1015
+
1016
+ static int
1017
+ eio__utimes (const char *filename, const struct timeval times[2])
1018
+ {
1019
+ if (times)
1020
+ {
1021
+ struct utimbuf buf;
1022
+
1023
+ buf.actime = times[0].tv_sec;
1024
+ buf.modtime = times[1].tv_sec;
1025
+
1026
+ return utime (filename, &buf);
1027
+ }
1028
+ else
1029
+ return utime (filename, 0);
1030
+ }
1031
+
1032
+ #endif
1033
+
1034
+ #ifndef HAVE_FUTIMES
1035
+
1036
+ # undef futimes
1037
+ # define futimes(fd,times) eio__futimes (fd, times)
1038
+
1039
+ static int
1040
+ eio__futimes (int fd, const struct timeval tv[2])
1041
+ {
1042
+ #if defined(__linux) && defined(__NR_utimensat)
1043
+ struct timespec ts[2];
1044
+ ts[0].tv_sec = tv[0].tv_sec, ts[0].tv_nsec = tv[0].tv_usec * 1000;
1045
+ ts[1].tv_sec = tv[1].tv_sec, ts[1].tv_nsec = tv[1].tv_usec * 1000;
1046
+ return syscall(__NR_utimensat, fd, NULL, ts, 0);
1047
+ #else
1048
+ errno = ENOSYS;
1049
+ return -1;
1050
+ #endif
1051
+ }
1052
+
1053
+ #endif
1054
+
1055
+ #if !HAVE_FDATASYNC
1056
+ # undef fdatasync
1057
+ # define fdatasync(fd) fsync (fd)
1058
+ #endif
1059
+
1060
+ static int
1061
+ eio__syncfs (int fd)
1062
+ {
1063
+ int res;
1064
+
1065
+ #if HAVE_SYS_SYNCFS
1066
+ res = (int)syscall (__NR_syncfs, (int)(fd));
1067
+ #else
1068
+ res = -1;
1069
+ errno = ENOSYS;
1070
+ #endif
1071
+
1072
+ if (res < 0 && errno == ENOSYS && fd >= 0)
1073
+ sync ();
1074
+
1075
+ return res;
1076
+ }
1077
+
1078
+ /* sync_file_range always needs emulation */
1079
+ static int
1080
+ eio__sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags)
1081
+ {
1082
+ #if HAVE_SYNC_FILE_RANGE
1083
+ int res;
1084
+
1085
+ if (EIO_SYNC_FILE_RANGE_WAIT_BEFORE != SYNC_FILE_RANGE_WAIT_BEFORE
1086
+ || EIO_SYNC_FILE_RANGE_WRITE != SYNC_FILE_RANGE_WRITE
1087
+ || EIO_SYNC_FILE_RANGE_WAIT_AFTER != SYNC_FILE_RANGE_WAIT_AFTER)
1088
+ {
1089
+ flags = 0
1090
+ | (flags & EIO_SYNC_FILE_RANGE_WAIT_BEFORE ? SYNC_FILE_RANGE_WAIT_BEFORE : 0)
1091
+ | (flags & EIO_SYNC_FILE_RANGE_WRITE ? SYNC_FILE_RANGE_WRITE : 0)
1092
+ | (flags & EIO_SYNC_FILE_RANGE_WAIT_AFTER ? SYNC_FILE_RANGE_WAIT_AFTER : 0);
1093
+ }
1094
+
1095
+ res = sync_file_range (fd, offset, nbytes, flags);
1096
+
1097
+ if (!res || errno != ENOSYS)
1098
+ return res;
1099
+ #endif
1100
+
1101
+ /* even though we could play tricks with the flags, it's better to always
1102
+ * call fdatasync, as that matches the expectation of its users best */
1103
+ return fdatasync (fd);
1104
+ }
1105
+
1106
+ static int
1107
+ eio__fallocate (int fd, int mode, off_t offset, size_t len)
1108
+ {
1109
+ #if HAVE_FALLOCATE
1110
+ return fallocate (fd, mode, offset, len);
1111
+ #else
1112
+ errno = ENOSYS;
1113
+ return -1;
1114
+ #endif
1115
+ }
1116
+
1117
+ #if !HAVE_READAHEAD
1118
+ # undef readahead
1119
+ # define readahead(fd,offset,count) eio__readahead (fd, offset, count, self)
1120
+
1121
+ static eio_ssize_t
1122
+ eio__readahead (int fd, off_t offset, size_t count, etp_worker *self)
1123
+ {
1124
+ size_t todo = count;
1125
+ dBUF;
1126
+
1127
+ while (todo > 0)
1128
+ {
1129
+ size_t len = todo < EIO_BUFSIZE ? todo : EIO_BUFSIZE;
1130
+
1131
+ pread (fd, eio_buf, len, offset);
1132
+ offset += len;
1133
+ todo -= len;
1134
+ }
1135
+
1136
+ FUBd;
1137
+
1138
+ errno = 0;
1139
+ return count;
1140
+ }
1141
+
1142
+ #endif
1143
+
1144
+ /* sendfile always needs emulation */
1145
+ static eio_ssize_t
1146
+ eio__sendfile (int ofd, int ifd, off_t offset, size_t count)
1147
+ {
1148
+ eio_ssize_t written = 0;
1149
+ eio_ssize_t res;
1150
+
1151
+ if (!count)
1152
+ return 0;
1153
+
1154
+ for (;;)
1155
+ {
1156
+ #ifdef __APPLE__
1157
+ # undef HAVE_SENDFILE /* broken, as everything on os x */
1158
+ #endif
1159
+ #if HAVE_SENDFILE
1160
+ # if __linux
1161
+ off_t soffset = offset;
1162
+ res = sendfile (ofd, ifd, &soffset, count);
1163
+
1164
+ # elif __FreeBSD__
1165
+ /*
1166
+ * Of course, the freebsd sendfile is a dire hack with no thoughts
1167
+ * wasted on making it similar to other I/O functions.
1168
+ */
1169
+ off_t sbytes;
1170
+ res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0);
1171
+
1172
+ #if 0 /* according to the manpage, this is correct, but broken behaviour */
1173
+ /* freebsd' sendfile will return 0 on success */
1174
+ /* freebsd 8 documents it as only setting *sbytes on EINTR and EAGAIN, but */
1175
+ /* not on e.g. EIO or EPIPE - sounds broken */
1176
+ if ((res < 0 && (errno == EAGAIN || errno == EINTR) && sbytes) || res == 0)
1177
+ res = sbytes;
1178
+ #endif
1179
+
1180
+ /* according to source inspection, this is correct, and useful behaviour */
1181
+ if (sbytes)
1182
+ res = sbytes;
1183
+
1184
+ # elif defined (__APPLE__)
1185
+ off_t sbytes = count;
1186
+ res = sendfile (ifd, ofd, offset, &sbytes, 0, 0);
1187
+
1188
+ /* according to the manpage, sbytes is always valid */
1189
+ if (sbytes)
1190
+ res = sbytes;
1191
+
1192
+ # elif __hpux
1193
+ res = sendfile (ofd, ifd, offset, count, 0, 0);
1194
+
1195
+ # elif __solaris
1196
+ struct sendfilevec vec;
1197
+ size_t sbytes;
1198
+
1199
+ vec.sfv_fd = ifd;
1200
+ vec.sfv_flag = 0;
1201
+ vec.sfv_off = offset;
1202
+ vec.sfv_len = count;
1203
+
1204
+ res = sendfilev (ofd, &vec, 1, &sbytes);
1205
+
1206
+ if (res < 0 && sbytes)
1207
+ res = sbytes;
1208
+
1209
+ # endif
1210
+
1211
+ #elif defined (_WIN32) && 0
1212
+ /* does not work, just for documentation of what would need to be done */
1213
+ /* actually, cannot be done like this, as TransmitFile changes the file offset, */
1214
+ /* libeio guarantees that the file offset does not change, and windows */
1215
+ /* has no way to get an independent handle to the same file description */
1216
+ HANDLE h = TO_SOCKET (ifd);
1217
+ SetFilePointer (h, offset, 0, FILE_BEGIN);
1218
+ res = TransmitFile (TO_SOCKET (ofd), h, count, 0, 0, 0, 0);
1219
+
1220
+ #else
1221
+ res = -1;
1222
+ errno = ENOSYS;
1223
+ #endif
1224
+
1225
+ /* we assume sendfile can copy at least 128mb in one go */
1226
+ if (res <= 128 * 1024 * 1024)
1227
+ {
1228
+ if (res > 0)
1229
+ written += res;
1230
+
1231
+ if (written)
1232
+ return written;
1233
+
1234
+ break;
1235
+ }
1236
+ else
1237
+ {
1238
+ /* if we requested more, then probably the kernel was lazy */
1239
+ written += res;
1240
+ offset += res;
1241
+ count -= res;
1242
+
1243
+ if (!count)
1244
+ return written;
1245
+ }
1246
+ }
1247
+
1248
+ if (res < 0
1249
+ && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK
1250
+ /* BSDs */
1251
+ #ifdef ENOTSUP /* sigh, if the steenking pile called openbsd would only try to at least compile posix code... */
1252
+ || errno == ENOTSUP
1253
+ #endif
1254
+ #ifdef EOPNOTSUPP /* windows */
1255
+ || errno == EOPNOTSUPP /* BSDs */
1256
+ #endif
1257
+ #if __solaris
1258
+ || errno == EAFNOSUPPORT || errno == EPROTOTYPE
1259
+ #endif
1260
+ )
1261
+ )
1262
+ {
1263
+ /* emulate sendfile. this is a major pain in the ass */
1264
+ dBUF;
1265
+
1266
+ res = 0;
1267
+
1268
+ while (count)
1269
+ {
1270
+ eio_ssize_t cnt;
1271
+
1272
+ cnt = pread (ifd, eio_buf, count > EIO_BUFSIZE ? EIO_BUFSIZE : count, offset);
1273
+
1274
+ if (cnt <= 0)
1275
+ {
1276
+ if (cnt && !res) res = -1;
1277
+ break;
1278
+ }
1279
+
1280
+ cnt = write (ofd, eio_buf, cnt);
1281
+
1282
+ if (cnt <= 0)
1283
+ {
1284
+ if (cnt && !res) res = -1;
1285
+ break;
1286
+ }
1287
+
1288
+ offset += cnt;
1289
+ res += cnt;
1290
+ count -= cnt;
1291
+ }
1292
+
1293
+ FUBd;
1294
+ }
1295
+
1296
+ return res;
1297
+ }
1298
+
1299
+ #ifdef PAGESIZE
1300
+ # define eio_pagesize() PAGESIZE
1301
+ #else
1302
+ static intptr_t
1303
+ eio_pagesize (void)
1304
+ {
1305
+ static intptr_t page;
1306
+
1307
+ if (!page)
1308
+ page = sysconf (_SC_PAGESIZE);
1309
+
1310
+ return page;
1311
+ }
1312
+ #endif
1313
+
1314
+ static void
1315
+ eio_page_align (void **addr, size_t *length)
1316
+ {
1317
+ intptr_t mask = eio_pagesize () - 1;
1318
+
1319
+ /* round down addr */
1320
+ intptr_t adj = mask & (intptr_t)*addr;
1321
+
1322
+ *addr = (void *)((intptr_t)*addr - adj);
1323
+ *length += adj;
1324
+
1325
+ /* round up length */
1326
+ *length = (*length + mask) & ~mask;
1327
+ }
1328
+
1329
+ #if !_POSIX_MEMLOCK
1330
+ # define eio__mlockall(a) EIO_ENOSYS ()
1331
+ #else
1332
+
1333
+ static int
1334
+ eio__mlockall (int flags)
1335
+ {
1336
+ #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7
1337
+ extern int mallopt (int, int);
1338
+ mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */
1339
+ #endif
1340
+
1341
+ if (EIO_MCL_CURRENT != MCL_CURRENT
1342
+ || EIO_MCL_FUTURE != MCL_FUTURE)
1343
+ {
1344
+ flags = 0
1345
+ | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0)
1346
+ | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0);
1347
+ }
1348
+
1349
+ return mlockall (flags);
1350
+ }
1351
+ #endif
1352
+
1353
+ #if !_POSIX_MEMLOCK_RANGE
1354
+ # define eio__mlock(a,b) EIO_ENOSYS ()
1355
+ #else
1356
+
1357
+ static int
1358
+ eio__mlock (void *addr, size_t length)
1359
+ {
1360
+ eio_page_align (&addr, &length);
1361
+
1362
+ return mlock (addr, length);
1363
+ }
1364
+
1365
+ #endif
1366
+
1367
+ #if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO)
1368
+ # define eio__msync(a,b,c) EIO_ENOSYS ()
1369
+ #else
1370
+
1371
+ static int
1372
+ eio__msync (void *mem, size_t len, int flags)
1373
+ {
1374
+ eio_page_align (&mem, &len);
1375
+
1376
+ if (EIO_MS_ASYNC != MS_SYNC
1377
+ || EIO_MS_INVALIDATE != MS_INVALIDATE
1378
+ || EIO_MS_SYNC != MS_SYNC)
1379
+ {
1380
+ flags = 0
1381
+ | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0)
1382
+ | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0)
1383
+ | (flags & EIO_MS_SYNC ? MS_SYNC : 0);
1384
+ }
1385
+
1386
+ return msync (mem, len, flags);
1387
+ }
1388
+
1389
+ #endif
1390
+
1391
+ static int
1392
+ eio__mtouch (eio_req *req)
1393
+ {
1394
+ void *mem = req->ptr2;
1395
+ size_t len = req->size;
1396
+ int flags = req->int1;
1397
+
1398
+ eio_page_align (&mem, &len);
1399
+
1400
+ {
1401
+ intptr_t addr = (intptr_t)mem;
1402
+ intptr_t end = addr + len;
1403
+ intptr_t page = eio_pagesize ();
1404
+
1405
+ if (addr < end)
1406
+ if (flags & EIO_MT_MODIFY) /* modify */
1407
+ do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req));
1408
+ else
1409
+ do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req));
1410
+ }
1411
+
1412
+ return 0;
1413
+ }
1414
+
1415
+ /*****************************************************************************/
1416
+ /* requests implemented outside eio_execute, because they are so large */
1417
+
1418
+ static void
1419
+ eio__realpath (eio_req *req, etp_worker *self)
1420
+ {
1421
+ char *rel = req->ptr1;
1422
+ char *res;
1423
+ char *tmp1, *tmp2;
1424
+ #if SYMLOOP_MAX > 32
1425
+ int symlinks = SYMLOOP_MAX;
1426
+ #else
1427
+ int symlinks = 32;
1428
+ #endif
1429
+
1430
+ req->result = -1;
1431
+
1432
+ errno = EINVAL;
1433
+ if (!rel)
1434
+ return;
1435
+
1436
+ errno = ENOENT;
1437
+ if (!*rel)
1438
+ return;
1439
+
1440
+ if (!req->ptr2)
1441
+ {
1442
+ X_LOCK (wrklock);
1443
+ req->flags |= EIO_FLAG_PTR2_FREE;
1444
+ X_UNLOCK (wrklock);
1445
+ req->ptr2 = malloc (PATH_MAX * 3);
1446
+
1447
+ errno = ENOMEM;
1448
+ if (!req->ptr2)
1449
+ return;
1450
+ }
1451
+
1452
+ res = req->ptr2;
1453
+ tmp1 = res + PATH_MAX;
1454
+ tmp2 = tmp1 + PATH_MAX;
1455
+
1456
+ #if 0 /* disabled, the musl way to do things is just too racy */
1457
+ #if __linux && defined(O_NONBLOCK) && defined(O_NOATIME)
1458
+ /* on linux we may be able to ask the kernel */
1459
+ {
1460
+ int fd = open (rel, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOATIME);
1461
+
1462
+ if (fd >= 0)
1463
+ {
1464
+ sprintf (tmp1, "/proc/self/fd/%d", fd);
1465
+ req->result = readlink (tmp1, res, PATH_MAX);
1466
+ close (fd);
1467
+
1468
+ /* here we should probably stat the open file and the disk file, to make sure they still match */
1469
+
1470
+ if (req->result > 0)
1471
+ goto done;
1472
+ }
1473
+ else if (errno == ELOOP || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EIO)
1474
+ return;
1475
+ }
1476
+ #endif
1477
+ #endif
1478
+
1479
+ if (*rel != '/')
1480
+ {
1481
+ if (!getcwd (res, PATH_MAX))
1482
+ return;
1483
+
1484
+ if (res [1]) /* only use if not / */
1485
+ res += strlen (res);
1486
+ }
1487
+
1488
+ while (*rel)
1489
+ {
1490
+ eio_ssize_t len, linklen;
1491
+ char *beg = rel;
1492
+
1493
+ while (*rel && *rel != '/')
1494
+ ++rel;
1495
+
1496
+ len = rel - beg;
1497
+
1498
+ if (!len) /* skip slashes */
1499
+ {
1500
+ ++rel;
1501
+ continue;
1502
+ }
1503
+
1504
+ if (beg [0] == '.')
1505
+ {
1506
+ if (len == 1)
1507
+ continue; /* . - nop */
1508
+
1509
+ if (beg [1] == '.' && len == 2)
1510
+ {
1511
+ /* .. - back up one component, if possible */
1512
+
1513
+ while (res != req->ptr2)
1514
+ if (*--res == '/')
1515
+ break;
1516
+
1517
+ continue;
1518
+ }
1519
+ }
1520
+
1521
+ errno = ENAMETOOLONG;
1522
+ if (res + 1 + len + 1 >= tmp1)
1523
+ return;
1524
+
1525
+ /* copy one component */
1526
+ *res = '/';
1527
+ memcpy (res + 1, beg, len);
1528
+
1529
+ /* zero-terminate, for readlink */
1530
+ res [len + 1] = 0;
1531
+
1532
+ /* now check if it's a symlink */
1533
+ linklen = readlink (req->ptr2, tmp1, PATH_MAX);
1534
+
1535
+ if (linklen < 0)
1536
+ {
1537
+ if (errno != EINVAL)
1538
+ return;
1539
+
1540
+ /* it's a normal directory. hopefully */
1541
+ res += len + 1;
1542
+ }
1543
+ else
1544
+ {
1545
+ /* yay, it was a symlink - build new path in tmp2 */
1546
+ int rellen = strlen (rel);
1547
+
1548
+ errno = ENAMETOOLONG;
1549
+ if (linklen + 1 + rellen >= PATH_MAX)
1550
+ return;
1551
+
1552
+ errno = ELOOP;
1553
+ if (!--symlinks)
1554
+ return;
1555
+
1556
+ if (*tmp1 == '/')
1557
+ res = req->ptr2; /* symlink resolves to an absolute path */
1558
+
1559
+ /* we need to be careful, as rel might point into tmp2 already */
1560
+ memmove (tmp2 + linklen + 1, rel, rellen + 1);
1561
+ tmp2 [linklen] = '/';
1562
+ memcpy (tmp2, tmp1, linklen);
1563
+
1564
+ rel = tmp2;
1565
+ }
1566
+ }
1567
+
1568
+ /* special case for the lone root path */
1569
+ if (res == req->ptr2)
1570
+ *res++ = '/';
1571
+
1572
+ req->result = res - (char *)req->ptr2;
1573
+
1574
+ done:
1575
+ req->ptr2 = realloc (req->ptr2, req->result); /* trade time for space savings */
1576
+ }
1577
+
1578
+ static signed char
1579
+ eio_dent_cmp (const eio_dirent *a, const eio_dirent *b)
1580
+ {
1581
+ return a->score - b->score ? a->score - b->score /* works because our signed char is always 0..100 */
1582
+ : a->inode < b->inode ? -1
1583
+ : a->inode > b->inode ? 1
1584
+ : 0;
1585
+ }
1586
+
1587
+ #define EIO_DENT_CMP(i,op,j) eio_dent_cmp (&i, &j) op 0
1588
+
1589
+ #define EIO_SORT_CUTOFF 30 /* quite high, but performs well on many filesystems */
1590
+ #define EIO_SORT_FAST 60 /* when to only use insertion sort */
1591
+
1592
+ static void
1593
+ eio_dent_radix_sort (eio_dirent *dents, int size, signed char score_bits, eio_ino_t inode_bits)
1594
+ {
1595
+ unsigned char bits [9 + sizeof (eio_ino_t) * 8];
1596
+ unsigned char *bit = bits;
1597
+
1598
+ assert (CHAR_BIT == 8);
1599
+ assert (sizeof (eio_dirent) * 8 < 256);
1600
+ assert (offsetof (eio_dirent, inode)); /* we use bit #0 as sentinel */
1601
+ assert (offsetof (eio_dirent, score)); /* we use bit #0 as sentinel */
1602
+
1603
+ if (size <= EIO_SORT_FAST)
1604
+ return;
1605
+
1606
+ /* first prepare an array of bits to test in our radix sort */
1607
+ /* try to take endianness into account, as well as differences in eio_ino_t sizes */
1608
+ /* inode_bits must contain all inodes ORed together */
1609
+ /* which is used to skip bits that are 0 everywhere, which is very common */
1610
+ {
1611
+ eio_ino_t endianness;
1612
+ int i, j;
1613
+
1614
+ /* we store the byte offset of byte n into byte n of "endianness" */
1615
+ for (i = 0; i < sizeof (eio_ino_t); ++i)
1616
+ ((unsigned char *)&endianness)[i] = i;
1617
+
1618
+ *bit++ = 0;
1619
+
1620
+ for (i = 0; i < sizeof (eio_ino_t); ++i)
1621
+ {
1622
+ /* shifting off the byte offsets out of "endianness" */
1623
+ int offs = (offsetof (eio_dirent, inode) + (endianness & 0xff)) * 8;
1624
+ endianness >>= 8;
1625
+
1626
+ for (j = 0; j < 8; ++j)
1627
+ if (inode_bits & (((eio_ino_t)1) << (i * 8 + j)))
1628
+ *bit++ = offs + j;
1629
+ }
1630
+
1631
+ for (j = 0; j < 8; ++j)
1632
+ if (score_bits & (1 << j))
1633
+ *bit++ = offsetof (eio_dirent, score) * 8 + j;
1634
+ }
1635
+
1636
+ /* now actually do the sorting (a variant of MSD radix sort) */
1637
+ {
1638
+ eio_dirent *base_stk [9 + sizeof (eio_ino_t) * 8], *base;
1639
+ eio_dirent *end_stk [9 + sizeof (eio_ino_t) * 8], *end;
1640
+ unsigned char *bit_stk [9 + sizeof (eio_ino_t) * 8];
1641
+ int stk_idx = 0;
1642
+
1643
+ base_stk [stk_idx] = dents;
1644
+ end_stk [stk_idx] = dents + size;
1645
+ bit_stk [stk_idx] = bit - 1;
1646
+
1647
+ do
1648
+ {
1649
+ base = base_stk [stk_idx];
1650
+ end = end_stk [stk_idx];
1651
+ bit = bit_stk [stk_idx];
1652
+
1653
+ for (;;)
1654
+ {
1655
+ unsigned char O = *bit >> 3;
1656
+ unsigned char M = 1 << (*bit & 7);
1657
+
1658
+ eio_dirent *a = base;
1659
+ eio_dirent *b = end;
1660
+
1661
+ if (b - a < EIO_SORT_CUTOFF)
1662
+ break;
1663
+
1664
+ /* now bit-partition the array on the bit */
1665
+ /* this ugly asymmetric loop seems to perform much better than typical */
1666
+ /* partition algos found in the literature */
1667
+ do
1668
+ if (!(((unsigned char *)a)[O] & M))
1669
+ ++a;
1670
+ else if (!(((unsigned char *)--b)[O] & M))
1671
+ {
1672
+ eio_dirent tmp = *a; *a = *b; *b = tmp;
1673
+ ++a;
1674
+ }
1675
+ while (b > a);
1676
+
1677
+ /* next bit, or stop, if no bits left in this path */
1678
+ if (!*--bit)
1679
+ break;
1680
+
1681
+ base_stk [stk_idx] = a;
1682
+ end_stk [stk_idx] = end;
1683
+ bit_stk [stk_idx] = bit;
1684
+ ++stk_idx;
1685
+
1686
+ end = a;
1687
+ }
1688
+ }
1689
+ while (stk_idx--);
1690
+ }
1691
+ }
1692
+
1693
+ static void
1694
+ eio_dent_insertion_sort (eio_dirent *dents, int size)
1695
+ {
1696
+ /* first move the smallest element to the front, to act as a sentinel */
1697
+ {
1698
+ int i;
1699
+ eio_dirent *min = dents;
1700
+
1701
+ /* the radix pre-pass ensures that the minimum element is in the first EIO_SORT_CUTOFF + 1 elements */
1702
+ for (i = size > EIO_SORT_FAST ? EIO_SORT_CUTOFF + 1 : size; --i; )
1703
+ if (EIO_DENT_CMP (dents [i], <, *min))
1704
+ min = &dents [i];
1705
+
1706
+ /* swap elements 0 and j (minimum) */
1707
+ {
1708
+ eio_dirent tmp = *dents; *dents = *min; *min = tmp;
1709
+ }
1710
+ }
1711
+
1712
+ /* then do standard insertion sort, assuming that all elements are >= dents [0] */
1713
+ {
1714
+ eio_dirent *i, *j;
1715
+
1716
+ for (i = dents + 1; i < dents + size; ++i)
1717
+ {
1718
+ eio_dirent value = *i;
1719
+
1720
+ for (j = i - 1; EIO_DENT_CMP (*j, >, value); --j)
1721
+ j [1] = j [0];
1722
+
1723
+ j [1] = value;
1724
+ }
1725
+ }
1726
+ }
1727
+
1728
+ static void
1729
+ eio_dent_sort (eio_dirent *dents, int size, signed char score_bits, eio_ino_t inode_bits)
1730
+ {
1731
+ if (size <= 1)
1732
+ return; /* our insertion sort relies on size > 0 */
1733
+
1734
+ /* first we use a radix sort, but only for dirs >= EIO_SORT_FAST */
1735
+ /* and stop sorting when the partitions are <= EIO_SORT_CUTOFF */
1736
+ eio_dent_radix_sort (dents, size, score_bits, inode_bits);
1737
+
1738
+ /* use an insertion sort at the end, or for small arrays, */
1739
+ /* as insertion sort is more efficient for small partitions */
1740
+ eio_dent_insertion_sort (dents, size);
1741
+ }
1742
+
1743
+ /* read a full directory */
1744
+ static void
1745
+ eio__scandir (eio_req *req, etp_worker *self)
1746
+ {
1747
+ char *name, *names;
1748
+ int namesalloc = 4096 - sizeof (void *) * 4;
1749
+ int namesoffs = 0;
1750
+ int flags = req->int1;
1751
+ eio_dirent *dents = 0;
1752
+ int dentalloc = 128;
1753
+ int dentoffs = 0;
1754
+ eio_ino_t inode_bits = 0;
1755
+ #ifdef _WIN32
1756
+ HANDLE dirp;
1757
+ WIN32_FIND_DATA entp;
1758
+ #else
1759
+ DIR *dirp;
1760
+ EIO_STRUCT_DIRENT *entp;
1761
+ #endif
1762
+
1763
+ req->result = -1;
1764
+
1765
+ if (!(flags & EIO_READDIR_DENTS))
1766
+ flags &= ~(EIO_READDIR_DIRS_FIRST | EIO_READDIR_STAT_ORDER);
1767
+
1768
+ #ifdef _WIN32
1769
+ {
1770
+ int len = strlen ((const char *)req->ptr1);
1771
+ char *path = malloc (MAX_PATH);
1772
+ const char *fmt;
1773
+
1774
+ if (!len)
1775
+ fmt = "./*";
1776
+ else if (((const char *)req->ptr1)[len - 1] == '/' || ((const char *)req->ptr1)[len - 1] == '\\')
1777
+ fmt = "%s*";
1778
+ else
1779
+ fmt = "%s/*";
1780
+
1781
+ _snprintf (path, MAX_PATH, fmt, (const char *)req->ptr1);
1782
+ dirp = FindFirstFile (path, &entp);
1783
+ free (path);
1784
+
1785
+ if (dirp == INVALID_HANDLE_VALUE)
1786
+ {
1787
+ dirp = 0;
1788
+
1789
+ /* should steal _dosmaperr */
1790
+ switch (GetLastError ())
1791
+ {
1792
+ case ERROR_FILE_NOT_FOUND:
1793
+ req->result = 0;
1794
+ break;
1795
+
1796
+ case ERROR_INVALID_NAME:
1797
+ case ERROR_PATH_NOT_FOUND:
1798
+ case ERROR_NO_MORE_FILES:
1799
+ errno = ENOENT;
1800
+ break;
1801
+
1802
+ case ERROR_NOT_ENOUGH_MEMORY:
1803
+ errno = ENOMEM;
1804
+ break;
1805
+
1806
+ default:
1807
+ errno = EINVAL;
1808
+ break;
1809
+ }
1810
+ }
1811
+ }
1812
+ #else
1813
+ dirp = opendir (req->ptr1);
1814
+ #endif
1815
+
1816
+ if (req->flags & EIO_FLAG_PTR1_FREE)
1817
+ free (req->ptr1);
1818
+
1819
+ req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE;
1820
+ req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0;
1821
+ req->ptr2 = names = malloc (namesalloc);
1822
+
1823
+ if (dirp && names && (!flags || dents))
1824
+ for (;;)
1825
+ {
1826
+ int done;
1827
+
1828
+ #ifdef _WIN32
1829
+ done = !dirp;
1830
+ #else
1831
+ errno = 0;
1832
+ entp = readdir (dirp);
1833
+ done = !entp;
1834
+ #endif
1835
+
1836
+ if (done)
1837
+ {
1838
+ #ifndef _WIN32
1839
+ int old_errno = errno;
1840
+ closedir (dirp);
1841
+ errno = old_errno;
1842
+
1843
+ if (errno)
1844
+ break;
1845
+ #endif
1846
+
1847
+ /* sort etc. */
1848
+ req->int1 = flags;
1849
+ req->result = dentoffs;
1850
+
1851
+ if (flags & EIO_READDIR_STAT_ORDER)
1852
+ eio_dent_sort (dents, dentoffs, flags & EIO_READDIR_DIRS_FIRST ? 7 : 0, inode_bits);
1853
+ else if (flags & EIO_READDIR_DIRS_FIRST)
1854
+ if (flags & EIO_READDIR_FOUND_UNKNOWN)
1855
+ eio_dent_sort (dents, dentoffs, 7, inode_bits); /* sort by score and inode */
1856
+ else
1857
+ {
1858
+ /* in this case, all is known, and we just put dirs first and sort them */
1859
+ eio_dirent *oth = dents + dentoffs;
1860
+ eio_dirent *dir = dents;
1861
+
1862
+ /* now partition dirs to the front, and non-dirs to the back */
1863
+ /* by walking from both sides and swapping if necessary */
1864
+ while (oth > dir)
1865
+ {
1866
+ if (dir->type == EIO_DT_DIR)
1867
+ ++dir;
1868
+ else if ((--oth)->type == EIO_DT_DIR)
1869
+ {
1870
+ eio_dirent tmp = *dir; *dir = *oth; *oth = tmp;
1871
+
1872
+ ++dir;
1873
+ }
1874
+ }
1875
+
1876
+ /* now sort the dirs only (dirs all have the same score) */
1877
+ eio_dent_sort (dents, dir - dents, 0, inode_bits);
1878
+ }
1879
+
1880
+ break;
1881
+ }
1882
+
1883
+ /* now add the entry to our list(s) */
1884
+ name = D_NAME (entp);
1885
+
1886
+ /* skip . and .. entries */
1887
+ if (name [0] != '.' || (name [1] && (name [1] != '.' || name [2])))
1888
+ {
1889
+ int len = D_NAMLEN (entp) + 1;
1890
+
1891
+ while (ecb_expect_false (namesoffs + len > namesalloc))
1892
+ {
1893
+ namesalloc *= 2;
1894
+ req->ptr2 = names = realloc (names, namesalloc);
1895
+
1896
+ if (!names)
1897
+ break;
1898
+ }
1899
+
1900
+ memcpy (names + namesoffs, name, len);
1901
+
1902
+ if (dents)
1903
+ {
1904
+ struct eio_dirent *ent;
1905
+
1906
+ if (ecb_expect_false (dentoffs == dentalloc))
1907
+ {
1908
+ dentalloc *= 2;
1909
+ req->ptr1 = dents = realloc (dents, dentalloc * sizeof (eio_dirent));
1910
+
1911
+ if (!dents)
1912
+ break;
1913
+ }
1914
+
1915
+ ent = dents + dentoffs;
1916
+
1917
+ ent->nameofs = namesoffs; /* rather dirtily we store the offset in the pointer */
1918
+ ent->namelen = len - 1;
1919
+ ent->inode = D_INO (entp);
1920
+
1921
+ inode_bits |= ent->inode;
1922
+
1923
+ switch (D_TYPE (entp))
1924
+ {
1925
+ default:
1926
+ ent->type = EIO_DT_UNKNOWN;
1927
+ flags |= EIO_READDIR_FOUND_UNKNOWN;
1928
+ break;
1929
+
1930
+ #ifdef DT_FIFO
1931
+ case DT_FIFO: ent->type = EIO_DT_FIFO; break;
1932
+ #endif
1933
+ #ifdef DT_CHR
1934
+ case DT_CHR: ent->type = EIO_DT_CHR; break;
1935
+ #endif
1936
+ #ifdef DT_MPC
1937
+ case DT_MPC: ent->type = EIO_DT_MPC; break;
1938
+ #endif
1939
+ #ifdef DT_DIR
1940
+ case DT_DIR: ent->type = EIO_DT_DIR; break;
1941
+ #endif
1942
+ #ifdef DT_NAM
1943
+ case DT_NAM: ent->type = EIO_DT_NAM; break;
1944
+ #endif
1945
+ #ifdef DT_BLK
1946
+ case DT_BLK: ent->type = EIO_DT_BLK; break;
1947
+ #endif
1948
+ #ifdef DT_MPB
1949
+ case DT_MPB: ent->type = EIO_DT_MPB; break;
1950
+ #endif
1951
+ #ifdef DT_REG
1952
+ case DT_REG: ent->type = EIO_DT_REG; break;
1953
+ #endif
1954
+ #ifdef DT_NWK
1955
+ case DT_NWK: ent->type = EIO_DT_NWK; break;
1956
+ #endif
1957
+ #ifdef DT_CMP
1958
+ case DT_CMP: ent->type = EIO_DT_CMP; break;
1959
+ #endif
1960
+ #ifdef DT_LNK
1961
+ case DT_LNK: ent->type = EIO_DT_LNK; break;
1962
+ #endif
1963
+ #ifdef DT_SOCK
1964
+ case DT_SOCK: ent->type = EIO_DT_SOCK; break;
1965
+ #endif
1966
+ #ifdef DT_DOOR
1967
+ case DT_DOOR: ent->type = EIO_DT_DOOR; break;
1968
+ #endif
1969
+ #ifdef DT_WHT
1970
+ case DT_WHT: ent->type = EIO_DT_WHT; break;
1971
+ #endif
1972
+ }
1973
+
1974
+ ent->score = 7;
1975
+
1976
+ if (flags & EIO_READDIR_DIRS_FIRST)
1977
+ {
1978
+ if (ent->type == EIO_DT_UNKNOWN)
1979
+ {
1980
+ if (*name == '.') /* leading dots are likely directories, and, in any case, rare */
1981
+ ent->score = 1;
1982
+ else if (!strchr (name, '.')) /* absense of dots indicate likely dirs */
1983
+ ent->score = len <= 2 ? 4 - len : len <= 4 ? 4 : len <= 7 ? 5 : 6; /* shorter == more likely dir, but avoid too many classes */
1984
+ }
1985
+ else if (ent->type == EIO_DT_DIR)
1986
+ ent->score = 0;
1987
+ }
1988
+ }
1989
+
1990
+ namesoffs += len;
1991
+ ++dentoffs;
1992
+ }
1993
+
1994
+ if (EIO_CANCELLED (req))
1995
+ {
1996
+ errno = ECANCELED;
1997
+ break;
1998
+ }
1999
+
2000
+ #ifdef _WIN32
2001
+ if (!FindNextFile (dirp, &entp))
2002
+ {
2003
+ FindClose (dirp);
2004
+ dirp = 0;
2005
+ }
2006
+ #endif
2007
+ }
2008
+ }
2009
+
2010
+ /*****************************************************************************/
2011
+
2012
+ #define ALLOC(len) \
2013
+ if (!req->ptr2) \
2014
+ { \
2015
+ X_LOCK (wrklock); \
2016
+ req->flags |= EIO_FLAG_PTR2_FREE; \
2017
+ X_UNLOCK (wrklock); \
2018
+ req->ptr2 = malloc (len); \
2019
+ if (!req->ptr2) \
2020
+ { \
2021
+ errno = ENOMEM; \
2022
+ req->result = -1; \
2023
+ break; \
2024
+ } \
2025
+ }
2026
+
2027
+ X_THREAD_PROC (etp_proc)
2028
+ {
2029
+ ETP_REQ *req;
2030
+ struct timespec ts;
2031
+ etp_worker *self = (etp_worker *)thr_arg;
2032
+
2033
+ #if HAVE_PRCTL_SET_NAME
2034
+ prctl (PR_SET_NAME, (unsigned long)"eio_thread", 0, 0, 0);
2035
+ #endif
2036
+
2037
+ /* try to distribute timeouts somewhat evenly */
2038
+ ts.tv_nsec = ((unsigned long)self & 1023UL) * (1000000000UL / 1024UL);
2039
+
2040
+ for (;;)
2041
+ {
2042
+ ts.tv_sec = 0;
2043
+
2044
+ X_LOCK (reqlock);
2045
+
2046
+ for (;;)
2047
+ {
2048
+ self->req = req = reqq_shift (&req_queue);
2049
+
2050
+ if (req)
2051
+ break;
2052
+
2053
+ if (ts.tv_sec == 1) /* no request, but timeout detected, let's quit */
2054
+ {
2055
+ X_UNLOCK (reqlock);
2056
+ X_LOCK (wrklock);
2057
+ --started;
2058
+ X_UNLOCK (wrklock);
2059
+ goto quit;
2060
+ }
2061
+
2062
+ ++idle;
2063
+
2064
+ if (idle <= max_idle)
2065
+ /* we are allowed to idle, so do so without any timeout */
2066
+ X_COND_WAIT (reqwait, reqlock);
2067
+ else
2068
+ {
2069
+ /* initialise timeout once */
2070
+ if (!ts.tv_sec)
2071
+ ts.tv_sec = time (0) + idle_timeout;
2072
+
2073
+ if (X_COND_TIMEDWAIT (reqwait, reqlock, ts) == ETIMEDOUT)
2074
+ ts.tv_sec = 1; /* assuming this is not a value computed above.,.. */
2075
+ }
2076
+
2077
+ --idle;
2078
+ }
2079
+
2080
+ --nready;
2081
+
2082
+ X_UNLOCK (reqlock);
2083
+
2084
+ if (req->type < 0)
2085
+ goto quit;
2086
+
2087
+ ETP_EXECUTE (self, req);
2088
+
2089
+ X_LOCK (reslock);
2090
+
2091
+ ++npending;
2092
+
2093
+ if (!reqq_push (&req->channel->res_queue, req) && want_poll_cb)
2094
+ want_poll_cb (req->channel);
2095
+
2096
+ self->req = 0;
2097
+ etp_worker_clear (self);
2098
+
2099
+ X_UNLOCK (reslock);
2100
+ }
2101
+
2102
+ quit:
2103
+ X_LOCK (wrklock);
2104
+ etp_worker_free (self);
2105
+ X_UNLOCK (wrklock);
2106
+
2107
+ return 0;
2108
+ }
2109
+
2110
+ /*****************************************************************************/
2111
+
2112
+ int ecb_cold
2113
+ eio_init (void (*want_poll)(eio_channel *), void (*done_poll)(eio_channel *))
2114
+ {
2115
+ #if !HAVE_PREADWRITE
2116
+ X_MUTEX_CREATE (preadwritelock);
2117
+ #endif
2118
+
2119
+ return etp_init (want_poll, done_poll);
2120
+ }
2121
+
2122
+ ecb_inline void
2123
+ eio_api_destroy (eio_req *req)
2124
+ {
2125
+ free (req);
2126
+ }
2127
+
2128
+ #define REQ(rtype) \
2129
+ eio_req *req; \
2130
+ \
2131
+ req = (eio_req *)calloc (1, sizeof *req); \
2132
+ if (!req) \
2133
+ return 0; \
2134
+ \
2135
+ req->type = rtype; \
2136
+ req->pri = pri; \
2137
+ req->finish = cb; \
2138
+ req->data = data; \
2139
+ req->destroy = eio_api_destroy; \
2140
+ req->channel = channel
2141
+
2142
+ #define SEND eio_submit (req); return req
2143
+
2144
+ #define PATH \
2145
+ req->flags |= EIO_FLAG_PTR1_FREE; \
2146
+ req->ptr1 = strdup (path); \
2147
+ if (!req->ptr1) \
2148
+ { \
2149
+ eio_api_destroy (req); \
2150
+ return 0; \
2151
+ }
2152
+
2153
+ static void
2154
+ eio_execute (etp_worker *self, eio_req *req)
2155
+ {
2156
+ if (ecb_expect_false (EIO_CANCELLED (req)))
2157
+ {
2158
+ req->result = -1;
2159
+ req->errorno = ECANCELED;
2160
+ return;
2161
+ }
2162
+
2163
+ switch (req->type)
2164
+ {
2165
+ case EIO_READ: ALLOC (req->size);
2166
+ req->result = req->offs >= 0
2167
+ ? pread (req->int1, req->ptr2, req->size, req->offs)
2168
+ : read (req->int1, req->ptr2, req->size); break;
2169
+
2170
+ case EIO_WRITE:
2171
+ #if defined (__APPLE__)
2172
+ pthread_mutex_lock (&apple_bug_writelock);
2173
+ #endif
2174
+
2175
+ req->result = req->offs >= 0
2176
+ ? pwrite (req->int1, req->ptr2, req->size, req->offs)
2177
+ : write (req->int1, req->ptr2, req->size);
2178
+
2179
+ #if defined (__APPLE__)
2180
+ pthread_mutex_unlock (&apple_bug_writelock);
2181
+ #endif
2182
+ break;
2183
+
2184
+ case EIO_READAHEAD: req->result = readahead (req->int1, req->offs, req->size); break;
2185
+ case EIO_SENDFILE: req->result = eio__sendfile (req->int1, req->int2, req->offs, req->size); break;
2186
+
2187
+ case EIO_STAT: ALLOC (sizeof (EIO_STRUCT_STAT));
2188
+ req->result = stat (req->ptr1, (EIO_STRUCT_STAT *)req->ptr2); break;
2189
+ case EIO_LSTAT: ALLOC (sizeof (EIO_STRUCT_STAT));
2190
+ req->result = lstat (req->ptr1, (EIO_STRUCT_STAT *)req->ptr2); break;
2191
+ case EIO_FSTAT: ALLOC (sizeof (EIO_STRUCT_STAT));
2192
+ req->result = fstat (req->int1, (EIO_STRUCT_STAT *)req->ptr2); break;
2193
+
2194
+ case EIO_STATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS));
2195
+ req->result = statvfs (req->ptr1, (EIO_STRUCT_STATVFS *)req->ptr2); break;
2196
+ case EIO_FSTATVFS: ALLOC (sizeof (EIO_STRUCT_STATVFS));
2197
+ req->result = fstatvfs (req->int1, (EIO_STRUCT_STATVFS *)req->ptr2); break;
2198
+
2199
+ case EIO_CHOWN: req->result = chown (req->ptr1, req->int2, req->int3); break;
2200
+ case EIO_FCHOWN: req->result = fchown (req->int1, req->int2, req->int3); break;
2201
+ case EIO_CHMOD: req->result = chmod (req->ptr1, (eio_mode_t)req->int2); break;
2202
+ case EIO_FCHMOD: req->result = fchmod (req->int1, (eio_mode_t)req->int2); break;
2203
+ case EIO_TRUNCATE: req->result = truncate (req->ptr1, req->offs); break;
2204
+ case EIO_FTRUNCATE: req->result = ftruncate (req->int1, req->offs); break;
2205
+
2206
+ case EIO_OPEN: req->result = open (req->ptr1, req->int1, (eio_mode_t)req->int2); break;
2207
+ case EIO_CLOSE: req->result = close (req->int1); break;
2208
+ case EIO_DUP2: req->result = dup2 (req->int1, req->int2); break;
2209
+ case EIO_UNLINK: req->result = unlink (req->ptr1); break;
2210
+ case EIO_RMDIR: req->result = rmdir (req->ptr1); break;
2211
+ case EIO_MKDIR: req->result = mkdir (req->ptr1, (eio_mode_t)req->int2); break;
2212
+ case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break;
2213
+ case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break;
2214
+ case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break;
2215
+ case EIO_MKNOD: req->result = mknod (req->ptr1, (eio_mode_t)req->int2, (dev_t)req->offs); break;
2216
+
2217
+ case EIO_REALPATH: eio__realpath (req, self); break;
2218
+
2219
+ case EIO_READLINK: ALLOC (PATH_MAX);
2220
+ req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break;
2221
+
2222
+ case EIO_SYNC: req->result = 0; sync (); break;
2223
+ case EIO_FSYNC: req->result = fsync (req->int1); break;
2224
+ case EIO_FDATASYNC: req->result = fdatasync (req->int1); break;
2225
+ case EIO_SYNCFS: req->result = eio__syncfs (req->int1); break;
2226
+ case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break;
2227
+ case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break;
2228
+ case EIO_MTOUCH: req->result = eio__mtouch (req); break;
2229
+ case EIO_MLOCK: req->result = eio__mlock (req->ptr2, req->size); break;
2230
+ case EIO_MLOCKALL: req->result = eio__mlockall (req->int1); break;
2231
+ case EIO_FALLOCATE: req->result = eio__fallocate (req->int1, req->int2, req->offs, req->size); break;
2232
+
2233
+ case EIO_READDIR: eio__scandir (req, self); break;
2234
+
2235
+ case EIO_BUSY:
2236
+ #ifdef _WIN32
2237
+ Sleep (req->nv1 * 1e3);
2238
+ #else
2239
+ {
2240
+ struct timeval tv;
2241
+
2242
+ tv.tv_sec = req->nv1;
2243
+ tv.tv_usec = (req->nv1 - tv.tv_sec) * 1e6;
2244
+
2245
+ req->result = select (0, 0, 0, 0, &tv);
2246
+ }
2247
+ #endif
2248
+ break;
2249
+
2250
+ case EIO_UTIME:
2251
+ case EIO_FUTIME:
2252
+ {
2253
+ struct timeval tv[2];
2254
+ struct timeval *times;
2255
+
2256
+ if (req->nv1 != -1. || req->nv2 != -1.)
2257
+ {
2258
+ tv[0].tv_sec = req->nv1;
2259
+ tv[0].tv_usec = (req->nv1 - tv[0].tv_sec) * 1000000.;
2260
+ tv[1].tv_sec = req->nv2;
2261
+ tv[1].tv_usec = (req->nv2 - tv[1].tv_sec) * 1000000.;
2262
+
2263
+ times = tv;
2264
+ }
2265
+ else
2266
+ times = 0;
2267
+
2268
+ req->result = req->type == EIO_FUTIME
2269
+ ? futimes (req->int1, times)
2270
+ : utimes (req->ptr1, times);
2271
+ }
2272
+ break;
2273
+
2274
+ case EIO_GROUP:
2275
+ abort (); /* handled in eio_request */
2276
+
2277
+ case EIO_NOP:
2278
+ req->result = 0;
2279
+ break;
2280
+
2281
+ case EIO_CUSTOM:
2282
+ req->feed (req);
2283
+ break;
2284
+
2285
+ default:
2286
+ errno = ENOSYS;
2287
+ req->result = -1;
2288
+ break;
2289
+ }
2290
+
2291
+ req->errorno = errno;
2292
+ }
2293
+
2294
+ #ifndef EIO_NO_WRAPPERS
2295
+
2296
+ eio_req *eio_nop (int pri, eio_cb cb, void *data, eio_channel *channel)
2297
+ {
2298
+ REQ (EIO_NOP); SEND;
2299
+ }
2300
+
2301
+ eio_req *eio_busy (double delay, int pri, eio_cb cb, void *data, eio_channel *channel)
2302
+ {
2303
+ REQ (EIO_BUSY); req->nv1 = delay; SEND;
2304
+ }
2305
+
2306
+ eio_req *eio_sync (int pri, eio_cb cb, void *data, eio_channel *channel)
2307
+ {
2308
+ REQ (EIO_SYNC); SEND;
2309
+ }
2310
+
2311
+ eio_req *eio_fsync (int fd, int pri, eio_cb cb, void *data, eio_channel *channel)
2312
+ {
2313
+ REQ (EIO_FSYNC); req->int1 = fd; SEND;
2314
+ }
2315
+
2316
+ eio_req *eio_msync (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data, eio_channel *channel)
2317
+ {
2318
+ REQ (EIO_MSYNC); req->ptr2 = addr; req->size = length; req->int1 = flags; SEND;
2319
+ }
2320
+
2321
+ eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data, eio_channel *channel)
2322
+ {
2323
+ REQ (EIO_FDATASYNC); req->int1 = fd; SEND;
2324
+ }
2325
+
2326
+ eio_req *eio_syncfs (int fd, int pri, eio_cb cb, void *data, eio_channel *channel)
2327
+ {
2328
+ REQ (EIO_SYNCFS); req->int1 = fd; SEND;
2329
+ }
2330
+
2331
+ eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data, eio_channel *channel)
2332
+ {
2333
+ REQ (EIO_SYNC_FILE_RANGE); req->int1 = fd; req->offs = offset; req->size = nbytes; req->int2 = flags; SEND;
2334
+ }
2335
+
2336
+ eio_req *eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data, eio_channel *channel)
2337
+ {
2338
+ REQ (EIO_MTOUCH); req->ptr2 = addr; req->size = length; req->int1 = flags; SEND;
2339
+ }
2340
+
2341
+ eio_req *eio_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data, eio_channel *channel)
2342
+ {
2343
+ REQ (EIO_MLOCK); req->ptr2 = addr; req->size = length; SEND;
2344
+ }
2345
+
2346
+ eio_req *eio_mlockall (int flags, int pri, eio_cb cb, void *data, eio_channel *channel)
2347
+ {
2348
+ REQ (EIO_MLOCKALL); req->int1 = flags; SEND;
2349
+ }
2350
+
2351
+ eio_req *eio_fallocate (int fd, int mode, off_t offset, size_t len, int pri, eio_cb cb, void *data, eio_channel *channel)
2352
+ {
2353
+ REQ (EIO_FALLOCATE); req->int1 = fd; req->int2 = mode; req->offs = offset; req->size = len; SEND;
2354
+ }
2355
+
2356
+ eio_req *eio_close (int fd, int pri, eio_cb cb, void *data, eio_channel *channel)
2357
+ {
2358
+ REQ (EIO_CLOSE); req->int1 = fd; SEND;
2359
+ }
2360
+
2361
+ eio_req *eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data, eio_channel *channel)
2362
+ {
2363
+ REQ (EIO_READAHEAD); req->int1 = fd; req->offs = offset; req->size = length; SEND;
2364
+ }
2365
+
2366
+ eio_req *eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data, eio_channel *channel)
2367
+ {
2368
+ REQ (EIO_READ); req->int1 = fd; req->offs = offset; req->size = length; req->ptr2 = buf; SEND;
2369
+ }
2370
+
2371
+ eio_req *eio_write (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data, eio_channel *channel)
2372
+ {
2373
+ REQ (EIO_WRITE); req->int1 = fd; req->offs = offset; req->size = length; req->ptr2 = buf; SEND;
2374
+ }
2375
+
2376
+ eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data, eio_channel *channel)
2377
+ {
2378
+ REQ (EIO_FSTAT); req->int1 = fd; SEND;
2379
+ }
2380
+
2381
+ eio_req *eio_fstatvfs (int fd, int pri, eio_cb cb, void *data, eio_channel *channel)
2382
+ {
2383
+ REQ (EIO_FSTATVFS); req->int1 = fd; SEND;
2384
+ }
2385
+
2386
+ eio_req *eio_futime (int fd, double atime, double mtime, int pri, eio_cb cb, void *data, eio_channel *channel)
2387
+ {
2388
+ REQ (EIO_FUTIME); req->int1 = fd; req->nv1 = atime; req->nv2 = mtime; SEND;
2389
+ }
2390
+
2391
+ eio_req *eio_ftruncate (int fd, off_t offset, int pri, eio_cb cb, void *data, eio_channel *channel)
2392
+ {
2393
+ REQ (EIO_FTRUNCATE); req->int1 = fd; req->offs = offset; SEND;
2394
+ }
2395
+
2396
+ eio_req *eio_fchmod (int fd, eio_mode_t mode, int pri, eio_cb cb, void *data, eio_channel *channel)
2397
+ {
2398
+ REQ (EIO_FCHMOD); req->int1 = fd; req->int2 = (long)mode; SEND;
2399
+ }
2400
+
2401
+ eio_req *eio_fchown (int fd, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data, eio_channel *channel)
2402
+ {
2403
+ REQ (EIO_FCHOWN); req->int1 = fd; req->int2 = (long)uid; req->int3 = (long)gid; SEND;
2404
+ }
2405
+
2406
+ eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data, eio_channel *channel)
2407
+ {
2408
+ REQ (EIO_DUP2); req->int1 = fd; req->int2 = fd2; SEND;
2409
+ }
2410
+
2411
+ eio_req *eio_sendfile (int out_fd, int in_fd, off_t in_offset, size_t length, int pri, eio_cb cb, void *data, eio_channel *channel)
2412
+ {
2413
+ REQ (EIO_SENDFILE); req->int1 = out_fd; req->int2 = in_fd; req->offs = in_offset; req->size = length; SEND;
2414
+ }
2415
+
2416
+ eio_req *eio_open (const char *path, int flags, eio_mode_t mode, int pri, eio_cb cb, void *data, eio_channel *channel)
2417
+ {
2418
+ REQ (EIO_OPEN); PATH; req->int1 = flags; req->int2 = (long)mode; SEND;
2419
+ }
2420
+
2421
+ eio_req *eio_utime (const char *path, double atime, double mtime, int pri, eio_cb cb, void *data, eio_channel *channel)
2422
+ {
2423
+ REQ (EIO_UTIME); PATH; req->nv1 = atime; req->nv2 = mtime; SEND;
2424
+ }
2425
+
2426
+ eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data, eio_channel *channel)
2427
+ {
2428
+ REQ (EIO_TRUNCATE); PATH; req->offs = offset; SEND;
2429
+ }
2430
+
2431
+ eio_req *eio_chown (const char *path, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data, eio_channel *channel)
2432
+ {
2433
+ REQ (EIO_CHOWN); PATH; req->int2 = (long)uid; req->int3 = (long)gid; SEND;
2434
+ }
2435
+
2436
+ eio_req *eio_chmod (const char *path, eio_mode_t mode, int pri, eio_cb cb, void *data, eio_channel *channel)
2437
+ {
2438
+ REQ (EIO_CHMOD); PATH; req->int2 = (long)mode; SEND;
2439
+ }
2440
+
2441
+ eio_req *eio_mkdir (const char *path, eio_mode_t mode, int pri, eio_cb cb, void *data, eio_channel *channel)
2442
+ {
2443
+ REQ (EIO_MKDIR); PATH; req->int2 = (long)mode; SEND;
2444
+ }
2445
+
2446
+ static eio_req *
2447
+ eio__1path (int type, const char *path, int pri, eio_cb cb, void *data, eio_channel *channel)
2448
+ {
2449
+ REQ (type); PATH; SEND;
2450
+ }
2451
+
2452
+ eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data, eio_channel *channel)
2453
+ {
2454
+ return eio__1path (EIO_READLINK, path, pri, cb, data, channel);
2455
+ }
2456
+
2457
+ eio_req *eio_realpath (const char *path, int pri, eio_cb cb, void *data, eio_channel *channel)
2458
+ {
2459
+ return eio__1path (EIO_REALPATH, path, pri, cb, data, channel);
2460
+ }
2461
+
2462
+ eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data, eio_channel *channel)
2463
+ {
2464
+ return eio__1path (EIO_STAT, path, pri, cb, data, channel);
2465
+ }
2466
+
2467
+ eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data, eio_channel *channel)
2468
+ {
2469
+ return eio__1path (EIO_LSTAT, path, pri, cb, data, channel);
2470
+ }
2471
+
2472
+ eio_req *eio_statvfs (const char *path, int pri, eio_cb cb, void *data, eio_channel *channel)
2473
+ {
2474
+ return eio__1path (EIO_STATVFS, path, pri, cb, data, channel);
2475
+ }
2476
+
2477
+ eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data, eio_channel *channel)
2478
+ {
2479
+ return eio__1path (EIO_UNLINK, path, pri, cb, data, channel);
2480
+ }
2481
+
2482
+ eio_req *eio_rmdir (const char *path, int pri, eio_cb cb, void *data, eio_channel *channel)
2483
+ {
2484
+ return eio__1path (EIO_RMDIR, path, pri, cb, data, channel);
2485
+ }
2486
+
2487
+ eio_req *eio_readdir (const char *path, int flags, int pri, eio_cb cb, void *data, eio_channel *channel)
2488
+ {
2489
+ REQ (EIO_READDIR); PATH; req->int1 = flags; SEND;
2490
+ }
2491
+
2492
+ eio_req *eio_mknod (const char *path, eio_mode_t mode, dev_t dev, int pri, eio_cb cb, void *data, eio_channel *channel)
2493
+ {
2494
+ REQ (EIO_MKNOD); PATH; req->int2 = (long)mode; req->offs = (off_t)dev; SEND;
2495
+ }
2496
+
2497
+ static eio_req *
2498
+ eio__2path (int type, const char *path, const char *new_path, int pri, eio_cb cb, void *data, eio_channel *channel)
2499
+ {
2500
+ REQ (type); PATH;
2501
+
2502
+ req->flags |= EIO_FLAG_PTR2_FREE;
2503
+ req->ptr2 = strdup (new_path);
2504
+ if (!req->ptr2)
2505
+ {
2506
+ eio_api_destroy (req);
2507
+ return 0;
2508
+ }
2509
+
2510
+ SEND;
2511
+ }
2512
+
2513
+ eio_req *eio_link (const char *path, const char *new_path, int pri, eio_cb cb, void *data, eio_channel *channel)
2514
+ {
2515
+ return eio__2path (EIO_LINK, path, new_path, pri, cb, data, channel);
2516
+ }
2517
+
2518
+ eio_req *eio_symlink (const char *path, const char *new_path, int pri, eio_cb cb, void *data, eio_channel *channel)
2519
+ {
2520
+ return eio__2path (EIO_SYMLINK, path, new_path, pri, cb, data, channel);
2521
+ }
2522
+
2523
+ eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data, eio_channel *channel)
2524
+ {
2525
+ return eio__2path (EIO_RENAME, path, new_path, pri, cb, data, channel);
2526
+ }
2527
+
2528
+ eio_req *eio_custom (void (*execute)(eio_req *), int pri, eio_cb cb, void *data, eio_channel *channel)
2529
+ {
2530
+ REQ (EIO_CUSTOM); req->feed = execute; SEND;
2531
+ }
2532
+
2533
+ #endif
2534
+
2535
+ eio_req *eio_grp (eio_cb cb, void *data, eio_channel *channel)
2536
+ {
2537
+ const int pri = EIO_PRI_MAX;
2538
+
2539
+ REQ (EIO_GROUP); SEND;
2540
+ }
2541
+
2542
+ #undef REQ
2543
+ #undef PATH
2544
+ #undef SEND
2545
+
2546
+ /*****************************************************************************/
2547
+ /* grp functions */
2548
+
2549
+ void
2550
+ eio_grp_feed (eio_req *grp, void (*feed)(eio_req *req), int limit)
2551
+ {
2552
+ grp->int2 = limit;
2553
+ grp->feed = feed;
2554
+
2555
+ grp_try_feed (grp);
2556
+ }
2557
+
2558
+ void
2559
+ eio_grp_limit (eio_req *grp, int limit)
2560
+ {
2561
+ grp->int2 = limit;
2562
+
2563
+ grp_try_feed (grp);
2564
+ }
2565
+
2566
+ void
2567
+ eio_grp_add (eio_req *grp, eio_req *req)
2568
+ {
2569
+ assert (("cannot add requests to IO::AIO::GRP after the group finished", grp->int1 != 2));
2570
+
2571
+ grp->flags |= EIO_FLAG_GROUPADD;
2572
+
2573
+ ++grp->size;
2574
+ req->grp = grp;
2575
+
2576
+ req->grp_prev = 0;
2577
+ req->grp_next = grp->grp_first;
2578
+
2579
+ if (grp->grp_first)
2580
+ grp->grp_first->grp_prev = req;
2581
+
2582
+ grp->grp_first = req;
2583
+ }
2584
+
2585
+ /*****************************************************************************/
2586
+ /* misc garbage */
2587
+
2588
+ eio_ssize_t
2589
+ eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count)
2590
+ {
2591
+ return eio__sendfile (ofd, ifd, offset, count);
2592
+ }
2593
+