-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
Copy pathcoroutine_lock.cc
129 lines (109 loc) Β· 3.36 KB
/
coroutine_lock.cc
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
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| [email protected] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: NathanFreeman <[email protected]> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
#ifdef HAVE_IOURING_FUTEX
#include "swoole_iouring.h"
#else
#include "swoole_coroutine_system.h"
using swoole::coroutine::System;
#endif
#include "swoole_lock.h"
namespace swoole {
CoroutineLock::CoroutineLock(bool shared) : Lock() {
type_ = COROUTINE_LOCK;
shared_ = shared;
if (shared) {
value = (sw_atomic_t *) sw_mem_pool()->alloc(sizeof(sw_atomic_t));
} else {
value = new sw_atomic_t;
}
*value = 0;
}
CoroutineLock::~CoroutineLock() {
if (shared_) {
sw_mem_pool()->free((void *) value);
} else {
delete value;
}
value = nullptr;
}
int CoroutineLock::lock() {
return lock_impl(true);
}
int CoroutineLock::trylock() {
return lock_impl(false);
}
int CoroutineLock::lock_rd() {
return lock_impl(true);
}
int CoroutineLock::trylock_rd() {
return lock_impl(false);
}
int CoroutineLock::unlock() {
Coroutine *current_coroutine = Coroutine::get_current();
if (current_coroutine == nullptr) {
swoole_warning("The coroutine lock can only be used in a coroutine environment");
return SW_ERROR_CO_OUT_OF_COROUTINE;
}
if (*value == 0) {
return 0;
}
*value = 0;
cid = 0;
coroutine = nullptr;
#ifdef HAVE_IOURING_FUTEX
return Iouring::futex_wakeup((uint32_t *) value) >= 0 ? 0 : errno;
#else
return 0;
#endif
}
int CoroutineLock::lock_impl(bool blocking) {
Coroutine *current_coroutine = Coroutine::get_current();
if (current_coroutine == nullptr) {
swoole_warning("The coroutine lock can only be used in a coroutine environment");
return SW_ERROR_CO_OUT_OF_COROUTINE;
}
if (current_coroutine == static_cast<Coroutine *>(coroutine) && current_coroutine->get_cid() == cid) {
return 0;
}
int result = 0;
#ifndef HAVE_IOURING_FUTEX
double second = 0.001;
#endif
while (true) {
if (sw_atomic_cmp_set(value, 0, 1)) {
break;
}
if (!blocking) {
return EBUSY;
}
#ifdef HAVE_IOURING_FUTEX
result = Iouring::futex_wait((uint32_t *) value);
if (result != 0) {
return errno;
}
#else
if (System::sleep(second) != SW_OK) {
return SW_ERROR_CO_CANCELED;
}
second *= 2;
#endif
}
cid = current_coroutine->get_cid();
coroutine = (void *) current_coroutine;
return result;
}
} // namespace swoole