Skip to content

Commit ce934b8

Browse files
authored
Added Thread\Barrier (#5380)
* refactor thread barrier * Added Swoole\Thread\Barrier * remove test code * Add protection code
1 parent 565b560 commit ce934b8

15 files changed

+305
-53
lines changed

ext-src/php_swoole.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,7 @@ PHP_MINIT_FUNCTION(swoole) {
766766
php_swoole_thread_minit(module_number);
767767
php_swoole_thread_atomic_minit(module_number);
768768
php_swoole_thread_lock_minit(module_number);
769+
php_swoole_thread_barrier_minit(module_number);
769770
php_swoole_thread_queue_minit(module_number);
770771
php_swoole_thread_map_minit(module_number);
771772
php_swoole_thread_arraylist_minit(module_number);

ext-src/php_swoole_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ void php_swoole_name_resolver_minit(int module_number);
271271
void php_swoole_thread_minit(int module_number);
272272
void php_swoole_thread_atomic_minit(int module_number);
273273
void php_swoole_thread_lock_minit(int module_number);
274+
void php_swoole_thread_barrier_minit(int module_number);
274275
void php_swoole_thread_queue_minit(int module_number);
275276
void php_swoole_thread_map_minit(int module_number);
276277
void php_swoole_thread_arraylist_minit(int module_number);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
namespace Swoole\Thread {
3+
class Barrier {
4+
public function __construct(int $count) {}
5+
public function wait(): void {}
6+
public function __wakeup(): void {}
7+
}
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* This is a generated file, edit the .stub.php file instead.
2+
* Stub hash: eac62993bfb3fbd87587a8e6997c16bca7dc5dbc */
3+
4+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Swoole_Thread_Barrier___construct, 0, 0, 1)
5+
ZEND_ARG_TYPE_INFO(0, count, IS_LONG, 0)
6+
ZEND_END_ARG_INFO()
7+
8+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Thread_Barrier_wait, 0, 0, IS_VOID, 0)
9+
ZEND_END_ARG_INFO()
10+
11+
#define arginfo_class_Swoole_Thread_Barrier___wakeup arginfo_class_Swoole_Thread_Barrier_wait

ext-src/swoole_thread_atomic.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,15 @@ static PHP_METHOD(swoole_thread_atomic, set);
114114
static PHP_METHOD(swoole_thread_atomic, cmpset);
115115
static PHP_METHOD(swoole_thread_atomic, wait);
116116
static PHP_METHOD(swoole_thread_atomic, wakeup);
117-
#ifdef SW_THREAD
118117
static PHP_METHOD(swoole_thread_atomic, __wakeup);
119-
#endif
120118

121119
static PHP_METHOD(swoole_thread_atomic_long, __construct);
122120
static PHP_METHOD(swoole_thread_atomic_long, add);
123121
static PHP_METHOD(swoole_thread_atomic_long, sub);
124122
static PHP_METHOD(swoole_thread_atomic_long, get);
125123
static PHP_METHOD(swoole_thread_atomic_long, set);
126124
static PHP_METHOD(swoole_thread_atomic_long, cmpset);
127-
#ifdef SW_THREAD
128125
static PHP_METHOD(swoole_thread_atomic_long, __wakeup);
129-
#endif
130126
SW_EXTERN_C_END
131127

132128
// clang-format off

ext-src/swoole_thread_barrier.cc

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Swoole |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 2.0 of the Apache license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.apache.org/licenses/LICENSE-2.0.html |
9+
| If you did not receive a copy of the Apache2.0 license and are unable|
10+
| to obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Author: Tianfeng Han <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#include "php_swoole_private.h"
18+
#include "php_swoole_thread.h"
19+
#include "swoole_memory.h"
20+
#include "swoole_lock.h"
21+
22+
#ifdef SW_THREAD
23+
24+
BEGIN_EXTERN_C()
25+
#include "stubs/php_swoole_thread_barrier_arginfo.h"
26+
END_EXTERN_C()
27+
28+
using swoole::Barrier;
29+
30+
static zend_class_entry *swoole_thread_barrier_ce;
31+
static zend_object_handlers swoole_thread_barrier_handlers;
32+
33+
struct BarrierResource : public ThreadResource {
34+
Barrier barrier_;
35+
BarrierResource(int count) : ThreadResource() {
36+
barrier_.init(false, count);
37+
}
38+
void wait() {
39+
barrier_.wait();
40+
}
41+
~BarrierResource() {
42+
barrier_.destroy();
43+
}
44+
};
45+
46+
struct BarrierObject {
47+
BarrierResource *barrier;
48+
zend_object std;
49+
};
50+
51+
static sw_inline BarrierObject *php_swoole_thread_barrier_fetch_object(zend_object *obj) {
52+
return (BarrierObject *) ((char *) obj - swoole_thread_barrier_handlers.offset);
53+
}
54+
55+
static BarrierResource *php_swoole_thread_barrier_get_ptr(zval *zobject) {
56+
return php_swoole_thread_barrier_fetch_object(Z_OBJ_P(zobject))->barrier;
57+
}
58+
59+
static BarrierResource *php_swoole_thread_barrier_get_and_check_ptr(zval *zobject) {
60+
BarrierResource *barrier = php_swoole_thread_barrier_get_ptr(zobject);
61+
if (!barrier) {
62+
php_swoole_fatal_error(E_ERROR, "must call constructor first");
63+
}
64+
return barrier;
65+
}
66+
67+
static void php_swoole_thread_barrier_free_object(zend_object *object) {
68+
BarrierObject *bo = php_swoole_thread_barrier_fetch_object(object);
69+
zend_long resource_id = zend::object_get_long(object, ZEND_STRL("id"));
70+
if (bo->barrier && php_swoole_thread_resource_free(resource_id, bo->barrier)) {
71+
delete bo->barrier;
72+
bo->barrier = nullptr;
73+
}
74+
zend_object_std_dtor(object);
75+
}
76+
77+
static zend_object *php_swoole_thread_barrier_create_object(zend_class_entry *ce) {
78+
BarrierObject *bo = (BarrierObject *) zend_object_alloc(sizeof(BarrierObject), ce);
79+
zend_object_std_init(&bo->std, ce);
80+
object_properties_init(&bo->std, ce);
81+
bo->std.handlers = &swoole_thread_barrier_handlers;
82+
return &bo->std;
83+
}
84+
85+
SW_EXTERN_C_BEGIN
86+
static PHP_METHOD(swoole_thread_barrier, __construct);
87+
static PHP_METHOD(swoole_thread_barrier, wait);
88+
static PHP_METHOD(swoole_thread_barrier, __wakeup);
89+
SW_EXTERN_C_END
90+
91+
// clang-format off
92+
static const zend_function_entry swoole_thread_barrier_methods[] =
93+
{
94+
PHP_ME(swoole_thread_barrier, __construct, arginfo_class_Swoole_Thread_Barrier___construct, ZEND_ACC_PUBLIC)
95+
PHP_ME(swoole_thread_barrier, wait, arginfo_class_Swoole_Thread_Barrier_wait, ZEND_ACC_PUBLIC)
96+
PHP_ME(swoole_thread_barrier, __wakeup, arginfo_class_Swoole_Thread_Barrier___wakeup, ZEND_ACC_PUBLIC)
97+
PHP_FE_END
98+
};
99+
// clang-format on
100+
101+
void php_swoole_thread_barrier_minit(int module_number) {
102+
SW_INIT_CLASS_ENTRY(swoole_thread_barrier, "Swoole\\Thread\\Barrier", nullptr, swoole_thread_barrier_methods);
103+
zend_declare_property_long(swoole_thread_barrier_ce, ZEND_STRL("id"), 0, ZEND_ACC_PUBLIC);
104+
SW_SET_CLASS_CLONEABLE(swoole_thread_barrier, sw_zend_class_clone_deny);
105+
SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_barrier, sw_zend_class_unset_property_deny);
106+
SW_SET_CLASS_CUSTOM_OBJECT(swoole_thread_barrier,
107+
php_swoole_thread_barrier_create_object,
108+
php_swoole_thread_barrier_free_object,
109+
BarrierObject,
110+
std);
111+
}
112+
113+
static PHP_METHOD(swoole_thread_barrier, __construct) {
114+
auto bo = php_swoole_thread_barrier_fetch_object(Z_OBJ_P(ZEND_THIS));
115+
if (bo->barrier != nullptr) {
116+
zend_throw_error(NULL, "Constructor of %s can only be called once", SW_Z_OBJCE_NAME_VAL_P(ZEND_THIS));
117+
RETURN_FALSE;
118+
}
119+
120+
zend_long count;
121+
ZEND_PARSE_PARAMETERS_START(1, 1)
122+
Z_PARAM_LONG(count)
123+
ZEND_PARSE_PARAMETERS_END();
124+
125+
if (count < 2) {
126+
zend_throw_exception(
127+
swoole_exception_ce, "The parameter $count must be greater than 1", SW_ERROR_INVALID_PARAMS);
128+
RETURN_FALSE;
129+
}
130+
131+
bo->barrier = new BarrierResource(count);
132+
auto resource_id = php_swoole_thread_resource_insert(bo->barrier);
133+
zend_update_property_long(swoole_thread_barrier_ce, SW_Z8_OBJ_P(ZEND_THIS), ZEND_STRL("id"), resource_id);
134+
RETURN_TRUE;
135+
}
136+
137+
static PHP_METHOD(swoole_thread_barrier, wait) {
138+
BarrierResource *barrier = php_swoole_thread_barrier_get_and_check_ptr(ZEND_THIS);
139+
if (barrier) {
140+
barrier->wait();
141+
}
142+
}
143+
144+
static PHP_METHOD(swoole_thread_barrier, __wakeup) {
145+
auto bo = php_swoole_thread_barrier_fetch_object(Z_OBJ_P(ZEND_THIS));
146+
zend_long resource_id = zend::object_get_long(ZEND_THIS, ZEND_STRL("id"));
147+
bo->barrier = static_cast<BarrierResource *>(php_swoole_thread_resource_fetch(resource_id));
148+
if (!bo->barrier) {
149+
zend_throw_exception(swoole_exception_ce, EMSG_NO_RESOURCE, ECODE_NO_RESOURCE);
150+
return;
151+
}
152+
}
153+
#endif

