SylixOS 中 CTRL + C 的大致处理流程

SylixOS 中 CTRL + C 的大致处理流程

Q:SylixOS 中 CTRL + C 的大致处理流程
(1)当键盘按下 CTRL+C 时,主机就向目标板发送一个控制字符,其 ASSIC 码为 0x03,在 SylixOS 下常用的控制字符如下,此定义是在 tyLib.c 文件中。
  1. /*********************************************************************************************************
  2.   全局变量(控制字 __LINUX_BACKSPACE_CHAR 直接按 backspace 处理)
  3. *********************************************************************************************************/
  4. #define __LINUX_BACKSPACE_CHAR      127                           /*  linux 下的退格 control-?    */
  5. #define __TTY_BACKSPACE(ptyDev, ch) ((ch) == __LINUX_BACKSPACE_CHAR || (ch) == __TTY_CC(ptyDev, VERASE))
  6. static CHAR             _G_cTyBackspaceChar  = 0x08;                /*  默认值     control-H        */
  7. static CHAR             _G_cTyDeleteLineChar = 0x15;                  /*  默认值     control-U        */
  8. static CHAR             _G_cTyEofChar           = 0x04;                    /*  默认值     control-D        */
  9. static CHAR             _G_cTyAbortChar        = 0x03;                   /*  默认值     control-C        */
  10. static CHAR             _G_cTyMonTrapChar   = 0x18;                    /*  默认值     control-X        */

(2)开发板收到数据时,就转入 uart 中断处理函数中执行,中断处理函数如下:
  1. /*********************************************************************************************************
  2. ** 函数名称: imx6SioIsr
  3. ** 功能描述: SIO 通道中断处理函数
  4. ** 输 入  : psiochanChan                 SIO 通道
  5. ** 输 出  : NONE
  6. ** 全局变量:
  7. ** 调用模块:
  8. *********************************************************************************************************/
  9. static irqreturn_t  imx6SioIsr (SIO_CHAN  *psiochanChan, ULONG  ulVector)
  10. {
  11.     __PSIO_CHANNEL          psiochanUart = (__PSIO_CHANNEL)psiochanChan;
  12.     CHAR                    cChar;
  13.     if (imx6UartIsTxInt(psiochanUart->iChannelNum)) {                         /*  发送中断                    */
  14.         while (!imx6UartTxFifoFull(psiochanUart->iChannelNum)) {
  15.             if (psiochanUart->pcbGetTxChar(psiochanUart->pvGetTxArg, &cChar) != ERROR_NONE) {
  16.                 imx6UartTxIntDisable(psiochanUart->iChannelNum);          /*  关闭发送中断                */
  17.                 break;
  18.             } else {
  19.                 imx6UartTxFifoPut(psiochanUart->iChannelNum, cChar);    /*  发送数据                    */
  20.             }
  21.         }
  22.     }
  23.     while (!imx6UartRxFifoEmpty(psiochanUart->iChannelNum)) {        /*  需要接收数据                */
  24.         if (imx6UartRxFifoGet(psiochanUart->iChannelNum, &cChar)     /*  接收数据                    */
  25.             == ERROR_NONE) {
  26.             psiochanUart->pcbPutRcvChar(psiochanUart->pvPutRcvArg, cChar);
  27.         } else {
  28.             break;
  29.         }
  30.     }
  31.     imx6UartIntClear(psiochanUart->iChannelNum);                             /*  清除中断                    */
  32.     return  (LW_IRQ_HANDLED);
  33. }
      
由代码可知,在 uart 接受完数据后,执行了 psiochanUart->pcbPutRcvChar(psiochanUart->pvPutRcvArg, cChar) 这个函数,这个函数是注册 SIO 设备时所注册好的回调函数,其函数原型是 _TyIRd,如下所示:
  1. /*********************************************************************************************************
  2. ** 函数名称: _TyIRx
  3. ** 功能描述: 向终端的接收缓冲区中写入一个从硬件接收到的数据, FIFO
  4. ** 输 入  :
  5. **           ptyDev,            TY 设备
  6. **           cInChar,           接收到的数据
  7. ** 输 出  : ERROR_NONE or PX_ERROR
  8. ** 全局变量:
  9. ** 调用模块:
  10. *********************************************************************************************************/
  11. INT  _TyIRd (TY_DEV_ID  ptyDev, CHAR   cInchar)   
