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

krakjoe / parallel / 20272758286

16 Dec 2025 03:11PM UTC coverage: 96.815%. Remained the same
20272758286

Pull #357

github

web-flow
Merge 771053661 into 14042a874
Pull Request #357: Cleanup code formatting and docs

44 of 48 new or added lines in 6 files covered. (91.67%)

30 existing lines in 11 files now uncovered.

3009 of 3108 relevant lines covered (96.81%)

6860.26 hits per line

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

97.89
/src/parallel.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_PARALLEL
19
#define HAVE_PARALLEL_PARALLEL
20

21
#include "parallel.h"
22

23
/* {{{ */
24
TSRM_TLS HashTable php_parallel_runtimes;
25

26
static struct {
27
    pthread_mutex_t     mutex;
28
    zend_string        *bootstrap;
29
    volatile zend_ulong running;
30
} php_parallel_globals;
31

32
#define PCG(e) php_parallel_globals.e
33
/* }}} */
34

35
/* {{{ */
36
typedef int (*php_sapi_deactivate_t)(void);
37
typedef size_t (*php_sapi_output_t)(const char*, size_t);
38

39
static php_sapi_deactivate_t php_sapi_deactivate_function;
40
static php_sapi_output_t     php_sapi_output_function;
41

42
static pthread_mutex_t php_parallel_output_mutex = PTHREAD_MUTEX_INITIALIZER;
43

44
static size_t php_parallel_output_function(const char *str, size_t len) {
25,870✔
45
    size_t result;
25,870✔
46

47
    pthread_mutex_lock(&php_parallel_output_mutex);
25,870✔
48
    result =
25,870✔
49
        php_sapi_output_function(str, len);
25,870✔
50
    pthread_mutex_unlock(&php_parallel_output_mutex);
25,870✔
51

52
    return result;
25,870✔
53
} /* }}} */
54

55
/* {{{ */
56
ZEND_BEGIN_ARG_INFO_EX(php_parallel_bootstrap_arginfo, 0, 0, 1)
57
    ZEND_ARG_TYPE_INFO(0, file, IS_STRING, 0)
58
ZEND_END_ARG_INFO()
59

60
static PHP_NAMED_FUNCTION(php_parallel_bootstrap)
162✔
61
{
62
    zend_string *bootstrap;
162✔
63

64
    ZEND_PARSE_PARAMETERS_START(1, 1)
162✔
65
        Z_PARAM_PATH_STR(bootstrap)
324✔
66
    ZEND_PARSE_PARAMETERS_END();
216✔
67

68
    pthread_mutex_lock(&PCG(mutex));
162✔
69

70
    if (PCG(bootstrap)) {
162✔
71
        php_parallel_exception_ex(
18✔
72
            php_parallel_runtime_error_bootstrap_ce,
73
            "\\parallel\\bootstrap already set to %s",
74
            ZSTR_VAL(PCG(bootstrap)));
75
        pthread_mutex_unlock(&PCG(mutex));
18✔
76
        return;
18✔
77
    }
78

79
    if (PCG(running)) {
144✔
80
        php_parallel_exception_ex(
36✔
81
            php_parallel_runtime_error_bootstrap_ce,
82
            "\\parallel\\bootstrap should be called once, "
83
            "before any calls to \\parallel\\run");
84
        pthread_mutex_unlock(&PCG(mutex));
36✔
85
        return;
36✔
86
    }
87

88
    PCG(bootstrap) =
216✔
89
        php_parallel_copy_string_interned(bootstrap);
108✔
90
    pthread_mutex_unlock(&PCG(mutex));
108✔
91
} /* }}} */
92

93
// This will return an idle runtime (aka thread) or spawn a new one, bootstap it
94
// and return that. This method is solely called by the userlands
95
// `\parallel\run()` function call.
96
/* {{{ */
97
static zend_always_inline php_parallel_runtime_t* php_parallel_runtimes_fetch() {
504✔
98
    php_parallel_runtime_t *runtime;
504✔
99

100
    ZEND_HASH_FOREACH_PTR(&php_parallel_runtimes, runtime) {
1,368✔
101
        if (!php_parallel_scheduler_busy(runtime)) {
882✔
102
            return runtime;
103
        }
104
    } ZEND_HASH_FOREACH_END();
105

106
    if (!(runtime = php_parallel_runtime_construct(PCG(bootstrap)))) {
486✔
107
        return NULL;
108
    }
109

110
    pthread_mutex_lock(&PCG(mutex));
486✔
111
    PCG(running)++;
486✔
112
    pthread_mutex_unlock(&PCG(mutex));
486✔
113

114
    return zend_hash_next_index_insert_ptr(&php_parallel_runtimes, runtime);
972✔
115
}
116

117
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(php_parallel_run_arginfo, 0, 1, \\parallel\\Future, 1)
118
    ZEND_ARG_OBJ_INFO(0, task, Closure, 0)
119
    ZEND_ARG_TYPE_INFO(0, argv, IS_ARRAY, 0)
120
ZEND_END_ARG_INFO()
121

122
static PHP_NAMED_FUNCTION(php_parallel_run)
504✔
123
{
124
    php_parallel_runtime_t *runtime;
504✔
125
    zval *closure = NULL;
504✔
126
    zval *argv = NULL;
504✔
127

128
    ZEND_PARSE_PARAMETERS_START(1, 2)
504✔
129
        Z_PARAM_OBJECT_OF_CLASS(closure, zend_ce_closure)
1,008✔
130
        Z_PARAM_OPTIONAL
504✔
131
        Z_PARAM_ARRAY(argv)
792✔
132
    ZEND_PARSE_PARAMETERS_END();
504✔
133

134
    runtime = php_parallel_runtimes_fetch();
504✔
135

136
    if (!EG(exception)) {
504✔
137
        php_parallel_scheduler_push(
504✔
138
            runtime, closure, argv, return_value);
139
    }
140
} /* }}} */
141

142
#ifdef ZEND_DEBUG
143
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(php_parallel_count_arginfo, 0, 0, IS_LONG, 0)
144
ZEND_END_ARG_INFO()
145

UNCOV
146
PHP_NAMED_FUNCTION(php_parallel_count)
×
147
{
UNCOV
148
    RETURN_LONG(zend_hash_num_elements(&php_parallel_runtimes));
×
149
}
150
#endif
151

152
/* {{{ */
153
zend_function_entry php_parallel_functions[] = {
154
    ZEND_NS_FENTRY("parallel", bootstrap, php_parallel_bootstrap, php_parallel_bootstrap_arginfo, 0)
155
    ZEND_NS_FENTRY("parallel", run,       php_parallel_run,       php_parallel_run_arginfo, 0)
156
#ifdef ZEND_DEBUG
157
    ZEND_NS_FENTRY("parallel", count,     php_parallel_count,     php_parallel_count_arginfo, 0)
158
#endif
159
    PHP_FE_END
160
}; /* }}} */
161

162
PHP_MINIT_FUNCTION(PARALLEL_CORE)
3,168✔
163
{
164
    if (strncmp(sapi_module.name, "cli", sizeof("cli")-1) == SUCCESS) {
3,168✔
165
        php_sapi_deactivate_function = sapi_module.deactivate;
3,168✔
166

167
        sapi_module.deactivate = NULL;
3,168✔
168
    }
169

170
    memset(&php_parallel_globals, 0, sizeof(php_parallel_globals));
3,168✔
171

172
    php_sapi_output_function = sapi_module.ub_write;
3,168✔
173

174
    sapi_module.ub_write = php_parallel_output_function;
3,168✔
175

176
    PHP_MINIT(PARALLEL_HANDLERS)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
177
    PHP_MINIT(PARALLEL_EXCEPTIONS)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
178
    PHP_MINIT(PARALLEL_COPY)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
179
    PHP_MINIT(PARALLEL_SCHEDULER)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
180
    PHP_MINIT(PARALLEL_CHANNEL)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
181
    PHP_MINIT(PARALLEL_EVENTS)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
182
    PHP_MINIT(PARALLEL_SYNC)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
183

184
    php_parallel_mutex_init(&PCG(mutex), 1);
3,168✔
185
    PCG(running) = 0;
3,168✔
186
    PCG(bootstrap) = NULL;
3,168✔
187

188
    return SUCCESS;
3,168✔
189
}
190

191
PHP_MSHUTDOWN_FUNCTION(PARALLEL_CORE)
3,168✔
192
{
193
    PHP_MSHUTDOWN(PARALLEL_SYNC)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
194
    PHP_MSHUTDOWN(PARALLEL_EVENTS)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
195
    PHP_MSHUTDOWN(PARALLEL_CHANNEL)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
196
    PHP_MSHUTDOWN(PARALLEL_SCHEDULER)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
197
    PHP_MSHUTDOWN(PARALLEL_COPY)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
198
    PHP_MSHUTDOWN(PARALLEL_EXCEPTIONS)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
199
    PHP_MSHUTDOWN(PARALLEL_HANDLERS)(INIT_FUNC_ARGS_PASSTHRU);
3,168✔
200

201
    php_parallel_mutex_destroy(&PCG(mutex));
3,168✔
202

203
    if (strncmp(sapi_module.name, "cli", sizeof("cli")-1) == SUCCESS) {
3,168✔
204
        sapi_module.deactivate = php_sapi_deactivate_function;
3,168✔
205
    }
206

207
    sapi_module.ub_write = php_sapi_output_function;
3,168✔
208

209
    return SUCCESS;
3,168✔
210
}
211

212
static void php_parallel_runtimes_release(zval *zv) {
486✔
213
    php_parallel_runtime_t *runtime =
486✔
214
        (php_parallel_runtime_t*) Z_PTR_P(zv);
215

216
    OBJ_RELEASE(&runtime->std);
486✔
217
    pthread_mutex_lock(&PCG(mutex));
486✔
218
    PCG(running)--;
486✔
219
    pthread_mutex_unlock(&PCG(mutex));
486✔
220
}
486✔
221

222
PHP_RINIT_FUNCTION(PARALLEL_CORE)
5,352✔
223
{
224
    PHP_RINIT(PARALLEL_COPY)(INIT_FUNC_ARGS_PASSTHRU);
5,352✔
225

226
    zend_hash_init(
5,352✔
227
        &php_parallel_runtimes, 16, NULL, php_parallel_runtimes_release, 0);
228

229
    return SUCCESS;
5,352✔
230
}
231

232
PHP_RSHUTDOWN_FUNCTION(PARALLEL_CORE)
5,352✔
233
{
234
    zend_hash_destroy(&php_parallel_runtimes);
5,352✔
235

236
    PHP_RSHUTDOWN(PARALLEL_COPY)(INIT_FUNC_ARGS_PASSTHRU);
5,352✔
237

238
    // In case of a `zend_bailout()` this mutex could still be locked, so we
239
    // unlock it just in case.
240
    // See https://github.com/krakjoe/parallel/issues/313 for more details
241
    if (UNEXPECTED(CG(unclean_shutdown) == 1)) {
5,352✔
242
        pthread_mutex_unlock(&php_parallel_output_mutex);
109✔
243
    }
244

245
    return SUCCESS;
5,352✔
246
}
247
#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