drivers/sensors: sensor deadlock fix.

remove lock when driver run set_interval and batch to avoid deadlock

Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
dongjiuzhu1
2024-12-02 11:14:15 +08:00
committed by Xiang Xiao
parent b45a658f67
commit 6203332457
+52 -6
View File
@@ -260,6 +260,8 @@ static int sensor_update_interval(FAR struct file *filep,
uint32_t min_interval = interval;
uint32_t min_latency = interval != UINT32_MAX ?
user->state.latency : UINT32_MAX;
uint32_t orig_min_interval;
uint32_t orig_min_latency;
int ret = 0;
if (interval == user->state.interval)
@@ -267,6 +269,8 @@ static int sensor_update_interval(FAR struct file *filep,
return 0;
}
nxrmutex_lock(&upper->lock);
again:
list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node)
{
if (tmp == user || tmp->state.interval == UINT32_MAX)
@@ -291,6 +295,8 @@ static int sensor_update_interval(FAR struct file *filep,
min_interval != upper->state.min_interval)
{
uint32_t expected_interval = min_interval;
orig_min_interval = upper->state.min_interval;
nxrmutex_unlock(&upper->lock);
ret = lower->ops->set_interval(lower, filep, &min_interval);
if (ret < 0)
{
@@ -300,6 +306,17 @@ static int sensor_update_interval(FAR struct file *filep,
{
return -EINVAL;
}
nxrmutex_lock(&upper->lock);
/* The upper min_interval is updated by other threads, set to
* driver again to avoid race condition.
*/
if (orig_min_interval != upper->state.min_interval)
{
goto again;
}
}
if (min_latency == UINT32_MAX)
@@ -311,7 +328,20 @@ static int sensor_update_interval(FAR struct file *filep,
(min_latency != upper->state.min_latency ||
(min_interval != upper->state.min_interval && min_latency)))
{
orig_min_latency = upper->state.min_latency;
nxrmutex_unlock(&upper->lock);
ret = lower->ops->batch(lower, filep, &min_latency);
nxrmutex_lock(&upper->lock);
/* The upper min_latency is updated by other threads, set to
* driver again to avoid race condition.
*/
if (orig_min_latency != upper->state.min_latency)
{
goto again;
}
if (ret >= 0)
{
upper->state.min_latency = min_latency;
@@ -322,6 +352,7 @@ static int sensor_update_interval(FAR struct file *filep,
upper->state.min_interval = min_interval;
user->state.interval = interval;
sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR);
nxrmutex_unlock(&upper->lock);
return ret;
}
@@ -333,6 +364,7 @@ static int sensor_update_latency(FAR struct file *filep,
FAR struct sensor_lowerhalf_s *lower = upper->lower;
FAR struct sensor_user_s *tmp;
uint32_t min_latency = latency;
uint32_t orig_min_latency;
int ret = 0;
if (latency == user->state.latency)
@@ -346,6 +378,8 @@ static int sensor_update_latency(FAR struct file *filep,
return 0;
}
nxrmutex_lock(&upper->lock);
again:
if (latency <= upper->state.min_latency)
{
goto update;
@@ -373,21 +407,36 @@ update:
if (min_latency == upper->state.min_latency)
{
user->state.latency = latency;
nxrmutex_unlock(&upper->lock);
return ret;
}
if (lower->ops->batch)
{
orig_min_latency = upper->state.min_latency;
nxrmutex_unlock(&upper->lock);
ret = lower->ops->batch(lower, filep, &min_latency);
if (ret < 0)
{
return ret;
}
nxrmutex_lock(&upper->lock);
/* The upper min_latency is updated by other threads, set to
* driver again to avoid race condition.
*/
if (orig_min_latency != upper->state.min_latency)
{
goto again;
}
}
upper->state.min_latency = min_latency;
user->state.latency = latency;
sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR);
nxrmutex_unlock(&upper->lock);
return ret;
}
@@ -726,8 +775,6 @@ static int sensor_close(FAR struct file *filep)
}
list_delete(&user->node);
sensor_update_latency(filep, upper, user, UINT32_MAX);
sensor_update_interval(filep, upper, user, UINT32_MAX);
nxsem_destroy(&user->buffersem);
/* The user is closed, notify to other users */
@@ -735,6 +782,9 @@ static int sensor_close(FAR struct file *filep)
sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR);
nxrmutex_unlock(&upper->lock);
sensor_update_latency(filep, upper, user, UINT32_MAX);
sensor_update_interval(filep, upper, user, UINT32_MAX);
kmm_free(user);
return ret;
}
@@ -855,18 +905,14 @@ static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
case SNIOC_SET_INTERVAL:
{
nxrmutex_lock(&upper->lock);
ret = sensor_update_interval(filep, upper, user,
arg1 ? arg1 : UINT32_MAX);
nxrmutex_unlock(&upper->lock);
}
break;
case SNIOC_BATCH:
{
nxrmutex_lock(&upper->lock);
ret = sensor_update_latency(filep, upper, user, arg1);
nxrmutex_unlock(&upper->lock);
}
break;