@@ -70,6 +70,62 @@ bool waitForAnyOutput(Subprocess& proc) {
70
70
LOG (INFO) << " Read " << buffer;
71
71
return len == 1 ;
72
72
}
73
+
74
+ sigset_t makeSignalMask (folly::span<int const > signals) {
75
+ sigset_t sigmask;
76
+ sigemptyset (&sigmask);
77
+ for (auto sig : signals) {
78
+ sigaddset (&sigmask, sig);
79
+ }
80
+ return sigmask;
81
+ }
82
+
83
+ struct ScopedSignalMaskOverride {
84
+ sigset_t sigmask;
85
+ explicit ScopedSignalMaskOverride (folly::span<int const > signals) {
86
+ auto target = makeSignalMask (signals);
87
+ PCHECK (0 == pthread_sigmask (SIG_SETMASK, &target, &sigmask));
88
+ }
89
+ ~ScopedSignalMaskOverride () {
90
+ PCHECK (0 == pthread_sigmask (SIG_SETMASK, &sigmask, nullptr ));
91
+ }
92
+ };
93
+
94
+ uint64_t readSignalMask (sigset_t sigmask) {
95
+ static_assert (NSIG - 1 <= 64 ); // 0 is not a signal
96
+ uint64_t ret = 0 ;
97
+ for (int sig = 1 ; sig < NSIG; ++sig) {
98
+ if (sigismember (&sigmask, sig)) {
99
+ ret |= (uint64_t (1 ) << (sig - 1 ));
100
+ }
101
+ }
102
+ return ret;
103
+ }
104
+
105
+ sigset_t getCurrentSignalMask () {
106
+ sigset_t sigmask;
107
+ pthread_sigmask (SIG_SETMASK, nullptr , &sigmask);
108
+ return sigmask;
109
+ }
110
+
111
+ std::string_view readOneLineOfProcSelfStatus (
112
+ std::string_view text, std::string_view key) {
113
+ std::vector<std::string_view> lines;
114
+ folly::split (' \n ' , text, lines);
115
+ auto prefix = fmt::format (" {}:" , key);
116
+ auto iter = std::find_if (lines.begin (), lines.end (), [&](auto line) {
117
+ return folly::StringPiece (line).starts_with (prefix);
118
+ });
119
+ if (iter == lines.end ()) {
120
+ return {};
121
+ }
122
+ auto line = *iter;
123
+ line.remove_prefix (prefix.size ());
124
+ while (!line.empty () && std::isspace (line[0 ])) {
125
+ line.remove_prefix (1 );
126
+ }
127
+ return line;
128
+ }
73
129
} // namespace
74
130
75
131
struct SubprocessFdActionsListTest : testing::Test {};
@@ -970,3 +1026,36 @@ TEST(WritePidIntoBufTest, WritesPidIntoBufExampleEnvVar) {
970
1026
folly::split (' \n ' , p.first , lines);
971
1027
EXPECT_THAT (lines, testing::Contains (fmt::format (" {}{}" , prefix, pid)));
972
1028
}
1029
+
1030
+ #if defined(__linux__)
1031
+
1032
+ TEST (SetSignalMask, KeepsExistingMask) {
1033
+ // the /proc filesystem, including /proc/self/status, is linux-specific
1034
+ ASSERT_EQ (0 , readSignalMask (getCurrentSignalMask ()));
1035
+ ScopedSignalMaskOverride guard{std::array{SIGURG, SIGCHLD}};
1036
+ auto options = Subprocess::Options ().pipeStdout ();
1037
+ Subprocess proc (
1038
+ std::vector<std::string>{" /bin/cat" , " /proc/self/status" }, options);
1039
+ auto p = proc.communicate ();
1040
+ proc.wait ();
1041
+ auto line = readOneLineOfProcSelfStatus (p.first , " SigBlk" );
1042
+ auto expected = (1 << (SIGURG - 1 )) | (1 << (SIGCHLD - 1 ));
1043
+ EXPECT_EQ (fmt::format (" {:016x}" , expected), line);
1044
+ }
1045
+
1046
+ TEST (SetSignalMask, CanOverrideExistingMask) {
1047
+ // the /proc filesystem, including /proc/self/status, is linux-specific
1048
+ ASSERT_EQ (0 , readSignalMask (getCurrentSignalMask ()));
1049
+ ScopedSignalMaskOverride guard{std::array{SIGURG, SIGCHLD}};
1050
+ auto sigmask = makeSignalMask (std::array{SIGUSR1, SIGUSR2});
1051
+ auto options = Subprocess::Options ().pipeStdout ().setSignalMask (sigmask);
1052
+ Subprocess proc (
1053
+ std::vector<std::string>{" /bin/cat" , " /proc/self/status" }, options);
1054
+ auto p = proc.communicate ();
1055
+ proc.wait ();
1056
+ auto line = readOneLineOfProcSelfStatus (p.first , " SigBlk" );
1057
+ auto expected = (1 << (SIGUSR1 - 1 )) | (1 << (SIGUSR2 - 1 ));
1058
+ EXPECT_EQ (fmt::format (" {:016x}" , expected), line);
1059
+ }
1060
+
1061
+ #endif
0 commit comments