Skip to content

Commit d860c8a

Browse files
committed
#6: * Fix for Scope tests
1 parent 28d1793 commit d860c8a

File tree

5 files changed

+56
-49
lines changed

5 files changed

+56
-49
lines changed

scope.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ static void scope_destroy(zend_object *object)
12291229
}
12301230
}
12311231

1232-
static HashTable *async_scope_object_gc(zend_object *object, zval **table, int *num)
1232+
static HashTable *scope_object_gc(zend_object *object, zval **table, int *num)
12331233
{
12341234
async_scope_object_t *scope_obj = (async_scope_object_t *)object;
12351235
async_scope_t *scope = scope_obj->scope;
@@ -1281,6 +1281,32 @@ static HashTable *async_scope_object_gc(zend_object *object, zval **table, int *
12811281
return NULL;
12821282
}
12831283

1284+
static void scope_object_free(zend_object *object)
1285+
{
1286+
async_scope_object_t *scope_object = (async_scope_object_t *) object;
1287+
1288+
async_scope_t *scope = scope_object->scope;
1289+
1290+
if (scope == NULL) {
1291+
return;
1292+
}
1293+
1294+
scope_object->scope = NULL;
1295+
scope->scope.scope_object = NULL;
1296+
zend_object_std_dtor(&scope_object->std);
1297+
1298+
// At this point, the user-defined Scope object is about to be destroyed.
1299+
// This means we are obligated to cancel the Scope and all its child Scopes along with their coroutines.
1300+
// However, the Scope itself will not be destroyed.
1301+
if (false == scope->scope.try_to_dispose(&scope->scope)) {
1302+
zend_object *exception = async_new_exception(
1303+
async_ce_cancellation_exception, "Scope is being disposed due to object destruction"
1304+
);
1305+
1306+
ZEND_ASYNC_SCOPE_CANCEL(&scope->scope, exception, true, ZEND_ASYNC_SCOPE_IS_DISPOSE_SAFELY(&scope->scope));
1307+
}
1308+
}
1309+
12841310
void async_register_scope_ce(void)
12851311
{
12861312
async_ce_scope_provider = register_class_Async_ScopeProvider();
@@ -1294,7 +1320,8 @@ void async_register_scope_ce(void)
12941320

12951321
async_scope_handlers.clone_obj = NULL;
12961322
async_scope_handlers.dtor_obj = scope_destroy;
1297-
async_scope_handlers.get_gc = async_scope_object_gc;
1323+
async_scope_handlers.get_gc = scope_object_gc;
1324+
async_scope_handlers.free_obj = scope_object_free;
12981325
}
12991326

13001327
/**

tests/scope/019-scope_gc_basic.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Scope: GC handler basic functionality
55

66
use Async\Scope;
77
use function Async\spawn;
8+
use function Async\suspend;
89

910
// Test that GC handler is registered and functioning for scope
1011
$scope = new Scope();
@@ -16,6 +17,8 @@ $coroutine = $scope->spawn(function() {
1617
// Force garbage collection to ensure our GC handler is called
1718
$collected = gc_collect_cycles();
1819

20+
suspend(); // Suspend to simulate coroutine lifecycle
21+
1922
// Check that coroutine completed successfully
2023
$result = $coroutine->getResult();
2124
var_dump($result);

tests/scope/020-scope_gc_with_finally.phpt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Scope: GC handler with finally handlers
55

66
use Async\Scope;
77
use function Async\spawn;
8+
use function Async\suspend;
89

910
// Test GC with scope finally handlers containing callable ZVALs
1011
$scope = new Scope();
@@ -21,6 +22,8 @@ $coroutine = $scope->spawn(function() {
2122
// Force garbage collection
2223
$collected = gc_collect_cycles();
2324

25+
suspend(); // Suspend to simulate coroutine lifecycle
26+
2427
// Wait for completion
2528
$result = $coroutine->getResult();
2629
var_dump($result);
@@ -34,5 +37,5 @@ var_dump($collected >= 0);
3437
?>
3538
--EXPECT--
3639
string(18) "scope_finally_test"
37-
Scope finally executed
38-
bool(true)
40+
bool(true)
41+
Scope finally executed

tests/scope/021-scope_gc_with_context.phpt

Lines changed: 0 additions & 45 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Scope: GC handler with context data
3+
--FILE--
4+
<?php
5+
6+
use Async\Scope;
7+
use Async\Context;
8+
use function Async\spawn;
9+
10+
// Test for a special case:
11+
// If a Scope is created with a faulty constructor,
12+
// the dtor method will not be called. However, even in this case, the
13+
// memory must be properly freed.
14+
$scope = new Scope(2);
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Uncaught ArgumentCountError: %s
19+
%a

0 commit comments

Comments
 (0)