1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "le_loop.h"
17#include "le_epoll.h"
18
19
20static int TaskNodeCompare(const HashNode *node1, const HashNode *node2)
21{
22    BaseTask *task1 = HASHMAP_ENTRY(node1, BaseTask, hashNode);
23    BaseTask *task2 = HASHMAP_ENTRY(node2, BaseTask, hashNode);
24    return (int)task1->taskId.fd - (int)task2->taskId.fd;
25}
26
27static int TaskKeyCompare(const HashNode *node, const void *key)
28{
29    BaseTask *task = HASHMAP_ENTRY(node, BaseTask, hashNode);
30    TaskId *taskId = (TaskId *)key;
31    return (int)task->taskId.fd - taskId->taskId.fd;
32}
33
34static int TaskGetNodeHasCode(const HashNode *node)
35{
36    BaseTask *task = HASHMAP_ENTRY(node, BaseTask, hashNode);
37    return task->taskId.fd;
38}
39
40static int TaskGetKeyHasCode(const void *key)
41{
42    TaskId *taskId = (TaskId *)key;
43    return taskId->taskId.fd;
44}
45
46static void TaskNodeFree(const HashNode *node, void *context)
47{
48    BaseTask *task = HASHMAP_ENTRY(node, BaseTask, hashNode);
49    CloseTask((const LoopHandle)context, task);
50    free(task);
51}
52
53static LE_STATUS CreateLoop_(EventLoop **loop, uint32_t maxevents, uint32_t timeout)
54{
55#ifdef LOOP_EVENT_USE_EPOLL
56    LE_STATUS ret = CreateEpollLoop(loop, maxevents, timeout);
57    LE_CHECK(ret == LE_SUCCESS, return ret, "Failed to create epoll loop");
58#endif
59    (*loop)->maxevents = maxevents;
60    (*loop)->timeout = timeout;
61    (*loop)->stop = 0;
62    LoopMutexInit(&(*loop)->mutex);
63
64    OH_ListInit(&((*loop)->idleList));
65
66    HashInfo info = {
67        TaskNodeCompare,
68        TaskKeyCompare,
69        TaskGetNodeHasCode,
70        TaskGetKeyHasCode,
71        TaskNodeFree,
72        128
73    };
74    ret = OH_HashMapCreate(&(*loop)->taskMap, &info);
75    LE_CHECK(ret == LE_SUCCESS, return ret, "failed to create hash map loop");
76    OH_ListInit(&((*loop)->timerList));
77    return ret;
78}
79
80LE_STATUS CloseLoop(EventLoop *loop)
81{
82    if (!loop->stop) {
83        return LE_SUCCESS;
84    }
85    OH_HashMapDestory(loop->taskMap, loop);
86    if (loop->close) {
87        loop->close(loop);
88    }
89    return LE_SUCCESS;
90}
91
92LE_STATUS ProcessEvent(const EventLoop *loop, int fd, uint32_t oper)
93{
94    BaseTask *task = GetTaskByFd((EventLoop *)loop, fd);
95    if (task != NULL) {
96        task->handleEvent((LoopHandle)loop, (TaskHandle)task, oper);
97    } else {
98        loop->delEvent(loop, fd, EVENT_READ | EVENT_WRITE);
99    }
100    return LE_SUCCESS;
101}
102
103LE_STATUS AddTask(EventLoop *loop, BaseTask *task)
104{
105    LoopMutexLock(&loop->mutex);
106    int ret = OH_HashMapAdd(loop->taskMap, &task->hashNode);
107    LoopMutexUnlock(&loop->mutex);
108#ifndef STARTUP_INIT_TEST
109    return ret;
110#else
111    ret = 0;
112    return ret;
113#endif
114}
115
116BaseTask *GetTaskByFd(EventLoop *loop, int fd)
117{
118    BaseTask *task = NULL;
119    LoopMutexLock(&loop->mutex);
120    TaskId id = {0, {fd}};
121    HashNode *node = OH_HashMapGet(loop->taskMap, &id);
122    if (node != NULL) {
123        task = HASHMAP_ENTRY(node, BaseTask, hashNode);
124    }
125    LoopMutexUnlock(&loop->mutex);
126    return task;
127}
128
129void DelTask(EventLoop *loop, BaseTask *task)
130{
131    loop->delEvent(loop, task->taskId.fd,
132        EVENT_READ | EVENT_WRITE | EVENT_ERROR | EVENT_FREE | EVENT_TIMEOUT | EVENT_SIGNAL);
133    LoopMutexLock(&loop->mutex);
134    OH_HashMapRemove(loop->taskMap, (TaskId *)task);
135    LoopMutexUnlock(&loop->mutex);
136    return;
137}
138
139static EventLoop *g_defaultLoop = NULL;
140LoopHandle LE_GetDefaultLoop(void)
141{
142    if (g_defaultLoop == NULL) {
143        LE_CreateLoop((LoopHandle *)&g_defaultLoop);
144    }
145    return (LoopHandle)g_defaultLoop;
146}
147
148LE_STATUS LE_CreateLoop(LoopHandle *handle)
149{
150    EventLoop *loop = NULL;
151    LE_STATUS ret = CreateLoop_(&loop, LOOP_MAX_SOCKET, DEFAULT_TIMEOUT);
152    *handle = (LoopHandle)loop;
153    return ret;
154}
155
156void LE_RunLoop(const LoopHandle handle)
157{
158    LE_CHECK(handle != NULL, return, "Invalid handle");
159    EventLoop *loop = (EventLoop *)handle;
160    loop->runLoop(loop);
161}
162
163void LE_CloseLoop(const LoopHandle loopHandle)
164{
165    LE_CHECK(loopHandle != NULL, return, "Invalid handle");
166    CloseLoop((EventLoop *)loopHandle);
167    if ((LoopHandle)g_defaultLoop == loopHandle) {
168        g_defaultLoop = NULL;
169    }
170}
171
172void LE_StopLoop(const LoopHandle handle)
173{
174    LE_CHECK(handle != NULL, return, "Invalid handle");
175    EventLoop *loop = (EventLoop *)handle;
176    loop->stop = 1;
177}