Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
B
brpc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
brpc
Commits
ffead26e
Commit
ffead26e
authored
Dec 02, 2017
by
Zhangyi Chen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Default implementation of read_command_output is based on popen right now since
we met some weird bug
parent
6c34eb53
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
124 additions
and
20 deletions
+124
-20
popen.cpp
src/butil/popen.cpp
+35
-12
popen_unittest.cpp
test/popen_unittest.cpp
+89
-8
No files found.
src/butil/popen.cpp
View file @
ffead26e
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
// Author: Zhangyi Chen (chenzhangyi01@baidu.com)
// Author: Zhangyi Chen (chenzhangyi01@baidu.com)
// Date: 2017/11/04 17:37:43
// Date: 2017/11/04 17:37:43
#include <gflags/gflags.h>
#include "butil/build_config.h"
#include "butil/build_config.h"
#include "butil/logging.h"
#include "butil/logging.h"
...
@@ -31,7 +32,7 @@ uint64_t BAIDU_WEAK bthread_usleep(uint64_t microseconds);
...
@@ -31,7 +32,7 @@ uint64_t BAIDU_WEAK bthread_usleep(uint64_t microseconds);
namespace
butil
{
namespace
butil
{
const
int
CHILD_STACK_SIZE
=
64
*
1024
;
const
int
CHILD_STACK_SIZE
=
256
*
1024
;
struct
ChildArgs
{
struct
ChildArgs
{
const
char
*
cmd
;
const
char
*
cmd
;
...
@@ -48,7 +49,7 @@ int launch_child_process(void* args) {
...
@@ -48,7 +49,7 @@ int launch_child_process(void* args) {
_exit
(
1
);
_exit
(
1
);
}
}
int
read_command_output
(
std
::
ostream
&
os
,
const
char
*
cmd
)
{
int
read_command_output
_through_clone
(
std
::
ostream
&
os
,
const
char
*
cmd
)
{
int
pipe_fd
[
2
];
int
pipe_fd
[
2
];
if
(
pipe
(
pipe_fd
)
!=
0
)
{
if
(
pipe
(
pipe_fd
)
!=
0
)
{
PLOG
(
ERROR
)
<<
"Fail to pipe"
;
PLOG
(
ERROR
)
<<
"Fail to pipe"
;
...
@@ -71,7 +72,7 @@ int read_command_output(std::ostream& os, const char* cmd) {
...
@@ -71,7 +72,7 @@ int read_command_output(std::ostream& os, const char* cmd) {
child_stack
=
child_stack_mem
+
CHILD_STACK_SIZE
;
child_stack
=
child_stack_mem
+
CHILD_STACK_SIZE
;
// ^ Assume stack grows downward
// ^ Assume stack grows downward
cpid
=
clone
(
launch_child_process
,
child_stack
,
cpid
=
clone
(
launch_child_process
,
child_stack
,
__WCLONE
|
CLONE_VM
|
SIGCHL
D
,
&
args
);
__WCLONE
|
CLONE_VM
|
SIGCHLD
|
CLONE_UNTRACE
D
,
&
args
);
if
(
cpid
<
0
)
{
if
(
cpid
<
0
)
{
PLOG
(
ERROR
)
<<
"Fail to clone child process"
;
PLOG
(
ERROR
)
<<
"Fail to clone child process"
;
rc
=
-
1
;
rc
=
-
1
;
...
@@ -97,7 +98,7 @@ int read_command_output(std::ostream& os, const char* cmd) {
...
@@ -97,7 +98,7 @@ int read_command_output(std::ostream& os, const char* cmd) {
pipe_fd
[
0
]
=
-
1
;
pipe_fd
[
0
]
=
-
1
;
for
(;;)
{
for
(;;)
{
pid_t
wpid
=
waitpid
(
cpid
,
&
wstatus
,
WNOHANG
);
pid_t
wpid
=
waitpid
(
cpid
,
&
wstatus
,
WNOHANG
|
__WALL
);
if
(
wpid
>
0
)
{
if
(
wpid
>
0
)
{
break
;
break
;
}
}
...
@@ -141,15 +142,15 @@ END:
...
@@ -141,15 +142,15 @@ END:
return
rc
;
return
rc
;
}
}
}
// namespace butil
DEFINE_bool
(
run_command_through_clone
,
false
,
"(Linux specific) Run command with clone syscall to "
"avoid the costly page table duplication"
);
#e
lse
// OS_LINUX
#e
ndif
// OS_LINUX
#include <stdio.h>
#include <stdio.h>
namespace
butil
{
int
read_command_output_through_popen
(
std
::
ostream
&
os
,
const
char
*
cmd
)
{
int
read_command_output
(
std
::
ostream
&
os
,
const
char
*
cmd
)
{
FILE
*
pipe
=
popen
(
cmd
,
"r"
);
FILE
*
pipe
=
popen
(
cmd
,
"r"
);
if
(
pipe
==
NULL
)
{
if
(
pipe
==
NULL
)
{
return
-
1
;
return
-
1
;
...
@@ -170,9 +171,31 @@ int read_command_output(std::ostream& os, const char* cmd) {
...
@@ -170,9 +171,31 @@ int read_command_output(std::ostream& os, const char* cmd) {
// retry;
// retry;
}
}
}
}
return
pclose
(
pipe
);
const
int
wstatus
=
pclose
(
pipe
);
if
(
wstatus
<
0
)
{
return
wstatus
;
}
if
(
WIFEXITED
(
wstatus
))
{
return
WEXITSTATUS
(
wstatus
);
}
if
(
WIFSIGNALED
(
wstatus
))
{
os
<<
"Child process was killed by signal "
<<
WTERMSIG
(
wstatus
);
}
errno
=
ECHILD
;
return
-
1
;
}
}
}
// namespace butil
int
read_command_output
(
std
::
ostream
&
os
,
const
char
*
cmd
)
{
#if !defined(OS_LINUX)
return
read_command_output_through_popen
(
os
,
cmd
);
#else
return
FLAGS_run_command_through_clone
?
read_command_output_through_clone
(
os
,
cmd
)
:
read_command_output_through_popen
(
os
,
cmd
);
#endif
}
#endif // OS_LINUX
}
// namespace butil
test/popen_unittest.cpp
View file @
ffead26e
...
@@ -6,40 +6,121 @@
...
@@ -6,40 +6,121 @@
#include "butil/popen.h"
#include "butil/popen.h"
#include "butil/errno.h"
#include "butil/errno.h"
#include "butil/strings/string_piece.h"
#include "butil/strings/string_piece.h"
#include "butil/build_config.h"
#include <gtest/gtest.h>
#include <gtest/gtest.h>
namespace
butil
{
extern
int
read_command_output_through_clone
(
std
::
ostream
&
,
const
char
*
);
extern
int
read_command_output_through_popen
(
std
::
ostream
&
,
const
char
*
);
}
namespace
{
namespace
{
class
PopenTest
:
public
testing
::
Test
{
class
PopenTest
:
public
testing
::
Test
{
};
};
TEST
(
PopenTest
,
sanity
)
{
TEST
(
PopenTest
,
posix_popen
)
{
std
::
ostringstream
oss
;
int
rc
=
butil
::
read_command_output_through_popen
(
oss
,
"echo
\"
Hello World
\"
"
);
ASSERT_EQ
(
0
,
rc
)
<<
berror
(
errno
);
ASSERT_EQ
(
"Hello World
\n
"
,
oss
.
str
());
oss
.
str
(
""
);
rc
=
butil
::
read_command_output_through_popen
(
oss
,
"exit 1"
);
EXPECT_EQ
(
1
,
rc
)
<<
berror
(
errno
);
ASSERT_TRUE
(
oss
.
str
().
empty
())
<<
oss
;
oss
.
str
(
""
);
rc
=
butil
::
read_command_output_through_popen
(
oss
,
"kill -9 $$"
);
ASSERT_EQ
(
-
1
,
rc
);
ASSERT_EQ
(
errno
,
ECHILD
);
ASSERT_TRUE
(
butil
::
StringPiece
(
oss
.
str
()).
ends_with
(
"was killed by signal 9"
));
oss
.
str
(
""
);
rc
=
butil
::
read_command_output_through_clone
(
oss
,
"kill -15 $$"
);
ASSERT_EQ
(
-
1
,
rc
);
ASSERT_EQ
(
errno
,
ECHILD
);
ASSERT_TRUE
(
butil
::
StringPiece
(
oss
.
str
()).
ends_with
(
"was killed by signal 15"
));
oss
.
str
(
""
);
ASSERT_EQ
(
0
,
butil
::
read_command_output_through_clone
(
oss
,
"for i in `seq 1 100000`; do echo -n '=' ; done"
));
ASSERT_EQ
(
100000u
,
oss
.
str
().
length
());
std
::
string
expected
;
expected
.
resize
(
100000
,
'='
);
ASSERT_EQ
(
expected
,
oss
.
str
());
}
#if defined(OS_LINUX)
TEST
(
PopenTest
,
clone
)
{
std
::
ostringstream
oss
;
std
::
ostringstream
oss
;
int
rc
=
butil
::
read_command_output
(
oss
,
"echo
\"
Hello World
\"
"
);
int
rc
=
butil
::
read_command_output
_through_clone
(
oss
,
"echo
\"
Hello World
\"
"
);
ASSERT_EQ
(
0
,
rc
)
<<
berror
(
errno
);
ASSERT_EQ
(
0
,
rc
)
<<
berror
(
errno
);
ASSERT_EQ
(
"Hello World
\n
"
,
oss
.
str
());
ASSERT_EQ
(
"Hello World
\n
"
,
oss
.
str
());
oss
.
str
(
""
);
oss
.
str
(
""
);
rc
=
butil
::
read_command_output
(
oss
,
"exit 1"
);
rc
=
butil
::
read_command_output
_through_clone
(
oss
,
"exit 1"
);
ASSERT_EQ
(
1
,
rc
)
<<
berror
(
errno
);
ASSERT_EQ
(
1
,
rc
)
<<
berror
(
errno
);
ASSERT_TRUE
(
oss
.
str
().
empty
())
<<
oss
.
str
()
;
ASSERT_TRUE
(
oss
.
str
().
empty
())
<<
oss
;
oss
.
str
(
""
);
oss
.
str
(
""
);
rc
=
butil
::
read_command_output
(
oss
,
"kill -9 $$"
);
rc
=
butil
::
read_command_output
_through_clone
(
oss
,
"kill -9 $$"
);
ASSERT_EQ
(
-
1
,
rc
);
ASSERT_EQ
(
-
1
,
rc
);
ASSERT_EQ
(
errno
,
ECHILD
);
ASSERT_EQ
(
errno
,
ECHILD
);
ASSERT_TRUE
(
butil
::
StringPiece
(
oss
.
str
()).
ends_with
(
"was killed by signal 9"
));
ASSERT_TRUE
(
butil
::
StringPiece
(
oss
.
str
()).
ends_with
(
"was killed by signal 9"
));
oss
.
str
(
""
);
oss
.
str
(
""
);
rc
=
butil
::
read_command_output
(
oss
,
"kill -15 $$"
);
rc
=
butil
::
read_command_output
_through_clone
(
oss
,
"kill -15 $$"
);
ASSERT_EQ
(
-
1
,
rc
);
ASSERT_EQ
(
-
1
,
rc
);
ASSERT_EQ
(
errno
,
ECHILD
);
ASSERT_EQ
(
errno
,
ECHILD
);
ASSERT_TRUE
(
butil
::
StringPiece
(
oss
.
str
()).
ends_with
(
"was killed by signal 15"
));
ASSERT_TRUE
(
butil
::
StringPiece
(
oss
.
str
()).
ends_with
(
"was killed by signal 15"
));
oss
.
str
(
""
);
oss
.
str
(
""
);
ASSERT_EQ
(
0
,
butil
::
read_command_output
(
oss
,
"for i in `seq 1 100000`; do echo -n '=' ; done"
));
ASSERT_EQ
(
0
,
butil
::
read_command_output
_through_clone
(
oss
,
"for i in `seq 1 100000`; do echo -n '=' ; done"
));
ASSERT_EQ
(
100000u
,
oss
.
str
().
length
())
<<
oss
.
str
()
;
ASSERT_EQ
(
100000u
,
oss
.
str
().
length
());
std
::
string
expected
;
std
::
string
expected
;
expected
.
resize
(
100000
,
'='
);
expected
.
resize
(
100000
,
'='
);
ASSERT_EQ
(
expected
,
oss
.
str
());
ASSERT_EQ
(
expected
,
oss
.
str
());
}
}
struct
CounterArg
{
volatile
int64_t
counter
;
volatile
bool
stop
;
};
static
void
*
counter_thread
(
void
*
args
)
{
CounterArg
*
ca
=
(
CounterArg
*
)
args
;
while
(
!
ca
->
stop
)
{
++
ca
->
counter
;
}
return
NULL
;
}
static
int
fork_thread
(
void
*
arg
)
{
usleep
(
100
*
1000
);
_exit
(
0
);
}
const
int
CHILD_STACK_SIZE
=
64
*
1024
;
TEST
(
PopenTest
,
does_vfork_suspend_all_threads
)
{
pthread_t
tid
;
CounterArg
ca
=
{
0
,
false
};
ASSERT_EQ
(
0
,
pthread_create
(
&
tid
,
NULL
,
counter_thread
,
&
ca
));
usleep
(
100
*
1000
);
char
*
child_stack_mem
=
(
char
*
)
malloc
(
CHILD_STACK_SIZE
);
void
*
child_stack
=
child_stack_mem
+
CHILD_STACK_SIZE
;
const
int64_t
counter_before_fork
=
ca
.
counter
;
pid_t
cpid
=
clone
(
fork_thread
,
child_stack
,
CLONE_VFORK
,
NULL
);
const
int64_t
counter_after_fork
=
ca
.
counter
;
usleep
(
100
*
1000
);
const
int64_t
counter_after_sleep
=
ca
.
counter
;
int
ws
;
ca
.
stop
=
true
;
pthread_join
(
tid
,
NULL
);
std
::
cout
<<
"bc="
<<
counter_before_fork
<<
" ac="
<<
counter_after_fork
<<
" as="
<<
counter_after_sleep
<<
std
::
endl
;
ASSERT_EQ
(
cpid
,
waitpid
(
cpid
,
&
ws
,
__WALL
));
}
#endif // OS_LINUX
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment