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

krakjoe / parallel / 25781091697

13 May 2026 05:51AM UTC coverage: 95.107% (+0.07%) from 95.033%
25781091697

push

github

realFlowControl
bump version to 1.12.13

2896 of 3045 relevant lines covered (95.11%)

5722.08 hits per line

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

98.28
/src/cache.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_CACHE
19
#define HAVE_PARALLEL_CACHE
20

21
#include "parallel.h"
22

23
static struct {
24
        pthread_mutex_t mutex;
25
        HashTable       functions;
26
#if PHP_VERSION_ID < 80200
27
        HashTable statics;
28
#endif
29
        struct {
30
                size_t size;
31
                size_t used;
32
                void  *mem;
33
                void  *block;
34
        } memory;
35
} php_parallel_cache_globals = {PTHREAD_MUTEX_INITIALIZER};
36

37
#define PCG(e) php_parallel_cache_globals.e
38
#define PCM(e) PCG(memory).e
39

40
#define PARALLEL_CACHE_CHUNK PARALLEL_PLATFORM_ALIGNED((1024 * 1024) * 8)
41
#define PARALLEL_CACHE_FILE_HASH_OFFSET 1469598103934665603ULL
42
#define PARALLEL_CACHE_FILE_HASH_PRIME 1099511628211ULL
43

44
#if PHP_VERSION_ID < 80200
45
#define PARALLEL_CACHE_STATICS_PARAM , bool statics
46
#define PARALLEL_CACHE_STATICS_ARG(value) , value
47
#else
48
#define PARALLEL_CACHE_STATICS_PARAM
49
#define PARALLEL_CACHE_STATICS_ARG(value)
50
#endif
51

52
typedef struct _php_parallel_cache_entry_t {
53
        zend_op_array *function;
54
#if PHP_VERSION_ID >= 80400
55
        uint64_t source;
56
#endif
57
} php_parallel_cache_entry_t;
58

59
/* {{{ */
60
static zend_always_inline void *php_parallel_cache_alloc(size_t size)
7,725✔
61
{
62
        void  *mem;
7,725✔
63
        size_t aligned = PARALLEL_PLATFORM_ALIGNED(size);
7,725✔
64

65
        ZEND_ASSERT(size < PARALLEL_CACHE_CHUNK);
7,725✔
66

67
        if ((PCM(used) + aligned) >= PCM(size)) {
7,725✔
68
                PCM(size) = PARALLEL_PLATFORM_ALIGNED(PCM(size) + PARALLEL_CACHE_CHUNK);
×
69
                PCM(mem) = (void *)realloc(PCM(mem), PCM(size));
×
70

71
                if (!PCM(mem)) {
×
72
                        /* out of memory */
73
                        return NULL;
74
                }
75

76
                PCM(block) = (void *)(((char *)PCM(mem)) + PCM(used));
×
77
        }
78

79
        mem = PCM(block);
7,725✔
80
        PCM(block) = (void *)(((char *)PCM(block)) + aligned);
7,725✔
81
        PCM(used) += aligned;
7,725✔
82

83
        return mem;
7,725✔
84
}
85

86
static zend_always_inline void *php_parallel_cache_copy_mem(void *source, zend_long size)
4,033✔
87
{
88
        void *destination = php_parallel_cache_alloc(size);
120✔
89

90
        memcpy(destination, source, size);
3,913✔
91

92
        return destination;
4,033✔
93
} /* }}} */
94

95
#if PHP_VERSION_ID >= 80400
96
static zend_always_inline uint64_t php_parallel_cache_file_hash(const zend_op_array *source)
1,006✔
97
{ /* {{{ */
98
        FILE    *file;
1,006✔
99
        uint64_t hash = PARALLEL_CACHE_FILE_HASH_OFFSET;
1,006✔
100
        char     buffer[4096];
1,006✔
101
        size_t   read;
1,006✔
102

103
        if (!source->filename) {
1,006✔
104
                return 0;
105
        }
106

107
        file = VCWD_FOPEN(ZSTR_VAL(source->filename), "rb");
1,006✔
108
        if (!file) {
1,006✔
109
                return 0;
110
        }
111

112
        while ((read = fread(buffer, 1, sizeof(buffer), file)) > 0) {
2,012✔
113
                char *it = buffer, *end = buffer + read;
1,006✔
114

115
                while (it < end) {
377,538✔
116
                        hash ^= (unsigned char)*it++;
376,532✔
117
                        hash *= PARALLEL_CACHE_FILE_HASH_PRIME;
376,532✔
118
                }
119
        }
120

121
        fclose(file);
1,006✔
122

123
        return hash;
1,006✔
124
} /* }}} */
125
#endif
126

