passenger 5.0.25 → 5.0.26

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +20 -0
  3. data/CONTRIBUTORS +1 -0
  4. data/build/cxx_dependency_map.rb +7338 -7104
  5. data/build/cxx_tests.rb +3 -3
  6. data/build/misc.rb +1 -0
  7. data/dev/index_cxx_dependencies.rb +3 -2
  8. data/resources/templates/standalone/config.erb +1 -1
  9. data/resources/templates/standalone/http.erb +1 -0
  10. data/resources/templates/standalone/server.erb +1 -0
  11. data/src/agent/Core/ApplicationPool/AbstractSession.h +83 -0
  12. data/src/agent/Core/ApplicationPool/Common.h +6 -4
  13. data/src/agent/Core/ApplicationPool/Options.h +4 -1
  14. data/src/agent/Core/ApplicationPool/Pool.h +2 -2
  15. data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +3 -6
  16. data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +3 -3
  17. data/src/agent/Core/ApplicationPool/Session.h +15 -27
  18. data/src/agent/Core/ApplicationPool/TestSession.h +188 -0
  19. data/src/agent/Core/Controller.h +15 -6
  20. data/src/agent/Core/Controller/CheckoutSession.cpp +13 -5
  21. data/src/agent/Core/Controller/ForwardResponse.cpp +20 -2
  22. data/src/agent/Core/Controller/Hooks.cpp +15 -2
  23. data/src/agent/Core/Controller/InitRequest.cpp +5 -1
  24. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +1 -0
  25. data/src/agent/Core/Controller/Request.h +11 -4
  26. data/src/agent/Core/Controller/SendRequest.cpp +34 -13
  27. data/src/agent/Core/Controller/StateInspectionAndConfiguration.cpp +2 -2
  28. data/src/agent/Core/CoreMain.cpp +27 -1
  29. data/src/agent/Core/OptionParser.h +11 -1
  30. data/src/agent/Core/SpawningKit/DirectSpawner.h +1 -0
  31. data/src/agent/Core/SpawningKit/SmartSpawner.h +1 -0
  32. data/src/agent/Core/SpawningKit/Spawner.h +21 -1
  33. data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +1 -1
  34. data/src/agent/UstRouter/OptionParser.h +7 -1
  35. data/src/agent/UstRouter/UstRouterMain.cpp +27 -1
  36. data/src/cxx_supportlib/Algorithms/MovingAverage.h +223 -0
  37. data/src/cxx_supportlib/Constants.h +2 -2
  38. data/src/cxx_supportlib/DataStructures/StringKeyTable.h +96 -40
  39. data/src/cxx_supportlib/ResourceLocator.h +33 -14
  40. data/src/cxx_supportlib/ServerKit/Channel.h +198 -69
  41. data/src/cxx_supportlib/ServerKit/Errors.h +6 -1
  42. data/src/cxx_supportlib/ServerKit/HttpRequest.h +20 -1
  43. data/src/cxx_supportlib/ServerKit/HttpServer.h +124 -32
  44. data/src/cxx_supportlib/ServerKit/Server.h +65 -1
  45. data/src/cxx_supportlib/Utils/IOUtils.cpp +12 -22
  46. data/src/cxx_supportlib/Utils/JsonUtils.h +87 -1
  47. data/src/cxx_supportlib/Utils/StrIntUtils.cpp +16 -1
  48. data/src/cxx_supportlib/Utils/StrIntUtils.h +31 -1
  49. data/src/cxx_supportlib/Utils/VariantMap.h +6 -1
  50. data/src/cxx_supportlib/WatchdogLauncher.h +17 -9
  51. data/src/cxx_supportlib/vendor-copy/libuv/AUTHORS +43 -0
  52. data/src/cxx_supportlib/vendor-copy/libuv/ChangeLog +350 -1
  53. data/src/cxx_supportlib/vendor-copy/libuv/Makefile.am +9 -1
  54. data/src/cxx_supportlib/vendor-copy/libuv/README.md +48 -0
  55. data/src/cxx_supportlib/vendor-copy/libuv/checksparse.sh +1 -0
  56. data/src/cxx_supportlib/vendor-copy/libuv/common.gypi +5 -5
  57. data/src/cxx_supportlib/vendor-copy/libuv/configure.ac +2 -1
  58. data/src/cxx_supportlib/vendor-copy/libuv/gyp_uv.py +0 -3
  59. data/src/cxx_supportlib/vendor-copy/libuv/include/uv-version.h +5 -1
  60. data/src/cxx_supportlib/vendor-copy/libuv/include/uv.h +30 -3
  61. data/src/cxx_supportlib/vendor-copy/libuv/src/fs-poll.c +3 -3
  62. data/src/cxx_supportlib/vendor-copy/libuv/src/inet.c +0 -4
  63. data/src/cxx_supportlib/vendor-copy/libuv/src/queue.h +17 -1
  64. data/src/cxx_supportlib/vendor-copy/libuv/src/threadpool.c +10 -10
  65. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/aix.c +84 -166
  66. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/android-ifaddrs.c +11 -11
  67. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/async.c +7 -1
  68. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/atomic-ops.h +17 -0
  69. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/core.c +140 -21
  70. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/darwin.c +15 -11
  71. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/dl.c +4 -7
  72. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/freebsd.c +52 -37
  73. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fs.c +181 -60
  74. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fsevents.c +39 -34
  75. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/getaddrinfo.c +4 -4
  76. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/internal.h +3 -1
  77. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/kqueue.c +12 -4
  78. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-core.c +38 -15
  79. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-inotify.c +36 -8
  80. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.c +4 -4
  81. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.h +2 -2
  82. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop-watcher.c +6 -1
  83. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop.c +28 -8
  84. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/netbsd.c +18 -16
  85. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/openbsd.c +18 -16
  86. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pipe.c +3 -3
  87. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/process.c +18 -6
  88. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/proctitle.c +2 -2
  89. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pthread-fixes.c +1 -0
  90. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/signal.c +2 -0
  91. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/stream.c +47 -30
  92. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/sunos.c +13 -11
  93. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tcp.c +43 -8
  94. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/thread.c +21 -15
  95. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tty.c +16 -2
  96. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/udp.c +54 -14
  97. data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.c +104 -21
  98. data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.h +14 -1
  99. data/src/cxx_supportlib/vendor-copy/libuv/src/version.c +1 -5
  100. data/src/cxx_supportlib/vendor-copy/libuv/uv.gyp +22 -1
  101. data/src/nginx_module/CacheLocationConfig.c +52 -0
  102. data/src/nginx_module/CacheLocationConfig.c.erb +13 -1
  103. data/src/nginx_module/Configuration.c +1 -0
  104. data/src/nginx_module/Configuration.h +1 -0
  105. data/src/nginx_module/ConfigurationCommands.c +20 -0
  106. data/src/nginx_module/ConfigurationFields.h +4 -0
  107. data/src/nginx_module/CreateLocationConfig.c +8 -0
  108. data/src/nginx_module/MergeLocationConfig.c +12 -0
  109. data/src/nginx_module/config +31 -13
  110. data/src/nginx_module/ngx_http_passenger_module.c +4 -0
  111. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  112. data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -1
  113. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +11 -1
  114. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +6 -1
  115. data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +32 -31
  116. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +13 -2
  117. data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -0
  118. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +6 -1
  119. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +6 -0
  120. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +29 -19
  121. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +2 -2
  122. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +2 -3
  123. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +2 -1
  124. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +2 -0
  125. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +3 -17
  126. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +7 -10
  127. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +11 -9
  128. metadata +5 -2
