Newer
Older
#include "sched.hh"
#include <list>
#include "mutex.hh"
#include <mutex>
#include "debug.hh"
#include "align.hh"
#include "drivers/clock.hh"
std::vector<cpu*> cpus;
thread __thread * s_current;
elf::tls_data tls;
}
#include "arch-switch.hh"
namespace sched {
// FIXME: a proper idle mechanism
while (runqueue.empty()) {
barrier();
auto n = &runqueue.front();
runqueue.pop_front();
return n;
});
assert(!n->_waiting);
n->_on_runqueue = false;
if (n != thread::current()) {
n->switch_to();
}
void cpu::handle_incoming_wakeups()
{
for (unsigned i = 0; i < cpus.size(); ++i) {
incoming_wakeup_queue q;
incoming_wakeups[i].copy_and_clear(q);
while (!q.empty()) {
runqueue.push_back(q.front());
q.pop_front_nonatomic();
}
}
}
void schedule(bool yield)
{
cpu::current()->schedule(yield);
}
auto t = current();
// FIXME: what about other cpus?
if (t->_cpu->runqueue.empty()) {
t->_cpu->runqueue.push_back(*t);
thread::stack_info::stack_info(void* _begin, size_t _size)
: begin(_begin), size(_size)
{
auto end = align_down(begin + size, 16);
size = static_cast<char*>(end) - static_cast<char*>(begin);
}
mutex thread_list_mutex;
typedef bi::list<thread,
bi::member_hook<thread,
bi::list_member_hook<>,
&thread::_thread_list_link>
> thread_list_type;
thread_list_type thread_list;
thread::thread(std::function<void ()> func, stack_info stack, bool main)
, _stack(stack)
with_lock(thread_list_mutex, [this] {
thread_list.push_back(*this);
});
_cpu = current()->tcpu(); // inherit creator's cpu
_cpu->runqueue.push_back(*this);
with_lock(thread_list_mutex, [this] {
thread_list.erase(thread_list.iterator_to(*this));
});
debug("thread dtor");
}
void thread::prepare_wait()
{
_waiting = true;
}
void thread::wake()
{
// prevent two concurrent wakeups
if (!_waiting.exchange(false)) {
return;
}
_cpu->incoming_wakeups[cpu::current()->id].push_front(*this);
// FIXME: IPI
}
void thread::main()
{
_func();
}
thread* thread::current()
{
return sched::s_current;
}
void thread::wait()
{
if (!_waiting) {
return;
}
schedule();
}
void thread::sleep_until(u64 abstime)
{
timer t(*current());
t.set(abstime);
wait_until([&] { return t.expired(); });
}
void thread::stop_wait()
{
_waiting = false;
}
void thread::complete()
{
_waiting = true;
_terminated = true;
if (_joiner) {
_joiner->wake();
}
while (true) {
schedule();
}
}
void thread::join()
{
_joiner = current();
wait_until([this] { return _terminated; });
}
thread::stack_info thread::get_stack_info()
{
return _stack;
timer_list timers;
timer_list::timer_list()
{
clock_event->set_callback(this);
}
void timer_list::fired()
{
auto now = clock::get()->time();
auto i = _list.begin();
while (i != _list.end() && i->_time < now) {
auto j = i++;
j->_expired = true;
j->_t.wake();
_list.erase(j);
}
if (!_list.empty()) {
clock_event->set(_list.begin()->_time);
}
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
}
timer::timer(thread& t)
: _t(t)
, _expired()
{
}
timer::~timer()
{
cancel();
}
void timer::set(u64 time)
{
_time = time;
// FIXME: locking
timers._list.insert(*this);
if (timers._list.iterator_to(*this) == timers._list.begin()) {
clock_event->set(time);
}
};
void timer::cancel()
{
// FIXME: locking
timers._list.erase(*this);
_expired = false;
// even if we remove the first timer, allow it to expire rather than
// reprogramming the timer
}
bool timer::expired() const
{
return _expired;
}
bool operator<(const timer& t1, const timer& t2)
{
if (t1._time < t2._time) {
return true;
} else if (t1._time == t2._time) {
return &t1 < &t2;
} else {
return false;
}
}
void init(elf::tls_data tls_data, std::function<void ()> cont)
thread::stack_info stack { new char[4096*10], 4096*10 };
thread t{cont, stack, true};