passenger 5.0.8 → 5.0.9

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

Potentially problematic release.


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

Files changed (168) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +20 -0
  5. data/CHANGELOG +21 -0
  6. data/bin/passenger-install-apache2-module +3 -1
  7. data/build/agents.rb +7 -5
  8. data/build/basics.rb +3 -3
  9. data/build/common_library.rb +52 -30
  10. data/build/cxx_tests.rb +20 -13
  11. data/build/misc.rb +5 -5
  12. data/doc/Design and Architecture.html +1 -1
  13. data/doc/Design and Architecture.txt +1 -1
  14. data/doc/Packaging.html +4 -4
  15. data/doc/Packaging.txt.md +4 -4
  16. data/doc/Users guide Apache.html +22 -9
  17. data/doc/Users guide Apache.idmap.txt +4 -2
  18. data/doc/Users guide Apache.txt +2 -0
  19. data/doc/Users guide Nginx.html +22 -9
  20. data/doc/Users guide Nginx.idmap.txt +4 -2
  21. data/doc/Users guide Nginx.txt +2 -0
  22. data/doc/Users guide Standalone.html +14 -9
  23. data/doc/Users guide Standalone.idmap.txt +4 -2
  24. data/doc/users_guide_snippets/installation.txt +10 -6
  25. data/ext/apache2/Hooks.cpp +13 -2
  26. data/ext/common/ApplicationPool2/Pool/Inspection.h +8 -3
  27. data/ext/common/BackgroundEventLoop.cpp +249 -67
  28. data/ext/common/BackgroundEventLoop.h +5 -5
  29. data/ext/common/Constants.h +1 -1
  30. data/ext/common/InstanceDirectory.h +8 -6
  31. data/ext/common/ServerKit/Context.h +8 -2
  32. data/ext/common/ServerKit/FileBufferedChannel.h +262 -226
  33. data/ext/common/ServerKit/HeaderTable.h +28 -3
  34. data/ext/common/ServerKit/HttpHeaderParser.h +37 -13
  35. data/ext/common/ServerKit/HttpServer.h +17 -1
  36. data/ext/common/ServerKit/Implementation.cpp +2 -0
  37. data/ext/common/ServerKit/Server.h +25 -28
  38. data/ext/common/Utils/IOUtils.cpp +11 -0
  39. data/ext/common/Utils/ProcessMetricsCollector.h +4 -0
  40. data/ext/common/Utils/StrIntUtils.cpp +11 -7
  41. data/ext/common/Utils/StrIntUtils.h +1 -1
  42. data/ext/common/Utils/StrIntUtilsNoStrictAliasing.cpp +21 -16
  43. data/ext/common/agents/Base.cpp +6 -0
  44. data/ext/common/agents/Base.h +2 -0
  45. data/ext/common/agents/HelperAgent/AdminServer.h +25 -25
  46. data/ext/common/agents/HelperAgent/Main.cpp +37 -12
  47. data/ext/common/agents/HelperAgent/RequestHandler.h +18 -20
  48. data/ext/common/agents/HelperAgent/RequestHandler/AppResponse.h +4 -0
  49. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +10 -6
  50. data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +2 -0
  51. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +1 -1
  52. data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +1 -1
  53. data/ext/common/agents/HelperAgent/RequestHandler/Utils.cpp +9 -2
  54. data/ext/common/agents/HelperAgent/ResponseCache.h +11 -11
  55. data/ext/common/agents/LoggingAgent/AdminServer.h +8 -8
  56. data/ext/common/agents/LoggingAgent/Main.cpp +6 -5
  57. data/ext/common/agents/Watchdog/AdminServer.h +13 -13
  58. data/ext/common/agents/Watchdog/Main.cpp +8 -3
  59. data/ext/libuv/.gitignore +72 -0
  60. data/ext/libuv/AUTHORS +199 -0
  61. data/ext/libuv/ChangeLog +2023 -0
  62. data/ext/libuv/LICENSE +46 -0
  63. data/ext/libuv/Makefile.am +336 -0
  64. data/ext/libuv/README.md +197 -0
  65. data/ext/libuv/checksparse.sh +233 -0
  66. data/ext/libuv/common.gypi +210 -0
  67. data/ext/libuv/configure.ac +67 -0
  68. data/ext/libuv/gyp_uv.py +96 -0
  69. data/ext/libuv/include/android-ifaddrs.h +54 -0
  70. data/ext/libuv/include/pthread-fixes.h +72 -0
  71. data/ext/libuv/include/tree.h +768 -0
  72. data/ext/libuv/include/uv-aix.h +32 -0
  73. data/ext/libuv/include/uv-bsd.h +34 -0
  74. data/ext/libuv/include/uv-darwin.h +61 -0
  75. data/ext/libuv/include/uv-errno.h +418 -0
  76. data/ext/libuv/include/uv-linux.h +34 -0
  77. data/ext/libuv/include/uv-sunos.h +44 -0
  78. data/ext/libuv/include/uv-threadpool.h +37 -0
  79. data/ext/libuv/include/uv-unix.h +383 -0
  80. data/ext/libuv/include/uv-version.h +39 -0
  81. data/ext/libuv/include/uv.h +1455 -0
  82. data/ext/libuv/libuv.pc.in +11 -0
  83. data/ext/libuv/m4/.gitignore +4 -0
  84. data/ext/libuv/m4/as_case.m4 +21 -0
  85. data/ext/libuv/m4/libuv-check-flags.m4 +319 -0
  86. data/ext/libuv/src/fs-poll.c +255 -0
  87. data/ext/libuv/src/heap-inl.h +245 -0
  88. data/ext/libuv/src/inet.c +313 -0
  89. data/ext/libuv/src/queue.h +92 -0
  90. data/ext/libuv/src/threadpool.c +303 -0
  91. data/ext/libuv/src/unix/aix.c +1240 -0
  92. data/ext/libuv/src/unix/android-ifaddrs.c +703 -0
  93. data/ext/libuv/src/unix/async.c +284 -0
  94. data/ext/libuv/src/unix/atomic-ops.h +60 -0
  95. data/ext/libuv/src/unix/core.c +985 -0
  96. data/ext/libuv/src/unix/darwin-proctitle.c +206 -0
  97. data/ext/libuv/src/unix/darwin.c +331 -0
  98. data/ext/libuv/src/unix/dl.c +83 -0
  99. data/ext/libuv/src/unix/freebsd.c +435 -0
  100. data/ext/libuv/src/unix/fs.c +1189 -0
  101. data/ext/libuv/src/unix/fsevents.c +899 -0
  102. data/ext/libuv/src/unix/getaddrinfo.c +202 -0
  103. data/ext/libuv/src/unix/getnameinfo.c +120 -0
  104. data/ext/libuv/src/unix/internal.h +314 -0
  105. data/ext/libuv/src/unix/kqueue.c +418 -0
  106. data/ext/libuv/src/unix/linux-core.c +876 -0
  107. data/ext/libuv/src/unix/linux-inotify.c +257 -0
  108. data/ext/libuv/src/unix/linux-syscalls.c +471 -0
  109. data/ext/libuv/src/unix/linux-syscalls.h +158 -0
  110. data/ext/libuv/src/unix/loop-watcher.c +63 -0
  111. data/ext/libuv/src/unix/loop.c +135 -0
  112. data/ext/libuv/src/unix/netbsd.c +368 -0
  113. data/ext/libuv/src/unix/openbsd.c +384 -0
  114. data/ext/libuv/src/unix/pipe.c +288 -0
  115. data/ext/libuv/src/unix/poll.c +113 -0
  116. data/ext/libuv/src/unix/process.c +551 -0
  117. data/ext/libuv/src/unix/proctitle.c +102 -0
  118. data/ext/libuv/src/unix/pthread-fixes.c +103 -0
  119. data/ext/libuv/src/unix/signal.c +465 -0
  120. data/ext/libuv/src/unix/spinlock.h +53 -0
  121. data/ext/libuv/src/unix/stream.c +1598 -0
  122. data/ext/libuv/src/unix/sunos.c +763 -0
  123. data/ext/libuv/src/unix/tcp.c +327 -0
  124. data/ext/libuv/src/unix/thread.c +519 -0
  125. data/ext/libuv/src/unix/timer.c +172 -0
  126. data/ext/libuv/src/unix/tty.c +265 -0
  127. data/ext/libuv/src/unix/udp.c +833 -0
  128. data/ext/libuv/src/uv-common.c +544 -0
  129. data/ext/libuv/src/uv-common.h +214 -0
  130. data/ext/libuv/src/version.c +49 -0
  131. data/ext/libuv/uv.gyp +487 -0
  132. data/ext/nginx/ContentHandler.c +21 -10
  133. data/ext/nginx/ngx_http_passenger_module.c +7 -0
  134. data/ext/oxt/implementation.cpp +9 -2
  135. data/ext/oxt/initialize.hpp +5 -1
  136. data/lib/phusion_passenger.rb +3 -3
  137. data/lib/phusion_passenger/admin_tools/instance.rb +10 -6
  138. data/lib/phusion_passenger/admin_tools/instance_registry.rb +6 -2
  139. data/lib/phusion_passenger/packaging.rb +3 -4
  140. data/lib/phusion_passenger/platform_info.rb +13 -1
  141. data/lib/phusion_passenger/platform_info/apache.rb +15 -4
  142. data/lib/phusion_passenger/platform_info/apache_detector.rb +5 -1
  143. data/lib/phusion_passenger/rack/thread_handler_extension.rb +184 -99
  144. data/lib/phusion_passenger/request_handler/thread_handler.rb +13 -6
  145. data/lib/phusion_passenger/standalone/start_command.rb +2 -2
  146. data/resources/templates/apache2/apache_install_broken.txt.erb +2 -1
  147. metadata +99 -22
  148. metadata.gz.asc +7 -7
  149. data/ext/libeio/Changes +0 -76
  150. data/ext/libeio/LICENSE +0 -36
  151. data/ext/libeio/Makefile.am +0 -15
  152. data/ext/libeio/Makefile.in +0 -694
  153. data/ext/libeio/aclocal.m4 +0 -9418
  154. data/ext/libeio/autogen.sh +0 -3
  155. data/ext/libeio/config.guess +0 -1540
  156. data/ext/libeio/config.h.in +0 -136
  157. data/ext/libeio/config.sub +0 -1779
  158. data/ext/libeio/configure +0 -14822
  159. data/ext/libeio/configure.ac +0 -22
  160. data/ext/libeio/demo.c +0 -194
  161. data/ext/libeio/ecb.h +0 -714
  162. data/ext/libeio/eio.c +0 -2818
  163. data/ext/libeio/eio.h +0 -414
  164. data/ext/libeio/install-sh +0 -520
  165. data/ext/libeio/libeio.m4 +0 -195
  166. data/ext/libeio/ltmain.sh +0 -9636
  167. data/ext/libeio/missing +0 -376
  168. data/ext/libeio/xthread.h +0 -166
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011, 2012 Phusion
3
+ * Copyright (c) 2011-2015 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -31,7 +31,7 @@
31
31
 
