passenger 4.0.0.rc4 → 4.0.0.rc6

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 (83) hide show
  1. data.tar.gz.asc +12 -0
  2. data/.travis.yml +4 -4
  3. data/NEWS +46 -0
  4. data/bin/passenger-config +31 -1
  5. data/bin/passenger-install-apache2-module +1 -1
  6. data/bin/passenger-install-nginx-module +1 -0
  7. data/build/common_library.rb +4 -0
  8. data/build/cplusplus_support.rb +27 -6
  9. data/build/cxx_tests.rb +1 -1
  10. data/build/misc.rb +28 -6
  11. data/build/packaging.rb +72 -65
  12. data/build/test_basics.rb +1 -1
  13. data/dev/googlecode_upload.py +265 -0
  14. data/dev/run_travis.sh +9 -0
  15. data/doc/Users guide Apache.html +376 -193
  16. data/doc/Users guide Apache.idmap.txt +80 -62
  17. data/doc/Users guide Apache.txt +61 -35
  18. data/doc/Users guide Nginx.html +278 -83
  19. data/doc/Users guide Nginx.idmap.txt +26 -10
  20. data/doc/Users guide Nginx.txt +59 -31
  21. data/doc/Users guide Standalone.html +1 -1
  22. data/doc/users_guide_snippets/installation.txt +121 -11
  23. data/doc/users_guide_snippets/rvm_helper_tool.txt +56 -0
  24. data/ext/apache2/Bucket.cpp +1 -1
  25. data/ext/apache2/Configuration.cpp +7 -1
  26. data/ext/apache2/Configuration.hpp +4 -0
  27. data/ext/apache2/Hooks.cpp +2 -2
  28. data/ext/common/AgentsStarter.cpp +2 -2
  29. data/ext/common/AgentsStarter.h +1 -1
  30. data/ext/common/AgentsStarter.hpp +2 -2
  31. data/ext/common/ApplicationPool2/DirectSpawner.h +4 -8
  32. data/ext/common/ApplicationPool2/Group.h +17 -11
  33. data/ext/common/ApplicationPool2/Implementation.cpp +39 -11
  34. data/ext/common/ApplicationPool2/Pool.h +23 -4
  35. data/ext/common/ApplicationPool2/Process.h +30 -11
  36. data/ext/common/ApplicationPool2/SmartSpawner.h +3 -1
  37. data/ext/common/Constants.h +1 -1
  38. data/ext/common/EventedBufferedInput.h +4 -0
  39. data/ext/common/Utils.cpp +21 -3
  40. data/ext/common/Utils.h +8 -1
  41. data/ext/common/Utils/HttpHeaderBufferer.h +1 -1
  42. data/ext/common/Utils/IOUtils.cpp +5 -4
  43. data/ext/common/Utils/IOUtils.h +32 -14
  44. data/ext/common/Utils/MessagePassing.h +2 -2
  45. data/ext/common/Utils/ProcessMetricsCollector.h +47 -15
  46. data/ext/common/Utils/ScopeGuard.h +20 -3
  47. data/ext/common/Utils/StrIntUtils.h +14 -5
  48. data/ext/common/agents/Base.cpp +161 -50
  49. data/ext/common/agents/HelperAgent/AgentOptions.h +2 -2
  50. data/ext/common/agents/HelperAgent/Main.cpp +1 -0
  51. data/ext/common/agents/HelperAgent/RequestHandler.h +166 -52
  52. data/ext/common/agents/LoggingAgent/Main.cpp +1 -1
  53. data/ext/common/agents/Watchdog/Main.cpp +2 -2
  54. data/ext/nginx/Configuration.c +31 -4
  55. data/ext/nginx/Configuration.h +1 -0
  56. data/ext/nginx/ContentHandler.c +148 -34
  57. data/ext/nginx/ngx_http_passenger_module.c +4 -1
  58. data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
  59. data/ext/oxt/macros.hpp +30 -8
  60. data/lib/phusion_passenger.rb +2 -2
  61. data/lib/phusion_passenger/classic_rails/thread_handler_extension.rb +1 -1
  62. data/lib/phusion_passenger/native_support.rb +19 -1
  63. data/lib/phusion_passenger/platform_info/compiler.rb +6 -0
  64. data/lib/phusion_passenger/platform_info/ruby.rb +54 -5
  65. data/lib/phusion_passenger/preloader_shared_helpers.rb +8 -1
  66. data/lib/phusion_passenger/rack/out_of_band_gc.rb +3 -1
  67. data/lib/phusion_passenger/rack/thread_handler_extension.rb +32 -5
  68. data/lib/phusion_passenger/request_handler/thread_handler.rb +28 -8
  69. data/lib/phusion_passenger/ruby_core_enhancements.rb +9 -1
  70. data/lib/phusion_passenger/standalone/runtime_installer.rb +1 -0
  71. data/lib/phusion_passenger/utils/unseekable_socket.rb +50 -5
  72. data/passenger.gemspec +1 -1
  73. data/resources/templates/apache2/config_snippets.txt.erb +1 -1
  74. data/test/cxx/ApplicationPool2/PoolTest.cpp +4 -9
  75. data/test/cxx/RequestHandlerTest.cpp +5 -5
  76. data/test/ruby/classic_rails/loader_spec.rb +1 -1
  77. data/test/ruby/classic_rails/preloader_spec.rb +1 -1
  78. data/test/ruby/request_handler_spec.rb +207 -1
  79. data/test/ruby/shared/loader_sharedspec.rb +1 -0
  80. data/test/ruby/spec_helper.rb +11 -1
  81. data/test/stub/apache2/httpd.conf.erb +1 -1
  82. metadata +5 -3
  83. metadata.gz.asc +12 -0
