ffrt mutex/recursive_mutex api normalization

Signed-off-by: yuanzhipu <2710242656@qq.com>
This commit is contained in:
yuanzhipu 2024-07-27 20:04:07 +08:00
parent b92ceb53c8
commit 36663943b6
7 changed files with 224 additions and 147 deletions

View File

@ -2451,6 +2451,18 @@ typedef enum {
struct ffrt_mutex_t;
struct ffrt_mutexattr_t;
typedef enum {
ffrt_mutex_normal = PTHREAD_MUTEX_NORMAL,
ffrt_mutex_recursive = PTHREAD_MUTEX_RECURSIVE,
ffrt_mutex_default = ffrt_mutex_normal
} ffrt_mutex_type;
int ffrt_mutexattr_init(ffrt_mutexattr_t* attr);
int ffrt_mutexattr_settype(ffrt_mutexattr_t* attr, int type);
int ffrt_mutexattr_gettype(ffrt_mutexattr_t* attr, int* type);
int ffrt_mutexattr_destroy(ffrt_mutexattr_t* attr);
int ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr);
int ffrt_mutex_lock(ffrt_mutex_t* mutex);
int ffrt_mutex_unlock(ffrt_mutex_t* mutex);
@ -2459,14 +2471,17 @@ int ffrt_mutex_destroy(ffrt_mutex_t* mutex);
```
#### 参数
`type`
* FFRT锁类型当前仅支持互斥锁ffrt_mutex_normal和递归锁ffrt_mutex_recursive
`attr`
* 当前FFRT只支持基础类型的mutex因此attr必须为空指针
* FFRT锁属性attr如果为空指针代表互斥锁mutex
`mutex`
* 指向所操作的互斥指针
* 指向所操作的锁指针
#### 返回值
@ -2475,9 +2490,12 @@ int ffrt_mutex_destroy(ffrt_mutex_t* mutex);
#### 描述
* 该接口只能在FFRT task 内部调用在FFRT task 外部调用存在未定义的行为
* 该功能能够避免pthread传统的pthread_mutex_t 在抢不到锁时陷入内核的问题,在使用得当的条件下将会有更好的性能
* **注意:目前暂不支持递归和定时功能**
* **注意:目前暂不支持定时功能**
* **注意C API中的ffrt_mutexattr_t需要用户调用`ffrt_mutexattr_init`和`ffrt_mutexattr_destroy`显示创建和销毁而C++ API无需该操作**
* **注意C API中的ffrt_mutex_t需要用户调用`ffrt_mutex_init`和`ffrt_mutex_destroy`显式创建和销毁而C++ API无需该操作**
* **注意C API中的ffrt_mutex_t对象的置空和销毁由用户完成对同一个ffrt_mutex_t仅能调用一次`ffrt_mutex_destroy`重复对同一个ffrt_mutex_t调用`ffrt_mutex_destroy`,其行为是未定义的**
* **注意C API中的同一个ffrt_mutexattr_t只能调用一次`ffrt_mutexattr_init`和`ffrt_mutexattr_destroy`,重复调用其行为是未定义的**
* **注意:用户需要在调用`ffrt_mutex_init`之后和调用`ffrt_mutex_destroy`之前显示调用`ffrt_mutexattr_destroy`**
* **注意:在`ffrt_mutex_destroy`之后再对ffrt_mutex_t进行访问其行为是未定义的**
#### 样例
@ -2567,11 +2585,43 @@ void ffrt_mutex_task()
printf("sum = %d", sum);
}
void ffrt_recursive_mutex_task()
{
int sum = 0;
int ret = 0;
ffrt_mutexattr_t attr;
ffrt_mutex_t mtx;
ret = ffrt_mutexattr_init(&attr);
if (ret != ffrt_success) {
printf("mutexattr init error\n");
}
ret = ffrt_mutexattr_settype(&attr, ffrt_mutex_recursive);
if (ret != ffrt_success) {
printf("mutexattr settype error\n");
}
tuple t = {&sum, &mtx};
int ret = ffrt_mutex_init(&mtx, &attr);
if (ret != ffrt_success) {
printf("error\n");
}
for (int i = 0; i < 10; i++) {
ffrt_submit_c(func, NULL, &t, NULL, NULL, NULL);
}
ffrt_mutexattr_destory(&attr);
ffrt_mutex_destroy(&mtx);
ffrt_wait();
printf("sum = %d", sum);
}
int main(int narg, char** argv)
{
int r;
/* mutex */
ffrt_submit_c(ffrt_mutex_task, NULL, NULL, NULL, NULL, NULL);
ffrt_wait();
/* recursive mutex */
ffrt_submit_c(ffrt_recursive_mutex_task, NULL, NULL, NULL, NULL, NULL);
ffrt_wait();
return 0;
}
```

