From 30f0de876c12c5eca37ecf9367ccab0aad7f2ecf Mon Sep 17 00:00:00 2001 From: xuxiaoqing Date: Sat, 28 Jan 2023 16:25:04 +0800 Subject: [PATCH] feat: optimize interrupt performance in user mode Signed-off-by: xuxiaoqing --- .../syscall/include/hdf_syscall_adapter.h | 3 +- .../adapter/syscall/src/hdf_syscall_adapter.c | 44 ++- .../adapter/vnode/src/hdf_vnode_adapter.c | 227 +++++++++-- .../unittest/common/hdf_ioservice_test.cpp | 354 +++++++++++++++--- framework/include/core/hdf_io_service_if.h | 32 +- framework/include/osal/osal_thread.h | 3 +- framework/support/posix/src/osal_thread.c | 33 +- framework/test/unittest/osal/osal_all_test.c | 130 ++++++- framework/utils/src/hdf_thread_ex.c | 7 +- 9 files changed, 716 insertions(+), 117 deletions(-) diff --git a/framework/core/adapter/syscall/include/hdf_syscall_adapter.h b/framework/core/adapter/syscall/include/hdf_syscall_adapter.h index 2dd041d7e..02c5be54e 100644 --- a/framework/core/adapter/syscall/include/hdf_syscall_adapter.h +++ b/framework/core/adapter/syscall/include/hdf_syscall_adapter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Copyright (c) 2020-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. @@ -36,6 +36,7 @@ struct HdfDevListenerThread { bool shouldStop; struct DListHead *listenerListPtr; uint8_t status; + int policy; }; struct HdfSyscallAdapter { diff --git a/framework/core/adapter/syscall/src/hdf_syscall_adapter.c b/framework/core/adapter/syscall/src/hdf_syscall_adapter.c index 9bf19430f..beb84d8a2 100644 --- a/framework/core/adapter/syscall/src/hdf_syscall_adapter.c +++ b/framework/core/adapter/syscall/src/hdf_syscall_adapter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Copyright (c) 2020-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -341,6 +342,7 @@ static int32_t HdfDevListenerThreadDoInit(struct HdfDevListenerThread *thread) thread->status = LISTENER_INITED; thread->shouldStop = false; thread->pollChanged = true; + thread->policy = SCHED_OTHER; return HDF_SUCCESS; } @@ -465,6 +467,7 @@ static int32_t HdfDevListenerThreadStart(struct HdfDevListenerThread *thread) .name = "evt_listen", .priority = OSAL_THREAD_PRI_DEFAULT, .stackSize = 0, + .policy = thread->policy, }; thread->status = LISTENER_STARTED; @@ -507,13 +510,14 @@ static int32_t HdfIoServiceGroupThreadInit(struct HdfSyscallAdapterGroup *group) return HdfDevListenerThreadInit(group->thread); } -static int32_t HdfIoServiceGroupThreadStart(struct HdfSyscallAdapterGroup *group) +static int32_t HdfIoServiceGroupThreadStart(struct HdfSyscallAdapterGroup *group, int policy) { OsalMutexLock(&group->mutex); if (HdfIoServiceGroupThreadInit(group) != HDF_SUCCESS) { OsalMutexUnlock(&group->mutex); return HDF_FAILURE; } + group->thread->policy = policy; int32_t ret = HdfDevListenerThreadStart(group->thread); OsalMutexUnlock(&group->mutex); return ret; @@ -806,12 +810,13 @@ static int32_t HdfIoServiceThreadBindLocked(struct HdfSyscallAdapter *adapter) return HdfDevListenerThreadInit(adapter->thread); } -static int32_t HdfIoServiceStartListen(struct HdfSyscallAdapter *adapter) +static int32_t HdfIoServiceStartListen(struct HdfSyscallAdapter *adapter, int policy) { if (HdfIoServiceThreadBindLocked(adapter) != HDF_SUCCESS) { HDF_LOGE("%s: Failed to bind a thread to SyscallAdapter", __func__); return HDF_FAILURE; } + adapter->thread->policy = policy; return HdfDevListenerThreadStart(adapter->thread); } @@ -829,14 +834,20 @@ static bool AddListenerToAdapterLocked(struct HdfSyscallAdapter *adapter, struct return true; } -int32_t HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener) +int32_t HdfDeviceRegisterEventListenerWithSchedPolicy( + struct HdfIoService *target, struct HdfDevEventlistener *listener, int policy) { if (target == NULL || listener == NULL) { return HDF_ERR_INVALID_PARAM; } + if (policy != SCHED_FIFO && policy != SCHED_RR && policy != SCHED_OTHER) { + HDF_LOGE("%{public}s: Register event listener with invalid sched policy", __func__); + return HDF_ERR_INVALID_PARAM; + } + if (listener->callBack == NULL && listener->onReceive == NULL) { - HDF_LOGE("Listener onReceive func not implemented"); + HDF_LOGE("%{public}s: Listener onReceive func not implemented", __func__); return HDF_ERR_INVALID_OBJECT; } @@ -851,12 +862,12 @@ int32_t HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDe if (adapter->group != NULL) { /* Do not bind any service in a service goup to its own thread or start the group thread. */ - ret = HdfIoServiceGroupThreadStart(adapter->group); + ret = HdfIoServiceGroupThreadStart(adapter->group, policy); OsalMutexUnlock(&adapter->mutex); return ret; } - if (HdfIoServiceStartListen(adapter) != HDF_SUCCESS) { + if (HdfIoServiceStartListen(adapter, policy) != HDF_SUCCESS) { DListRemove(&listener->listNode); ret = HDF_FAILURE; } @@ -865,6 +876,11 @@ int32_t HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDe return ret; } +int32_t HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener) +{ + return HdfDeviceRegisterEventListenerWithSchedPolicy(target, listener, SCHED_OTHER); +} + int32_t HdfDeviceUnregisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener) { if (target == NULL || listener == NULL) { @@ -931,12 +947,18 @@ void HdfIoServiceGroupRecycle(struct HdfIoServiceGroup *group) OsalMemFree(adapterGroup); } -int32_t HdfIoServiceGroupRegisterListener(struct HdfIoServiceGroup *group, struct HdfDevEventlistener *listener) +int32_t HdfIoServiceGroupRegisterListenerWithSchedPolicy( + struct HdfIoServiceGroup *group, struct HdfDevEventlistener *listener, int policy) { if (group == NULL || listener == NULL) { return HDF_ERR_INVALID_PARAM; } + if (policy != SCHED_FIFO && policy != SCHED_RR && policy != SCHED_OTHER) { + HDF_LOGE("Group register event listener with invalid sched policy"); + return HDF_ERR_INVALID_PARAM; + } + if (listener->callBack == NULL && listener->onReceive == NULL) { HDF_LOGE("Listener onReceive func not implemented"); return HDF_ERR_INVALID_OBJECT; @@ -952,6 +974,7 @@ int32_t HdfIoServiceGroupRegisterListener(struct HdfIoServiceGroup *group, struc int32_t ret = HDF_SUCCESS; struct HdfDevListenerThread *listenerThread = adapterGroup->thread; + listenerThread->policy = policy; OsalMutexLock(&listenerThread->mutex); struct HdfDevEventlistener *it = NULL; @@ -976,6 +999,11 @@ FINISH: return ret; } +int32_t HdfIoServiceGroupRegisterListener(struct HdfIoServiceGroup *group, struct HdfDevEventlistener *listener) +{ + return HdfIoServiceGroupRegisterListenerWithSchedPolicy(group, listener, SCHED_OTHER); +} + static int32_t GetListenerCount(struct HdfDevListenerThread *thread) { struct HdfDevEventlistener *listener = NULL; diff --git a/framework/core/adapter/vnode/src/hdf_vnode_adapter.c b/framework/core/adapter/vnode/src/hdf_vnode_adapter.c index c8d7bfc1f..77d240cf5 100644 --- a/framework/core/adapter/vnode/src/hdf_vnode_adapter.c +++ b/framework/core/adapter/vnode/src/hdf_vnode_adapter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Copyright (c) 2020-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. @@ -17,10 +17,11 @@ #include "hdf_log.h" #include "hdf_sbuf.h" -#define HDF_LOG_TAG hdf_vnode -#define VOID_DATA_SIZE 4 -#define EVENT_QUEUE_MAX 100 -#define MAX_RW_SIZE (1024 * 1204) // 1M +#define HDF_LOG_TAG hdf_vnode +#define VOID_DATA_SIZE 4 +#define EVENT_QUEUE_MAX 100 +#define EVENT_RINGBUFFER_MAX 10 +#define MAX_RW_SIZE (1024 * 1204) // 1M enum HdfVNodeClientStatus { VNODE_CLIENT_RUNNING, @@ -40,6 +41,10 @@ struct HdfVNodeAdapterClient { int32_t eventQueueSize; int32_t wakeup; uint32_t status; + struct HdfDevEvent *eventRingBuffer[EVENT_RINGBUFFER_MAX]; + volatile uint32_t readCursor; + volatile uint32_t writeCursor; + volatile bool writeHeadEvent; }; struct HdfIoServiceKClient { @@ -246,19 +251,103 @@ static int HdfVNodeAdapterServCall(const struct HdfVNodeAdapterClient *client, u return ret; } +static int EventDataProcess(struct HdfDevEvent *event, struct HdfWriteReadBuf *bwr, struct HdfWriteReadBuf *bwrUser) +{ + int ret = HDF_SUCCESS; + size_t eventSize = HdfSbufGetDataSize(event->data); + if (eventSize > bwr->readSize) { + bwr->readSize = eventSize; + ret = HDF_DEV_ERR_NORANGE; + } else { + if (HdfSbufCopyToUser(event->data, (void *)(uintptr_t)bwr->readBuffer, bwr->readSize) != HDF_SUCCESS) { + return HDF_ERR_IO; + } + bwr->readConsumed = eventSize; + bwr->cmdCode = (int32_t)event->id; + } + if (CopyToUser(bwrUser, bwr, sizeof(struct HdfWriteReadBuf)) != 0) { + HDF_LOGE("%s: failed to copy bwr", __func__); + ret = HDF_ERR_IO; + } + + return ret; +} + +static int ReadDeviceEventInRingBuffer( + struct HdfVNodeAdapterClient *client, struct HdfWriteReadBuf *bwr, struct HdfWriteReadBuf *bwrUser) +{ + struct HdfDevEvent *event = NULL; + int ret = HDF_SUCCESS; + uint32_t cursor; + + do { + event = NULL; + if (client->readCursor == client->writeCursor) { + break; + } + if (client->writeHeadEvent == true) { + HDF_LOGE("%{public}s: client->writeHeadEvent == true", __func__); + break; + } + cursor = client->readCursor; + event = client->eventRingBuffer[cursor]; + } while (!__sync_bool_compare_and_swap(&(client->readCursor), cursor, (cursor + 1) % EVENT_RINGBUFFER_MAX)); + + if (event == NULL) { + HDF_LOGE("%{public}s: eventRingBuffer is empty", __func__); + return HDF_DEV_ERR_NODATA; + } + + ret = EventDataProcess(event, bwr, bwrUser); + if (ret != HDF_SUCCESS) { + if (!__sync_bool_compare_and_swap(&(client->readCursor), (cursor + 1) % EVENT_RINGBUFFER_MAX, cursor)) { + HDF_LOGE("%{public}s: EventDataProcess failed and cursor had been changed, drop the event", __func__); + DevEventFree(event); + } + return ret; + } + DevEventFree(event); + + return ret; +} + +static int ReadDeviceEventInEventQueue( + struct HdfVNodeAdapterClient *client, struct HdfWriteReadBuf *bwr, struct HdfWriteReadBuf *bwrUser) +{ + struct HdfDevEvent *event = NULL; + int ret = HDF_SUCCESS; + + OsalMutexLock(&client->mutex); + if (DListIsEmpty(&client->eventQueue)) { + OsalMutexUnlock(&client->mutex); + HDF_LOGE("%{public}s: eventQueue is empty", __func__); + return HDF_DEV_ERR_NODATA; + } + event = CONTAINER_OF(client->eventQueue.next, struct HdfDevEvent, listNode); + ret = EventDataProcess(event, bwr, bwrUser); + if (ret != HDF_SUCCESS) { + OsalMutexUnlock(&client->mutex); + return ret; + } + DListRemove(&event->listNode); + client->eventQueueSize--; + OsalMutexUnlock(&client->mutex); + DevEventFree(event); + + return ret; +} + static int HdfVNodeAdapterReadDevEvent(struct HdfVNodeAdapterClient *client, unsigned long arg) { struct HdfWriteReadBuf bwr; struct HdfWriteReadBuf *bwrUser = (struct HdfWriteReadBuf *)((uintptr_t)arg); - struct HdfDevEvent *event = NULL; - size_t eventSize; - int ret = HDF_SUCCESS; + if (bwrUser == NULL) { return HDF_ERR_INVALID_PARAM; } - if (CopyFromUser(&bwr, (void*)bwrUser, sizeof(bwr)) != 0) { + if (CopyFromUser(&bwr, (void *)bwrUser, sizeof(bwr)) != 0) { HDF_LOGE("Copy from user failed"); return HDF_FAILURE; } @@ -266,38 +355,13 @@ static int HdfVNodeAdapterReadDevEvent(struct HdfVNodeAdapterClient *client, uns if (bwr.readSize > MAX_RW_SIZE) { return HDF_ERR_INVALID_PARAM; } - OsalMutexLock(&client->mutex); - - if (DListIsEmpty(&client->eventQueue)) { - OsalMutexUnlock(&client->mutex); - return HDF_DEV_ERR_NODATA; - } - event = CONTAINER_OF(client->eventQueue.next, struct HdfDevEvent, listNode); - eventSize = HdfSbufGetDataSize(event->data); - if (eventSize > bwr.readSize) { - bwr.readSize = eventSize; - ret = HDF_DEV_ERR_NORANGE; + if (!DListIsEmpty(&client->eventQueue)) { + ret = ReadDeviceEventInEventQueue(client, &bwr, bwrUser); } else { - if (HdfSbufCopyToUser(event->data, (void *)(uintptr_t)bwr.readBuffer, bwr.readSize) != HDF_SUCCESS) { - OsalMutexUnlock(&client->mutex); - return HDF_ERR_IO; - } - bwr.readConsumed = eventSize; - bwr.cmdCode = (int32_t)event->id; + ret = ReadDeviceEventInRingBuffer(client, &bwr, bwrUser); } - if (CopyToUser(bwrUser, &bwr, sizeof(struct HdfWriteReadBuf)) != 0) { - HDF_LOGE("%s: failed to copy bwr", __func__); - ret = HDF_ERR_IO; - } - if (ret == HDF_SUCCESS) { - DListRemove(&event->listNode); - DevEventFree(event); - client->eventQueueSize--; - } - - OsalMutexUnlock(&client->mutex); return ret; } @@ -348,6 +412,73 @@ static int VNodeAdapterSendDevEventToClient(struct HdfVNodeAdapterClient *vnodeC return HDF_SUCCESS; } +static void DropOldEventInRingBuffer(struct HdfVNodeAdapterClient *vnodeClient) +{ + struct HdfDevEvent *firstEvent = NULL; + uint32_t cursor; + char *nodePath = NULL; + + do { + cursor = vnodeClient->readCursor; + firstEvent = NULL; + if ((vnodeClient->writeCursor + 1) % EVENT_RINGBUFFER_MAX != vnodeClient->readCursor) { + break; + } + firstEvent = vnodeClient->eventRingBuffer[cursor]; + } while (!__sync_bool_compare_and_swap(&(vnodeClient->readCursor), cursor, (cursor + 1) % EVENT_RINGBUFFER_MAX)); + + if (firstEvent != NULL) { + if (vnodeClient->adapter != NULL) { + nodePath = vnodeClient->adapter->vNodePath; + HDF_LOGE("dev(%{public}s) event ringbuffer full, drop old one", nodePath == NULL ? "unknown" : nodePath); + } + DevEventFree(firstEvent); + } +} + +static void AddEventToRingBuffer(struct HdfVNodeAdapterClient *vnodeClient, struct HdfDevEvent *event) +{ + uint32_t cursor; + + if (vnodeClient->writeCursor == vnodeClient->readCursor) { + vnodeClient->writeHeadEvent = true; + } + do { + cursor = vnodeClient->writeCursor; + } while (!__sync_bool_compare_and_swap(&(vnodeClient->writeCursor), cursor, (cursor + 1) % EVENT_RINGBUFFER_MAX)); + + vnodeClient->eventRingBuffer[cursor] = event; + vnodeClient->writeHeadEvent = false; +} + +static int VNodeAdapterSendDevEventToClientNoLock( + struct HdfVNodeAdapterClient *vnodeClient, uint32_t id, const struct HdfSBuf *data) +{ + struct HdfDevEvent *event = NULL; + + if (vnodeClient->status != VNODE_CLIENT_LISTENING) { + return HDF_SUCCESS; + } + DropOldEventInRingBuffer(vnodeClient); + + event = OsalMemAlloc(sizeof(struct HdfDevEvent)); + if (event == NULL) { + return HDF_DEV_ERR_NO_MEMORY; + } + event->id = id; + event->data = HdfSbufCopy(data); + if (event->data == NULL) { + HDF_LOGE("%s: sbuf oom", __func__); + OsalMemFree(event); + return HDF_DEV_ERR_NO_MEMORY; + } + + AddEventToRingBuffer(vnodeClient, event); + wake_up_interruptible(&vnodeClient->pollWait); + + return HDF_SUCCESS; +} + static int HdfVNodeAdapterSendDevEvent(struct HdfVNodeAdapter *adapter, struct HdfVNodeAdapterClient *vnodeClient, uint32_t id, const struct HdfSBuf *data) { @@ -371,6 +502,19 @@ static int HdfVNodeAdapterSendDevEvent(struct HdfVNodeAdapter *adapter, struct H return ret; } +static int HdfVNodeAdapterSendDevEventNoLock( + struct HdfVNodeAdapter *adapter, struct HdfVNodeAdapterClient *vnodeClient, uint32_t id, const struct HdfSBuf *data) +{ + if (adapter == NULL || data == NULL || HdfSbufGetDataSize(data) == 0) { + return HDF_ERR_INVALID_PARAM; + } + if (vnodeClient != NULL) { + return VNodeAdapterSendDevEventToClientNoLock(vnodeClient, id, data); + } + + return HDF_FAILURE; +} + static void HdfVNodeAdapterClientStartListening(struct HdfVNodeAdapterClient *client) { OsalMutexLock(&client->mutex); @@ -469,6 +613,9 @@ static struct HdfVNodeAdapterClient *HdfNewVNodeAdapterClient(struct HdfVNodeAda client->ioServiceClient.device = (struct HdfDeviceObject *)adapter->ioService.target; client->ioServiceClient.priv = NULL; client->wakeup = 0; + client->readCursor = 0; + client->writeCursor = 0; + client->writeHeadEvent = false; init_waitqueue_head(&client->pollWait); OsalMutexLock(&adapter->mutex); DListInsertTail(&client->listNode, &adapter->clientList); @@ -539,6 +686,8 @@ static unsigned int HdfVNodeAdapterPoll(struct file *filep, poll_table *wait) mask |= POLLHUP; } else if (!DListIsEmpty(&client->eventQueue)) { mask |= POLLIN; + } else if (client->readCursor != client->writeCursor) { + mask |= POLLIN; } else if (client->wakeup > 0) { mask |= POLLIN; client->wakeup--; @@ -657,7 +806,7 @@ int32_t HdfDeviceSendEvent(const struct HdfDeviceObject *deviceObject, uint32_t return HDF_ERR_NOT_SUPPORT; } - adapter = (struct HdfVNodeAdapter *)(((struct DeviceNodeExt*)deviceNode)->ioService); + adapter = (struct HdfVNodeAdapter *)(((struct DeviceNodeExt *)deviceNode)->ioService); return HdfVNodeAdapterSendDevEvent(adapter, NULL, id, data); } @@ -673,5 +822,5 @@ int32_t HdfDeviceSendEventToClient(const struct HdfDeviceIoClient *client, uint3 return HDF_ERR_INVALID_PARAM; } - return HdfVNodeAdapterSendDevEvent(vnodeClient->adapter, vnodeClient, id, data); + return HdfVNodeAdapterSendDevEventNoLock(vnodeClient->adapter, vnodeClient, id, data); } diff --git a/framework/core/manager/test/unittest/common/hdf_ioservice_test.cpp b/framework/core/manager/test/unittest/common/hdf_ioservice_test.cpp index 108a7aa7c..20860e917 100644 --- a/framework/core/manager/test/unittest/common/hdf_ioservice_test.cpp +++ b/framework/core/manager/test/unittest/common/hdf_ioservice_test.cpp @@ -1,19 +1,21 @@ /* - * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Copyright (c) 2020-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ -#include +#include #include #include #include #include -#include -#include #include +#include +#include +#include + #include "hdf_io_service.h" #include "hdf_log.h" #include "hdf_power_state.h" @@ -24,6 +26,7 @@ #include "sample_driver_test.h" #include "svcmgr_ioservice.h" +namespace OHOS { using namespace testing::ext; struct Eventlistener { @@ -39,20 +42,31 @@ public: void TearDown(); static int OnDevEventReceived( struct HdfDevEventlistener *listener, struct HdfIoService *service, uint32_t id, struct HdfSBuf *data); + static int OnDevEventReceivedTest( + struct HdfDevEventlistener *listener, struct HdfIoService *service, uint32_t id, struct HdfSBuf *data); + static int OnDevEventReceivedTest1( + struct HdfDevEventlistener *listener, struct HdfIoService *service, uint32_t id, struct HdfSBuf *data); - void TestServiceStop(struct IoServiceStatusData* issd); + void TestServiceStop(struct IoServiceStatusData *issd); static struct Eventlistener listener0; static struct Eventlistener listener1; + static struct Eventlistener listener2; + static struct Eventlistener listener3; const char *testSvcName = SAMPLE_SERVICE; const int eventWaitTimeUs = (150 * 1000); + const int eventWaitTimeMs = 10; static int eventCount; const int servstatWaitTime = 15; // ms }; int IoServiceTest::eventCount = 0; +static OsalTimespec g_beginTime; +static OsalTimespec g_endTime; struct Eventlistener IoServiceTest::listener0; struct Eventlistener IoServiceTest::listener1; +struct Eventlistener IoServiceTest::listener2; +struct Eventlistener IoServiceTest::listener3; void IoServiceTest::SetUpTestCase() { @@ -61,6 +75,12 @@ void IoServiceTest::SetUpTestCase() listener1.listener.onReceive = OnDevEventReceived; listener1.listener.priv = const_cast(static_cast("listener1")); + + listener2.listener.onReceive = OnDevEventReceivedTest; + listener2.listener.priv = const_cast(static_cast("listener2")); + + listener3.listener.onReceive = OnDevEventReceivedTest1; + listener3.listener.priv = const_cast(static_cast("listener3")); } void IoServiceTest::TearDownTestCase() @@ -71,6 +91,8 @@ void IoServiceTest::SetUp() { listener0.eventCount = 0; listener1.eventCount = 0; + listener2.eventCount = 0; + listener3.eventCount = 0; eventCount = 0; } @@ -97,6 +119,43 @@ int IoServiceTest::OnDevEventReceived( return 0; } +int IoServiceTest::OnDevEventReceivedTest( + struct HdfDevEventlistener *listener, struct HdfIoService *service, uint32_t id, struct HdfSBuf *data) +{ + OsalTimespec time; + OsalGetTime(&time); + OsalGetTime(&g_endTime); + HDF_LOGE("%s: received event[%{public}d] from %s at %{public}" PRIu64 ".%{public}" PRIu64 "", + static_cast(listener->priv), eventCount++, static_cast(service->priv), time.sec, time.usec); + + const char *string = HdfSbufReadString(data); + if (string == nullptr) { + HDF_LOGE("failed to read string in event data"); + return 0; + } + struct Eventlistener *l = CONTAINER_OF(listener, struct Eventlistener, listener); + if (strcmp(string, static_cast(service->priv)) == 0) { + l->eventCount++; + } + HDF_LOGE("%{public}s: dev event received: %{public}u %{public}s", static_cast(service->priv), id, string); + return 0; +} + +int IoServiceTest::OnDevEventReceivedTest1( + struct HdfDevEventlistener *listener, struct HdfIoService *service, uint32_t id, struct HdfSBuf *data) +{ + const char *string = HdfSbufReadString(data); + if (string == nullptr) { + HDF_LOGE("failed to read string in event data"); + return 0; + } + struct Eventlistener *l = CONTAINER_OF(listener, struct Eventlistener, listener); + HDF_LOGI("%{public}s: read data size is %{public}d", static_cast(service->priv), strlen(string)); + HDF_LOGI("%{public}s: read data is %{public}s", static_cast(service->priv), string); + l->eventCount++; + return 0; +} + static int SendEvent(struct HdfIoService *serv, const char *eventData, bool broadcast) { OsalTimespec time; @@ -168,42 +227,42 @@ HWTEST_F(IoServiceTest, HdfIoService001, TestSize.Level0) HWTEST_F(IoServiceTest, HdfIoService002, TestSize.Level0) { struct HdfIoService *serv = HdfIoServiceBind(testSvcName); - ASSERT_NE(serv, nullptr); + EXPECT_NE(serv, nullptr); serv->priv = const_cast(static_cast("serv0")); struct HdfIoServiceGroup *group = HdfIoServiceGroupObtain(); - ASSERT_NE(group, nullptr); + EXPECT_NE(group, nullptr); int ret = HdfIoServiceGroupAddService(group, serv); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = HdfIoServiceGroupRegisterListener(group, &listener0.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = SendEvent(serv, testSvcName, false); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(1, listener0.eventCount); + EXPECT_EQ(1, listener0.eventCount); ret = HdfDeviceUnregisterEventListener(serv, &listener0.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); HdfIoServiceGroupRecycle(group); group = HdfIoServiceGroupObtain(); - ASSERT_NE(group, nullptr); + EXPECT_NE(group, nullptr); ret = HdfIoServiceGroupAddService(group, serv); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = HdfIoServiceGroupRegisterListener(group, &listener0.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = SendEvent(serv, testSvcName, false); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(2, listener0.eventCount); + EXPECT_EQ(2, listener0.eventCount); HdfIoServiceGroupRecycle(group); HdfIoServiceRecycle(serv); @@ -338,59 +397,59 @@ HWTEST_F(IoServiceTest, HdfIoService005, TestSize.Level0) HWTEST_F(IoServiceTest, HdfIoService006, TestSize.Level0) { struct HdfIoServiceGroup *group = HdfIoServiceGroupObtain(); - ASSERT_NE(group, nullptr); + EXPECT_NE(group, nullptr); struct HdfIoService *serv = HdfIoServiceBind(testSvcName); - ASSERT_NE(serv, nullptr); + EXPECT_NE(serv, nullptr); serv->priv = const_cast(static_cast("serv")); struct HdfIoService *serv1 = HdfIoServiceBind(testSvcName); - ASSERT_NE(serv1, nullptr); + EXPECT_NE(serv1, nullptr); serv1->priv = const_cast(static_cast("serv1")); int ret = HdfIoServiceGroupAddService(group, serv); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = HdfIoServiceGroupRegisterListener(group, &listener0.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = HdfIoServiceGroupAddService(group, serv1); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = SendEvent(serv, testSvcName, false); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(1, listener0.eventCount); + EXPECT_EQ(1, listener0.eventCount); ret = SendEvent(serv1, testSvcName, false); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(2, listener0.eventCount); + EXPECT_EQ(2, listener0.eventCount); HdfIoServiceGroupRemoveService(group, serv); ret = SendEvent(serv, testSvcName, false); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(2, listener0.eventCount); + EXPECT_EQ(2, listener0.eventCount); ret = SendEvent(serv1, testSvcName, false); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(3, listener0.eventCount); + EXPECT_EQ(3, listener0.eventCount); ret = HdfIoServiceGroupAddService(group, serv); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = SendEvent(serv, testSvcName, false); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(4, listener0.eventCount); + EXPECT_EQ(4, listener0.eventCount); HdfIoServiceGroupRecycle(group); HdfIoServiceRecycle(serv); @@ -517,32 +576,32 @@ HWTEST_F(IoServiceTest, HdfIoService009, TestSize.Level0) HWTEST_F(IoServiceTest, HdfIoService010, TestSize.Level0) { struct HdfIoServiceGroup *group = HdfIoServiceGroupObtain(); - ASSERT_NE(group, nullptr); + EXPECT_NE(group, nullptr); struct HdfIoService *serv = HdfIoServiceBind(testSvcName); - ASSERT_NE(serv, nullptr); + EXPECT_NE(serv, nullptr); serv->priv = const_cast(static_cast("serv")); int ret = HdfIoServiceGroupAddService(group, serv); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = HdfIoServiceGroupAddService(group, serv); EXPECT_NE(ret, HDF_SUCCESS); ret = HdfIoServiceGroupRegisterListener(group, &listener0.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = SendEvent(serv, testSvcName, false); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(1, listener0.eventCount); + EXPECT_EQ(1, listener0.eventCount); HdfIoServiceGroupRemoveService(group, serv); HdfIoServiceGroupRemoveService(group, serv); ret = HdfIoServiceGroupUnregisterListener(group, &listener0.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); HdfIoServiceGroupRecycle(group); HdfIoServiceRecycle(serv); @@ -650,38 +709,35 @@ HWTEST_F(IoServiceTest, HdfIoService013, TestSize.Level0) */ HWTEST_F(IoServiceTest, HdfIoService014, TestSize.Level0) { - struct HdfIoServiceGroup *group = HdfIoServiceGroupObtain(); - ASSERT_NE(group, nullptr); - struct HdfIoService *serv = HdfIoServiceBind(testSvcName); - ASSERT_NE(serv, nullptr); + EXPECT_NE(serv, nullptr); serv->priv = const_cast(static_cast("serv")); struct HdfIoService *serv1 = HdfIoServiceBind(testSvcName); - ASSERT_NE(serv1, nullptr); + EXPECT_NE(serv1, nullptr); serv1->priv = const_cast(static_cast("serv1")); int ret = HdfDeviceRegisterEventListener(serv, &listener0.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = HdfDeviceRegisterEventListener(serv1, &listener1.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = SendEvent(serv, testSvcName, true); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); usleep(eventWaitTimeUs); - ASSERT_EQ(1, listener0.eventCount); - ASSERT_EQ(1, listener1.eventCount); + EXPECT_EQ(1, listener0.eventCount); + EXPECT_EQ(1, listener1.eventCount); ret = HdfDeviceUnregisterEventListener(serv, &listener0.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); ret = HdfDeviceUnregisterEventListener(serv, &listener0.listener); EXPECT_NE(ret, HDF_SUCCESS); ret = HdfDeviceUnregisterEventListener(serv1, &listener1.listener); - ASSERT_EQ(ret, HDF_SUCCESS); + EXPECT_EQ(ret, HDF_SUCCESS); HdfIoServiceRecycle(serv); HdfIoServiceRecycle(serv1); @@ -895,7 +951,7 @@ HWTEST_F(IoServiceTest, HdfIoService017, TestSize.Level0) ret = testService->dispatcher->Dispatch(&testService->object, SAMPLE_DRIVER_UNREGISTER_DEVICE, data, nullptr); ASSERT_EQ(status, HDF_SUCCESS); - OsalMSleep(10); + OsalMSleep(eventWaitTimeMs); ASSERT_FALSE(issd.callbacked); status = servmgr->UnregisterServiceStatusListener(servmgr, listener); @@ -905,3 +961,193 @@ HWTEST_F(IoServiceTest, HdfIoService017, TestSize.Level0) SvcMgrIoserviceRelease(servmgr); HdfSbufRecycle(data); } + +// test read buffer is insufficient +HWTEST_F(IoServiceTest, HdfIoService018, TestSize.Level1) +{ + struct HdfIoService *serv = HdfIoServiceBind(testSvcName); + ASSERT_NE(serv, nullptr); + serv->priv = const_cast(static_cast("ring buffer insufficient")); + + int ret = HdfDeviceRegisterEventListener(serv, &listener3.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + + const char *eventData = + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_0000000000_" + "0000000000_"; + HDF_LOGI("send: eventData sizeof is %{public}d", strlen(eventData)); + ret = SendEvent(serv, eventData, false); + usleep(eventWaitTimeUs); + ASSERT_EQ(1, listener3.eventCount); + + ret = SendEvent(serv, eventData, true); + usleep(eventWaitTimeUs); + ASSERT_EQ(2, listener3.eventCount); + + ret = HdfDeviceUnregisterEventListener(serv, &listener3.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + HdfIoServiceRecycle(serv); + OsalMSleep(eventWaitTimeMs); +} + +static uint64_t SendEventLoop(HdfIoService *serv, const char *logInfo, bool sendType) +{ + uint64_t temp = 0; + constexpr int testLoop = 1000; + constexpr int waitTime = 10; + int count = 0; + int ret; + + for (int i = 0; i < testLoop; i++) { + OsalGetTime(&g_beginTime); + ret = SendEvent(serv, logInfo, sendType); + if (ret != HDF_SUCCESS) { + return 0; + } + OsalMSleep(waitTime); + if (g_endTime.sec != g_beginTime.sec || g_endTime.usec < g_beginTime.usec) { + continue; + } + count++; + uint64_t duration = g_endTime.usec - g_beginTime.usec; + temp += duration; + HDF_LOGI("%{public}s takes %{public}" PRIu64 " us", logInfo, duration); + } + + return count == 0 ? 0 : temp / count; +} + +// test optimization ratio of ringbuffer and schedpolicy +HWTEST_F(IoServiceTest, HdfIoService019, TestSize.Level1) +{ + struct HdfIoService *serv = HdfIoServiceBind(testSvcName); + ASSERT_NE(serv, nullptr); + serv->priv = const_cast(static_cast("serv")); + + int ret = HdfDeviceRegisterEventListener(serv, &listener2.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + uint64_t boardcastAvg = SendEventLoop(serv, "boardcast send event", true); + ASSERT_NE(boardcastAvg, 0); + + ret = HdfDeviceUnregisterEventListener(serv, &listener2.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + HdfIoServiceRecycle(serv); + usleep(eventWaitTimeUs); + + struct HdfIoService *serv1 = HdfIoServiceBind(testSvcName); + ASSERT_NE(serv1, nullptr); + serv1->priv = const_cast(static_cast("serv1")); + + ret = HdfDeviceRegisterEventListenerWithSchedPolicy(serv1, &listener2.listener, SCHED_RR); + ASSERT_EQ(ret, HDF_SUCCESS); + uint64_t singleAvg = SendEventLoop(serv1, "single send event", false); + ASSERT_NE(singleAvg, 0); + + double rate = static_cast(boardcastAvg - singleAvg) / boardcastAvg; + HDF_LOGI("Optimization ratio is %{public}f", rate); + + ret = HdfDeviceUnregisterEventListener(serv1, &listener2.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + HdfIoServiceRecycle(serv1); + OsalMSleep(eventWaitTimeMs); +} + +// test interface HdfIoServiceGroupRegisterListenerWithSchedPolicy +HWTEST_F(IoServiceTest, HdfIoService020, TestSize.Level1) +{ + struct HdfIoService *serv = HdfIoServiceBind(testSvcName); + ASSERT_NE(serv, nullptr); + serv->priv = const_cast(static_cast("serv")); + + struct HdfIoServiceGroup *group = HdfIoServiceGroupObtain(); + ASSERT_NE(group, nullptr); + + int ret = HdfIoServiceGroupAddService(group, serv); + ASSERT_EQ(ret, HDF_SUCCESS); + + ret = HdfIoServiceGroupRegisterListenerWithSchedPolicy(group, &listener0.listener, SCHED_FIFO); + ASSERT_EQ(ret, HDF_SUCCESS); + + ret = HdfIoServiceGroupRegisterListenerWithSchedPolicy(group, &listener1.listener, SCHED_RR); + ASSERT_EQ(ret, HDF_SUCCESS); + + ret = SendEvent(serv, testSvcName, false); + ASSERT_EQ(ret, HDF_SUCCESS); + + usleep(eventWaitTimeUs); + ASSERT_EQ(1, listener0.eventCount); + ASSERT_EQ(1, listener1.eventCount); + + ret = HdfIoServiceGroupUnregisterListener(group, &listener0.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + + ret = HdfIoServiceGroupUnregisterListener(group, &listener1.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + + HdfIoServiceGroupRecycle(group); + HdfIoServiceRecycle(serv); + OsalMSleep(eventWaitTimeMs); +} + +// test interface HdfDeviceRegisterEventListenerWithSchedPolicy +HWTEST_F(IoServiceTest, HdfIoService021, TestSize.Level1) +{ + struct HdfIoService *serv = HdfIoServiceBind(testSvcName); + ASSERT_NE(serv, nullptr); + serv->priv = const_cast(static_cast("serv")); + + int ret = HdfDeviceRegisterEventListenerWithSchedPolicy(serv, &listener0.listener, SCHED_FIFO); + ASSERT_EQ(ret, HDF_SUCCESS); + + ret = HdfDeviceRegisterEventListenerWithSchedPolicy(serv, &listener1.listener, SCHED_RR); + ASSERT_EQ(ret, HDF_SUCCESS); + + ret = SendEvent(serv, testSvcName, false); + ASSERT_EQ(ret, HDF_SUCCESS); + + usleep(eventWaitTimeUs); + ASSERT_EQ(1, listener0.eventCount); + ASSERT_EQ(1, listener1.eventCount); + + ret = HdfDeviceUnregisterEventListener(serv, &listener0.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + + ret = HdfDeviceUnregisterEventListener(serv, &listener1.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + HdfIoServiceRecycle(serv); + OsalMSleep(eventWaitTimeMs); +} + +// test the ringbuffer drops event +HWTEST_F(IoServiceTest, HdfIoService022, TestSize.Level1) +{ + struct HdfIoService *serv = HdfIoServiceBind(testSvcName); + ASSERT_NE(serv, nullptr); + serv->priv = const_cast(static_cast("drop event")); + + int ret = HdfDeviceRegisterEventListener(serv, &listener2.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + constexpr int loop = 100; + + for (int i = 0; i < loop; i++) { + ret = SendEvent(serv, "drop event", false); + ASSERT_EQ(ret, HDF_SUCCESS); + } + usleep(eventWaitTimeUs); + HDF_LOGI("receive: listener2.eventCount == %{public}d", listener2.eventCount); + ASSERT_TRUE(listener2.eventCount <= loop); + + ret = HdfDeviceUnregisterEventListener(serv, &listener2.listener); + ASSERT_EQ(ret, HDF_SUCCESS); + HdfIoServiceRecycle(serv); +} +} // namespace OHOS \ No newline at end of file diff --git a/framework/include/core/hdf_io_service_if.h b/framework/include/core/hdf_io_service_if.h index 56eeae8b9..a7f88e3cc 100644 --- a/framework/include/core/hdf_io_service_if.h +++ b/framework/include/core/hdf_io_service_if.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Copyright (c) 2020-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. @@ -199,6 +199,21 @@ void HdfIoServiceGroupRemoveService(struct HdfIoServiceGroup *group, struct HdfI */ int32_t HdfIoServiceGroupRegisterListener(struct HdfIoServiceGroup *group, struct HdfDevEventlistener *listener); +/** + * @brief Registers a custom {@link HdfDevEventlistener} for listening for events reported by driver services + * in a specified driver service group object. + * + * @param group Indicates the pointer to the driver service group object to listen to, + * which is obtained via {@link HdfIoServiceGroupObtain}. + * @param listener Indicates the pointer to the {@link HdfDevEventlistener} to register. + * @param policy Indicates the sched policy of the HdfDevEventlistener thread. + * @return Returns 0 if the operation is successful; returns a negative value otherwise. + * + * @since 4.0 + */ +int32_t HdfIoServiceGroupRegisterListenerWithSchedPolicy( + struct HdfIoServiceGroup *group, struct HdfDevEventlistener *listener, int policy); + /** * @brief Unregisters a previously registered {@link HdfDevEventlistener} that is used for listening for events * reported by driver services in a specified driver service group object. @@ -246,6 +261,21 @@ void HdfIoServiceRecycle(struct HdfIoService *service); */ int HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener); +/** + * @brief Registers a custom {@link HdfDevEventlistener} for listening for events reported + * by a specified driver service object. + * + * @param target Indicates the pointer to the driver service object to listen, which is obtained through + * the {@link HdfIoServiceBind} function. + * @param listener Indicates the pointer to the listener to register. + * @param policy Indicates the sched policy of the HdfDevEventlistener thread. + * @return Returns 0 if the operation is successful; returns a negative value otherwise. + * + * @since 4.0 + */ +int32_t HdfDeviceRegisterEventListenerWithSchedPolicy( + struct HdfIoService *target, struct HdfDevEventlistener *listener, int policy); + /** * @brief Unregisters a previously registered {@link HdfDevEventlistener} to release resources * if it is no longer required. diff --git a/framework/include/osal/osal_thread.h b/framework/include/osal/osal_thread.h index 136783e10..0ed77ccf6 100644 --- a/framework/include/osal/osal_thread.h +++ b/framework/include/osal/osal_thread.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Copyright (c) 2020-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. @@ -63,6 +63,7 @@ struct OsalThreadParam { char *name; /**< Thread name */ size_t stackSize; /**< Thread stack size, which may cause thread stack overflow if it is too small */ OSAL_THREAD_PRIORITY priority; /**< Thread priority */ + int policy; /**< Thread scheduling policy */ }; /** diff --git a/framework/support/posix/src/osal_thread.c b/framework/support/posix/src/osal_thread.c index 2ccf0d2ab..d8202699d 100644 --- a/framework/support/posix/src/osal_thread.c +++ b/framework/support/posix/src/osal_thread.c @@ -1,17 +1,19 @@ /* - * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * Copyright (c) 2020-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ -#include "osal_thread.h" -#include #include +#include +#include + #include "hdf_base.h" #include "hdf_log.h" #include "osal_mem.h" +#include "osal_thread.h" #ifndef PTHREAD_STACK_MIN #define OSAL_PTHREAD_STACK_MIN 4096 #else @@ -116,6 +118,29 @@ static int OsalCreatePthread(pthread_t *threadId, pthread_attr_t *attribute, str return HDF_SUCCESS; } +static int32_t OsalThreadSetSchedPolicy(pthread_attr_t *attribute, const int policy) +{ + if (policy == SCHED_OTHER) { + return HDF_SUCCESS; + } + if (policy != SCHED_FIFO && policy != SCHED_RR) { + HDF_LOGE("%s invalid policy", __func__); + return HDF_FAILURE; + } + int resultCode = pthread_attr_setinheritsched(attribute, PTHREAD_EXPLICIT_SCHED); + if (resultCode < 0) { + HDF_LOGE("pthread_attr_setinheritsched errorno: %d", resultCode); + return HDF_FAILURE; + } + resultCode = pthread_attr_setschedpolicy(attribute, policy); + if (resultCode < 0) { + HDF_LOGE("pthread_attr_setschedpolicy errorno: %d", resultCode); + return HDF_FAILURE; + } + + return HDF_SUCCESS; +} + int32_t OsalThreadStart(struct OsalThread *thread, const struct OsalThreadParam *param) { pthread_attr_t attribute; @@ -157,7 +182,7 @@ int32_t OsalThreadStart(struct OsalThread *thread, const struct OsalThreadParam HDF_LOGE("pthread_attr_setschedparam errorno: %d", resultCode); goto DEAL_FAIL; } - + OsalThreadSetSchedPolicy(&attribute, param->policy); resultCode = OsalCreatePthread(¶->id, &attribute, thread->realThread, param->name); if (resultCode != 0) { HDF_LOGE("OsalCreatePthread errorno: %d", resultCode); diff --git a/framework/test/unittest/osal/osal_all_test.c b/framework/test/unittest/osal/osal_all_test.c index 2ebd24fd5..109ea595a 100644 --- a/framework/test/unittest/osal/osal_all_test.c +++ b/framework/test/unittest/osal/osal_all_test.c @@ -1,26 +1,33 @@ /* - * Copyright (c) 2020-2022 Huawei Device Co., Ltd. + * Copyright (c) 2020-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ +#ifdef __USER__ +#include +#endif + #include "hdf_base.h" #include "hdf_log.h" +#include "osal_case_cmd_test.h" +#include "osal_file_test.h" #include "osal_firmware.h" +#include "osal_get_case_test.h" #include "osal_irq.h" #include "osal_list_test.h" -#include "osal_file_test.h" -#include "osal_case_cmd_test.h" -#include "osal_get_case_test.h" -#include "osal_test_case_def.h" #include "osal_mem.h" #include "osal_mutex.h" #include "osal_spinlock.h" +#include "osal_test_case_def.h" #ifndef __USER__ #include "osal_test_type.h" #endif +#ifdef __USER__ +#include "pthread.h" +#endif #include "osal_thread.h" #include "osal_time.h" #include "osal_timer.h" @@ -39,6 +46,11 @@ static int32_t g_waitMutexTime = 3100; static bool g_threadTest1Flag = true; OSAL_DECLARE_THREAD(thread1); OSAL_DECLARE_THREAD(thread2); +#ifdef __USER__ +OSAL_DECLARE_THREAD(thread3); +OSAL_DECLARE_THREAD(thread4); +OSAL_DECLARE_THREAD(thread5); +#endif OSAL_DECLARE_THREAD(thread); struct OsalMutex g_mutexTest; OSAL_DECLARE_SPINLOCK(g_spinTest); @@ -175,6 +187,65 @@ static int ThreadTest2(void *arg) return 0; } +#ifdef __USER__ +#define SCHED_OTHER_PRIORITY 0 +#define SCHED_FIFO_PRIORITY 15 +#define SCHED_RR_PRIORITY 15 +static int ThreadTest3(void *arg) +{ + int policy; + struct sched_param param; + + HDF_LOGE("[OSAL_UT_TEST]%s test thread para end", __func__); + (void)arg; + + OsalSleep(HDF_THREAD_TEST_SLEEP_S); + pthread_getschedparam(pthread_self(), &policy, ¶m); + UT_TEST_CHECK_RET(policy != SCHED_OTHER, OSAL_THREAD_CREATE); + UT_TEST_CHECK_RET(param.sched_priority != SCHED_OTHER_PRIORITY, OSAL_THREAD_CREATE); + printf("%s: policy is %d, param.sched_priority is %d \n", __func__, policy, param.sched_priority); + HDF_LOGE("%s thread return\n", __func__); + + return 0; +} + +static int ThreadTest4(void *arg) +{ + int policy; + struct sched_param param; + + HDF_LOGI("[OSAL_UT_TEST]%s test thread para end", __func__); + (void)arg; + + OsalSleep(HDF_THREAD_TEST_SLEEP_S); + pthread_getschedparam(pthread_self(), &policy, ¶m); + UT_TEST_CHECK_RET(policy != SCHED_FIFO, OSAL_THREAD_CREATE); + UT_TEST_CHECK_RET(param.sched_priority != SCHED_FIFO_PRIORITY, OSAL_THREAD_CREATE); + printf("%s: policy is %d, param.sched_priority is %d \n", __func__, policy, param.sched_priority); + HDF_LOGE("%s thread return\n", __func__); + + return 0; +} + +static int ThreadTest5(void *arg) +{ + int policy; + struct sched_param param; + + HDF_LOGI("[OSAL_UT_TEST]%s test thread para end", __func__); + (void)arg; + + OsalSleep(HDF_THREAD_TEST_SLEEP_S); + pthread_getschedparam(pthread_self(), &policy, ¶m); + UT_TEST_CHECK_RET(policy != SCHED_RR, OSAL_THREAD_CREATE); + UT_TEST_CHECK_RET(param.sched_priority != SCHED_RR_PRIORITY, OSAL_THREAD_CREATE); + printf("%s: policy is %d, param.sched_priority is %d \n", __func__, policy, param.sched_priority); + HDF_LOGE("%s thread return\n", __func__); + + return 0; +} +#endif + #define HDF_DBG_CNT_CTRL 10 #ifndef __USER__ OSAL_DECLARE_TIMER(g_testTimerLoop1); @@ -564,6 +635,47 @@ static void OsaThreadTest1(void) UT_TEST_CHECK_RET(ret != HDF_SUCCESS, OSAL_THREAD_CREATE); } +#ifdef __USER__ +#define HDF_TEST_POLICY_STACK_SIZE 0 +static void OsaThreadSchedPolicyTest(void) +{ + HDF_LOGE("[OSAL_UT_TEST]%{public}s start", __func__); + + struct OsalThreadParam threadCfg1; + (void)memset_s(&threadCfg1, sizeof(threadCfg1), 0, sizeof(threadCfg1)); + threadCfg1.name = "hdf_test3"; + threadCfg1.priority = OSAL_THREAD_PRI_HIGH; + threadCfg1.stackSize = HDF_TEST_POLICY_STACK_SIZE; + threadCfg1.policy = SCHED_OTHER; + int ret = OsalThreadCreate(&thread3, (OsalThreadEntry)ThreadTest3, NULL); + UT_TEST_CHECK_RET(ret != HDF_SUCCESS, OSAL_THREAD_CREATE); + ret = OsalThreadStart(&thread3, &threadCfg1); + UT_TEST_CHECK_RET(ret != HDF_SUCCESS, OSAL_THREAD_CREATE); + + struct OsalThreadParam threadCfg2; + (void)memset_s(&threadCfg2, sizeof(threadCfg2), 0, sizeof(threadCfg2)); + threadCfg2.name = "hdf_test4"; + threadCfg2.priority = OSAL_THREAD_PRI_HIGH; + threadCfg2.stackSize = HDF_TEST_POLICY_STACK_SIZE; + threadCfg2.policy = SCHED_FIFO; + ret = OsalThreadCreate(&thread4, (OsalThreadEntry)ThreadTest4, NULL); + UT_TEST_CHECK_RET(ret != HDF_SUCCESS, OSAL_THREAD_CREATE); + ret = OsalThreadStart(&thread4, &threadCfg2); + UT_TEST_CHECK_RET(ret != HDF_SUCCESS, OSAL_THREAD_CREATE); + + struct OsalThreadParam threadCfg3; + (void)memset_s(&threadCfg3, sizeof(threadCfg3), 0, sizeof(threadCfg3)); + threadCfg3.name = "hdf_test5"; + threadCfg3.priority = OSAL_THREAD_PRI_HIGH; + threadCfg3.stackSize = HDF_TEST_POLICY_STACK_SIZE; + threadCfg3.policy = SCHED_RR; + ret = OsalThreadCreate(&thread5, (OsalThreadEntry)ThreadTest5, NULL); + UT_TEST_CHECK_RET(ret != HDF_SUCCESS, OSAL_THREAD_CREATE); + ret = OsalThreadStart(&thread5, &threadCfg3); + UT_TEST_CHECK_RET(ret != HDF_SUCCESS, OSAL_THREAD_CREATE); +} +#endif + static void OsaThreadTest(void) { struct OsalThreadParam threadCfg; @@ -828,6 +940,9 @@ int OsaTestBegin(int32_t testFlag) #ifndef __USER__ OsaIrqTest(); OsaTimerTest(); +#endif +#ifdef __USER__ + OsaThreadSchedPolicyTest(); #endif OsaThreadTest(); OsaMemoryTest(); @@ -855,6 +970,11 @@ int OsaTestEnd(void) OsalThreadDestroy(&thread1); OsalThreadDestroy(&thread); OsalThreadDestroy(&thread2); +#ifdef __USER__ + OsalThreadDestroy(&thread3); + OsalThreadDestroy(&thread4); + OsalThreadDestroy(&thread5); +#endif HDF_LOGE("%s", __func__); return 0; diff --git a/framework/utils/src/hdf_thread_ex.c b/framework/utils/src/hdf_thread_ex.c index d9f07c68f..bdf8d8188 100644 --- a/framework/utils/src/hdf_thread_ex.c +++ b/framework/utils/src/hdf_thread_ex.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. @@ -18,6 +18,7 @@ void HdfThreadStart(struct HdfThread *thread) struct OsalThreadParam param = { .priority = OSAL_THREAD_PRI_DEFAULT, .stackSize = 0, + .policy = 0, }; OsalThreadStart(&thread->adapter, ¶m); thread->status = true; @@ -74,8 +75,7 @@ void HdfThreadDestruct(struct HdfThread *thread) struct HdfThread *HdfThreadNewInstance(void) { - struct HdfThread *thread = - (struct HdfThread *)OsalMemCalloc(sizeof(struct HdfThread)); + struct HdfThread *thread = (struct HdfThread *)OsalMemCalloc(sizeof(struct HdfThread)); if (thread != NULL) { HdfThreadConstruct(thread); } @@ -89,4 +89,3 @@ void HdfThreadFreeInstance(struct HdfThread *thread) OsalMemFree(thread); } } - -- Gitee