When setting up an interrupt on timer expiry with signal.h and time.h, is it required to put the timer address in sigevent sigev_value.sival_ptr?

huangapple go评论71阅读模式
英文:

When setting up an interrupt on timer expiry with signal.h and time.h, is it required to put the timer address in sigevent sigev_value.sival_ptr?

问题

I'm currently setting up an interrupt on timer expiry with the Linux system programming libraries time.h and signal.h. In the example provided in this page of the manual, the sigevent field sigev_value.sival_ptr is set to point to the address of the pointer from which a signal should be created when it expires:

/* Create the timer. */

sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCKID, &sev, &timerid) == -1)
    errExit("timer_create");

printf("timer ID is %#jx\n", (uintmax_t) timerid);

If I'm not mistaken, putting that value there has no effect, as the pointer to the timer is already provided as an argument of the timer_create function. Why is it written in this way? Is it because of the way the signal handler is registered?

/* Establish handler for timer signal. */

printf("Establishing handler for signal %d\n", SIG);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIG, &sa, NULL) == -1)
    errExit("sigaction");

In this case, I also don't understand why sa_sigaction is used to point to the signal handling function. Since we don't initialize the siginfo_t struct to convey more information about the signal, shouldn't we use the sa_handler member instead?

I tried to run the example by not setting the sigev_value.sival_ptr and using sa_handler instead, and it worked without any issue, even though I thought it wouldn't. Here's a copy of the code I ran:

#include "RLED.hpp"
#include <iostream>
#include <signal.h>
#include <time.h>
#include <unistd.h>

bool value = false;
R::LED blueLED(0, 22);

void timer_handler(int signum) {
    value = !(value);
    if (value == 1)
    {
        blueLED.set();
    }
    else
    {
        blueLED.clear();
    }
}

int main()
{
    struct sigaction sa;
    struct sigevent sev;
    timer_t timerid;
    struct itimerspec its;

    // Set up the signal handler for the timer signal
    sa.sa_handler = timer_handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGRTMIN, &sa, NULL) == -1)
    {
        std::cout << "Error: signal cannot be setup" << std::endl;
    }

    // Create the timer
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGRTMIN;
    sev.sigev_value.sival_ptr = &timerid;
    timer_create(CLOCK_REALTIME, &sev, &timerid);

    // Configure the timer to expire every 1 second
    its.it_value.tv_sec = 1;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 1;
    its.it_interval.tv_nsec = 0;
    timer_settime(timerid, 0, &its, NULL);

    for (uint32_t i = 0; i < 10; i++)
    {
        sleep(1);
        std::cout << i << std::endl;
    }

    struct itimerspec curr_value;
    timer_gettime(timerid, &curr_value);
    std::cout << "Time: " << curr_value.it_value.tv_sec << "." << curr_value.it_value.tv_nsec << std::endl;

    its = {{0, 0}, {0, 0}};
    timer_settime(timerid, 0, &its, NULL);

    timer_delete(timerid);
    sigaction(SIGRTMIN, NULL, NULL);

    return 0;
}
英文:

I'm currently setting up an interrupt on timer expiry with the Linux system programming libraries time.h and signal.h. In the example provided in this page of the manual, the sigevent field sigev_value.sival_ptr is set to point to the address of the pointer from which a signal should be created when it expires:

/* Create the timer. */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &amp;timerid;
if (timer_create(CLOCKID, &amp;sev, &amp;timerid) == -1)
errExit(&quot;timer_create&quot;);
printf(&quot;timer ID is %#jx\n&quot;, (uintmax_t) timerid);

If I'm not mistaken, putting that value there has no effect, as the pointer to the timer is already provided as an argument of the timer_create function. Why is it written in this way? Is it because of the way the signal handler is registered ?

/* Establish handler for timer signal. */
printf(&quot;Establishing handler for signal %d\n&quot;, SIG);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&amp;sa.sa_mask);
if (sigaction(SIG, &amp;sa, NULL) == -1)
errExit(&quot;sigaction&quot;);

In this case, I also don't understand why sa_sigaction is use to point to the signal handling function. Since we don't initialize the siginfo_t struct to convey more information about the signal, shouldn't we use the sa_handler member instead?

I tried to run the example by not setting the sigev_value.sival_ptr and using sa_handler instead, and it worked without any issue, even though I thought it wouldn't. Here's a copy of the code I ran:

