pthread_rwlock requires the lock being unlocked as often as it has been acquired

tests/700-uv_rwlock.phpt throws a notice inside resource dtor, which causes a memory leak in PHP; setting track_errors=0 temporarily there for having the test pass here.
This commit is contained in:
Bob Weinand 2016-11-01 16:31:54 +01:00
parent 567ca4f30b
commit 30c34d72a3
2 changed files with 46 additions and 18 deletions

View File

@ -611,14 +611,26 @@ static void php_uv_lock_lock(enum php_uv_lock_type lock_type, INTERNAL_FUNCTION_
case IS_UV_RWLOCK: case IS_UV_RWLOCK:
case IS_UV_RWLOCK_RD: case IS_UV_RWLOCK_RD:
{ {
if (lock->locked == 0x01) {
zend_error(E_WARNING, "Cannot acquire a read lock while holding a write lock");
RETURN_FALSE;
}
uv_rwlock_rdlock(PHP_UV_LOCK_RWLOCK_P(lock)); uv_rwlock_rdlock(PHP_UV_LOCK_RWLOCK_P(lock));
lock->locked = 0x01; if (!lock->locked++) {
lock->locked = 0x02;
}
} }
break; break;
case IS_UV_RWLOCK_WR: case IS_UV_RWLOCK_WR:
{ {
if (lock->locked) {
zend_error(E_WARNING, "Cannot acquire a write lock when already holding a lock");
RETURN_FALSE;
}
uv_rwlock_wrlock(PHP_UV_LOCK_RWLOCK_P(lock)); uv_rwlock_wrlock(PHP_UV_LOCK_RWLOCK_P(lock));
lock->locked = 0x02; lock->locked = 0x01;
} }
break; break;
case IS_UV_MUTEX: case IS_UV_MUTEX:
@ -654,15 +666,17 @@ static void php_uv_lock_unlock(enum php_uv_lock_type lock_type, INTERNAL_FUNCTI
case IS_UV_RWLOCK: case IS_UV_RWLOCK:
case IS_UV_RWLOCK_RD: case IS_UV_RWLOCK_RD:
{ {
if (lock->locked == 0x01) { if (lock->locked > 0x01) {
uv_rwlock_rdunlock(PHP_UV_LOCK_RWLOCK_P(lock)); uv_rwlock_rdunlock(PHP_UV_LOCK_RWLOCK_P(lock));
lock->locked = 0x00; if (--lock->locked == 0x01) {
lock->locked = 0x00;
}
} }
} }
break; break;
case IS_UV_RWLOCK_WR: case IS_UV_RWLOCK_WR:
{ {
if (lock->locked == 0x02) { if (lock->locked == 0x01) {
uv_rwlock_wrunlock(PHP_UV_LOCK_RWLOCK_P(lock)); uv_rwlock_wrunlock(PHP_UV_LOCK_RWLOCK_P(lock));
lock->locked = 0x00; lock->locked = 0x00;
} }
@ -704,9 +718,16 @@ static void php_uv_lock_trylock(enum php_uv_lock_type lock_type, INTERNAL_FUNCTI
case IS_UV_RWLOCK: case IS_UV_RWLOCK:
case IS_UV_RWLOCK_RD: case IS_UV_RWLOCK_RD:
{ {
if (lock->locked == 0x01) {
zend_error(E_WARNING, "Cannot acquire a read lock while holding a write lock");
RETURN_FALSE;
}
error = uv_rwlock_tryrdlock(PHP_UV_LOCK_RWLOCK_P(lock)); error = uv_rwlock_tryrdlock(PHP_UV_LOCK_RWLOCK_P(lock));
if (error == 0) { if (error == 0) {
lock->locked = 0x01; if (!lock->locked++) {
lock->locked = 0x02;
}
RETURN_TRUE; RETURN_TRUE;
} else { } else {
RETURN_FALSE; RETURN_FALSE;
@ -715,9 +736,14 @@ static void php_uv_lock_trylock(enum php_uv_lock_type lock_type, INTERNAL_FUNCTI
break; break;
case IS_UV_RWLOCK_WR: case IS_UV_RWLOCK_WR:
{ {
if (lock->locked) {
zend_error(E_WARNING, "Cannot acquire a write lock when already holding a lock");
RETURN_FALSE;
}
error = uv_rwlock_trywrlock(PHP_UV_LOCK_RWLOCK_P(lock)); error = uv_rwlock_trywrlock(PHP_UV_LOCK_RWLOCK_P(lock));
if (error == 0) { if (error == 0) {
lock->locked = 0x02; lock->locked = 0x01;
RETURN_TRUE; RETURN_TRUE;
} else { } else {
RETURN_FALSE; RETURN_FALSE;
@ -1152,27 +1178,25 @@ void static destruct_uv_lock(zend_resource *rsrc)
if (lock->type == IS_UV_RWLOCK) { if (lock->type == IS_UV_RWLOCK) {
if (lock->locked == 0x01) { if (lock->locked == 0x01) {
php_error_docref(NULL, E_NOTICE, "uv_rwlock: unlocked resoruce detected. force rdunlock resource."); php_error_docref(NULL, E_NOTICE, "uv_rwlock: still locked resource detected; forcing wrunlock");
uv_rwlock_rdunlock(PHP_UV_LOCK_RWLOCK_P(lock));
lock->locked = 0x00;
} else if (lock->locked == 0x02) {
php_error_docref(NULL, E_NOTICE, "uv_rwlock: unlocked resoruce detected. force wrunlock resource.");
uv_rwlock_wrunlock(PHP_UV_LOCK_RWLOCK_P(lock)); uv_rwlock_wrunlock(PHP_UV_LOCK_RWLOCK_P(lock));
lock->locked = 0x00; } else if (lock->locked) {
php_error_docref(NULL, E_NOTICE, "uv_rwlock: still locked resource detected; forcing rdunlock");
while (--lock->locked > 0) {
uv_rwlock_rdunlock(PHP_UV_LOCK_RWLOCK_P(lock));
}
} }
uv_rwlock_destroy(PHP_UV_LOCK_RWLOCK_P(lock)); uv_rwlock_destroy(PHP_UV_LOCK_RWLOCK_P(lock));
} else if (lock->type == IS_UV_MUTEX) { } else if (lock->type == IS_UV_MUTEX) {
if (lock->locked == 0x01) { if (lock->locked == 0x01) {
php_error_docref(NULL, E_NOTICE, "uv_mutex: unlocked resoruce detected. force unlock resource."); php_error_docref(NULL, E_NOTICE, "uv_mutex: still locked resource detected; forcing unlock");
uv_mutex_unlock(PHP_UV_LOCK_MUTEX_P(lock)); uv_mutex_unlock(PHP_UV_LOCK_MUTEX_P(lock));
lock->locked = 0x00;
} }
uv_mutex_destroy(PHP_UV_LOCK_MUTEX_P(lock)); uv_mutex_destroy(PHP_UV_LOCK_MUTEX_P(lock));
} else if (lock->type == IS_UV_SEMAPHORE) { } else if (lock->type == IS_UV_SEMAPHORE) {
if (lock->locked == 0x01) { if (lock->locked == 0x01) {
php_error_docref(NULL, E_NOTICE, "uv_sem: unlocked resoruce detected. force unlock resource."); php_error_docref(NULL, E_NOTICE, "uv_sem: still locked resource detected; forcing unlock");
uv_sem_post(PHP_UV_LOCK_SEM_P(lock)); uv_sem_post(PHP_UV_LOCK_SEM_P(lock));
lock->locked = 0x00;
} }
uv_sem_destroy(PHP_UV_LOCK_SEM_P(lock)); uv_sem_destroy(PHP_UV_LOCK_SEM_P(lock));
} }

View File

@ -1,5 +1,7 @@
--TEST-- --TEST--
Check for uv_rwlock Check for uv_rwlock
--INI--
track_errors=0
--FILE-- --FILE--
<?php <?php
$lock = uv_rwlock_init(); $lock = uv_rwlock_init();
@ -20,4 +22,6 @@ if (uv_rwlock_tryrdlock($lock)) {
uv_rwlock_rdunlock($lock); uv_rwlock_rdunlock($lock);
--EXPECT-- --EXPECT--
OK OK
OK OK
Notice: Unknown: uv_rwlock: still locked resource detected; forcing rdunlock in Unknown on line 0