passenger 5.0.8 → 5.0.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

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