passenger 3.0.21 → 3.9.1.beta

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