View File

@ -38,6 +38,53 @@
#define FFRT_API_C_MUTEX_H
#include "type_def.h"
/**
* @brief Initializes mutex attr.
*
* @param mutex Indicates a pointer to the mutex.
* @param attr Indicates a pointer to the mutex attribute.
* @return Returns <b>ffrt_thrd_success</b> if the mutexattr is initialized;
returns <b>ffrt_thrd_error</b> otherwise.
* @since 12
* @version 1.0
*/
FFRT_C_API int ffrt_mutexattr_init(ffrt_mutexattr_t* attr);
/**
* @brief set mutex type.
*
* @param attr Indicates a pointer to the mutex attribute.
* @param type Indicates a int to the mutex type.
* @return Returns <b>ffrt_thrd_success</b> if the mutexattr type is set;
returns <b>ffrt_thrd_error</b> otherwise.
* @since 12
* @version 1.0
*/
FFRT_C_API int ffrt_mutexattr_settype(ffrt_mutexattr_t* attr, int type);
/**
* @brief get mutex type.
*
* @param attr Indicates a pointer to the mutex attribute.
* @param type Indicates a pointer to the mutex type.
* @return Returns <b>ffrt_thrd_success</b> if the mutexattr is initialized;
returns <b>ffrt_thrd_error</b> otherwise.
* @since 12
* @version 1.0
*/
FFRT_C_API int ffrt_mutexattr_gettype(ffrt_mutexattr_t* attr, int* type);
/**
* @brief destroy mutex attr, the user needs to invoke this interface.
*
* @param attr Indicates a pointer to the mutex attribute.
* @return Returns <b>ffrt_thrd_success</b> if the mutexattr is destroyed;
returns <b>ffrt_thrd_error</b> otherwise.
* @since 12
* @version 1.0
*/
FFRT_C_API int ffrt_mutexattr_destroy(ffrt_mutexattr_t* attr);
/**
* @brief Initializes a mutex.
*
@ -93,60 +140,4 @@ FFRT_C_API int ffrt_mutex_trylock(ffrt_mutex_t* mutex);
* @version 1.0
*/
FFRT_C_API int ffrt_mutex_destroy(ffrt_mutex_t* mutex);
/**
* @brief Initializes a recursive mutex.
*
* @param mutex Indicates a pointer to the mutex.
* @param attr Indicates a pointer to the mutex attribute.
* @return Returns <b>ffrt_thrd_success</b> if the mutex is initialized;
returns <b>ffrt_thrd_error</b> otherwise.
* @since 10
* @version 1.0
*/
FFRT_C_API int ffrt_recursive_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr);
/**
* @brief Locks a recursive mutex.
*
* @param mutex Indicates a pointer to the mutex.
* @return Returns <b>ffrt_thrd_success</b> if the mutex is locked;
returns <b>ffrt_thrd_error</b> or blocks the calling thread otherwise.
* @since 10
* @version 1.0
*/
FFRT_C_API int ffrt_recursive_mutex_lock(ffrt_mutex_t* mutex);
/**
* @brief Unlocks a recursive mutex.
*
* @param mutex Indicates a pointer to the mutex.
* @return Returns <b>ffrt_thrd_success</b> if the mutex is unlocked;
returns <b>ffrt_thrd_error</b> otherwise.
* @since 10
* @version 1.0
*/
FFRT_C_API int ffrt_recursive_mutex_unlock(ffrt_mutex_t* mutex);
/**
* @brief Attempts to lock a recursive mutex.
*
* @param mutex Indicates a pointer to the mutex.
* @return Returns <b>ffrt_thrd_success</b> if the mutex is locked;
returns <b>ffrt_thrd_error</b> or <b>ffrt_thrd_busy</b> otherwise.
* @since 10
* @version 1.0
*/
FFRT_C_API int ffrt_recursive_mutex_trylock(ffrt_mutex_t* mutex);
/**
* @brief Destroys a recursive mutex.
*
* @param mutex Indicates a pointer to the mutex.
* @return Returns <b>ffrt_thrd_success</b> if the mutex is destroyed;
returns <b>ffrt_thrd_error</b> otherwise.
* @since 10
* @version 1.0
*/
FFRT_C_API int ffrt_recursive_mutex_destroy(ffrt_mutex_t* mutex);
#endif

