• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

krakjoe / parallel / 20463488251

23 Dec 2025 02:33PM UTC coverage: 93.316% (-1.7%) from 94.99%
20463488251

Pull #364

github

web-flow
Merge 7e3199cf3 into 3c00d4ed1
Pull Request #364: Fix array literal copying into threads

5 of 6 new or added lines in 1 file covered. (83.33%)

114 existing lines in 6 files now uncovered.

2862 of 3067 relevant lines covered (93.32%)

361.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.93
/src/future.c
1
/*
2
  +----------------------------------------------------------------------+
3
  | parallel                                                             |
4
  +----------------------------------------------------------------------+
5
  | Copyright (c) Joe Watkins 2019-2024                                  |
6
  +----------------------------------------------------------------------+
7
  | This source file is subject to version 3.01 of the PHP license,      |
8
  | that is bundled with this package in the file LICENSE, and is        |
9
  | available through the world-wide-web at the following url:           |
10
  | http://www.php.net/license/3_01.txt                                  |
11
  | If you did not receive a copy of the PHP license and are unable to   |
12
  | obtain it through the world-wide-web, please send a note to          |
13
  | license@php.net so we can mail you a copy immediately.               |
14
  +----------------------------------------------------------------------+
15
  | Author: krakjoe                                                      |
16
  +----------------------------------------------------------------------+
17
 */
18
#ifndef HAVE_PARALLEL_FUTURE
19
#define HAVE_PARALLEL_FUTURE
20

21
#include "parallel.h"
22

23
zend_class_entry    *php_parallel_future_ce;
24
zend_object_handlers php_parallel_future_handlers;
25

26
zend_string         *php_parallel_future_string_runtime;
27

28
bool php_parallel_future_lock(php_parallel_future_t *future) { return php_parallel_monitor_lock(future->monitor); }
5✔
29

30
bool php_parallel_future_readable(php_parallel_future_t *future)
5✔
31
{
32
        return php_parallel_monitor_check(future->monitor, PHP_PARALLEL_READY);
5✔
33
}
34

35
static zend_always_inline void php_parallel_future_value_inline(php_parallel_future_t *future, zval *return_value)
51✔
36
{
37
        if (!php_parallel_monitor_check(future->monitor, PHP_PARALLEL_DONE)) {
51✔
38
                zval garbage = future->value;
49✔
39

40
                PARALLEL_ZVAL_COPY(&future->value, &garbage, 0);
49✔
41

42
                if (Z_OPT_REFCOUNTED(garbage)) {
49✔
43
                        if (Z_TYPE(garbage) == IS_ARRAY || Z_TYPE(garbage) == IS_OBJECT || Z_TYPE(garbage) == IS_REFERENCE) {
9✔
44
                                if (GC_REFCOUNT(Z_COUNTED(garbage)) > 1) {
6✔
UNCOV
45
                                        PARALLEL_ZVAL_DTOR(&garbage);
×
46
                                }
47
                        } else {
48
                                PARALLEL_ZVAL_DTOR(&garbage);
3✔
49
                        }
50
                }
51
                php_parallel_copy_free_garbage(&future->garbage);
49✔
52

53
                php_parallel_monitor_set(future->monitor, PHP_PARALLEL_DONE);
49✔
54
        }
55

56
        ZVAL_COPY(return_value, &future->value);
51✔
57
}
58

59
void php_parallel_future_value(php_parallel_future_t *future, zval *return_value)
2✔
60
{
61
        php_parallel_monitor_lock(future->monitor);
2✔
62

63
        if (php_parallel_monitor_check(future->monitor, PHP_PARALLEL_ERROR)) {
2✔
64
                ZVAL_OBJ(return_value, php_parallel_exceptions_restore(&future->value));
1✔
65
                php_parallel_monitor_unlock(future->monitor);
1✔
66
                return;
1✔
67
        } else if (php_parallel_monitor_check(future->monitor, PHP_PARALLEL_KILLED | PHP_PARALLEL_CANCELLED)) {
1✔
UNCOV
68
                ZVAL_NULL(return_value);
×
UNCOV
69
                php_parallel_monitor_unlock(future->monitor);
×
UNCOV
70
                return;
×
71
        }
72

73
        php_parallel_future_value_inline(future, return_value);
1✔
74

75
        php_parallel_monitor_unlock(future->monitor);
1✔
76
}
77