@@ -69,6 +69,7 @@ typedef struct {
69
69
 
70
70
  typedef struct {
71
71
  ngx_str_t root_dir;
72
+ ngx_str_t default_ruby;
72
73
  ngx_int_t log_level;
73
74
  ngx_str_t debug_log_file;
74
75
  ngx_str_t temp_dir;
@@ -53,10 +53,11 @@ static void abort_request(ngx_http_request_t *r);
53
53
  static void finalize_request(ngx_http_request_t *r, ngx_int_t rc);
54
54
 
55
55
 
56
- static void
56
+ static unsigned int
57
57
  uint_to_str(ngx_uint_t i, u_char *str, ngx_uint_t size) {
58
- ngx_memzero(str, size);
59
- ngx_snprintf(str, size, "%ui", i);
58
+ unsigned int len = ngx_snprintf(str, size - 1, "%ui", i) - str;
59
+ str[len] = '\0';
60
+ return len;
60
61
  }
61
62
 
62
63
  static FileType
@@ -222,6 +223,57 @@ set_upstream_server_address(ngx_http_upstream_t *upstream, ngx_http_upstream_con
222
223
  }
223
224
  }
224
225
 
226
+ /**
227
+ * If the helper agent socket cannot be connected to then we want Nginx to print
228
+ * the proper socket filename in the error message. The socket filename is stored
229
+ * in one of the upstream peer data structures. This name is initialized during
230
+ * the first ngx_http_read_client_request_body() call so there's no way to fix the
231
+ * name before the first request, which is why we do it after the fact.
232
+ */
233
+ static void
234
+ fix_peer_address(ngx_http_request_t *r) {
235
+ ngx_http_upstream_rr_peer_data_t *rrp;
236
+ ngx_http_upstream_rr_peers_t *peers;
237
+ ngx_http_upstream_rr_peer_t *peer;
238
+ unsigned int peer_index;
239
+ const char *request_socket_filename;
240
+ unsigned int request_socket_filename_len;
241
+
242
+ if (r->upstream->peer.get != ngx_http_upstream_get_round_robin_peer) {
243
+ /* This function only supports the round-robin upstream method. */
244
+ return;
245
+ }
246
+
247
+ rrp = r->upstream->peer.data;
248
+ peers = rrp->peers;
249
+ request_socket_filename =
250
+ agents_starter_get_request_socket_filename(passenger_agents_starter,
251
+ &request_socket_filename_len);
252
+
253
+ while (peers != NULL) {
254
+ if (peers->name) {
255
+ if (peers->name->data == (u_char *) request_socket_filename) {
256
+ /* Peer names already fixed. */
257
+ return;
258
+ }
259
+ peers->name->data = (u_char *) request_socket_filename;
260
+ peers->name->len = request_socket_filename_len;
261
+ }
262
+ peer_index = 0;
263
+ while (1) {
264
+ peer = &peers->peer[peer_index];
265
+ peer->name.data = (u_char *) request_socket_filename;
266
+ peer->name.len = request_socket_filename_len;
267
+ if (peer->down) {
268
+ peer_index++;
269
+ } else {
270
+ break;
271
+ }
272
+ }
273
+ peers = peers->next;
274
+ }
275
+ }
276
+
225
277
 
226
278
  /* Convenience macros for building the SCGI header in create_request(). */
227
279
 
@@ -311,8 +363,8 @@ create_request(ngx_http_request_t *r)
311
363
  u_char ch;
312
364
  const char * helper_agent_request_socket_password_data;
313
365
  unsigned int helper_agent_request_socket_password_len;
314
- u_char buf[sizeof("4294967296")];
315
- size_t len, size, key_len, val_len, content_length;
366
+ u_char buf[sizeof("4294967296") + 1];
367
+ size_t len, size, key_len, val_len;
316
368
  const u_char *app_type_string;
317
369
  size_t app_type_string_len;
318
370
  int server_name_len;
@@ -366,15 +418,15 @@ create_request(ngx_http_request_t *r)
366
418
  * Determine the request header length.
367
419
  **************************************************/
368
420
 
369
- /* Length of the Content-Length header. */
370
- if (r->headers_in.content_length_n < 0) {
371
- content_length = 0;
372
- } else {
373
- content_length = r->headers_in.content_length_n;
421
+ len = 0;
422
+
423
+ /* Length of the Content-Length header. A value of -1 means that the content
424
+ * length is unspecified, which is the case for e.g. WebSocket requests. */
425
+ if (r->headers_in.content_length_n >= 0) {
426
+ len += sizeof("CONTENT_LENGTH") +
427
+ uint_to_str(r->headers_in.content_length_n, buf, sizeof(buf)) +
428
+ 1; /* +1 for trailing null */
374
429
  }
375
- uint_to_str(content_length, buf, sizeof(buf));
376
- /* +1 for trailing null */
377
- len = sizeof("CONTENT_LENGTH") + ngx_strlen(buf) + 1;
378
430
 
379
431
  /* DOCUMENT_ROOT, SCRIPT_NAME, RAILS_RELATIVE_URL_ROOT, PATH_INFO and REQUEST_URI. */
380
432
  len += sizeof("DOCUMENT_ROOT") + context->public_dir.len + 1;
@@ -427,7 +479,11 @@ create_request(ngx_http_request_t *r)
427
479
  slcf, debugger);
428
480
  ANALYZE_BOOLEAN_CONFIG_LENGTH("PASSENGER_SHOW_VERSION_IN_HEADER",
429
481
  slcf, show_version_in_header);
430
- ANALYZE_STR_CONFIG_LENGTH("PASSENGER_RUBY", slcf, ruby);
482
+ if (slcf->ruby.data != NULL) {
483
+ ANALYZE_STR_CONFIG_LENGTH("PASSENGER_RUBY", slcf, ruby);
484
+ } else {
485
+ len += sizeof("PASSENGER_RUBY") + passenger_main_conf.default_ruby.len + 1;
486
+ }
431
487
  ANALYZE_STR_CONFIG_LENGTH("PASSENGER_PYTHON", slcf, python);
432
488
  len += sizeof("PASSENGER_ENV") + slcf->environment.len + 1;
433
489
  len += sizeof("PASSENGER_SPAWN_METHOD") + slcf->spawn_method.len + 1;
@@ -560,12 +616,13 @@ create_request(ngx_http_request_t *r)
560
616
  b->last = ngx_snprintf(b->last, 10, "%ui", len);
561
617
  *b->last++ = (u_char) ':';
562
618
 
563
- /* Build CONTENT_LENGTH header. This must always be sent, even if 0. */
564
- b->last = ngx_copy(b->last, "CONTENT_LENGTH",
565
- sizeof("CONTENT_LENGTH"));
619
+ if (r->headers_in.content_length_n >= 0) {
620
+ b->last = ngx_copy(b->last, "CONTENT_LENGTH",
621
+ sizeof("CONTENT_LENGTH"));
566
622
 
567
- b->last = ngx_snprintf(b->last, 10, "%ui", content_length);
568
- *b->last++ = (u_char) 0;
623
+ b->last = ngx_snprintf(b->last, 10, "%ui", r->headers_in.content_length_n);
624
+ *b->last++ = (u_char) 0;
625
+ }
569
626
 
570
627
  /* Build DOCUMENT_ROOT, SCRIPT_NAME, RAILS_RELATIVE_URL_ROOT, PATH_INFO and REQUEST_URI. */
571
628
  b->last = ngx_copy(b->last, "DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT"));
