foolio 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (261) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +21 -0
  6. data/examples/timer.rb +20 -0
  7. data/ext/foolio/extconf.rb +34 -0
  8. data/ext/foolio/foolio_ext.c +921 -0
  9. data/ext/foolio/gen.rb +50 -0
  10. data/ext/foolio/make_table.rb +12 -0
  11. data/ext/foolio/templ +243 -0
  12. data/ext/libuv/.gitignore +33 -0
  13. data/ext/libuv/.mailmap +13 -0
  14. data/ext/libuv/.travis.yml +9 -0
  15. data/ext/libuv/AUTHORS +61 -0
  16. data/ext/libuv/LICENSE +44 -0
  17. data/ext/libuv/Makefile +71 -0
  18. data/ext/libuv/README.md +90 -0
  19. data/ext/libuv/common.gypi +178 -0
  20. data/ext/libuv/gyp_uv +73 -0
  21. data/ext/libuv/include/uv-private/eio.h +403 -0
  22. data/ext/libuv/include/uv-private/ev.h +838 -0
  23. data/ext/libuv/include/uv-private/ngx-queue.h +108 -0
  24. data/ext/libuv/include/uv-private/tree.h +768 -0
  25. data/ext/libuv/include/uv-private/uv-unix.h +324 -0
  26. data/ext/libuv/include/uv-private/uv-win.h +517 -0
  27. data/ext/libuv/include/uv.h +1838 -0
  28. data/ext/libuv/src/fs-poll.c +235 -0
  29. data/ext/libuv/src/inet.c +293 -0
  30. data/ext/libuv/src/unix/async.c +148 -0
  31. data/ext/libuv/src/unix/core.c +696 -0
  32. data/ext/libuv/src/unix/cygwin.c +83 -0
  33. data/ext/libuv/src/unix/darwin.c +342 -0
  34. data/ext/libuv/src/unix/dl.c +83 -0
  35. data/ext/libuv/src/unix/eio/Changes +63 -0
  36. data/ext/libuv/src/unix/eio/LICENSE +36 -0
  37. data/ext/libuv/src/unix/eio/Makefile.am +15 -0
  38. data/ext/libuv/src/unix/eio/aclocal.m4 +8957 -0
  39. data/ext/libuv/src/unix/eio/autogen.sh +3 -0
  40. data/ext/libuv/src/unix/eio/config.h.in +86 -0
  41. data/ext/libuv/src/unix/eio/config_cygwin.h +80 -0
  42. data/ext/libuv/src/unix/eio/config_darwin.h +141 -0
  43. data/ext/libuv/src/unix/eio/config_freebsd.h +81 -0
  44. data/ext/libuv/src/unix/eio/config_linux.h +94 -0
  45. data/ext/libuv/src/unix/eio/config_netbsd.h +81 -0
  46. data/ext/libuv/src/unix/eio/config_openbsd.h +137 -0
  47. data/ext/libuv/src/unix/eio/config_sunos.h +84 -0
  48. data/ext/libuv/src/unix/eio/configure.ac +22 -0
  49. data/ext/libuv/src/unix/eio/demo.c +194 -0
  50. data/ext/libuv/src/unix/eio/ecb.h +370 -0
  51. data/ext/libuv/src/unix/eio/eio.3 +3428 -0
  52. data/ext/libuv/src/unix/eio/eio.c +2593 -0
  53. data/ext/libuv/src/unix/eio/eio.pod +969 -0
  54. data/ext/libuv/src/unix/eio/libeio.m4 +195 -0
  55. data/ext/libuv/src/unix/eio/xthread.h +164 -0
  56. data/ext/libuv/src/unix/error.c +105 -0
  57. data/ext/libuv/src/unix/ev/Changes +388 -0
  58. data/ext/libuv/src/unix/ev/LICENSE +36 -0
  59. data/ext/libuv/src/unix/ev/Makefile.am +18 -0
  60. data/ext/libuv/src/unix/ev/Makefile.in +771 -0
  61. data/ext/libuv/src/unix/ev/README +58 -0
  62. data/ext/libuv/src/unix/ev/aclocal.m4 +8957 -0
  63. data/ext/libuv/src/unix/ev/autogen.sh +6 -0
  64. data/ext/libuv/src/unix/ev/config.guess +1526 -0
  65. data/ext/libuv/src/unix/ev/config.h.in +125 -0
  66. data/ext/libuv/src/unix/ev/config.sub +1658 -0
  67. data/ext/libuv/src/unix/ev/config_cygwin.h +123 -0
  68. data/ext/libuv/src/unix/ev/config_darwin.h +122 -0
  69. data/ext/libuv/src/unix/ev/config_freebsd.h +120 -0
  70. data/ext/libuv/src/unix/ev/config_linux.h +141 -0
  71. data/ext/libuv/src/unix/ev/config_netbsd.h +120 -0
  72. data/ext/libuv/src/unix/ev/config_openbsd.h +126 -0
  73. data/ext/libuv/src/unix/ev/config_sunos.h +122 -0
  74. data/ext/libuv/src/unix/ev/configure +13037 -0
  75. data/ext/libuv/src/unix/ev/configure.ac +18 -0
  76. data/ext/libuv/src/unix/ev/depcomp +630 -0
  77. data/ext/libuv/src/unix/ev/ev++.h +816 -0
  78. data/ext/libuv/src/unix/ev/ev.3 +5311 -0
  79. data/ext/libuv/src/unix/ev/ev.c +3925 -0
  80. data/ext/libuv/src/unix/ev/ev.pod +5243 -0
  81. data/ext/libuv/src/unix/ev/ev_epoll.c +266 -0
  82. data/ext/libuv/src/unix/ev/ev_kqueue.c +235 -0
  83. data/ext/libuv/src/unix/ev/ev_poll.c +148 -0
  84. data/ext/libuv/src/unix/ev/ev_port.c +179 -0
  85. data/ext/libuv/src/unix/ev/ev_select.c +310 -0
  86. data/ext/libuv/src/unix/ev/ev_vars.h +203 -0
  87. data/ext/libuv/src/unix/ev/ev_win32.c +153 -0
  88. data/ext/libuv/src/unix/ev/ev_wrap.h +196 -0
  89. data/ext/libuv/src/unix/ev/event.c +402 -0
  90. data/ext/libuv/src/unix/ev/event.h +170 -0
  91. data/ext/libuv/src/unix/ev/install-sh +294 -0
  92. data/ext/libuv/src/unix/ev/libev.m4 +39 -0
  93. data/ext/libuv/src/unix/ev/ltmain.sh +8413 -0
  94. data/ext/libuv/src/unix/ev/missing +336 -0
  95. data/ext/libuv/src/unix/ev/mkinstalldirs +111 -0
  96. data/ext/libuv/src/unix/freebsd.c +326 -0
  97. data/ext/libuv/src/unix/fs.c +739 -0
  98. data/ext/libuv/src/unix/internal.h +188 -0
  99. data/ext/libuv/src/unix/kqueue.c +120 -0
  100. data/ext/libuv/src/unix/linux/inotify.c +239 -0
  101. data/ext/libuv/src/unix/linux/linux-core.c +557 -0
  102. data/ext/libuv/src/unix/linux/syscalls.c +388 -0
  103. data/ext/libuv/src/unix/linux/syscalls.h +124 -0
  104. data/ext/libuv/src/unix/loop-watcher.c +62 -0
  105. data/ext/libuv/src/unix/loop.c +94 -0
  106. data/ext/libuv/src/unix/netbsd.c +108 -0
  107. data/ext/libuv/src/unix/openbsd.c +295 -0
  108. data/ext/libuv/src/unix/pipe.c +259 -0
  109. data/ext/libuv/src/unix/poll.c +114 -0
  110. data/ext/libuv/src/unix/process.c +495 -0
  111. data/ext/libuv/src/unix/signal.c +269 -0
  112. data/ext/libuv/src/unix/stream.c +990 -0
  113. data/ext/libuv/src/unix/sunos.c +481 -0
  114. data/ext/libuv/src/unix/tcp.c +393 -0
  115. data/ext/libuv/src/unix/thread.c +251 -0
  116. data/ext/libuv/src/unix/timer.c +136 -0
  117. data/ext/libuv/src/unix/tty.c +145 -0
  118. data/ext/libuv/src/unix/udp.c +659 -0
  119. data/ext/libuv/src/unix/uv-eio.c +107 -0
  120. data/ext/libuv/src/unix/uv-eio.h +13 -0
  121. data/ext/libuv/src/uv-common.c +380 -0
  122. data/ext/libuv/src/uv-common.h +170 -0
  123. data/ext/libuv/src/win/async.c +100 -0
  124. data/ext/libuv/src/win/atomicops-inl.h +56 -0
  125. data/ext/libuv/src/win/core.c +278 -0
  126. data/ext/libuv/src/win/dl.c +86 -0
  127. data/ext/libuv/src/win/error.c +155 -0
  128. data/ext/libuv/src/win/fs-event.c +510 -0
  129. data/ext/libuv/src/win/fs.c +1948 -0
  130. data/ext/libuv/src/win/getaddrinfo.c +365 -0
  131. data/ext/libuv/src/win/handle-inl.h +149 -0
  132. data/ext/libuv/src/win/handle.c +154 -0
  133. data/ext/libuv/src/win/internal.h +343 -0
  134. data/ext/libuv/src/win/loop-watcher.c +122 -0
  135. data/ext/libuv/src/win/pipe.c +1672 -0
  136. data/ext/libuv/src/win/poll.c +616 -0
  137. data/ext/libuv/src/win/process-stdio.c +500 -0
  138. data/ext/libuv/src/win/process.c +1013 -0
  139. data/ext/libuv/src/win/req-inl.h +220 -0
  140. data/ext/libuv/src/win/req.c +25 -0
  141. data/ext/libuv/src/win/signal.c +57 -0
  142. data/ext/libuv/src/win/stream-inl.h +67 -0
  143. data/ext/libuv/src/win/stream.c +167 -0
  144. data/ext/libuv/src/win/tcp.c +1394 -0
  145. data/ext/libuv/src/win/thread.c +372 -0
  146. data/ext/libuv/src/win/threadpool.c +74 -0
  147. data/ext/libuv/src/win/timer.c +224 -0
  148. data/ext/libuv/src/win/tty.c +1799 -0
  149. data/ext/libuv/src/win/udp.c +716 -0
  150. data/ext/libuv/src/win/util.c +864 -0
  151. data/ext/libuv/src/win/winapi.c +132 -0
  152. data/ext/libuv/src/win/winapi.h +4452 -0
  153. data/ext/libuv/src/win/winsock.c +557 -0
  154. data/ext/libuv/src/win/winsock.h +171 -0
  155. data/ext/libuv/test/benchmark-async-pummel.c +97 -0
  156. data/ext/libuv/test/benchmark-async.c +137 -0
  157. data/ext/libuv/test/benchmark-fs-stat.c +135 -0
  158. data/ext/libuv/test/benchmark-getaddrinfo.c +94 -0
  159. data/ext/libuv/test/benchmark-list.h +127 -0
  160. data/ext/libuv/test/benchmark-loop-count.c +88 -0
  161. data/ext/libuv/test/benchmark-million-timers.c +65 -0
  162. data/ext/libuv/test/benchmark-ping-pongs.c +213 -0
  163. data/ext/libuv/test/benchmark-pound.c +324 -0
  164. data/ext/libuv/test/benchmark-pump.c +462 -0
  165. data/ext/libuv/test/benchmark-sizes.c +44 -0
  166. data/ext/libuv/test/benchmark-spawn.c +162 -0
  167. data/ext/libuv/test/benchmark-tcp-write-batch.c +140 -0
  168. data/ext/libuv/test/benchmark-thread.c +64 -0
  169. data/ext/libuv/test/benchmark-udp-packet-storm.c +247 -0
  170. data/ext/libuv/test/blackhole-server.c +118 -0
  171. data/ext/libuv/test/dns-server.c +321 -0
  172. data/ext/libuv/test/echo-server.c +378 -0
  173. data/ext/libuv/test/fixtures/empty_file +0 -0
  174. data/ext/libuv/test/fixtures/load_error.node +1 -0
  175. data/ext/libuv/test/run-benchmarks.c +64 -0
  176. data/ext/libuv/test/run-tests.c +138 -0
  177. data/ext/libuv/test/runner-unix.c +295 -0
  178. data/ext/libuv/test/runner-unix.h +36 -0
  179. data/ext/libuv/test/runner-win.c +285 -0
  180. data/ext/libuv/test/runner-win.h +42 -0
  181. data/ext/libuv/test/runner.c +355 -0
  182. data/ext/libuv/test/runner.h +159 -0
  183. data/ext/libuv/test/task.h +112 -0
  184. data/ext/libuv/test/test-async.c +118 -0
  185. data/ext/libuv/test/test-callback-order.c +76 -0
  186. data/ext/libuv/test/test-callback-stack.c +203 -0
  187. data/ext/libuv/test/test-connection-fail.c +148 -0
  188. data/ext/libuv/test/test-cwd-and-chdir.c +64 -0
  189. data/ext/libuv/test/test-delayed-accept.c +188 -0
  190. data/ext/libuv/test/test-dlerror.c +58 -0
  191. data/ext/libuv/test/test-error.c +59 -0
  192. data/ext/libuv/test/test-fail-always.c +29 -0
  193. data/ext/libuv/test/test-fs-event.c +474 -0
  194. data/ext/libuv/test/test-fs-poll.c +146 -0
  195. data/ext/libuv/test/test-fs.c +1843 -0
  196. data/ext/libuv/test/test-get-currentexe.c +63 -0
  197. data/ext/libuv/test/test-get-loadavg.c +36 -0
  198. data/ext/libuv/test/test-get-memory.c +38 -0
  199. data/ext/libuv/test/test-getaddrinfo.c +122 -0
  200. data/ext/libuv/test/test-getsockname.c +342 -0
  201. data/ext/libuv/test/test-hrtime.c +54 -0
  202. data/ext/libuv/test/test-idle.c +81 -0
  203. data/ext/libuv/test/test-ipc-send-recv.c +209 -0
  204. data/ext/libuv/test/test-ipc.c +620 -0
  205. data/ext/libuv/test/test-list.h +427 -0
  206. data/ext/libuv/test/test-loop-handles.c +336 -0
  207. data/ext/libuv/test/test-multiple-listen.c +102 -0
  208. data/ext/libuv/test/test-mutexes.c +63 -0
  209. data/ext/libuv/test/test-pass-always.c +28 -0
  210. data/ext/libuv/test/test-ping-pong.c +253 -0
  211. data/ext/libuv/test/test-pipe-bind-error.c +140 -0
  212. data/ext/libuv/test/test-pipe-connect-error.c +96 -0
  213. data/ext/libuv/test/test-platform-output.c +87 -0
  214. data/ext/libuv/test/test-poll-close.c +72 -0
  215. data/ext/libuv/test/test-poll.c +573 -0
  216. data/ext/libuv/test/test-process-title.c +49 -0
  217. data/ext/libuv/test/test-ref.c +338 -0
  218. data/ext/libuv/test/test-run-once.c +48 -0
  219. data/ext/libuv/test/test-semaphore.c +111 -0
  220. data/ext/libuv/test/test-shutdown-close.c +103 -0
  221. data/ext/libuv/test/test-shutdown-eof.c +183 -0
  222. data/ext/libuv/test/test-signal.c +162 -0
  223. data/ext/libuv/test/test-spawn.c +863 -0
  224. data/ext/libuv/test/test-stdio-over-pipes.c +246 -0
  225. data/ext/libuv/test/test-tcp-bind-error.c +191 -0
  226. data/ext/libuv/test/test-tcp-bind6-error.c +154 -0
  227. data/ext/libuv/test/test-tcp-close-while-connecting.c +80 -0
  228. data/ext/libuv/test/test-tcp-close.c +129 -0
  229. data/ext/libuv/test/test-tcp-connect-error-after-write.c +95 -0
  230. data/ext/libuv/test/test-tcp-connect-error.c +70 -0
  231. data/ext/libuv/test/test-tcp-connect-timeout.c +85 -0
  232. data/ext/libuv/test/test-tcp-connect6-error.c +68 -0
  233. data/ext/libuv/test/test-tcp-flags.c +51 -0
  234. data/ext/libuv/test/test-tcp-shutdown-after-write.c +131 -0
  235. data/ext/libuv/test/test-tcp-unexpected-read.c +113 -0
  236. data/ext/libuv/test/test-tcp-write-error.c +168 -0
  237. data/ext/libuv/test/test-tcp-write-to-half-open-connection.c +135 -0
  238. data/ext/libuv/test/test-tcp-writealot.c +170 -0
  239. data/ext/libuv/test/test-thread.c +183 -0
  240. data/ext/libuv/test/test-threadpool.c +57 -0
  241. data/ext/libuv/test/test-timer-again.c +141 -0
  242. data/ext/libuv/test/test-timer.c +152 -0
  243. data/ext/libuv/test/test-tty.c +110 -0
  244. data/ext/libuv/test/test-udp-dgram-too-big.c +86 -0
  245. data/ext/libuv/test/test-udp-ipv6.c +156 -0
  246. data/ext/libuv/test/test-udp-multicast-join.c +139 -0
  247. data/ext/libuv/test/test-udp-multicast-ttl.c +86 -0
  248. data/ext/libuv/test/test-udp-options.c +86 -0
  249. data/ext/libuv/test/test-udp-send-and-recv.c +208 -0
  250. data/ext/libuv/test/test-util.c +97 -0
  251. data/ext/libuv/test/test-walk-handles.c +77 -0
  252. data/ext/libuv/uv.gyp +375 -0
  253. data/ext/libuv/vcbuild.bat +105 -0
  254. data/foolio.gemspec +18 -0
  255. data/lib/foolio.rb +9 -0
  256. data/lib/foolio/handle.rb +27 -0
  257. data/lib/foolio/listener.rb +26 -0
  258. data/lib/foolio/loop.rb +79 -0
  259. data/lib/foolio/stream.rb +109 -0
  260. data/lib/foolio/version.rb +3 -0
  261. metadata +309 -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
+