Skip to content

Commit 3cb08bc

Browse files
committed
Delay GC until safepoint is reached
1 parent 2480362 commit 3cb08bc

File tree

10 files changed

+58
-34
lines changed

10 files changed

+58
-34
lines changed

Zend/tests/gc/bug70805.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ $i = 0;
2828
$c = new A;
2929
$array = array($c); //This is used to leave a room for $GLOBALS["a"]
3030
unset($c);
31+
flush(); // handle interrupts
3132

3233
while ($i++ < 9998) {
3334
$t = [];
@@ -37,11 +38,13 @@ while ($i++ < 9998) {
3738
$t = [new C];
3839
$t[] = &$t;
3940
unset($t); // This is used to trigger C::__destruct while doing gc_collect_roots
41+
flush(); // handle interrupts
4042

4143
$e = $a;
4244
unset($a); // This one cannot be put into roots buf because it's full, thus gc_collect_roots will be called,
4345
// but C::__destructor which is called in gc_collect_roots will put $a into buf
4446
// which will make $a be put into gc roots buf twice
47+
flush(); // handle interrupts
4548
var_dump(gc_collect_cycles());
4649
?>
4750
--EXPECT--

Zend/tests/gc/bug70805_1.phpt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ $i = 0;
3030
$c = new A;
3131
$array = array($c);
3232
unset($c);
33+
flush(); // handle interrupts
3334

3435
while ($i++ < 9998) {
3536
$t = [];
@@ -39,9 +40,11 @@ while ($i++ < 9998) {
3940
$t = [new C];
4041
$t[] = &$t;
4142
unset($t);
43+
flush(); // handle interrupts
4244
unset($a);
45+
flush(); // handle interrupts
4346

4447
var_dump(gc_collect_cycles());
4548
?>
4649
--EXPECT--
47-
int(2)
50+
int(0)

Zend/tests/gc/bug70805_2.phpt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,15 @@ while ($i++ < 9999) {
3131
$t[] = &$t;
3232
unset($t);
3333
}
34+
flush(); // handle interrupts
3435
$t = [new C];
3536
$t[] = &$t;
3637
unset($t);
38+
flush(); // handle interrupts
3739

3840
unset($a);
41+
flush(); // handle interrupts
3942
var_dump(gc_collect_cycles());
4043
?>
4144
--EXPECT--
42-
int(2)
45+
int(0)

Zend/tests/gc/gc_023.phpt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,23 @@ for ($i=0; $i < 9999; $i++) {
1111
}
1212
var_dump(gc_collect_cycles());
1313
unset($a);
14+
flush(); // check interrupts
1415
var_dump(gc_collect_cycles());
1516
$a=array();
1617
for ($i=0; $i < 10001; $i++) {
1718
$a[$i] = array(array());
1819
$a[$i][0] = & $a[$i];
1920
}
21+
flush(); // check interrupts
2022
var_dump(gc_collect_cycles());
21-
unset($a); // 10000 zvals collected automatic
23+
unset($a);
24+
flush(); // check interrupts. 10000 zvals collected automatic
2225
var_dump(gc_collect_cycles());
2326
echo "ok\n";
2427
?>
2528
--EXPECT--
2629
int(0)
2730
int(9999)
2831
int(0)
29-
int(1)
32+
int(0)
3033
ok

Zend/tests/gc/gc_045.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ array(12) {
6060
["threshold"]=>
6161
int(10001)
6262
["buffer_size"]=>
63-
int(16384)
63+
int(%d)
6464
["roots"]=>
65-
int(10000)
65+
int(9999)
6666
["application_time"]=>
6767
float(%f)
6868
["collector_time"]=>

Zend/zend_execute.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4269,6 +4269,8 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *ca
42694269
zend_atomic_bool_store_ex(&EG(vm_interrupt), false);
42704270
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
42714271
zend_timeout();
4272+
} else if (zend_atomic_bool_load_ex(&EG(gc_requested))) {
4273+
gc_handle_requested_run();
42724274
} else if (zend_interrupt_function) {
42734275
zend_interrupt_function(call);
42744276
}

Zend/zend_gc.c

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
*/
6969
#include "zend.h"
7070
#include "zend_API.h"
71+
#include "zend_atomic.h"
7172
#include "zend_compile.h"
7273
#include "zend_errors.h"
7374
#include "zend_fibers.h"
@@ -687,7 +688,19 @@ static void gc_adjust_threshold(int count)
687688
}
688689
}
689690

690-
/* Perform a GC run and then add a node as a possible root. */
691+
static void gc_request_run(void)
692+
{
693+
zend_atomic_bool_store_ex(&EG(gc_requested), true);
694+
zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
695+
}
696+
697+
void gc_handle_requested_run(void)
698+
{
699+
zend_atomic_bool_store_ex(&EG(gc_requested), false);
700+
gc_adjust_threshold(gc_collect_cycles());
701+
}
702+
703+
/* Add a node as a possible root and request a GC run. */
691704
static zend_never_inline void ZEND_FASTCALL gc_possible_root_when_full(zend_refcounted *ref)
692705
{
693706
uint32_t idx;
@@ -696,20 +709,8 @@ static zend_never_inline void ZEND_FASTCALL gc_possible_root_when_full(zend_refc
696709
ZEND_ASSERT(GC_TYPE(ref) == IS_ARRAY || GC_TYPE(ref) == IS_OBJECT);
697710
ZEND_ASSERT(GC_INFO(ref) == 0);
698711

699-
if (GC_G(gc_enabled) && !GC_G(gc_active)) {
700-
GC_ADDREF(ref);
701-
gc_adjust_threshold(gc_collect_cycles());
702-
if (UNEXPECTED(GC_DELREF(ref) == 0)) {
703-
rc_dtor_func(ref);
704-
return;
705-
} else if (UNEXPECTED(GC_INFO(ref))) {
706-
return;
707-
}
708-
}
709-
710-
if (GC_HAS_UNUSED()) {
711-
idx = GC_FETCH_UNUSED();
712-
} else if (EXPECTED(GC_HAS_NEXT_UNUSED())) {
712+
ZEND_ASSERT(!GC_HAS_UNUSED());
713+
if (EXPECTED(GC_HAS_NEXT_UNUSED())) {
713714
idx = GC_FETCH_NEXT_UNUSED();
714715
} else {
715716
gc_grow_root_buffer();
@@ -730,6 +731,10 @@ static zend_never_inline void ZEND_FASTCALL gc_possible_root_when_full(zend_refc
730731
GC_BENCH_INC(zval_buffered);
731732
GC_BENCH_INC(root_buf_length);
732733
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
734+
735+
if (GC_G(gc_enabled) && !GC_G(gc_active)) {
736+
gc_request_run();
737+
}
733738
}
734739

735740
/* Add a possible root node to the buffer.

Zend/zend_gc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ void gc_globals_ctor(void);
7070
void gc_globals_dtor(void);
7171
void gc_reset(void);
7272

73+
void gc_handle_requested_run(void);
74+
7375
#ifdef ZTS
7476
size_t zend_gc_globals_size(void);
7577
#endif

Zend/zend_globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ struct _zend_executor_globals {
219219

220220
zend_atomic_bool vm_interrupt;
221221
zend_atomic_bool timed_out;
222+
zend_atomic_bool gc_requested;
222223

223224
HashTable *in_autoload;
224225

Zend/zend_vm_def.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10506,23 +10506,25 @@ ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY)
1050610506
SAVE_OPLINE();
1050710507
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
1050810508
zend_timeout();
10509+
ZEND_VM_CONTINUE();
10510+
} else if (zend_atomic_bool_load_ex(&EG(gc_requested))) {
10511+
gc_handle_requested_run();
1050910512
} else if (zend_interrupt_function) {
1051010513
zend_interrupt_function(execute_data);
10511-
if (EG(exception)) {
10512-
/* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */
10513-
const zend_op *throw_op = EG(opline_before_exception);
10514+
}
10515+
if (EG(exception)) {
10516+
/* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */
10517+
const zend_op *throw_op = EG(opline_before_exception);
1051410518

10515-
if (throw_op
10516-
&& throw_op->result_type & (IS_TMP_VAR|IS_VAR)
10517-
&& throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT
10518-
&& throw_op->opcode != ZEND_ADD_ARRAY_UNPACK
10519-
&& throw_op->opcode != ZEND_ROPE_INIT
10520-
&& throw_op->opcode != ZEND_ROPE_ADD) {
10521-
ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var));
10519+
if (throw_op
10520+
&& throw_op->result_type & (IS_TMP_VAR|IS_VAR)
10521+
&& throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT
10522+
&& throw_op->opcode != ZEND_ADD_ARRAY_UNPACK
10523+
&& throw_op->opcode != ZEND_ROPE_INIT
10524+
&& throw_op->opcode != ZEND_ROPE_ADD) {
10525+
ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var));
1052210526

10523-
}
1052410527
}
10525-
ZEND_VM_ENTER();
1052610528
}
10527-
ZEND_VM_CONTINUE();
10529+
ZEND_VM_ENTER();
1052810530
}

0 commit comments

Comments
 (0)