• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "softbus_conn_async_helper.h"
17 
18 #include "softbus_adapter_mem.h"
19 #include "softbus_error_code.h"
20 
21 #include "conn_log.h"
22 
23 struct AsyncContext {
24     ConnAsyncFunction function;
25     void *arg;
26 };
27 
28 struct CancelContext {
29     int32_t callId;
30     ConnAsyncFreeHook freeHook;
31 };
32 
FreeMessageHook(SoftBusMessage * msg)33 static void FreeMessageHook(SoftBusMessage *msg)
34 {
35     CONN_CHECK_AND_RETURN_LOGE(msg != NULL, CONN_COMMON, "msg is null");
36     CONN_CHECK_AND_RETURN_LOGE(msg->obj != NULL, CONN_COMMON, "obj is null");
37 
38     struct AsyncContext *ctx = (struct AsyncContext *)msg->obj;
39     SoftBusFree(ctx);
40     msg->obj = NULL;
41     SoftBusFree(msg);
42 }
43 
HandleMessage(SoftBusMessage * msg)44 static void HandleMessage(SoftBusMessage *msg)
45 {
46     CONN_CHECK_AND_RETURN_LOGE(msg != NULL, CONN_COMMON, "msg is null");
47     CONN_CHECK_AND_RETURN_LOGE(msg->obj != NULL, CONN_COMMON, "obj is null");
48 
49     struct AsyncContext *ctx = (struct AsyncContext *)msg->obj;
50     ctx->function(msg->what, ctx->arg);
51     //  it is caller's responsibility to release 'arg'
52     ctx->arg = NULL;
53     // 'msg' and 'ctx' will be release by 'FreeMessageHook' later
54 }
55 
ConnAsyncConstruct(const char * name,ConnAsync * async,SoftBusLooper * looper)56 int32_t ConnAsyncConstruct(const char *name, ConnAsync *async, SoftBusLooper *looper)
57 {
58     CONN_CHECK_AND_RETURN_RET_LOGE(name != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "name is null");
59     CONN_CHECK_AND_RETURN_RET_LOGE(async != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "async is null");
60     CONN_CHECK_AND_RETURN_RET_LOGE(looper != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "looper is null");
61 
62     async->handler.name = (char *)name;
63     async->handler.looper = looper;
64     async->handler.HandleMessage = HandleMessage;
65 
66     return SOFTBUS_OK;
67 }
68 
RemoveAllAsyncCall(const SoftBusMessage * msg,void * ignore)69 static int32_t RemoveAllAsyncCall(const SoftBusMessage *msg, void *ignore)
70 {
71     (void)ignore;
72     CONN_LOGE(CONN_COMMON, "MEMORY LEAK WARNING, it should cancel before destroying, call id=%{public}d", msg->what);
73     // 0 stand for match success
74     return 0;
75 }
76 
ConnAsyncDestruct(ConnAsync * async)77 void ConnAsyncDestruct(ConnAsync *async)
78 {
79     CONN_CHECK_AND_RETURN_LOGE(async != NULL, CONN_COMMON, "async is null");
80 
81     SoftBusHandler *handler = &async->handler;
82     SoftBusLooper *looper = handler->looper;
83     looper->RemoveMessageCustom(looper, handler, RemoveAllAsyncCall, NULL);
84 
85     async->handler.name = NULL;
86     async->handler.looper = NULL;
87     async->handler.HandleMessage = NULL;
88 }
89 
ConnAsyncCall(ConnAsync * async,ConnAsyncFunction function,void * arg,uint64_t delayMs)90 int32_t ConnAsyncCall(ConnAsync *async, ConnAsyncFunction function, void *arg, uint64_t delayMs)
91 {
92     static uint16_t callIdGenerator = 0;
93 
94     CONN_CHECK_AND_RETURN_RET_LOGE(async != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "async is null");
95     CONN_CHECK_AND_RETURN_RET_LOGE(function != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "function is null");
96     // arg is nullable
97 
98     int32_t callId = (++callIdGenerator);
99     struct AsyncContext *ctx = SoftBusCalloc(sizeof(struct AsyncContext));
100     CONN_CHECK_AND_RETURN_RET_LOGE(ctx, SOFTBUS_MEM_ERR, CONN_COMMON, "malloc async ctx fail");
101     ctx->function = function;
102     ctx->arg = arg;
103 
104     SoftBusMessage *msg = SoftBusCalloc(sizeof(SoftBusMessage));
105     if (msg == NULL) {
106         CONN_LOGE(CONN_COMMON, "malloc softbus message fail");
107         SoftBusFree(ctx);
108         return SOFTBUS_MEM_ERR;
109     }
110     msg->what = callId;
111     msg->obj = ctx;
112     msg->handler = &async->handler;
113     msg->FreeMessage = FreeMessageHook;
114 
115     SoftBusLooper *looper = async->handler.looper;
116     looper->PostMessageDelay(looper, msg, delayMs);
117 
118     CONN_LOGI(CONN_COMMON, "receive async call, call id=%{public}d, delay=%{public}" PRIu64 "ms", callId, delayMs);
119     return callId;
120 }
121 
FreeAsyncCallArg(const SoftBusMessage * msg,void * args)122 static int32_t FreeAsyncCallArg(const SoftBusMessage *msg, void *args)
123 {
124     struct CancelContext *cancelCtx = (struct CancelContext *)args;
125     if (msg->what != cancelCtx->callId) {
126         // 1 stand for mismatch
127         return 1;
128     }
129     struct AsyncContext *asyncCtx = (struct AsyncContext *)msg->obj;
130     if (asyncCtx->arg != NULL) {
131         if (cancelCtx->freeHook != NULL) {
132             cancelCtx->freeHook(asyncCtx->arg);
133             asyncCtx->arg = NULL;
134         } else {
135             CONN_LOGE(CONN_COMMON, "MEMORY LEAK WARNING, it should provide hook to free memory, call id=%{public}d",
136                 msg->what);
137         }
138     }
139     // 0 stand for match success
140     return 0;
141 }
142 
ConnAsyncCancel(ConnAsync * async,int32_t callId,ConnAsyncFreeHook hook)143 void ConnAsyncCancel(ConnAsync *async, int32_t callId, ConnAsyncFreeHook hook)
144 {
145     CONN_CHECK_AND_RETURN_LOGE(async != NULL, CONN_COMMON, "async is null");
146     // free hook is nullable
147 
148     CONN_LOGI(CONN_COMMON, "cancel async call, call id=%{public}d", callId);
149     struct CancelContext ctx = {
150         .callId = callId,
151         .freeHook = hook,
152     };
153     SoftBusHandler *handler = &async->handler;
154     SoftBusLooper *looper = handler->looper;
155     looper->RemoveMessageCustom(looper, handler, FreeAsyncCallArg, &ctx);
156 }
157 
ConnAsyncGetInstance(void)158 ConnAsync *ConnAsyncGetInstance(void)
159 {
160     static ConnAsync async = { 0 };
161     return &async;
162 }
163 
ConnAsyncInit(void)164 int32_t ConnAsyncInit(void)
165 {
166     SoftBusLooper *looper = GetLooper(LOOP_TYPE_CONN);
167     CONN_CHECK_AND_RETURN_RET_LOGE(
168         looper, SOFTBUS_INVALID_PARAM, CONN_COMMON, "connection looper is null, init looper module first");
169 
170     ConnAsync *async = ConnAsyncGetInstance();
171     return ConnAsyncConstruct("conn_async", async, looper);
172 }
173