View File

@ -37,6 +37,7 @@
*/
#ifndef FFRT_API_C_TYPE_DEF_H
#define FFRT_API_C_TYPE_DEF_H
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
@ -183,6 +184,12 @@ typedef struct {
long storage;
} ffrt_mutexattr_t;
typedef enum {
ffrt_mutex_normal = PTHREAD_MUTEX_NORMAL,
ffrt_mutex_recursive = PTHREAD_MUTEX_RECURSIVE,
ffrt_mutex_default = ffrt_mutex_normal
} ffrt_mutex_type;
typedef struct {
uint32_t storage[(ffrt_mutex_storage_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
} ffrt_mutex_t;

View File

@ -61,11 +61,14 @@ class recursive_mutex : public ffrt_mutex_t {
public:
recursive_mutex()
{
ffrt_recursive_mutex_init(this, nullptr);
ffrt_mutexattr_init(&attr);
ffrt_mutexattr_settype(&attr, ffrt_mutex_recursive);
ffrt_recursive_mutex_init(this, &attr);
}
~recursive_mutex()
{
ffrt_mutexattr_destroy(&attr);
ffrt_recursive_mutex_destroy(this);
}
@ -74,18 +77,20 @@ public:
inline bool try_lock()
{
return ffrt_recursive_mutex_trylock(this) == ffrt_success ? true : false;
return ffrt_mutex_trylock(this) == ffrt_success ? true : false;
}
inline void lock()
{
ffrt_recursive_mutex_lock(this);
ffrt_mutex_lock(this);
}
inline void unlock()
{
ffrt_recursive_mutex_unlock(this);
ffrt_mutex_unlock(this);
}
private:
ffrt_mutexattr_t attr;
};
} // namespace ffrt
#endif

View File

@ -280,6 +280,53 @@ void mutexPrivate::wake()
#ifdef __cplusplus
extern "C" {
#endif
API_ATTRIBUTE((visibility("default")))
int ffrt_mutexattr_init(ffrt_mutexattr_t* attr)
{
if (attr == nullptr) {
FFRT_LOGE("attr should not be empty");
return ffrt_error_inval;
}
attr->storage = static_cast<long>(ffrt_mutex_dafault);
return ffrt_success;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_mutexattr_settype(ffrt_mutexattr_t* attr, int type)
{
if (attr == nullptr) {
FFRT_LOGE("attr should not be empty");
return ffrt_error_inval;
}
if (type != ffrt_mutex_normal && type != ffrt_mutex_recursive && type != ffrt_mutex_default) {
FFRT_LOGE("mutex type is invaild");
return ffrt_error_inval;
}
attr->storage = static_cast<long>(type);
return ffrt_success;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_mutexattr_gettype(ffrt_mutexattr_t* attr, int* type)
{
if (attr == nullptr || type == nullptr) {
FFRT_LOGE("attr or type should not be empty");
return ffrt_error_inval;
}
*type = static_cast<int>(attr->storage);
return ffrt_success;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_mutexattr_destroy(ffrt_mutexattr_t* attr)
{
if (attr == nullptr) {
FFRT_LOGE("attr should not be empty");
return ffrt_error_inval;
}
return ffrt_success;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr)
{
@ -287,33 +334,18 @@ int ffrt_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr)
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
if (attr != nullptr) {
FFRT_LOGE("only support normal mutex");
return ffrt_error;
}
static_assert(sizeof(ffrt::mutexPrivate) <= ffrt_mutex_storage_size,
if (attr == nullptr || attr->storage == static_cast<long>(ffrt_mutex_normal)) {
static_assert(sizeof(ffrt::mutexPrivate) <= ffrt_mutex_storage_size,
"size must be less than ffrt_mutex_storage_size");
new (mutex)ffrt::mutexPrivate();
return ffrt_success;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_recursive_mutex_init(ffrt_mutex_t* mutex, const ffrt_mutexattr_t* attr)
{
if (!mutex) {
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
if (attr != nullptr) {
FFRT_LOGE("only support normal mutex");
return ffrt_error;
}
static_assert(sizeof(ffrt::RecursiveMutexPrivate) <= ffrt_mutex_storage_size,
new (mutex)ffrt::mutexPrivate();
return ffrt_success;
} else if (attr->storage == static_cast<long>(ffrt_mutex_recursive)) {
static_assert(sizeof(ffrt::RecursiveMutexPrivate) <= ffrt_mutex_storage_size,
"size must be less than ffrt_mutex_storage_size");
new (mutex)ffrt::RecursiveMutexPrivate();
return ffrt_success;
new (mutex)ffrt::RecursiveMutexPrivate();
return ffrt_success;
}
return ffrt_error_inval;
}
API_ATTRIBUTE((visibility("default")))
@ -323,19 +355,7 @@ int ffrt_mutex_lock(ffrt_mutex_t* mutex)
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
auto p = reinterpret_cast<ffrt::mutexPrivate*>(mutex);
p->lock();
return ffrt_success;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_recursive_mutex_lock(ffrt_mutex_t* mutex)
{
if (!mutex) {
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
auto p = reinterpret_cast<ffrt::RecursiveMutexPrivate*>(mutex);
auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
p->lock();
return ffrt_success;
}
@ -347,19 +367,7 @@ int ffrt_mutex_unlock(ffrt_mutex_t* mutex)
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
auto p = reinterpret_cast<ffrt::mutexPrivate*>(mutex);
p->unlock();
return ffrt_success;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_recursive_mutex_unlock(ffrt_mutex_t* mutex)
{
if (!mutex) {
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
auto p = reinterpret_cast<ffrt::RecursiveMutexPrivate*>(mutex);
auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
p->unlock();
return ffrt_success;
}
@ -371,18 +379,7 @@ int ffrt_mutex_trylock(ffrt_mutex_t* mutex)
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
auto p = reinterpret_cast<ffrt::mutexPrivate*>(mutex);
return p->try_lock() ? ffrt_success : ffrt_error_busy;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_recursive_mutex_trylock(ffrt_mutex_t* mutex)
{
if (!mutex) {
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
auto p = reinterpret_cast<ffrt::RecursiveMutexPrivate*>(mutex);
auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
return p->try_lock() ? ffrt_success : ffrt_error_busy;
}
@ -393,23 +390,11 @@ int ffrt_mutex_destroy(ffrt_mutex_t* mutex)
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
auto p = reinterpret_cast<ffrt::mutexPrivate*>(mutex);
auto p = reinterpret_cast<ffrt::mutexBase*>(mutex);
p->~mutexPrivate();
return ffrt_success;
}
API_ATTRIBUTE((visibility("default")))
int ffrt_recursive_mutex_destroy(ffrt_mutex_t* mutex)
{
if (!mutex) {
FFRT_LOGE("mutex should not be empty");
return ffrt_error_inval;
}
auto p = reinterpret_cast<ffrt::RecursiveMutexPrivate*>(mutex);
p->~RecursiveMutexPrivate();
return ffrt_success;
}
#ifdef __cplusplus
}
#endif

View File

@ -100,7 +100,16 @@ public:
};
#endif
class mutexPrivate {
class mutexBase {
public:
mutexBase() = default;
virtual ~mutexBase() = default;
virtual void lock() {}
virtual void unlock() {}
virtual bool try_lock() {return false;}
};
class mutexPrivate : public mutexBase {
std::atomic<int> l;
#ifdef FFRT_MUTEX_DEADLOCK_CHECK
std::atomic<uintptr_t> owner;
@ -120,16 +129,16 @@ public:
mutexPrivate(mutexPrivate const &) = delete;
void operator = (mutexPrivate const &) = delete;
bool try_lock();
void lock();
void unlock();
bool try_lock() override;
void lock() override;
void unlock() override;
};
class RecursiveMutexPrivate {
class RecursiveMutexPrivate : public mutexBase {
public:
void lock();
void unlock();
bool try_lock();
void lock() override;
void unlock() override;
bool try_lock() override;
RecursiveMutexPrivate() = default;
~RecursiveMutexPrivate() = default;

View File

@ -23,6 +23,10 @@
#include "dfx/log/ffrt_log_api.h"
#include "c/thread.h"
extern "C" int ffrt_mutexattr_init(ffrt_mutexattr_t* attr);
extern "C" int ffrt_mutexattr_settype(ffrt_mutexattr_t* attr, int type);
extern "C" int ffrt_mutexattr_gettype(ffrt_mutexattr_t* attr, int* type);
extern "C" int ffrt_mutexattr_destroy(ffrt_mutexattr_t* attr);
extern "C" int ffrt_mutex_init(ffrt_mutex_t *mutex, const ffrt_mutexattr_t* attr);
extern "C" int ffrt_mutex_lock(ffrt_mutex_t *mutex);
extern "C" int ffrt_mutex_unlock(ffrt_mutex_t *mutex);
@ -51,6 +55,18 @@ protected:
}
};
HWTEST_F(SyncTest, mutexattr_nullptr_fail, TestSize.Level1)
{
int ret = ffrt_mutexattr_init(nullptr);
EXPECT_EQ(ret, ffrt_error_inval);
ret = ffrt_mutexattr_settype(nullptr, 0);
EXPECT_EQ(ret, ffrt_error_inval);
ret = ffrt_mutexattr_gettype(nullptr, nullptr);
EXPECT_EQ(ret, ffrt_error_inval);
ret = ffrt_mutexattr_destroy(nullptr);
EXPECT_EQ(ret, ffrt_error_inval);
}
HWTEST_F(SyncTest, mutex_nullptr_fail, TestSize.Level1)
{
int ret = ffrt_mutex_init(nullptr, nullptr);
@ -64,6 +80,20 @@ HWTEST_F(SyncTest, mutex_nullptr_fail, TestSize.Level1)
ffrt_mutex_destroy(nullptr);
}
HWTEST_F(SyncTest, recursive_mutex_try_lock, TestSize.Level1)
{
int val = -1;
ffrt::recursive_mutex lock;
lock.lock();
val = lock.try_lock();
EXPECT_EQ(val, 1);
lock.unlock();
val = lock.try_lock();
EXPECT_EQ(val, 1);
lock.unlock();
lock.unlock();
}
HWTEST_F(SyncTest, class_data_align, TestSize.Level1)
{
struct memTest {