32
32
  extern "C" {
33
33
  struct ev_loop;
34
- struct ev_async;
34
+ struct uv_loop_s;
35
35
  }
36
36
 
37
37
  namespace Passenger {
@@ -45,12 +45,12 @@ namespace Passenger {
45
45
  * Implements a libev event loop that runs in a background thread.
46
46
  */
47
47
  struct BackgroundEventLoop {
48
- struct ev_loop *loop;
49
- ev_async *async;
48
+ struct ev_loop *libev_loop;
49
+ struct uv_loop_s *libuv_loop;
50
50
  boost::shared_ptr<SafeLibev> safe;
51
51
  BackgroundEventLoopPrivate *priv;
52
52
 
53
- BackgroundEventLoop(bool scalable = false, bool useLibeio = false);
53
+ BackgroundEventLoop(bool scalable = false, bool usesLibuv = true);
54
54
  ~BackgroundEventLoop();
55
55
 
56
56
  void start(const string &threadName = "", unsigned int stackSize = 1024 * 1024);
@@ -116,7 +116,7 @@
116
116
 
117
117
  #define PASSENGER_DEFAULT_USER "nobody"
118
118
 
119
- #define PASSENGER_VERSION "5.0.8"
119
+ #define PASSENGER_VERSION "5.0.9"
120
120
 
121
121
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
122
122
 
@@ -49,6 +49,7 @@ class InstanceDirectory {
49
49
  public:
50
50
  struct CreationOptions {
51
51
  string prefix;
52
+ uid_t originalUid;
52
53
  bool userSwitching;
53
54
  uid_t defaultUid;
54
55
  gid_t defaultGid;
@@ -56,6 +57,7 @@ public:
56
57
 
57
58
  CreationOptions()
58
59
  : prefix("passenger"),
60
+ originalUid(geteuid()),
59
61
  userSwitching(true),
60
62
  defaultUid(USER_NOT_GIVEN),
61
63
  defaultGid(GROUP_NOT_GIVEN)
@@ -108,17 +110,17 @@ private:
108
110
 
109
111
  void initializeInstanceDirectory(const CreationOptions &options) {
110
112
  createPropertyFile(options);
111
- createAgentSocketsSubdir();
113
+ createAgentSocketsSubdir(options);
112
114
  createAppSocketsSubdir(options);
113
115
  createLockFile();
114
116
  }
115
117
 
116
- bool runningAsRoot() const {
117
- return geteuid() == 0;
118
+ bool runningAsRoot(const CreationOptions &options) const {
119
+ return options.originalUid == 0;
118
120
  }
119
121
 
120
- void createAgentSocketsSubdir() {
121
- if (runningAsRoot()) {
122
+ void createAgentSocketsSubdir(const CreationOptions &options) {
123
+ if (runningAsRoot(options)) {
122
124
  /* The server socket must be accessible by the web server
123
125
  * and by the apps, which may run as complete different users,
124
126
  * so this subdirectory must be world-accessible.
@@ -130,7 +132,7 @@ private:
130
132
  }
131
133
 
132
134
  void createAppSocketsSubdir(const CreationOptions &options) {
133
- if (runningAsRoot()) {
135
+ if (runningAsRoot(options)) {
134
136
  if (options.userSwitching) {
135
137
  /* Each app may be running as a different user,
136
138
  * so the apps.s subdirectory must be world-writable.
@@ -35,6 +35,10 @@
35
35
  #include <Utils/json.h>
36
36
  #include <Utils/JsonUtils.h>
37
37
 
38
+ extern "C" {
39
+ struct uv_loop_s;
40
+ }
41
+
38
42
  namespace Passenger {
39
43
  namespace ServerKit {
40
44
 
@@ -66,12 +70,14 @@ private:
66
70
 
67
71
  public:
68
72
  SafeLibevPtr libev;
73
+ struct uv_loop_s *libuv;
69
74
  struct MemoryKit::mbuf_pool mbuf_pool;
70
75
  string secureModePassword;
71
76
  FileBufferedChannelConfig defaultFileBufferedChannelConfig;
72
77
 
73
- Context(const SafeLibevPtr &_libev)
74
- : libev(_libev)
78
+ Context(const SafeLibevPtr &_libev, struct uv_loop_s *_libuv)
79
+ : libev(_libev),
80
+ libuv(_libuv)
75
81
  {
76
82
  initialize();
77
83
  }
@@ -31,7 +31,7 @@
31
31
  #include <boost/move/move.hpp>
32
32
  #include <boost/atomic.hpp>
33
33
  #include <sys/types.h>
34
- #include <eio.h>
34
+ #include <uv.h>
35
35
  #include <cassert>
36
36
  #include <cstddef>
37
37
  #include <cstring>
@@ -58,6 +58,13 @@ using namespace std;
58
58
  #define FBC_DEBUG_FROM_STATIC(expr) \
59
59
  P_TRACE(3, "[FBC " << (void *) self << "] " << expr)
60
60
 
61
+ #define FBC_DEBUG_FROM_CALLBACK(context, expr) \
62
+ P_TRACE(3, "[FBC " << (void *) context->logbase << "] " << expr)
63
+ #define FBC_ERROR_FROM_CALLBACK(context, expr) \
64
+ P_ERROR("[FBC " << (void *) context->logbase << "] " << expr)
65
+ #define FBC_CRITICAL_FROM_CALLBACK(context, expr) \
66
+ P_CRITICAL("[FBC " << (void *) context->logbase << "] " << expr)
67
+
61
68
 
62
69
  /**
63
70
  * Adds "unlimited" buffering capability to a Channel. A Channel has a buffer size
@@ -196,51 +203,81 @@ public:
196
203
 
197
204
 
198
205
  private:
199
- struct IOContext {
206
+ /**
207
+ * A structure containing the details of a libuv asynchronous
208
+ * filesystem I/O request.
209
+ *
210
+ * The I/O callback is responsible for destroying its corresponding
211
+ * FileIOContext object.
212
+ */
213
+ struct FileIOContext {
214
+ /**
215
+ * A back pointer to the FileBufferedChannel that created this
216
+ * IOContext.
217
+ *
218
+ * This pointer is set to NULL when this I/O operation is
219
+ * canceled (through the `cancel()` method). Cancelation
220
+ * occurs when the FileBufferedChannel is about to be deinitialized.
221
+ * So be sure to check for cancellation (using `isCanceled`)
222
+ * before using the backpointer.
223
+ */
200
224
  FileBufferedChannel *self;
201
- SafeLibevPtr libev;
202
- eio_req *req;
203
- boost::atomic<bool> canceled;
204
225
  /**
205
- * Synchronizes access to `req`. Because all I/O callbacks call
206
- * `eioFinished()`, this mutex blocks callbacks until the main
207
- * thread is done assigning `req`.
208
- * See https://github.com/phusion/passenger/issues/1326
226
+ * Pointers to the libev and libuv loops that this FileBufferedChannel
227
+ * used. We keep the pointers here so that callbacks can perform
228
+ * asynchronous I/O operations as part of their cleanup, even in the
229
+ * event the original I/O operation is canceled.
230
+ *
231
+ * I/O callbacks do not have to worry about whether these pointers are
232
+ * stale, because callbacks are run inside the event loop, and we stop the
233
+ * event loop before destryoing it.
209
234
  */
210
- boost::mutex syncher;
235
+ SafeLibevPtr libev;
236
+ uv_loop_t *libuv;
237
+ /* req.data always refers back to the FileIOContext object itself. */
238
+ uv_fs_t req;
211
239
 
212
- eio_ssize_t result;
213
- int errcode;
240
+ /**
241
+ * Also a pointer to the FileBufferedChannel, but this is used for
242
+ * logging purposes inside callbacks (see FBC_DEBUG_FROM_CALLBACK).
243
+ * This pointer is never set to NULL, may be still, and is never
244
+ * followed.
245
+ */
246
+ void *logbase;
214
247
 
215
- IOContext(FileBufferedChannel *_self)
248
+ FileIOContext(FileBufferedChannel *_self)
216
249
  : self(_self),
217
250
  libev(_self->ctx->libev),
218
- req(NULL),
219
- canceled(false),
220
- result(-1),
221
- errcode(-1)
222
- { }
251
+ libuv(_self->ctx->libuv),
252
+ logbase(_self)
253
+ {
254
+ req.type = UV_UNKNOWN_REQ;
255
+ req.result = -1;
256
+ req.data = this;
257
+ }
223
258
 
224
- virtual ~IOContext() { }
259
+ virtual ~FileIOContext() { }
225
260
 
226
261
  void cancel() {
227
- boost::lock_guard<boost::mutex> l(syncher);
228
- if (req != NULL) {
229
- eio_cancel(req);
262
+ if (!isCanceled()) {
263
+ // uv_cancel() fails if the work is already in progress
264
+ // or completed, so we set self to NULL as an extra
265
+ // indicator that this I/O operation is canceled.
266
+ uv_cancel((uv_req_t *) &req);
267
+ self = NULL;
230
268
  }
231
- canceled.store(true, boost::memory_order_release);
232
269
  }
233
270
 
271
+ /**
272
+ * Checks whether this I/O operation has been canceled.
273
+ * Note that the libuv request may not have been canceled
274
+ * because it was already executing at the time `cancel()`
275
+ * was called. So after you've checked that `isCanceled()`
276
+ * returns true, you must also cleanup any potential finished
277
+ * work in `req`.
278
+ */
234
279
  bool isCanceled() const {
235
- return (req != NULL && EIO_CANCELLED(req))
236
- || canceled.load(boost::memory_order_acquire);
237
- }
238
-
239
- void eioFinished() {
240
- boost::lock_guard<boost::mutex> l(syncher);
241
- result = req->result;
242
- errcode = req->errorno;
243
- req = NULL;
280
+ return self == NULL || req.result == UV_ECANCELED;
244
281
  }
245
282
  };
246
283
 
@@ -254,9 +291,9 @@ private:
254
291
  * fast case where the consumer can keep up with the writes.
255
292
  * - We improve the clarity of the code by clearly grouping variables
256
293
  * that are only used in the in-file mode.
257
- * - While eio operations are in progress, they hold a smart pointer to the
294
+ * - While libuv operations are in progress, they hold a smart pointer to the
258
295
  * InFileMode structure, which ensures that the file descriptor that they
259
- * operate on stays open until all eio operations have finished (or until
296
+ * operate on stays open until all libuv operations have finished (or until
260
297
  * their cancellation have been acknowledged by their callbacks).
261
298
  *
262
299
  * The variables inside this structure point to different places in the file:
@@ -282,6 +319,11 @@ private:
282
319
  struct InFileMode {
283
320
  /***** Common state *****/
284
321
 
322
+ /**
323
+ * The libuv loop associated with the FileBufferedChannel.
324
+ */
325
+ uv_loop_t *libuv;
326
+
285
327
  /**
286
328
  * The file descriptor of the temp file. It's -1 if the file is being
287
329
  * created.
@@ -306,12 +348,12 @@ private:
306
348
 
307
349
  /**
308
350
  * The write operation that the writer is currently performing. Might be
309
- * an `eio_open()`, `eio_write()`, or whatever.
351
+ * an `uv_fs_open()`, `uv_fs_write()`, or whatever.
310
352
  *
311
353
  * @invariant
312
354
  * (writerRequest != NULL) == (writerState == WS_CREATING_FILE || writerState == WS_MOVING)
313
355
  */
314
- IOContext *writerRequest;
356
+ FileIOContext *writerRequest;
315
357
 
316
358
  /**
317
359
  * Number of bytes already read from the file by the reader.
@@ -331,8 +373,9 @@ private:
331
373
  */
332
374
  boost::int64_t written;
333
375
 
334
- InFileMode()
335
- : fd(-1),
376
+ InFileMode(uv_loop_t *_libuv)
377
+ : libuv(_libuv),
378
+ fd(-1),
336
379
  readRequest(NULL),
337
380
  writerState(WS_INACTIVE),
338
381
  writerRequest(NULL),
@@ -344,10 +387,32 @@ private:
344
387
  P_ASSERT_EQ(readRequest, 0);
345
388
  P_ASSERT_EQ(writerRequest, 0);
346
389
  if (fd != -1) {
347
- P_LOG_FILE_DESCRIPTOR_CLOSE(fd);
348
- eio_close(fd, 0, NULL, NULL);
390
+ closeFdInBackground();
391
+ }
392
+ }
393
+
394
+ void closeFdInBackground() {
395
+ uv_fs_t *req = (uv_fs_t *) malloc(sizeof(uv_fs_t));
396
+ if (req == NULL) {
397
+ P_CRITICAL("Cannot close file descriptor for FileBufferedChannel temp file: "
398
+ "cannot allocate memory for necessary temporary data structure");
399
+ abort();
400
+ }
401
+
402
+ int result = uv_fs_close(libuv, req, fd, fileClosed);
403
+ if (result != 0) {
404
+ P_CRITICAL("Cannot close file descriptor for FileBufferedChannel temp file: "
405
+ "cannot initiate I/O operation: "
406
+ << uv_strerror(result) << " (errno=" << -result << ")");
407
+ abort();
349
408
  }
350
409
  }
410
+
411
+ static void fileClosed(uv_fs_t *req) {
412
+ P_LOG_FILE_DESCRIPTOR_CLOSE(req->file);
413
+ uv_fs_req_cleanup(req);
414
+ free(req);
415
+ }
351
416
  };
352
417
 
353
418
  FileBufferedChannelConfig *config;
@@ -642,14 +707,15 @@ private:
642
707
  terminateReaderBecauseOfEOF();
643
708
  }
644
709
 
645
- struct ReadContext: public IOContext {
710
+ struct ReadContext: public FileIOContext {
646
711
  MemoryKit::mbuf buffer;
647
- // Smart pointer to keep fd open until eio operation
712
+ uv_buf_t uvBuffer;
713
+ // Smart pointer to keep fd open until libuv operation
648
714
  // is finished.
649
715
  boost::shared_ptr<InFileMode> inFileMode;
650
716
 
651
717
  ReadContext(FileBufferedChannel *self)
652
- : IOContext(self)
718
+ : FileIOContext(self)
653
719
  { }
654
720
  };
655
721
 
@@ -665,57 +731,25 @@ private:
665
731
  ReadContext *readContext = new ReadContext(this);
666
732
  readContext->buffer = MemoryKit::mbuf_get(&ctx->mbuf_pool);
667
733
  readContext->inFileMode = inFileMode;
734
+ readContext->uvBuffer = uv_buf_init(readContext->buffer.start, size);
668
735
  readerState = RS_READING_FROM_FILE;
669
736
  inFileMode->readRequest = readContext;
670
- boost::unique_lock<boost::mutex> l(readContext->syncher);
671
- readContext->req = eio_read(inFileMode->fd, readContext->buffer.start,
672
- size, inFileMode->readOffset, 0, _nextChunkDoneReading, readContext);
673
- l.unlock();
674
- verifyInvariants();
675
- }
676
-
677
- // Since a ReadContext contains an mbuf, we may only destroy it
678
- // in the event loop thread.
679
- static void destroyReadContext(ReadContext *readContext) {
680
- if (readContext->libev->onEventLoopThread()) {
681
- destroyReadContext_onEventLoopThread(readContext);
682
- } else {
683
- readContext->libev->runLater(boost::bind(
684
- destroyReadContext_onEventLoopThread,
685
- readContext));
686
- }
687
- }
688
737
 
689
- static void destroyReadContext_onEventLoopThread(ReadContext *readContext) {
690
- delete readContext;
738
+ uv_fs_read(ctx->libuv, &readContext->req, inFileMode->fd,
739
+ &readContext->uvBuffer, 1, inFileMode->readOffset,
740
+ _nextChunkDoneReading);
741
+ verifyInvariants();
691
742
  }
692
743
 
693
- static int _nextChunkDoneReading(eio_req *req) {
744
+ static void _nextChunkDoneReading(uv_fs_t *req) {
694
745
  ReadContext *readContext = (ReadContext *) req->data;
695
- readContext->eioFinished();
746
+ uv_fs_req_cleanup(req);
696
747
  if (readContext->isCanceled()) {
697
- destroyReadContext(readContext);
698
- return 0;
699
- }
700
-
701
- if (readContext->libev->onEventLoopThread()) {
702
- _nextChunkDoneReading_onEventLoopThread(readContext);
703
- } else {
704
- readContext->libev->runLater(boost::bind(
705
- _nextChunkDoneReading_onEventLoopThread,
706
- readContext));
707
- }
708
- return 0;
709
- }
710
-
711
- static void _nextChunkDoneReading_onEventLoopThread(ReadContext *readContext) {
712
- if (readContext->isCanceled()) {
713
- destroyReadContext(readContext);
748
+ delete readContext;
714
749
  return;
715
750
  }
716
751
 
717
- FileBufferedChannel *self = readContext->self;
718
- self->nextChunkDoneReading(readContext);
752
+ readContext->self->nextChunkDoneReading(readContext);
719
753
  }
720
754
 
721
755
  void nextChunkDoneReading(ReadContext *readContext) {
@@ -724,13 +758,12 @@ private:
724
758
  FBC_DEBUG("Reader: done reading chunk");
725
759
  P_ASSERT_EQ(readerState, RS_READING_FROM_FILE);
726
760
  verifyInvariants();
727
- int fd = readContext->result;
728
- int errcode = readContext->errcode;
729
761
  MemoryKit::mbuf buffer(boost::move(readContext->buffer));
730
- destroyReadContext(readContext);
762
+ delete readContext;
731
763
  inFileMode->readRequest = NULL;
732
764
 
733
- if (fd != -1) {
765
+ if (readContext->req.result >= 0) {
766
+ int fd = readContext->req.result;
734
767
  unsigned int generation = this->generation;
735
768
 
736
769
  assert(fd <= inFileMode->written);
@@ -757,6 +790,7 @@ private:
757
790
  terminateReaderBecauseOfEOF();
758
791
  }
759
792
  } else {
793
+ int errcode = -readContext->req.result;
760
794
  setError(errcode, __FILE__, __LINE__);
761
795
  }
762
796
  }
@@ -800,7 +834,7 @@ private:
800
834
 
801
835
  FBC_DEBUG("Switching to in-file mode");
802
836
  mode = IN_FILE_MODE;
803
- inFileMode = boost::make_shared<InFileMode>();
837
+ inFileMode = boost::make_shared<InFileMode>(ctx->libuv);
804
838
  createBufferFile();
805
839
  }
806
840
 
@@ -826,11 +860,11 @@ private:
826
860
 
827
861
  /***** File creator *****/
828
862
 
829
- struct FileCreationContext: public IOContext {
863
+ struct FileCreationContext: public FileIOContext {
830
864
  string path;
831
865
 
832
866
  FileCreationContext(FileBufferedChannel *self)
833
- : IOContext(self)
867
+ : FileIOContext(self)
834
868
  { }
835
869
  };
836
870
 
@@ -847,41 +881,28 @@ private:
847
881
  inFileMode->writerState = WS_CREATING_FILE;
848
882
  inFileMode->writerRequest = fcContext;
849
883
 
850
- boost::lock_guard<boost::mutex> l(fcContext->syncher);
851
884
  if (config->delayInFileModeSwitching == 0) {
852
885
  FBC_DEBUG("Writer: creating file " << fcContext->path);
853
- fcContext->req = eio_open(fcContext->path.c_str(),
854
- O_RDWR | O_CREAT | O_EXCL, 0600, 0,
855
- _bufferFileCreated, fcContext);
886
+ int result = uv_fs_open(ctx->libuv, &fcContext->req,
887
+ fcContext->path.c_str(), O_RDWR | O_CREAT | O_EXCL,
888
+ 0600, _bufferFileCreated);
889
+ if (result != 0) {
890
+ fcContext->req.result = result;
891
+ ctx->libev->runLater(boost::bind(_bufferFileCreated,
892
+ &fcContext->req));
893
+ }
856
894
  } else {
857
895
  FBC_DEBUG("Writer: delaying in-file mode switching for " <<
858
896
  config->delayInFileModeSwitching << "ms");
859
- fcContext->req = eio_busy(
860
- (eio_tstamp) config->delayInFileModeSwitching / 1000.0,
861
- 0, _bufferFileDoneDelaying, fcContext);
862
- }
863
- }
864
-
865
- static int _bufferFileDoneDelaying(eio_req *req) {
866
- FileCreationContext *fcContext = static_cast<FileCreationContext *>(req->data);
867
- fcContext->eioFinished();
868
- if (fcContext->isCanceled()) {
869
- delete fcContext;
870
- return 0;
897
+ ctx->libev->runAfter(config->delayInFileModeSwitching,
898
+ boost::bind(_bufferFileDoneDelaying, fcContext));
871
899
  }
872
-
873
- if (fcContext->libev->onEventLoopThread()) {
874
- _bufferFileDoneDelaying_onEventLoopThread(fcContext);
875
- } else {
876
- fcContext->libev->runLater(boost::bind(
877
- _bufferFileDoneDelaying_onEventLoopThread,
878
- fcContext));
879
- }
880
- return 0;
881
900
  }
882
901
 
883
- static void _bufferFileDoneDelaying_onEventLoopThread(FileCreationContext *fcContext) {
902
+ static void _bufferFileDoneDelaying(FileCreationContext *fcContext) {
884
903
  if (fcContext->isCanceled()) {
904
+ // We don't cleanup fcContext->req here because we didn't
905
+ // start a libuv request.
885
906
  delete fcContext;
886
907
  return;
887
908
  }
@@ -891,72 +912,52 @@ private:
891
912
  }
892
913
 
893
914
  void bufferFileDoneDelaying(FileCreationContext *fcContext) {
894
- boost::lock_guard<boost::mutex> l(fcContext->syncher);
895
915
  FBC_DEBUG("Writer: done delaying in-file mode switching. "
896
916
  "Creating file: " << fcContext->path);
897
- fcContext->req = eio_open(fcContext->path.c_str(),
898
- O_RDWR | O_CREAT | O_EXCL, 0600, 0,
899
- _bufferFileCreated, fcContext);
900
- }
901
-
902
- static int _bufferFileCreated(eio_req *req) {
903
- FileCreationContext *fcContext = static_cast<FileCreationContext *>(req->data);
904
- fcContext->eioFinished();
905
- if (fcContext->isCanceled()) {
906
- if (req->result != -1) {
907
- FileBufferedChannel *self = fcContext->self;
908
- FBC_DEBUG_FROM_STATIC("Writer: creation of file " << fcContext->path <<
909
- "canceled. Deleting file in the background");
910
- eio_unlink(fcContext->path.c_str(), 0, bufferFileUnlinked, fcContext);
911
- eio_close(req->result, 0, NULL, NULL);
912
- } else {
913
- delete fcContext;
914
- }
915
- return 0;
917
+ int result = uv_fs_open(ctx->libuv, &fcContext->req,
918
+ fcContext->path.c_str(), O_RDWR | O_CREAT | O_EXCL,
919
+ 0600, _bufferFileCreated);
920
+ if (result != 0) {
921
+ fcContext->req.result = result;
922
+ _bufferFileCreated(&fcContext->req);
916
923
  }
917
-
918
- if (fcContext->libev->onEventLoopThread()) {
919
- _bufferFileCreated_onEventLoopThread(fcContext);
920
- } else {
921
- fcContext->libev->runLater(boost::bind(
922
- _bufferFileCreated_onEventLoopThread,
923
- fcContext));
924
- }
925
- return 0;
926
924
  }
927
925
 
928
- static void _bufferFileCreated_onEventLoopThread(FileCreationContext *fcContext) {
926
+ static void _bufferFileCreated(uv_fs_t *req) {
927
+ FileCreationContext *fcContext = static_cast<FileCreationContext *>(req->data);
928
+ uv_fs_req_cleanup(req);
929
929
  if (fcContext->isCanceled()) {
930
- if (fcContext->result != -1) {
931
- FileBufferedChannel *self = fcContext->self;
932
- FBC_DEBUG_FROM_STATIC("Writer: creation of file " << fcContext->path <<
930
+ if (req->result >= 0) {
931
+ FBC_DEBUG_FROM_CALLBACK(fcContext,
932
+ "Writer: creation of file " << fcContext->path <<
933
933
  "canceled. Deleting file in the background");
934
- eio_unlink(fcContext->path.c_str(), 0, bufferFileUnlinked, fcContext);
935
- eio_close(fcContext->result, 0, NULL, NULL);
934
+ closeBufferFileInBackground(fcContext);
935
+ // Will take care of deleting fcContext
936
+ unlinkBufferFileInBackground(fcContext);
936
937
  } else {
937
938
  delete fcContext;
938
939
  }
939
940
  return;
940
941
  }
941
942
 
942
- FileBufferedChannel *self = fcContext->self;
943
- self->bufferFileCreated(fcContext);
943
+ fcContext->self->bufferFileCreated(fcContext);
944
944
  }
945
945
 
946
946
  void bufferFileCreated(FileCreationContext *fcContext) {
947
947
  P_ASSERT_EQ(inFileMode->writerState, WS_CREATING_FILE);
948
948
  verifyInvariants();
949
- int fd = fcContext->result;
950
- int errcode = fcContext->errcode;
951
949
  inFileMode->writerRequest = NULL;
952
950
 
953
- if (fd != -1) {
951
+ if (fcContext->req.result >= 0) {
954
952
  FBC_DEBUG("Writer: file created. Deleting file in the background");
955
- P_LOG_FILE_DESCRIPTOR_OPEN4(fd, __FILE__, __LINE__, "FileBufferedChannel buffer file");
956
- eio_unlink(fcContext->path.c_str(), 0, bufferFileUnlinked, fcContext);
957
- inFileMode->fd = fd;
953
+ P_LOG_FILE_DESCRIPTOR_OPEN4(fcContext->req.result, __FILE__, __LINE__,
954
+ "FileBufferedChannel buffer file");
955
+ inFileMode->fd = fcContext->req.result;
956
+ // Will take care of deleting fcContext
957
+ unlinkBufferFileInBackground(fcContext);
958
958
  moveNextBufferToFile();
959
959
  } else {
960
+ int errcode = -fcContext->req.result;
960
961
  delete fcContext;
961
962
  if (errcode == EEXIST) {
962
963
  FBC_DEBUG("Writer: file already exists, retrying");
@@ -969,38 +970,97 @@ private:
969
970
  }
970
971
  }
971
972
 
972
- static int bufferFileUnlinked(eio_req *req) {
973
+ static void closeBufferFileInBackground(FileCreationContext *fcContext) {
974
+ // Do not use fcContext->self in here. This method may be called
975
+ // when the I/O operation is already canceled.
976
+
977
+ assert(fcContext->req.result >= 0);
978
+
979
+ uv_fs_t *closeReq = (uv_fs_t *) malloc(sizeof(uv_fs_t));
980
+ if (closeReq == NULL) {
981
+ FBC_CRITICAL_FROM_CALLBACK(fcContext,
982
+ "Cannot close file descriptor for " << fcContext->path
983
+ << ": cannot allocate memory for necessary temporary data structure");
984
+ abort();
985
+ }
986
+
987
+ int result = uv_fs_close(fcContext->libuv, closeReq, fcContext->req.result,
988
+ bufferFileClosed);
989
+ if (result != 0) {
990
+ FBC_CRITICAL_FROM_CALLBACK(fcContext,
991
+ "Cannot close file descriptor for " << fcContext->path
992
+ << ": cannot initiate I/O operation: "
993
+ << uv_strerror(result) << " (errno=" << -result << ")");
994
+ abort();
995
+ }
996
+ }
997
+
998
+ static void unlinkBufferFileInBackground(FileCreationContext *fcContext) {
999
+ // Nobody will cancel this unlink operation. We set self to NULL
1000
+ // here as a warning that we should not use the backpointer.
1001
+ fcContext->self = NULL;
1002
+
1003
+ uv_fs_t *unlinkReq = (uv_fs_t *) malloc(sizeof(uv_fs_t));
1004
+ if (unlinkReq == NULL) {
1005
+ FBC_ERROR_FROM_CALLBACK(fcContext,
1006
+ "Cannot delete " << fcContext->path <<
1007
+ ": cannot allocate memory for necessary temporary data structure");
1008
+ delete fcContext;
1009
+ } else {
1010
+ unlinkReq->data = fcContext;
1011
+ int result = uv_fs_unlink(fcContext->libuv, unlinkReq, fcContext->path.c_str(),
1012
+ bufferFileUnlinked);
1013
+ if (result != 0) {
1014
+ FBC_ERROR_FROM_CALLBACK(fcContext,
1015
+ "Cannot delete " << fcContext->path << ": cannot initiate I/O operation: "
1016
+ << uv_strerror(result) << " (errno=" << -result << ")");
1017
+ free(unlinkReq);
1018
+ delete fcContext;
1019
+ }
1020
+ }
1021
+ }
1022
+
1023
+ static void bufferFileUnlinked(uv_fs_t *req) {
973
1024
  FileCreationContext *fcContext = static_cast<FileCreationContext *>(req->data);
974
- FileBufferedChannel *self = fcContext->self;
1025
+ assert(fcContext->self == NULL);
975
1026
 
976
- if (fcContext->isCanceled()) {
1027
+ if (req->result == UV_ECANCELED) {
1028
+ uv_fs_req_cleanup(req);
977
1029
  delete fcContext;
978
- return 0;
1030
+ return;
979
1031
  }
980
1032
 
981
- if (req->result != -1) {
982
- FBC_DEBUG_FROM_STATIC("Writer: file " << fcContext->path << " deleted");
1033
+ if (req->result >= 0) {
1034
+ FBC_DEBUG_FROM_CALLBACK(fcContext,
1035
+ "Writer: file " << fcContext->path << " deleted");
983
1036
  } else {
984
- FBC_DEBUG_FROM_STATIC("Writer: failed to delete " << fcContext->path <<
985
- ": errno=" << req->errorno << " (" << strerror(req->errorno) << ")");
1037
+ FBC_DEBUG_FROM_CALLBACK(fcContext,
1038
+ "Writer: failed to delete " << fcContext->path <<
1039
+ ": " << uv_strerror(req->result) << " (errno=" << -req->result << ")");
986
1040
  }
987
1041
 
1042
+ uv_fs_req_cleanup(req);
988
1043
  delete fcContext;
989
- return 0;
1044
+ }
1045
+
1046
+ static void bufferFileClosed(uv_fs_t *req) {
1047
+ uv_fs_req_cleanup(req);
1048
+ free(req);
990
1049
  }
991
1050
 
992
1051
 
993
1052
  /***** Mover *****/
994
1053
 
995
- struct MoveContext: public IOContext {
996
- // Smart pointer to keep fd open until eio operation
1054
+ struct MoveContext: public FileIOContext {
1055
+ // Smart pointer to keep fd open until libuv operation
997
1056
  // is finished.
998
1057
  boost::shared_ptr<InFileMode> inFileMode;
999
1058
  MemoryKit::mbuf buffer;
1059
+ uv_buf_t uvBuffer;
1000
1060
  size_t written;
1001
1061
 
1002
1062
  MoveContext(FileBufferedChannel *self)
1003
- : IOContext(self)
1063
+ : FileIOContext(self)
1004
1064
  { }
1005
1065
  };
1006
1066
 
@@ -1026,61 +1086,32 @@ private:
1026
1086
  moveContext->inFileMode = inFileMode;
1027
1087
  moveContext->buffer = peekBuffer();
1028
1088
  moveContext->written = 0;
1089
+ moveContext->uvBuffer = uv_buf_init(moveContext->buffer.start,
1090
+ moveContext->buffer.size());
1029
1091
 
1030
1092
  inFileMode->writerState = WS_MOVING;
1031
1093
  inFileMode->writerRequest = moveContext;
1032
- boost::unique_lock<boost::mutex> l(moveContext->syncher);
1033
- moveContext->req = eio_write(inFileMode->fd,
1034
- moveContext->buffer.start,
1035
- moveContext->buffer.size(),
1094
+ int result = uv_fs_write(ctx->libuv, &moveContext->req, inFileMode->fd,
1095
+ &moveContext->uvBuffer, 1,
1036
1096
  inFileMode->readOffset + inFileMode->written,
1037
- 0, _bufferWrittenToFile, moveContext);
1038
- l.unlock();
1039
- verifyInvariants();
1040
- }
1041
-
1042
- // Since a MoveContext contains an mbuf, we may only destroy it
1043
- // in the event loop thread.
1044
- static void destroyMoveContext(MoveContext *moveContext) {
1045
- if (moveContext->libev->onEventLoopThread()) {
1046
- destroyMoveContext_onEventLoopThread(moveContext);
1047
- } else {
1048
- moveContext->libev->runLater(boost::bind(
1049
- destroyMoveContext_onEventLoopThread,
1050
- moveContext));
1097
+ _bufferWrittenToFile);
1098
+ if (result != 0) {
1099
+ moveContext->req.result = result;
1100
+ ctx->libev->runLater(boost::bind(_bufferWrittenToFile,
1101
+ &moveContext->req));
1051
1102
  }
1103
+ verifyInvariants();
1052
1104
  }
1053
1105
 
1054
- static void destroyMoveContext_onEventLoopThread(MoveContext *moveContext) {
1055
- delete moveContext;
1056
- }
1057
-
1058
- static int _bufferWrittenToFile(eio_req *req) {
1106
+ static void _bufferWrittenToFile(uv_fs_t *req) {
1059
1107
  MoveContext *moveContext = static_cast<MoveContext *>(req->data);
1060
- moveContext->eioFinished();
1108
+ uv_fs_req_cleanup(req);
1061
1109
  if (moveContext->isCanceled()) {
1062
- destroyMoveContext(moveContext);
1063
- return 0;
1064
- }
1065
-
1066
- if (moveContext->libev->onEventLoopThread()) {
1067
- _bufferWrittenToFile_onEventLoopThread(moveContext);
1068
- } else {
1069
- moveContext->libev->runLater(boost::bind(
1070
- _bufferWrittenToFile_onEventLoopThread,
1071
- moveContext));
1072
- }
1073
- return 0;
1074
- }
1075
-
1076
- static void _bufferWrittenToFile_onEventLoopThread(MoveContext *moveContext) {
1077
- if (moveContext->isCanceled()) {
1078
- destroyMoveContext(moveContext);
1110
+ delete moveContext;
1079
1111
  return;
1080
1112
  }
1081
1113
 
1082
- FileBufferedChannel *self = moveContext->self;
1083
- self->bufferWrittenToFile(moveContext);
1114
+ moveContext->self->bufferWrittenToFile(moveContext);
1084
1115
  }
1085
1116
 
1086
1117
  void bufferWrittenToFile(MoveContext *moveContext) {
@@ -1089,8 +1120,8 @@ private:
1089
1120
  assert(!peekBuffer().empty());
1090
1121
  verifyInvariants();
1091
1122
 
1092
- if (moveContext->result != -1) {
1093
- moveContext->written += moveContext->result;
1123
+ if (moveContext->req.result >= 0) {
1124
+ moveContext->written += moveContext->req.result;
1094
1125
  assert(moveContext->written <= moveContext->buffer.size());
1095
1126
 
1096
1127
  if (moveContext->written == moveContext->buffer.size()) {
@@ -1106,29 +1137,34 @@ private:
1106
1137
  if (generation != this->generation || mode >= ERROR) {
1107
1138
  // buffersFlushedCallback deinitialized this object, or callback
1108
1139
  // called a method that encountered an error.
1109
- destroyMoveContext(moveContext);
1140
+ delete moveContext;
1110
1141
  return;
1111
1142
  }
1112
1143
 
1113
1144
  inFileMode->writerRequest = NULL;
1114
- destroyMoveContext(moveContext);
1145
+ delete moveContext;
1115
1146
  moveNextBufferToFile();
1116
1147
  } else {
1117
1148
  FBC_DEBUG("Writer: move incomplete, proceeding " <<
1118
1149
  "with writing rest of buffer");
1119
- boost::unique_lock<boost::mutex> l(moveContext->syncher);
1120
- moveContext->req = eio_write(inFileMode->fd,
1150
+ moveContext->uvBuffer = uv_buf_init(
1121
1151
  moveContext->buffer.start + moveContext->written,
1122
- moveContext->buffer.size() - moveContext->written,
1152
+ moveContext->buffer.size() - moveContext->written);
1153
+ int result = uv_fs_write(ctx->libuv, &moveContext->req,
1154
+ inFileMode->fd, &moveContext->uvBuffer, 1,
1123
1155
  inFileMode->readOffset + inFileMode->written,
1124
- 0, _bufferWrittenToFile, moveContext);
1125
- l.unlock();
1156
+ _bufferWrittenToFile);
1157
+ if (result != 0) {
1158
+ moveContext->req.result = result;
1159
+ ctx->libev->runLater(boost::bind(_bufferWrittenToFile,
1160
+ &moveContext->req));
1161
+ }
1126
1162
  verifyInvariants();
1127
1163
  }
1128
1164
  } else {
1129
1165
  FBC_DEBUG("Writer: file write failed");
1130
- int errcode = moveContext->errcode;
1131
- destroyMoveContext(moveContext);
1166
+ int errcode = -moveContext->req.result;
1167
+ delete moveContext;
1132
1168
  inFileMode->writerRequest = NULL;
1133
1169
  inFileMode->writerState = WS_TERMINATED;
1134
1170
  setError(errcode, __FILE__, __LINE__);