I was given a project in my CSSE class that has to do with signals and handlers. After spending the last 48 hours stressing and cursing the lack of proper information (that I could find) on the Internet to help me understand, I decided to turn here once more.

THe problem I am having is I am supposed to write a signal handler that, when SIGALRM send sa signal, interupts the a process called mygets, which apparently functions like fgets,but if it receives any signal while running, it will return -1 and set errno to EINTR.

mygets is inside a function tgets (code will follow). I am supposed to write the handler to modify the code to return somthing different (namely 0 if SIGALRM is what caused the interupt, and -1 if somthing else does, or an error occurs.)
I am also required to use mygets and a function set_alarm_handler that sets the alarm handler, and cannot use anything else to read or set the handler. I am allowed to "use a global variable to help you determine whether the signal that woke mygets up is really SIGALRM." and must use SIGALRM as well

My attempt, as well as the code for the set_alarm_handler and tgets follows.

/**
 * Lab08 Solution File
 * @author <your name here>
 * @author <your name here>
 */
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

/* The type for signal handler functions
 * You can use this. */
typedef void (*sighandler_t)(int);
pid_t pid;
ssize_t timerstatus = 1;


/*****************************************************************************\
*******************************************************************************
**  Timer Puzzle
*******************************************************************************
\*****************************************************************************/
/**
 *  This function reads a line from stdin, waiting indefinitely until a newline
 *  character is encountered.
 *  You are expected to call this to actually read a line from stdin
 *
 *  @param buf Buffer to hold the line
 *
 *  @param buf_size Size of the buffer
 *
 *
 *  @return -1 if interrupted by a signal or if there is an error
 *          otherwise the number of characters read, including the newline
 *          character (if present), but excluding the null-terminator.
 *
 *  @remarks  This function will read everything from STDIN until the newline
 *            character is encountered.
 *            The buffer will contain the newline character 
 *            and null-terminator.
 *            However, if there is insufficient space, then 
 *            the buffer will store a truncated version of the line read,
 *            and the newline character will *not* be present.
 *            However, in any case, the buffer will still be null-terminated.
 *                   
 *  */
ssize_t mygets(char* buf, int buf_size);

/**
 * Use this to set the alarm signal handler.
 * @param alarm_handler  Address of the Signal handler for SIGALRM
 * @return SIG_ERR on error; otherwise the address of the previous handler
 */
sighandler_t
set_alarm_handler(sighandler_t alarm_handler)
{
    struct sigaction action, old_action;

    action.sa_handler = alarm_handler;  
    sigemptyset(&action.sa_mask); /* block sigs of type being handled */
    
    /* Make sure you do not specify SA_RESTART,
    SA_RESTART will cause IO functions to be restarted when
    they are interrupted by signals. */
    action.sa_flags = 0;  

    if (sigaction(SIGALRM, &action, &old_action) < 0)
    {
        return SIG_ERR;
    }
    
    return old_action.sa_handler;
}

/**
 * Reads a line from STDIN within a timeout period.
 *
 * @param buf Pointer to buffer to hold the line read from STDIN,
 *        including the newline character.
 *
 * @param buf_size Size of the buffer, including the space for holding the
 *        newline and null-terminator character. If there is insufficient 
 *        space, then buffer will store a truncated version of the line. 
 *        In whatever case, buffer must be null-terminated.
 *
 * @param timeout_secs Number of seconds before timing out;
 *        Can be zero if no timeout is desired, in which case this
 *        function should wait indefinitely  for a line of input.
 *
 * @return -1 if interrupted by a signal or if there is an error.
 *         Number of characters read (including the newline char if present
 *            but excluding the null-terminator) if a line is read 
 *             before timing out.
 *         0 if timeout happened before finishing reading a line.
 *
 *  @remarks Note that reading a line means read everything from STDIN until
 *           the newline character is encountered. 
 *           So if 'timeout_secs' seconds has passed *before* a newline char is
 *           encountered, then this function must return 0.
 *           If a newline char is encountered within 'timeout_secs' seconds,
 *           then this function must return the number of characters read. 
 *
 *           IMPORTANT!!!: This function should restore the original alarm 
 *           signal handler before returning!
 *
 * */
void timer_handler(int signum){

  if (signum == SIGALRM){
   
    timerstatus = 0;
    return 0;
    raise(signum);
    raise(signum);
  }else{
    timerstatus = -1;
    return -1;
}

  return 1;

}

ssize_t
tgets(char* buf, int buf_size, int timeout_secs)
{
    ssize_t num_read = 0;
    
    /* TODO: set up your alarm handler here */
    sighandler_t old = set_alarm_handler(timer_handler);
   
    /* Use this to read a line */
    num_read = mygets(buf, buf_size); //this is the only line that i did not write
  
    /* TODO: restore alarm handler */
    set_alarm_handler(old); 
    
    /* TODO: check the return value of mygets */
    if (num_read == -1){
      return timerstatus ;}
  
    /* TODO: change the return value  */
    
    return num_read;
}

Any guidance or example handler's of this kind you could provide would be greatly apprieciated.

As of now, the program I am to use to test the program simply tells me that it has failed, so I am unsure of what the error is. If you need more info on what is required, ask, but I think I included everything.

Recommended Answers

All 2 Replies

The tgets function has a timeout_secs argument, which you never use. You have to request a SIGALRM to be raised at that timeout. Read a man page for alarm().

The if/else in the signal handler is meaningless: the handler is installed specifically for SIGALRM, so the signum will never be anything else. It means BTW, that timerstatus, once set to 0, will stay 0 forever. You should set it to -1 in the mainline rignt before invoking alarm().

Lines 117 and 118 make no sense.

PS: don't forget to cancel an alarm when done, otherwise you'd get a funny race condition.

Oh, I see. So, I have to set the alarm. I for some reason thought mygets did that on its own. I tried the changes you suggested, and it works just fine now! I realised that I didn't have to terminate the process, because the signal does it anyway.

EDIT:
How rude of me! I forgot to thank you! Thank you for the help!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.