注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

linux下bash的job管理  

2013-08-18 23:00:55|  分类: bash分析 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、job管理
这个就是所谓的一个作业概念,通俗的说,就是一个管道进程组以及比这个单位更小的一些进程组。这个说的比较抽象,但是更具体的我也不是很清楚,所以只能从一些例子来简单说明一下。
对于前台和后台进程来说,它们的一个重要区别就是对于当前终端的读入权限,只有前台作业具有读取当前终端输入的权利,其他的进程都没有,这一点由操作系统保证,每个tty驱动中只保留一个当前前端进程组的进程组ID。如果有不在该进程组的进程来读取数据,此时该进程会受到一个TTIN错误,导致进程被挂起。
而所谓的bg和fg来说,它们的重要区别就在于是否拥有终端的读取权。
二、将前台进程挂起
如果前台进程正在运行,可以通过Ctrl+Z来暂时挂起这个进程。这个按键组合默认同样是操作系统驱动支持和识别的一个信号,它的级别和我们最为熟悉的ctrl+C一样,只是后者使用的人比较多,前者用的比较少而已。看一下一个终端的默认设置
[root@Harry gawk-4.1.0]# stty -a
speed 38400 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?;
swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke
三、内核的相关配置及处理
1、按键定义
标准内核ttyio配置linux-2.6.21\drivers\char\tty_io.c
struct ktermios tty_std_termios = {    /* for the benefit of tty drivers  */
    .c_iflag = ICRNL | IXON,
    .c_oflag = OPOST | ONLCR,
    .c_cflag = B38400 | CS8 | CREAD | HUPCL,
    .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
           ECHOCTL | ECHOKE | IEXTEN,
    .c_cc = INIT_C_CC,
    .c_ispeed = 38400,
    .c_ospeed = 38400
};
linux-2.6.21\include\asm-i386、termios.h
/*    intr=^C        quit=^\        erase=del    kill=^U
    eof=^D        vtime=\0    vmin=\1        sxtc=\0
    start=^Q    stop=^S        susp=^Z        eol=\0
    reprint=^R    discard=^U    werase=^W    lnext=^V
    eol2=\0
*/
#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
所以,这个按键组合也是通用的、默认的组合,这个组合也是我们windows下常用的“撤销”操作的默认按键。
2、按键处理
static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
n_tty.c
        signal = SIGTSTP;
        if (c == SUSP_CHAR(tty)) {
send_signal:
            isig(signal, tty, 0);
            return;
        }
当有这个按键组合的时候,内核向终端的前端进程发送SIGTSTP命令,这个命令和调试器使用的SITSTP不同,内核的注释是这么说明的
#define SIGSTOP        23    /* Stop, unblockable (POSIX).  */
#define SIGTSTP        24    /* Keyboard stop (POSIX).  */
对于这个信号,系统会将接受该信号的进程设置为STP状态,并且买一送一,还会通知父进程子进程的状态变化,不过父进程接受到的是SIGCHILD信号,在附带信息中会提示说明受到的信号是SIGTSTP。这个也是bash能够感受到自己管理的job有停止的底层基础。
三、bash对于该信号的处理
1、信号的接受
当bash收到SIGCHLD信号之后,调用wait类接口提取子进程最新状态,
wait_for --->>waitchld---->>>set_job_status_and_cleanup
  do
    {
      job_state |= PRUNNING (child);
#if 0
      if (PEXITED (child) && (WIFSTOPPED (child->status)))
#else
      /* Only checking for WIFSTOPPED now, not for PS_DONE */
      if (PSTOPPED (child))
#endif
    {
      any_stopped = 1;
      any_tstped |= interactive && job_control &&
                (WSTOPSIG (child->status) == SIGTSTP);
    }
      child = child->next;
    }
  while (child != jobs[job]->pipe);
在waitchld函数的最后,还会打印出状态变化的子进程的状态信息
  /* We have successfully recorded the useful information about this process
     that has just changed state.  If we notify asynchronously, and the job
     that this process belongs to is no longer running, then notify the user
     of that fact now. */
  if (asynchronous_notification && interactive)
    notify_of_job_status ();
2、状态的打印
notify_of_job_status--->pretty_print_job--->>print_pipeline--->>printable_job_status

static char *
printable_job_status (j, p, format)
     int j;
     PROCESS *p;
     int format;
{
  static char *temp;
  int es;

  temp = _("Done");

  if (STOPPED (j) && format == 0)
    {
      if (posixly_correct == 0 || p == 0 || (WIFSTOPPED (p->status) == 0))
    temp = _("Stopped");
      else
    {
      temp = retcode_name_buffer;
      sprintf (temp, _("Stopped(%s)"), signal_name (WSTOPSIG (p->status)));
    }
    }
  else if (RUNNING (j))
    temp = _("Running");
  else
    {
      if (WIFSTOPPED (p->status))
    temp = j_strsignal (WSTOPSIG (p->status));
      else if (WIFSIGNALED (p->status))
    temp = j_strsignal (WTERMSIG (p->status));
      else if (WIFEXITED (p->status))
    {
      temp = retcode_name_buffer;
      es = WEXITSTATUS (p->status);
      if (es == 0)
        strcpy (temp, _("Done"));
      else if (posixly_correct)
        sprintf (temp, _("Done(%d)"), es);
      else
        sprintf (temp, _("Exit %d"), es);
    }
      else
    temp = _("Unknown status");
    }

  return temp;
}
这里其实包含了我们常见的大部分状态,包括coredump、stopped,exit等,并且要注意的是,它通常是打印到标准错误的。这一点对于通过telnet或者ssh创建的终端中派生的进程尤为重要。当终端由于网络或者超时断开之后,此时shell的标准错误会处于关闭状态,如果一个子shell感受到自己的一个后台子进程退出,则它会向自己的标准错误中打印后台进程退出命令,此时由于telent已经断开,所以标准错误,也就是伪终端已经不存在,此时打印失败,当打印失败之后,此时shell直接退出,大家一起玩完。这个问题其实还是比较严重的,特别是对于一些需要长时间运行的后台程序。
四、前后台进程的转换
1、演示一下用法
[root@Harry gawk-4.1.0]# sleep 1111 &
[1] 9055
[root@Harry gawk-4.1.0]# jobs
[1]+  Running                 sleep 1111 &
[root@Harry gawk-4.1.0]# sleep 2222
^Z
[2]+  Stopped                 sleep 2222
[root@Harry gawk-4.1.0]# jobs
[1]-  Running                 sleep 1111 &
[2]+  Stopped                 sleep 2222
[root@Harry gawk-4.1.0]# bg %2
[2]+ sleep 2222 &
[root@Harry gawk-4.1.0]# jobs
[1]-  Running                 sleep 1111 &
[2]+  Running                 sleep 2222 &
[root@Harry gawk-4.1.0]# strace fg %1
strace: fg: command not found
[root@Harry gawk-4.1.0]#  fg %1
sleep 1111
2、under the hood
strace执行bg的时候,执行的系统调用大致是
ioctl(255, TIOCSPGRP, [9133])           = 0
执行fg执行的系统调用
ioctl(255, TIOCSPGRP, [9155])           = 0
[root@Harry ~]# ps aux | grep -we 9133 -e 9155
tsecer    9133  0.0  0.1   5120  1712 pts/3    S    22:56   0:00 bash
tsecer    9155  0.0  0.0   3940   508 pts/3    S+   22:56   0:00 sleep 6666
可见所谓的bg和fg只是修改了tty中前端进程组的ID而已。
  评论这张
 
阅读(938)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017