Properly ending a daemon written in C: Difference between revisions

From Try-AS/400
Jump to navigation Jump to search
(New)
 
(→‎Blocking Calls: Completing the sentence)
 
Line 41: Line 41:
If the application program is "stuck" in kind of a wait condition, it depends on the wait condition if the blocking call is cancelled, allowing the application code to take control again.
If the application program is "stuck" in kind of a wait condition, it depends on the wait condition if the blocking call is cancelled, allowing the application code to take control again.


This code snippet shows an example how to restart  
This code snippet shows an example how to restart an interrupted recv() from a socket by restarting the <code>while</code> loop.


  /* Main loop. */
  /* Main loop. */
Line 60: Line 60:
  }
  }


Some OS' automatically restart the last operation if it became interrupted by a signal. OS/400 V4R5 does not, so we restart in a loop, making this example a generic restart function, if <code>EINTR</code> is given as error reason.
<blockquote>'''Note''': Some OS' automatically restart the last operation if it became interrupted by a signal. OS/400 V4R5 does not, so we restart in a loop, making this example a generic restart function, if <code>EINTR</code> is given as error reason.


[[Category: Programming]]
[[Category: Programming]]

Latest revision as of 15:34, 13 August 2022

Properly ending a daemon, or background task can be done in multiple ways. Since we're using C as programming language, using the UNIX way of handling this affair proved to be most easy.

OS/400 incorporates quite a bit of UNIX APIs, including signals. If you use option 4 on wrkactjob, or end the subsystem the job in question is running within, SIGTERM is being sent to tell the application program to cleanly end.

Using the signal API

In short, declare the necessary infrastructure for a signal, and make it do something.

#include <string.h>
#include <signal.h>
#include <stdlib.h>

/* Using this globally eases handling. */
int exit_flag = 0;

void set_exit_flag(int signum) {
  /* We ignore signum, because we only watch for SIGTERM. */
  exit_flag = 1;
}

int main() {
  struct sigaction termaction;

  /* Create signal handler for SIGTERM. */
  memset(&termaction, 0, sizeof(struct sigaction));
  termaction.sa_handler = set_exit_flag;
  sigaction(SIGTERM, &termaction, NULL);

  /* Main loop. */
  while( exit_flag == 0 ) {
    ...
  }

  /* Add cleanup routines here. */

  exit(0);
}

In our case, we set exit_flag to 1, so the program exits from its main loop at the next iteration.

Blocking Calls

If the application program is "stuck" in kind of a wait condition, it depends on the wait condition if the blocking call is cancelled, allowing the application code to take control again.

This code snippet shows an example how to restart an interrupted recv() from a socket by restarting the while loop.

/* Main loop. */
while( exit_flag == 0 ) {

  /* Handle incoming network data. */
  if ( (n = recv(sockfd, rcvBuf, BUFSIZE, 0)) == -1) {
    if ( errno == EINTR ) {
      continue;
    } else {
      /* Some other error happened. Handle next request. */
      Qp0zLprintf("recv(): %s\n", strerror(errno));
      break;
    }
  }

/* Do things with the received data. */
}

Note: Some OS' automatically restart the last operation if it became interrupted by a signal. OS/400 V4R5 does not, so we restart in a loop, making this example a generic restart function, if EINTR is given as error reason.