127
#if PHP_VERSION_ID < 80200
128
static zend_always_inline HashTable *php_parallel_cache_statics(HashTable *statics)
21✔
129
{ /* {{{ */
130
        HashTable *cached = zend_hash_index_find_ptr(&PCG(statics), (zend_ulong)statics);
42✔
131

132
        if (cached) {
133
                return cached;
134
        }
135

136
        cached = php_parallel_copy_hash_persistent(statics, php_parallel_copy_string_interned, php_parallel_cache_copy_mem,
21✔
137
                                                   PHP_PARALLEL_COPY_STORAGE_CACHE_POOL);
138

139
        return zend_hash_index_update_ptr(&PCG(statics), (zend_ulong)statics, cached);
21✔
140
} /* }}} */
141
#endif
142

143
static zend_always_inline void php_parallel_cache_type(zend_type *type)
266✔
144
{ /* {{{ */
145
        zend_type *single;
266✔
146

147
        if (!ZEND_TYPE_IS_SET(*type)) {
266✔
148
                return;
149
        }
150

151
        if (ZEND_TYPE_HAS_LIST(*type)) {
150✔
152
                zend_type_list *list = ZEND_TYPE_LIST(*type);
6✔
153

154
                list = php_parallel_cache_copy_mem(list, ZEND_TYPE_LIST_SIZE(list->num_types));
6✔
155

156
                if (ZEND_TYPE_USES_ARENA(*type)) {
6✔
157
                        ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
5✔
158
                }
159

160
                ZEND_TYPE_SET_PTR(*type, list);
6✔
161
        }
162

163
        ZEND_TYPE_FOREACH(*type, single)
150✔
164
        {
165
                if (ZEND_TYPE_HAS_NAME(*single)) {
156✔
166
                        zend_string *name = ZEND_TYPE_NAME(*single);
90✔
167

168
                        ZEND_TYPE_SET_PTR(*single, php_parallel_copy_string_interned(name));
90✔
169
                }
170
        }
171
        ZEND_TYPE_FOREACH_END();
156✔
172
} /* }}} */
173

