The react game – code view

Some key functionality aspects are shown as follows; first is the code that sets up the signal handler for SIGRTMIN and creates the POSIX interval (ch13/react.c):

For readability, only key parts of the source code are displayed in the following; to view the complete source code, build it, and run it, the entire tree is available for cloning from GitHub, here: https://github.com/PacktPublishing/Hands-on-System-Programming-with-Linux.
static int init(void)
{
struct sigevent sev;
struct rlimit rlim;
struct sigaction act;

// Trap SIGRTMIN : delivered on (interval) timer expiry
memset(&act, 0, sizeof(act));
act.sa_flags = SA_SIGINFO | SA_RESTART;
act.sa_sigaction = timer_handler;
if (sigaction(SIGRTMIN, &act, NULL) == -1)
FATAL("sigaction SIGRTMIN failed ");

[...]

/* Create and init the timer */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGRTMIN;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1)
FATAL("timer_create failed ");

printf("Initializing timer to generate SIGRTMIN every %ld ms ",
freq_ms);
memset(&itv, 0, sizeof(struct itimerspec));
itv.it_value.tv_sec = (freq_ms * 1000000) / 1000000000;
itv.it_value.tv_nsec = (freq_ms * 1000000) % 1000000000;
itv.it_interval.tv_sec = (freq_ms * 1000000) / 1000000000;
itv.it_interval.tv_nsec = (freq_ms * 1000000) % 1000000000;
[...]

The surprise start is implemented as follows:

/* random_start
* The element of surprise: fire off an 'alarm' - resulting in SIGALRM being
* delivered to us - in a random number between [min..max] seconds.
*/
static void random_start(int min, int max)
{
unsigned int nr;

alarm(0);
srandom(time(0));
nr = (random() % max) + min;

#define CHEAT_MODE 0
#if (CHEAT_MODE == 1)
printf("Ok Cheater :-) get ready; press ^C in %ds ... ", nr);
#endif
alarm(nr);
}

It's invoked as follows:

#define MIN_START_SEC 1
#define MAX_START_SEC 5
[...]
random_start(MIN_START_SEC, MAX_START_SEC);

The signal handler (the function startoff) and associated logic for the alarm (for SIGALRM) is as follows:

static void arm_timer(timer_t tmrid, struct itimerspec *itmspec)
{
VPRINT("Arming timer now ");
if (timer_settime(tmrid, 0, itmspec, NULL) == -1)
FATAL("timer_settime failed ");
jumped_the_gun = 0;
}

/*
* startoff
* The signal handler for SIGALRM; arrival here implies the app has
* "started" - we shall arm the interval timer here, it will start
* running immediately. Take a timestamp now.
*/
static void startoff(int sig)
{
char press_msg[] = " *** QUICK! Press ^C !!! *** ";

arm_timer(timerid, &itv);
write(STDERR_FILENO, press_msg, strlen(press_msg));

//—- timestamp it: start time
if (clock_gettime(CLOCK_REALTIME, &tm_start) < 0)
FATAL("clock_gettime (tm_start) failed ");
}

Remember, while the user is lolling around, our POSIX interval timer continues to set and reset itself at the frequency specified by the user (as the first parameter passed, which we save in the variable freq_ms); so, every freq_ms milliseconds, our process will receive the signal SIGRTMIN. Here's its signal handler routine:

static volatile sig_atomic_t gTimerRepeats = 0, c = 0, first_time = 1,
jumped_the_gun = 1;
[...]
static void timer_handler(int sig, siginfo_t * si, void *uc)

{
char buf[] = ".";

c++;
if (verbose) {
write(2, buf, 1);
#define SHOW_OVERRUN 1
#if (SHOW_OVERRUN == 1)
{
int ovrun = timer_getoverrun(timerid);
if (ovrun == -1)
WARN("timer_getoverrun");
else {
if (ovrun)
printf(" overrun=%d [@count=%d] ", ovrun, c);
}
}
#endif
}
}

When the user does (finally!) press ^C, the signal handler for SIGINT (the function userpress) is invoked:

static void userpress(int sig)
{
struct timespec res;

// timestamp it: end time
if (clock_gettime(CLOCK_REALTIME, &tm_end) < 0)
FATAL("clock_gettime (tm_end) failed ");

[...]
printf(" *** PRESSED *** ");
/* Calculate the delta; subtracting one struct timespec
* from another takes a little work. A retrofit ver of
* the 'timerspecsub' macro has been incorporated into
* our ../common.h header to do this.
*/
timerspecsub(&tm_end, &tm_start, &res);
printf
(" Your reaction time is precisely %ld.%ld s.ns"
" [~= %3.0f ms, count=%d] ",
res.tv_sec, res.tv_nsec,
res.tv_sec * 1000 +
round((double)res.tv_nsec / 1000000), c);
}
[...]
c = 0;
if (!gTimerRepeats)
exit(EXIT_SUCCESS);
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset