如何在信号驱动的恶魔中暂停主循环?
How to suspend the main-loop in a signal-driven demon?
我正在为 raspberry pi 开发电子 phone 线路仿真。为此,我需要一个函数,它每 20 毫秒(=50Hz,振铃电压频率的一半)调用一次,检查电流并更新 HW PWM 的占空比。为此,我在相应的计时器上设置了一个信号处理程序(因为我会在纯嵌入式环境中将其挂入调度程序)并让它完成工作。请注意,下面的代码被缩短只是为了关注这个问题。
这已经很好用了。我很惊讶,时间保持得如此准确(抖动低于 10µs,用示波器测量)。
然而,目前有一个缺陷:当这样工作时,实际上不需要主循环。我不能 return 从它,因为那会终止进程。当我让它成为一个空循环时,一切正常。但我正在考虑不必要地消耗 CPU 负载。
我试过睡眠,等待 (这两个都不应该再使用了,我知道)和 sigsuspend。但是所有这些都让警报处理程序不再被调用。
#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);
}
是否有任何提示,当在此循环中实际上什么都不做时如何继续?
至少 将 volatile
添加到标志的定义中,否则循环将被优化器删除(对于- O2,或更高)
(用cc -Wall -O4 -S signal.c
检查)
#include <stdbool.h>
// volatile sig_atomic_t
volatile bool
b_Alive=false;
主要():
...
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);
还有,定时器类型(来自精细手册):
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.
而且,由于 pause()
不消耗任何 CPU 滴答,因此使用 ITIMER_VIRTUAL 时计时器永远不会过期。 (另外:传递了不同的信号)
我正在为 raspberry pi 开发电子 phone 线路仿真。为此,我需要一个函数,它每 20 毫秒(=50Hz,振铃电压频率的一半)调用一次,检查电流并更新 HW PWM 的占空比。为此,我在相应的计时器上设置了一个信号处理程序(因为我会在纯嵌入式环境中将其挂入调度程序)并让它完成工作。请注意,下面的代码被缩短只是为了关注这个问题。
这已经很好用了。我很惊讶,时间保持得如此准确(抖动低于 10µs,用示波器测量)。
然而,目前有一个缺陷:当这样工作时,实际上不需要主循环。我不能 return 从它,因为那会终止进程。当我让它成为一个空循环时,一切正常。但我正在考虑不必要地消耗 CPU 负载。
我试过睡眠,等待 (这两个都不应该再使用了,我知道)和 sigsuspend。但是所有这些都让警报处理程序不再被调用。
#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);
}
是否有任何提示,当在此循环中实际上什么都不做时如何继续?
至少 将 volatile
添加到标志的定义中,否则循环将被优化器删除(对于- O2,或更高)
(用cc -Wall -O4 -S signal.c
检查)
#include <stdbool.h>
// volatile sig_atomic_t
volatile bool
b_Alive=false;
主要():
...
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);
还有,定时器类型(来自精细手册):
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.
而且,由于 pause()
不消耗任何 CPU 滴答,因此使用 ITIMER_VIRTUAL 时计时器永远不会过期。 (另外:传递了不同的信号)