Live data from Hacker News

Why isn't memset() async-signal-safe?

boston.conman.org

91–98 of 98 posts

Re: Why isn't memset() async-signal-safe?

#91

Earlier quoted context omitted.

OK there we go, then. A compiler that conforms to the ABI generates code which clears the flag, if necessary. Interrupts preserve the flag. Thus, the flag should not be surprisingly set on entry into memcpy. If so, there is a bug.

> A compiler that conforms to the ABI generates code which clears the flag, if necessary. I'm sorry, I do not follow. The conforming compiler expects that the functions are called with the clear flag. The non-conforming kernel on the other hand does not clear the flag before calling the signal handler which breaks it.

But that's obviously a bug. ABI says, caller clears flag. Ergo, all situations that trigger function calls shall clear flag.

Re: Why isn't memset() async-signal-safe?

#92

Earlier quoted context omitted.

For trapping memory accesses, either something like userfaultfd, or otherwise handling segfaults via a signalfd from another thread with its own independent stack. (I'd also eliminate limitations about using a signalfd only within the same process that would have received the signals.) Or, if you just need a "dirty page" bit, add a dedicated mechanism for that, which can use hardware features to run much faster witho…

>signalfd from another thread with its own independent stack. This has similar reentrancy issues to signals.

How so? The other thread would handle the signal from a well-defined point (reading the signalfd), and the thread that faulted would stop at the point of the fault until the thread processing the signal let it continue.

Re: Why isn't memset() async-signal-safe?

#93

Earlier quoted context omitted.

>signalfd from another thread with its own independent stack. This has similar reentrancy issues to signals.

How so? The other thread would handle the signal from a well-defined point (reading the signalfd), and the thread that faulted would stop at the point of the fault until the thread processing the signal let it continue.

What if the stopped thread was holding a mutex? The thread handling the signalfd can only safely call async signal safe functions, exactly like a signal handler.

edit: technically of course full reentrancy (implied by async signal safety) is not strictly required, "only" a fully non-blocking implementation of every function called by the signalfd thread.

Re: Why isn't memset() async-signal-safe?

#94
post #22

It isn't POSIX, but Linux does have the very useful signalfd, which creates a file descriptor that accepts signals. This is a good solution for some types of programs.

But as pointed in this old HN story it is useless in this case. https://news.ycombinator.com/item?id=9564975

It is an easy solution to the problem discussed above though. Yeah, all the mechanics of setting up your signals still are a PITA, but at least you don't have to worry about async-safe functions anymore.

Really all signalfd does is provide an easy way to handle signals in an epoll driven application. If you have a different kind of main loop, then you are probably back to stuffing messages into queues, or dealing with all of the async-safe BS.

Re: Why isn't memset() async-signal-safe?

#95

Earlier quoted context omitted.

How so? The other thread would handle the signal from a well-defined point (reading the signalfd), and the thread that faulted would stop at the point of the fault until the thread processing the signal let it continue.

What if the stopped thread was holding a mutex? The thread handling the signalfd can only safely call async signal safe functions, exactly like a signal handler. edit: technically of course full reentrancy (implied by async signal safety) is not strictly required, "only" a fully non-blocking implementation of every function called by the signalfd thread.

Ah, I see your concern. Right, if you called a function that took locks and then faulted, the thread handling the fault can't attempt to take the same locks. That should result in far fewer restrictions than "async-signal-safe", though.

Re: Why isn't memset() async-signal-safe?

#96

Earlier quoted context omitted.

What if the stopped thread was holding a mutex? The thread handling the signalfd can only safely call async signal safe functions, exactly like a signal handler. edit: technically of course full reentrancy (implied by async signal safety) is not strictly required, "only" a fully non-blocking implementation of every function called by the signalfd thread.

Ah, I see your concern. Right, if you called a function that took locks and then faulted, the thread handling the fault can't attempt to take the same locks. That should result in far fewer restrictions than "async-signal-safe", though.

You do not know which lock it was holding though; when handling a segfault for example you need to be pessimistic and assume that you can't touch any lock (think of the allocator lock for example).

Async signal safety implies both reentrancy and non blocking algorithms [1]. You might not need reentrancy but you do need non-blocking. That's really a significant restriction as libraries with non-blocking guarantees are rare.

Re: Why isn't memset() async-signal-safe?

#97

Earlier quoted context omitted.

Ah, I see your concern. Right, if you called a function that took locks and then faulted, the thread handling the fault can't attempt to take the same locks. That should result in far fewer restrictions than "async-signal-safe", though.

You do not know which lock it was holding though; when handling a segfault for example you need to be pessimistic and assume that you can't touch any lock (think of the allocator lock for example). Async signal safety implies both reentrancy and non blocking algorithms [1]. You might not need reentrancy but you do need non-blocking. That's really a significant restriction as libraries with non-blocking guarantees are…

Depending on the nature of your segfault handler, you could either make sure you have any data structures you need already allocated, or allocate out of a separate arena. Or, alternatively, handle the signal in another process entirely.

Re: Why isn't memset() async-signal-safe?

#98

Earlier quoted context omitted.

You do not know which lock it was holding though; when handling a segfault for example you need to be pessimistic and assume that you can't touch any lock (think of the allocator lock for example). Async signal safety implies both reentrancy and non blocking algorithms [1]. You might not need reentrancy but you do need non-blocking. That's really a significant restriction as libraries with non-blocking guarantees are…

Depending on the nature of your segfault handler, you could either make sure you have any data structures you need already allocated, or allocate out of a separate arena. Or, alternatively, handle the signal in another process entirely.

I.e. it is safe as long as you follow the same rules you would use in a normal signal handler :).

Out of process handling is a robust solution though.

Post reply on HN