« Close

Datasheets and User Guides

App Notes

Software & Driver

 

5.1 - Does LJM handle signals?

Does LJM handle signals?

LJM catches all terminal signals, by default, in order to clean up LabJack device connections. LJM's signal handlers do the following:

  • Ends all device streaming and close all device connections
  • Optionally log which signal was received at LJM_FATAL priority
  • Essentially exit the processes by setting the signal handler to default and re-raising the signal

LJM attempts to set the signal handlers upon the first call to LJM that attempts communication. (LJM_CloseAll is a quick way to force LJM to initialize the signal handlers.)

On Windows, signals are handled using signal. The signals that are handled are:

  • SIGINT
  • SIGILL
  • SIGABRT
  • SIGFPE
  • SIGSEGV
  • SIGTERM

On Linux/Mac, LJM uses the oldact parameter of sigaction to determine if there was previously a signal handler; if oldact is not NULL for a given signal, LJM will reset oldact as the signal handler and not handle that signal. The default signals that are handled are:

  • SIGHUP
  • SIGINT
  • SIGQUIT
  • SIGILL
  • SIGABRT
  • SIGFPE
  • SIGBUS
  • SIGSEGV
  • SIGTERM
  • SIGTSTP
  • SIGPIPE

Custom Cleanup: If your application needs to clean up resources, you can call LJM's signal handler from your own signal handler. To do this, force LJM to initialize signal handlers by calling LJM_CloseAll, then call sigaction to set your handler, and finally set the previous signal handler to be called in your handler. A Linux/Mac C++ example to catch Ctrl-C follows (signal may be used in the same way on Windows):

...
#include <signal.h>
#include <errno.h>

static volatile void (*ljm_handler)(int) = NULL;

void my_handler(int sig)
{
	// printf may not be re-entrant: because of this, it typically should not be
	// used in a signal handler. It is used here for ease of exposition.
	printf("my_handler is handling signal: %d\n", sig);

	// Perform custom cleanup behavior here
	...

	if (ljm_handler != NULL) {
		printf("Calling ljm_handler from my_handler...\n");
		ljm_handler(sig);
	}
	exit(-1);
}

int main()
{
	// Initialize the LJM signal handler by "attempting" device communication
	// using LJM_CloseAll - we can ignore the return value. Other functions,
	// such as LJM_Open or LJM_ListAll work as well.
	LJM_CloseAll();

	struct sigaction act, oldact;
	act.sa_handler = my_handler;
	act.sa_flags = 0;
	int error = sigaction(SIGINT, &act, &oldact);
	if (error) {
		printf("There was an error during sigaction: %d\n", errno);
		exit(errno);
	}

	printf("oldact.sa_handler: %p\n", oldact.sa_handler);
	ljm_handler = (volatile void (*)(int))oldact.sa_handler;

	...
}

Note that sigprocmask can be used to block signals while you are calling sigaction. Also note that other signal behaviors can be implemented using sigaction. See the man-pages for sigaction and sigprocmask for more details.