Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

signals: switch to app TLS if available #1288

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions arch/x64/tls-switch.hh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ public:
}
}
};
//
//Simple RAII utility classes that implement the logic to switch
//fsbase to the specified app address and back to the kernel one
class user_tls_switch {
thread_control_block *_kernel_tcb;
public:
user_tls_switch() {
asm volatile ( "movq %%gs:16, %0\n\t" : "=r"(_kernel_tcb));

//Switch to app tcb if app tcb present
if (_kernel_tcb->app_tcb) {
set_fsbase(reinterpret_cast<u64>(_kernel_tcb->app_tcb));
}
}

~user_tls_switch() {
//Switch to kernel tcb if app tcb present
if (_kernel_tcb->app_tcb) {
set_fsbase(reinterpret_cast<u64>(_kernel_tcb->self));
}
}
};

}

Expand Down
10 changes: 10 additions & 0 deletions core/sched.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2088,6 +2088,16 @@ void with_thread_by_id(unsigned id, std::function<void(thread *)> f) {
}
}

thread *find_first_app_thread(std::function<bool(thread &)> f) {
WITH_LOCK(thread_map_mutex) {
for (auto th : thread_map) {
if(th.second->is_app() && f(*th.second)) {
return th.second;
}
}
}
return nullptr;
}

}

Expand Down
2 changes: 2 additions & 0 deletions include/osv/sched.hh
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,8 @@ void with_all_threads(std::function<void(sched::thread &)>);
// should return quickly.
void with_thread_by_id(unsigned id, std::function<void(sched::thread *)>);

thread *find_first_app_thread(std::function<bool(thread &)> f);

}

#endif /* SCHED_HH_ */
29 changes: 29 additions & 0 deletions libc/signal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#include <osv/pid.h>
#include <osv/export.h>

#ifdef __x86_64__
#include "tls-switch.hh"
#endif

using namespace osv::clock::literals;

namespace osv {
Expand Down Expand Up @@ -393,6 +397,11 @@ int kill(pid_t pid, int sig)
signal_actions[sigidx].sa_flags = 0;
signal_actions[sigidx].sa_handler = SIG_DFL;
}
#ifdef __x86_64__
//In case this signal handler thread has specified app thread local storage
//let us switch to it before invoking the user handler routine
arch::user_tls_switch tls_switch;
#endif
if (sa.sa_flags & SA_SIGINFO) {
// FIXME: proper second (siginfo) and third (context) arguments (See example in call_signal_handler)
sa.sa_sigaction(sig, nullptr, nullptr);
Expand All @@ -401,6 +410,26 @@ int kill(pid_t pid, int sig)
}
}, sched::thread::attr().detached().stack(65536).name("signal_handler"),
false, true);
//If we are running statically linked executable or a dynamic one with Linux
//dynamic linker, its threads very likely use app thread local storage and signal
//routine may rely on it presence. For that reason we use app TLS of the current
//thread if it has one. Otherwise we find 1st app thread with non-null app TLS
//and assign the signal handler thread app TLS to it so it is switched to (see above).
//TODO: Ideally we should only run the logic below if the current app is statically
//linked executable or a dynamic one ran with Linux dynamic linker
//(what if we are handling "Ctrl-C"?)
u64 app_tcb = sched::thread::current()->get_app_tcb();
if (!app_tcb) {
auto first_app_thread = sched::find_first_app_thread([&](sched::thread &t) {
return t.get_app_tcb();
});
if (first_app_thread) {
app_tcb = first_app_thread->get_app_tcb();
}
}
if (app_tcb) {
t->set_app_tcb(app_tcb);
}
t->start();
}
return 0;
Expand Down