0

I'm creating a very simple program execution timer in C. I'll provide sample code below. The problem is that the fflush(NULL) doesn't flush every "Hello World\n" from the stdout when ending a program with Ctrl+C (i.e. SIGINT signal). They still appear sometimes after the Estimated running time... message and I wonder why.

Timer.c

#include <signal.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>

#define _TIMER
#include "timer.h"

static clock_t startTime;

int installTimer(void)
{
    errno = 0;
    if (signal(SIGINT, signalHandler) == SIG_ERR ||
        signal(SIGTERM, signalHandler) == SIG_ERR ||
        signal(SIGABRT, signalHandler) == SIG_ERR)
        return 1;
    if (atexit(displayTimer))
        return 1;
    if ((startTime = clock()) == -1)
        return 1;
    return 0;
}

static void displayTimer()
{
    clock_t endTime;
    if ((endTime = clock()) == -1)
        printf("ERROR: clock() failed.\n");
    else
        printf("Estimated running time: %.4fs\n", (endTime - startTime) / (double) CLOCKS_PER_SEC);
}

static void signalHandler(int signal)
{
    fflush(NULL);
    exit(EXIT_FAILURE);
}

Timer.h:

int installTimer(void);

#ifdef _TIMER
   static void displayTimer(void);
   static void signalHandler(int);
#endif

timerTest.c

#include <stdio.h>
#include "timer.h"

int main(void)
{
    if (installTimer())
    {
        printf("ERROR: installTimer() failed.\n");
        return 1;
    }
    int i;
    for (i = 0; i < 300000; ++i)
        printf("Hello World!\n");
    return 0;
}
Jori
  • 1,122
  • 2
  • 18
  • 36

1 Answers1

3

Your program invokes undefined behavior. You can't call fflush() inside signal handlers. It is generally a bad idea to call IO library functions inside signal handlers.

Strictly conforming programs can only call the C standard library functions abort(), _Exit(), quick_exit(), and signal() from within a signal handler.

In other words, fflush() is not asynchronous-safe, so please don't try to do this.

For further details, see this question: I need a list of Async-Signal-Safe Functions from glibc

That question points to a link with possible workarounds.

Community
  • 1
  • 1
Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • Thanks, but do you have a list of async-signal-safe functions for Windows too? – Jori Jan 11 '14 at 17:53
  • Also if I understand it correctly, there is no way of printing the estimated time message at the end of the program since `fflush()` isn't async-signal-safe (although I could replace `printf` with `write` if that is safe on Windows). – Jori Jan 11 '14 at 17:56
  • Hum, I'm going to be honest here: for Windows, I have no idea. You could install a Windows POSIX implementation and then use the POSIX list for asynchronous-safe functions. Otherwise, I suggest reading the specific documentation. I don't usually develop for Windows, so I'm really out of that world. As for your second question, yeah, you will have to do it with a safe call like `write`. – Filipe Gonçalves Jan 11 '14 at 21:11