source: svn/newcon3bcm2_21bu/nexus/base/src/b_objdb.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 15.4 KB
Line 
1/***************************************************************************
2 *     (c)2004-2011 Broadcom Corporation
3 *
4 *  This program is the proprietary software of Broadcom Corporation and/or its licensors,
5 *  and may only be used, duplicated, modified or distributed pursuant to the terms and
6 *  conditions of a separate, written license agreement executed between you and Broadcom
7 *  (an "Authorized License").  Except as set forth in an Authorized License, Broadcom grants
8 *  no license (express or implied), right to use, or waiver of any kind with respect to the
9 *  Software, and Broadcom expressly reserves all rights in and to the Software and all
10 *  intellectual property rights therein.  IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU
11 *  HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY
12 *  NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE.
13 *
14 *  Except as expressly set forth in the Authorized License,
15 *
16 *  1.     This program, including its structure, sequence and organization, constitutes the valuable trade
17 *  secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof,
18 *  and to use this information only in connection with your use of Broadcom integrated circuit products.
19 *
20 *  2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
21 *  AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
22 *  WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
23 *  THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES
24 *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE,
25 *  LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION
26 *  OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF
27 *  USE OR PERFORMANCE OF THE SOFTWARE.
28 *
29 *  3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
30 *  LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR
31 *  EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR
32 *  USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF
33 *  THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT
34 *  ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
35 *  LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF
36 *  ANY LIMITED REMEDY.
37 *
38 * $brcm_Workfile: b_objdb.c $
39 * $brcm_Revision: 13 $
40 * $brcm_Date: 10/5/11 12:39p $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/base/src/b_objdb.c $
47 *
48 * 13   10/5/11 12:39p erickson
49 * SW7420-1148: backing out /main/8. insert must be explicit. non-proxied
50 *  servers require explicit nexus_register_Xxx and nexus_unregister_Xxx.
51 *
52 * 12   10/4/11 4:39p erickson
53 * SW7420-1992: allow b_objdb_remove to receive NULL client. results in
54 *  general release/removal.
55 *
56 * 11   9/29/11 7:03p bandrews
57 * SW7420-2078: objdb now accepts NULL clients for verification
58 *
59 * 10   9/16/11 3:40p erickson
60 * SW7420-2064: clean up unprotected callbacks when client exits, allow
61 *  re-registration when client connects
62 *
63 * 9   9/13/11 1:24p erickson
64 * SW7420-1148: change client modes to unprotected/protected/untrusted
65 *
66 * 8   9/2/11 10:01a erickson
67 * SW7420-1148: allow implicit insert on acquire. allows non-thunked
68 *  server to work with thunked client.
69 *
70 * 7   7/26/11 1:33p erickson
71 * SW7420-1992: add surfacecmp module and examples
72 *
73 * 6   7/26/11 12:07p erickson
74 * SW7420-1992: callback database must take client id so that callbacks
75 *  can be disconnected when a client releases
76 *
77 * 5   6/2/11 8:57a erickson
78 * SW7420-1671: add more #include's
79 *
80 * 4   6/1/11 9:05a erickson
81 * SW7420-1671: add #include
82 *
83 * 3   5/13/11 12:18p erickson
84 * SW7420-1873: remove shutdown attribute
85 *
86 * 2   4/7/11 5:26p erickson
87 * SW7420-1671: correct comment
88 *
89 * 1   4/1/11 9:59a erickson
90 * SW7420-1671: refactor object database for multiprocess stress
91 *
92 ************************************************************/
93#include "bstd.h"
94#include "bkni.h"
95#include "nexus_base.h"
96#include "b_objdb.h"
97
98/* b_objdb is a standalone piece of code. it is very important that there is no #include
99into some part of a nexus driver. it should have no dependency other than BDBG and NEXUS_ModuleHandle. */
100
101BDBG_MODULE(b_objdb);
102BDBG_OBJECT_ID(b_objdb);
103
104#define BDBG_MSG_TRACE(X)
105#define LOCK(P_DB)   NEXUS_Module_Lock((P_DB)->module)
106#define UNLOCK(P_DB) NEXUS_Module_Unlock((P_DB)->module)
107
108static struct b_objdb_heap *b_objdb_alloc_heap_locked(unsigned nobjects, struct b_objdb_heap *old_heap)
109{
110    struct b_objdb_heap *heap;
111    BDBG_ASSERT(nobjects>0);
112
113    heap = BKNI_Malloc(sizeof(*heap)+(nobjects-1)*sizeof(*heap->data));
114    if(heap) {
115        heap->count = nobjects;
116        BKNI_Memset(heap->data, 0, nobjects*sizeof(*heap->data));
117        if(old_heap) {
118            unsigned new,old;
119            /* copy valid data into the new heap, and compact it */
120            for(old=new=0;old<old_heap->count;old++) {
121                if(old_heap->data[old].handle) {
122                    heap->data[new] = old_heap->data[old];
123                    new++;
124                    if(new>=nobjects) {
125                        BDBG_WRN(("nexus_driver_module_p_allocate_heap: (%p) not enough %u entries in new heap", heap, nobjects));
126                        break;
127                    }
128                }
129            }
130            BKNI_Free(old_heap);
131        }
132    } else {
133        BDBG_WRN(("nexus_driver_module_p_allocate_heap: can't allocate heap for %u entries", nobjects));
134    }
135    return heap;
136}
137
138int b_objdb_init(struct b_objdb *db, struct b_objdb_class *class_table)
139{
140    unsigned class_no;
141
142    BKNI_Memset(db, 0, sizeof(*db));
143    BDBG_OBJECT_SET(db, b_objdb);
144    db->class_table = class_table;
145    if (db->class_table) {
146        /* create backlink */
147        for(class_no=0;db->class_table[class_no].destructor;class_no++) {
148            db->class_table[class_no].db = db;
149        }
150    }
151    return 0;
152}
153
154void b_objdb_uninit(struct b_objdb *db)
155{
156    BDBG_OBJECT_ASSERT(db, b_objdb);
157
158    /* NOTE: db->module may be NULL here for uninitialized modules. */
159
160    if (db->class_table) {
161        unsigned class_no;
162        for(class_no=0;db->class_table[class_no].destructor;class_no++) {
163            struct b_objdb_class *p_class = &db->class_table[class_no];
164            if (p_class->objects) {
165                BKNI_Free(p_class->objects);
166                p_class->objects = NULL;
167            }
168        }
169    }
170    BDBG_OBJECT_DESTROY(db, b_objdb);
171}
172
173int b_objdb_insert_locked(struct b_objdb_class *p_class, void *handle, const struct b_objdb_client *client, bool acquiring)
174{
175    int rc = 0;
176    unsigned count;
177
178    BDBG_ASSERT(p_class);
179    BDBG_OBJECT_ASSERT(p_class->db, b_objdb);
180    BDBG_MSG(("%s %s:%p client=%p", acquiring?"acquire":"insert", p_class->type_name, handle, client));
181    if (!client) return BERR_TRACE(NEXUS_INVALID_PARAMETER);
182
183    for(count=0;;) {
184        struct b_objdb_heap *heap = p_class->objects;
185        unsigned i;
186
187        if(heap) {
188            count = heap->count;
189        }
190        if(acquiring) {
191            for(i=0;i<count;i++) {
192                if (heap && heap->data[i].handle == handle) {
193                    if (heap->data[i].acquired_client) {
194                        BDBG_WRN(("object already acquired %s:%p", p_class->type_name, handle));
195                    }
196                    else {
197                        /* successfully acquired */
198                        heap->data[i].acquired_client = client;
199                    }
200                    goto done;
201                }
202            }
203            /* for non-proxied server, create requires an explicit nexus_register_Xxx and destroy
204            requires an explicit nexus_unregister_Xxx. this allows a non-proxied server to
205            safely destroy an object that is still acquired. */
206            BDBG_ERR(("acquiring object that wasn't inserted %s:%p", p_class->type_name, handle));
207            rc = -1;
208            goto done;
209        }
210
211        /* on a very first round count==0 */
212        for(i=0;i<count;i++) {
213            if(heap && heap->data[i].handle == NULL) {
214                heap->data[i].handle = handle;
215                heap->data[i].client = client;
216                heap->data[i].acquired_client = NULL; /* not acquired */
217                heap->data[i].order = p_class->db->object_count++;
218                goto done;
219            }
220        }
221
222        /* if not found resize heap */
223        heap = b_objdb_alloc_heap_locked((count+4), heap);
224        if(!heap) { /* wasn't able to allocate new heap, so we keep the old */
225            rc = BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
226            goto done;
227        }
228        p_class->objects = heap;
229    }
230done:
231    return rc;
232}
233
234int b_objdb_remove_locked(struct b_objdb_class *p_class, void *handle, const struct b_objdb_client *client, bool releasing)
235{
236    struct b_objdb_heap *heap;
237
238    BDBG_ASSERT(p_class);
239    BDBG_OBJECT_ASSERT(p_class->db, b_objdb);
240    BDBG_MSG(("%s %s:%p client=%#x", releasing?"release":"remove", p_class->type_name, handle, client));
241
242    (p_class->db->cancel_callbacks_locked)(p_class->db->cancel_callbacks_context, handle, releasing?(void*)client:NULL);
243    heap = p_class->objects;
244    if(heap) {
245        unsigned i;
246        for(i=0;i<heap->count;i++) {
247            if(heap->data[i].handle == handle) {
248                if (releasing) {
249                    if (heap->data[i].acquired_client == client || !client) {
250                        heap->data[i].acquired_client = 0;
251                        if (!heap->data[i].client) {
252                            heap->data[i].handle = NULL;
253                        }
254                    }
255                    else {
256                        BDBG_ERR(("releasing object that is not acquired %s:%p", p_class->type_name, handle));
257                        return -1;
258                    }
259                }
260                else {
261                    if (!client || client->verify == b_objdb_verify_none || heap->data[i].client == client) {
262                        if (heap->data[i].acquired_client) {
263                            BDBG_WRN(("removing object which is still acquired %s:%p", p_class->type_name, handle));
264                        }
265                        heap->data[i].handle = NULL;
266                        heap->data[i].client = 0;
267                        heap->data[i].acquired_client = NULL;
268                    }
269                    else {
270                        BDBG_ERR(("attempting to remove object that is not owned %s:%p", p_class->type_name, handle));
271                        return -1;
272                    }
273                }
274                goto done;
275            }
276        }
277        BDBG_ERR(("removing unknown object %s:%p", p_class->type_name, handle));
278        return -1;
279    }
280done:
281    return 0;
282}
283
284int b_objdb_verify_locked(struct b_objdb_class *p_class, void *handle, const struct b_objdb_client *client)
285{
286    struct b_objdb_heap *heap;
287
288    BDBG_ASSERT(p_class);
289    BDBG_OBJECT_ASSERT(p_class->db, b_objdb);
290    if (client && client->verify == b_objdb_verify_none) {
291        return 0;
292    }
293
294    BDBG_MSG_TRACE(("verify: %s:%p client=%#x", p_class->type_name, handle, client));
295    heap = p_class->objects;
296    if (heap) {
297        unsigned i;
298        /* TODO: consider hash table for interfaces with many instances and tight performance requirements (e.g. surfaces) */
299        for(i=0;i<heap->count;i++) {
300            if (heap->data[i].handle == handle) {
301                if (client) {
302                    if (client->verify == b_objdb_verify_partial) {
303                        /* don't need to check ownership. it exists, so it's good. */
304                        return 0;
305                    }
306
307                    /* if you are the owner or have it acquired, you are allowed to use this handle */
308                    if (heap->data[i].client == client || heap->data[i].acquired_client == client) {
309                        return 0;
310                    }
311                }
312                else {
313                    /* no client check. the handle/type exists, so we pass. */
314                    return 0;
315                }
316            }
317        }
318        BDBG_WRN(("unknown object: %s:%p", p_class->type_name, handle));
319    }
320    return -1;
321
322}
323
324void b_objdb_clear(struct b_objdb *db)
325{
326    BDBG_OBJECT_ASSERT(db, b_objdb);
327    LOCK(db);
328    if (db->class_table) {
329        unsigned class_no;
330        for(class_no=0;db->class_table[class_no].destructor;class_no++) {
331            struct b_objdb_class *p_class = &db->class_table[class_no];
332            if (p_class->objects) {
333                BKNI_Memset(p_class->objects->data, 0, sizeof(struct b_objdb_entry) * p_class->objects->count);
334            }
335        }
336    }
337    UNLOCK(db);
338}
339
340int b_objdb_get_newest_entry(struct b_objdb *db, const struct b_objdb_client *client, struct b_objdb_class **p_class, struct b_objdb_entry **p_entry)
341{
342    struct b_objdb_entry *newest = NULL;
343    unsigned class_no_newest = 0;
344    int rc = -1;
345    unsigned class_no;
346
347    BDBG_OBJECT_ASSERT(db, b_objdb);
348    LOCK(db);
349    if (!db->class_table) goto done;
350
351    for(class_no=0;db->class_table[class_no].destructor;class_no++) {
352        struct b_objdb_class *p_class = &db->class_table[class_no];
353        struct b_objdb_heap *heap = p_class->objects;
354        struct b_objdb_entry *entry = NULL;
355        unsigned i;
356
357        if (!heap) continue;
358        for(i=0;i<heap->count;i++) {
359            if (!heap->data[i].handle) {
360                continue;
361            }
362            /* must be either owned or acquired */
363            if (heap->data[i].client != client && heap->data[i].acquired_client != client) {
364                continue;
365            }
366            if (entry==NULL || entry->order < heap->data[i].order ) { /* find entry with maximum order */
367                entry = &heap->data[i];
368            }
369        }
370
371        if(entry && (newest==NULL || newest->order < entry->order)) { /* replace if order is larger */
372            newest = entry;
373            class_no_newest = class_no;
374        }
375    }
376    if (newest) {
377        *p_entry = newest;
378        *p_class = &db->class_table[class_no_newest];
379        rc = 0;
380    }
381
382done:
383    UNLOCK(db);
384    return rc;
385}
386
387void b_objdb_uninit_entry(struct b_objdb_class *p_class, struct b_objdb_entry *entry, const struct b_objdb_client *client)
388{
389    BDBG_ASSERT(p_class);
390    BDBG_OBJECT_ASSERT(p_class->db, b_objdb);
391
392    LOCK(p_class->db);
393    if (entry->acquired_client == client) {
394        /* if it was acquired, it must have a release function registered */
395        BDBG_MSG(("auto-release: [order %u] %s:%p client=%#x", entry->order, p_class->type_name, entry->handle, client));
396        (p_class->db->cancel_callbacks_locked)(p_class->db->cancel_callbacks_context, entry->handle, (void*)client);
397        BDBG_ASSERT(p_class->release);
398        p_class->release(entry->handle);
399        entry->acquired_client = NULL;
400    }
401
402    if (entry->client == client) {
403        BDBG_MSG(("auto-remove: [order %u] %s:%p client=%#x", entry->order, p_class->type_name, entry->handle, client));
404        (p_class->db->cancel_callbacks_locked)(p_class->db->cancel_callbacks_context, entry->handle, NULL);
405        p_class->destructor(entry->handle);
406        entry->handle = NULL;
407        entry->client = NULL;
408        entry->acquired_client = NULL;
409    }
410    UNLOCK(p_class->db);
411}
412
413void b_objdb_uninit_client(struct b_objdb *db, const struct b_objdb_client *client)
414{
415    BDBG_OBJECT_ASSERT(db, b_objdb);
416    LOCK(db);
417    (db->cancel_callbacks_locked)(db->cancel_callbacks_context, NULL, (void*)client);
418    UNLOCK(db);
419}
Note: See TracBrowser for help on using the repository browser.