Visit Our UNIX and Linux User Community


Signalsafe data structures


 
Thread Tools Search this Thread
Top Forums Programming Signalsafe data structures
# 1  
Old 12-06-2011
Signalsafe data structures

Hello,

I have a signal handler which manipulates a data structure. The data structure's operations aren't atomic. So if two threads/processes are in a critical section at the same time the data structure will be broken.

With threads you can avoid this stuff with semaphores etc.
However, signal handlers work a bit different than threads. If a signal handler is currently manipulating the data structure and during this the signal handler is called again, then the following happens:

It cannot access the data structure because the first signal handler has it locked, which results in a deadlock.

How can I avoid it but still manipulate my data structure? I cannot lose signals either.
# 2  
Old 12-07-2011
The general way to deal with this is: don't. In your signal handler, do as little work as possible - i.e. set/increment a flag to let your program know the signal has been caught, and do the work from the main body of the code.

In the case of incrementing a flag, you might want to have a look at __sync_fetch_and_add() and such in the gcc documentation - do a search for "gcc atomic builtins".
# 3  
Old 12-07-2011
Ok, but I need to safe an integer value retrieved by the signal handler. Can I do that?
(If multiple signals come in I have to safe multiple integer values)
# 4  
Old 12-07-2011
Working on it. It's harder than it sounds to guarantee order AND guarantee safety.

---------- Post updated at 11:18 AM ---------- Previous update was at 11:09 AM ----------

How about this:

Code:
#define SIGBUF_SIZE 1024

struct
{
        unsigned int rdpos, wrpos;
        int buffer[SIGBUF_SIZE];
} sigbuf={ 0, 0 };

int put_value(int val)
{
        unsigned int wrpos=__sync_fetch_and_add(&sigbuf.wrpos, 1);
        unsigned int rdpos=__sync_fetch_and_add(&sigbuf.rdpos, 0);
        // Compare this way, to prevent integer wraparound problems!
        unsigned int off=(wrpos-rdpos);

        if(off >= SIGBUF_SIZE)
        {
                __sync_fetch_and_sub(&sigbuf.wrpos, 1);
                return(-1);
        }

        sigbuf.buffer[wrpos % SIGBUF_SIZE]=val;
        return(0);
}

int get_value(void)
{
        unsigned int wrpos=__sync_fetch_and_add(&sigbuf.wrpos, 0);
        // Do NOT add here!  If a signal happens, it may see a 'free'
        // element even though there's not.  Only add once we're sure
        // there's anything to read.
        unsigned int rdpos=__sync_fetch_and_add(&sigbuf.rdpos, 0);
        unsigned int off=(wrpos-rdpos);

        if(off == 0)    // Empty buffer
                return(-1);

        return(sigbuf.buffer[__sync_fetch_and_add(&sigbuf.rdpos, 1)%SIGBUF_SIZE]);
}

basically, rdpos and wrpos get incremented without limit, and % SIGBUF_SIZE is used to wrap their values to inside the array. We do 'unsigned int off=(wrpos-rdpos)' instead of just comparing rdpos and wrpos because, if it hits integer wraparound, rdpos might be near INT_MAX while rdpos is practically zero. Subtracting gets rid of the wraparound.


You shouldn't call get_value in a signal handler, but put_value ought to be safe.
# 5  
Old 12-15-2011
As others said, you should be very wary of doing work in a signal handler. There is a short list of async-signal safe functions. If you're calling anything outside that list, there is already potential for breakage even disregarding that caused by potential data structure corruption.

I would do as recommended, restructure your code to capture the signal and relay it outside the signal handler to be handled by the main thread of execution. You can use, for example, a pipe to put a byte on signaling something has been caught; since write is safe you can call it.

Even the pthread_mutex_lock is async-signal unsafe. Outside of rolling your own async-signal safe locks using atomic variables, I can't suggest anything else. Not to mention that even if you properly protect the data structure, you're still limited in what you can do to it by the lack of safe functions you can call.
# 6  
Old 12-22-2011
Locking the list is not an option.

If the list is locked and another signal comes in while the list is locked, the 2nd signal handler will go into a deadlock, because the 1st signal handler waits till the 2nd one finishes, hence the list is never freed.

So writing my caught signal info into a pipe works? How much data can a pipe hold? And how do I know how much I have to read from the pipe when n signal handlers wrote something into it?

/edit:
I just realized that write() doesn't work either, because it can be interrupted before writing something, in which case it throws an error.

Last edited by littlegnome; 12-22-2011 at 09:40 AM..
# 7  
Old 12-22-2011
Is the code I wrote at your request, weeks ago, somehow insufficient or broken?

Previous Thread | Next Thread
Test Your Knowledge in Computers #574
Difficulty: Medium
The process of allocating and deallocating memory is generally referred to as memory swapping.
True or False?

3 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

Perl Data Structures

Here is what i need to do. @data #has all column wise data so say info for col 1 location for all rows would be in this array $array = \@data But i need to create a file which should contain these information in a format for all columns even if i have got no values from some of the index... (0 Replies)
Discussion started by: dinjo_jo
0 Replies

2. Programming

shared memory - userdefined data structures

Hello, I wonder if I can write my userdefined data structures(ex: a list) to a shared memory segment? I know, the shm functions get (void*) parameter so I should be able to read and write a list into the shared memory. may someone inform and clarify me about that, please? (1 Reply)
Discussion started by: xyzt
1 Replies

3. Programming

Recommendations For Generic C Data Structures & Algorithms

Hi All, Rather than re-invent the wheel, I am trying to find a mature C library that provides generic support for lists, trees, etc. I understand C doesn't formally support "generics", but am aware of a few solutions like GLib and SGLib. Can anyone kindly recommend what they think is best?... (1 Reply)
Discussion started by: tristan12
1 Replies

Featured Tech Videos