libc system函数的探究

网友投稿 672 2022-10-04

libc system函数的探究

libc system函数的探究

system导致父进程等待

在mac上的在线帮助有对system的如下说明:

The system() function hands the argument command to the command interpreter sh(1). The calling process waits for the shell to finish executing the com- mand, ignoring SIGINT and SIGQUIT, and blocking SIGCHLD.

system的工作大致是这样的: 父进程fork子进程 父进程等待子进程 在子进程中执行字符串所表述的命令 返回执行结果。

源码:

int system(const char * cmdstring){ pid_t pid; int status; if( cmdstring == NULL ) { return 1; } if( (pid = fork()) < 0 ) { status = -1; } else if( pid == 0 ) { // execl create new process to replace old process execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); // if above statement execute successfully, the following function would not work. _exit(127); } else { while( waitpid(pid, &status, 0) < 0 ) { if( errno != EINTR ) { status = -1; break; } } } return

在执行命令期间,他会忽略一些信号:SIGINT,SIGQUIT,并且阻塞SIGCHLD 我很好奇, 说明中的wait是不是挂起之意(进程挂起:进程被移除内存之外,暂时保存在外存)。于是实验了一番。 test.c

#include #include #include #include #include #include void* run( void *arg ){ while(1) { printf("test main is running.\n"); }}int main(int argc, char *argv[]) { int ret; pthread_t tid; ret = pthread_create( &tid, NULL, run, NULL ); if( ret != 0 ) { perror("pthread_create: "); return 1; } system( "./run.sh" ); pthread_join( tid, NULL ); return 0;}

run.sh

#! /bin/bashwhile true; do echo "shell script is running"done

标准输出的结果是这样的:

test main is running.test main is running.test main is running.shell script is runningtest main is running.test main is running.test main is running.shell script is runningtest main is running.test main is running.test main is running....

这样看来,父进程仍然正常工作。 但如果父进程所有的工作任务全部放在一个线程中,那么就有可能出现使用system后进程挂起的假象。 比如这样:

int main(int argc, char *argv[]) { int ret; scanf("%d", &ret); system( "./run.sh > ~/code/txt" ); write( STDOUT_FILENO, "finish\n", 7 ); return 0;}

这样的话,除非主动kill进程,否则finish不会输出。 那我们将system的任务放到一个独立的线程中,这样就可以使得两边同时工作。 比如这样:

void* run( void *arg ){ system( "./run.sh > ~/code/txt" );}int main(int argc, char *argv[]) { int ret; pthread_t tid; ret = pthread_create( &tid, NULL, run, NULL ); if( ret != 0 ) { perror("pthread_create: "); return 1; } scanf("%d", &ret); write( STDOUT_FILENO, "finish\n", 7 ); pthread_join( tid, NULL ); return 0;}

当system子进程变成孤儿进程

在mac上,一旦父进程退出,子进程变成孤儿进程,随即被​​/sbin/launchd​​收养。

实验代码: ​​​➜ code cat run.sh​​

#! /bin/bashwhile true; do echo "shell script is running" done

​​➜ code cat test.c​​

#include #include #include int main(int argc, char *argv[]) { system( "./run.sh" ); return 0;}

➜ MacOS git:(master) ✗ pstree -p 8445-+= 00001 root /sbin/launchd \-+= 02083 weiyang /Applications/iTerm.app/Contents/MacOS/iTerm2 \-+= 08323 weiyang /Applications/iTerm.app/Contents/MacOS/iTerm2 --server login -fp wei \-+= 08324 root login -fp weiyang \-+= 08325 weiyang -zsh \-+= 08442 weiyang ./a.out \--- 08445 weiyang /bin/bash ./run.sh➜ MacOS git:(master) ✗ kill 8442➜ MacOS git:(master) ✗ pstree -p 8445-+= 00001 root /sbin/launchd \--- 08445 weiyang /bin/bash ./run.sh

使得父进程退出后,system子进程也结束

通过重写system函数,我们可以得到子进程的进程号。在父进程退出的时候,也令子进程退出。

#include #include #include #include #include #include #include #include int system2( const char * cmdstring, int * _pid ){ pid_t pid; *_pid = 0; int status; if( cmdstring == NULL ) { return 1; } if( ( pid = fork() ) < 0 ) { status = -1; } else if( pid == 0 ) { // execl create new process to replace old process execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); // if above statement execute successfully, the following function would not work. _exit(127); } else { *_pid = pid; // For waitpid return value, -1 means error, 0 means no exited child. // Positive interger means child PID. while( waitpid(pid, &status, 0) < 0 ) { // EINTR means interrupt signal, operate failed. Please try again. if( errno != EINTR ) { status = -1; break; } } } *_pid = 0; return status;}int pid;void sigCapture( int sig ){ printf( "sig is %d, child pid is %d\n", sig, pid ); if( pid > 0 && -1 == kill( pid, SIGKILL ) ) { perror( "kill child process: " ); }}int main( int argc, char *argv[] ) { int ret; signal( SIGTERM, sigCapture ); ret = system2( "./run.sh", &pid ); // Deal with return value. if (-1 == ret) { printf("system error!"); } else { printf("ret is not -1, exit ret value = 0x%x\n", ret); //0x7f00 // call shell script and finish successfully. if (WIFEXITED(ret)) // WIFEXITED is a macro { if (0 == WEXITSTATUS(ret)) // return value of shell script run. { printf("run shell script successfully."); } // 0x7f = 127 else { printf("run shell script fail, script exit code: %d, reason: %s\n", WEXITSTATUS(ret), strerror(errno)); } } else { printf("exit ret = %d\n", WEXITSTATUS(ret)); } } return 0;}

command:

➜ code ps aux |grep run.shweiyang 13681 93.0 0.0 4279596 1232 s003 S+ 9:46AM 0:01.86 /bin/bash ./run.shweiyang 13684 0.0 0.0 4268776 668 s002 R+ 9:46AM 0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn run.sh➜ code ps aux |grep a.outweiyang 13690 0.0 0.0 4267752 748 s002 R+ 9:46AM 0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn a.outweiyang 13680 0.0 0.0 4268752 812 s003 S+ 9:46AM 0:00.01 ./a.out➜ code kill 13680➜ code ps aux |grep run.shweiyang 13704 0.0 0.0 4267752 884 s002 S+ 9:46AM 0:00.01 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn run.sh

result:

shell script is runningshell script is runningshell script is runningshell script is runningsig is 15, child pid is 13681shell script is runningshell script is runningret is not -1, exit ret value = 0x9exit ret = 0

注: 使用kill发送信号,格式为 ​​ps -signal_number pid​​​,如果不指定信号编码,默认的信号是15 SIGTERM。各类信号编码可以使用​​kill -l​​查看。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【github myLocker】线程切换调试,读写指针修改文件,socket 阻塞设置
下一篇:小程序授权登陆的解决方法(附代码)(请先授权小程序,登录后才能操作)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~