#include &quot;RLED.hpp&quot;
#include &lt;iostream&gt;
#include &lt;signal.h&gt;
#include &lt;time.h&gt;
#include &lt;unistd.h&gt;
bool value = false;
R::LED blueLED( 0, 22 );
void timer_handler(int signum) {
value = !(value);
if (value == 1)
{
blueLED.set();
}
else
{
blueLED.clear();
}
}
int main()
{
struct sigaction sa;
struct sigevent sev;
timer_t timerid;
struct itimerspec its;
// Set up the signal handler for the timer signal
sa.sa_handler = timer_handler;
sigemptyset(&amp;sa.sa_mask);
if (sigaction(SIGRTMIN, &amp;sa, NULL) == -1)
{
std::cout &lt;&lt; &quot;Error: signal cannot be setup&quot; &lt;&lt; std::endl;
}
// Create the timer
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGRTMIN;
sev.sigev_value.sival_ptr = &amp;timerid;
timer_create(CLOCK_REALTIME, &amp;sev, &amp;timerid);
// Configure the timer to expire every 1 second
its.it_value.tv_sec = 1;
its.it_value.tv_nsec = 0;
its.it_interval.tv_sec = 1;
its.it_interval.tv_nsec = 0;
timer_settime(timerid, 0, &amp;its, NULL);
for (uint32_t i = 0; i &lt; 10; i++)
{
sleep(1);
std::cout &lt;&lt; i &lt;&lt; std::endl;
}
struct itimerspec curr_value;
timer_gettime(timerid, &amp;curr_value);
std::cout &lt;&lt; &quot;Time: &quot; &lt;&lt; curr_value.it_value.tv_sec &lt;&lt; &quot;.&quot; &lt;&lt; curr_value.it_value.tv_nsec &lt;&lt; std::endl;
its = {{0, 0}, {0, 0}};
timer_settime(timerid, 0, &amp;its, NULL);
timer_delete(timerid);
sigaction(SIGRTMIN, NULL, NULL);
return 0;
}

答案1

得分: 0

Sure, here are the translated parts:

  1. "the sigevent field sigev_value.sival_ptr is set to point to the address of the pointer from which a signal should be created when it expires:" -> "sigevent字段的sigev_value.sival_ptr被设置为指向指针的地址,该指针将在计时器到期时创建信号:"

  2. "That's an awkward way to phrase it. How about 'the member is set to point to the location of the timer ID.'" -> "这种表达方式有点别扭。如何说成'该成员被设置为指向计时器ID的位置'。"

  3. "If I'm not mistaken, putting that value there has no effect, as the pointer to the timer is already provided as an argument of the timer_create function." -> "如果我没有错,将该值放在那里没有效果,因为计时器的指针已经作为timer_create函数的参数提供。"

  4. "Why is it written in this way? Is it because of the way the signal handler is registered?" -> "为什么要这样写?是因为信号处理程序的注册方式吗?"

  5. "I also don't understand why sa_sigaction is used to point to the signal handling function. Since we don't initialize the siginfo_t struct to convey more information about the signal, shouldn't we use the sa_handler member instead?" -> "我也不明白为什么要使用sa_sigaction来指向信号处理函数。既然我们没有初始化siginfo_t结构来传递有关信号的更多信息,那么我们应该使用sa_handler成员,不是吗?"

  6. "I tried to run the example by not setting the sigev_value.sival_ptr and using sa_handler instead, and it worked without any issue, even though I thought it wouldn't." -> "我尝试运行示例,没有设置sigev_value.sival_ptr,而是使用sa_handler,它运行得很顺利,尽管我以为会出问题。"

英文:

> the sigevent field sigev_value.sival_ptr is set to point to the address of the pointer from which a signal should be created when it expires:

That's an awkward way to phrase it. How about "the member is set to point to the location of the timer ID."

> If I'm not mistaken, putting that value there has no effect, as the pointer to the timer is already provided as an argument of the timer_create function.

If you mean that timer_create() does not use that value directly or rely on it being set, then yes, you are correct.

Or if you say that in the context that the example code also sets

>
&gt; sev.sigev_notify = SIGEV_SIGNAL;
&gt;

then I would also say that for notification by signal, nothing takes any notice of the value set in the sigev_value.

> Why is it written in this way? Is it because of the way the signal handler is registered ?

No particular technical reason. The field is relevant for notification by callback, however, so if there is an accompanying example of that, then perhaps the object was to minimize the differences between the two examples.

> I also don't understand why sa_sigaction is use to point to the signal handling function. Since we don't initialize the siginfo_t struct to convey more information about the signal, shouldn't we use the sa_handler member instead?

I have no idea what you mean by "we don't initialize the siginfo_t struct". Such initialization is not the responsibility of the application. You choose between two options for the signature of the signal handler function. You set the appropriate flag and use either sa_handler or sa_sigaction, depending on which signature you chose. If the latter, the system provides an appropriate siginfo_t * for each signal.

> I tried to run the example by not setting the sigev_value.sival_ptr and using sa_handler instead, and it worked without any issue, even though I thought it wouldn't.

You have specified a signal handler function with the appropriate signature for sa_handler. sigev_value is not relevant to notification by signal. I have not reviewed your full example code, but those details look fine to me.

huangapple
  • 本文由 发表于 2023年5月10日 23:46:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76220399.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定