@@ -39,10 +39,8 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) {
39
39
 
40
40
 
41
41
  void uv_dlclose(uv_lib_t* lib) {
42
- if (lib->errmsg) {
43
- free(lib->errmsg);
44
- lib->errmsg = NULL;
45
- }
42
+ uv__free(lib->errmsg);
43
+ lib->errmsg = NULL;
46
44
 
47
45
  if (lib->handle) {
48
46
  /* Ignore errors. No good way to signal them without leaking memory. */
@@ -67,13 +65,12 @@ const char* uv_dlerror(const uv_lib_t* lib) {
67
65
  static int uv__dlerror(uv_lib_t* lib) {
68
66
  const char* errmsg;
69
67
 
70
- if (lib->errmsg)
71
- free(lib->errmsg);
68
+ uv__free(lib->errmsg);
72
69
 
73
70
  errmsg = dlerror();
74
71
 
75
72
  if (errmsg) {
76
- lib->errmsg = strdup(errmsg);
73
+ lib->errmsg = uv__strdup(errmsg);
77
74
  return -1;
78
75
  }
79
76
  else {
@@ -74,6 +74,30 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
74
74
  }
75
75
 
76
76
 
77
+ #ifdef __DragonFly__
78
+ int uv_exepath(char* buffer, size_t* size) {
79
+ char abspath[PATH_MAX * 2 + 1];
80
+ ssize_t abspath_size;
81
+
82
+ if (buffer == NULL || size == NULL || *size == 0)
83
+ return -EINVAL;
84
+
85
+ abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
86
+ if (abspath_size < 0)
87
+ return -errno;
88
+
89
+ assert(abspath_size > 0);
90
+ *size -= 1;
91
+
92
+ if (*size > abspath_size)
93
+ *size = abspath_size;
94
+
95
+ memcpy(buffer, abspath, *size);
96
+ buffer[*size] = '\0';
97
+
98
+ return 0;
99
+ }
100
+ #else
77
101
  int uv_exepath(char* buffer, size_t* size) {
78
102
  char abspath[PATH_MAX * 2 + 1];
79
103
  int mib[4];
@@ -82,19 +106,12 @@ int uv_exepath(char* buffer, size_t* size) {
82
106
  if (buffer == NULL || size == NULL || *size == 0)
83
107
  return -EINVAL;
84
108
 
85
- #ifdef __DragonFly__
86
- mib[0] = CTL_KERN;
87
- mib[1] = KERN_PROC;
88
- mib[2] = KERN_PROC_ARGS;
89
- mib[3] = getpid();
90
- #else
91
109
  mib[0] = CTL_KERN;
92
110
  mib[1] = KERN_PROC;
93
111
  mib[2] = KERN_PROC_PATHNAME;
94
112
  mib[3] = -1;
95
- #endif
96
113
 
97
- abspath_size = sizeof abspath;;
114
+ abspath_size = sizeof abspath;
98
115
  if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
99
116
  return -errno;
100
117
 
@@ -110,7 +127,7 @@ int uv_exepath(char* buffer, size_t* size) {
110
127
 
111
128
  return 0;
112
129
  }
113
-
130
+ #endif
114
131
 
115
132
  uint64_t uv_get_free_memory(void) {
116
133
  int freecount;
@@ -151,7 +168,7 @@ void uv_loadavg(double avg[3]) {
151
168
 
152
169
 
153
170
  char** uv_setup_args(int argc, char** argv) {
154
- process_title = argc ? strdup(argv[0]) : NULL;
171
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
155
172
  return argv;
156
173
  }
157
174
 
@@ -159,8 +176,8 @@ char** uv_setup_args(int argc, char** argv) {
159
176
  int uv_set_process_title(const char* title) {
160
177
  int oid[4];
161
178
 
162
- if (process_title) free(process_title);
163
- process_title = strdup(title);
179
+ uv__free(process_title);
180
+ process_title = uv__strdup(title);
164
181
 
165
182
  oid[0] = CTL_KERN;
166
183
  oid[1] = KERN_PROC;
@@ -223,17 +240,13 @@ error:
223
240
 
224
241
 
225
242
  int uv_uptime(double* uptime) {
226
- time_t now;
227
- struct timeval info;
228
- size_t size = sizeof(info);
229
- static int which[] = {CTL_KERN, KERN_BOOTTIME};
230
-
231
- if (sysctl(which, 2, &info, &size, NULL, 0))
243
+ int r;
244
+ struct timespec sp;
245
+ r = clock_gettime(CLOCK_MONOTONIC, &sp);
246
+ if (r)
232
247
  return -errno;
233
248
 
234
- now = time(NULL);
235
-
236
- *uptime = (double)(now - info.tv_sec);
249
+ *uptime = sp.tv_sec;
237
250
  return 0;
238
251
  }
239
252
 
@@ -271,7 +284,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
271
284
  if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
272
285
  return -errno;
273
286
 
274
- *cpu_infos = malloc(numcpus * sizeof(**cpu_infos));
287
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
275
288
  if (!(*cpu_infos))
276
289
  return -ENOMEM;
277
290
 
@@ -279,7 +292,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
279
292
 
280
293
  size = sizeof(cpuspeed);
281
294
  if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
282
- SAVE_ERRNO(free(*cpu_infos));
295
+ SAVE_ERRNO(uv__free(*cpu_infos));
283
296
  return -errno;
284
297
  }
285
298
 
@@ -288,21 +301,21 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
288
301
  */
289
302
  size = sizeof(maxcpus);
290
303
  if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
291
- SAVE_ERRNO(free(*cpu_infos));
304
+ SAVE_ERRNO(uv__free(*cpu_infos));
292
305
  return -errno;
293
306
  }
294
307
 
295
308
  size = maxcpus * CPUSTATES * sizeof(long);
296
309
 
297
- cp_times = malloc(size);
310
+ cp_times = uv__malloc(size);
298
311
  if (cp_times == NULL) {
299
- free(*cpu_infos);
312
+ uv__free(*cpu_infos);
300
313
  return -ENOMEM;
301
314
  }
302
315
 
303
316
  if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
304
- SAVE_ERRNO(free(cp_times));
305
- SAVE_ERRNO(free(*cpu_infos));
317
+ SAVE_ERRNO(uv__free(cp_times));
318
+ SAVE_ERRNO(uv__free(*cpu_infos));
306
319
  return -errno;
307
320
  }
308
321
 
@@ -315,13 +328,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
315
328
  cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
316
329
  cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
317
330
 
318
- cpu_info->model = strdup(model);
331
+ cpu_info->model = uv__strdup(model);
319
332
  cpu_info->speed = cpuspeed;
320
333
 
321
334
  cur+=CPUSTATES;
322
335
  }
323
336
 
324
- free(cp_times);
337
+ uv__free(cp_times);
325
338
  return 0;
326
339
  }
327
340
 
@@ -330,10 +343,10 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
330
343
  int i;
331
344
 
332
345
  for (i = 0; i < count; i++) {
333
- free(cpu_infos[i].model);
346
+ uv__free(cpu_infos[i].model);
334
347
  }
335
348
 
336
- free(cpu_infos);
349
+ uv__free(cpu_infos);
337
350
  }
338
351
 
339
352
 
@@ -359,9 +372,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
359
372
  (*count)++;
360
373
  }
361
374
 
362
- *addresses = malloc(*count * sizeof(**addresses));
363
- if (!(*addresses))
375
+ *addresses = uv__malloc(*count * sizeof(**addresses));
376
+ if (!(*addresses)) {
377
+ freeifaddrs(addrs);
364
378
  return -ENOMEM;
379
+ }
365
380
 
366
381
  address = *addresses;
367
382
 
@@ -379,7 +394,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
379
394
  if (ent->ifa_addr->sa_family == AF_LINK)
380
395
  continue;
381
396
 
382
- address->name = strdup(ent->ifa_name);
397
+ address->name = uv__strdup(ent->ifa_name);
383
398
 
384
399
  if (ent->ifa_addr->sa_family == AF_INET6) {
385
400
  address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
@@ -428,8 +443,8 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
428
443
  int i;
429
444
 
430
445
  for (i = 0; i < count; i++) {
431
- free(addresses[i].name);
446
+ uv__free(addresses[i].name);
432
447
  }
433
448
 
434
- free(addresses);
449
+ uv__free(addresses);
435
450
  }
@@ -58,52 +58,67 @@
58
58
  # include <sys/sendfile.h>
59
59
  #endif
60
60
 
61
- #define INIT(type) \
61
+ #define INIT(subtype) \
62
62
  do { \
63
- uv__req_init((loop), (req), UV_FS); \
64
- (req)->fs_type = UV_FS_ ## type; \
65
- (req)->result = 0; \
66
- (req)->ptr = NULL; \
67
- (req)->loop = loop; \
68
- (req)->path = NULL; \
69
- (req)->new_path = NULL; \
70
- (req)->cb = (cb); \
63
+ req->type = UV_FS; \
64
+ if (cb != NULL) \
65
+ uv__req_init(loop, req, UV_FS); \
66
+ req->fs_type = UV_FS_ ## subtype; \
67
+ req->result = 0; \
68
+ req->ptr = NULL; \
69
+ req->loop = loop; \
70
+ req->path = NULL; \
71
+ req->new_path = NULL; \
72
+ req->cb = cb; \
71
73
  } \
72
74
  while (0)
73
75
 
74
76
  #define PATH \
75
77
  do { \
76
- (req)->path = strdup(path); \
77
- if ((req)->path == NULL) \
78
- return -ENOMEM; \
78
+ assert(path != NULL); \
79
+ if (cb == NULL) { \
80
+ req->path = path; \
81
+ } else { \
82
+ req->path = uv__strdup(path); \
83
+ if (req->path == NULL) { \
84
+ uv__req_unregister(loop, req); \
85
+ return -ENOMEM; \
86
+ } \
87
+ } \
79
88
  } \
80
89
  while (0)
81
90
 
82
91
  #define PATH2 \
83
92
  do { \
84
- size_t path_len; \
85
- size_t new_path_len; \
86
- path_len = strlen((path)) + 1; \
87
- new_path_len = strlen((new_path)) + 1; \
88
- (req)->path = malloc(path_len + new_path_len); \
89
- if ((req)->path == NULL) \
90
- return -ENOMEM; \
91
- (req)->new_path = (req)->path + path_len; \
92
- memcpy((void*) (req)->path, (path), path_len); \
93
- memcpy((void*) (req)->new_path, (new_path), new_path_len); \
93
+ if (cb == NULL) { \
94
+ req->path = path; \
95
+ req->new_path = new_path; \
96
+ } else { \
97
+ size_t path_len; \
98
+ size_t new_path_len; \
99
+ path_len = strlen(path) + 1; \
100
+ new_path_len = strlen(new_path) + 1; \
101
+ req->path = uv__malloc(path_len + new_path_len); \
102
+ if (req->path == NULL) { \
103
+ uv__req_unregister(loop, req); \
104
+ return -ENOMEM; \
105
+ } \
106
+ req->new_path = req->path + path_len; \
107
+ memcpy((void*) req->path, path, path_len); \
108
+ memcpy((void*) req->new_path, new_path, new_path_len); \
109
+ } \
94
110
  } \
95
111
  while (0)
96
112
 
97
113
  #define POST \
98
114
  do { \
99
- if ((cb) != NULL) { \
100
- uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
115
+ if (cb != NULL) { \
116
+ uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
101
117
  return 0; \
102
118
  } \
103
119
  else { \
104
- uv__fs_work(&(req)->work_req); \
105
- uv__fs_done(&(req)->work_req, 0); \
106
- return (req)->result; \
120
+ uv__fs_work(&req->work_req); \
121
+ return req->result; \
107
122
  } \
108
123
  } \
109
124
  while (0)
@@ -309,8 +324,6 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
309
324
  }
310
325
 
311
326
  done:
312
- if (req->bufs != req->bufsml)
313
- free(req->bufs);
314
327
  return result;
315
328
  }
316
329
 
@@ -350,8 +363,8 @@ out:
350
363
  int i;
351
364
 
352
365
  for (i = 0; i < n; i++)
353
- free(dents[i]);
354
- free(dents);
366
+ uv__free(dents[i]);
367
+ uv__free(dents);
355
368
  }
356
369
  errno = saved_errno;
357
370
 
@@ -361,21 +374,28 @@ out:
361
374
  }
362
375
 
363
376
 
364
- static ssize_t uv__fs_readlink(uv_fs_t* req) {
365
- ssize_t len;
366
- char* buf;
377
+ static ssize_t uv__fs_pathmax_size(const char* path) {
378
+ ssize_t pathmax;
367
379
 
368
- len = pathconf(req->path, _PC_PATH_MAX);
380
+ pathmax = pathconf(path, _PC_PATH_MAX);
369
381
 
370
- if (len == -1) {
382
+ if (pathmax == -1) {
371
383
  #if defined(PATH_MAX)
372
- len = PATH_MAX;
384
+ return PATH_MAX;
373
385
  #else
374
- len = 4096;
386
+ return 4096;
375
387
  #endif
376
388
  }
377
389
 
378
- buf = malloc(len + 1);
390
+ return pathmax;
391
+ }
392
+
393
+ static ssize_t uv__fs_readlink(uv_fs_t* req) {
394
+ ssize_t len;
395
+ char* buf;
396
+
397
+ len = uv__fs_pathmax_size(req->path);
398
+ buf = uv__malloc(len + 1);
379
399
 
380
400
  if (buf == NULL) {
381
401
  errno = ENOMEM;
@@ -385,7 +405,7 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
385
405
  len = readlink(req->path, buf, len);
386
406
 
387
407
  if (len == -1) {
388
- free(buf);
408
+ uv__free(buf);
389
409
  return -1;
390
410
  }
391
411
 
@@ -395,6 +415,27 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
395
415
  return 0;
396
416
  }
397
417
 
418
+ static ssize_t uv__fs_realpath(uv_fs_t* req) {
419
+ ssize_t len;
420
+ char* buf;
421
+
422
+ len = uv__fs_pathmax_size(req->path);
423
+ buf = uv__malloc(len + 1);
424
+
425
+ if (buf == NULL) {
426
+ errno = ENOMEM;
427
+ return -1;
428
+ }
429
+
430
+ if (realpath(req->path, buf) == NULL) {
431
+ uv__free(buf);
432
+ return -1;
433
+ }
434
+
435
+ req->ptr = buf;
436
+
437
+ return 0;
438
+ }
398
439
 
399
440
  static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
400
441
  struct pollfd pfd;
@@ -545,7 +586,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
545
586
 
546
587
  return -1;
547
588
  }
548
- #elif defined(__FreeBSD__) || defined(__APPLE__)
589
+ #elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
549
590
  {
550
591
  off_t len;
551
592
  ssize_t r;
@@ -555,7 +596,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
555
596
  * number of bytes have been sent, we don't consider it an error.
556
597
  */
557
598
 
558
- #if defined(__FreeBSD__)
599
+ #if defined(__FreeBSD__) || defined(__DragonFly__)
559
600
  len = 0;
560
601
  r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
561
602
  #else
@@ -565,7 +606,14 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
565
606
  r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
566
607
  #endif
567
608
 
568
- if (r != -1 || len != 0) {
609
+ /*
610
+ * The man page for sendfile(2) on DragonFly states that `len` contains
611
+ * a meaningful value ONLY in case of EAGAIN and EINTR.
612
+ * Nothing is said about it's value in case of other errors, so better
613
+ * not depend on the potential wrong assumption that is was not modified
614
+ * by the syscall.
615
+ */
616
+ if (r == 0 || ((errno == EAGAIN || errno == EINTR) && len != 0)) {
569
617
  req->off += len;
570
618
  return (ssize_t) len;
571
619
  }
@@ -610,7 +658,9 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
610
658
  */
611
659
  #if defined(__APPLE__)
612
660
  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
613
- pthread_mutex_lock(&lock);
661
+
662
+ if (pthread_mutex_lock(&lock))
663
+ abort();
614
664
  #endif
615
665
 
616
666
  if (req->off < 0) {
@@ -667,12 +717,10 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
667
717
 
668
718
  done:
669
719
  #if defined(__APPLE__)
670
- pthread_mutex_unlock(&lock);
720
+ if (pthread_mutex_unlock(&lock))
721
+ abort();
671
722
  #endif
672
723
 
673
- if (req->bufs != req->bufsml)
674
- free(req->bufs);
675
-
676
724
  return r;
677
725
  }
678
726
 
@@ -777,6 +825,47 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
777
825
  }
778
826
 
779
827
 
828
+ typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
829
+ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
830
+ unsigned int iovmax;
831
+ unsigned int nbufs;
832
+ uv_buf_t* bufs;
833
+ ssize_t total;
834
+ ssize_t result;
835
+
836
+ iovmax = uv__getiovmax();
837
+ nbufs = req->nbufs;
838
+ bufs = req->bufs;
839
+ total = 0;
840
+
841
+ while (nbufs > 0) {
842
+ req->nbufs = nbufs;
843
+ if (req->nbufs > iovmax)
844
+ req->nbufs = iovmax;
845
+
846
+ result = process(req);
847
+ if (result <= 0) {
848
+ if (total == 0)
849
+ total = result;
850
+ break;
851
+ }
852
+
853
+ if (req->off >= 0)
854
+ req->off += result;
855
+
856
+ req->bufs += req->nbufs;
857
+ nbufs -= req->nbufs;
858
+ total += result;
859
+ }
860
+
861
+ if (bufs != req->bufsml)
862
+ uv__free(bufs);
863
+ req->bufs = NULL;
864
+
865
+ return total;
866
+ }
867
+
868
+
780
869
  static void uv__fs_work(struct uv__work* w) {
781
870
  int retry_on_eintr;
782
871
  uv_fs_t* req;
@@ -810,9 +899,10 @@ static void uv__fs_work(struct uv__work* w) {
810
899
  X(MKDIR, mkdir(req->path, req->mode));
811
900
  X(MKDTEMP, uv__fs_mkdtemp(req));
812
901
  X(OPEN, uv__fs_open(req));
813
- X(READ, uv__fs_read(req));
902
+ X(READ, uv__fs_buf_iter(req, uv__fs_read));
814
903
  X(SCANDIR, uv__fs_scandir(req));
815
904
  X(READLINK, uv__fs_readlink(req));
905
+ X(REALPATH, uv__fs_realpath(req));
816
906
  X(RENAME, rename(req->path, req->new_path));
817
907
  X(RMDIR, rmdir(req->path));
818
908
  X(SENDFILE, uv__fs_sendfile(req));
@@ -820,7 +910,7 @@ static void uv__fs_work(struct uv__work* w) {
820
910
  X(SYMLINK, symlink(req->path, req->new_path));
821
911
  X(UNLINK, unlink(req->path));
822
912
  X(UTIME, uv__fs_utime(req));
823
- X(WRITE, uv__fs_write(req));
913
+ X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
824
914
  default: abort();
825
915
  }
826
916
  #undef X
@@ -850,8 +940,7 @@ static void uv__fs_done(struct uv__work* w, int status) {
850
940
  req->result = -ECANCELED;
851
941
  }
852
942
 
853
- if (req->cb != NULL)
854
- req->cb(req);
943
+ req->cb(req);
855
944
  }
856
945
 
857
946
 
@@ -1008,9 +1097,12 @@ int uv_fs_mkdtemp(uv_loop_t* loop,
1008
1097
  const char* tpl,
1009
1098
  uv_fs_cb cb) {
1010
1099
  INIT(MKDTEMP);
1011
- req->path = strdup(tpl);
1012
- if (req->path == NULL)
1100
+ req->path = uv__strdup(tpl);
1101
+ if (req->path == NULL) {
1102
+ if (cb != NULL)
1103
+ uv__req_unregister(loop, req);
1013
1104
  return -ENOMEM;
1105
+ }
1014
1106
  POST;
1015
1107
  }
1016
1108
 
@@ -1035,16 +1127,22 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
1035
1127
  unsigned int nbufs,
1036
1128
  int64_t off,
1037
1129
  uv_fs_cb cb) {
1130
+ if (bufs == NULL || nbufs == 0)
1131
+ return -EINVAL;
1132
+
1038
1133
  INIT(READ);
1039
1134
  req->file = file;
1040
1135
 
1041
1136
  req->nbufs = nbufs;
1042
1137
  req->bufs = req->bufsml;
1043
1138
  if (nbufs > ARRAY_SIZE(req->bufsml))
1044
- req->bufs = malloc(nbufs * sizeof(*bufs));
1139
+ req->bufs = uv__malloc(nbufs * sizeof(*bufs));
1045
1140
 
1046
- if (req->bufs == NULL)
1141
+ if (req->bufs == NULL) {
1142
+ if (cb != NULL)
1143
+ uv__req_unregister(loop, req);
1047
1144
  return -ENOMEM;
1145
+ }
1048
1146
 
1049
1147
  memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
1050
1148
 
@@ -1075,6 +1173,16 @@ int uv_fs_readlink(uv_loop_t* loop,
1075
1173
  }
1076
1174
 
1077
1175
 
1176
+ int uv_fs_realpath(uv_loop_t* loop,
1177
+ uv_fs_t* req,
1178
+ const char * path,
1179
+ uv_fs_cb cb) {
1180
+ INIT(REALPATH);
1181
+ PATH;
1182
+ POST;
1183
+ }
1184
+
1185
+
1078
1186
  int uv_fs_rename(uv_loop_t* loop,
1079
1187
  uv_fs_t* req,
1080
1188
  const char* path,
@@ -1157,16 +1265,22 @@ int uv_fs_write(uv_loop_t* loop,
1157
1265
  unsigned int nbufs,
1158
1266
  int64_t off,
1159
1267
  uv_fs_cb cb) {
1268
+ if (bufs == NULL || nbufs == 0)
1269
+ return -EINVAL;
1270
+
1160
1271
  INIT(WRITE);
1161
1272
  req->file = file;
1162
1273
 
1163
1274
  req->nbufs = nbufs;
1164
1275
  req->bufs = req->bufsml;
1165
1276
  if (nbufs > ARRAY_SIZE(req->bufsml))
1166
- req->bufs = malloc(nbufs * sizeof(*bufs));
1277
+ req->bufs = uv__malloc(nbufs * sizeof(*bufs));
1167
1278
 
1168
- if (req->bufs == NULL)
1279
+ if (req->bufs == NULL) {
1280
+ if (cb != NULL)
1281
+ uv__req_unregister(loop, req);
1169
1282
  return -ENOMEM;
1283
+ }
1170
1284
 
1171
1285
  memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
1172
1286
 
@@ -1176,7 +1290,14 @@ int uv_fs_write(uv_loop_t* loop,
1176
1290
 
1177
1291
 
1178
1292
  void uv_fs_req_cleanup(uv_fs_t* req) {
1179
- free((void*) req->path);
1293
+ /* Only necessary for asychronous requests, i.e., requests with a callback.
1294
+ * Synchronous ones don't copy their arguments and have req->path and
1295
+ * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
1296
+ * exception to the rule, it always allocates memory.
1297
+ */
1298
+ if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP))
1299
+ uv__free((void*) req->path); /* Memory is shared with req->new_path. */
1300
+
1180
1301
  req->path = NULL;
1181
1302
  req->new_path = NULL;
1182
1303
 
@@ -1184,6 +1305,6 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
1184
1305
  uv__fs_scandir_cleanup(req);
1185
1306
 
1186
1307
  if (req->ptr != &req->statbuf)
1187
- free(req->ptr);
1308
+ uv__free(req->ptr);
1188
1309
  req->ptr = NULL;
1189
1310
  }