78
bool php_parallel_future_unlock(php_parallel_future_t *future) { return php_parallel_monitor_unlock(future->monitor); }
5✔
79

80
ZEND_BEGIN_ARG_INFO_EX(php_parallel_future_value_arginfo, 0, 0, 0)
81
ZEND_END_ARG_INFO()
82

83
PHP_METHOD(Parallel_Future, value)
55✔
84
{
85
        php_parallel_future_t *future = php_parallel_future_from(getThis());
55✔
86
        int32_t                state;
55✔
87

88
        PARALLEL_PARAMETERS_NONE(return);
55✔
89

90
        php_parallel_monitor_lock(future->monitor);
55✔
91

92
        if (php_parallel_monitor_check(future->monitor, PHP_PARALLEL_CANCELLED)) {
55✔
93
                php_parallel_exception_ex(php_parallel_future_error_cancelled_ce, "cannot retrieve value");
1✔
94
                php_parallel_monitor_unlock(future->monitor);
1✔
95
                return;
1✔
96
        }
97

98
        if (php_parallel_monitor_check(future->monitor, PHP_PARALLEL_KILLED)) {
54✔
99
                php_parallel_exception_ex(php_parallel_future_error_killed_ce, "cannot retrieve value");
1✔
100
                php_parallel_monitor_unlock(future->monitor);
1✔
101
                return;
1✔
102
        }
103

104
        if (php_parallel_monitor_check(future->monitor, PHP_PARALLEL_DONE)) {
53✔
105
                php_parallel_monitor_unlock(future->monitor);
2✔
106

107
                goto _php_parallel_future_value;
2✔
108
        } else {
109
                state = php_parallel_monitor_wait_locked(future->monitor,
51✔
110
                                                         PHP_PARALLEL_READY | PHP_PARALLEL_FAILURE | PHP_PARALLEL_ERROR);
111
                php_parallel_monitor_unlock(future->monitor);
51✔
112
        }
113

114
        if ((state == FAILURE) || (state & PHP_PARALLEL_FAILURE)) {
51✔
UNCOV
115
                php_parallel_exception_ex(php_parallel_future_error_ce, "cannot retrieve value");
×
UNCOV
116
                php_parallel_monitor_set(future->monitor, PHP_PARALLEL_READY | PHP_PARALLEL_FAILURE);
×
UNCOV
117
                return;
×
118
        }
119

120
        if ((state & PHP_PARALLEL_ERROR)) {
51✔
121
                zval exception;
3✔
122

123
                ZVAL_OBJ(&exception, php_parallel_exceptions_restore(&future->value));
3✔
124

125
                php_parallel_monitor_set(future->monitor, PHP_PARALLEL_READY | PHP_PARALLEL_ERROR);
3✔
126

127
                zend_throw_exception_object(&exception);
3✔
128
                return;
3✔
129
        }
130

131
        php_parallel_monitor_set(future->monitor, PHP_PARALLEL_READY);
48✔
132

133
_php_parallel_future_value:
50✔
134
        php_parallel_future_value_inline(future, return_value);
50✔
135
}
136

137
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(php_parallel_future_cancel_arginfo, 0, 0, _IS_BOOL, 0)
138
ZEND_END_ARG_INFO()
139

