Defining Custom Signal

Is it possible to send a custom signal to a process?

e.g. Send signal 9999 to my process, which handles it with some custom handler.

How would one do this?

SIGUSR1 and SIGUSR2 and "custom" signals. Nothing else but your code will raise or send those signals to your app.

SIGHUP is traditionally used to cause a daemon to close the logfiles it has open, and reread the initfile, if there is one.

Is it possible to have more than 2 user-defined signals?

You might check out the "real time" signals, whose numbers are defined as a range from SIGRTMIN to SIGRTMAX. Not all systems support them however. POSIX compliant ones should, but OSX for one does not last time I checked... Also, the first three realtime signals (SIGRTMIN+0, ..., SIGRTMIN+2) are reserved on some versions of Linux.

OK, I have decided to just send SIGUSR1 and read instructions from a file.

However, once receiving SIGUSR1, I can no longer send SIGINT to stop the process. It breaks out of my sleep or pause call, but it doesn't stop execution. I have to create a special handler for SIGINT in order for it to work. However, SIGSEGV stops the process as usual. But this worries me - am I doing something wrong, and are there any other signals which will need special attention?

We can't read your code from here unless you post it. I wonder if there are problems with your signal mask.

Here is the code:

#include <Python.h>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

#define MAX_STR_LEN 255

void catch_int(int sig_num);
void catch_usr1(int sig_num);
void write_run_file();
void run_action(char *line);
void run_script_function(char *fname, char *func);

int main(int argc, char *argv[]) {

  signal(SIGUSR1, catch_usr1);
  /*signal(SIGINT, catch_int);*/

  write_run_file();

  Py_SetProgramName(argv[0]);
  Py_Initialize();

  while(1) {
    printf("Still Alive!\n");
    sleep(1);
  }

  Py_Finalize();

  return 0;

}

void write_run_file() {

  FILE *fh;

  fh = fopen("test.RUN", "w");
  if(fh == NULL) {
    printf("Could not open .RUN file.\n");
    exit(1);
  }

  fprintf(fh, "%i", getpid());

  fclose(fh);

}

void catch_int(int sig_num) {

  exit(1);

}

void catch_usr1(int sig_num) {

  FILE *fh;
  char line[MAX_STR_LEN];

  sigset_t mask_set, old_set;

  /* reset for next time */
  signal(SIGUSR1, catch_usr1);

  /* mask any further signals */
  sigfillset(&mask_set);
  sigprocmask(SIG_SETMASK, &mask_set, &old_set);

  printf("Caught SIGUSR1\n");

  fh = fopen("action", "r");
  if(fh == NULL) {
    printf("Could not open file.\n");
    return;
  }
  
  while(fgets(line, MAX_STR_LEN, fh)) {
    printf("Running %s\n", line);
    run_action(line);
    printf("Finished action\n");
    fflush(stdout);
    fflush(stderr);
  }

  fclose(fh);

  /* restore old signal mask */
  sigprocmask(SIG_SETMASK, &old_set, NULL);

}

void run_action(char *line) {

  char *action, *fname, *func;
  char py_fun[] = "PYFUN";

  action = strtok(line, " ");

  if(strlen(action) == 0) {
    return;
  }

  if(strcmp(action, py_fun) == 0) {
    fname = strtok(NULL, " ");
    func = strtok(NULL, " ");
    run_script_function(fname, func);
  }

}

void run_script_function(char *fname, char *func) {

  FILE *fh;
  char call[MAX_STR_LEN];

  fh = fopen(fname, "r");
  if(fh == NULL) {
    printf("Could not open file %s\n", fname);
    exit(1);
  }

  PyRun_SimpleFile(fh, fname);

  fclose(fh);

  strcpy(call, func);
  strcat(call, "()");

  PyRun_SimpleString(call);

}

It actually happens both before and after receiving the first SIGUSR1. It also happens both with and without the mask.

You should not use old-style signal() handling together with sigprocmask(); the latter is part of a new set of functions that eclipse signal() entirely. sigaction() is the modern equivalent. It can be told to keep receiving a signal instead of needing to be reset every time. You shouldn't need to change the signal mask, I think, unless you need to block a signal, it should let them through by default.

I have removed the mask and switched to sigaction. The SIGINT problem still exists.

If I send SIGINT, then send SIGUSR1 and start using Python, it interrupts the Python instead of the C (even if I wait several seconds between sending SIGINT and SIGUSR1).

? Interrupts the pyton?

What command are you using to send the signal to the process? That it should kill the wrong one is quite bizzare.

I'm using the kill function (man 2 kill). I wrote a C function to grab the PID from test.RUN, write the action file, and send SIGUSR1. I call this from a separate Python process.

The Python interpreter is embedded in my executable. Maybe Python defines it's own signal handler for SIGINT (so it can print the traceback, etc.). But that would mean the signal is just sitting around until I call the Python interpreter.

Python definitely screws with signals to the bone for various purposes, one of which is to make sure signals are caught between opcodes instead of during them. It'd be better to have the signal handling done in python if you're going to use it.

But I only use Python for a small part of my program. I need SIGINT to work when I'm in the C part of my code also.