1 /*
2  * Copyright (c) 2020 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 #include "task_manager.h"
16 #include <securec.h>
17 #include <log.h>
18 #include <ohos_errno.h>
19 #include "memory_adapter.h"
20 #include "time_adapter.h"
21 #include "queue_adapter.h"
22 #include "service_impl.h"
23 #include "message_inner.h"
24 #include "samgr_lite_inner.h"
25 
26 #undef LOG_TAG
27 #undef LOG_DOMAIN
28 #define LOG_TAG "Samgr"
29 #define LOG_DOMAIN 0xD001800
30 
31 #define DONT_WAIT 0
32 static void BeginWork(ServiceImpl *service);
33 static void EndWork(ServiceImpl *service, const Exchange *exchange);
34 static void *TaskEntry(void *);
35 static void ProcRequest(Exchange *exchange, ServiceImpl *serviceImpl);
36 static void ProcDirectRequest(Exchange *exchange);
37 static void ProcResponse(Exchange *exchange);
38 static ServiceImpl *CorrectServiceImpl(Exchange *exchange, ServiceImpl *serviceImpl);
39 
SAMGR_CreateFixedTaskPool(const TaskConfig * config,const char * name,uint8 size)40 TaskPool *SAMGR_CreateFixedTaskPool(const TaskConfig *config, const char *name, uint8 size)
41 {
42     if (config == NULL || size == 0 || MAX_TASK_SIZE <= THREAD_Total()) {
43         return NULL;
44     }
45 
46     MQueueId queueId = (MQueueId)QUEUE_Create(name, sizeof(Exchange), config->queueSize);
47     if (queueId == NULL) {
48         HILOG_ERROR(HILOG_MODULE_SAMGR, "Create Queue<%s> size:%hu failed!", name, config->queueSize);
49         return NULL;
50     }
51 
52     TaskPool *taskPool = (TaskPool *)SAMGR_Malloc(sizeof(TaskPool) + sizeof(ThreadId) * size);
53     if (taskPool == NULL) {
54         HILOG_ERROR(HILOG_MODULE_SAMGR, "Create TaskPool<%s> size:%hu failed!", name, config->queueSize);
55         QUEUE_Destroy(queueId);
56         return NULL;
57     }
58 
59     (void)memset_s(taskPool, sizeof(TaskPool) + sizeof(ThreadId) * size, 0,
60                    sizeof(TaskPool) + sizeof(ThreadId) * size);
61     taskPool->queueId = queueId;
62     taskPool->stackSize = config->stackSize;
63     taskPool->priority = (uint8)config->priority;
64     taskPool->size = size;
65     taskPool->top = 0;
66     taskPool->ref = 1;
67     return taskPool;
68 }
69 
SAMGR_StartTaskPool(TaskPool * pool,const char * name)70 int32 SAMGR_StartTaskPool(TaskPool *pool, const char *name)
71 {
72     if (pool == NULL) {
73         return EC_INVALID;
74     }
75 
76     if (pool->top > 0) {
77         return EC_SUCCESS;
78     }
79 
80     ThreadAttr attr = {name, pool->stackSize, pool->priority, 0, 0};
81     while (pool->top < pool->size) {
82         register ThreadId threadId = (ThreadId)THREAD_Create(TaskEntry, pool->queueId, &attr);
83         if (threadId == NULL) {
84             HILOG_ERROR(HILOG_MODULE_SAMGR, "Start Task<%s, %hu, %hhu> failed!", name, pool->stackSize, pool->priority);
85             break;
86         }
87         pool->tasks[pool->top] = threadId;
88         ++(pool->top);
89     }
90     return EC_SUCCESS;
91 }
92 
SAMGR_ReleaseTaskPool(TaskPool * pool)93 int32 SAMGR_ReleaseTaskPool(TaskPool *pool)
94 {
95     if (pool == NULL) {
96         return EC_INVALID;
97     }
98 
99     pool->ref--;
100     if (pool->ref == 0) {
101         Exchange exchange = {0};
102         exchange.type = MSG_EXIT;
103         QUEUE_Put(pool->queueId, &exchange, 0, DONT_WAIT);
104         SAMGR_Free(pool);
105     }
106     return EC_SUCCESS;
107 }
108 
SAMGR_ReferenceTaskPool(TaskPool * pool)109 TaskPool *SAMGR_ReferenceTaskPool(TaskPool *pool)
110 {
111     if (pool == NULL) {
112         return NULL;
113     }
114 
115     if (pool->ref >= MAX_REF_NUM) {
116         return NULL;
117     }
118 
119     pool->ref++;
120     return pool;
121 }
122 
TaskEntry(void * argv)123 static void *TaskEntry(void *argv)
124 {
125     ServiceImpl *serviceImpl = NULL;
126     THREAD_SetThreadLocal(argv);
127     while (TRUE) {
128         Exchange exchange;
129         uint32 msgRcvRet = SAMGR_MsgRecv((MQueueId)argv, (uint8 *)&exchange, sizeof(Exchange));
130         if (msgRcvRet != EC_SUCCESS) {
131             continue;
132         }
133 
134         if (exchange.type == MSG_EXIT) {
135             SAMGR_FreeMsg(&exchange);
136             break;
137         }
138 
139         serviceImpl = CorrectServiceImpl(&exchange, serviceImpl);
140         BeginWork(serviceImpl);
141         ProcResponse(&exchange);
142         ProcDirectRequest(&exchange);
143         ProcRequest(&exchange, serviceImpl);
144         EndWork(serviceImpl, &exchange);
145         SAMGR_FreeMsg(&exchange);
146     }
147     QUEUE_Destroy((MQueueId)argv);
148     return NULL;
149 }
150 
ProcRequest(Exchange * exchange,ServiceImpl * serviceImpl)151 static void ProcRequest(Exchange *exchange, ServiceImpl *serviceImpl)
152 {
153     if (serviceImpl == NULL || exchange->type == MSG_ACK || exchange->type == MSG_DIRECT) {
154         return;
155     }
156 
157     DEFAULT_MessageHandle(serviceImpl, &(exchange->id), &(exchange->request));
158 
159     if (exchange->type == MSG_CON) {
160         SAMGR_SendResponse(&exchange->request, &exchange->response);
161     }
162 }
163 
ProcResponse(Exchange * exchange)164 static void ProcResponse(Exchange *exchange)
165 {
166     if (exchange->handler == NULL) {
167         return;
168     }
169 
170     if (exchange->type != MSG_ACK) {
171         return;
172     }
173 
174     exchange->handler(&exchange->request, &exchange->response);
175 }
176 
ProcDirectRequest(Exchange * exchange)177 static void ProcDirectRequest(Exchange *exchange)
178 {
179     if (exchange->handler == NULL) {
180         return;
181     }
182 
183     if (exchange->type != MSG_DIRECT) {
184         return;
185     }
186 
187     exchange->handler(&exchange->request, &exchange->response);
188 }
189 
CorrectServiceImpl(Exchange * exchange,ServiceImpl * serviceImpl)190 static ServiceImpl *CorrectServiceImpl(Exchange *exchange, ServiceImpl *serviceImpl)
191 {
192     if (exchange->type == MSG_ACK) {
193         // The ack message use the last service.
194         return serviceImpl;
195     }
196 
197     if (serviceImpl == NULL || serviceImpl->serviceId != exchange->id.serviceId) {
198         serviceImpl = SAMGR_GetServiceByID(exchange->id.serviceId);
199     }
200 
201     if (serviceImpl == NULL) {
202         return NULL;
203     }
204 
205     return serviceImpl;
206 }
207 
SAMGR_GetCurrentQueueID()208 MQueueId SAMGR_GetCurrentQueueID()
209 {
210     return (MQueueId)THREAD_GetThreadLocal();
211 }
212 
BeginWork(ServiceImpl * service)213 static void BeginWork(ServiceImpl *service)
214 {
215     if (service == NULL || service->inited != SVC_IDLE) {
216         return;
217     }
218 
219     if (service->ops.step == BOOT_SYS_WAIT) {
220         WDT_Start(MSG_PROC_THRESHOLD);
221     }
222 
223     service->ops.messages++;
224     service->ops.timestamp = SAMGR_GetProcessTime();
225     service->inited = SVC_BUSY;
226 }
227 
EndWork(ServiceImpl * service,const Exchange * exchange)228 static void EndWork(ServiceImpl *service, const Exchange *exchange)
229 {
230     if (service == NULL || service->inited != SVC_BUSY) {
231         return;
232     }
233 
234     if (service->ops.step == BOOT_SYS_WAIT) {
235         WDT_Stop();
236     }
237 
238     uint32 lastTime = service->ops.timestamp;
239     service->ops.timestamp = (uint32)SAMGR_GetProcessTime();
240     uint32 interval = GET_INTERVAL(lastTime, service->ops.timestamp);
241     if (interval > MSG_PROC_THRESHOLD) {
242         const char *name = service->service->GetName(service->service);
243         HILOG_INFO(HILOG_MODULE_SAMGR, "Message Timeout <service:%s, feature:%d, type:%d, reqId:%d, time:%ums>",
244                    name, exchange->id.featureId, exchange->type, exchange->request.msgId, interval);
245         service->ops.abnormal++;
246     }
247     service->inited = SVC_IDLE;
248 }
249