@@ -642,8 +699,15 @@ create_request(ngx_http_request_t *r)
642
699
  SERIALIZE_BOOLEAN_CONFIG_DATA("PASSENGER_SHOW_VERSION_IN_HEADER",
643
700
  slcf, show_version_in_header);
644
701
 
645
- SERIALIZE_STR_CONFIG_DATA("PASSENGER_RUBY",
646
- slcf, ruby);
702
+ if (slcf->ruby.data != NULL) {
703
+ SERIALIZE_STR_CONFIG_DATA("PASSENGER_RUBY",
704
+ slcf, ruby);
705
+ } else {
706
+ b->last = ngx_copy(b->last, "PASSENGER_RUBY",
707
+ sizeof("PASSENGER_RUBY"));
708
+ b->last = ngx_copy(b->last, passenger_main_conf.default_ruby.data,
709
+ passenger_main_conf.default_ruby.len + 1);
710
+ }
647
711
  SERIALIZE_STR_CONFIG_DATA("PASSENGER_PYTHON",
648
712
  slcf, python);
649
713
 
@@ -833,6 +897,7 @@ reinit_request(ngx_http_request_t *r)
833
897
  context->status_end = NULL;
834
898
 
835
899
  r->upstream->process_header = process_status_line;
900
+ r->state = 0;
836
901
 
