• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef PLS_H
2 #define PLS_H
3 
4 /**
5  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *    * Redistributions of source code must retain the above copyright
11  *      notice, this list of conditions and the following disclaimer.
12  *    * Redistributions in binary form must reproduce the above
13  *      copyright notice, this list of conditions and the following
14  *      disclaimer in the documentation and/or other materials provided
15  *      with the distribution.
16  *    * Neither the name of The Linux Foundation nor the names of its
17  *      contributors may be used to endorse or promote products derived
18  *      from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <stdlib.h>
34 #include "AEEStdDef.h"
35 #include "AEEatomic.h"
36 #include "verify.h"
37 #include "HAP_farf.h"
38 
39 struct PLS;
40 
41 struct plskey {
42    uintptr_t type;
43    uintptr_t key;
44 };
45 
46 struct PLS {
47    struct PLS* next;
48    struct plskey key;
49    void (*dtor)(void* data);
50    uint64_t data[1];
51 };
52 
53 
54 struct pls_table {
55    struct PLS* lst;
56    uint32_t uRefs;
57    uint32_t primThread;
58 };
59 
60 /**
61  * initialize on every thread and stick the pls_thread_deinit
62  * function into the threads tls
63  */
pls_thread_init(struct pls_table * me,uintptr_t tid)64 static __inline int pls_thread_init(struct pls_table* me, uintptr_t tid) {
65    if(tid == me->primThread) {
66       return 0;
67    }
68    if(0 == atomic_CompareOrAdd(&me->uRefs, 0, 1)) {
69       return -1;
70    }
71    return 0;
72 }
73 
74 /* call this constructor before the first thread creation with the
75  * first threads id
76  */
pls_ctor(struct pls_table * me,uintptr_t primThread)77 static __inline void pls_ctor(struct pls_table* me, uintptr_t primThread) {
78    me->uRefs = 1;
79    me->primThread = primThread;
80 }
81 
pls_thread_deinit(struct pls_table * me)82 static __inline struct pls_table* pls_thread_deinit(struct pls_table* me) {
83    if(me && 0 != me->uRefs && 0 == atomic_Add(&me->uRefs, -1)) {
84       struct PLS* lst, *next;
85       lst = me->lst;
86       me->lst = 0;
87       while(lst) {
88          next = lst->next;
89          if(lst->dtor) {
90             FARF(HIGH, "pls dtor %p", lst->dtor);
91             lst->dtor((void*)lst->data);
92          }
93          free(lst);
94          lst = next;
95       }
96       return me;
97    }
98    return 0;
99 }
100 
101 /**
102  * adds a new key to the local storage, overriding
103  * any previous value at the key.  Overriding the key
104  * does not cause the destructor to run.
105  *
106  * @param type, type part of the key to be used for lookup,
107           these should be static addresses.
108  * @param key, the key to be used for lookup
109  * @param size, the size of the data
110  * @param ctor, constructor that takes a context and memory of size
111  * @param ctx, constructor context passed as the first argument to ctor
112  * @param dtor, destructor to run at pls shutdown
113  * @param ppo, output data
114  * @retval, 0 for success
115  */
116 
pls_add(struct pls_table * me,uintptr_t type,uintptr_t key,int size,int (* ctor)(void * ctx,void * data),void * ctx,void (* dtor)(void * data),void ** ppo)117 static __inline int pls_add(struct pls_table* me, uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* data), void** ppo) {
118    int nErr = 0;
119    struct PLS* pls = 0;
120    struct PLS* prev;
121    VERIFY(me->uRefs != 0);
122    VERIFY(0 != (pls = (struct PLS*)calloc(1, size + sizeof(*pls) - sizeof(pls->data))));
123    if(ctor) {
124       VERIFY(0 == ctor(ctx, (void*)pls->data));
125    }
126    pls->dtor = dtor;
127    pls->key.type = type;
128    pls->key.key = key;
129    do {
130       pls->next = me->lst;
131       prev = (struct PLS*)atomic_CompareAndExchangeUP((uintptr_t*)&me->lst, (uintptr_t)pls, (uintptr_t)pls->next);
132    } while(prev != pls->next);
133    if(ppo) {
134       *ppo = (void*)pls->data;
135    }
136    FARF(HIGH, "pls added %p", dtor);
137 bail:
138    if(nErr && pls) {
139       free(pls);
140    }
141    return nErr;
142 }
143 
144 static __inline int pls_lookup(struct pls_table* me, uintptr_t type, uintptr_t key, void** ppo);
145 
146 /**
147  * like add, but will only add 1 item if two threads try to add at the same time.  returns
148  * item if its already there, otherwise tries to add.
149  * ctor may be called twice
150  * callers should avoid calling pls_add which will override the singleton
151  */
pls_add_lookup_singleton(struct pls_table * me,uintptr_t type,uintptr_t key,int size,int (* ctor)(void * ctx,void * data),void * ctx,void (* dtor)(void * data),void ** ppo)152 static __inline int pls_add_lookup_singleton(struct pls_table* me, uintptr_t type, uintptr_t key, int size, int (*ctor)(void* ctx, void* data), void* ctx, void (*dtor)(void* data), void** ppo) {
153    int nErr = 0;
154    struct PLS* pls = 0;
155    struct PLS* prev;
156    if(0 == pls_lookup(me, type, key, ppo)) {
157       return 0;
158    }
159    VERIFY(me->uRefs != 0);
160    VERIFY(0 != (pls = (struct PLS*)calloc(1, size + sizeof(*pls) - sizeof(pls->data))));
161    if(ctor) {
162       VERIFY(0 == ctor(ctx, (void*)pls->data));
163    }
164    pls->dtor = dtor;
165    pls->key.type = type;
166    pls->key.key = key;
167    do {
168       pls->next = me->lst;
169       if(0 == pls_lookup(me, type, key, ppo)) {
170          if(pls->dtor) {
171             pls->dtor((void*)pls->data);
172          }
173          free(pls);
174          return 0;
175       }
176       prev = (struct PLS*)atomic_CompareAndExchangeUP((uintptr_t*)&me->lst, (uintptr_t)pls, (uintptr_t)pls->next);
177    } while(prev != pls->next);
178    if(ppo) {
179       *ppo = (void*)pls->data;
180    }
181    FARF(HIGH, "pls added %p", dtor);
182 bail:
183    if(nErr && pls) {
184       free(pls);
185    }
186    return nErr;
187 }
188 
189 
190 /**
191  * finds the last data pointer added for key to the local storage
192  *
193  * @param key, the key to be used for lookup
194  * @param ppo, output data
195  * @retval, 0 for success
196  */
197 
pls_lookup(struct pls_table * me,uintptr_t type,uintptr_t key,void ** ppo)198 static __inline int pls_lookup(struct pls_table* me, uintptr_t type, uintptr_t key, void** ppo) {
199    struct PLS* lst;
200    for(lst = me->lst; me->uRefs != 0 && lst != 0; lst = lst->next) {
201       if(lst->key.type == type && lst->key.key == key) {
202          if(ppo) {
203             *ppo = lst->data;
204          }
205          return 0;
206       }
207    }
208    return -1;
209 }
210 
211 #endif //PLS_H
212 
213 
214