How to suspend the main-loop in a signal-driven demon?

心不动则不痛 提交于 2019-12-13 03:45:26

问题


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.

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

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.

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?


回答1:


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

(check with cc -Wall -O4 -S signal.c)


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

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.

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



来源:https://stackoverflow.com/questions/54618065/how-to-suspend-the-main-loop-in-a-signal-driven-demon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!