Tags: 75b52e27, article, comgt, global, gmail, google, linux, lt86732ca3, posting, programming, ramesh, sekhar, todaysummary, unix, unix-linux, variables

Global Variables

On Programmer » Unix & Linux

3,618 words with 0 Comments; publish: Wed, 30 Apr 2008 09:49:00 GMT; (20078.13, « »)

In article <86732ca3.0410200848.75b52e27.unix-linux.todaysummary.com.posting.google.com>,

ramesh.sekhar.unix-linux.todaysummary.com.gmail.com (siddhartha) wrote:

> Jonathan Adams <jwadams.unix-linux.todaysummary.com.gmail.com> wrote in message

> news:<jwadams-15D071.03585920102004.unix-linux.todaysummary.com.news1nwk.sfbay.sun.com>...

> Hi Jonathan,

> I'm a relative newbie to signals - could you clarify your last

> statement with an example?

(added comp.unix.programmer, and set Followup-To:, since this is all

outside of the C standard, and POSIX has the most to say about it)

The problem with signals is that they interrupt the program at an

uncertain point in the text -- you could be in the middle of (say)

updating the malloc() bookkeeping information. If you are, then

calling any function which can invoke malloc() from the signal handler

would almost certainly hopelessly mess up the malloc() heap, causing

random data corruption.

In a multithreaded process, you're likely to just deadlock, since there

will be a lock protecting the malloc state which you are already holding.

Practically, this severely restricts what you can do in a signal handler.

Without further precautions[1], you can only safely:

1. assign a value to a (possibly volatile) sig_atomic_t variable.

2. mess with local state on the stack

3. call async-signal-safe functions. These are functions which

are "reentrant" (basically, those which do not manipulate any

kind of global state -- strcmp() and strlen() are good

examples, as are most system calls, since the kernel can

guarantee safety)

Typical "bad ideas" one sees in signal handlers are:

1. calling printf(), fprintf(), or any other stdio function

which acts on a FILE *, directly or indirectly.

(fputs(), puts(), etc.)

2. calling anything which might call malloc().

(sprintf()/snprintf() are insidious examples, because

many implementation of them can call malloc() unexpectedly.)

You also see people calling fork()+exec() in signal handlers, which is

not *precisely* unsafe, but a bit ill-advised.[2] Many gnome

applications do this, in order to pop up "I got a bad signal, what

should I do?" windows.

The simple fact is that signal handlers are very hard to write correctly

once you get beyond simple cases. (and even simple cases introduce

issues like EINTR and SA_RESTART, which can have program-wide effects)

Throw multi-threaded programming into the mix, and now you have *two*

subtly incompatible asynchronous mechanisms, which is why most robust MT

programs block all asynchronous signals in all threads, and have a

dedicated thread in sigwaitinfo(3thr) or sigtimedwait(3thr) handling all

signals.

To get back to your original question, strtok() cannot be made

async-signal-safe because it's interface relies on a piece of global

data. Calling it from a signal handler will smash that data, with no

way to recover the previous state.

fopen() uses malloc(), which is not safe. It also has to maintain the

global list of open files, for fflush(NULL) to find.

Cheers,

- jonathan

[1] For example, you could block the signal whenever you call into any

code which uses the unsafe functions. This can quickly lead to

out-of-hand code complexity, though.

[2] The worst case of this I've ever seen was a daemon which tried to

"save" itself from SIGSEGVs by fork()ing and exec()ing a new copy of

itself. Of course, the signal handler was buggy, and could deadlock...

All Comments

Leave a comment...

  • 0 Comments