Newer
Older
* Copyright (C) 2013-2014 Cloudius Systems, Ltd.
*
* This work is open source software, licensed under the terms of the
* BSD license as described in the LICENSE file in the top-level directory.
*/
#include <boost/format.hpp>
#include <osv/mutex.h>
#include <osv/waitqueue.hh>
#include <stdarg.h>
#include <time.h>
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// We don't expect applications to use the Linux futex() system call (it is
// normally only used to implement higher-level synchronization mechanisms),
// but unfortunately gcc's C++ runtime uses a subset of futex in the
// __cxa__guard_* functions, which safeguard the concurrent initialization
// of function-scope static objects. We only implement here this subset.
// The __cxa_guard_* functions only call futex in the rare case of contention,
// in fact so rarely that OSv existed for a year before anyone noticed futex
// was missing. So the performance of this implementation is not critical.
static std::unordered_map<void*, waitqueue> queues;
static mutex queues_mutex;
enum {
FUTEX_WAIT = 0,
FUTEX_WAKE = 1,
};
int futex(int *uaddr, int op, int val, const struct timespec *timeout,
int *uaddr2, int val3)
{
switch (op) {
case FUTEX_WAIT:
assert(timeout == 0);
WITH_LOCK(queues_mutex) {
if (*uaddr == val) {
waitqueue &q = queues[uaddr];
q.wait(queues_mutex);
}
}
return 0;
case FUTEX_WAKE:
assert(val == INT_MAX);
WITH_LOCK(queues_mutex) {
auto i = queues.find(uaddr);
if (i != queues.end()) {
i->second.wake_all(queues_mutex);
queues.erase(i);
}
}
// FIXME: We are expected to return a count of woken threads, but
// wake_all doesn't have this feature, and the only user we care
// about, __cxa_guard_*, doesn't need this return value anyway.
return 0;
default:
abort("Unimplemented futex() operation %d\n", op);
}
}
long syscall(long number, ...)
{
switch (number) {
case __NR_gettid: return gettid();
case __NR_clock_gettime: {
va_list args;
clockid_t arg1;
struct timespec *arg2;
va_start(args, number);
arg1 = va_arg(args, typeof(arg1));
arg2 = va_arg(args, typeof(arg2));
va_end(args);
return clock_gettime(arg1, arg2);
}
case __NR_clock_getres: {
va_list args;
clockid_t arg1;
struct timespec *arg2;
va_start(args, number);
arg1 = va_arg(args, typeof(arg1));
arg2 = va_arg(args, typeof(arg2));
va_end(args);
return clock_getres(arg1, arg2);
}
case __NR_futex: {
va_list args;
int *arg1;
int arg2;
int arg3;
const struct timespec *arg4;
int *arg5;
int arg6;
va_start(args, number);
arg1 = va_arg(args, typeof(arg1));
arg2 = va_arg(args, typeof(arg2));
arg3 = va_arg(args, typeof(arg3));
arg4 = va_arg(args, typeof(arg4));
arg5 = va_arg(args, typeof(arg5));
arg6 = va_arg(args, typeof(arg6));
va_end(args);
return futex(arg1, arg2, arg3, arg4, arg5, arg6);
}
abort("syscall(): unimplemented system call %d. Aborting.\n", number);