837
902
  return NGX_OK;
838
903
  }
@@ -1108,9 +1173,10 @@ done:
1108
1173
  static ngx_int_t
1109
1174
  process_header(ngx_http_request_t *r)
1110
1175
  {
1111
- ngx_int_t rc;
1112
- ngx_uint_t i;
1176
+ ngx_str_t *status_line;
1177
+ ngx_int_t rc, status;
1113
1178
  ngx_table_elt_t *h;
1179
+ ngx_http_upstream_t *u;
1114
1180
  ngx_http_upstream_header_t *hh;
1115
1181
  ngx_http_upstream_main_conf_t *umcf;
1116
1182
  ngx_http_core_loc_conf_t *clcf;
@@ -1120,7 +1186,7 @@ process_header(ngx_http_request_t *r)
1120
1186
  clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1121
1187
  slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module);
1122
1188
 
1123
- for ( ;; ) {
1189
+ for ( ;; ) {
1124
1190
 
1125
1191
  rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1126
1192
 
@@ -1130,7 +1196,7 @@ process_header(ngx_http_request_t *r)
1130
1196
 
1131
1197
  h = ngx_list_push(&r->upstream->headers_in.headers);
1132
1198
  if (h == NULL) {
1133
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
1199
+ return NGX_ERROR;
1134
1200
  }
1135
1201
 
1136
1202
  h->hash = r->header_hash;
@@ -1138,10 +1204,11 @@ process_header(ngx_http_request_t *r)
1138
1204
  h->key.len = r->header_name_end - r->header_name_start;
1139
1205
  h->value.len = r->header_end - r->header_start;
1140
1206
 
1141
- h->key.data = ngx_palloc(r->pool,
1142
- h->key.len + 1 + h->value.len + 1 + h->key.len);
1207
+ h->key.data = ngx_pnalloc(r->pool,
1208
+ h->key.len + 1 + h->value.len + 1
1209
+ + h->key.len);
1143
1210
  if (h->key.data == NULL) {
1144
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
1211
+ return NGX_ERROR;
1145
1212
  }
1146
1213
 
1147
1214
  h->value.data = h->key.data + h->key.len + 1;
@@ -1156,21 +1223,18 @@ process_header(ngx_http_request_t *r)
1156
1223
  ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1157
1224
 
1158
1225
  } else {
1159
- for (i = 0; i < h->key.len; i++) {
1160
- h->lowcase_key[i] = ngx_tolower(h->key.data[i]);
1161
- }
1226
+ ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1162
1227
  }
1163
1228
 
1164
1229
  hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1165
1230
  h->lowcase_key, h->key.len);
