... Consequently, to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called. ...
I see in [a source file](https://github.com/znc/znc/blob/b2dcad5fd49e6c0d604de38c311db0e08ed061a7/src/main.cpp#L286) that [async-signal-unsafe functions](https://www.securecoding.cert.org/confluence/display/cplusplus/SIG30-CPP.+Call+only+asynchronous-safe+functions+within+signal+handlers#SIG30-CPP.Callonlyasynchronous-safefunctionswithinsignalhandlers-ImplementationDetails) are used between calls of the functions "fork" and "execvp". Would you like to improve your program design if you consider information like [the following](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)?
```
... Consequently, to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called. ...
```
<!-- github-sync-id:23154489 -->
I find that the issue "async-signal-safety" is independent from the thread count if you care for better software portability, isn't it?
I find that the issue "async-signal-safety" is independent from the thread count if you care for better software portability, isn't it?
<!-- github-comment-id:29098899 -->
@elfring Your quote is from this paragraph from your link:
A process shall be created with a single thread. If a multi-threaded process calls fork(), the new process shall contain a replica of the calling thread and its entire address space, possibly including the states of mutexes and other resources. Consequently, to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called. Fork handlers may be established by means of the pthread_atfork() function in order to maintain application invariants across fork() calls.
This is about multi-threaded process calling fork(). May you elaborate what's wrong with single-threaded process calling fork() and not exec(), please?
@elfring Your quote is from this paragraph from [your link](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html):
> A process shall be created with a single thread. If a multi-threaded process calls fork(), the new process shall contain a replica of the calling thread and its entire address space, possibly including the states of mutexes and other resources. Consequently, to avoid errors, the child process may only execute async-signal-safe operations until such time as one of the exec functions is called. Fork handlers may be established by means of the pthread_atfork() function in order to maintain application invariants across fork() calls.
This is about multi-threaded process calling fork(). May you elaborate what's wrong with single-threaded process calling fork() and not exec(), please?
<!-- github-comment-id:29128427 -->
Do you interpret the shown wording "... If a multi-threaded process calls ..." in the way that it is not specified which behaviour should be expected for the address space in an ordinary single-threaded process?
I find that the POSIX specification contains a limitation about which statements can be executed between calls of the functions "fork" and "execvp" in a portable way. More threads will increase the technical challenges to keep the process memory consistent, won't it?
Does this standard try to point that out by the wording "... including the states of mutexes ..." (and in the section "RATIONALE") here?
Do you interpret the shown wording "... If a multi-threaded process calls ..." in the way that it is not specified which behaviour should be expected for the address space in an ordinary single-threaded process?
I find that the POSIX specification contains a limitation about which statements can be executed between calls of the functions "fork" and "execvp" in a portable way. More threads will increase the technical challenges to keep the process memory consistent, won't it?
Does this standard try to point that out by the wording "... including the states of mutexes ..." (and in the section "RATIONALE") here?
<!-- github-comment-id:29129292 -->
Do you interpret the shown wording "... If a multi-threaded process
calls ..." in the way that it is not specified which behaviour should
be expected for the address space in an ordinary single-threaded process?
No. I interpret this like "the paragraph applies only for multi-threaded
processes".
When fork() is called in a multi-threaded process, at that moment
other threads may be in any state. For example, it could be writing to
some structure, but didn't finish yet. In the child process, all those
threads are simply gone, leaving memory of the child in some
inconsistent state. Memory of the parent is still consistent, because in
the parent those threads are still running and they have a chance to
finish whatever they did.
That's why in a multi-threaded process only safe functions may be called
after fork(). exec() clears memory address space, and starts new
program in this process from scratch, so in the new program everything
is fine again.
This issue is not presented in a single-threaded process, because we
have only 1 thread - the one which calls fork(), and we know what the
thread is doing: it's calling fork() (surprise! ;) ). No other thread
disappears in child leaving memory in some inconsistent state, because
no other thread exists at all.
I find that the POSIX specification contains a limitation about which
statements can be executed between calls of the functions "fork" and
"execvp" in a portable way. More threads will increase the technical
challenges to keep the process memory consistent, won't it?
More threads will create those technical challenges. I don't see any
challenge with one thread.
Does this standard try to point that out by the wording "... including
the states of mutexes ..." (and in the section "RATIONALE") here?
If another thread was accessing the mutex during fork(), the mutex may
be left in an unusable state. This implies that such thread exists. If
no thread does that, there is no problem. And in a single-threaded
program we know that no other thread accesses mutexes or any other memory.
23.11.2013 13:47, Markus Elfring пишет:
> Do you interpret the shown wording "... If a multi-threaded process
> calls ..." in the way that it is not specified which behaviour should
> be expected for the address space in an ordinary single-threaded process?
No. I interpret this like "the paragraph applies only for multi-threaded
processes".
When `fork()` is called in a multi-threaded process, at that moment
other threads may be in any state. For example, it could be writing to
some structure, but didn't finish yet. In the child process, all those
threads are simply gone, leaving memory of the child in some
inconsistent state. Memory of the parent is still consistent, because in
the parent those threads are still running and they have a chance to
finish whatever they did.
That's why in a multi-threaded process only safe functions may be called
after `fork()`. `exec()` clears memory address space, and starts new
program in this process from scratch, so in the new program everything
is fine again.
This issue is not presented in a single-threaded process, because we
have only 1 thread - the one which calls `fork()`, and we know what the
thread is doing: it's calling `fork()` (surprise! ;) ). No other thread
disappears in child leaving memory in some inconsistent state, because
no other thread exists at all.
> I find that the POSIX specification contains a limitation about which
> statements can be executed between calls of the functions "fork" and
> "execvp" in a portable way. More threads will increase the technical
> challenges to keep the process memory consistent, won't it?
More threads will _create_ those technical challenges. I don't see any
challenge with one thread.
> Does this standard try to point that out by the wording "... including
> the states of mutexes ..." (and in the section "RATIONALE") here?
If another thread was accessing the mutex during `fork()`, the mutex may
be left in an unusable state. This implies that such thread exists. If
no thread does that, there is no problem. And in a single-threaded
program we know that no other thread accesses mutexes or any other memory.
<!-- github-comment-id:29130326 -->
This issue might become more interesting if you would like to add another thread for the signal handler fix. ;-)
This issue might become more interesting if you would like to add another thread for [the signal handler fix](https://github.com/znc/znc/issues/434). ;-)
<!-- github-comment-id:29131029 -->
Also, what exactly are we arguing about? The file access through CFile should be safe (open, write, close, fcntl are in the list). That only leaves fprintf() and fflush() to worry about. So the fix would be to bypass the I/O library and use write() directly to output these messages and everyone is happy?
Wait, what? Threads for signal-handling?!?
Also, what exactly are we arguing about? The file access through CFile should be safe (open, write, close, fcntl are in the list). That only leaves fprintf() and fflush() to worry about. So the fix would be to bypass the I/O library and use write() directly to output these messages and everyone is happy?
<!-- github-comment-id:29131202 -->
Oh, wait. Nothing can sanely create threads at that point anyway. The parent process is going to exit() soon and the child process survives. So anything creating threads here is already broken and agree with DarthGandalf that I can't think of any realistic problems.
Oh, wait. Nothing can sanely create threads at that point anyway. The parent process is going to exit() soon and the child process survives. So anything creating threads here is already broken and agree with DarthGandalf that I can't think of any realistic problems.
<!-- github-comment-id:29131259 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
I see in a source file that async-signal-unsafe functions are used between calls of the functions "fork" and "execvp". Would you like to improve your program design if you consider information like the following?
There is only 1 thread at that point...
I find that the issue "async-signal-safety" is independent from the thread count if you care for better software portability, isn't it?
@elfring Your quote is from this paragraph from your link:
This is about multi-threaded process calling fork(). May you elaborate what's wrong with single-threaded process calling fork() and not exec(), please?
Do you interpret the shown wording "... If a multi-threaded process calls ..." in the way that it is not specified which behaviour should be expected for the address space in an ordinary single-threaded process?
I find that the POSIX specification contains a limitation about which statements can be executed between calls of the functions "fork" and "execvp" in a portable way. More threads will increase the technical challenges to keep the process memory consistent, won't it?
Does this standard try to point that out by the wording "... including the states of mutexes ..." (and in the section "RATIONALE") here?
23.11.2013 13:47, Markus Elfring пишет:
No. I interpret this like "the paragraph applies only for multi-threaded
processes".
When
fork()is called in a multi-threaded process, at that momentother threads may be in any state. For example, it could be writing to
some structure, but didn't finish yet. In the child process, all those
threads are simply gone, leaving memory of the child in some
inconsistent state. Memory of the parent is still consistent, because in
the parent those threads are still running and they have a chance to
finish whatever they did.
That's why in a multi-threaded process only safe functions may be called
after
fork().exec()clears memory address space, and starts newprogram in this process from scratch, so in the new program everything
is fine again.
This issue is not presented in a single-threaded process, because we
have only 1 thread - the one which calls
fork(), and we know what thethread is doing: it's calling
fork()(surprise! ;) ). No other threaddisappears in child leaving memory in some inconsistent state, because
no other thread exists at all.
More threads will create those technical challenges. I don't see any
challenge with one thread.
If another thread was accessing the mutex during
fork(), the mutex maybe left in an unusable state. This implies that such thread exists. If
no thread does that, there is no problem. And in a single-threaded
program we know that no other thread accesses mutexes or any other memory.
This issue might become more interesting if you would like to add another thread for the signal handler fix. ;-)
How it is even related?..
Wait, what? Threads for signal-handling?!?
Also, what exactly are we arguing about? The file access through CFile should be safe (open, write, close, fcntl are in the list). That only leaves fprintf() and fflush() to worry about. So the fix would be to bypass the I/O library and use write() directly to output these messages and everyone is happy?
Oh, wait. Nothing can sanely create threads at that point anyway. The parent process is going to exit() soon and the child process survives. So anything creating threads here is already broken and agree with DarthGandalf that I can't think of any realistic problems.
Should the function "_exit" be eventually called instead of "exit" from the single-threaded child process?
Why?