Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 : #include "ref_obj.h"
11 :
12 : #ifdef __cplusplus
13 : extern "C" {
14 : #endif
15 :
16 : #define REF_OBJ_UPDATING 0x8000000000000000UL
17 : #define TRY_LOOP_MAX 0x80000000UL
18 :
19 : typedef struct {
20 : int step;
21 : uint64_t oldValTrigger;
22 : } RefObjUpdate;
23 :
24 0 : void InitRefObj(RefObj *obj)
25 : {
26 0 : obj->refCount = 0;
27 0 : obj->obj = NULL;
28 0 : }
29 :
30 32 : static bool ObjRefCount(RefObj *obj, const RefObjUpdate *update,
31 : void(*pfnHook)(RefObj *, const void *, void *), void *appInfo, const void *usrData)
32 : {
33 : uint64_t oldVal;
34 : uint64_t newVal;
35 32 : uint64_t tryCount = 0UL;
36 32 : uint64_t perSchedYield = 0x3FFU;
37 : do {
38 32 : tryCount++;
39 32 : if ((tryCount & perSchedYield) == 0U) {
40 0 : (void)mmSchedYield();
41 : }
42 32 : oldVal = obj->refCount;
43 32 : if ((oldVal & REF_OBJ_UPDATING) != 0) {
44 0 : continue;
45 : }
46 : // 防溢出
47 32 : if (((update->step < 0) && (oldVal < (uint64_t)(0L - update->step))) ||
48 32 : ((update->step > 0) && (oldVal >= REF_OBJ_UPDATING - update->step))) {
49 0 : return false;
50 : }
51 32 : newVal = (oldVal == update->oldValTrigger) ? REF_OBJ_UPDATING : (oldVal + update->step);
52 32 : if (mmCompareAndSwap64(&obj->refCount, oldVal, newVal)) {
53 32 : if (oldVal == update->oldValTrigger) {
54 30 : pfnHook(obj, usrData, appInfo);
55 : }
56 32 : return true;
57 : }
58 0 : } while (tryCount < TRY_LOOP_MAX);
59 0 : return false;
60 : }
61 :
62 0 : static void CreateRefObjVal(RefObj *obj, const void *userData, void *fnCreateObj)
63 : {
64 : (void)userData;
65 0 : obj->obj = ((FnCreateRefObjValue)fnCreateObj)(obj);
66 0 : mmSetData64(&obj->refCount, 1);
67 0 : }
68 :
69 15 : static void CreateRefObjValWithUserData(RefObj *obj, const void *userData, void *fnCreateObj)
70 : {
71 15 : obj->obj = ((FnCreateRefObjValueWithUserData)fnCreateObj)(obj, userData);
72 15 : mmSetData64(&obj->refCount, 1);
73 15 : }
74 :
75 15 : static void DestroyRefObjVal(RefObj *obj, const void *userData, void *fnDestroyObj)
76 : {
77 : (void)userData;
78 15 : mmSetData64(&obj->refCount, 0);
79 15 : if (fnDestroyObj != NULL) {
80 12 : ((FnDestroyRefObjValue)fnDestroyObj)(obj);
81 : }
82 15 : }
83 :
84 0 : void* GetObjRef(RefObj *obj, FnCreateRefObjValue fnCreateObj)
85 : {
86 0 : RefObjUpdate update = {1, 0};
87 0 : if (!ObjRefCount(obj, &update, CreateRefObjVal, fnCreateObj, NULL)) {
88 0 : return NULL;
89 : }
90 0 : if (obj->obj == NULL) {
91 0 : ReleaseObjRef(obj, NULL);
92 : }
93 0 : return obj->obj;
94 : }
95 :
96 16 : void* GetObjRefWithUserData(RefObj *obj, const void *userData, FnCreateRefObjValueWithUserData fnCreateObj)
97 : {
98 16 : RefObjUpdate update = {1, 0};
99 16 : if (!ObjRefCount(obj, &update, CreateRefObjValWithUserData, fnCreateObj, userData)) {
100 0 : return NULL;
101 : }
102 16 : if (obj->obj == NULL) {
103 3 : ReleaseObjRef(obj, NULL);
104 : }
105 16 : return obj->obj;
106 : }
107 :
108 16 : void ReleaseObjRef(RefObj *obj, FnDestroyRefObjValue fnDestroyObj)
109 : {
110 16 : RefObjUpdate update = {-1, 1};
111 16 : (void)ObjRefCount(obj, &update, DestroyRefObjVal, fnDestroyObj, NULL);
112 16 : }
113 :
114 : #ifdef __cplusplus
115 : }
116 : #endif
|