174
/* {{{ */
175
static zend_op_array *php_parallel_cache_create(const zend_function *source PARALLEL_CACHE_STATICS_PARAM)
2,499✔
176
{
177
        zend_op_array *cached = php_parallel_cache_copy_mem((void *)source, sizeof(zend_op_array));
2,499✔
178
        uint32_t      *literal_map = NULL;
2,499✔
179
        uint32_t      *offset_map = NULL;
2,499✔
180
        uint32_t       new_last_literal = cached->last_literal;
2,499✔
181

182
        cached->fn_flags |= ZEND_ACC_IMMUTABLE;
2,499✔
183

184
#if PHP_VERSION_ID < 80200
185
        if (statics && cached->static_variables) {
795✔
186
                cached->static_variables = php_parallel_cache_statics(cached->static_variables);
42✔
187
        }
188
#endif
189

190
#if PHP_VERSION_ID >= 80200
191
        ZEND_MAP_PTR_INIT(cached->static_variables_ptr, cached->static_variables);
1,704✔
192
#else
193
        ZEND_MAP_PTR_INIT(cached->static_variables_ptr, &cached->static_variables);
795✔
194
#endif
195

196
        ZEND_MAP_PTR_INIT(cached->run_time_cache, NULL);
2,499✔
197

198
#if PHP_VERSION_ID >= 80100
199
        if (cached->num_dynamic_func_defs) {
2,127✔
200
                uint32_t it = 0;
180✔
201

202
                cached->dynamic_func_defs = php_parallel_cache_copy_mem(
360✔
203
                    cached->dynamic_func_defs, sizeof(zend_op_array *) * cached->num_dynamic_func_defs);
180✔
204

205
                while (it < cached->num_dynamic_func_defs) {
390✔
206
                        cached->dynamic_func_defs[it] = (zend_op_array *)php_parallel_cache_create(
420✔
207
                            (zend_function *)cached->dynamic_func_defs[it] PARALLEL_CACHE_STATICS_ARG(statics));
210✔
208
                        it++;
210✔
209
                }
210
        }
211
#endif
212

213
        if (!cached->refcount) {
2,499✔
214
                goto _php_parallel_cached_function_return;
1,636✔
215
        }
216

217
        cached->refcount = NULL;
863✔
218

219
        if (cached->last_literal) {
863✔
220
                zend_op *src_opline = source->op_array.opcodes;
863✔
221
                zend_op *src_end = src_opline + source->op_array.last;
863✔
222

223
                // A map to keep track of which literals are referenced by the
224
                // `ZEND_INIT_FCALL` opcodes we found so that we can expand those later
225
                literal_map = emalloc(sizeof(uint32_t) * cached->last_literal);
863✔
226
                memset(literal_map, 0, sizeof(uint32_t) * cached->last_literal);
863✔
227

228
                // Search for `ZEND_INIT_FCALL` opcodes and remember the indexes for the
229
                // literals, as we are rewriting them later to `ZEND_INIT_FCALL_BY_NAME`
230
                // which requires a second, lower cased literal just in the next literal
231
                // slot.
232
                while (src_opline < src_end) {
6,633✔
233
                        if (src_opline->opcode == ZEND_INIT_FCALL && src_opline->op2_type == IS_CONST) {
5,770✔
234
                                uint32_t idx;
270✔
235
#if ZEND_USE_ABS_CONST_ADDR
236
                                idx = (zval *)src_opline->op2.zv - source->op_array.literals;
237
#else
238
                                idx = ((zval *)((char *)src_opline + src_opline->op2.constant) - source->op_array.literals);
270✔
239
#endif
240
                                if (idx < cached->last_literal) {
270✔
241
                                        if (literal_map[idx] == 0) {
270✔
242
                                                literal_map[idx] = 1;
270✔
243
                                                new_last_literal++;
270✔
244
                                        }
245
                                }
246
                        }
247
                        src_opline++;
5,770✔
248
                }
249
        }
250

251
        if (new_last_literal) {
863✔
252
                zval    *literal = source->op_array.literals;
863✔
253
                zval    *slot = php_parallel_cache_alloc(sizeof(zval) * new_last_literal);
863✔
254
                uint32_t idx = 0;
863✔
255

256
                offset_map = emalloc(sizeof(uint32_t) * cached->last_literal);
863✔
257

258
                cached->literals = slot;
863✔
259

260
                for (uint32_t i = 0; i < cached->last_literal; i++) {
4,343✔
261
                        /* Record the mapping from old literal index (i) to new literal index (idx)
262
                           so we can update opcode operands later. */
263
                        offset_map[i] = idx;
3,480✔
264

265
                        if (Z_TYPE_P(literal) == IS_ARRAY) {
3,480✔
266
                                ZVAL_ARR(slot, php_parallel_copy_hash_persistent(Z_ARRVAL_P(literal), php_parallel_copy_string_interned,
42✔
267
                                                                                 php_parallel_cache_copy_mem,
268
                                                                                 PHP_PARALLEL_COPY_STORAGE_CACHE_POOL));
269
                        } else if (Z_TYPE_P(literal) == IS_STRING) {
3,438✔
270
                                ZVAL_STR(slot, php_parallel_copy_string_interned(Z_STR_P(literal)));
2,008✔
271
                        } else {
272
                                *slot = *literal;
1,430✔
273
                        }
274

275
                        Z_TYPE_FLAGS_P(slot) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE);
3,480✔
276

277
                        /* If this literal was used by INIT_FCALL, insert its lowercased version next. */
278
                        if (literal_map[i]) {
3,480✔
279
                                zend_string *lower = zend_string_tolower(Z_STR_P(slot));
270✔
280
                                slot++;
270✔
281
                                idx++;
270✔
282
                                ZVAL_STR(slot, php_parallel_copy_string_interned(lower));
270✔
283
                                zend_string_release(lower);
270✔
284
                                Z_TYPE_FLAGS_P(slot) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE);
270✔
285
                        }
286

287
                        literal++;
3,480✔
288
                        slot++;
3,480✔
289
                        idx++;
3,480✔
290
                }
291
                cached->last_literal = new_last_literal;
863✔
292
        }
293