140
PHP_METHOD(Parallel_Future, cancel)
8✔
141
{
142
        php_parallel_future_t *future = php_parallel_future_from(getThis());
8✔
143

144
        PARALLEL_PARAMETERS_NONE(return);
8✔
145

146
        if (php_parallel_monitor_check(future->monitor, PHP_PARALLEL_CANCELLED)) {
8✔
147
                php_parallel_exception_ex(php_parallel_future_error_cancelled_ce, "task was already cancelled");
1✔
148
                return;
1✔
149
        }
150

151
        if (php_parallel_monitor_check(future->monitor, PHP_PARALLEL_KILLED)) {
7✔
152
                php_parallel_exception_ex(php_parallel_future_error_killed_ce, "runtime executing task was killed");
1✔
153
                return;
1✔
154
        }
155

156
        RETURN_BOOL(php_parallel_scheduler_cancel(future));
7✔
157
}
158

159
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(php_parallel_future_cancelled_arginfo, 0, 0, _IS_BOOL, 0)
160
ZEND_END_ARG_INFO()
161

162
PHP_METHOD(Parallel_Future, cancelled)
4✔
163
{
164
        php_parallel_future_t *future = php_parallel_future_from(getThis());
4✔
165

166
        PARALLEL_PARAMETERS_NONE(return);
4✔
167

168
        RETURN_BOOL(php_parallel_monitor_check(future->monitor, PHP_PARALLEL_CANCELLED));
5✔
169
}
170

171
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(php_parallel_future_done_arginfo, 0, 0, _IS_BOOL, 0)
172
ZEND_END_ARG_INFO()
173

174
PHP_METHOD(Parallel_Future, done)
2✔
175
{
176
        php_parallel_future_t *future = php_parallel_future_from(getThis());
2✔
177

178
        RETURN_BOOL(php_parallel_monitor_check(future->monitor, PHP_PARALLEL_READY));
2✔
179
}
180

181
ZEND_BEGIN_ARG_INFO_EX(php_parallel_future_construct_arginfo, 0, 0, 0)
182
ZEND_END_ARG_INFO()
183

184
PHP_METHOD(Parallel_Future, __construct)
1✔
185
{
186
        php_parallel_future_t *future = php_parallel_future_from(getThis());
1✔
187

188
        php_parallel_exception_ex(php_parallel_future_error_ce, "construction of Future objects is not allowed");
1✔
189

190
        php_parallel_monitor_set(future->monitor, PHP_PARALLEL_READY | PHP_PARALLEL_DONE);
1✔
191
}
1✔
192

193
zend_function_entry php_parallel_future_methods[] = {
194
    PHP_ME(Parallel_Future, __construct, php_parallel_future_construct_arginfo,
195
           ZEND_ACC_PUBLIC) PHP_ME(Parallel_Future, value, php_parallel_future_value_arginfo, ZEND_ACC_PUBLIC)
196
        PHP_ME(Parallel_Future, done, php_parallel_future_done_arginfo, ZEND_ACC_PUBLIC)
197
            PHP_ME(Parallel_Future, cancel, php_parallel_future_cancel_arginfo, ZEND_ACC_PUBLIC)
198
                PHP_ME(Parallel_Future, cancelled, php_parallel_future_cancelled_arginfo, ZEND_ACC_PUBLIC) PHP_FE_END};
199

200
zend_object *php_parallel_future_create(zend_class_entry *type)
69✔
201
{
202
        php_parallel_future_t *future = ecalloc(1, sizeof(php_parallel_future_t) + zend_object_properties_size(type));
69✔
203

204
        zend_object_std_init(&future->std, type);
69✔
205

206
        future->std.handlers = &php_parallel_future_handlers;
69✔
207

208
        future->monitor = php_parallel_monitor_create();
69✔
209

210
        zend_llist_init(&future->garbage, sizeof(php_parallel_garbage_t), NULL, 1);
69✔
211

212
        return &future->std;
69✔
213
}
214