1166
1231
 
1167
1232
  if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1168
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
1233
+ return NGX_ERROR;
1169
1234
  }
1170
1235
 
1171
1236
  ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1172
- "http scgi header: \"%V: %V\"",
1173
- &h->key, &h->value);
1237
+ "http scgi header: \"%V: %V\"", &h->key, &h->value);
1174
1238
 
1175
1239
  continue;
1176
1240
  }
@@ -1230,6 +1294,53 @@ process_header(ngx_http_request_t *r)
1230
1294
  h->lowcase_key = (u_char *) "date";
1231
1295
  }
1232
1296
 
1297
+ /* Process "Status" header. */
1298
+
1299
+ u = r->upstream;
1300
+
1301
+ if (u->headers_in.status_n) {
1302
+ goto done;
1303
+ }
1304
+
1305
+ if (u->headers_in.status) {
1306
+ status_line = &u->headers_in.status->value;
1307
+
1308
+ status = ngx_atoi(status_line->data, 3);
1309
+ if (status == NGX_ERROR) {
1310
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1311
+ "upstream sent invalid status \"%V\"",
1312
+ status_line);
1313
+ return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1314
+ }
1315
+
1316
+ u->headers_in.status_n = status;
1317
+ u->headers_in.status_line = *status_line;
1318
+
1319
+ } else if (u->headers_in.location) {
1320
+ u->headers_in.status_n = 302;
1321
+ ngx_str_set(&u->headers_in.status_line,
1322
+ "302 Moved Temporarily");
1323
+
1324
+ } else {
1325
+ u->headers_in.status_n = 200;
1326
+ ngx_str_set(&u->headers_in.status_line, "200 OK");
1327
+ }
1328
+
1329
+ if (u->state) {
1330
+ u->state->status = u->headers_in.status_n;
1331
+ }
1332
+
1333
+ done:
1334
+
1335
+ /* Supported since Nginx 1.3.15. */
1336
+ #ifdef NGX_HTTP_SWITCHING_PROTOCOLS
1337
+ if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS
1338
+ && r->headers_in.upgrade)
1339
+ {
1340
+ u->upgrade = 1;
1341
+ }
1342
+ #endif
1343
+
1233
1344
  return NGX_OK;
1234
1345
  }
1235
1346
 
