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 "lnn_state_machine.h"
17 
18 #include <stdlib.h>
19 
20 #include <securec.h>
21 
22 #include "lnn_log.h"
23 #include "softbus_adapter_mem.h"
24 #include "softbus_def.h"
25 #include "softbus_errcode.h"
26 
IsDuplicateState(FsmStateMachine * fsm,FsmState * state)27 static bool IsDuplicateState(FsmStateMachine *fsm, FsmState *state)
28 {
29     struct ListNode *item = NULL;
30 
31     LIST_FOR_EACH(item, &fsm->stateList) {
32         if (item == (struct ListNode *)state) {
33             return true;
34         }
35     }
36     return false;
37 }
38 
FreeFsmHandleMsg(SoftBusMessage * msg)39 static void FreeFsmHandleMsg(SoftBusMessage *msg)
40 {
41     if (msg != NULL) {
42         if (msg->obj != NULL) {
43             SoftBusFree(msg->obj);
44         }
45         SoftBusFree(msg);
46     }
47 }
48 
FreeFsmHandleMsgObj(FsmCtrlMsgObj * ctrlMsgObj)49 static void FreeFsmHandleMsgObj(FsmCtrlMsgObj *ctrlMsgObj)
50 {
51     if (ctrlMsgObj == NULL) {
52         return;
53     }
54     if (ctrlMsgObj->obj != NULL) {
55         SoftBusFree(ctrlMsgObj->obj);
56         ctrlMsgObj->obj = NULL;
57     }
58 }
59 
CreateFsmHandleMsg(FsmStateMachine * fsm,int32_t what,uint64_t arg1,uint64_t arg2,void * obj)60 static SoftBusMessage *CreateFsmHandleMsg(FsmStateMachine *fsm,
61     int32_t what, uint64_t arg1, uint64_t arg2, void *obj)
62 {
63     SoftBusMessage *msg = NULL;
64     FsmCtrlMsgObj *ctrlMsgObj = NULL;
65 
66     msg = SoftBusCalloc(sizeof(*msg));
67     if (msg == NULL) {
68         LNN_LOGE(LNN_STATE, "calloc msg failed");
69         return NULL;
70     }
71     msg->what = what;
72     msg->arg1 = arg1;
73     msg->arg2 = arg2;
74     msg->handler = &fsm->handler;
75     msg->FreeMessage = FreeFsmHandleMsg;
76 
77     ctrlMsgObj = SoftBusMalloc(sizeof(*ctrlMsgObj));
78     if (ctrlMsgObj == NULL) {
79         LNN_LOGE(LNN_STATE, "calloc ctrl msg obj failed");
80         SoftBusFree(msg);
81         return NULL;
82     }
83     ctrlMsgObj->fsm = fsm;
84     ctrlMsgObj->obj = obj;
85     msg->obj = ctrlMsgObj;
86     return msg;
87 }
88 
ProcessStartMessage(SoftBusMessage * msg)89 static void ProcessStartMessage(SoftBusMessage *msg)
90 {
91     FsmCtrlMsgObj *ctrlMsgObj = msg->obj;
92     FsmStateMachine *fsm = NULL;
93     FsmState *state = NULL;
94 
95     if (ctrlMsgObj == NULL) {
96         LNN_LOGE(LNN_STATE, "unexpected state in start msg process");
97         return;
98     }
99     fsm = ctrlMsgObj->fsm;
100     state = (FsmState *)ctrlMsgObj->obj;
101     if (fsm == NULL || state == NULL) {
102         return;
103     }
104     if (fsm->curState != NULL || (fsm->flag & FSM_FLAG_RUNNING) != 0) {
105         LNN_LOGE(LNN_STATE, "unexpected state in start msg process");
106         return;
107     }
108     if (IsDuplicateState(fsm, state) == true) {
109         fsm->curState = state;
110         if (fsm->curState->enter != NULL) {
111             fsm->curState->enter(fsm);
112         }
113         fsm->flag |= FSM_FLAG_RUNNING;
114     }
115 }
116 
ProcessDataMessage(SoftBusMessage * msg)117 static void ProcessDataMessage(SoftBusMessage *msg)
118 {
119     FsmCtrlMsgObj *ctrlMsgObj = msg->obj;
120     FsmStateMachine *fsm = NULL;
121 
122     if (ctrlMsgObj == NULL) {
123         LNN_LOGE(LNN_STATE, "unexpected state in data msg=%{public}d process, ctrlMsgObj is null", (int32_t)msg->arg1);
124         return;
125     }
126     fsm = ctrlMsgObj->fsm;
127     if (fsm == NULL) {
128         LNN_LOGE(LNN_STATE, "unexpected state in data msg=%{public}d process, fsm is null", (int32_t)msg->arg1);
129         return;
130     }
131     if (fsm->curState == NULL || (fsm->flag & FSM_FLAG_RUNNING) == 0) {
132         LNN_LOGE(LNN_STATE, "unexpected state in data msg process, arg1=%{public}d, flag=0x%{public}x",
133             (int32_t)msg->arg1, fsm->flag);
134         return;
135     }
136     if (fsm->curState->process != NULL) {
137         fsm->curState->process(fsm, (int32_t)msg->arg1, ctrlMsgObj->obj);
138     }
139 }
140 
ProcessStopMessage(SoftBusMessage * msg)141 static void ProcessStopMessage(SoftBusMessage *msg)
142 {
143     FsmCtrlMsgObj *ctrlMsgObj = msg->obj;
144     FsmStateMachine *fsm = NULL;
145 
146     if (ctrlMsgObj == NULL) {
147         return;
148     }
149     fsm = ctrlMsgObj->fsm;
150     if (fsm == NULL) {
151         LNN_LOGE(LNN_STATE, "unexpected state in stop msg process");
152         return;
153     }
154     if (fsm->curState == NULL || (fsm->flag & FSM_FLAG_RUNNING) == 0) {
155         LNN_LOGE(LNN_STATE, "unexpected state in stop msg process");
156         return;
157     }
158     fsm->curState = NULL;
159     fsm->flag &= ~FSM_FLAG_RUNNING;
160 }
161 
162 /* remove message when return 0, else return 1 */
RemoveAllMessageFunc(const SoftBusMessage * msg,void * para)163 static int32_t RemoveAllMessageFunc(const SoftBusMessage *msg, void *para)
164 {
165     (void)para;
166 
167     FreeFsmHandleMsgObj((FsmCtrlMsgObj *)msg->obj);
168     return 0;
169 }
170 
ProcessDeinitMessage(SoftBusMessage * msg)171 static void ProcessDeinitMessage(SoftBusMessage *msg)
172 {
173     FsmCtrlMsgObj *ctrlMsgObj = msg->obj;
174     FsmStateMachine *fsm = NULL;
175 
176     if (ctrlMsgObj == NULL) {
177         LNN_LOGE(LNN_STATE, "unexpected state in deinit msg process");
178         return;
179     }
180     fsm = ctrlMsgObj->fsm;
181     if (fsm == NULL) {
182         LNN_LOGE(LNN_STATE, "fsm is null in deinit msg process");
183         return;
184     }
185     if (fsm->looper != NULL) {
186         fsm->looper->RemoveMessageCustom(fsm->looper, &fsm->handler, RemoveAllMessageFunc, NULL);
187     }
188     if (fsm->deinitCallback != NULL) {
189         fsm->deinitCallback(fsm);
190     }
191 }
192 
FsmStateMsgHandler(SoftBusMessage * msg)193 static void FsmStateMsgHandler(SoftBusMessage *msg)
194 {
195     if (msg == NULL) {
196         LNN_LOGE(LNN_STATE, "process msg is null");
197         return;
198     }
199 
200     if (msg->what != FSM_CTRL_MSG_DATA) {
201         LNN_LOGI(LNN_STATE, "process fsm ctrl msgType=%{public}d", msg->what);
202     }
203     switch (msg->what) {
204         case FSM_CTRL_MSG_START:
205             ProcessStartMessage(msg);
206             break;
207         case FSM_CTRL_MSG_DATA:
208             ProcessDataMessage(msg);
209             break;
210         case FSM_CTRL_MSG_STOP:
211             ProcessStopMessage(msg);
212             break;
213         case FSM_CTRL_MSG_DEINIT:
214             ProcessDeinitMessage(msg);
215             break;
216         default:
217             break;
218     }
219 }
220 
PostMessageToFsm(FsmStateMachine * fsm,int32_t what,uint64_t arg1,uint64_t arg2,void * obj)221 static int32_t PostMessageToFsm(FsmStateMachine *fsm, int32_t what, uint64_t arg1,
222     uint64_t arg2, void *obj)
223 {
224     SoftBusMessage *msg = NULL;
225 
226     msg = CreateFsmHandleMsg(fsm, what, arg1, arg2, obj);
227     if (msg == NULL) {
228         LNN_LOGE(LNN_STATE, "create fsm handle msg fail");
229         return SOFTBUS_ERR;
230     }
231     fsm->looper->PostMessage(fsm->looper, msg);
232     return SOFTBUS_OK;
233 }
234 
235 /* remove message when return 0, else return 1 */
RemoveMessageFunc(const SoftBusMessage * msg,void * para)236 static int32_t RemoveMessageFunc(const SoftBusMessage *msg, void *para)
237 {
238     int32_t msgType;
239 
240     if (msg == NULL || para == NULL) {
241         return 1;
242     }
243     msgType = (int32_t)(intptr_t)para;
244     if (msg->what == FSM_CTRL_MSG_DATA && (int32_t)msg->arg1 == msgType) {
245         LNN_LOGI(LNN_STATE, "remove fsm data msgType=%{public}d", msgType);
246         FreeFsmHandleMsgObj((FsmCtrlMsgObj *)msg->obj);
247         return 0;
248     }
249     return 1;
250 }
251 
LnnFsmInit(FsmStateMachine * fsm,SoftBusLooper * looper,char * name,FsmDeinitCallback cb)252 int32_t LnnFsmInit(FsmStateMachine *fsm, SoftBusLooper *looper, char *name, FsmDeinitCallback cb)
253 {
254     if (fsm == NULL || name == NULL) {
255         return SOFTBUS_INVALID_PARAM;
256     }
257 
258     (void)memset_s(fsm, sizeof(*fsm), 0, sizeof(*fsm));
259     ListInit(&fsm->stateList);
260     fsm->looper = looper == NULL ? GetLooper(LOOP_TYPE_DEFAULT) : looper;
261     if (fsm->looper == NULL) {
262         LNN_LOGE(LNN_STATE, "get looper fail");
263         return SOFTBUS_ERR;
264     }
265     fsm->handler.name = name;
266     fsm->handler.HandleMessage = FsmStateMsgHandler;
267     fsm->handler.looper = fsm->looper;
268     fsm->deinitCallback = cb;
269     return SOFTBUS_OK;
270 }
271 
LnnFsmDeinit(FsmStateMachine * fsm)272 int32_t LnnFsmDeinit(FsmStateMachine *fsm)
273 {
274     if (fsm == NULL || fsm->looper == NULL) {
275         return SOFTBUS_INVALID_PARAM;
276     }
277     return PostMessageToFsm(fsm, FSM_CTRL_MSG_DEINIT, 0, 0, NULL);
278 }
279 
LnnFsmAddState(FsmStateMachine * fsm,FsmState * state)280 int32_t LnnFsmAddState(FsmStateMachine *fsm, FsmState *state)
281 {
282     if (fsm == NULL || fsm->looper == NULL || state == NULL) {
283         return SOFTBUS_INVALID_PARAM;
284     }
285 
286     if (IsDuplicateState(fsm, state)) {
287         LNN_LOGE(LNN_STATE, "already exist state");
288         return SOFTBUS_ERR;
289     }
290     ListInit(&state->list);
291     ListAdd(&fsm->stateList, &state->list);
292     return SOFTBUS_OK;
293 }
294 
LnnFsmStart(FsmStateMachine * fsm,FsmState * initialState)295 int32_t LnnFsmStart(FsmStateMachine *fsm, FsmState *initialState)
296 {
297     if (fsm == NULL || fsm->looper == NULL || initialState == NULL) {
298         return SOFTBUS_INVALID_PARAM;
299     }
300     return PostMessageToFsm(fsm, FSM_CTRL_MSG_START, 0, 0, initialState);
301 }
302 
LnnFsmStop(FsmStateMachine * fsm)303 int32_t LnnFsmStop(FsmStateMachine *fsm)
304 {
305     if (fsm == NULL || fsm->looper == NULL) {
306         return SOFTBUS_INVALID_PARAM;
307     }
308     return PostMessageToFsm(fsm, FSM_CTRL_MSG_STOP, 0, 0, NULL);
309 }
310 
LnnFsmPostMessage(FsmStateMachine * fsm,uint32_t msgType,void * data)311 int32_t LnnFsmPostMessage(FsmStateMachine *fsm, uint32_t msgType, void *data)
312 {
313     if (fsm == NULL || fsm->looper == NULL) {
314         return SOFTBUS_INVALID_PARAM;
315     }
316     return PostMessageToFsm(fsm, FSM_CTRL_MSG_DATA, msgType, 0, data);
317 }
318 
LnnFsmPostMessageDelay(FsmStateMachine * fsm,uint32_t msgType,void * data,uint64_t delayMillis)319 int32_t LnnFsmPostMessageDelay(FsmStateMachine *fsm, uint32_t msgType,
320     void *data, uint64_t delayMillis)
321 {
322     SoftBusMessage *msg = NULL;
323 
324     if (fsm == NULL || fsm->looper == NULL) {
325         return SOFTBUS_INVALID_PARAM;
326     }
327     msg = CreateFsmHandleMsg(fsm, FSM_CTRL_MSG_DATA, msgType, 0, data);
328     if (msg == NULL) {
329         LNN_LOGE(LNN_STATE, "create fsm handle msg fail");
330         return SOFTBUS_ERR;
331     }
332     fsm->looper->PostMessageDelay(fsm->looper, msg, delayMillis);
333     return SOFTBUS_OK;
334 }
335 
LnnFsmRemoveMessageByType(FsmStateMachine * fsm,int32_t what)336 int32_t LnnFsmRemoveMessageByType(FsmStateMachine *fsm, int32_t what)
337 {
338     if (fsm == NULL || fsm->looper == NULL) {
339         return SOFTBUS_INVALID_PARAM;
340     }
341     fsm->looper->RemoveMessage(fsm->looper, &fsm->handler, what);
342     return SOFTBUS_OK;
343 }
344 
LnnFsmRemoveMessage(FsmStateMachine * fsm,int32_t msgType)345 int32_t LnnFsmRemoveMessage(FsmStateMachine *fsm, int32_t msgType)
346 {
347     if (fsm == NULL || fsm->looper == NULL) {
348         return SOFTBUS_INVALID_PARAM;
349     }
350     fsm->looper->RemoveMessageCustom(fsm->looper, &fsm->handler,
351         RemoveMessageFunc, (void *)(intptr_t)msgType);
352     return SOFTBUS_OK;
353 }
354 
LnnFsmRemoveMessageSpecific(FsmStateMachine * fsm,int32_t (* customFunc)(const SoftBusMessage *,void *),void * args)355 int32_t LnnFsmRemoveMessageSpecific(FsmStateMachine *fsm,
356     int32_t (*customFunc)(const SoftBusMessage*, void*), void *args)
357 {
358     if (fsm == NULL || fsm->looper == NULL) {
359         return SOFTBUS_INVALID_PARAM;
360     }
361     fsm->looper->RemoveMessageCustom(fsm->looper, &fsm->handler,
362         customFunc == NULL ? RemoveMessageFunc : customFunc, args);
363     return SOFTBUS_OK;
364 }
365 
366 /* we must change state of state machine during its procedure, otherwise it will introduce concurrency */
LnnFsmTransactState(FsmStateMachine * fsm,FsmState * state)367 int32_t LnnFsmTransactState(FsmStateMachine *fsm, FsmState *state)
368 {
369     if (fsm == NULL || state == NULL) {
370         return SOFTBUS_INVALID_PARAM;
371     }
372 
373     if (fsm->curState == NULL || (fsm->flag & FSM_FLAG_RUNNING) == 0) {
374         LNN_LOGE(LNN_STATE, "unexpected state in change state process");
375         return SOFTBUS_ERR;
376     }
377 
378     if (IsDuplicateState(fsm, state)) {
379         if (fsm->curState->exit != NULL) {
380             fsm->curState->exit(fsm);
381         }
382         fsm->curState = state;
383         if (fsm->curState->enter != NULL) {
384             fsm->curState->enter(fsm);
385         }
386     }
387     return SOFTBUS_OK;
388 }
389