精华内容
下载资源
问答
  • linux System V IPC总结

    千次阅读 2014-02-09 22:45:54
    原文1:http://www.ibm.com/developerworks/cn/linux/l-ipc/ ... 深刻理解Linux进程间通信(IPC) ...一个大型的应用系统,往往需要众多进程协作,进程(Linux进程概念见附1)间通信的重要性显而易见。 本系列文章


    原文1:http://www.ibm.com/developerworks/cn/linux/l-ipc/



    深刻理解Linux进程间通信(IPC)


    一个大型的应用系统,往往需要众多进程协作,进程(Linux进程概念见附1)间通信的重要性显而易见。
    本系列文章阐述了Linux环境下的几种主要进程间通信手段,并针对每个通信手段关键技术环节给出详细实例。
    为达到阐明问题的目的,本文还对某些通信手段的内部实现机制进行了分析。

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    1、Linux IPC,System IPC , Unix IPC

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

            linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的。而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间通信方面的侧重点有所不同。前者对Unix早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,通信进程局限在单个计算机内;后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。Linux则把两者继承了下来,如图示:



               其中,最初Unix IPC包括:管道、FIFO、信号;System V IPC包括:System V消息队列、System V信号灯、System V共享内存区;Posix IPC包括: Posix消息队列、Posix信号灯、Posix共享内存区。有两点需要简单说明一下:1)由于Unix版本的多样性,电子电气工程协会(IEEE)开发了一个独立的Unix标准,这个新的ANSI Unix标准被称为计算机环境的可移植性操作系统界面(PSOIX)。现有大部分Unix和流行版本都是遵循POSIX标准的,而Linux从一开始就遵循POSIX标准;2)BSD并不是没有涉足单机内的进程间通信(socket本身就可以用于单机内的进程间通信)。事实上,很多Unix版本的单机IPC留有BSD的痕迹,如4.4BSD支持的匿名内存映射、4.3+BSD对可靠信号语义的实现等等。

            图一给出了linux 所支持的各种IPC手段,在本文接下来的讨论中,为了避免概念上的混淆,在尽可能少提及Unix的各个版本的情况下,所有问题的讨论最终都会归结到Linux环境下的进程间通信上来。并且,对于Linux所支持通信手段的不同实现版本(如对于共享内存来说,有Posix共享内存区以及System V共享内存区两个实现版本),将主要介绍Posix API。

    System V,BSD,POSIX

           System V是Unix操作系统最早的商业发行版之一。它最初由AT&T(American Telephone & Telegraph)开发,最早在1983年发布。System V主要发行了4个版本,其中SVR4(System V Release 4)是最成功的版本。BSD(Berkeley Software Distribution,有时也被称为Berkeley Unix)是加州大学于1977至1995年间开发的。在19世纪八十年代至九十年代之间,System V和BSD代表了Unix的两种主要的操作风格。它们的主要区别如下:

        系统                          System V           BSD
        root脚本位置            /etc/init.d/           /etc/rc.d/
        默认shell                  Bshell                Cshell
        文件系统数据           /etc/mnttab        /etc/mtab
        内核位置                  /UNIX                 /vmUnix
        打印机设备                lp                     rlp
        字符串函数                memcopy        bcopy
        终端初始化设置文件    /etc/initab       /etc/ttys
        终端控制                  termio               termios

        Linux系统的操作风格往往介于这两种风格之间。

        POSIX(Portable Operating System Interface [for Unix])是由IEEE(Institute of Electrical and Electronics Engineers,电子电气工程协会)开发的。现有的大部分Unix都遵循POSIX标准,而Linux从一开始就遵循POSIX标准。

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    2、最初的Unix IPC

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    1、信号

          信号是Unix/Linux系统在一定条件下生成的事件。信号是一种异步通信机制,进程不需要执行任何操作来等待信号的到达。信号异步通知接收信号的进程发生了某个事件,然后操作系统将会中断接收到信号的进程的执行,转而去执行相应的信号处理程序。

        (1)注册信号处理函数

            #include <signal.h>
            /*typedef void (*sighandler_t)(int);  sighandler_t signal(int signum,sighandler_t handler);*/
            * void (*signal(int signum, void (*handler)(int)))(int);  //SIG_IGN && SIG_DFL
            * int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

        (2)发送信号

            #include <signal.h>
            * int kill(pid_t pid,int sig); //#include <sys/types.h> 
            * int raise(int sig);            //kill(getpid(),sig);
            * unsigned int alarm(unsigned int seconds); //(#include <unistd.h>) seconds秒后,向进程本身发送SIGALRM信号。
        (3)信号集

            信号集被定义为:

               typedef struct {unsigned long sig[_NSIG_WORDS];} sigset_t;
            * int sigaddset(sigset_t *set,int sig);
            * int sigemptyset(sigset_t *set);


    2、管道(Pipe)

        管道用来连接不同进程之间的数据流。


        (1)在两个程序之间传递数据的最简单的方法是使用popen()和pclose()函数:

            #include <stdio.h>
            FILE *popen(const char *command, const char *open_mode);
            int pclose(FILE *stream);
        popen()函数首先调用一个shell,然后把 command 作为参数传递给shell。这样每次调用popen()函数都需要启动两个进程;但是由于在Linux中,所有的参数扩展(parameter expansion)都是由shell执行的,这样 command 中包含的所有参数扩展都可以在 command 程序启动之前完成。


        (2)pipe()函数:

            #include <unistd.h>
            int pipe(int pipefd[2]);
        popen()函数只能返回一个管道描述符,并且返回的是文件流(file stream),可以使用函数fread()和fwrite()来访问。pipe()函数可以返回两个管道描述符: pipefd[0] pipefd[1] ,任何写入 pipefd[1] 的数据都可以从 pipefd[0] 读回;pipe()函数返回的是文件描述符(file descriptor),因此只能使用底层的read()和write()系统调用来访问。pipe()函数通常用来实现父子进程之间的通信。


        (3)命名管道:FIFO    

       #include <sys/types.h>
            #include <sys/stat.h>
            int mkfifo(const char *fifo_name, mode_t mode);
        前面两种管道只能用在相关的程序之间,使用命名管道可以解决这个问题。在使用open()打开FIFO时,mode中不能包含O_RDWR。mode最常用的是O_RDONLY,O_WRONLY与O_NONBLOCK的组合。O_NONBLOCK影响了read()和write()在FIFO上的执行方式。

        PS:要想查看库函数用法,最可靠的资料来自Linux manual page:

        $sudo apt-get install manpages-dev

        $man 3 function name


    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    3、System V IPC

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

         System V IPC指的是AT&T在System V.2发行版中引入的三种进程间通信工具:

         (1)信号量,用来管理对共享资源的访问

         (2)共享内存,用来高效地实现进程间的数据共享

         (3)消息队列,用来实现进程间数据的传递。

         我们把这三种工具统称为System V IPC的对象,每个对象都具有一个唯一的IPC标识符(identifier)。要保证不同的进程能够获取同一个IPC对象,

         必须提供一个IPC关键字(IPC key),内核负责把IPC关键字转换成IPC标识符。   


        3.1 System V IPC具有相似的语法:


        (1) 选择IPC关键字,可以使用如下三种方式:

                a)IPC_PRIVATE。由内核负责选择一个关键字然后生成一个IPC对象并把IPC标识符直接传递给另一个进程。

                b)直接选择一个关键字。

                c)使用ftok()函数生成一个关键字。

        (2) 使用semget()/shmget()/msgget()函数根据IPC关键字key和一个标志flag创建或访问IPC对象。如果key是IPC_PRIVATE;

              或者key尚未与已经存在的IPC对象相关联且flag中包含IPC_CREAT标志,那么就会创建一个全新的IPC对象。

        (3) 使用semctl()/shmctl()/msgctl()函数修改IPC对象的属性。

        (4) 使用semctl()/shmctl()/msgctl()函数和IPC_RMID标志销毁IPC实例。

        System V IPC为每个IPC对象设置了一个ipc_perm结构体并在创建IPC对象的时候进行初始化。这个结构体中定义了IPC对象的访问权限和所有者:


         struct ipc_perm{
           uid_t uid;   //所有者的用户id
           gid_t gid;   //所有者的组id
           uid_t cuid;  //创建者的用户id
           gid_t cgid;  //创建者的组id
           mode_t mode; //访问模式
           …
        };

        shell中管理IPC对象的命令是ipcs、ipcmk和ipcrm。


    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

        3.1  System V IPC 具体通信机制

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    1、信号量(Semaphores)

        System V的信号量集表示的是一个或多个信号量的集合。内核为每个信号量集维护一个semid_ds数据结构,而信号量集中的每个信号量使用一个无名结构体表示,这个结构体至少包含以下成员:


         struct{
             unsigned  short semval; //信号量值,总是>=0
            pid_t sempid;   //上一次操作的pid
           …
        };
        # include  <sys /types.h >
        # include  <sys /ipc.h >
        # include  <sys /sem.h >


        (1)创建或访问信号量
            * int semget(key_t key,int nsems,int flag); 
        nsems指定信号量集中信号量的个数,如果只是获取信号量集的标识符(而非新建),那么nsems可以为0。flag的低9位作为信号量的访问权限位,类似于文件的访问权限;如果flag中同时指定了IPC_CREAT和IPC_EXCL,那么如果key已与现存IPC对象想关联的话,函数将会返回EEXIST错误。例如,flag可以为IPC_CREAT|0666。

        (2)控制信号量集
            * int semctl(int semid,int semnum,int cmd,union semun arg);
        对semid信号量集合执行cmd操作;cmd常用的两个值是:SETVAL初始化第semnum个信号量的值为arg.val;IPC_RMID删除信号量。

        (3)对一个或多个信号量进行操作

            * int semop(int semid,struct sembuf *sops,unsigned nsops);
            * struct sembuf{
                  unsigned short sem_num;  //信号量索引
                  short   sem_op;     //对信号量进行的操作,常用的两个值为-1和+1,分别代表P、V操作
                  short   sem_flag;   //比较重要的值是SEM_UNDO:当进程结束时,相应的操作将被取消;同时,如果进程结束时没有释放资源的话,系统会自动释放
               };


    2、共享内存

        共享内存允许两个或多个进程共享一定的存储区,因为不需要拷贝数据,所以这是最快的一种IPC。

        #include <sys/ipc.h>
        
    #include <sys/shm.h>
        (1)创建或访问共享内存
            * int shmget(key_t key,size_t size,int shmflg);

        (2)附加共享内存到进程的地址空间
            * void *shmat(int shmid,const void *shmaddr,int shmflg);//shmaddr通常为NULL,由系统选择共享内存附加的地址;shmflg可以为SHM_RDONLY

        (3)从进程的地址空间分离共享内存
            * int shmdt(const void *shmaddr); //shmaddr是shmat()函数的返回值

        (4)控制共享内存
            * int shmctl(int shmid,int cmd,struct shmid_ds *buf);
            * struct shmid_ds{
                  struct ipc_perm shm_perm;
                  …
              
    }; 
        cmd的常用取值有:(a)IPC_STAT获取当前共享内存的shmid_ds结构并保存在buf中(2)IPC_SET使用buf中的值设置当前共享内存的shmid_ds结构(3)IPC_RMID删除当前共享内存


    3、消息队列

        消息队列保存在内核中,是一个由消息组成的链表。

        #include <sys/types.h>
        #include <sys/ipc.h>
        #include <sys/msg.h>
        (1)创建或访问消息队列
        * int msgget(key_t key,int msgflg);

        (2)操作消息队列
            * int msgsnd(int msqid,const void *msg,size_t nbytes,int msgflg);
        msg指向的结构体必须以一个long int成员开头,作为msgrcv()的消息类型,必须大于0。nbytes指的是msg指向结构体的大小,但不包括long int部分的大小
            * ssize_t msgrcv(int msqid,void *msg,size_t nbytes,long msgtype,int msgflg);
        如果msgtype是0,就返回消息队列中的第一个消息;如果是正整数,就返回队列中的第一个该类型的消息;如果是负数,就返回队列中具有最小值的第一个消息,并且该最小值要小于等于msgtype的绝对值。

        (3)控制消息队列

            * int msgctl(int msqid,int cmd,struct msqid_ds *buf);
            * struct msqid_ds{
                  struct ipc_perm msg_perm;
                  …
               };

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    4、Socket套接字

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
      套接字(Socket)是由Berkeley在BSD系统中引入的一种基于连接的IPC,是对网络接口(硬件)和网络协议(软件)的抽象。它既解决了无名管道只能在相关进程间单向通信的问题,又解决了网络上不同主机之间无法通信的问题。

      套接字有三个属性:域(domain)、类型(type)和协议(protocol),对应于不同的域,套接字还有一个地址(address)来作为它的名字。

      域(domain)指定了套接字通信所用到的协议族,最常用的域是AF_INET,代表网络套接字,底层协议是IP协议。对于网络套接字,由于服务器端有可能会提供多种服务,客户端需要使用IP端口号来指定特定的服务。AF_UNIX代表本地套接字,使用Unix/Linux文件系统实现。

      IP协议提供了两种通信手段:流(streams)和数据报(datagrams),对应的套接字类型(type)分别为流式套接字和数据报套接字。流式套接字(SOCK_STREAM)用于提供面向连接、可靠的数据传输服务。该服务保证数据能够实现无差错、无重复发送,并按顺序接收。流式套接字使用TCP协议。数据报套接字(SOCK_DGRAM)提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP协议。

      一种类型的套接字可能可以使用多于一种的协议来实现,套接字的协议(protocol)属性用于指定一种特定的协议。


    linux下进程间通信的几种主要手段简介:

    1. 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
    2. 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数);
    3. 报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
    4. 共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
    5. 信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
    6. 套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。

    下面将对上述通信机制做具体阐述。

    附1:参考文献[2]中对linux环境下的进程进行了概括说明:

    一般来说,linux下的进程包含以下几个关键要素:

    • 有一段可执行程序;
    • 有专用的系统堆栈空间;
    • 内核中有它的控制块(进程控制块),描述进程所占用的资源,这样,进程才能接受内核的调度;
    • 具有独立的存储空间

    进程和线程有时候并不完全区分,而往往根据上下文理解其含义。


    展开全文
  • Linux使用yum命令出现未注册的情况

    千次阅读 2020-03-01 19:01:10
    当我们安装好RHEL版的linux,执行yum命令时,如果出现This system is not registered with an entitlement server. You can use subscription-manager to register.这种未注册提示时 如图所示使用yum install tentle...

    当我们安装好RHEL版的linux,执行yum命令时,如果出现This system is not registered with an entitlement server. You can use subscription-manager to register.这种未注册提示时

    如图所示使用yum install telnet出现红线标记的未注册提示
    在这里插入图片描述

    流程如下

    1.删除原来的yum源

    检查yum源:rpm -qa | grep yum
    转载请附地址
    删除原来的yum源 rpm -qa|grep yum|xargs rpm -e --nodeps
    在这里插入图片描述

    2.下载CentOS的yum源

    1) 网上找的这几个可以下载的网站

    阿里云网络源地址:https://mirrors.aliyun.com/ 
    
    网易163网络源地址:http://mirrors.163.com/ 
    
    CentOS网络源地址:http://centos.ustc.edu.cn/centos/ 
    

    我选用的是阿里的
    在这里插入图片描述
    2) 打开centos网页,网页拉到最下就可以看到如下图,点击标蓝的链接
    在这里插入图片描述
    3) 依次点击7->os->x86_64->Packages
    也可直接点击此链接https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/

    在此网页https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/中找到下图标记的三个文件,复制他们的链接地址
    在这里插入图片描述
    4) 在linux中把他们用wget命令下载下来,请先确保linux环境可以联网

    wget https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/yum-3.4.3-163.el7.centos.noarch.rpm
    wget https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/yum-metadata-parser-1.1.4-10.el7.x86_64.rpm
    wget https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/yum-plugin-fastestmirror-1.1.31-52.el7.noarch.rpm

    3.安装三个包

    1) 使用rpm -ivh yum-*一次性安装3个包
    在这里插入图片描述

    2)使用rpm -qa |grep yum检查是否安装成功
    在这里插入图片描述

    4.配置repo文件

    1) 在linux中进入etc文件,备份yum.repos.d文件
    cd /etc
    mv yum.repos.d yum.repos.d.bak
    mkdir yum.repos.d
    在这里插入图片描述
    2) 下载repo文件

    点击下载地址

    我们使用的是CentOS7,所以复制此句话,并在linux中运行此句话。
    在这里插入图片描述
    3) 修改下载好的repo文件

    下载好的repo文件应该在etc/yum.repos.d目录下,里面应该也只有一个文件,直接vim 文件名

    把repo文件里所有 $releasever全部替换成版本号7

    操作如下:点击i,然后shift+: 输入命令%s/$releasever/7/g

    替换完毕后,点击esc,然后 :wq 保存退出vim模式

    4) 清除缓存

    yum clean all

    5) 重新生成缓存

    yum makecache

    注意:4和5可能还会出现未注册的提示,不用理

    5.再次使用yum install 命令试试安装

    展开全文
  • linux input system

    千次阅读 2011-09-23 13:42:12
    Linux input system   转载时请注明出处和作者联系方式 文章出处: http://blog.csdn.net/weixu_2008 作者联系方式:徐威 weixu_2008@163.com     本文简单介绍一下 linux 的 input system ...

    Linux input system

     

    转载时请注明出处和作者联系方式
    文章出处:http://blog.csdn.net/weixu_2008

    作者联系方式:徐威weixu_2008@163.com

     

     

    本文简单介绍一下linuxinput system并通过一个实际的案例介绍一下在具体的项目中如何实现自己的inputsystem

     

    1.  系统结构

     

    钻研技术的总是喜欢了解细节以及系统的整个框架,那首先就从linuxinput system的结构开始说起,如下图所示:

    Input system 有三大块组成:

    • Drivers:相当于输入设备的驱动程序,负责接收来自硬件的输入中断,并把输入中断转换成相应的输出给Input Core这个部分的实现取决于具体的硬件,也是实际当中我们主要做的部分。

     

    • Input CoreLinux input system中的核心部分,是输入设备的抽象,把来自输入设备的输入输出到相应的Handler,这部分的代码可以看linux的内核代码中Drivers/input/input.c在实际中我们不需要自己去写这部分的代码。

     

    • Handlers:用户空间中的应用程序通过handlers来接收输入,对于用户空间来说,Handler就像一个设备一样,可以从中得到底层的输入。在实际应用中,这块基本上很少会去修改。

     

    综上:一个输入的数据流的路径:Drivers → Input Core → Handlers → Applications

     

     

    讲完了结构,那在实际中,DriverInput Core Handler Application 是如何联系上的呢?

     

    首先说说Driver是怎么和Input CoreHandler联系上的呢?

     

    Input Core中,由两个链表:input_dev_listinput_handler_list

    当有一个新的driver调用input_register_device的时候,Input Core就会把这个input_dev添加到input_dev_list中,同时还会在input_handler_list中寻找所有匹配的input_handler,把input_handlerinput_dev连接(connect)起来,一旦连接以后,input_dev发生的输入就会通过Input Core 传递到input_handler,用户空间的applications通过input_handler进而得到输入。

     

    同样,当有一个新的handler调用input_register_handler的时候,Input Core就会把这个input_handler添加到input_handler_list上面,同时遍历input_dev_list找出所有匹配的input_dev,并且把匹配的input_devinput_handler连接(connect)起来。

     

    如果用图来说明的话,input_devinput_dev_handler之间的关系如下:

     

    123表示input_dev设备,其通过input_dev->node变量连接到全局输入设备链表input_dev_list中。结点 456表示input_handler处理器,其通过input_handler->node连接到全局handler处理器链表input_handler_list中。结点7是一个input_handle的结构体,其用来连接input_devinput_handlerinput_handledev成员指向了对应的input_dev设备,input_handlehandler成员指向了对应的input_handler。另外,结点7input_handle通过d_node连接到了结点2input_dev上的h_list链表上。另一方面,结点7input_handle通过h_node连接到了结点5input_handlerh_list链表上。通过这种关系,将input_devinput_handler联系了起来。

     

    Application又是怎么和Handler联系上的呢?

    每一个handler都类似于/dev/下面的一个设备,application需要打开这个设备,使用read方法来读取输入。

    而在handler中,又有一个client_list的链表,每当有application打开这个handler的时候,都会建立一个新的client并且添加到这个client_list上面去,这样所有的applications都会接到同样的输入。

     

    在系统中,可以通过以下命令来看有哪些input_devinput_dev_handler

    cat /proc/bus/input/devices

    cat /proc/bus/input/handlers

     

    2.  实例

        01  #include <asm/irq.h> 
        02  #include <asm/io.h> 
        03  static struct input_dev *button_dev;    /*输入设备结构体*/  
        04  static irqreturn_t button_interrupt(int irq, void *dummy) /*中断处理函数*/  
        05  {  
        06      input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);      
        /*向输入子系统报告产生按键事件*/  
        07      input_sync(button_dev);         /*通知接收者,一个报告发送完毕*/  
        08      return IRQ_HANDLED;  
        09  }  
        10  static int __init button_init(void) /*加载函数*/  
        11  {  
        12      int error;  
        13      if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL))  /*申请中断处理函数*/  
        14      {  
        15          /*申请失败,则打印出错信息*/  
        16          printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_  
        irq);  
        17          return -EBUSY;  
        18      }  
        19      button_dev = input_allocate_device();   /*分配一个设备结构体*/  
        20      if (!button_dev)                        /*判断分配是否成功*/  
        21      {  
        22          printk(KERN_ERR "button.c: Not enough memory\n");  
        23          error = -ENOMEM;  
        24          goto err_free_irq;  
        25      }  
        26      button_dev->evbit[0] = BIT_MASK(EV_KEY);    /*设置按键信息*/  
        27      button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);  
        28      error = input_register_device(button_dev);  /*注册一个输入设备*/  
        29      if (error)  
        30      {  
        31          printk(KERN_ERR "button.c: Failed to register device\n");  
        32          goto err_free_dev;  
        33      }  
        34      return 0;  
        35      err_free_dev:                               /*以下是错误处理*/  
        36          input_free_device(button_dev);  
        37      err_free_irq:  
        38          free_irq(BUTTON_IRQ, button_interrupt);  
        39      return error;  
        40  }  
        41  static void __exit button_exit(void)            /*卸载函数*/  
        42  {  
        43      input_unregister_device(button_dev);        /*注销按键设备*/  
        44      free_irq(BUTTON_IRQ, button_interrupt); /*释放按键占用的中断线*/  
        45  }  
        46  module_init(button_init);  
        47  module_exit(button_exit); 
    


     

     

    3. 扩展

     

    另外,我们也可以通过往/dev/uinput中写数据来模拟输入。

    代码:

     

    #include <string.h> 
    #include <stdio.h> 
    #include <sys/types.h> 
    #include <sys/stat.h> 
    #include <fcntl.h> 
    #include <linux/input.h> 
    #include <linux/uinput.h> 
    #include <stdio.h> 
    #include <sys/time.h> 
    #include <sys/types.h> 
    #include <unistd.h> 
     
    /* Globals */ 
    static int uinp_fd = -1; 
    struct uinput_user_dev uinp;  // uInput device structure 
    struct input_event event;  // Input device structure 
     
    /* Setup the uinput device */ 
     
    int setup_uinput_device() 
    { 
      // Temporary variable 
      int i=0; 
       
      // Open the input device  
        uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY); 
     
      if (uinp_fd == NULL) 
     
      { 
        printf("Unable to open /dev/uinput\n"); 
        return -1; 
      } 
     
      memset(&uinp,0,sizeof(uinp));   // Intialize the uInput device to NULL 
     
      strncpy(uinp.name, "PolyVision Touch Screen", UINPUT_MAX_NAME_SI
      uinp.id.version = 4; 
      uinp.id.bustype = BUS_USB; 
     
      // Setup the uinput device  
      ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY); 
      ioctl(uinp_fd, UI_SET_EVBIT, EV_REL); 
      ioctl(uinp_fd, UI_SET_RELBIT, REL_X); 
      ioctl(uinp_fd, UI_SET_RELBIT, REL_Y); 
     
      for (i=0; i < 256; i++) { 
           ioctl(uinp_fd, UI_SET_KEYBIT, i); 
      } 
     
      ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MOUSE); 
      ioctl(uinp_fd, UI_SET_KEYBIT, BTN_TOUCH); 
     
      ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MOUSE); 
      ioctl(uinp_fd, UI_SET_KEYBIT, BTN_LEFT); 
      ioctl(uinp_fd, UI_SET_KEYBIT, BTN_MIDDLE); 
      ioctl(uinp_fd, UI_SET_KEYBIT, BTN_RIGHT); 
      ioctl(uinp_fd, UI_SET_KEYBIT, BTN_FORWARD); 
      ioctl(uinp_fd, UI_SET_KEYBIT, BTN_BACK); 
     
      /* Create input device into input sub-system */ 
      write(uinp_fd, &uinp, sizeof(uinp)); 
     
      if (ioctl(uinp_fd, UI_DEV_CREATE)) 
      { 
        printf("Unable to create UINPUT device."); 
        return -1; 
      } 
      return 1; 
    } 
     
    void send_click_events( ) 
    { 
             // Move pointer to (0,0) location 
         
       memset(&event, 0, sizeof(event)); 
      gettimeofday(&event.time, NULL); 
     
            event.type = EV_REL; 
            event.code = REL_X; 
             event.value = 100; 
            write(uinp_fd, &event, sizeof(event)); 
     
            event.type = EV_REL; 
            event.code = REL_Y; 
            event.value = 100; 
            write(uinp_fd, &event, sizeof(event)); 
     
      event.type = EV_SYN; 
            event.code = SYN_REPORT; 
            event.value = 0; 
            write(uinp_fd, &event, sizeof(event)); 
       
      // Report BUTTON CLICK - PRESS event  
     
      memset(&event, 0, sizeof(event)); 
      gettimeofday(&event.time, NULL); 
      event.type = EV_KEY; 
      event.code = BTN_LEFT; 
      event.value = 1; 
      write(uinp_fd, &event, sizeof(event)); 
     
      event.type = EV_SYN; 
      event.code = SYN_REPORT; 
      event.value = 0; 
      write(uinp_fd, &event, sizeof(event)); 
     
      // Report BUTTON CLICK - RELEASE event  
     
      memset(&event, 0, sizeof(event)); 
      gettimeofday(&event.time, NULL); 
      event.type = EV_KEY; 
      event.code = BTN_LEFT; 
      event.value = 0; 
      write(uinp_fd, &event, sizeof(event)); 
     
      event.type = EV_SYN; 
      event.code = SYN_REPORT; 
      event.value = 0; 
      write(uinp_fd, &event, sizeof(event)); 
    }   
     
    void send_a_button() 
    { 
      // Report BUTTON CLICK - PRESS event  
     
      memset(&event, 0, sizeof(event)); 
      gettimeofday(&event.time, NULL); 
            event.type = EV_KEY; 
            event.code = KEY_A; 
             event.value = 1; 
            write(uinp_fd, &event, sizeof(event)); 
     
            event.type = EV_SYN; 
            event.code = SYN_REPORT; 
            event.value = 0; 
            write(uinp_fd, &event, sizeof(event)); 
     
     
      // Report BUTTON CLICK - RELEASE event  
     
    memset(&event, 0, sizeof(event)); 
      gettimeofday(&event.time, NULL); 
            event.type = EV_KEY; 
            event.code = KEY_A; 
            event.value = 0; 
            write(uinp_fd, &event, sizeof(event)); 
     
            event.type = EV_SYN; 
            event.code = SYN_REPORT; 
            event.value = 0; 
            write(uinp_fd, &event, sizeof(event)); 
    } 
     
     
    /* This function will open the uInput device. Please make  
       sure that you have inserted the uinput.ko into kernel.  */ 
     
    int main() 
    { 
      // Return an error if device not found. 
      if (setup_uinput_device() < 0)  
      { 
        printf("Unable to find uinput device\n"); 
        return -1; 
      } 
       
      send_a_button();    // Send a "A" key 
       
      send_click_events();  // Send mouse event 
     
      /* Destroy the input device */ 
      ioctl(uinp_fd, UI_DEV_DESTROY); 
     
      /* Close the UINPUT device */ 
      close(uinp_fd); 
    } 
     
     


     

    linux中,也并不是所有的input都是通过Input Core的,比如:

    USB input system

     

    Linux Bluetooth input system

     

    Linux ACPI input system

     

    现在已经有了很多开源库介绍inputabstract layer可以google下。

     

    4.  参考

    ·       http://www.cnblogs.com/dekun_1986/archive/2011/09/12/2174264.html

    ·        http://blog.csdn.net/wenny198561/article/details/6309208

    ·        http://blog.csdn.net/jack0106/article/details/6336136

    ·        http://blog.chinaunix.net/attachment/attach/25/69/93/2925699329b2cbd71db82a8b965509be27bd20ad46.pdf

    ·        http://www4.informatik.uni-erlangen.de/~thoenig/thesis/thesis.pdf

    ·        http://www.einfochips.com/download/dash_jan_tip.pdf

    展开全文
  • 关于linux system函数调用遇到的坑

    千次阅读 2018-07-11 11:39:10
    关于linux c++守护进程调用调用system函数 我们的程序是守护进程,也就是说在最开始会设置一些信号处理,比如说 ... signal(SIGCHLD, SIG_IGN); //忽略子进程结束的信号 ... 在这样的场景之下,我想实现这样的...

    关于linux c++守护进程调用调用system函数

    我们的程序是守护进程,也就是说在最开始会设置一些信号处理,比如说

    ...
    signal(SIGCHLD, SIG_IGN); //忽略子进程结束的信号
    ...

    在这样的场景之下,我想实现这样的一个功能:

    通过调用system函数来执行一些系统命令,并根据系统命令的返回值是不是0来判断命令是否执行成功(正常情况下调用system函数,执行成功 return 0; 执行失败 return 正数;)当我写下

    int ret = system("ls -a");
    std::cout<<"call system ret="<<ret<<std::endl;

    时发现始终 ret = -1 查看errno发现errno=10(errno.10 is: No child processes)

    进一步分析:

    system的实现大致是这样的:

    1)主进程fork一个子进程
    2)子进程调用exec函数去执行命令
    3)父进程调用waitpid来等来子进程结束

    也就是说在调用waitpid的时候子进程退出,父进程收不到他的退出信号只发现这个进程不在了,所以有errno=10 ret = -1
    具体原因:

    当父进程未调用wait系列函数等待子进程结束且未显示忽略SIGCHLD信号,则子进程将成为僵尸进程。如果忽略SIGCHLD信号,子进程不会成为僵尸进程,子进程结束后将会直接退出并释放资源,等父进程调用waitpid时发现pid进程不存在了

    解决办法:

    signal(SIGCHLD, SIG_DFL);
    int ret = system(cmd);
    signal(SIGCHLD, SIG_IGN);

    在调用system函数的时候按照默认方式处理SIGCHLD信号。

    深入探索

    system函数的内部实现是要阻塞SIGCHLD信号,原因是怕system的调用者在调用system函数之前有注册过SIGCHLD的信号处理函数,当产生SIGCHLD信号时system的调用者使用一种wait获取到子进程的终止状态,而system函数就无法获取子进程的终止状态(子进程的终止状态只能被获取一次)
    注意一点:不管有没有SIGCHLD信号通知,waitpid都可获取子进程的终止状态

    忽略SIGCHLD信号调用system的结果是errno=10 ret=-1,忽略SIGCHLD信号然后阻塞SIGCHLD信号并没有影响errno=10 ret=-1的结果,因为阻塞是暂时不接受这个信号,忽略是接受到这个信号后的一种处理方式

    关于TcpServer程序调用system函数的问题

    场景:我有一个tcp服务器假设它叫agent,它会监听一个端口(如8420)。它的工作是接受远程发过来的命令,来启动、停止一个或多个服务程序。这个处理命令的实现是通过system函数来实现的,比如说启动:system(“cd /home/user/xxxsvr; ./xxxsvr”)

    出现的问题:当agent收到命令并根据命令启动多个程序之后把agent关闭,他监听的端口8420并没有关闭,而是被agent启动的某个程序占用

    分析 : 还是system函数的实现。fork一个子进程会复制父进程的所有资源,包括文件描述符。

    解决的办法

    fcntl(listen_fd, F_SETFD, FD_CLOEXEC);

    FD_CLOEXEC标志用来控制在执行 exec 后,是否关闭对应的文件描述符

    展开全文
  • Redhat Linux Server 报未注册的错误

    千次阅读 2015-01-20 23:36:58
    Linux系统版本: [红帽企业Linux.6.4.服务器版].rhel-server-6.4-x86_64-dvd 在虚拟机中安装完系统后, 想使用# yum check-update sudo命令更新sudo, 报出了如下错误:  This system is not registered to Red Hat ...
  • 我们安装好RHEL的Linux后,执行yum命令安装软件,如果是未注册的肯定会出现This system is not registered with an entitlement server. You can use subscription-manager to register. 类似这样的问题 具体如下图...
  • Linuxsystem()和popen()差异

    万次阅读 2015-07-25 22:06:33
    Linuxsystem()和popen()差异1. system()和popen()简介在linux中我们可以通过system()来执行一个shell命令,popen()也是执行shell命令并且通过管道和shell命令进行通信。 system()、popen()给我们处理了fork、exec...
  • 我虚拟机安装的系统是RedHat Enterprise Linux 6.4-i686,是32位的。使用yum命令安装软件时候出现以下错误: This system is not registered to Red Hat Subscription Management.You can use subscription-manager ...
  • linux字符设备注册相关函数

    千次阅读 2010-01-03 10:22:00
    概述本文介绍linux字符设备注册相关的四个函数:cdev_alloc、cdev_init、cdev_add和cdev_del。这四个函数在文件:fs/char_dev.c中定义,在头文件include/linux/cdev.h中声明。其中cdev_alloc和cdev_init是一对“互斥...
  • linux kernel文件系统数据结构file_system_type  文件系统类型用于表示各种不同的文件系统,如fat, sysfs, proc等等,对于每个不同的文件系统,都以struct file_system_type进行描述,内核将它们以单链表的形式...
  • 浅谈linux字符设备注册

    千次阅读 2010-09-18 10:35:00
    Linux中有两种字符设备注册的方法: 这里所提到的函数在文件:fs/char_dev.c中定义,在头文件include/linux/cdev.h中声明。 一、 老方法: 如果你深入浏览 2.6 内核的大量驱动代码, 你可能...
  • http://processors.wiki.ti.com/index.php?title=Creating_a_Root_File_System_for_Linux_on_OMAP35x 翻译文章,转载本文请标明出处,谢谢。 今天,我们只关注root file system的创建,并不聚焦具体的芯片...
  • linux 可运行jar注册为服务

    千次阅读 2019-05-27 14:36:15
    最近在做项目的时候,开发完成后需要将打包的可运行jar包注册linux系统服务,通过服务启停命令来控制jar的部署。 一、编写jar启动执行的脚本 vim new_monitor-start.sh 脚本: #!/bin/sh nohup /usr/local/...
  • 我们的程序是守护进程,也就是说在最开始会...通过调用system函数来执行一些系统命令,并根据系统命令的返回值是不是0来判断命令是否执行成功(正常情况下调用system函数,执行成功 return 0; 执行失败 return 正...
  • Linux 如何将java服务注册Linux系统服务启动 前言 当注册为系统服务启动之后,对于程序的管理更加简单方面。 systemctl start test-demo-api.service //启动项目 systemctl stop test-demo-api.service //...
  • 注册成服务一般是有两种方式: 在usr/lib/systemd/system下新建 服务名.service ...能够使用service命令进行操作的,就是已经注册成为linux的系统服务了。window中也可以注册成为系统服务的办法。 service命令用的...
  • windows和linux注册动态链接库的方法

    千次阅读 2015-12-31 22:36:29
    windows和linux注册动态链接库的方法
  • linux文件系统注册与安装

    千次阅读 2014-03-04 14:14:01
    转载:http://www.eefocus.com/article/09-06/75215s.html(深入分析linux内核源码)   当内核被编译时,就已经确定了可以支持哪些文件系统,这些文件系统在系统引导时,在 VFS 中进行注册。如果文件系统是...
  • 原因是你的Linux没有在红帽网络上注册,所以无法下载上面的软件包,替代方案可以使用centos。 下面介绍下使用centos 的流程 1.卸载rhel的默认安装的yum包 查看yum包 rpm -qa|grep yum 卸载之 rpm -qa|grep yum...
  • 1.显示系统(Display system) 架构 显示系统由核心层与各个组件(fb、crt等)部分,其架构图如图1所示。每个组件都是可装载卸载的,即系统不需要实现所有组件,仅需要激活一个组件就能使用该组件在组件指定的特性和...
  • 将java应用注册Linux服务

    千次阅读 2018-07-30 14:01:37
    将java应用注册Linux服务 将java应用注册成windows服务详见:https://blog.csdn.net/rico_zhou/article/details/81283953 接下来我们将java程序比如可执行jar包注册linux服务,以方便管理和启动,linux环境为...
  • 其主要作用:注册usb文件系统,注册一个usbfs_nb通知链,最后是在proc文件系统下面创建bus/usb目录。 进入/proc/bus/usb目录 # ls 001 002 devices 此devices的内容完全与usb debug文件系统里的...
  • 由于《Linux Device Driver》3rd 是针对kernel 2.6.10的,我的的平台是Debian kernel 2.6.32,导致了基本的模块(misc-modules下的那些)都编译不过。主要原因是内核升级带来的接口变化。就编译misc-modules目录而言
  • Linux注册服务(chkconfig)

    千次阅读 2011-12-01 15:38:32
    # description: Saves and restores system entropy pool for \ # higher quality random number generation. 使用范例: chkconfig --list #列出所有的系统服务 chkconfig --add httpd #增加httpd服务 ...
  • 就字面上来说 这句话是使用redhat的yum源需要注册。 但我的情况是在/etc/yum.repos.d/目录下(我的repo文件命名为rhel_dvd.repo) 而文本里面方框的内容是[redhat 7] 所以当我输入yum repolist命令的时候 出现了一下...
  • 参考: http://blog.csdn.net/gxfan/article/details/3079766 ... 在linux内核中,每一种注册了的文件系统都由一个类型为file_system_type的结构体来代表,该结构体中含有一个类型为file_system_ty
  • 本人使用的是Ubuntu2018下的IDEA2018,今天打开IDEA时提示证书已过期,试了下其他的注册码以及server都不行,最后参考了这篇博客才注册成功,但是原博客没有说明Windows系统还是Linux系统,也没有给出具体步骤,此处...
  • Linux下将tomcat注册为服务

    千次阅读 2018-11-27 10:07:05
    在/usr/lib/systemd/system/目录下新建文件tomcat.service,并添加如下的内容: [Unit] Description=tomcat1 After=syslog.target network.target remote-fs.target nss-lookup.target [Service] Type=forking PID...
  • 在RedHat Enterprise Linux下使用yum时会遇到如下问题: #yum install pam-devel #This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register. ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 98,285
精华内容 39,314
关键字:

linuxsystem未注册

linux 订阅