294
        if (cached->last_var) {
863✔
295
                zend_string **vars = cached->vars;
540✔
296
                uint32_t      it = 0, end = cached->last_var;
540✔
297
                zend_string **heap = php_parallel_cache_alloc(cached->last_var * sizeof(zend_string *));
540✔
298

299
                while (it < end) {
1,281✔
300
                        heap[it] = php_parallel_copy_string_interned(vars[it]);
741✔
301
                        it++;
741✔
302
                }
303
                cached->vars = heap;
540✔
304
        }
305

306
        if (cached->last) {
863✔
307
                zend_op *opcodes = php_parallel_cache_copy_mem(cached->opcodes, sizeof(zend_op) * cached->last);
863✔
308
                zend_op *opline = opcodes, *end = opline + cached->last;
863✔
309

310
                while (opline < end) {
6,633✔
311
                        /* Replace ZEND_INIT_FCALL with ZEND_INIT_FCALL_BY_NAME.
312
                           We must clear op1_type (IS_UNUSED) and op1.var (0) to invalidate the
313
                           original thread's cache slot. */
314
                        if (opline->opcode == ZEND_INIT_FCALL) {
5,770✔
315
                                opline->opcode = ZEND_INIT_FCALL_BY_NAME;
270✔
316
                                opline->op1_type = IS_UNUSED;
270✔
317
                                opline->op1.var = 0;
270✔
318
                                ZEND_VM_SET_OPCODE_HANDLER(opline);
270✔
319
                        }
320

321
                        /* Remap IS_CONST operands to their new locations in the expanded literal table
322
                           using the offset_map we built earlier. */
323
                        if (opline->op1_type == IS_CONST) {
5,770✔
324
                                uint32_t idx;
1,835✔
325
                                zend_op *src_opline = source->op_array.opcodes + (opline - opcodes);
1,835✔
326
#if ZEND_USE_ABS_CONST_ADDR
327
                                idx = (zval *)src_opline->op1.zv - source->op_array.literals;
328
                                opline->op1.zv = &cached->literals[offset_map[idx]];
329
#else
330
                                idx = ((zval *)((char *)src_opline + src_opline->op1.constant) - source->op_array.literals);
1,835✔
331
                                opline->op1.constant = (char *)&cached->literals[offset_map[idx]] - (char *)opline;
1,835✔
332
#endif
333
                                if (opline->opcode == ZEND_SEND_VAL || opline->opcode == ZEND_SEND_VAL_EX ||
1,835✔
334
                                    opline->opcode == ZEND_QM_ASSIGN) {
335
                                        zend_vm_set_opcode_handler_ex(opline, 0, 0, 0);
261✔
336
                                }
337
                        }
338
                        if (opline->op2_type == IS_CONST) {
5,770✔
339
                                uint32_t idx;
1,020✔
340
                                zend_op *src_opline = source->op_array.opcodes + (opline - opcodes);
1,020✔
341
#if ZEND_USE_ABS_CONST_ADDR
342
                                idx = (zval *)src_opline->op2.zv - source->op_array.literals;
343
                                opline->op2.zv = &cached->literals[offset_map[idx]];
344
#else
345
                                idx = ((zval *)((char *)src_opline + src_opline->op2.constant) - source->op_array.literals);
1,020✔
346
                                opline->op2.constant = (char *)&cached->literals[offset_map[idx]] - (char *)opline;
1,020✔
347
#endif
348
                        }
349
#if ZEND_USE_ABS_JMP_ADDR
350
                        switch (opline->opcode) {
351
                        case ZEND_JMP:
352
                        case ZEND_FAST_CALL:
353
                                opline->op1.jmp_addr = &opcodes[opline->op1.jmp_addr - source->op_array.opcodes];
354
                                break;
355
#if PHP_VERSION_ID < 80200
356
                        case ZEND_JMPZNZ:
357
#endif
358
                        case ZEND_JMPZ:
359
                        case ZEND_JMPNZ:
360
                        case ZEND_JMPZ_EX:
361
                        case ZEND_JMPNZ_EX:
362
                        case ZEND_JMP_SET:
363
                        case ZEND_COALESCE:
364
                        case ZEND_FE_RESET_R:
365
                        case ZEND_FE_RESET_RW:
366
                        case ZEND_ASSERT_CHECK:
367
                                opline->op2.jmp_addr = &opcodes[opline->op2.jmp_addr - source->op_array.opcodes];
368
                                break;
369

370
                        case ZEND_CATCH:
371
                                if (!(opline->extended_value & ZEND_LAST_CATCH)) {
372
                                        opline->op2.jmp_addr = &opcodes[opline->op2.jmp_addr - source->op_array.opcodes];
373
                                }
374
                                break;
375
                        }
376
#endif
377

378
                        opline++;
5,770✔
379
                }
380
                cached->opcodes = opcodes;
863✔
381
        }
