It does help, the crash disappeared.
BR Justin
On 08/28/2016 02:31 PM, Nadav Har'El wrote:
Hi Justin, I hate this patch, but can you please check if it fixes
your crash-during-exit problem that you reported yesterday?
--
Nadav Har'El
[email protected] <mailto:[email protected]>
On Sun, Aug 28, 2016 at 3:29 PM, Nadav Har'El <[email protected]
<mailto:[email protected]>> wrote:
The change to osv::run() (and friends) to reuse the calling thread
rather
than start a new one to run a new shared-object introduced a new
problem:
The new shared object may use pthread_key_create() to add
destructors to
run when closing threads. There is (currently) a global list of these
destructors and once added they never get removed (even if the
object is
unloaded). The danger is that osv::run() runs code which adds such a
destructors and allocates data (with pthread_setspecific()) and
then the
program is unloaded - but the thread will only exit (and the
destructors
run) later - and crash when trying to run the destructor pointing to
already-deleted code.
Previously we didn't have this problem, because osv::run() had a
new thread,
which exited (and ran the destructors) *before* the reference
counter on
the application dropped to 0 and the shared object was unloaded.
A hacky workaround added in this patch is to run in
application::start_and_join - used by osv::run,
application::run_and_join
and osv_execve - a new function which runs all these destructors. This
assumes the thread starting these run functions did not have any
thread-
specific data (it would be deleted too!). It's a hack, but should
be good
enough for use cases like osv_execve() which anyway uses a fresh
thread
for running the application.
Signed-off-by: Nadav Har'El <[email protected]
<mailto:[email protected]>>
---
libc/pthread.hh | 4 ++++
core/app.cc | 9 +++++++++
libc/pthread.cc | 38 ++++++++++++++++++++++++++------------
3 files changed, 39 insertions(+), 12 deletions(-)
diff --git a/libc/pthread.hh b/libc/pthread.hh
index 53e9db9..1a4d02c 100644
--- a/libc/pthread.hh
+++ b/libc/pthread.hh
@@ -20,6 +20,10 @@ extern "C" {
#ifdef __cplusplus
}
+
+namespace pthread_private {
+void run_tsd_dtors();
+}
#endif
#endif /* PTHREAD_HH_ */
diff --git a/core/app.cc b/core/app.cc
index 56fd18b..ad3145f 100644
--- a/core/app.cc
+++ b/core/app.cc
@@ -17,6 +17,7 @@
#include <algorithm>
#include <boost/range/algorithm/transform.hpp>
#include <osv/wait_record.hh>
+#include "libc/pthread.hh"
using namespace boost::range;
@@ -251,6 +252,14 @@ void application::start_and_join(waiter*
setup_waiter)
}
_thread = pthread_self(); // may be null if the caller is not
a pthread.
main();
+ // FIXME: run_tsd_dtors() is a hack - If the new program
registered a
+ // destructor via pthread_key_create() and this thread keeps
living with
+ // data for this key, the destructor function, part of the
new program,
+ // may be called after the program is unloaded - and crash.
Let's run
+ // the destructors now. This is wrong if the calling program
has its own
+ // thread-local data. It is fine if the thread was created
specially for
+ // running start_and_join (or run_and_join() or osv::run()).
+ pthread_private::run_tsd_dtors();
sched::thread::current()->set_name(original_name);
sched::thread::current()->set_app_runtime(original_app);
original_app.reset();
diff --git a/libc/pthread.cc b/libc/pthread.cc
index ac7b3f0..62db224 100644
--- a/libc/pthread.cc
+++ b/libc/pthread.cc
@@ -41,27 +41,41 @@ namespace pthread_private {
__thread pthread_t current_pthread;
__thread int cancel_state = PTHREAD_CANCEL_ENABLE;
+ // NOTE: currently, the list of keys and destructor for each
is global,
+ // not per shared object or ELF namespace. So if a shared
object uses
+ // pthread_key_create() but doesn't call pthread_key_delete()
before
+ // exiting, the key will be leaked. This is relatively
harmless (beyond
+ // running out of keys) unless the shared object is unloaded
before the
+ // thread exits and the destructors are run.
+ // As a *hack* you can call run_tsd_dtors() before unloading
the object,
+ // but this will run all dtors, not just those belonging to
the unloaded
+ // object, so this is only useful on a thread especially
created for
+ // running the object.
__attribute__ ((init_priority ((int)init_prio::pthread)))
mutex tsd_key_mutex;
__attribute__ ((init_priority ((int)init_prio::pthread)))
std::vector<bool>
tsd_used_keys(tsd_nkeys);
__attribute__ ((init_priority ((int)init_prio::pthread)))
std::vector<void (*)(void*)> tsd_dtor(tsd_nkeys);
+ void run_tsd_dtors() {
+ bool done = false;
+ for (unsigned iter = 0; !done && iter <
PTHREAD_DESTRUCTOR_ITERATIONS; ++iter) {
+ done = true;
+ for (unsigned i = 0; i < tsd_nkeys; ++i) {
+ if (tsd[i] && tsd_dtor[i]) {
+ void *val = tsd[i];
+ tsd[i] = nullptr;
+ tsd_dtor[i](val);
+ done = false;
+ }
+ }
+ }
+ }
+
void __attribute__((constructor))
pthread_register_tsd_dtor_notifier()
{
sched::thread::register_exit_notifier([] {
- bool done = false;
- for (unsigned iter = 0; !done && iter <
PTHREAD_DESTRUCTOR_ITERATIONS; ++iter) {
- done = true;
- for (unsigned i = 0; i < tsd_nkeys; ++i) {
- if (tsd[i] && tsd_dtor[i]) {
- void *val = tsd[i];
- tsd[i] = nullptr;
- tsd_dtor[i](val);
- done = false;
- }
- }
- }
+ run_tsd_dtors();
});
}
--
2.7.4
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.