如何在信号驱动的恶魔中暂停主循环? [英] How to suspend the main-loop in a signal-driven demon?

查看:103
本文介绍了如何在信号驱动的恶魔中暂停主循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为树莓派进行电子电话线路仿真。为此,我需要一个函数,该函数每20 ms(= 50Hz,振铃电压频率的一半)被调用一次,检查电流并更新HW PWM的占空比。为了到达那里,我在相应的计时器上设置了一个信号处理程序(因为我将其挂在纯嵌入式环境中的调度程序中)并让其完成工作。请注意,缩短了下面的代码只是为了关注该问题。

I'm working on an electronic phone-line emulation for a raspberry pi. For this, I’m in need of a function, which is called each 20 ms (=50Hz, half of the ringing voltage-frequency), checks the electrical current and updates the duty-cycle of a HW PWM. To get there, I set up a signal-handler on an according timer (as I’d hang it into the scheduler in a pure embedded environment) and let it do its work. Note, that the code below is shortened just in order to kfocus on the issue.

这已经可以很好地工作了。令我惊讶的是,保持了如此精确的定时(用示波器测量的抖动低于10µs)。

This already works pretty well. I was amazed, how accurate the timing is kept (the jitter is below 10µs, measured with an oscilloscope).

但是,到目前为止,存在一个缺陷:那实际上不需要主循环。我不能从中返回,因为那样会终止进程。当我让它成为一个空循环时,一切工作正常。但是我在考虑不必要地消耗CPU负载。

However, there’s up to now one flaw: When working like that, the main-loop is actually not required. I cannot return from it, since that would kill the process. When I just let it be an empty loop, all is working fine. But I’m thinking about unnecessarily consumed CPU load.

我尝试了 sleep 等待 (我知道应该不再使用两者)和 sigsuspend

I tried sleep, wait (both of which should not be used anymore, I know), and sigsuspend. But all of these let to the alarm-handler not being called anymore.

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <sys/time.h>
#include <bcm2835.h>

#define PIN_PWM RPI_V2_GPIO_P1_35

bool b_Alive;

/** Signal-Handlers: ******************************************************************/

void SIG_Alarm (int signum) {
    /** Just toggle a pin for now:                                                    */
    static bool bOn;
    if (bOn) {
        bOn = 0;
        bcm2835_gpio_write(PIN_PWM, LOW);
    }else{
        bOn = 1;
        bcm2835_gpio_write(PIN_PWM, HIGH);
    }
}

void SIG_Quit (int signum) {
    /** Shutdown the bcm-library:                                                     */
    bcm2835_close();
    /** Close the sys-log handler:                                                    */
    syslog(LOG_NOTICE + LOG_DAEMON, "Received SigInt and closed.");
    closelog();
    b_Alive = false;    
}

/** Main-Function: ********************************************************************/


int main(void) {
    /** Variables:                                                                    */
    struct sigaction sa;
    struct itimerval timer;
    /** Open syslog instead: */
    openlog( "PhoneLined", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_LOCAL0 );
    /** Setup pins:                                                                   */
    if (!bcm2835_init()) return 1;
    bcm2835_gpio_fsel(PIN_PWM, BCM2835_GPIO_FSEL_OUTP);
    /** Setup signal handler for kill:                                                */
    memset(&sa, 0, sizeof (sa));
    sigemptyset(&sa.sa_mask);
    sa.sa_handler = &SIG_Quit;
    sigaction(SIGINT , &sa, NULL);
    sigaction(SIGQUIT, &sa, NULL);
    sigaction(SIGKILL, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);
    /** Setup signal handler for timer:                                               */
    memset(&sa, 0, sizeof (sa));
    sigemptyset(&sa.sa_mask);
    sa.sa_handler = &SIG_Alarm;
    sigaction(SIGVTALRM, &sa, NULL);
    /** Configure the timer of a start- and cycle-time of 20ms (=50Hz):               */
    timer.it_value.tv_sec = 0;
    timer.it_value.tv_usec = 20000;
    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_usec = 20000;
    setitimer(ITIMER_VIRTUAL, &timer, NULL);
    /** Prepare main-loop:                                                            */
    b_Alive = true;
    syslog(LOG_NOTICE + LOG_DAEMON, "Sucessfully initialized.");
    /** ... and do nothing, while the timer works:                                    */
    while (b_Alive) {
        //pause(), suspend, wait or anything?
    }
    exit(EXIT_SUCCESS);
}

在实际上什么也没做的情况下,是否有任何提示,如何进行

Are there any hints, how to proceed, when nothing is actually to be done in this loop?

推荐答案

至少添加 volatile ,否则该循环将被优化器(对于O2或更高版本)删除

at least add volatile to your flag's definition, or the loop will be removed by the optimiser (for-O2, or higher)

cc -Wall -O4 -S signal.c

#include <stdbool.h>
// volatile sig_atomic_t
volatile bool
        b_Alive=false;






main():


main():

...
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 20000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 20000;
setitimer(ITIMER_REAL, &timer, NULL);

// Prepare main-loop:            

b_Alive = true;
    syslog(LOG_NOTICE + LOG_DAEMON, "Sucessfully initialized.");
    /** ... and do nothing, while the timer works:                                    */
    while (b_Alive) {
        pause(); //, suspend, wait or anything?
    }
    exit(EXIT_SUCCESS);






并且,定时器类型(来自精美手册) :


And, the timertypes (from the fine manual):

   ITIMER_REAL    This timer counts down in real (i.e., wall clock) time.  At each expiration, a SIGALRM signal is generated.

   ITIMER_VIRTUAL This timer counts down against the user-mode CPU time consumed by the process.  (The measurement includes CPU time consumed by all threads in the process.)  At each
                  expiration, a SIGVTALRM signal is generated.






而且,由于暂停()不消耗任何CPU滴答声,使用ITIMER_VIRTUAL时,计时器永远不会过期。 (另:传递了不同的信号)


And, since pause() does not consume any CPU ticks, the timer would never expire when using ITIMER_VIRTUAL. (also: a different signal is delivered)

这篇关于如何在信号驱动的恶魔中暂停主循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