ext-src/swoole_thread_lock.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ using swoole::RWLock;
3737
static zend_class_entry *swoole_thread_lock_ce;
3838
static zend_object_handlers swoole_thread_lock_handlers;
3939

40-
#ifdef SW_THREAD
4140
struct LockResource : public ThreadResource {
4241
Lock *lock_;
4342
LockResource(int type) : ThreadResource() {
@@ -62,7 +61,6 @@ struct LockResource : public ThreadResource {
6261
delete lock_;
6362
}
6463
};
65-
#endif
6664

6765
struct LockObject {
6866
LockResource *lock;
@@ -113,9 +111,7 @@ static PHP_METHOD(swoole_thread_lock, lock_read);
113111
static PHP_METHOD(swoole_thread_lock, trylock_read);
114112
static PHP_METHOD(swoole_thread_lock, unlock);
115113
static PHP_METHOD(swoole_thread_lock, destroy);
116-
#ifdef SW_THREAD
117114
static PHP_METHOD(swoole_thread_lock, __wakeup);
118-
#endif
119115
SW_EXTERN_C_END
120116

121117
// clang-format off

include/swoole.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ typedef unsigned long ulong_t;
176176
#define SW_ASSERT(e)
177177
#define SW_ASSERT_1BYTE(v)
178178
#endif
179-
#define SW_START_SLEEP usleep(100000) // sleep 1s,wait fork and pthread_create
179+
#define SW_START_SLEEP usleep(100000) // sleep 0.1s, wait fork and pthread_create
180180

181181
#ifdef SW_THREAD
182182
#define SW_THREAD_LOCAL thread_local

include/swoole_lock.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,23 @@ class SpinLock : public Lock {
105105
int trylock() override;
106106
};
107107
#endif
108+
109+
#if defined(HAVE_PTHREAD_BARRIER) && !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__))
110+
#define SW_USE_PTHREAD_BARRIER
111+
#endif
112+
113+
struct Barrier {
114+
#ifdef SW_USE_PTHREAD_BARRIER
115+
pthread_barrier_t barrier_;
116+
pthread_barrierattr_t barrier_attr_;
117+
bool shared_;
118+
#else
119+
sw_atomic_t count_;
120+
sw_atomic_t barrier_;
121+
#endif
122+
void init(bool shared, int count);
123+
void wait();
124+
void destroy();
125+
};
126+
108127
} // namespace swoole

include/swoole_server.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,7 @@ struct ServerGS {
394394

395395
sw_atomic_t spinlock;
396396

397-
#ifdef HAVE_PTHREAD_BARRIER
398-
pthread_barrier_t manager_barrier;
399-
pthread_barrierattr_t manager_barrier_attr;
400-
#endif
397+
Barrier manager_barrier;
401398

402399
ProcessPool task_workers;
403400
ProcessPool event_workers;
@@ -858,9 +855,7 @@ class Server {
858855
std::shared_ptr<std::vector<std::string>> http_index_files = nullptr;
859856
std::shared_ptr<std::unordered_set<std::string>> http_compression_types = nullptr;
860857

861-
#ifdef HAVE_PTHREAD_BARRIER
862-
pthread_barrier_t reactor_thread_barrier = {};
863-
#endif
858+
Barrier reactor_thread_barrier = {};
864859

865860
/**
866861
* temporary directory for HTTP uploaded file.

src/lock/barrier.cc

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Swoole |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 2.0 of the Apache license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.apache.org/licenses/LICENSE-2.0.html |
9+
| If you did not receive a copy of the Apache2.0 license and are unable|
10+
| to obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Author: Tianfeng Han <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#include "swoole.h"
18+
#include "swoole_lock.h"
19+
20+
namespace swoole {
21+
22+
#define BARRIER_USEC 10000
23+
24+
void Barrier::init(bool shared, int count) {
25+
#ifdef SW_USE_PTHREAD_BARRIER
26+
if (shared) {
27+
pthread_barrierattr_setpshared(&barrier_attr_, PTHREAD_PROCESS_SHARED);
28+
pthread_barrier_init(&barrier_, &barrier_attr_, count);
29+
} else {
30+
pthread_barrier_init(&barrier_, nullptr, count);
31+
}
32+
shared_ = shared;
33+
#else
34+
barrier_ = 0;
35+
count_ = count;
36+
#endif
37+
}
38+
39+
void Barrier::wait() {
40+
#ifdef SW_USE_PTHREAD_BARRIER
41+
pthread_barrier_wait(&barrier_);
42+
#else
43+
sw_atomic_add_fetch(&barrier_, 1);
44+
SW_LOOP {
45+
if (barrier_ == count_) {
46+
break;
47+
}
48+
usleep(BARRIER_USEC);
49+
sw_atomic_memory_barrier();
50+
}
51+
#endif
52+
}
53+
54+
void Barrier::destroy() {
55+
#ifdef SW_USE_PTHREAD_BARRIER
56+
pthread_barrier_destroy(&barrier_);
57+
if (shared_) {
58+
pthread_barrierattr_destroy(&barrier_attr_);
59+
}
60+
#endif
61+
}
62+
63+
}; // namespace swoole

src/server/manager.cc

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,7 @@ void Manager::wait(Server *_server) {
192192
int sigid = SIGTERM;
193193
procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &sigid);
194194
#endif
195-
196-
#if defined(HAVE_PTHREAD_BARRIER) && !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__))
197-
pthread_barrier_wait(&_server->gs->manager_barrier);
198-
#else
199-
SW_START_SLEEP;
200-
#endif
195+
_server->gs->manager_barrier.wait();
201196
}
202197

203198
if (_server->isset_hook(Server::HOOK_MANAGER_START)) {

0 commit comments

Comments
 (0)