【问题标题】:how to code the kernel mode of rt-linux?如何编写rt-linux的内核模式?
【发布时间】:2014-05-05 02:56:46
【问题描述】:

中断是在内核模式下处理的,但要在 rt linux 中处理中断,他们是这样说的:

我需要在内核空间和内核模块中使用 RTLinux 编写代码。使用 QNX,您无法编写内核模块(内核未打开),并且您在用户空间中具有实时性。

我的问题: 如何在内核空间编写代码? 那到底是什么意思? 我应该在哪里修改内核??

有人请提出一些想法。

udp 代码:

 int CreateSocket()
 {
     socklen_t len;

   // Socket creation for UDP

   acceptSocket=socket(AF_INET,SOCK_DGRAM,0);

   if(acceptSocket==-1)

   {

     printf("Failure: socket creation is failed, failure code\n");

     return 1;

   }

   else

   {

     printf("Socket started!\n");

   }

 memset(&addr, 0, sizeof(addr));

 addr.sin_family=AF_INET;

 addr.sin_port=htons(port);

 addr.sin_addr.s_addr=htonl(INADDR_ANY);

 rc=bind(acceptSocket,(struct sockaddr*)&addr,sizeof(addr));

 if(rc== -1)

 {

     printf("Oh dear, something went wrong with bind()! %s\n", strerror(errno));

   return 1;

 }

 else

 {

   printf("Socket an port %d \n",port);
 }


   while(rc!=-1)
   {
     len = sizeof(client);
     rc=recvfrom(acceptSocket,buf, 256, 0, (struct sockaddr*) &client, &len);

     //I am calculating the time here
     InterruptTime = GetTimeStamp();
     measurements[17] = InterruptTime;

     if(rc==0)
     {
       printf("Server has no connection..\n");
       break;
     }
     if(rc==-1)
     {
         printf("Oh dear, something went wrong with read()! %s\n", strerror(errno));
       break;
     }

     XcpIp_RxCallback( (uint16) rc, (uint8*) buf, (uint16) port );


   }

   close(acceptSocket);
   return 1;
   }

int main()
{
CreateSocket();

while(1)
{
     TASK1(Task2ms_Raster);
     TASK2(Task10ms_Raster);
     TASK3(Task100ms_Raster);
}

【问题讨论】:

    标签: c linux linux-kernel kernel real-time


    【解决方案1】:

    与 QNX 不同,Linux 内核是开源软件。这意味着您可以以任何您想要的方式修改和更改它。您从http://kernel.org 获取源代码(最好使用 Git 克隆到本地存储库),进行修改、添加等。编译并使用它启动您的计算机。

    请注意,自 2.6 版以来的 Linux 还提供实时调度,这可能就足够了。

    更新代码示例

    对于时间光栅任务执行,我建议如下:

    #define _POSIX_C_SOURCE 200809L
    #define _XOPEN_SOURCE   500
    
    #include <sched.h>  /* for sched_setsched */
    #include <unistd.h> /* for usleep */
    #include <time.h>   /* for clock_gettime */
    #include <string.h> /* for memset */
    
    #define MS_to_US(x) ((x)*1000)
    
    useconds_t delta_t_us(struct timespec const *a, struct timespec const *b)
    {
        time_t const delta_sec  = b->tv_sec  - a->tv_sec;
        long   const delta_nsec = b->tv_nsec - a->tv_nsec;
    
        /* this might actually overflow for "long" time intervalls"
         * should be safe for a delta_t < 2ms though */
        return delta_sec * 1000000 + delta_nsec / 1000;
    }
    
    void rastertask()
    {
        struct sched_param sparm;
        memset(&sparm, 0, sizeof(sparm));
        sparm.sched_priority = 10; /* 0 = lowest, 99 = highest */
    
        sched_setscheduler(
            0 /* pid, 0 ==> this process */,
            SCHED_RR /* policy */,
            &sparm);
    
        unsigned int n_loop;
        for(n_loop=0;;n_loop++) {
            struct timespec ts_start, ts_end;
            clock_gettime(CLOCK_MONOTONIC, &ts_start);
    
            TASK1(); /* gets called every 2ms */
            if( (n_loop % 5) == 0) {
                TASK2(); /* get called every 5 * 2ms = 10ms */
            }
            if( (n_loop % 50) == 0) {
                TASK2(); /* get called every 50 * 2ms = 100ms */
            }
    
            if( (n_loop % 250) == 0 ) {
                /* reset loop counter when smallest common
                 * multiple of timing grid has been reached */
                n_loop = 0;
            }
    
            clock_gettime(CLOCK_MONOTONIC, &ts_end);
            useconds_t const tasks_execution_time = delta_t_us(&ts_start, &ts_end);
    
            if( tasks_execution_time >= MS_to_US(2) ) {
                /* report an error that tasks took longer than 2ms to execute */
            }
    
            /* wait for 2ms - task_execution_time so that tasks get called in
             * a close 2ms timing grid */
            usleep( MS_to_US(2) - tasks_execution_time );
        }
    }
    

    请注意,该进程需要 CAP_SYS_NICE 权限(Linux 2.6.12 之前)或足够的 RLIMIT_RTPRIO 资源限制才能设置其优先级。

    【讨论】:

    • @user3458454:你没有修改“the”中断。为什么?因为在一个典型的系统中有数百个不同的中断源。无论如何,您所做的是,您编写一个中断处理程序并将其注册到内核,以便在您感兴趣的中断源的中断请求时调用它。现在问题仍然存在吗?为什么要在内核空间中操作?通常,只有在实现设备驱动程序或内核子系统时才会这样做——说真的,如果你必须像以前那样提出问题,那么你不应该在内核中乱来。 你到底想做什么?
    • @user3458454:以太网?所以你想为网卡写一个中断处理程序?然后什么?你想自己做整个网络处理吗?您确实意识到网络是一项令人讨厌的业务,而不是胆小的人。当涉及到以太网时,中断处理程序必须做很多事情(从 NIC 读取以太网帧,测试校验和等),然后将其交给网络堆栈,重新组装数据包,进行安全检查等。所有这已经在 Linux 中实现供您使用。你不自己实现那个
    • @user3458454:你没有。为网卡注册一个中断处理程序意味着您必须完成所有令人讨厌的网络工作。您要做的是唤醒客户端以响应新数据的到来。使用epoll API 以获得最低延迟。设置并调用epoll_wait 后,您的进程将休眠,直到数据到达。 –– 从您对问题的处理方法来看,您已经习惯了微控制器编程,在应用程序级别直接处理中断是常见的做法。但是对于 (RT)Linux,您不会这样做。
    • @user3458454:是的,这当然是可能的,但不一定是明智的。这实际上取决于代码在做什么。所有与网络和 I/O 相关的事情都应该在用户空间中完成,因为在内核模式下尝试这样做并不是很聪明(值得注意的例外:网络文件系统,但这只是因为文件系统传统上存在于内核中)。通常,您将在内核模式下执行的代码量保持在最低限度,并尽可能多地移动到用户空间。
    • @user3458454:假设您正在开发一个机器人控制系统:您将整个电机控制和传感器读数放入内核中以获得硬实时。但是与其他系统和更高级别逻辑不需要的所有通信原则上不能以实时行为行事,因此您将它们放入用户空间。用户空间部分通过设备节点 I/O 和 ioctl、syscall 或 sysfs 与内核模式部分交互。
    猜你喜欢
    • 2012-09-27
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 2014-04-26
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多