@@ -1390,6 +1501,7 @@ passenger_content_handler(ngx_http_request_t *r)
1390
1501
  u->process_header = process_status_line;
1391
1502
  u->abort_request = abort_request;
1392
1503
  u->finalize_request = finalize_request;
1504
+ r->state = 0;
1393
1505
 
1394
1506
  u->buffering = slcf->upstream_config.buffering;
1395
1507
 
@@ -1403,6 +1515,8 @@ passenger_content_handler(ngx_http_request_t *r)
1403
1515
 
1404
1516
  rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
1405
1517
 
1518
+ fix_peer_address(r);
1519
+
1406
1520
  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
1407
1521
  return rc;
1408
1522
  }
@@ -246,6 +246,7 @@ start_helper_server(ngx_cycle_t *cycle) {
246
246
  char *default_user = NULL;
247
247
  char *default_group = NULL;
248
248
  char *passenger_root = NULL;
249
+ char *default_ruby = NULL;
249
250
  char *temp_dir = NULL;
250
251
  char *analytics_log_user;
251
252
  char *analytics_log_group;
@@ -262,6 +263,7 @@ start_helper_server(ngx_cycle_t *cycle) {
262
263
  default_user = ngx_str_null_terminate(&passenger_main_conf.default_user);
263
264
  default_group = ngx_str_null_terminate(&passenger_main_conf.default_group);
264
265
  passenger_root = ngx_str_null_terminate(&passenger_main_conf.root_dir);
266
+ default_ruby = ngx_str_null_terminate(&passenger_main_conf.default_ruby);
265
267
  temp_dir = ngx_str_null_terminate(&passenger_main_conf.temp_dir);
266
268
  analytics_log_user = ngx_str_null_terminate(&passenger_main_conf.analytics_log_user);
267
269
  analytics_log_group = ngx_str_null_terminate(&passenger_main_conf.analytics_log_group);
@@ -287,7 +289,7 @@ start_helper_server(ngx_cycle_t *cycle) {
287
289
  temp_dir, passenger_main_conf.user_switching,
288
290
  default_user, default_group,
289
291
  core_conf->user, core_conf->group,
290
- passenger_root, "ruby", passenger_main_conf.max_pool_size,
292
+ passenger_root, default_ruby, passenger_main_conf.max_pool_size,
291
293
  passenger_main_conf.max_instances_per_app,
292
294
  passenger_main_conf.pool_idle_time,
293
295
  "",
@@ -350,6 +352,7 @@ cleanup:
350
352
  free(default_user);
351
353
  free(default_group);
352
354
  free(passenger_root);
355
+ free(default_ruby);
353
356
  free(temp_dir);
354
357
  free(analytics_log_user);
355
358
  free(analytics_log_group);
@@ -61,7 +61,7 @@ public:
61
61
  ret = pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);
62
62
  } while (ret == EINTR);
63
63
  if (ret != 0) {
64
- throw boost::thread_resource_error("Cannot initialize a spin lock", ret);
64
+ throw boost::thread_resource_error(ret, "Cannot initialize a spin lock");
65
65
  }
66
66
  }
67
67
 
@@ -78,7 +78,7 @@ public:
78
78
  ret = pthread_spin_lock(&spin);
79
79
  } while (OXT_UNLIKELY(ret == EINTR));
80
80
  if (OXT_UNLIKELY(ret != 0)) {
81
- throw boost::thread_resource_error("Cannot lock spin lock", ret);
81
+ throw boost::thread_resource_error(ret, "Cannot lock spin lock");
82
82
  }
83
83
  }
84
84
 
@@ -88,7 +88,7 @@ public:
88
88
  ret = pthread_spin_unlock(&spin);
89
89
  } while (OXT_UNLIKELY(ret == EINTR));
90
90
  if (OXT_UNLIKELY(ret != 0)) {
91
- throw boost::thread_resource_error("Cannot unlock spin lock", ret);
91
+ throw boost::thread_resource_error(ret, "Cannot unlock spin lock");
92
92
  }