215
void php_parallel_future_destroy(zend_object *o)
69✔
216
{
217
        php_parallel_future_t *future = php_parallel_future_fetch(o);
69✔
218

219
        php_parallel_monitor_lock(future->monitor);
69✔
220

221
        if (!php_parallel_monitor_check(future->monitor, PHP_PARALLEL_READY)) {
69✔
222
                php_parallel_monitor_wait_locked(future->monitor, PHP_PARALLEL_READY);
2✔
223
        }
224

225
        php_parallel_monitor_unlock(future->monitor);
69✔
226

227
        switch (Z_TYPE(future->value)) {
69✔
228
        case IS_PTR:
4✔
229
                php_parallel_exceptions_destroy(Z_PTR(future->value));
4✔
230
                break;
4✔
231

232
        default:
65✔
233
                if (Z_OPT_REFCOUNTED(future->value)) {
65✔
234
                        if (Z_TYPE(future->value) == IS_ARRAY || Z_TYPE(future->value) == IS_OBJECT ||
10✔
235
                            Z_TYPE(future->value) == IS_REFERENCE) {
3✔
236
                                if (GC_REFCOUNT(Z_COUNTED(future->value)) > 1) {
7✔
237
                                        PARALLEL_ZVAL_DTOR(&future->value);
2✔
238
                                }
239
                        } else {
240
                                PARALLEL_ZVAL_DTOR(&future->value);
3✔
241
                        }
242
                }
243
                php_parallel_copy_free_garbage(&future->garbage);
65✔
244
        }
245

246
        if (future->runtime) {
69✔
247
                OBJ_RELEASE(&future->runtime->std);
68✔
248
        }
249

250
        php_parallel_monitor_destroy(future->monitor);
69✔
251

252
        zend_object_std_dtor(o);
69✔
253
}
69✔
254

255
static HashTable *php_parallel_future_debug(zend_object *zo, int *temp)
2✔
256
{
257
        php_parallel_future_t *future = php_parallel_future_fetch(zo);
2✔
258
        HashTable             *debug;
2✔
259
        zval                   zdbg;
2✔
260

261
        ALLOC_HASHTABLE(debug);
2✔
262
        zend_hash_init(debug, 3, NULL, ZVAL_PTR_DTOR, 0);
2✔
263

264
        *temp = 1;
2✔
265

266
        GC_ADDREF(&future->runtime->std);
2✔
267

268
        ZVAL_OBJ(&zdbg, &future->runtime->std);
2✔
269

270
        zend_hash_add(debug, php_parallel_future_string_runtime, &zdbg);
2✔
271

272
        return debug;
2✔
273
}
274

275
PHP_MINIT_FUNCTION(PARALLEL_FUTURE)
164✔
276
{
277
        zend_class_entry ce;
164✔
278

279
        memcpy(&php_parallel_future_handlers, php_parallel_standard_handlers(), sizeof(zend_object_handlers));
164✔
280

281
        php_parallel_future_handlers.offset = XtOffsetOf(php_parallel_future_t, std);
164✔
282
        php_parallel_future_handlers.free_obj = php_parallel_future_destroy;
164✔
283
        php_parallel_future_handlers.get_debug_info = php_parallel_future_debug;
164✔
284

285
        INIT_NS_CLASS_ENTRY(ce, "parallel", "Future", php_parallel_future_methods);
164✔
286

287
        php_parallel_future_ce = zend_register_internal_class(&ce);
164✔
288
        php_parallel_future_ce->create_object = php_parallel_future_create;
164✔
289
        php_parallel_future_ce->ce_flags |= ZEND_ACC_FINAL;
164✔
290

291
#ifdef ZEND_ACC_NOT_SERIALIZABLE
292
        php_parallel_future_ce->ce_flags |= ZEND_ACC_NOT_SERIALIZABLE;
164✔
293
#else
294
        php_parallel_future_ce->serialize = zend_class_serialize_deny;
295
        php_parallel_future_ce->unserialize = zend_class_unserialize_deny;
296
#endif
297

298
        php_parallel_future_string_runtime = zend_string_init_interned(ZEND_STRL("runtime"), 1);
164✔
299

300
        return SUCCESS;
164✔
301
}
302

303
PHP_MSHUTDOWN_FUNCTION(PARALLEL_FUTURE)
164✔
304
{
305
        zend_string_release(php_parallel_future_string_runtime);
164✔
306

307
        return SUCCESS;
164✔
308
}
309
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc