Repository navigation
Expand file tree
/
Copy pathSpinlock.cpp
More file actions
76 lines (64 loc) · 2.41 KB
/
Copy pathSpinlock.cpp
File metadata and controls
76 lines (64 loc) · 2.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
74
75
76
#include "SceTypes.hpp"
#include "Common.hpp"
#include <atomic>
#include <new>
#include <stdexcept>
#include <thread>
struct PthreadSpinlockPrivate {
std::atomic<std::thread::id> owner{};
};
namespace {
constexpr int GUEST_EPERM = 1;
constexpr int GUEST_ENOMEM = 12;
constexpr int GUEST_EBUSY = 16;
constexpr int PROCESS_PRIVATE = 0;
constexpr int PROCESS_SHARED = 1;
constexpr int SPIN_COUNT = 100000;
bool tryAcquire(PthreadSpinlockPrivate* spinlock) {
std::thread::id unowned{};
return spinlock->owner.compare_exchange_strong(unowned, std::this_thread::get_id(), std::memory_order_acquire, std::memory_order_relaxed);
}
}
extern "C" {
int APS5_VABI pthread_spin_init_nid_postfix(PthreadSpinlockPrivate** lock, int pshared) {
if (!lock) return PosixThread::GUEST_EINVAL;
if (pshared != PROCESS_PRIVATE && pshared != PROCESS_SHARED) return PosixThread::GUEST_EINVAL;
auto* spinlock = new (std::nothrow) PthreadSpinlockPrivate;
if (!spinlock) return GUEST_ENOMEM;
*lock = spinlock;
return 0;
}
int APS5_VABI pthread_spin_destroy_nid_postfix(PthreadSpinlockPrivate** lock) {
if (!lock || !*lock) return PosixThread::GUEST_EINVAL;
delete *lock;
*lock = nullptr;
return 0;
}
int APS5_VABI pthread_spin_trylock_nid_postfix(PthreadSpinlockPrivate** lock) {
if (!lock || !*lock) return PosixThread::GUEST_EINVAL;
return tryAcquire(*lock) ? 0 : GUEST_EBUSY;
}
int APS5_VABI pthread_spin_lock_nid_postfix(PthreadSpinlockPrivate** lock) {
if (!lock || !*lock) return PosixThread::GUEST_EINVAL;
auto* spinlock = *lock;
if (spinlock->owner.load(std::memory_order_relaxed) == std::this_thread::get_id())
throw std::runtime_error("pthread_spin_lock: the calling thread already holds the lock and would spin forever");
int count = SPIN_COUNT;
while (!tryAcquire(spinlock)) {
while (spinlock->owner.load(std::memory_order_relaxed) != std::thread::id{}) {
if (--count <= 0) {
count = SPIN_COUNT;
std::this_thread::yield();
}
}
}
return 0;
}
int APS5_VABI pthread_spin_unlock_nid_postfix(PthreadSpinlockPrivate** lock) {
if (!lock || !*lock) return PosixThread::GUEST_EINVAL;
auto owner = std::this_thread::get_id();
if (!(*lock)->owner.compare_exchange_strong(owner, std::thread::id{}, std::memory_order_release, std::memory_order_relaxed))
return GUEST_EPERM;
return 0;
}
}