93
93
  }
94
94
 
@@ -102,7 +102,7 @@ public:
102
102
  } else if (ret == EBUSY) {
103
103
  return false;
104
104
  } else {
105
- throw boost::thread_resource_error("Cannot lock spin lock", ret);
105
+ throw boost::thread_resource_error(ret, "Cannot lock spin lock");
106
106
  }
107
107
  }
108
108
  };
@@ -2,7 +2,7 @@
2
2
  * OXT - OS eXtensions for boosT
3
3
  * Provides important functionality necessary for writing robust server software.
4
4
  *
5
- * Copyright (c) 2010, 2011, 2012 Phusion
5
+ * Copyright (c) 2010-2013 Phusion
6
6
  *
7
7
  * Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  * of this software and associated documentation files (the "Software"), to deal
@@ -36,27 +36,49 @@
36
36
  + __GNUC_MINOR__ * 100 \
37
37
  + __GNUC_PATCHLEVEL__)
38
38
 
39
- #if (defined(__GNUC__) && (__GNUC__ > 2) && !defined(OXT_DEBUG)) || defined(IN_DOXYGEN)
39
+ #if (defined(__GNUC__) && (__GNUC__ > 2)) || defined(IN_DOXYGEN)
40
40
  /**
41
41
  * Indicate that the given expression is likely to be true.
42
42
  * This allows the CPU to better perform branch prediction.
43
- *
44
- * Defining OXT_DEBUG will cause this macro to become an
45
- * empty stub.
46
43
  */
47
44
  #define OXT_LIKELY(expr) __builtin_expect((expr), 1)
48
45
 
49
46
  /**
50
47
  * Indicate that the given expression is likely to be false.
51
48
  * This allows the CPU to better perform branch prediction.
52
- *
53
- * Defining OXT_DEBUG will cause this macro to become an
54
- * empty stub.
55
49
  */
56
50
  #define OXT_UNLIKELY(expr) __builtin_expect((expr), 0)
51
+
52
+ /**
53
+ * Force inlining of the given function.
54
+ */
55
+ #define OXT_FORCE_INLINE __attribute__((always_inline))
56
+
57
+ #if __GNUC__ >= 4
58
+ #define OXT_RESTRICT __restrict__
59
+ #else
60
+ #define OXT_RESTRICT
61
+ #endif
62
+ #ifndef restrict
63
+ /**
64
+ * The C99 'restrict' keyword, now usable in C++.
65
+ */
66
+ #define restrict OXT_RESTRICT
67
+ #endif
68
+ #ifndef restrict_ref
69
+ /**
70
+ * The C99 'restrict' keyword, for use with C++ references.
71
+ * On compilers that support 'restrict' in C++ but not on
72
+ * references, this macro does nothing.
73
+ */
74
+ #define restrict_ref OXT_RESTRICT
75
+ #endif
57
76
  #else
58
77
  #define OXT_LIKELY(expr) expr
59
78
  #define OXT_UNLIKELY(expr) expr
79
+ #define OXT_FORCE_INLINE
80
+ #define restrict
81
+ #define restrict_ref
60
82
  #endif
61
83
 
62
84
  /*
@@ -31,10 +31,10 @@ module PhusionPassenger
31
31
  PACKAGE_NAME = 'passenger'
32
32
 
33
33
  # Phusion Passenger version number. Don't forget to edit ext/common/Constants.h too.
34
- VERSION_STRING = '4.0.0.rc4'
34
+ VERSION_STRING = '4.0.0.rc6'
35
35
 
36
36
  PREFERRED_NGINX_VERSION = '1.2.7'
37
- PREFERRED_PCRE_VERSION = '8.31'
37
+ PREFERRED_PCRE_VERSION = '8.32'
38
38
  STANDALONE_INTERFACE_VERSION = 1
39
39
 
40
40