* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nstackx_event.h"
#include "nstackx_log.h"
#include "nstackx_error.h"
#include "nstackx_util.h"
#include "nstackx_epoll.h"
#include "securec.h"
#define TAG "nStackXEvent"
typedef struct {
EventHandle handle;
void *arg;
} EventInfo;
EventNode *SearchEventNode(const List *eventNodeChain, EpollDesc epollfd);
void CloseNodePipe(const EventNode *node)
{
CloseDesc(node->pipeFd[PIPE_OUT]);
CloseDesc(node->pipeFd[PIPE_IN]);
}
static void EventProcessHandle(void *arg)
{
int32_t ret;
EventInfo event = {0};
EpollTask *task = arg;
EventNode *node = container_of(task, EventNode, task);
#ifdef NSTACKX_WITH_LITEOS_M
ret = (int32_t)recvfrom(node->pipeFd[PIPE_OUT], &event, sizeof(event), 0, NULL, NULL);
#else
ret = (int32_t)read(node->pipeFd[PIPE_OUT], &event, sizeof(event));
#endif
if (ret != (int32_t)sizeof(event)) {
LOGE(TAG, "failed to read from pipe: %d", GetErrno());
return;
}
if (event.handle != NULL) {
event.handle(event.arg);
}
}
int32_t PostEvent(const List *eventNodeChain, EpollDesc epollfd, EventHandle handle, void *arg)
{
int32_t ret;
EventNode *node = NULL;
EventInfo event = {
.handle = handle,
.arg = arg,
};
if (eventNodeChain == NULL || handle == NULL) {
return NSTACKX_EINVAL;
}
node = SearchEventNode(eventNodeChain, epollfd);
if (node == NULL) {
LOGE(TAG, "Cannot find event node for %d", epollfd->recvFd);
return NSTACKX_EFAILED;
}
#ifdef NSTACKX_WITH_LITEOS_M
ret = (int32_t)sendto(node->pipeFd[PIPE_IN], &event, sizeof(event), 0, NULL, 0);
#else
ret = (int32_t)write(node->pipeFd[PIPE_IN], &event, sizeof(event));
#endif
if (ret != (int32_t)sizeof(event)) {
LOGE(TAG, "failed to write to pipe: %d", errno);
return NSTACKX_EFAILED;
}
return NSTACKX_EOK;
}
void ClearEvent(const List *eventNodeChain, EpollDesc epollfd)
{
EventNode *node = NULL;
EventInfo event = {0};
int32_t eventLen = (int32_t)sizeof(event);
if (eventNodeChain == NULL) {
LOGE(TAG, "eventNodeChain is null");
return;
}
node = SearchEventNode(eventNodeChain, epollfd);
if (node == NULL) {
return;
}
int32_t ret = eventLen;
while (ret == eventLen) {
#ifdef NSTACKX_WITH_LITEOS_M
ret = (int32_t)recvfrom(node->pipeFd[PIPE_OUT], &event, sizeof(event), 0, NULL, NULL);
#else
ret = (int32_t)read(node->pipeFd[PIPE_OUT], &event, sizeof(event));
#endif
if (ret != eventLen) {
break;
}
if (event.handle != NULL) {
event.handle(event.arg);
}
}
}
static int32_t CreateNonBlockPipe(EventNode *node)
{
struct EpollDescStr fds;
if (CreateEpollFdPair(&fds) != NSTACKX_EOK) {
LOGE(TAG, "CreateEpollFdPair failed");
return NSTACKX_EFAILED;
}
node->pipeFd[PIPE_OUT] = fds.recvFd;
node->pipeFd[PIPE_IN] = fds.sendFd;
return NSTACKX_EOK;
}
int32_t EventModuleInit(List *eventNodeChain, EpollDesc epollfd)
{
List *pos = NULL;
EventNode *node = NULL;
if (eventNodeChain == NULL) {
LOGE(TAG, "eventNodeChain is null");
return NSTACKX_EINVAL;
}
LIST_FOR_EACH(pos, eventNodeChain) {
node = (EventNode *)pos;
if (IsEpollDescEqual(node->epollfd, epollfd)) {
return NSTACKX_EOK;
}
}
node = calloc(1, sizeof(EventNode));
if (node == NULL) {
LOGE(TAG, "calloc failed");
return NSTACKX_ENOMEM;
}
if (CreateNonBlockPipe(node) != NSTACKX_EOK) {
LOGE(TAG, "create pipe failed");
goto L_ERR_FAILED;
}
node->task.taskfd = node->pipeFd[PIPE_OUT];
node->task.epollfd = epollfd;
node->task.readHandle = EventProcessHandle;
node->epollfd = epollfd;
if (RegisterEpollTask(&node->task, EPOLLIN) != NSTACKX_EOK) {
LOGE(TAG, "RegisterEpollTask failed");
CloseNodePipe(node);
goto L_ERR_FAILED;
}
ListInsertTail(eventNodeChain, &(node->list));
return NSTACKX_EOK;
L_ERR_FAILED:
free(node);
return NSTACKX_EFAILED;
}
void DeleteEventNode(EventNode *node)
{
ListRemoveNode(&node->list);
if (DeRegisterEpollTask(&node->task) != NSTACKX_EOK) {
LOGE(TAG, "DeRegisterEpollTask failed");
}
CloseNodePipe(node);
free(node);
}