passenger 5.1.10 → 5.1.11
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.
- checksums.yaml +4 -4
- data/CHANGELOG +18 -0
- data/Rakefile +20 -17
- data/bin/passenger-install-apache2-module +14 -11
- data/build/agent.rb +45 -18
- data/build/apache2.rb +32 -16
- data/build/basics.rb +29 -40
- data/build/common_library.rb +70 -54
- data/build/cxx_tests.rb +34 -43
- data/build/integration_tests.rb +10 -10
- data/build/misc.rb +6 -6
- data/build/node_tests.rb +1 -2
- data/build/oxt_tests.rb +7 -5
- data/build/packaging.rb +11 -441
- data/build/ruby_extension.rb +1 -1
- data/build/ruby_tests.rb +1 -2
- data/build/support/cplusplus.rb +6 -5
- data/build/support/cxx_dependency_map.rb +357 -833
- data/build/support/general.rb +23 -1
- data/build/test_basics.rb +3 -28
- data/dev/ci/tests/rpm/Jenkinsfile +68 -0
- data/dev/ci/tests/rpm/run +63 -0
- data/dev/ci/tests/source-packaging/run +1 -1
- data/dev/ci/tests/source-packaging/setup +1 -1
- data/doc/{Packaging.txt.md → Packaging.md} +0 -0
- data/resources/templates/apache2/deployment_example.txt.erb +2 -2
- data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
- data/resources/templates/nginx/deployment_example.txt.erb +1 -1
- data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
- data/resources/templates/standalone/server.erb +2 -2
- data/src/agent/AgentMain.cpp +0 -4
- data/src/agent/Core/CoreMain.cpp +88 -5
- data/src/agent/Core/SpawningKit/Spawner.h +2 -1
- data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
- data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
- data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
- data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
- data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
- data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
- data/src/agent/Shared/Fundamentals/Utils.h +46 -0
- data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
- data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
- data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
- data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
- data/src/apache2_module/Hooks.cpp +4 -1
- data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
- data/src/cxx_supportlib/Constants.h +1 -2
- data/src/cxx_supportlib/Crypto.cpp +2 -1
- data/src/cxx_supportlib/Hooks.h +16 -37
- data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
- data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
- data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
- data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
- data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
- data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
- data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
- data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
- data/src/cxx_supportlib/Utils.cpp +41 -561
- data/src/cxx_supportlib/Utils.h +0 -68
- data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
- data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
- data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
- data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
- data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
- data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
- data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
- data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
- data/src/nginx_module/CacheLocationConfig.c +0 -75
- data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/Configuration.c +0 -1
- data/src/nginx_module/Configuration.h +0 -1
- data/src/nginx_module/ConfigurationCommands.c +1 -1
- data/src/nginx_module/ContentHandler.c +0 -1
- data/src/nginx_module/ContentHandler.h +0 -1
- data/src/nginx_module/CreateLocationConfig.c +0 -5
- data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/LocationConfig.h +0 -4
- data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
- data/src/nginx_module/MergeLocationConfig.c +0 -12
- data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
- data/src/nginx_module/ngx_http_passenger_module.h +0 -1
- data/src/ruby_supportlib/phusion_passenger.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
- data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
- data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
- data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
- data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
- data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
- data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
- data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
- data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
- metadata +19 -97
- data/build/documentation.rb +0 -70
- data/doc/CloudLicensingConfiguration.html +0 -172
- data/doc/CloudLicensingConfiguration.txt.md +0 -3
- data/doc/Packaging.html +0 -488
- data/doc/Security of user switching support.idmap.txt +0 -34
- data/doc/Security of user switching support.txt +0 -197
- data/doc/ServerOptimizationGuide.html +0 -172
- data/doc/ServerOptimizationGuide.txt.md +0 -3
- data/doc/images/by_sa.png +0 -0
- data/doc/images/cloud_licensing_batch_job.png +0 -0
- data/doc/images/code_walkthrough.jpg +0 -0
- data/doc/images/direct_spawning.png +0 -0
- data/doc/images/direct_spawning.svg +0 -251
- data/doc/images/glyphicons-halflings-white.png +0 -0
- data/doc/images/glyphicons-halflings.png +0 -0
- data/doc/images/icons/README +0 -5
- data/doc/images/icons/callouts/1.png +0 -0
- data/doc/images/icons/callouts/10.png +0 -0
- data/doc/images/icons/callouts/11.png +0 -0
- data/doc/images/icons/callouts/12.png +0 -0
- data/doc/images/icons/callouts/13.png +0 -0
- data/doc/images/icons/callouts/14.png +0 -0
- data/doc/images/icons/callouts/15.png +0 -0
- data/doc/images/icons/callouts/2.png +0 -0
- data/doc/images/icons/callouts/3.png +0 -0
- data/doc/images/icons/callouts/4.png +0 -0
- data/doc/images/icons/callouts/5.png +0 -0
- data/doc/images/icons/callouts/6.png +0 -0
- data/doc/images/icons/callouts/7.png +0 -0
- data/doc/images/icons/callouts/8.png +0 -0
- data/doc/images/icons/callouts/9.png +0 -0
- data/doc/images/icons/caution.png +0 -0
- data/doc/images/icons/example.png +0 -0
- data/doc/images/icons/home.png +0 -0
- data/doc/images/icons/important.png +0 -0
- data/doc/images/icons/next.png +0 -0
- data/doc/images/icons/note.png +0 -0
- data/doc/images/icons/prev.png +0 -0
- data/doc/images/icons/tip.png +0 -0
- data/doc/images/icons/up.png +0 -0
- data/doc/images/icons/warning.png +0 -0
- data/doc/images/many_web_framework_protocols.png +0 -0
- data/doc/images/passenger_architecture.png +0 -0
- data/doc/images/passenger_architecture.svg +0 -385
- data/doc/images/passenger_architecture_overview.png +0 -0
- data/doc/images/passenger_core_architecture.png +0 -0
- data/doc/images/passenger_nodejs_architecture.svg +0 -558
- data/doc/images/phusion_banner.png +0 -0
- data/doc/images/rack.png +0 -0
- data/doc/images/smart_spawning.png +0 -0
- data/doc/images/smart_spawning.svg +0 -323
- data/doc/images/spawn_server_architecture.png +0 -0
- data/doc/images/spawn_server_architecture.svg +0 -655
- data/doc/images/spawning_preparation_work.png +0 -0
- data/doc/images/startup_sequence.png +0 -0
- data/doc/images/typical_isolated_web_application.png +0 -0
- data/doc/images/typical_isolated_web_application.svg +0 -213
- data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
- data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
- data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
- data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
- data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
- data/doc/users_guide_snippets/deployment_basics.txt +0 -37
- data/doc/users_guide_snippets/enterprise_only.txt +0 -1
- data/doc/users_guide_snippets/environment_variables.txt +0 -44
- data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
- data/doc/users_guide_snippets/installation.txt +0 -228
- data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
- data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
- data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
- data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
- data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
- data/doc/users_guide_snippets/since_version.txt +0 -1
- data/doc/users_guide_snippets/support_information.txt +0 -8
- data/doc/users_guide_snippets/tips.txt +0 -302
- data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
- data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
- data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
- data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
- data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
- data/src/agent/Shared/Base.cpp +0 -1678
- data/src/agent/UstRouter/ApiServer.h +0 -292
- data/src/agent/UstRouter/Client.h +0 -112
- data/src/agent/UstRouter/Controller.h +0 -1309
- data/src/agent/UstRouter/LogSink.h +0 -145
- data/src/agent/UstRouter/OptionParser.h +0 -180
- data/src/agent/UstRouter/RemoteSender.h +0 -853
- data/src/agent/UstRouter/RemoteSink.h +0 -145
- data/src/agent/UstRouter/Transaction.h +0 -278
- data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
- data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
- data/src/ruby_supportlib/phusion_passenger/platform_info/macos.rb +0 -45
@@ -0,0 +1,107 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 2010-2017 Phusion Holding B.V.
|
4
|
+
*
|
5
|
+
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
|
+
* trademarks of Phusion Holding B.V.
|
7
|
+
*
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
13
|
+
* furnished to do so, subject to the following conditions:
|
14
|
+
*
|
15
|
+
* The above copyright notice and this permission notice shall be included in
|
16
|
+
* all copies or substantial portions of the Software.
|
17
|
+
*
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
|
+
* THE SOFTWARE.
|
25
|
+
*/
|
26
|
+
#ifndef _PASSENGER_PROCESS_MANAGEMENT_UTILS_H_
|
27
|
+
#define _PASSENGER_PROCESS_MANAGEMENT_UTILS_H_
|
28
|
+
|
29
|
+
#include <sys/types.h>
|
30
|
+
|
31
|
+
namespace Passenger {
|
32
|
+
|
33
|
+
using namespace std;
|
34
|
+
|
35
|
+
|
36
|
+
/**
|
37
|
+
* Thread-safe and async-signal safe way to fork().
|
38
|
+
*
|
39
|
+
* On Linux, the fork() glibc wrapper grabs a ptmalloc lock, so
|
40
|
+
* if malloc causes a segfault then we can't fork.
|
41
|
+
* http://sourceware.org/bugzilla/show_bug.cgi?id=4737
|
42
|
+
*
|
43
|
+
* OS X apparently does something similar, except they use a
|
44
|
+
* spinlock so it results in 100% CPU. See _cthread_fork_prepare()
|
45
|
+
* at http://www.opensource.apple.com/source/Libc/Libc-166/threads.subproj/cthreads.c
|
46
|
+
* However, since POSIX in OS X is implemented on top of a Mach layer,
|
47
|
+
* calling asyncFork() can mess up the state of the Mach layer, causing
|
48
|
+
* some POSIX functions to mysteriously fail. See
|
49
|
+
* https://code.google.com/p/phusion-passenger/issues/detail?id=1094
|
50
|
+
* You should therefore not use asyncFork() unless you're in a signal
|
51
|
+
* handler or if you only perform async-signal-safe stuff in the child.
|
52
|
+
*
|
53
|
+
* On 2017 October 9 with macOS 10.11 El Capitan, we also confirmed
|
54
|
+
* a case in which the child process can get stuck indefinitely with 0% CPU.
|
55
|
+
* If we we create a thread which performs memory allocation, and shortly
|
56
|
+
* after thread creation we fork, then the child process gets stuck because
|
57
|
+
* one of its pthread_atfork() handlers tries to allocate memory, which tries
|
58
|
+
* to grab a lock which was already locked. This means that on macOS
|
59
|
+
* we pretty much can never use regular fork() at all in a multithreaded
|
60
|
+
* environment.
|
61
|
+
*/
|
62
|
+
pid_t asyncFork();
|
63
|
+
|
64
|
+
/**
|
65
|
+
* Resets the current process's signal handler disposition and signal mask
|
66
|
+
* to default values. One should call this every time one forks a child process;
|
67
|
+
* non-default signal masks/handler dispositions can cause all kinds of weird quirks,
|
68
|
+
* like waitpid() malfunctioning on macOS.
|
69
|
+
*
|
70
|
+
* This function is async-signal safe.
|
71
|
+
*/
|
72
|
+
void resetSignalHandlersAndMask();
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Disables malloc() debugging facilities on macOS.
|
76
|
+
*/
|
77
|
+
void disableMallocDebugging();
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Close all file descriptors that are higher than `lastToKeepOpen`.
|
81
|
+
*
|
82
|
+
* If you set `asyncSignalSafe` to true, then this function becomes fully async-signal,
|
83
|
+
* through the use of asyncFork() instead of fork(). However, read the documentation
|
84
|
+
* for asyncFork() to learn about its caveats.
|
85
|
+
*
|
86
|
+
* Also, regardless of whether `asyncSignalSafe` is true or not, this function is not
|
87
|
+
* *thread* safe. Make sure there are no other threads running that might open file
|
88
|
+
* descriptors, otherwise some file descriptors might not be closed even though they
|
89
|
+
* should be.
|
90
|
+
*/
|
91
|
+
void closeAllFileDescriptors(int lastToKeepOpen, bool asyncSignalSafe = false);
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Given a failed exec() syscall and its resulting errno
|
95
|
+
* value, print an appropriate error message to STDERR.
|
96
|
+
*
|
97
|
+
* This function is async signal-safe. Its main intended use is to be the
|
98
|
+
* default value for the `onExecFail` parameter for the
|
99
|
+
* `runCommand()` and `runCommandAndCaptureOutput()` functions.
|
100
|
+
*/
|
101
|
+
void printExecError(const char **command, int errcode);
|
102
|
+
void printExecError2(const char **command, int errcode, char *buf, size_t size);
|
103
|
+
|
104
|
+
|
105
|
+
} // namespace Passenger
|
106
|
+
|
107
|
+
#endif /* _PASSENGER_PROCESS_MANAGEMENT_UTILS_H_ */
|
@@ -30,6 +30,7 @@
|
|
30
30
|
|
31
31
|
#include <algorithm>
|
32
32
|
#include <cassert>
|
33
|
+
#include <cstdio>
|
33
34
|
#include <cstdlib>
|
34
35
|
#include <cstring>
|
35
36
|
#include <cerrno>
|
@@ -55,6 +56,8 @@
|
|
55
56
|
#include <FileDescriptor.h>
|
56
57
|
#include <ResourceLocator.h>
|
57
58
|
#include <Exceptions.h>
|
59
|
+
#include <ProcessManagement/Spawn.h>
|
60
|
+
#include <ProcessManagement/Utils.h>
|
58
61
|
#include <Utils.h>
|
59
62
|
#include <Utils/CachedFileStat.hpp>
|
60
63
|
#include <Utils/StrIntUtils.h>
|
@@ -69,16 +72,9 @@
|
|
69
72
|
#define HOST_NAME_MAX 255
|
70
73
|
#endif
|
71
74
|
#endif
|
72
|
-
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
|
73
|
-
// Introduced in Solaris 9. Let's hope nobody actually uses
|
74
|
-
// a version that doesn't support this.
|
75
|
-
#define HAS_CLOSEFROM
|
76
|
-
#endif
|
77
75
|
|
78
76
|
namespace Passenger {
|
79
77
|
|
80
|
-
static string passengerTempDir;
|
81
|
-
|
82
78
|
namespace {
|
83
79
|
/**
|
84
80
|
* Given a filename, FileGuard will unlink the file in its destructor, unless
|
@@ -717,54 +713,38 @@ makeDirTree(const string &path, const StaticString &mode, uid_t owner, gid_t gro
|
|
717
713
|
}
|
718
714
|
}
|
719
715
|
|
720
|
-
void
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
pid = syscalls::fork();
|
728
|
-
if (pid == 0) {
|
729
|
-
resetSignalHandlersAndMask();
|
730
|
-
disableMallocDebugging();
|
731
|
-
int devnull = open("/dev/null", O_RDONLY);
|
732
|
-
if (devnull != -1) {
|
733
|
-
dup2(devnull, 2);
|
734
|
-
}
|
735
|
-
closeAllFileDescriptors(2);
|
736
|
-
execlp("chmod", "chmod", "-R", "u+rwx", c_path, (char * const) 0);
|
737
|
-
perror("Cannot execute chmod");
|
738
|
-
_exit(1);
|
739
|
-
|
740
|
-
} else if (pid == -1) {
|
741
|
-
int e = errno;
|
742
|
-
throw SystemException("Cannot fork a new process", e);
|
743
|
-
|
744
|
-
} else {
|
745
|
-
boost::this_thread::restore_interruption ri(di);
|
746
|
-
boost::this_thread::restore_syscall_interruption rsi(dsi);
|
747
|
-
syscalls::waitpid(pid, NULL, 0);
|
716
|
+
static void
|
717
|
+
redirectStderrToDevNull() {
|
718
|
+
int devnull = open("/dev/null", O_RDONLY);
|
719
|
+
if (devnull > 2) {
|
720
|
+
dup2(devnull, 2);
|
721
|
+
close(devnull);
|
748
722
|
}
|
723
|
+
}
|
749
724
|
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
725
|
+
void
|
726
|
+
removeDirTree(const string &path) {
|
727
|
+
{
|
728
|
+
const char *command[] = {
|
729
|
+
"chmod",
|
730
|
+
"-R",
|
731
|
+
"u+rwx",
|
732
|
+
path.c_str(),
|
733
|
+
NULL
|
734
|
+
};
|
735
|
+
SubprocessInfo info;
|
736
|
+
runCommand(command, info, true, true, redirectStderrToDevNull);
|
737
|
+
}
|
738
|
+
{
|
739
|
+
const char *command[] = {
|
740
|
+
"rm",
|
741
|
+
"-rf",
|
742
|
+
path.c_str(),
|
743
|
+
NULL
|
744
|
+
};
|
745
|
+
SubprocessInfo info;
|
746
|
+
runCommand(command, info, true, true, redirectStderrToDevNull);
|
747
|
+
if (info.status != 0 && info.status != -2) {
|
768
748
|
throw RuntimeException("Cannot remove directory '" + path + "'");
|
769
749
|
}
|
770
750
|
}
|
@@ -782,8 +762,6 @@ prestartWebApps(const ResourceLocator &locator, const string &ruby,
|
|
782
762
|
*/
|
783
763
|
syscalls::sleep(2);
|
784
764
|
|
785
|
-
boost::this_thread::disable_interruption di;
|
786
|
-
boost::this_thread::disable_syscall_interruption dsi;
|
787
765
|
vector<string>::const_iterator it;
|
788
766
|
string prespawnScript = locator.getHelperScriptsDir() + "/prespawn";
|
789
767
|
|
@@ -794,47 +772,15 @@ prestartWebApps(const ResourceLocator &locator, const string &ruby,
|
|
794
772
|
continue;
|
795
773
|
}
|
796
774
|
|
797
|
-
|
775
|
+
const char *command[] = {
|
776
|
+
ruby.c_str(),
|
777
|
+
prespawnScript.c_str(),
|
778
|
+
it->c_str(),
|
779
|
+
NULL
|
780
|
+
};
|
781
|
+
SubprocessInfo info;
|
782
|
+
runCommand(command, info);
|
798
783
|
|
799
|
-
pid = fork();
|
800
|
-
if (pid == 0) {
|
801
|
-
long max_fds, i;
|
802
|
-
int e;
|
803
|
-
|
804
|
-
// Close all unnecessary file descriptors.
|
805
|
-
max_fds = sysconf(_SC_OPEN_MAX);
|
806
|
-
for (i = 3; i < max_fds; i++) {
|
807
|
-
syscalls::close(i);
|
808
|
-
}
|
809
|
-
|
810
|
-
execlp(ruby.c_str(),
|
811
|
-
ruby.c_str(),
|
812
|
-
prespawnScript.c_str(),
|
813
|
-
it->c_str(),
|
814
|
-
(char *) 0);
|
815
|
-
e = errno;
|
816
|
-
fprintf(stderr, "Cannot execute '%s %s %s': %s (%d)\n",
|
817
|
-
ruby.c_str(),
|
818
|
-
prespawnScript.c_str(), it->c_str(),
|
819
|
-
strerror(e), e);
|
820
|
-
fflush(stderr);
|
821
|
-
_exit(1);
|
822
|
-
} else if (pid == -1) {
|
823
|
-
perror("fork()");
|
824
|
-
} else {
|
825
|
-
try {
|
826
|
-
boost::this_thread::restore_interruption si(di);
|
827
|
-
boost::this_thread::restore_syscall_interruption ssi(dsi);
|
828
|
-
syscalls::waitpid(pid, NULL, 0);
|
829
|
-
} catch (const thread_interrupted &) {
|
830
|
-
syscalls::kill(SIGKILL, pid);
|
831
|
-
syscalls::waitpid(pid, NULL, 0);
|
832
|
-
throw;
|
833
|
-
}
|
834
|
-
}
|
835
|
-
|
836
|
-
boost::this_thread::restore_interruption si(di);
|
837
|
-
boost::this_thread::restore_syscall_interruption ssi(dsi);
|
838
784
|
syscalls::sleep(1);
|
839
785
|
it++;
|
840
786
|
}
|
@@ -923,472 +869,6 @@ getSignalName(int sig) {
|
|
923
869
|
}
|
924
870
|
}
|
925
871
|
|
926
|
-
void
|
927
|
-
resetSignalHandlersAndMask() {
|
928
|
-
struct sigaction action;
|
929
|
-
action.sa_handler = SIG_DFL;
|
930
|
-
action.sa_flags = SA_RESTART;
|
931
|
-
sigemptyset(&action.sa_mask);
|
932
|
-
sigaction(SIGHUP, &action, NULL);
|
933
|
-
sigaction(SIGINT, &action, NULL);
|
934
|
-
sigaction(SIGQUIT, &action, NULL);
|
935
|
-
sigaction(SIGILL, &action, NULL);
|
936
|
-
sigaction(SIGTRAP, &action, NULL);
|
937
|
-
sigaction(SIGABRT, &action, NULL);
|
938
|
-
#ifdef SIGEMT
|
939
|
-
sigaction(SIGEMT, &action, NULL);
|
940
|
-
#endif
|
941
|
-
sigaction(SIGFPE, &action, NULL);
|
942
|
-
sigaction(SIGBUS, &action, NULL);
|
943
|
-
sigaction(SIGSEGV, &action, NULL);
|
944
|
-
sigaction(SIGSYS, &action, NULL);
|
945
|
-
sigaction(SIGPIPE, &action, NULL);
|
946
|
-
sigaction(SIGALRM, &action, NULL);
|
947
|
-
sigaction(SIGTERM, &action, NULL);
|
948
|
-
sigaction(SIGURG, &action, NULL);
|
949
|
-
sigaction(SIGSTOP, &action, NULL);
|
950
|
-
sigaction(SIGTSTP, &action, NULL);
|
951
|
-
sigaction(SIGCONT, &action, NULL);
|
952
|
-
sigaction(SIGCHLD, &action, NULL);
|
953
|
-
#ifdef SIGINFO
|
954
|
-
sigaction(SIGINFO, &action, NULL);
|
955
|
-
#endif
|
956
|
-
sigaction(SIGUSR1, &action, NULL);
|
957
|
-
sigaction(SIGUSR2, &action, NULL);
|
958
|
-
|
959
|
-
// We reset the signal mask after resetting the signal handlers,
|
960
|
-
// because prior to calling resetSignalHandlersAndMask(), the
|
961
|
-
// process might be blocked on some signals. We want those signals
|
962
|
-
// to be processed after installing the new signal handlers
|
963
|
-
// so that bugs like https://github.com/phusion/passenger/pull/97
|
964
|
-
// can be prevented.
|
965
|
-
|
966
|
-
sigset_t signal_set;
|
967
|
-
int ret;
|
968
|
-
|
969
|
-
sigemptyset(&signal_set);
|
970
|
-
do {
|
971
|
-
ret = sigprocmask(SIG_SETMASK, &signal_set, NULL);
|
972
|
-
} while (ret == -1 && errno == EINTR);
|
973
|
-
}
|
974
|
-
|
975
|
-
void
|
976
|
-
disableMallocDebugging() {
|
977
|
-
unsetenv("MALLOC_FILL_SPACE");
|
978
|
-
unsetenv("MALLOC_PROTECT_BEFORE");
|
979
|
-
unsetenv("MallocGuardEdges");
|
980
|
-
unsetenv("MallocScribble");
|
981
|
-
unsetenv("MallocPreScribble");
|
982
|
-
unsetenv("MallocCheckHeapStart");
|
983
|
-
unsetenv("MallocCheckHeapEach");
|
984
|
-
unsetenv("MallocCheckHeapAbort");
|
985
|
-
unsetenv("MallocBadFreeAbort");
|
986
|
-
unsetenv("MALLOC_CHECK_");
|
987
|
-
|
988
|
-
const char *libs = getenv("DYLD_INSERT_LIBRARIES");
|
989
|
-
if (libs != NULL && strstr(libs, "/usr/lib/libgmalloc.dylib")) {
|
990
|
-
string newLibs = libs;
|
991
|
-
string::size_type pos = newLibs.find("/usr/lib/libgmalloc.dylib");
|
992
|
-
size_t len = strlen("/usr/lib/libgmalloc.dylib");
|
993
|
-
|
994
|
-
// Erase all leading ':' too.
|
995
|
-
while (pos > 0 && newLibs[pos - 1] == ':') {
|
996
|
-
pos--;
|
997
|
-
len++;
|
998
|
-
}
|
999
|
-
// Erase all trailing ':' too.
|
1000
|
-
while (pos + len < newLibs.size() && newLibs[pos + len] == ':') {
|
1001
|
-
len++;
|
1002
|
-
}
|
1003
|
-
|
1004
|
-
newLibs.erase(pos, len);
|
1005
|
-
if (newLibs.empty()) {
|
1006
|
-
unsetenv("DYLD_INSERT_LIBRARIES");
|
1007
|
-
} else {
|
1008
|
-
setenv("DYLD_INSERT_LIBRARIES", newLibs.c_str(), 1);
|
1009
|
-
}
|
1010
|
-
}
|
1011
|
-
}
|
1012
|
-
|
1013
|
-
int
|
1014
|
-
runShellCommand(const StaticString &command) {
|
1015
|
-
pid_t pid = fork();
|
1016
|
-
if (pid == 0) {
|
1017
|
-
resetSignalHandlersAndMask();
|
1018
|
-
disableMallocDebugging();
|
1019
|
-
closeAllFileDescriptors(2);
|
1020
|
-
execlp("/bin/sh", "/bin/sh", "-c", command.data(), (char * const) 0);
|
1021
|
-
_exit(1);
|
1022
|
-
} else if (pid == -1) {
|
1023
|
-
return -1;
|
1024
|
-
} else {
|
1025
|
-
int status;
|
1026
|
-
if (waitpid(pid, &status, 0) == -1) {
|
1027
|
-
return -1;
|
1028
|
-
} else {
|
1029
|
-
return status;
|
1030
|
-
}
|
1031
|
-
}
|
1032
|
-
}
|
1033
|
-
|
1034
|
-
string
|
1035
|
-
runCommandAndCaptureOutput(const char **command, int *status) {
|
1036
|
-
pid_t pid, waitRet;
|
1037
|
-
int e, waitStatus;
|
1038
|
-
Pipe p;
|
1039
|
-
|
1040
|
-
p = createPipe(__FILE__, __LINE__);
|
1041
|
-
|
1042
|
-
boost::this_thread::disable_syscall_interruption dsi;
|
1043
|
-
pid = syscalls::fork();
|
1044
|
-
if (pid == 0) {
|
1045
|
-
// Make ps nicer, we want to have as little impact on the rest
|
1046
|
-
// of the system as possible while collecting the metrics.
|
1047
|
-
int prio = getpriority(PRIO_PROCESS, getpid());
|
1048
|
-
prio++;
|
1049
|
-
if (prio > 20) {
|
1050
|
-
prio = 20;
|
1051
|
-
}
|
1052
|
-
setpriority(PRIO_PROCESS, getpid(), prio);
|
1053
|
-
|
1054
|
-
dup2(p[1], 1);
|
1055
|
-
close(p[0]);
|
1056
|
-
close(p[1]);
|
1057
|
-
closeAllFileDescriptors(2);
|
1058
|
-
execvp(command[0], (char * const *) command);
|
1059
|
-
_exit(1);
|
1060
|
-
} else if (pid == -1) {
|
1061
|
-
e = errno;
|
1062
|
-
throw SystemException("Cannot fork() a new process", e);
|
1063
|
-
} else {
|
1064
|
-
bool done = false;
|
1065
|
-
string result;
|
1066
|
-
|
1067
|
-
p[1].close();
|
1068
|
-
while (!done) {
|
1069
|
-
char buf[1024 * 4];
|
1070
|
-
ssize_t ret;
|
1071
|
-
|
1072
|
-
try {
|
1073
|
-
boost::this_thread::restore_syscall_interruption rsi(dsi);
|
1074
|
-
ret = syscalls::read(p[0], buf, sizeof(buf));
|
1075
|
-
} catch (const thread_interrupted &) {
|
1076
|
-
syscalls::kill(SIGKILL, pid);
|
1077
|
-
syscalls::waitpid(pid, NULL, 0);
|
1078
|
-
throw;
|
1079
|
-
}
|
1080
|
-
if (ret == -1) {
|
1081
|
-
e = errno;
|
1082
|
-
syscalls::kill(SIGKILL, pid);
|
1083
|
-
syscalls::waitpid(pid, NULL, 0);
|
1084
|
-
throw SystemException(string("Cannot read output from the '") +
|
1085
|
-
command[0] + "' command", e);
|
1086
|
-
}
|
1087
|
-
done = ret == 0;
|
1088
|
-
result.append(buf, ret);
|
1089
|
-
}
|
1090
|
-
p[0].close();
|
1091
|
-
|
1092
|
-
waitRet = syscalls::waitpid(pid, &waitStatus, 0);
|
1093
|
-
if (waitRet != -1) {
|
1094
|
-
if (status != NULL) {
|
1095
|
-
*status = waitStatus;
|
1096
|
-
}
|
1097
|
-
} else if (errno == ECHILD || errno == ESRCH) {
|
1098
|
-
if (status != NULL) {
|
1099
|
-
*status = -1;
|
1100
|
-
}
|
1101
|
-
} else {
|
1102
|
-
int e = errno;
|
1103
|
-
throw SystemException(string("Error waiting for the '") +
|
1104
|
-
command[0] + "' command", e);
|
1105
|
-
}
|
1106
|
-
return result;
|
1107
|
-
}
|
1108
|
-
}
|
1109
|
-
|
1110
|
-
#ifdef __APPLE__
|
1111
|
-
// http://www.opensource.apple.com/source/Libc/Libc-825.26/sys/fork.c
|
1112
|
-
// This bypasses atfork handlers.
|
1113
|
-
extern "C" {
|
1114
|
-
extern pid_t __fork(void);
|
1115
|
-
}
|
1116
|
-
#endif
|
1117
|
-
|
1118
|
-
pid_t
|
1119
|
-
asyncFork() {
|
1120
|
-
#if defined(__linux__)
|
1121
|
-
#if defined(SYS_fork)
|
1122
|
-
return (pid_t) syscall(SYS_fork);
|
1123
|
-
#else
|
1124
|
-
return syscall(SYS_clone, SIGCHLD, 0, 0, 0, 0);
|
1125
|
-
#endif
|
1126
|
-
#elif defined(__APPLE__)
|
1127
|
-
return __fork();
|
1128
|
-
#else
|
1129
|
-
return fork();
|
1130
|
-
#endif
|
1131
|
-
}
|
1132
|
-
|
1133
|
-
// Async-signal safe way to get the current process's hard file descriptor limit.
|
1134
|
-
static int
|
1135
|
-
getFileDescriptorLimit() {
|
1136
|
-
long long sysconfResult = sysconf(_SC_OPEN_MAX);
|
1137
|
-
|
1138
|
-
struct rlimit rl;
|
1139
|
-
long long rlimitResult;
|
1140
|
-
if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
|
1141
|
-
rlimitResult = 0;
|
1142
|
-
} else {
|
1143
|
-
rlimitResult = (long long) rl.rlim_max;
|
1144
|
-
}
|
1145
|
-
|
1146
|
-
long result;
|
1147
|
-
// OS X 10.9 returns LLONG_MAX. It doesn't make sense
|
1148
|
-
// to use that result so we limit ourselves to the
|
1149
|
-
// sysconf result.
|
1150
|
-
if (rlimitResult >= INT_MAX || sysconfResult > rlimitResult) {
|
1151
|
-
result = sysconfResult;
|
1152
|
-
} else {
|
1153
|
-
result = rlimitResult;
|
1154
|
-
}
|
1155
|
-
|
1156
|
-
if (result < 0) {
|
1157
|
-
// Unable to query the file descriptor limit.
|
1158
|
-
result = 9999;
|
1159
|
-
} else if (result < 2) {
|
1160
|
-
// The calls reported broken values.
|
1161
|
-
result = 2;
|
1162
|
-
}
|
1163
|
-
return result;
|
1164
|
-
}
|
1165
|
-
|
1166
|
-
// Async-signal safe function to get the highest file
|
1167
|
-
// descriptor that the process is currently using.
|
1168
|
-
// See also http://stackoverflow.com/questions/899038/getting-the-highest-allocated-file-descriptor
|
1169
|
-
static int
|
1170
|
-
getHighestFileDescriptor(bool asyncSignalSafe) {
|
1171
|
-
#if defined(F_MAXFD)
|
1172
|
-
int ret;
|
1173
|
-
|
1174
|
-
do {
|
1175
|
-
ret = fcntl(0, F_MAXFD);
|
1176
|
-
} while (ret == -1 && errno == EINTR);
|
1177
|
-
if (ret == -1) {
|
1178
|
-
ret = getFileDescriptorLimit();
|
1179
|
-
}
|
1180
|
-
return ret;
|
1181
|
-
|
1182
|
-
#else
|
1183
|
-
int p[2], ret, flags;
|
1184
|
-
pid_t pid = -1;
|
1185
|
-
int result = -1;
|
1186
|
-
|
1187
|
-
/* Since opendir() may not be async signal safe and thus may lock up
|
1188
|
-
* or crash, we use it in a child process which we kill if we notice
|
1189
|
-
* that things are going wrong.
|
1190
|
-
*/
|
1191
|
-
|
1192
|
-
// Make a pipe.
|
1193
|
-
p[0] = p[1] = -1;
|
1194
|
-
do {
|
1195
|
-
ret = pipe(p);
|
1196
|
-
} while (ret == -1 && errno == EINTR);
|
1197
|
-
if (ret == -1) {
|
1198
|
-
goto done;
|
1199
|
-
}
|
1200
|
-
|
1201
|
-
// Make the read side non-blocking.
|
1202
|
-
do {
|
1203
|
-
flags = fcntl(p[0], F_GETFL);
|
1204
|
-
} while (flags == -1 && errno == EINTR);
|
1205
|
-
if (flags == -1) {
|
1206
|
-
goto done;
|
1207
|
-
}
|
1208
|
-
do {
|
1209
|
-
fcntl(p[0], F_SETFL, flags | O_NONBLOCK);
|
1210
|
-
} while (ret == -1 && errno == EINTR);
|
1211
|
-
if (ret == -1) {
|
1212
|
-
goto done;
|
1213
|
-
}
|
1214
|
-
|
1215
|
-
if (asyncSignalSafe) {
|
1216
|
-
do {
|
1217
|
-
pid = asyncFork();
|
1218
|
-
} while (pid == -1 && errno == EINTR);
|
1219
|
-
} else {
|
1220
|
-
do {
|
1221
|
-
pid = fork();
|
1222
|
-
} while (pid == -1 && errno == EINTR);
|
1223
|
-
}
|
1224
|
-
|
1225
|
-
if (pid == 0) {
|
1226
|
-
// Don't close p[0] here or it might affect the result.
|
1227
|
-
|
1228
|
-
resetSignalHandlersAndMask();
|
1229
|
-
|
1230
|
-
struct sigaction action;
|
1231
|
-
action.sa_handler = _exit;
|
1232
|
-
action.sa_flags = SA_RESTART;
|
1233
|
-
sigemptyset(&action.sa_mask);
|
1234
|
-
sigaction(SIGSEGV, &action, NULL);
|
1235
|
-
sigaction(SIGPIPE, &action, NULL);
|
1236
|
-
sigaction(SIGBUS, &action, NULL);
|
1237
|
-
sigaction(SIGILL, &action, NULL);
|
1238
|
-
sigaction(SIGFPE, &action, NULL);
|
1239
|
-
sigaction(SIGABRT, &action, NULL);
|
1240
|
-
|
1241
|
-
DIR *dir = NULL;
|
1242
|
-
#ifdef __APPLE__
|
1243
|
-
/* /dev/fd can always be trusted on OS X. */
|
1244
|
-
dir = opendir("/dev/fd");
|
1245
|
-
#else
|
1246
|
-
/* On FreeBSD and possibly other operating systems, /dev/fd only
|
1247
|
-
* works if fdescfs is mounted. If it isn't mounted then /dev/fd
|
1248
|
-
* still exists but always returns [0, 1, 2] and thus can't be
|
1249
|
-
* trusted. If /dev and /dev/fd are on different filesystems
|
1250
|
-
* then that probably means fdescfs is mounted.
|
1251
|
-
*/
|
1252
|
-
struct stat dirbuf1, dirbuf2;
|
1253
|
-
if (stat("/dev", &dirbuf1) == -1
|
1254
|
-
|| stat("/dev/fd", &dirbuf2) == -1) {
|
1255
|
-
_exit(1);
|
1256
|
-
}
|
1257
|
-
if (dirbuf1.st_dev != dirbuf2.st_dev) {
|
1258
|
-
dir = opendir("/dev/fd");
|
1259
|
-
}
|
1260
|
-
#endif
|
1261
|
-
if (dir == NULL) {
|
1262
|
-
dir = opendir("/proc/self/fd");
|
1263
|
-
if (dir == NULL) {
|
1264
|
-
_exit(1);
|
1265
|
-
}
|
1266
|
-
}
|
1267
|
-
|
1268
|
-
struct dirent *ent;
|
1269
|
-
union {
|
1270
|
-
int highest;
|
1271
|
-
char data[sizeof(int)];
|
1272
|
-
} u;
|
1273
|
-
u.highest = -1;
|
1274
|
-
|
1275
|
-
while ((ent = readdir(dir)) != NULL) {
|
1276
|
-
if (ent->d_name[0] != '.') {
|
1277
|
-
int number = atoi(ent->d_name);
|
1278
|
-
if (number > u.highest) {
|
1279
|
-
u.highest = number;
|
1280
|
-
}
|
1281
|
-
}
|
1282
|
-
}
|
1283
|
-
if (u.highest != -1) {
|
1284
|
-
ssize_t ret, written = 0;
|
1285
|
-
do {
|
1286
|
-
ret = write(p[1], u.data + written, sizeof(int) - written);
|
1287
|
-
if (ret == -1) {
|
1288
|
-
_exit(1);
|
1289
|
-
}
|
1290
|
-
written += ret;
|
1291
|
-
} while (written < (ssize_t) sizeof(int));
|
1292
|
-
}
|
1293
|
-
closedir(dir);
|
1294
|
-
_exit(0);
|
1295
|
-
|
1296
|
-
} else if (pid == -1) {
|
1297
|
-
goto done;
|
1298
|
-
|
1299
|
-
} else {
|
1300
|
-
close(p[1]); // Do not retry on EINTR: http://news.ycombinator.com/item?id=3363819
|
1301
|
-
p[1] = -1;
|
1302
|
-
|
1303
|
-
union {
|
1304
|
-
int highest;
|
1305
|
-
char data[sizeof(int)];
|
1306
|
-
} u;
|
1307
|
-
ssize_t ret, bytesRead = 0;
|
1308
|
-
struct pollfd pfd;
|
1309
|
-
pfd.fd = p[0];
|
1310
|
-
pfd.events = POLLIN;
|
1311
|
-
|
1312
|
-
do {
|
1313
|
-
do {
|
1314
|
-
// The child process must finish within 30 ms, otherwise
|
1315
|
-
// we might as well query sysconf.
|
1316
|
-
ret = poll(&pfd, 1, 30);
|
1317
|
-
} while (ret == -1 && errno == EINTR);
|
1318
|
-
if (ret <= 0) {
|
1319
|
-
goto done;
|
1320
|
-
}
|
1321
|
-
|
1322
|
-
do {
|
1323
|
-
ret = read(p[0], u.data + bytesRead, sizeof(int) - bytesRead);
|
1324
|
-
} while (ret == -1 && errno == EINTR);
|
1325
|
-
if (ret == -1) {
|
1326
|
-
if (errno != EAGAIN) {
|
1327
|
-
goto done;
|
1328
|
-
}
|
1329
|
-
} else if (ret == 0) {
|
1330
|
-
goto done;
|
1331
|
-
} else {
|
1332
|
-
bytesRead += ret;
|
1333
|
-
}
|
1334
|
-
} while (bytesRead < (ssize_t) sizeof(int));
|
1335
|
-
|
1336
|
-
result = u.highest;
|
1337
|
-
goto done;
|
1338
|
-
}
|
1339
|
-
|
1340
|
-
done:
|
1341
|
-
// Do not retry on EINTR: http://news.ycombinator.com/item?id=3363819
|
1342
|
-
if (p[0] != -1) {
|
1343
|
-
close(p[0]);
|
1344
|
-
}
|
1345
|
-
if (p[1] != -1) {
|
1346
|
-
close(p[1]);
|
1347
|
-
}
|
1348
|
-
if (pid != -1) {
|
1349
|
-
do {
|
1350
|
-
ret = kill(pid, SIGKILL);
|
1351
|
-
} while (ret == -1 && errno == EINTR);
|
1352
|
-
do {
|
1353
|
-
ret = waitpid(pid, NULL, 0);
|
1354
|
-
} while (ret == -1 && errno == EINTR);
|
1355
|
-
}
|
1356
|
-
|
1357
|
-
if (result == -1) {
|
1358
|
-
result = getFileDescriptorLimit();
|
1359
|
-
}
|
1360
|
-
return result;
|
1361
|
-
#endif
|
1362
|
-
}
|
1363
|
-
|
1364
|
-
void
|
1365
|
-
closeAllFileDescriptors(int lastToKeepOpen, bool asyncSignalSafe) {
|
1366
|
-
#if defined(F_CLOSEM)
|
1367
|
-
int ret;
|
1368
|
-
do {
|
1369
|
-
ret = fcntl(lastToKeepOpen + 1, F_CLOSEM);
|
1370
|
-
} while (ret == -1 && errno == EINTR);
|
1371
|
-
if (ret != -1) {
|
1372
|
-
return;
|
1373
|
-
}
|
1374
|
-
#elif defined(HAS_CLOSEFROM)
|
1375
|
-
closefrom(lastToKeepOpen + 1);
|
1376
|
-
return;
|
1377
|
-
#endif
|
1378
|
-
|
1379
|
-
for (int i = getHighestFileDescriptor(asyncSignalSafe); i > lastToKeepOpen; i--) {
|
1380
|
-
/* Even though we normally shouldn't retry on EINTR
|
1381
|
-
* (http://news.ycombinator.com/item?id=3363819)
|
1382
|
-
* it's okay to do that here because because this function
|
1383
|
-
* may only be called in a single-threaded environment.
|
1384
|
-
*/
|
1385
|
-
int ret;
|
1386
|
-
do {
|
1387
|
-
ret = close(i);
|
1388
|
-
} while (ret == -1 && errno == EINTR);
|
1389
|
-
}
|
1390
|
-
}
|
1391
|
-
|
1392
872
|
void
|
1393
873
|
breakpoint() {
|
1394
874
|
// No-op.
|