0

I'm programming on Unix in C.

I have 3 critical zones:

Mutex1 -> Lock
{
{ ZONE1
{
Mutex1 -> unLock

Mutex2 -> Lock
{
{ ZONE2
{
Mutex2 -> unLock

Mutex3 -> Lock
{
{ ZONE3
{
Mutex3 -> unLock

For each zone, there is a mutex. N processes execute this code, so mutexes are required to manage the critical areas. My problem is:

SIGINT is handled in this way -> signal(SIGINT, handler);

void handler(int sign)
{
    exit(0);
}

If one process gets a signal (example ctrl+c) in a single critical area I need to unlock the mutex just taking into account where the process was when it received the signal (zone 1, zone 2, or zone 3).

What can I do to do this?

ABC
  • 71
  • 9
  • Set a variable that indicates which critical zone you're about to enter, and unlock the relevant mutex. Of necessity, that would be a global variable. However, when your process exits, the mutex should be unlocked — unless perhaps the type of mutex you're using isn't a POSIX [`pthread_mutex_init()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html) type. You've not specified how you've implemented your mutexes. You can have System V IPC undo the semaphore operations that a process does when it exits. – Jonathan Leffler Oct 20 '19 at 14:36
  • I thought about it but it doesn't make much sense. Assigning a variable is not atomic. – ABC Oct 20 '19 at 14:42
  • But you're only in one zone at a time, aren't you, so when you switch into a zone, if you set the variable before, you will at worst try to unlock a mutex that you don't have locked, which should fail. You set the 'which zone' variable back to 'none' immediately after you unlock the mutex. – Jonathan Leffler Oct 20 '19 at 14:43
  • If I unlock mutex ( so i do a semop) on handler in this case I have a big problem – ABC Oct 20 '19 at 14:46
  • OK; then you might need to show your implementation of mutexes, or you might need to clarify what you're planning to do instead of `exit(0);` (which probably isn't a good exit status — it means 'success' — for when your process stops because of an interrupt). Or I might need to stop trying to help since it appears I don't understand what your circumstances are. Signal handling is iffy — handling signals for coordinating across processes is harder. Have you considered using a multi-threaded implementation instead of a multi-processing one? – Jonathan Leffler Oct 20 '19 at 14:59
  • You should probably review [What is the difference between `sigaction()` and `signal()`?](https://stackoverflow.com/questions/231912/what-is-the-difference-between-sigaction-and-signal) and you should probably use `sigaction()` rather than `signal()` to set your signal handling. – Jonathan Leffler Oct 20 '19 at 15:05
  • I don't know if your system supports [`posix_mutexattr_getpshared()`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_setpshared.html) — if it does, it might help you use 'real' mutexes, rather than simulating them with semaphores. – Jonathan Leffler Oct 20 '19 at 15:14
  • `exit(0);` is not async-signal-safe so it can't safely be called from a signal handler. Among other problems, it can deadlock when it flushes all `FILE *` buffers if any one of those buffers is locked when the signal is received. So it's worse than just your mutex problem – Andrew Henle Oct 20 '19 at 16:08

1 Answers1

0

One option is to block signals around your critical sections with sigprocmask(). That way you can restrict signal response to the non-critical areas.

If you need signals to affect your critical sections, then you could have a communication with the signal handler à la:

volatile sigstate;

void handler(int signo) {
    if (sigstate & 1) {
          sigdefcount++;
    } else {
          _exit(1);
    }
}

Note that it is not safe to call exit() from a signal handler; it must be _exit(). With this, the code in your critical sections should set the sigstate flag, and periodically check the count. This quickly becomes complicated, since many system calls default to quietly restarting if interrupted, and you may need blocking interfaces with timeouts so you can check this indicator.

In most cases it is better to simplify your critical sections to have predictable execution times and disable signals within them. This might involve splitting some critical sections into subsections, which might be a more lucid design if a bit more work.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
mevets
  • 10,070
  • 1
  • 21
  • 33
  • It was the only solution that came to my mind. Doesn't another exist? – ABC Oct 20 '19 at 14:47
  • Not readily, but if your processes follow a dispatch-like pattern, with select as the basic wait for event mechanism, pselect permits a signal mask to make this sort of pattern more efficient. – mevets Oct 21 '19 at 00:28