这个函数的主要功能就是将 uart 接收到的数据上送到系统的输入缓冲区,然后进行一些处理。

 
(3)在 _TyIRd 中首先就对接受到的数据是否是 CTRL+C 字符做了一个判断,如下:
  1. if ((cInchar == __TTY_CC(ptyDev, VINTR)) &&
  2.     (iOpt & OPT_ABORT) &&
  3.     ((_G_pfuncTyAbortFunc != LW_NULL) ||
  4.     (ptyDev->TYDEV_pfuncCtrlC != LW_NULL))) {                                                  /*  是否需要进行 ABORT 处理     */        
  5.         LW_SPIN_UNLOCK_QUICK(&ptyDev->TYDEV_slLock, iregInterLevel);    /*  解锁 spinlock 打开中断      */
  6.     if (ptyDev->TYDEV_pfuncCtrlC) {
  7.         ptyDev->TYDEV_pfuncCtrlC(ptyDev->TYDEV_pvArgCtrlC);
  8.     }
  9.     if (_G_pfuncTyAbortFunc) {
  10.         _G_pfuncTyAbortFunc();
  11.     }
  12. }

  如果是 CTRL+C 字符就执行 ptyDev->TYDEV_pfuncCtrlC(ptyDev->TYDEV_pvArgCtrlC),这个也是事先注册好的函数,其原型是 __tshellRestart,如下所示:
  1. /*********************************************************************************************************
  2. ** 函数名称: __tshellRestart
  3. ** 功能描述: ttiny shell 线程重启 (control-C)
  4. ** 输 入  : ulThread   线程句柄
  5. ** 输 出  : NONE
  6. ** 全局变量:
  7. ** 调用模块:
  8. *********************************************************************************************************/
  9. static VOID  __tshellRestart (LW_OBJECT_HANDLE  ulThread)

  (4)__tshellRestart 函数调用了 __tshellRestartEx 函数,__tshellRestartEx 函数将自己交给了系统的工作队列处理线程来处理,相当于将具体的 restart 操作放到了中断下半部来处理,如下所示:
  1.     if (LW_CPU_GET_CUR_NESTING()) {
  2.         return  (_excJobAdd((VOIDFUNCPTR)__tshellRestartEx,
  3.                                      (PVOID)ulThread, (PVOID)bNeedAuthen, 0, 0, 0, 0));
  4.     }
          
 接着会判断本线程是否存在子线程,如果存在则杀死子线程,如果不存在,则重启当前线程,如下所示:
  1.     if (ulJoin) {
  2.     #if LW_CFG_SIGNAL_EN > 0
  3.         kill(ulJoin, SIGKILL);                                          /*  杀死等待的线程/进程         */
  4.     #else
  5.         API_ThreadDelete(&ulJoin, LW_NULL);
  6.     #endif                                                                  /*  LW_CFG_SIGNAL_EN > 0        */
  7.         iMsg = API_IoTaskStdGet(ulThread, STD_OUT);
  8.         if (iMsg >= 0) {
  9.             fdprintf(iMsg, "[sh]Warning: Program is killed (SIGKILL) by shell.\n"
  10.                                 "    Restart SylixOS is recommended!\n");
  11.         }
  12.     } else {                                                               /*  重启线程                    */
  13.         API_ThreadRestart(ulThread, (PVOID)__TTINY_SHELL_GET_STDFILE(ptcbShell));
  14.     }
API_ThreadRestart 就是重启线程函数了,这里就不具体分析了。


    • Related Articles

    • 如何禁止Ctrl+C执行?

      Q:如何禁止Ctrl+C执行? 应用层如何控制S ylixOS 禁止 Ctrl+C 快捷键杀掉应用,参考代码如下: #include <sys/stat.h> #include <termios.h> #include <fcntl.h> static INT iOptionNoAbort, iOption; static void do_cancel_ctrlc (void) { ioctl(STD_IN, FIOGETOPTIONS, &iOption); iOptionNoAbort = ...
    • SHELL 中 CTRL 控制命令

      SylixOS 的 shell 有几个 CTRL 命令比较特殊: CTRL + S :表示 SHELL 终端的停止操作,输入后, SHELL 不能再响应之后的输入。 CTRL + Q :表示 SHELL 终端的运行操作,输入后,可以将 SHELL 从 CTRL + S 之后返回到正常情况。 CTRL + D :表示 SHELL 终端的退出,输入后,SHELL 不能再响应输入,只能通过重启解决。
    • 应用线程或者进程如何保证不能被Ctrl+C杀掉?

      Q:应用线程或者进程如何保证不能被 Ctrl+C 杀掉? 使用 pthread_safe_np 和 pthread_unsafe_np 可以保证线程进入安全模式,避免被Ctrl+C杀掉。 更多扩展知识: 参考文章:SylixOS 中 CTRL + C 的大致处理流程 参考文章:SHELL 中 CTRL 控制命令 参考文章:如何禁止Contrl+X执行?
    • 添加标准 C 库头文件会与 SylixOS 内部数据结构冲突

      Q: 为什么加入一些标准 C 库头文件会与 SylixOS 内部数据结构冲突? SylixOS 为了提高兼容性与稳定性,SylixOS 提供了一套最适合自身多线程操作系统特点的标准 C 库(暂不包含数学库). 这套 C 库相关代码是从其他开源项目中演变而来。当然为了配合 SylixOS 系统,很多地方做出了修改。 这些库中相关的定义会随着 #include <SylixOS.h> 一同引入用户程序,当用户引用其他辅助 C 库时, 可能产生一些重复定义问题。 这里推荐使用 SylixOS 提供的 ...
    • SylixOS下的GIC中断实现(基于T3)

      GIC常用寄存器介绍 GICD_CTLR GICv2控制器将中断分为两组。配置对应寄存器可以控制这两组中断的使能与禁能。 GICD_ISENABLERn 中断向量使能寄存器,写入1使能对应的中断向量号,写0没有影响。读取数据表示对应中断向量号的使能状态。每32个中断向量使用一个寄存器位,后续中断向量放在接下来的寄存器地址上。 GICD_ICENABLERn ...