forked from nodejs/node-v0.x-archive
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnode_atomic.h
More file actions
129 lines (98 loc) · 2.46 KB
/
Copy pathnode_atomic.h
File metadata and controls
129 lines (98 loc) · 2.46 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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#ifndef NODE_ATOMIC_H_
#define NODE_ATOMIC_H_
#include "atomic_ops.h"
#include "node_internals.h"
#include "uv.h" // kind of annoying, ngx_queue_t is exposed by uv.h
namespace node {
template <class T>
class AtomicValue {
public:
AtomicValue(): value_(0) {
}
AtomicValue(T value): value_((AO_t) value) {
BUILD_BUG_ON(sizeof(value) > sizeof(value_));
}
T Get() {
return (T) AO_load_read(&value_);
}
T Swap(T value) {
AO_t old_value, new_value;
new_value = (AO_t) value;
do
old_value = value_;
while (!AO_compare_and_swap_full(&value_, old_value, new_value));
return (T) old_value;
}
private:
DISALLOW_COPY_AND_ASSIGN(AtomicValue);
AO_t value_;
};
class Mutex {
public:
Mutex(): mutex_(&mutex_storage_) {
if (uv_mutex_init(&mutex_storage_)) abort();
}
~Mutex() {
// Acquire and release the mutex before destroying it
// to make sure it's not in use by another thread.
uv_mutex_t* mutex = mutex_.Swap(NULL);
uv_mutex_lock(mutex);
uv_mutex_unlock(mutex);
uv_mutex_destroy(mutex);
}
class ScopedLock {
public:
ScopedLock(Mutex& mutex): parent_(mutex) {
uv_mutex_lock(parent_.mutex_.Get());
}
~ScopedLock() {
uv_mutex_unlock(parent_.mutex_.Get());
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedLock);
Mutex& parent_;
};
private:
DISALLOW_COPY_AND_ASSIGN(Mutex);
AtomicValue<uv_mutex_t*> mutex_;
uv_mutex_t mutex_storage_;
};
typedef ngx_queue_t AtomicQueueEntry;
template <class T>
class AtomicQueue {
public:
AtomicQueue() {
ngx_queue_init(&queue_);
}
void Insert(T* item) {
Mutex::ScopedLock scoped_lock(mutex_);
ngx_queue_t* q = GetEntry(item);
ngx_queue_insert_head(&queue_, q);
}
void Remove(T* item) {
Mutex::ScopedLock scoped_lock(mutex_);
ngx_queue_t* q = GetEntry(item);
ngx_queue_remove(q);
}
T* Pop() {
Mutex::ScopedLock scoped_lock(mutex_);
if (ngx_queue_empty(&queue_))
return NULL;
ngx_queue_t* q = ngx_queue_head(&queue_);
ngx_queue_remove(q);
return GetItem(q);
}
private:
ngx_queue_t queue_;
Mutex mutex_;
ngx_queue_t* GetEntry(T* item) {
char* addr = reinterpret_cast<char*>(item) + offset_of(T, queue_entry_);
return reinterpret_cast<ngx_queue_t*>(addr);
}
T* GetItem(ngx_queue_t* q) {
// gcc doesn't like that ngx_queue_data() uses a NULL offset
return container_of(q, T, queue_entry_);
}
};
} // namespace node
#endif // NODE_ATOMIC_H_