382

383
        if (literal_map) {
863✔
384
                efree(literal_map);
863✔
385
        }
386

387
        if (offset_map) {
863✔
388
                efree(offset_map);
863✔
389
        }
390

391
        if (cached->arg_info) {
863✔
392
                zend_arg_info *it = cached->arg_info, *end = it + cached->num_args, *info;
218✔
393

394
                if (cached->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
218✔
395
                        it--;
36✔
396
                }
397
                if (cached->fn_flags & ZEND_ACC_VARIADIC) {
218✔
398
                        end++;
12✔
399
                }
400

401
                cached->arg_info = info = php_parallel_cache_copy_mem(it, (end - it) * sizeof(zend_arg_info));
218✔
402

403
                while (it < end) {
484✔
404
                        if (info->name) {
266✔
405
                                info->name = php_parallel_copy_string_interned(it->name);
230✔
406
                        }
407

408
                        php_parallel_cache_type(&info->type);
266✔
409

410
                        info++;
266✔
411
                        it++;
266✔
412
                }
413
                if (cached->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
218✔
414
                        cached->arg_info++;
36✔
415
                }
416
        }
417

418
        if (cached->try_catch_array) {
863✔
419
                cached->try_catch_array = php_parallel_cache_copy_mem(cached->try_catch_array,
36✔
420
                                                                      sizeof(zend_try_catch_element) * cached->last_try_catch);
36✔
421
        }
422

423
        if (cached->live_range) {
863✔
424
                cached->live_range =
222✔
425
                    php_parallel_cache_copy_mem(cached->live_range, sizeof(zend_live_range) * cached->last_live_range);
222✔
426
        }
427

428
        if (cached->function_name)
863✔
429
                cached->function_name = php_parallel_copy_string_interned(cached->function_name);
863✔
430

431
        if (cached->filename)
863✔
432
                cached->filename = php_parallel_copy_string_interned(cached->filename);
863✔
433

434
        if (cached->doc_comment)
863✔
435
                cached->doc_comment = php_parallel_copy_string_interned(cached->doc_comment);
6✔
436

437
_php_parallel_cached_function_return:
857✔
438
        return cached;
2,499✔
439
} /* }}} */
440

441
/* {{{ */
442
static zend_always_inline zend_function *
443
php_parallel_cache_function_ex(const zend_function *source PARALLEL_CACHE_STATICS_PARAM)
2,973✔
444
{
445
        php_parallel_cache_entry_t *entry;
2,973✔
446
        zend_op_array              *cached;
2,973✔
447
#if PHP_VERSION_ID >= 80400
448
        uint64_t source_hash = php_parallel_cache_file_hash(&source->op_array);
2,012✔
449
#endif
450

451
        pthread_mutex_lock(&PCG(mutex));
2,973✔
452

453
        if ((entry = zend_hash_index_find_ptr(&PCG(functions), (zend_ulong)source->op_array.opcodes))) {
3,659✔
454
#if PHP_VERSION_ID >= 80400
455
                if (!zend_string_equals(entry->function->function_name, source->op_array.function_name) ||
316✔
456
                    entry->source != source_hash) {
234✔
457
                        goto _php_parallel_cached_function_create;
2✔
458
                }
459
#endif
460
                cached = entry->function;
684✔
461
                goto _php_parallel_cached_function_return;
684✔
462
        }
463

464
#if PHP_VERSION_ID >= 80400
465
_php_parallel_cached_function_create:
466
#endif
467
        entry = php_parallel_cache_alloc(sizeof(php_parallel_cache_entry_t));
2,289✔
468

469
        cached = php_parallel_cache_create(source PARALLEL_CACHE_STATICS_ARG(statics));
2,289✔
470
        entry->function = cached;
2,289✔
471
#if PHP_VERSION_ID >= 80400
472
        entry->source = source_hash;
774✔
473
#endif
474

475
        zend_hash_index_update_ptr(&PCG(functions), (zend_ulong)source->op_array.opcodes, entry);
2,289✔
476

477
_php_parallel_cached_function_return:
2,973✔
478
        pthread_mutex_unlock(&PCG(mutex));
2,973✔
479

480
        return (zend_function *)cached;
2,973✔
481
} /* }}} */
482

