1 /*
2 * Copyright (c) 2021-2024 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 "message_handler.h"
17
18 #include <securec.h>
19
20 #include "common_list.h"
21 #include "comm_log.h"
22 #include "softbus_adapter_mem.h"
23 #include "softbus_adapter_thread.h"
24 #include "softbus_def.h"
25 #include "softbus_error_code.h"
26
27 #define LOOP_NAME_LEN 16
28 #define TIME_THOUSANDS_MULTIPLIER 1000LL
29 #define MAX_LOOPER_CNT 30U
30 #define MAX_LOOPER_PRINT_CNT 64
31
32 static int8_t g_isNeedDestroy = 0;
33 static int8_t g_isThreadStarted = 0;
34 static uint32_t g_looperCnt = 0;
35
36 typedef struct {
37 SoftBusMessage *msg;
38 ListNode node;
39 } SoftBusMessageNode;
40
41 struct SoftBusLooperContext {
42 ListNode msgHead;
43 char name[LOOP_NAME_LEN];
44 volatile unsigned char stop; // destroys looper, stop =1, and running =0
45 volatile unsigned char running;
46 SoftBusMessage *currentMsg;
47 unsigned int msgSize;
48 SoftBusMutex lock;
49 SoftBusMutexAttr attr;
50 SoftBusCond cond;
51 SoftBusCond condRunning;
52 };
53
UptimeMicros(void)54 static int64_t UptimeMicros(void)
55 {
56 SoftBusSysTime t;
57 t.sec = 0;
58 t.usec = 0;
59 SoftBusGetTime(&t);
60 int64_t when = t.sec * TIME_THOUSANDS_MULTIPLIER * TIME_THOUSANDS_MULTIPLIER + t.usec;
61 return when;
62 }
63
FreeSoftBusMsg(SoftBusMessage * msg)64 NO_SANITIZE("cfi") static void FreeSoftBusMsg(SoftBusMessage *msg)
65 {
66 if (msg->FreeMessage == NULL) {
67 SoftBusFree(msg);
68 } else {
69 msg->FreeMessage(msg);
70 }
71 }
72
MallocMessage(void)73 SoftBusMessage *MallocMessage(void)
74 {
75 SoftBusMessage *msg = (SoftBusMessage *)SoftBusCalloc(sizeof(SoftBusMessage));
76 if (msg == NULL) {
77 COMM_LOGE(COMM_UTILS, "malloc SoftBusMessage failed");
78 return NULL;
79 }
80 return msg;
81 }
82
FreeMessage(SoftBusMessage * msg)83 void FreeMessage(SoftBusMessage *msg)
84 {
85 if (msg != NULL) {
86 FreeSoftBusMsg(msg);
87 }
88 }
89
LoopTask(void * arg)90 static void *LoopTask(void *arg)
91 {
92 SoftBusLooper *looper = arg;
93 SoftBusLooperContext *context = looper->context;
94 if (context == NULL) {
95 COMM_LOGE(COMM_UTILS, "loop context is NULL");
96 return NULL;
97 }
98
99 COMM_LOGD(COMM_UTILS, "LoopTask running. name=%{public}s", context->name);
100
101 if (SoftBusMutexLock(&context->lock) != SOFTBUS_OK) {
102 COMM_LOGE(COMM_UTILS, "lock failed");
103 return NULL;
104 }
105 context->running = 1;
106 g_isThreadStarted = 1;
107 (void)SoftBusMutexUnlock(&context->lock);
108
109 for (;;) {
110 if (SoftBusMutexLock(&context->lock) != SOFTBUS_OK) {
111 return NULL;
112 }
113 // wait
114 if (context->stop == 1) {
115 COMM_LOGI(COMM_UTILS, "LoopTask stop is 1. name=%{public}s", context->name);
116 (void)SoftBusMutexUnlock(&context->lock);
117 break;
118 }
119
120 if (g_isNeedDestroy == 1) {
121 (void)SoftBusMutexUnlock(&context->lock);
122 break;
123 }
124
125 if (IsListEmpty(&context->msgHead)) {
126 COMM_LOGD(COMM_UTILS, "LoopTask wait msg list empty. name=%{public}s", context->name);
127 SoftBusCondWait(&context->cond, &context->lock, NULL);
128 (void)SoftBusMutexUnlock(&context->lock);
129 continue;
130 }
131
132 int64_t now = UptimeMicros();
133 ListNode *item = context->msgHead.next;
134 SoftBusMessage *msg = NULL;
135 SoftBusMessageNode *itemNode = CONTAINER_OF(item, SoftBusMessageNode, node);
136 int64_t time = itemNode->msg->time;
137 if (now >= time) {
138 msg = itemNode->msg;
139 ListDelete(item);
140 SoftBusFree(itemNode);
141 context->msgSize--;
142 if (looper->dumpable) {
143 COMM_LOGD(COMM_UTILS,
144 "LoopTask get message. name=%{public}s, handle=%{public}s, what=%{public}" PRId32 ", arg1=%{public}"
145 PRIu64 ", msgSize=%{public}u, time=%{public}" PRId64,
146 context->name, msg->handler ? msg->handler->name : "null", msg->what, msg->arg1, context->msgSize,
147 msg->time);
148 }
149 } else {
150 SoftBusSysTime tv;
151 tv.sec = time / TIME_THOUSANDS_MULTIPLIER / TIME_THOUSANDS_MULTIPLIER;
152 tv.usec = time % (TIME_THOUSANDS_MULTIPLIER * TIME_THOUSANDS_MULTIPLIER);
153 SoftBusCondWait(&context->cond, &context->lock, &tv);
154 }
155
156 if (msg == NULL) {
157 (void)SoftBusMutexUnlock(&context->lock);
158 continue;
159 }
160 context->currentMsg = msg;
161 (void)SoftBusMutexUnlock(&context->lock);
162 if (looper->dumpable) {
163 COMM_LOGD(COMM_UTILS,
164 "LoopTask HandleMessage message. name=%{public}s, handle=%{public}s, what=%{public}" PRId32,
165 context->name, msg->handler ? msg->handler->name : "null", msg->what);
166 }
167
168 if (msg->handler != NULL && msg->handler->HandleMessage != NULL) {
169 msg->handler->HandleMessage(msg);
170 }
171 if (looper->dumpable) {
172 // Don`t print msg->handler, msg->handler->HandleMessage() may remove handler,
173 // so msg->handler maybe invalid pointer
174 COMM_LOGD(COMM_UTILS,
175 "LoopTask after HandleMessage message. "
176 "name=%{public}s, what=%{public}" PRId32 ", arg1=%{public}" PRIu64,
177 context->name, msg->what, msg->arg1);
178 }
179 (void)SoftBusMutexLock(&context->lock);
180 FreeSoftBusMsg(msg);
181 context->currentMsg = NULL;
182 (void)SoftBusMutexUnlock(&context->lock);
183 }
184 (void)SoftBusMutexLock(&context->lock);
185 context->running = 0;
186 COMM_LOGI(COMM_UTILS, "LoopTask running is 0. name=%{public}s", context->name);
187 SoftBusCondBroadcast(&context->cond);
188 SoftBusCondBroadcast(&context->condRunning);
189 (void)SoftBusMutexUnlock(&context->lock);
190 if (g_isNeedDestroy == 1) {
191 LooperDeinit();
192 }
193 return NULL;
194 }
195
StartNewLooperThread(SoftBusLooper * looper)196 static int StartNewLooperThread(SoftBusLooper *looper)
197 {
198 #if (defined(__aarch64__) || defined(__x86_64__))
199 #define MAINLOOP_STACK_SIZE (2 * 1024 * 1024)
200 #else
201 #ifdef ASAN_BUILD
202 #define MAINLOOP_STACK_SIZE 10240
203 #else
204 #define MAINLOOP_STACK_SIZE (32 * 1024)
205 #endif
206 #endif
207 SoftBusThreadAttr threadAttr;
208 SoftBusThread tid;
209 SoftBusThreadAttrInit(&threadAttr);
210
211 threadAttr.stackSize = MAINLOOP_STACK_SIZE;
212 int32_t ret = SoftBusThreadCreate(&tid, &threadAttr, LoopTask, looper);
213 if (ret != SOFTBUS_OK) {
214 COMM_LOGE(COMM_UTILS, "Init DeathProcTask ThreadAttr failed");
215 return -1;
216 }
217
218 COMM_LOGI(COMM_UTILS, "loop thread creating. name=%{public}s, tid=%{public}d", looper->context->name,
219 (int)(uintptr_t)tid);
220 return 0;
221 }
222
DumpLooperLocked(const SoftBusLooperContext * context,const SoftBusHandler * handler)223 static void DumpLooperLocked(const SoftBusLooperContext *context, const SoftBusHandler *handler)
224 {
225 int32_t i = 0;
226 ListNode *item = NULL;
227 LIST_FOR_EACH(item, &context->msgHead) {
228 SoftBusMessageNode *itemNode = LIST_ENTRY(item, SoftBusMessageNode, node);
229 SoftBusMessage *msg = itemNode->msg;
230 if (i > MAX_LOOPER_PRINT_CNT) {
231 COMM_LOGW(COMM_UTILS, "many messages left unprocessed, msgSize=%{public}u",
232 context->msgSize);
233 break;
234 }
235 if (handler != NULL && handler != msg->handler) {
236 continue;
237 }
238 COMM_LOGD(COMM_UTILS,
239 "DumpLooper. i=%{public}d, handler=%{public}s, what=%{public}" PRId32 ", arg1=%{public}" PRIu64 ", "
240 "arg2=%{public}" PRIu64 ", time=%{public}" PRId64,
241 i, msg->handler->name, msg->what, msg->arg1, msg->arg2, msg->time);
242
243 i++;
244 }
245 }
246
DumpLooper(const SoftBusLooper * looper)247 void DumpLooper(const SoftBusLooper *looper)
248 {
249 if (looper == NULL) {
250 return;
251 }
252 SoftBusLooperContext *context = looper->context;
253 if (SoftBusMutexLock(&context->lock) != SOFTBUS_OK) {
254 return;
255 }
256 if (looper->dumpable) {
257 DumpLooperLocked(context, NULL);
258 }
259 (void)SoftBusMutexUnlock(&context->lock);
260 }
261
PostMessageAtTimeParamVerify(const SoftBusLooper * looper,SoftBusMessage * msgPost)262 static int32_t PostMessageAtTimeParamVerify(const SoftBusLooper *looper, SoftBusMessage *msgPost)
263 {
264 if (msgPost == NULL) {
265 COMM_LOGE(COMM_UTILS, "the msgPost param is null.");
266 return SOFTBUS_INVALID_PARAM;
267 }
268
269 if (looper == NULL) {
270 COMM_LOGE(COMM_UTILS, "the looper param is null.");
271 return SOFTBUS_INVALID_PARAM;
272 }
273
274 if (looper->dumpable) {
275 COMM_LOGD(COMM_UTILS, "PostMessageAtTime name=%{public}s, what=%{public}d, time=%{public}" PRId64 "us",
276 looper->context->name, msgPost->what, msgPost->time);
277 }
278
279 if (msgPost->handler == NULL) {
280 COMM_LOGE(COMM_UTILS, "[%s] msg handler is null", looper->context->name);
281 return SOFTBUS_ERR;
282 }
283
284 return SOFTBUS_OK;
285 }
286
PostMessageAtTime(const SoftBusLooper * looper,SoftBusMessage * msgPost)287 static void PostMessageAtTime(const SoftBusLooper *looper, SoftBusMessage *msgPost)
288 {
289 if (PostMessageAtTimeParamVerify(looper, msgPost) != SOFTBUS_OK) {
290 FreeSoftBusMsg(msgPost);
291 return;
292 }
293
294 SoftBusMessageNode *newNode = (SoftBusMessageNode *)SoftBusCalloc(sizeof(SoftBusMessageNode));
295 if (newNode == NULL) {
296 COMM_LOGE(COMM_UTILS, "message node malloc failed.");
297 FreeSoftBusMsg(msgPost);
298 return;
299 }
300 ListInit(&newNode->node);
301 newNode->msg = msgPost;
302 SoftBusLooperContext *context = looper->context;
303 if (SoftBusMutexLock(&context->lock) != SOFTBUS_OK) {
304 SoftBusFree(newNode);
305 FreeSoftBusMsg(msgPost);
306 return;
307 }
308 if (context->stop == 1) {
309 SoftBusFree(newNode);
310 FreeSoftBusMsg(msgPost);
311 (void)SoftBusMutexUnlock(&context->lock);
312 COMM_LOGE(COMM_UTILS, "PostMessageAtTime stop is 1. name=%{public}s, running=%{public}d",
313 context->name, context->running);
314 return;
315 }
316 ListNode *item = NULL;
317 ListNode *nextItem = NULL;
318 bool insert = false;
319 LIST_FOR_EACH_SAFE(item, nextItem, &context->msgHead) {
320 SoftBusMessageNode *itemNode = LIST_ENTRY(item, SoftBusMessageNode, node);
321 SoftBusMessage *msg = itemNode->msg;
322 if (msg->time > msgPost->time) {
323 ListTailInsert(item, &(newNode->node));
324 insert = true;
325 break;
326 }
327 }
328 if (!insert) {
329 ListTailInsert(&(context->msgHead), &(newNode->node));
330 }
331 context->msgSize++;
332 if (looper->dumpable) {
333 COMM_LOGD(COMM_UTILS, "PostMessageAtTime insert. name=%{public}s", context->name);
334 DumpLooperLocked(context, msgPost->handler);
335 }
336 SoftBusCondBroadcast(&context->cond);
337 (void)SoftBusMutexUnlock(&context->lock);
338 }
339
LooperPostMessage(const SoftBusLooper * looper,SoftBusMessage * msg)340 static void LooperPostMessage(const SoftBusLooper *looper, SoftBusMessage *msg)
341 {
342 if (msg == NULL) {
343 COMM_LOGE(COMM_UTILS, "LooperPostMessage with nullmsg");
344 return;
345 }
346 if (looper == NULL) {
347 COMM_LOGE(COMM_UTILS, "LooperPostMessage with nulllooper");
348 return;
349 }
350 msg->time = UptimeMicros();
351 PostMessageAtTime(looper, msg);
352 }
353
LooperPostMessageDelay(const SoftBusLooper * looper,SoftBusMessage * msg,uint64_t delayMillis)354 static void LooperPostMessageDelay(const SoftBusLooper *looper, SoftBusMessage *msg, uint64_t delayMillis)
355 {
356 if (msg == NULL) {
357 COMM_LOGE(COMM_UTILS, "LooperPostMessageDelay with nullmsg");
358 return;
359 }
360 if (looper == NULL) {
361 COMM_LOGE(COMM_UTILS, "LooperPostMessageDelay with nulllooper");
362 return;
363 }
364 msg->time = UptimeMicros() + (int64_t)delayMillis * TIME_THOUSANDS_MULTIPLIER;
365 PostMessageAtTime(looper, msg);
366 }
367
WhatRemoveFunc(const SoftBusMessage * msg,void * args)368 static int WhatRemoveFunc(const SoftBusMessage *msg, void *args)
369 {
370 int32_t what = (int32_t)(intptr_t)args;
371 if (msg->what == what) {
372 return 0;
373 }
374 return 1;
375 }
376
LoopRemoveMessageCustom(const SoftBusLooper * looper,const SoftBusHandler * handler,int (* customFunc)(const SoftBusMessage *,void *),void * args)377 static void LoopRemoveMessageCustom(const SoftBusLooper *looper, const SoftBusHandler *handler,
378 int (*customFunc)(const SoftBusMessage*, void*), void *args)
379 {
380 SoftBusLooperContext *context = looper->context;
381 if (SoftBusMutexLock(&context->lock) != SOFTBUS_OK) {
382 return;
383 }
384 if (context->running == 0 || context->stop == 1) {
385 (void)SoftBusMutexUnlock(&context->lock);
386 return;
387 }
388 ListNode *item = NULL;
389 ListNode *nextItem = NULL;
390 LIST_FOR_EACH_SAFE(item, nextItem, &context->msgHead) {
391 SoftBusMessageNode *itemNode = LIST_ENTRY(item, SoftBusMessageNode, node);
392 SoftBusMessage *msg = itemNode->msg;
393 if (msg->handler == handler && customFunc(msg, args) == 0) {
394 COMM_LOGD(COMM_UTILS,
395 "LooperRemoveMessage. name=%{public}s, handler=%{public}s, what=%{public}d, arg1=%{public}" PRIu64 ", "
396 "time=%{public}" PRId64,
397 context->name, handler->name, msg->what, msg->arg1, msg->time);
398 FreeSoftBusMsg(msg);
399 ListDelete(&itemNode->node);
400 SoftBusFree(itemNode);
401 context->msgSize--;
402 }
403 }
404 (void)SoftBusMutexUnlock(&context->lock);
405 }
406
LooperRemoveMessage(const SoftBusLooper * looper,const SoftBusHandler * handler,int32_t what)407 static void LooperRemoveMessage(const SoftBusLooper *looper, const SoftBusHandler *handler, int32_t what)
408 {
409 LoopRemoveMessageCustom(looper, handler, WhatRemoveFunc, (void*)(intptr_t)what);
410 }
411
SetLooperDumpable(SoftBusLooper * loop,bool dumpable)412 void SetLooperDumpable(SoftBusLooper *loop, bool dumpable)
413 {
414 if (loop == NULL) {
415 COMM_LOGE(COMM_UTILS, "loop is null");
416 return;
417 }
418 loop->dumpable = dumpable;
419 }
420
CreateNewLooper(const char * name)421 SoftBusLooper *CreateNewLooper(const char *name)
422 {
423 if (g_looperCnt >= MAX_LOOPER_CNT) {
424 COMM_LOGE(COMM_UTILS, "Looper exceeds the maximum, count=%{public}u,", g_looperCnt);
425 return NULL;
426 }
427 SoftBusLooper *looper = (SoftBusLooper *)SoftBusCalloc(sizeof(SoftBusLooper));
428 if (looper == NULL) {
429 COMM_LOGE(COMM_UTILS, "Looper SoftBusCalloc fail");
430 return NULL;
431 }
432
433 SoftBusLooperContext *context = (SoftBusLooperContext *)SoftBusCalloc(sizeof(SoftBusLooperContext));
434 if (context == NULL) {
435 COMM_LOGE(COMM_UTILS, "Looper SoftBusCalloc fail");
436 SoftBusFree(looper);
437 return NULL;
438 }
439
440 if (memcpy_s(context->name, sizeof(context->name), name, strlen(name)) != EOK) {
441 COMM_LOGE(COMM_UTILS, "memcpy_s fail");
442 SoftBusFree(looper);
443 SoftBusFree(context);
444 return NULL;
445 }
446 ListInit(&context->msgHead);
447 // init context
448 SoftBusMutexInit(&context->lock, NULL);
449 SoftBusCondInit(&context->cond);
450 SoftBusCondInit(&context->condRunning);
451 // init looper
452 looper->context = context;
453 looper->dumpable = true;
454 looper->PostMessage = LooperPostMessage;
455 looper->PostMessageDelay = LooperPostMessageDelay;
456 looper->RemoveMessage = LooperRemoveMessage;
457 looper->RemoveMessageCustom = LoopRemoveMessageCustom;
458 int ret = StartNewLooperThread(looper);
459 if (ret != 0) {
460 COMM_LOGE(COMM_UTILS, "start fail");
461 SoftBusFree(looper);
462 SoftBusFree(context);
463 return NULL;
464 }
465 g_looperCnt++;
466 COMM_LOGD(COMM_UTILS, "wait looper start ok. name=%{public}s", context->name);
467 return looper;
468 }
469
470 struct LoopConfigItem {
471 int type;
472 SoftBusLooper *looper;
473 };
474
475 static struct LoopConfigItem g_loopConfig[] = {
476 {LOOP_TYPE_DEFAULT, NULL},
477 {LOOP_TYPE_BR_SEND, NULL},
478 {LOOP_TYPE_BR_RECV, NULL},
479 {LOOP_TYPE_P2P, NULL},
480 {LOOP_TYPE_LANE, NULL},
481 {LOOP_TYPE_HANDLE_FILE, NULL}
482 };
483
GetLooper(int type)484 SoftBusLooper *GetLooper(int type)
485 {
486 uint32_t len = sizeof(g_loopConfig) / sizeof(struct LoopConfigItem);
487 for (uint32_t i = 0; i < len; i++) {
488 if (g_loopConfig[i].type == type) {
489 return g_loopConfig[i].looper;
490 }
491 }
492 return NULL;
493 }
494
SetLooper(int type,SoftBusLooper * looper)495 void SetLooper(int type, SoftBusLooper *looper)
496 {
497 uint32_t len = sizeof(g_loopConfig) / sizeof(struct LoopConfigItem);
498 for (uint32_t i = 0; i < len; i++) {
499 if (g_loopConfig[i].type == type) {
500 g_loopConfig[i].looper = looper;
501 }
502 }
503 }
504
ReleaseLooper(const SoftBusLooper * looper)505 static void ReleaseLooper(const SoftBusLooper *looper)
506 {
507 uint32_t len = sizeof(g_loopConfig) / sizeof(struct LoopConfigItem);
508 for (uint32_t i = 0; i < len; i++) {
509 if (g_loopConfig[i].looper == looper) {
510 g_loopConfig[i].looper = NULL;
511 return;
512 }
513 }
514 }
515
DestroyLooper(SoftBusLooper * looper)516 void DestroyLooper(SoftBusLooper *looper)
517 {
518 if (looper == NULL) {
519 COMM_LOGE(COMM_UTILS, "looper is null");
520 return;
521 }
522
523 SoftBusLooperContext *context = looper->context;
524 if (context != NULL) {
525 (void)SoftBusMutexLock(&context->lock);
526
527 COMM_LOGI(COMM_UTILS, "set stop 1. name=%{public}s", context->name);
528 context->stop = 1;
529
530 SoftBusCondBroadcast(&context->cond);
531 (void)SoftBusMutexUnlock(&context->lock);
532 while (1) {
533 (void)SoftBusMutexLock(&context->lock);
534 COMM_LOGI(COMM_UTILS, "get. name=%{public}s, running=%{public}d", context->name, context->running);
535 if (context->running == 0) {
536 (void)SoftBusMutexUnlock(&context->lock);
537 break;
538 }
539 SoftBusCondWait(&context->condRunning, &context->lock, NULL);
540 (void)SoftBusMutexUnlock(&context->lock);
541 }
542 // release msg
543 ListNode *item = NULL;
544 ListNode *nextItem = NULL;
545 LIST_FOR_EACH_SAFE(item, nextItem, &context->msgHead) {
546 SoftBusMessageNode *itemNode = LIST_ENTRY(item, SoftBusMessageNode, node);
547 SoftBusMessage *msg = itemNode->msg;
548 FreeSoftBusMsg(msg);
549 ListDelete(&itemNode->node);
550 SoftBusFree(itemNode);
551 }
552 COMM_LOGI(COMM_UTILS, "destroy. name=%{public}s", context->name);
553 // destroy looper
554 SoftBusCondDestroy(&context->cond);
555 SoftBusCondDestroy(&context->condRunning);
556 SoftBusMutexDestroy(&context->lock);
557 SoftBusFree(context);
558 looper->context = NULL;
559 }
560 ReleaseLooper(looper);
561 SoftBusFree(looper);
562 if (g_looperCnt != 0) {
563 g_looperCnt--;
564 }
565 }
566
LooperInit(void)567 int LooperInit(void)
568 {
569 SoftBusLooper *looper = CreateNewLooper("BusCenter");
570 if (!looper) {
571 COMM_LOGE(COMM_UTILS, "init BusCenter looper fail.");
572 return SOFTBUS_ERR;
573 }
574 SetLooper(LOOP_TYPE_DEFAULT, looper);
575
576 SoftBusLooper *handleFileLooper = CreateNewLooper("HandleFile");
577 if (!handleFileLooper) {
578 COMM_LOGE(COMM_UTILS, "init HandleFile looper fail.");
579 return SOFTBUS_ERR;
580 }
581 SetLooper(LOOP_TYPE_HANDLE_FILE, handleFileLooper);
582 COMM_LOGD(COMM_UTILS, "init looper success.");
583 return SOFTBUS_OK;
584 }
585
LooperDeinit(void)586 void LooperDeinit(void)
587 {
588 uint32_t len = sizeof(g_loopConfig) / sizeof(struct LoopConfigItem);
589 for (uint32_t i = 0; i < len; i++) {
590 if (g_loopConfig[i].looper == NULL) {
591 continue;
592 }
593 (void)SoftBusMutexLock(&(g_loopConfig[i].looper->context->lock));
594 if (g_isThreadStarted == 0) {
595 g_isNeedDestroy = 1;
596 (void)SoftBusMutexUnlock(&(g_loopConfig[i].looper->context->lock));
597 return;
598 }
599 (void)SoftBusMutexUnlock(&(g_loopConfig[i].looper->context->lock));
600 DestroyLooper(g_loopConfig[i].looper);
601 }
602 }
603