One additional, important note: if you're using "reliable signals" (POSIX sigaction with the corresponding sa_mask field), you get control over how signals behave in a single-thread-single-process situation.
Consider the case of single process P1, with a signal-handler like the one you show above. Suppose that you are catching signal SIGUSR1 and having that enter the function signal_handler. While you are inside signal_handler, some other process P2 sends another SIGUSR1 to P1 (e.g., via kill). This signal is "blocked" (temporarily) via sa_mask until signal_handler returns in P1. This is true even if you don't set any bits in sa_mask (as long as you don't set SA_NODEFER in sa_flags, see below).
But, suppose you've also decided to catch SIGUSR2 with function signal_handler. Suppose that P2 also sends a SIGUSR2. In this case, the SIGUSR2 is (or may be) caught, starting another instance of signal_handler running, this time on behalf of the SIGUSR2 signal.
You can prevent this by making sure that when SIGUSR1 is being handled, SIGUSR2 is temporarily blocked as well. In general you'd probably want to make SIGUSR1 blocked while SIGUSR2 is being handled. To do this, set both corresponding bits in sa_mask:
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_flags = SA_RESTART | SA_SIGINFO; /* (decide for yourself which flags) */
sigaddset(&sa.sa_mask, SIGUSR1);
sigaddset(&sa.sa_mask, SIGUSR2);
sa.sa_sigaction = signal_handler;
error = sigaction(SIGUSR1, &sa, NULL);
if (error) ... handle error ...
error = sigaction(SIGUSR2, &sa, NULL);
if (error) ... handle error ...
The two sigaddset calls make sure that both SIGUSR1 and SIGUSR2 are held-off (blocked, temporarily) for the duration of the function.
If you're only catching one signal, there is no need for this extra complexity, because as long as SA_NODEFER is not set, the OS automatically adds whatever signal triggered entry to your signal handler to the "currently blocked signals" set at entry.
(Note that the OS's automatic blocking and unblocking of signals at entry and exit to your signal handler is done with sigprocmask, using SIG_BLOCK and SIG_SETMASK—not SIG_UNBLOCK—with the mask for the SIG_SETMASK at exit set by saving the previous mask filled in via SIG_BLOCK. Well, it's normally done inside kernel code, rather than actually calling sigprocmask, but the effect is the same, just more efficient.)