483
zend_function *php_parallel_cache_closure(const zend_function *source, zend_function *closure)
2,937✔
484
{ /* {{{ */
485
        zend_op_array *cache;
2,937✔
486

487
        cache = (zend_op_array *)php_parallel_cache_function_ex((zend_function *)source PARALLEL_CACHE_STATICS_ARG(0));
2,937✔
488

489
        if (!closure) {
2,937✔
490
                closure = php_parallel_copy_mem(cache, sizeof(zend_op_array), 1);
2,265✔
491
        } else {
492
                memcpy(closure, cache, sizeof(zend_op_array));
672✔
493
        }
494

495
        if (source->op_array.static_variables) {
2,937✔
496
                HashTable *statics = ZEND_MAP_PTR_GET(source->op_array.static_variables_ptr);
693✔
497

498
                if (statics) {
693✔
499
                        closure->op_array.static_variables = php_parallel_copy_hash_ctor(statics, 1);
558✔
500

501
#if PHP_VERSION_ID >= 80200
502
                        ZEND_MAP_PTR_INIT(closure->op_array.static_variables_ptr, closure->op_array.static_variables);
372✔
503
#else
504
                        ZEND_MAP_PTR_INIT(closure->op_array.static_variables_ptr, &closure->op_array.static_variables);
186✔
505
#endif
506
                }
507
        }
508

509
#if PHP_VERSION_ID >= 80100
510
        if (source->op_array.num_dynamic_func_defs) {
2,497✔
511
                uint32_t it = 0;
195✔
512
                /* Use regular persistent memory for dynamic_func_defs array, not cache pool */
513
                closure->op_array.dynamic_func_defs =
390✔
514
                    pemalloc(sizeof(zend_op_array *) * source->op_array.num_dynamic_func_defs, 1);
195✔
515
                memcpy(closure->op_array.dynamic_func_defs, source->op_array.dynamic_func_defs,
615✔
516
                       sizeof(zend_op_array *) * source->op_array.num_dynamic_func_defs);
195✔
517
                while (it < source->op_array.num_dynamic_func_defs) {
420✔
518
                        closure->op_array.dynamic_func_defs[it] = (zend_op_array *)php_parallel_cache_closure(
450✔
519
                            (zend_function *)source->op_array.dynamic_func_defs[it], NULL);
225✔
520
                        it++;
225✔
521
                }
522
        }
523
#endif
524

525
        return closure;
2,937✔
526
} /* }}} */
527

528
#if PHP_VERSION_ID < 80200
529
zend_function *php_parallel_cache_function(const zend_function *source)
36✔
530
{ /* {{{ */
531
        return php_parallel_cache_function_ex(source, 1);
36✔
532
} /* }}} */
533
#endif
534

535
/* {{{ */
536
PHP_MINIT_FUNCTION(PARALLEL_CACHE)
3,270✔
537
{
538
        zend_hash_init(&PCG(functions), 32, NULL, NULL, 1);
3,270✔
539
#if PHP_VERSION_ID < 80200
540
        zend_hash_init(&PCG(statics), 32, NULL, NULL, 1);
1,340✔
541
#endif
542

543
        PCM(size) = PARALLEL_CACHE_CHUNK;
3,270✔
544
        PCM(mem) = PCM(block) = malloc(PCM(size));
3,270✔
545

546
        if (!PCM(mem)) {
3,270✔
547
                /* out of memory */
548
        }
3,270✔
549

550
        return SUCCESS;
3,270✔
551
}
552

553
PHP_MSHUTDOWN_FUNCTION(PARALLEL_CACHE)
3,270✔
554
{
555
        zend_hash_destroy(&PCG(functions));
3,270✔
556
#if PHP_VERSION_ID < 80200
557
        zend_hash_destroy(&PCG(statics));
1,340✔
558
#endif
559

560
        if (PCM(mem))
3,270✔
561
                free(PCM(mem));
3,270✔
562

563
        return SUCCESS;
3,270✔
564
} /* }}} */
565
#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