source: svn/newcon3bcm2_21bu/nexus/base/src/nexus_base.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: 34.1 KB
Line 
1/***************************************************************************
2*     (c)2008-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: nexus_base.c $
39* $brcm_Revision: 42 $
40* $brcm_Date: 11/29/11 11:37a $
41*
42* API Description:
43*
44* Revision History:
45*
46* $brcm_Log: /nexus/base/src/nexus_base.c $
47*
48* 42   11/29/11 11:37a erickson
49* SW7420-2129: store current default heap per module
50*
51* 41   11/11/11 2:59p vsilyaev
52* SW7125-1156, SW7420-2085: Fixed debug output
53*
54* 40   11/4/11 1:54p vsilyaev
55* SW7231-439: Improved debuggability
56*
57* 39   11/4/11 1:01p vsilyaev
58* SW7231-439, SW7420-2085: Added debug code for the reference counting
59*
60* 38   10/7/11 1:49p vsilyaev
61* SW7420-2085: Added support for object reference counting
62*
63* 37   9/14/11 2:10p erickson
64* SW7405-5478: add NEXUS_Module_GetName for debug
65*
66* 36   8/5/11 5:13p erickson
67* SW7420-1123: attempt to give more helpful error if module handle is
68*  NULL. likely just uninitialized.
69*
70* 35   8/2/11 2:58p vsilyaev
71* SW7125-1014 : Add additional scheduler threads for active standby
72*  modules
73*
74* SW7125-1014/3   8/2/11 10:09a gmohile
75* SW7125-1014 : Add additional scheduler threads for active standby
76*  modules
77*
78* 34   7/21/11 2:32p vsilyaev
79* SW7125-1014 : Add module enable/disable
80*
81* SW7125-1014/2   7/20/11 4:38p gmohile
82* SW7125-1014 : Add module enable/disable
83*
84* SW7125-1014/1   7/12/11 3:05p gmohile
85* SW7125-1014 : Add module enable function
86*
87* 33   5/31/11 3:12p erickson
88* SW7420-1907: unlock module in NEXUS_Module_Create if param check fails
89*
90* 32   5/13/11 4:13p erickson
91* SWDTV-6386: add "nx_" namespace prefix for internal nexus threads
92*
93* 31   4/5/11 12:16p vsilyaev
94* SW7405-5221: Fixed linuxkernel build
95*
96* 30   4/4/11 6:14p vsilyaev
97* SW7405-5221: Added option to forward debug output to FIFO
98*
99* 29   3/30/11 6:56p vsilyaev
100* SW7335-1214: Serialize access to the field that holds a timer handle
101*
102* 28   3/16/11 10:11a erickson
103* SW7420-1642: add NEXUS_Base_Settings.driverModuleInit and
104*  .driverModuleUninit
105*
106* 27   2/9/11 10:43a erickson
107* SW7425-63: refactor default NEXUS_ModuleSettings to fix uninitialized
108*  memory
109*
110* 26   1/28/11 11:48a mphillip
111* SW7425-63: Fix initializer warning
112*
113* 25   1/19/11 11:11a erickson
114* SW7420-1123: add NEXUS_Module_GetSettings
115*
116* 24   11/15/10 3:11p vsilyaev
117* SW7405-4996: Added NEXUS_StrCmp
118*
119* 23   11/15/10 3:05p vsilyaev
120* SWNOOS-430: Replaced NO_OS with NO_OS_DIAGS
121*
122* 22   9/23/10 2:12p erickson
123* SW7420-943: refactor for driver/firmware partitioning
124*
125* 21   11/24/09 12:25p erickson
126* SW7405-3439: rename nexus/base external scheduler interface functions
127*
128* 20   6/23/09 5:27p vsilyaev
129* PR 54926: Added NEXUS_Module_EnumerateAll
130*
131* 19   6/19/09 3:20p vsilyaev
132* PR 54926: Added debug options to the module settings
133*
134* 18   4/19/09 7:20p agin
135* PR54339: Add nexus no-os scheduler support.
136*
137* 17   4/8/09 12:33p erickson
138* PR53862: use NEXUS_P_SchedulerGetInfo to get scheduler's callback_lock
139*
140* 16   2/6/09 10:22a erickson
141* PR51878: fix warning
142*
143* 15   1/28/09 6:27p vsilyaev
144* PR 51392: Moved magnum initialization from Nexus base to the platform.
145*  Initialize only magnum layer inside of
146*  NEXUS_Platform_GetDefaultSettings
147*
148* 14   1/20/09 3:46p vsilyaev
149* PR 49285, PR 50582: Improved debugability of scheduller and fixed
150*  problem in the scheduller, where it goes to WaitForGroup to extended
151*  amount of time
152*
153* 13   11/7/08 11:49a erickson
154* PR35457: update comments
155*
156* 12   11/5/08 12:15p vsilyaev
157* PR 48694: Separated handling of linuxkernel and linuxkernel with
158*  driver/ioctls/proxy
159*
160* 11   8/19/08 12:49p erickson
161* PR45859: print module priority using BDBG_MSG
162*
163* 10   8/6/08 2:24p erickson
164* PR45469: move NEXUS_Base_GetDefaultSettings to OS specific code
165*
166* 9   6/9/08 7:11p vsilyaev
167* PR 43184: Changed phase of detection for outstanding callbacks
168*
169* 8   6/5/08 2:19p vsilyaev
170* PR 42318: Rearranged scheduller to share the same context in user and
171*  kernel mode, this allows to serve callback from kernel to user with
172*  single transition kernel<->user
173*
174* 7   4/2/08 11:31a erickson
175* PR40198: fix DEBUG=n warning
176*
177* 6   3/27/08 5:29p rjlewis
178* PR40352: zero malloced memory.
179*
180* 5   3/20/08 6:15p rjlewis
181* PR40352: type mismatch compile error under VxWorks.
182*
183* 4   2/28/08 9:39p vsilyaev
184* PR 40103: Added NEXUS_TaskCallback functions
185*
186* 3   2/22/08 10:52a erickson
187* PR39870: convert assert to runtime check for coverity
188*
189* 2   1/31/08 11:49a vsilyaev
190* PR 38682: Added support for runtime options
191*
192* 1   1/18/08 2:13p jgarrett
193* PR 38808: Merging to main branch
194*
195* Nexus_Devel/19   1/16/08 3:37p vsilyaev
196* PR 38682: Don't execute KNI/DBG initialization in the linuxkernel
197*
198* Nexus_Devel/18   11/14/07 5:22p vsilyaev
199* PR 35824: Fixed NEXUS_Module_Assert behaviour on unknown threads
200*
201* Nexus_Devel/17   11/9/07 5:59p vsilyaev
202* PR 34419: Added check for the recursive used of locks
203*
204* Nexus_Devel/16   10/23/07 4:16p vsilyaev
205* PR 36199: Added memory mapper sub-module
206*
207* Nexus_Devel/15   10/12/07 5:42p vsilyaev
208* PR 35824: Fixed NEXUS_TryLockModules
209*
210* Nexus_Devel/14   10/10/07 4:19p vsilyaev
211* PR 35824: Added NEXUS_Time type
212*
213* Nexus_Devel/13   10/3/07 2:51p vsilyaev
214* PR 34419: Renamed cntx to context
215*
216* Nexus_Devel/12   9/28/07 6:47p vsilyaev
217* PR 34419: Added functions to fire callback from the interrupt context
218*
219* Nexus_Devel/11   9/28/07 1:03p vsilyaev
220* PR 34419: Added more debug output on exit and fixed typo in the debug
221* print
222*
223* Nexus_Devel/10   9/24/07 10:24p vsilyaev
224* PR 34419: Fixed memory leak
225*
226* Nexus_Devel/9   9/24/07 6:15p jgarrett
227* PR 35002: Fixing string funcs
228*
229* Nexus_Devel/8   9/24/07 10:33a vsilyaev
230* PR 34419: Added tagged versions of Nexus_Module_Lock and NEXUS_atoi
231* function
232*
233* Nexus_Devel/7   9/21/07 6:26p jgarrett
234* PR 35002: Fixing Base_Init(NULL)
235*
236* Nexus_Devel/6   9/10/07 4:32p vsilyaev
237* PR 34419: Added NEXUS_CallbackDesc
238*
239* Nexus_Devel/5   9/7/07 3:07p vsilyaev
240* PR 34419: Create schedullers on demand
241*
242* Nexus_Devel/4   9/4/07 2:43p vsilyaev
243* PR 34419: Use GetDefaultSettings
244*
245* Nexus_Devel/3   8/31/07 6:02p vsilyaev
246* PR 34419: Added configuration structure for NEXUS_Base
247*
248* Nexus_Devel/2   8/30/07 7:07p vsilyaev
249* PR 34419: More complete implementation
250*
251* Nexus_Devel/1   8/28/07 6:39p vsilyaev
252* PR 34419: Initial implementation
253*
254***************************************************************************/
255#include "nexus_base.h"
256#include "nexus_base_priv.h"
257#include "nexus_base_os_types.h"
258#include "bkni_multi.h"
259
260#define BDBG_MSG_TRACE(x) BDBG_MSG(x)
261
262BDBG_MODULE(nexus_base);
263
264static struct {
265    NEXUS_P_Scheduler *schedulers[NEXUS_ModulePriority_eMax];
266    BLST_S_HEAD(NEXUS_P_ModuleList, NEXUS_Module) modules;
267    BKNI_MutexHandle callbackHandlerLock; /* lock that serializes access to the field that holds timer handle */
268    NEXUS_Base_Settings settings;
269    bool coreInit;
270} NEXUS_P_Base_State;
271
272static const char NEXUS_P_Base_Name[] = "NEXUS_Base";
273
274
275void
276NEXUS_Module_GetDefaultSettings(NEXUS_ModuleSettings *pSettings)
277{
278    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
279    pSettings->priority = NEXUS_ModulePriority_eDefault;
280}
281
282BDBG_OBJECT_ID(NEXUS_Module);
283
284NEXUS_ModuleHandle NEXUS_Base=NULL;
285
286#if BDBG_DEBUG_BUILD
287static const char *
288NEXUS_P_Base_StrChr(const char *str, char c)
289{
290    for(;;str++) {
291        char ch = *str;
292        if( ch==c) {
293            return str;
294        } else if (ch=='\0') {
295            return NULL;
296        }
297    }
298}
299
300static char *
301NEXUS_P_Base_Strncpy(char *dst, const char *src, size_t len)
302{
303    char *buf;
304
305    for(buf=dst;len>0;buf++,src++) {
306        char ch = *src;
307        *buf=ch;
308        len--;
309        if(ch=='\0') {
310            break;
311        }
312    }
313    for(;len>0;len--,buf++) {
314        *buf='\0';
315    }
316    return dst;
317}
318
319static void
320NEXUS_P_Base_SetModuleDebugLevel(const char *modulelist, BDBG_Level level)
321{
322    if(!modulelist) {
323        return;
324    }
325    for(;;) {
326        char buf[64];
327        const char *end = NEXUS_P_Base_StrChr(modulelist, ',');
328        size_t name_len;
329
330        if (!end) {
331            if(*modulelist) {
332                BDBG_SetModuleLevel(modulelist, level);
333            }
334            break;
335        }
336        name_len = end-modulelist;
337        if(name_len>0 && name_len<sizeof(buf)) {
338            NEXUS_P_Base_Strncpy(buf, modulelist, name_len);
339            buf[name_len] = '\0';
340            BDBG_SetModuleLevel(buf, level);
341        }
342        modulelist = end+1;
343    }
344    return;
345}
346#endif /* BDBG_DEBUG_BUILD */
347
348static const char *NEXUS_P_Scheduler_names[NEXUS_ModulePriority_eMax] = {
349    "nx_sched_idle",
350    "nx_sched_low",
351    "nx_sched",
352    "nx_sched_high",
353    "nx_sched_idle_active",
354    "nx_sched_low_active",
355    "nx_sched_high_active"
356};
357
358void
359NEXUS_CallbackDesc_Init(NEXUS_CallbackDesc *desc)
360{
361    BDBG_ASSERT(desc);
362    desc->callback = NULL;
363    desc->context = NULL;
364    desc->param = 0;
365    return;
366}
367
368NEXUS_ModuleHandle
369NEXUS_Module_Create(const char *pModuleName, const NEXUS_ModuleSettings *pSettings)
370{
371    NEXUS_ModuleHandle module;
372    NEXUS_ModuleHandle prev,cur;
373    BERR_Code rc;
374    NEXUS_ModuleSettings defaultSettings;
375
376    BDBG_ASSERT(pModuleName);
377
378    if(pModuleName!=NEXUS_P_Base_Name) {
379        NEXUS_LockModule();
380    }
381
382    if(pSettings==NULL) {
383        NEXUS_Module_GetDefaultSettings(&defaultSettings);
384        pSettings = &defaultSettings;
385    }
386
387    if ((unsigned)pSettings->priority >= sizeof(NEXUS_P_Base_State.schedulers)/sizeof(NEXUS_P_Base_State.schedulers[0])) {
388        rc = BERR_TRACE(BERR_INVALID_PARAMETER);
389        goto err_paramcheck;
390    }
391
392    module = BKNI_Malloc(sizeof(*module));
393    if(!module) {
394        rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
395        goto err_alloc;
396    }
397    BKNI_Memset(module, 0, sizeof(*module));
398
399    BDBG_OBJECT_INIT(module, NEXUS_Module);
400    module->settings = *pSettings;
401    module->pModuleName = pModuleName;
402    module->currentClient.heap = NULL;
403    module->currentClient.untrusted = false;
404    rc = BKNI_CreateMutex(&module->lock);
405    if(rc!=BERR_SUCCESS) {
406        rc = BERR_TRACE(rc);
407        goto err_lock;
408    }
409    if(pModuleName!=NEXUS_P_Base_Name) {
410        if(NEXUS_P_Base_State.schedulers[pSettings->priority]==NULL) { /* create scheduler on demand */
411           NEXUS_P_Base_State.schedulers[pSettings->priority] = NEXUS_P_Scheduler_Create(NEXUS_P_Scheduler_names[pSettings->priority], &NEXUS_P_Base_State.settings.threadSettings[pSettings->priority]);
412           if(NEXUS_P_Base_State.schedulers[pSettings->priority]==NULL) {
413               rc = BERR_TRACE(BERR_OS_ERROR);
414               goto err_scheduler;
415           }
416        }
417        module->scheduler = NEXUS_P_Base_State.schedulers[pSettings->priority];
418    } else {
419        module->scheduler = NULL;
420    }
421    /* insert into the sorted list */
422    for(prev=NULL, cur=BLST_S_FIRST(&NEXUS_P_Base_State.modules); cur!=NULL; cur=BLST_S_NEXT(cur, link)) {
423        int cmp;
424        cmp = NEXUS_P_Base_StrCmp(pModuleName, cur->pModuleName);
425        if(cmp<0) {
426            break; /* Bingo */
427        } else if(cmp==0) {
428            BDBG_ERR(("NEXUS_Module_Create: duplicated module name"));
429            rc = BERR_TRACE(BERR_INVALID_PARAMETER);
430            goto err_name;
431        }
432        prev = cur;
433    }
434    if(prev) {
435        BLST_S_INSERT_AFTER(&NEXUS_P_Base_State.modules, prev, module, link);
436    } else {
437        BLST_S_INSERT_HEAD(&NEXUS_P_Base_State.modules, module, link);
438    }
439
440    if (NEXUS_P_Base_State.settings.driverModuleInit) {
441        (NEXUS_P_Base_State.settings.driverModuleInit)(NEXUS_P_Base_State.settings.procContext, module, pModuleName, pSettings);
442    }
443
444    module->enabled = true;
445
446    if(pModuleName!=NEXUS_P_Base_Name) {
447        NEXUS_UnlockModule();
448    }
449
450    BDBG_MSG(("Creating module %s, priority %d", pModuleName, pSettings->priority));
451    return module;
452err_name:
453err_scheduler:
454    BKNI_DestroyMutex(module->lock);
455err_lock:
456    BKNI_Free(module);
457err_alloc:
458err_paramcheck:
459    if(pModuleName!=NEXUS_P_Base_Name) {
460        NEXUS_UnlockModule();
461    }
462    return NULL;
463}
464
465
466void
467NEXUS_Module_Destroy(NEXUS_ModuleHandle module)
468{
469    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
470    NEXUS_LockModule();
471
472    if (NEXUS_P_Base_State.settings.driverModuleUninit) {
473        (NEXUS_P_Base_State.settings.driverModuleUninit)(NEXUS_P_Base_State.settings.procContext, module, module->pModuleName, &module->settings);
474    }
475
476    BDBG_MSG(("Destroying module %s", module->pModuleName));
477
478    module->enabled = false;
479    BLST_S_REMOVE(&NEXUS_P_Base_State.modules, module, NEXUS_Module, link);
480    NEXUS_UnlockModule();
481    BKNI_DestroyMutex(module->lock);
482    BDBG_OBJECT_DESTROY(module, NEXUS_Module);
483    BKNI_Free(module);
484    return;
485}
486
487const char *NEXUS_Module_GetName(NEXUS_ModuleHandle module)
488{
489    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
490    return module->pModuleName;
491}
492
493void NEXUS_Module_GetSettings( NEXUS_ModuleHandle module, NEXUS_ModuleSettings *pSettings )
494{
495    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
496    NEXUS_LockModule();
497    *pSettings = module->settings;
498    NEXUS_UnlockModule();
499}
500
501/* See nexus/base/src/$(OS)/nexus_base_os.c for NEXUS_Base_GetDefaultSettings */
502
503#if NEXUS_BASE_EXTERNAL_SCHEDULER
504/**
505Allow an external scheduler to drive the scheduler state machine. This allows for thread consolidation
506in complex systems like linux kernel mode. */
507static NEXUS_Error
508NEXUS_P_Base_ExternalSchedulerInit(void)
509{
510    unsigned i;
511    for(i=0;i<sizeof(NEXUS_P_Base_State.schedulers)/sizeof(NEXUS_P_Base_State.schedulers[0]);i++) {
512        NEXUS_P_Base_State.schedulers[i] = NEXUS_P_Scheduler_Init(i, NEXUS_P_Scheduler_names[i], &NEXUS_P_Base_State.settings.threadSettings[i]);
513        if(!NEXUS_P_Base_State.schedulers[i]) {
514            return BERR_TRACE(NEXUS_OS_ERROR);
515        }
516    }
517    return NEXUS_SUCCESS;
518}
519
520/* Drive the scheduler from an external context. */
521NEXUS_Error
522NEXUS_P_Base_ExternalScheduler_Step(NEXUS_ModulePriority priority, unsigned timeout, NEXUS_P_Base_Scheduler_Status *status, bool (*complete)(void *context), void *context)
523{
524    NEXUS_P_Scheduler *scheduler;
525
526    scheduler = NEXUS_P_Base_State.schedulers[priority];
527    return NEXUS_P_Scheduler_Step(scheduler, timeout, status, complete, context);
528}
529
530/* All the external context to get the scheduler's mutex. */
531void
532NEXUS_P_Base_GetSchedulerConfig(NEXUS_ModulePriority priority, NEXUS_Base_Scheduler_Config *config)
533{
534    BKNI_Memset(config, 0, sizeof(*config));
535    if (priority < NEXUS_ModulePriority_eMax) {
536        config->name = NEXUS_P_Scheduler_names[priority];
537        config->pSettings = &NEXUS_P_Base_State.settings.threadSettings[priority];
538
539        if (NEXUS_P_Base_State.schedulers[priority]) {
540            NEXUS_P_SchedulerInfo info;
541            NEXUS_P_SchedulerGetInfo(NEXUS_P_Base_State.schedulers[priority], &info);
542            config->callback_lock = info.callback_lock;
543        }
544    }
545    return;
546}
547#endif
548
549NEXUS_Error
550NEXUS_Base_Core_Init(void)
551{
552    NEXUS_Error rc;
553    BDBG_ASSERT(NEXUS_Base==NULL);
554    rc = NEXUS_P_Base_Os_Init();
555    if(rc!=BERR_SUCCESS) {
556        rc = BERR_TRACE(rc);
557        goto err_os;
558    }
559#if BDBG_DEBUG_BUILD
560    NEXUS_P_Base_SetModuleDebugLevel(NEXUS_GetEnv("wrn_modules"), BDBG_eWrn);
561    NEXUS_P_Base_SetModuleDebugLevel(NEXUS_GetEnv("msg_modules"), BDBG_eMsg);
562    NEXUS_P_Base_SetModuleDebugLevel(NEXUS_GetEnv("trace_modules"), BDBG_eTrace);
563#endif
564    NEXUS_P_Base_State.coreInit = true;
565 
566    return NEXUS_SUCCESS;
567err_os:
568    return BERR_TRACE(rc);
569}
570
571void
572NEXUS_Base_Core_Uninit(void)
573{
574    BDBG_ASSERT(NEXUS_Base==NULL);
575    BDBG_MSG_TRACE(("NEXUS_Base_Core_Uninit: NEXUS_P_Base_Os_Uninit"));
576    NEXUS_P_Base_Os_Uninit();
577    NEXUS_P_Base_State.coreInit = false;
578    return;
579}
580
581
582NEXUS_Error
583NEXUS_Base_Init(const NEXUS_Base_Settings *pSettings)
584{
585    BERR_Code rc;
586    unsigned i;
587    NEXUS_Base_Settings settings;
588
589
590    if(!pSettings) {
591        NEXUS_Base_GetDefaultSettings(&settings);
592        pSettings = &settings;
593    }
594
595    if(!NEXUS_P_Base_State.coreInit) {
596        BDBG_ERR(("NEXUS_Base_Core_Init should be called prior to NEXUS_Base_Init"));
597        NEXUS_Base_Core_Init();
598    }
599
600
601    BLST_S_INIT(&NEXUS_P_Base_State.modules);
602    NEXUS_P_Base_State.settings = *pSettings;
603    NEXUS_P_MapInit();
604
605    BDBG_ASSERT(NEXUS_Base==NULL);
606    rc = BKNI_CreateMutex(&NEXUS_P_Base_State.callbackHandlerLock);
607    if(rc!=BERR_SUCCESS) {
608        rc = BERR_TRACE(rc);
609        goto err_calback_handler_lock;
610    }
611
612    for(i=0;i<sizeof(NEXUS_P_Base_State.schedulers)/sizeof(NEXUS_P_Base_State.schedulers[0]);i++) {
613        NEXUS_P_Base_State.schedulers[i] = NULL;
614    }
615    NEXUS_Base = NEXUS_Module_Create(NEXUS_P_Base_Name, NULL);
616    if(!NEXUS_Base) {
617        rc = BERR_TRACE(BERR_OS_ERROR);
618        goto err_module;
619    }
620    NEXUS_LockModule();
621#if NEXUS_BASE_EXTERNAL_SCHEDULER
622    rc = NEXUS_P_Base_ExternalSchedulerInit(); /* initialize schedulers, but don't start threads */
623    if(rc!=BERR_SUCCESS) {
624        NEXUS_UnlockModule();
625        NEXUS_Module_Destroy(NEXUS_Base);
626        rc = BERR_TRACE(rc);
627        goto err_module;
628    }
629#endif
630    NEXUS_UnlockModule();
631    NEXUS_P_Base_Scheduler_Init();
632
633    return BERR_SUCCESS;
634
635err_module:
636    BKNI_DestroyMutex(NEXUS_P_Base_State.callbackHandlerLock);
637err_calback_handler_lock:
638    return rc;
639}
640
641#define NEXUS_P_FILENAME(str) ((str)?(str):"")
642
643void
644NEXUS_Base_Uninit(void)
645{
646    unsigned i;
647    BDBG_ASSERT(NEXUS_Base);
648    BDBG_MSG_TRACE(("NEXUS_Base_Uninit:>"));
649    NEXUS_LockModule();
650    BDBG_MSG_TRACE(("NEXUS_Base_Uninit:Locked"));
651    for(i=0;i<sizeof(NEXUS_P_Base_State.schedulers)/sizeof(NEXUS_P_Base_State.schedulers[0]);i++) {
652        if(NEXUS_P_Base_State.schedulers[i]) {
653            BDBG_MSG_TRACE(("NEXUS_Base_Uninit:NEXUS_P_Scheduler_Destroy"));
654            NEXUS_P_Scheduler_Destroy(NEXUS_P_Base_State.schedulers[i]);
655        }
656    }
657    BDBG_MSG_TRACE(("NEXUS_Base_Uninit: NEXUS_P_Base_Scheduler_Uninit"));
658    NEXUS_P_Base_Scheduler_Uninit();
659    BDBG_MSG_TRACE(("NEXUS_Base_Uninit: NEXUS_UnlockModule"));
660    NEXUS_UnlockModule();
661    BDBG_MSG_TRACE(("NEXUS_Base_Uninit: NEXUS_Module_Destroy"));
662    NEXUS_Module_Destroy(NEXUS_Base);
663    BDBG_MSG_TRACE(("NEXUS_Base_Uninit: BKNI_DestroyMutex"));
664    BKNI_DestroyMutex(NEXUS_P_Base_State.callbackHandlerLock);
665    NEXUS_Base = NULL;
666    return;
667}
668
669bool
670NEXUS_Module_Assert(NEXUS_ModuleHandle module)
671{
672    NEXUS_P_ThreadInfo *info;
673    NEXUS_P_LockEntry *entry;
674    info = NEXUS_P_ThreadInfo_Get();
675    if(info) {
676        if(BLIFO_READ_PEEK(&info->stack)>0) {
677            entry = BLIFO_READ(&info->stack);
678            return entry->module == module;
679    } else if (!module->enabled) {
680        return true;
681        } else {
682            return false;
683        }
684    }
685    return true;
686}
687
688static void
689NEXUS_Module_P_CheckLock(const char *function, NEXUS_P_ThreadInfo *info, NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber)
690{
691    BSTD_UNUSED(pFileName);
692    BSTD_UNUSED(lineNumber);
693    BSTD_UNUSED(function);
694    if(info && BLIFO_READ_PEEK(&info->stack)>0) {
695        const NEXUS_P_LockEntry *entry;
696        entry = BLIFO_READ(&info->stack);
697        if(entry->module == module) {
698            BDBG_ERR(("%s[%s]: trying apply recursive lock:%s at %s:%u old at %s:%u", function, info->pThreadName, module->pModuleName, NEXUS_P_FILENAME(pFileName), lineNumber, NEXUS_P_FILENAME(entry->pFileName), entry->lineNumber));
699            BDBG_ASSERT(0);
700        }
701    }
702}
703
704void
705NEXUS_Module_Lock_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber)
706{
707    NEXUS_P_ThreadInfo *info;
708    NEXUS_P_LockEntry *entry;
709    BERR_Code rc;
710    BSTD_UNUSED(pFileName);
711    BSTD_UNUSED(lineNumber);
712   
713    if (!module) {
714        BDBG_ERR(("Locking a NULL module handle. It is possible that the module was not initialized and the application is calling its API."));
715    }
716    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
717    info = NEXUS_P_ThreadInfo_Get();
718    NEXUS_Module_P_CheckLock("NEXUS_Module_Lock_Tagged", info, module, pFileName, lineNumber);
719    rc = BKNI_AcquireMutex(module->lock);
720    BDBG_ASSERT(rc==BERR_SUCCESS);
721    if(info) {
722        if(BLIFO_WRITE_PEEK(&info->stack)>0) {
723            entry = BLIFO_WRITE(&info->stack);
724            entry->module = module;
725            entry->pFileName = pFileName;
726            entry->lineNumber = lineNumber;
727            BLIFO_WRITE_COMMIT(&info->stack, 1);
728        } else {
729            BDBG_WRN(("NEXUS_Module_Lock[%s]: overflow of lock LIFO %s:%u", info->pThreadName, NEXUS_P_FILENAME(pFileName), lineNumber));
730        }
731    }
732    return;
733}
734
735
736bool
737NEXUS_Module_TryLock_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber )
738{
739    NEXUS_P_ThreadInfo *info;
740    NEXUS_P_LockEntry *entry;
741
742    BERR_Code rc;
743    BSTD_UNUSED(pFileName);
744    BSTD_UNUSED(lineNumber);
745    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
746    info = NEXUS_P_ThreadInfo_Get();
747    NEXUS_Module_P_CheckLock("NEXUS_Module_TryLock_Tagged", info, module, pFileName, lineNumber);
748    rc = BKNI_TryAcquireMutex(module->lock);
749    if(rc==BERR_SUCCESS && info) {
750        if(BLIFO_WRITE_PEEK(&info->stack)>0) {
751            entry = BLIFO_WRITE(&info->stack);
752            entry->module = module;
753            entry->pFileName = pFileName;
754            entry->lineNumber = lineNumber;
755            BLIFO_WRITE_COMMIT(&info->stack, 1);
756        } else {
757            BDBG_WRN(("NEXUS_Module_TryLock[%s]: overflow of lock LIFO %s:%u", info->pThreadName, NEXUS_P_FILENAME(pFileName), lineNumber));
758        }
759    }
760    return rc==BERR_SUCCESS;
761}
762
763void
764NEXUS_Module_Unlock_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber)
765{
766    NEXUS_P_ThreadInfo *info;
767    NEXUS_P_LockEntry *entry;
768
769    BSTD_UNUSED(pFileName);
770    BSTD_UNUSED(lineNumber);
771    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
772    info = NEXUS_P_ThreadInfo_Get();
773    if(info) {
774        if(BLIFO_READ_PEEK(&info->stack)>0) {
775            entry = BLIFO_READ(&info->stack);
776            if(entry->module!=module) {
777                BDBG_ERR(("NEXUS_Module_Unlock[%s]: not paired unlock operation %s(%s:%u), last lock:%s(%s:%u) ", info->pThreadName,  module->pModuleName, NEXUS_P_FILENAME(pFileName), lineNumber, entry->module->pModuleName, NEXUS_P_FILENAME(entry->pFileName), entry->lineNumber));
778                BDBG_ASSERT(0);
779            }
780            BLIFO_READ_COMMIT(&info->stack, 1);
781        } else {
782            BDBG_ERR(("NEXUS_Module_Unlock[%s]: underflow of lock LIFO (%s:%u)", info->pThreadName, NEXUS_P_FILENAME(pFileName), lineNumber));
783            BDBG_ASSERT(0);
784        }
785    }
786    BKNI_ReleaseMutex(module->lock);
787    return;
788}
789
790void
791NEXUS_Module_Enable_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber)
792{   
793    BSTD_UNUSED(pFileName);
794    BSTD_UNUSED(lineNumber);
795    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
796    BDBG_ASSERT(module->enabled == false);
797   
798    module->enabled = true;
799    BKNI_ReleaseMutex(module->lock);
800    BDBG_MSG(("Enabling %s Module", module->pModuleName));   
801
802    return;
803}
804
805void
806NEXUS_Module_Disable_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber)
807{   
808    BERR_Code rc;
809    BSTD_UNUSED(pFileName);
810    BSTD_UNUSED(lineNumber);
811    BDBG_OBJECT_ASSERT(module, NEXUS_Module);       
812    BDBG_ASSERT(module->enabled == true);
813   
814    BDBG_MSG(("Disabling %s Module", module->pModuleName));
815    rc = BKNI_AcquireMutex(module->lock);
816    BDBG_ASSERT(rc==BERR_SUCCESS);     
817
818    module->enabled = false;
819
820    return;
821}
822
823void
824NEXUS_Module_Use(NEXUS_ModuleHandle upModule, NEXUS_ModuleHandle downModule, const char *pFileName, unsigned lineNumber)
825{
826    BSTD_UNUSED(pFileName);
827    BSTD_UNUSED(lineNumber);
828    BSTD_UNUSED(upModule);
829    BSTD_UNUSED(downModule);
830    return;
831}
832
833void NEXUS_Module_SetCurrentClient(NEXUS_ModuleHandle module, NEXUS_HeapHandle heap, bool untrusted)
834{
835    module->currentClient.heap = heap;
836    module->currentClient.untrusted = untrusted;
837}
838
839NEXUS_HeapHandle NEXUS_Module_GetDefaultHeap(NEXUS_ModuleHandle module, bool boundsHeap)
840{
841    if (!boundsHeap || module->currentClient.untrusted) {
842        return module->currentClient.heap;
843    }
844    /* only NULL if bounds heap for trusted client */
845    return NULL;
846}
847
848void
849NEXUS_P_ThreadInfo_Init(NEXUS_P_ThreadInfo *info)
850{
851    BLIFO_INIT(&info->stack, info->locks, NEXUS_P_BASE_MAX_LOCKS);
852    return ;
853}
854
855void
856NEXUS_Module_GetPriority(NEXUS_ModuleHandle module, NEXUS_ModulePriority *pPriority)
857{
858    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
859    BDBG_ASSERT(pPriority);
860    *pPriority = module->settings.priority;
861    return ;
862}
863
864
865bool NEXUS_Module_ActiveStandyCompatible(NEXUS_ModuleHandle module)
866{
867    BDBG_OBJECT_ASSERT(module, NEXUS_Module);
868   
869    if(module->settings.priority == NEXUS_ModulePriority_eIdleActiveStandby ||
870       module->settings.priority == NEXUS_ModulePriority_eLowActiveStandby ||
871       module->settings.priority == NEXUS_ModulePriority_eHighActiveStandby) {
872    return true;
873    } else {
874    return false;
875    }
876}
877
878
879#ifdef NO_OS_DIAGS
880void
881NEXUS_Base_NO_OS_Scheduler_Dispatch(void)
882{
883    int idx;
884    for (idx=0; idx<NEXUS_ModulePriority_eMax; idx++)
885    {
886        if (NEXUS_P_Base_State.schedulers[idx])
887            NEXUS_P_NO_OS_Scheduler_Thread(NEXUS_P_Base_State.schedulers[idx]);
888    }
889}
890#endif /* NO_OS_DIAGS */
891
892void
893NEXUS_Module_EnumerateAll(void (*callback)(void *context, NEXUS_ModuleHandle module, const char *pModuleName, const NEXUS_ModuleSettings *pSettings), void *context)
894{
895    NEXUS_ModuleHandle module;
896    NEXUS_LockModule();
897    for(module=BLST_S_FIRST(&NEXUS_P_Base_State.modules); module!=NULL; module=BLST_S_NEXT(module, link)) {
898        callback(context,module,module->pModuleName,&module->settings);
899    }
900    NEXUS_UnlockModule();
901    return ;
902}
903
904int NEXUS_StrCmp(const char *str1, const char *str2)
905{
906    if(str1==NULL) {
907        if(str2==NULL) {
908            return 0;
909        } else {
910            return 1;
911        }
912    } else if(str2==NULL) {
913        return -1;
914    } else {
915        return NEXUS_P_Base_StrCmp(str1, str2);
916    }
917}
918
919BDBG_OBJECT_ID(NEXUS_CallbackHandler);
920
921BDBG_FILE_MODULE(nexus_callbackhandler);
922#define BDBG_MSG_CALLBACK(x)    /* BDBG_MODULE_MSG(nexus_callbackhandler, x) */
923
924void NEXUS_Base_P_CallbackHandler_Init(NEXUS_CallbackHandler *handler, NEXUS_ModuleHandle module, void (*pCallback)(void *), void *pContext,const char *pFileName,unsigned lineNumber)
925{
926    BDBG_ASSERT(handler);
927    BDBG_OBJECT_INIT(handler, NEXUS_CallbackHandler);
928    BDBG_MSG_CALLBACK(("Init:%#x", (unsigned)handler));
929    handler->module = module;
930    handler->pCallback = pCallback;
931    handler->pContext = pContext;
932    handler->pFileName = pFileName;
933    handler->lineNumber = lineNumber;
934    handler->pCallbackGuard = NULL;
935    handler->timer = NULL;
936    return;
937}
938
939static void NEXUS_Base_P_CallbackHandler_TimerDispatch(void *context)
940{
941    NEXUS_CallbackHandler *handler=context;
942    BDBG_OBJECT_ASSERT(handler, NEXUS_CallbackHandler);
943    /* module lock already acquired by the scheduller */
944    BKNI_AcquireMutex(NEXUS_P_Base_State.callbackHandlerLock);
945    handler->timer=NULL;
946    BKNI_ReleaseMutex(NEXUS_P_Base_State.callbackHandlerLock);
947    if(handler->pCallbackGuard) {
948        NEXUS_Error rc = handler->pCallbackGuard(handler->pContext);
949        if(rc!=NEXUS_SUCCESS) {
950            BDBG_MSG_CALLBACK(("Timer Deflected:%#x", (unsigned)handler));
951            return;
952        }
953    }
954    BDBG_MSG_CALLBACK(("Timer:%#x", (unsigned)handler));
955    handler->pCallback(handler->pContext);
956    return;
957}
958
959static void NEXUS_Base_P_CallbackHandler_TimerCancel(NEXUS_CallbackHandler *handler)
960{
961    BDBG_MSG_CALLBACK(("TimerCanceled:%#x %#x", (unsigned)handler, (unsigned)handler->timer));
962    BKNI_AcquireMutex(NEXUS_P_Base_State.callbackHandlerLock);
963    if(handler->timer) {
964        NEXUS_Module_CancelTimer(handler->module, handler->timer, handler->pFileName, handler->lineNumber);
965        handler->timer = NULL;
966    }
967    BKNI_ReleaseMutex(NEXUS_P_Base_State.callbackHandlerLock);
968    return;
969}
970
971void NEXUS_Base_P_CallbackHandler_Dispatch(void *context, int arg)
972{
973    NEXUS_CallbackHandler *handler=context;
974    BSTD_UNUSED(arg);
975    BDBG_OBJECT_ASSERT(handler, NEXUS_CallbackHandler);
976    if(handler->pCallbackGuard) {
977        NEXUS_Error rc = handler->pCallbackGuard(handler->pContext);
978        if(rc!=NEXUS_SUCCESS) {
979            BDBG_MSG_CALLBACK(("Deflected:%#x", (unsigned)handler));
980            return;
981        }
982    }
983
984    if(NEXUS_Module_TryLock_Tagged(handler->module, handler->pFileName, handler->lineNumber)) {
985        /* don't check timer, if it was set it would just cause 1:1 mapping between schedulled callback and callbacks executed */
986        BDBG_MSG_CALLBACK(("Locked:%#x", (unsigned)handler));
987        handler->pCallback(handler->pContext);
988        NEXUS_Module_Unlock_Tagged(handler->module, handler->pFileName, handler->lineNumber);
989    } else {
990        BKNI_AcquireMutex(NEXUS_P_Base_State.callbackHandlerLock);
991        if(handler->timer==NULL) {
992            BDBG_MSG_CALLBACK(("Queued:%#x", (unsigned)handler));
993            handler->timer = NEXUS_Module_ScheduleTimer(handler->module, 0, NEXUS_Base_P_CallbackHandler_TimerDispatch, handler, handler->pFileName, handler->lineNumber);
994        } else {
995            BDBG_MSG_CALLBACK(("Skipped:%#x %#x", (unsigned)handler, (unsigned)handler->timer));
996            /* however if timer is already set, then multiple callbacks get collapsed, this is fine, since callbacks don't have guarantees to get called for each  'Fire' function */
997        }
998        BKNI_ReleaseMutex(NEXUS_P_Base_State.callbackHandlerLock);
999    }
1000    return;
1001}
1002
1003void NEXUS_Base_P_CallbackHandler_Stop(NEXUS_CallbackHandler *handler)
1004{
1005    BDBG_OBJECT_ASSERT(handler, NEXUS_CallbackHandler);
1006    BDBG_MSG_CALLBACK(("Stop:%#x", (unsigned)handler));
1007    /* cancel any pending timer */
1008    NEXUS_Base_P_CallbackHandler_TimerCancel(handler);
1009    return;
1010}
1011
1012
1013void NEXUS_Base_P_CallbackHandler_Shutdown(NEXUS_CallbackHandler *handler)
1014{
1015    BDBG_OBJECT_ASSERT(handler, NEXUS_CallbackHandler);
1016    BDBG_MSG_CALLBACK(("Shutdown:%#x", (unsigned)handler));
1017    NEXUS_Base_P_CallbackHandler_TimerCancel(handler);
1018#if 0
1019    BDBG_OBJECT_UNSET(handler, NEXUS_CallbackHandler);
1020#else
1021    BDBG_OBJECT_DESTROY(handler, NEXUS_CallbackHandler);
1022#endif
1023    return;
1024}
1025
1026BDBG_FILE_MODULE(nexus_refcnt);
1027#define BDBG_REFCNT(x) BDBG_MODULE_MSG(nexus_refcnt,x)
1028
1029
1030void NEXUS_RefCntObj_P_Init(NEXUS_RefCnt *cnt, const NEXUS_RefCntDescriptor *descriptor)
1031{
1032    BDBG_ASSERT(cnt);
1033    BDBG_ASSERT(descriptor);
1034    BDBG_REFCNT(("%p: Init %p", descriptor, ((uint8_t *)cnt)-descriptor->offset));
1035    cnt->ref_cnt = 1;
1036    cnt->descriptor = descriptor;
1037    return;
1038}
1039
1040static int b_add_ref_cnf(NEXUS_RefCnt *cnt, int add, NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber)
1041{
1042    int result;
1043    if(module) {
1044        NEXUS_Module_Lock_Tagged(module, pFileName, lineNumber);
1045    }
1046    result = cnt->ref_cnt + add;
1047    cnt->ref_cnt = result;
1048    if(module) {
1049        NEXUS_Module_Unlock_Tagged(module, pFileName, lineNumber);
1050    }
1051    return result;
1052}
1053
1054void NEXUS_RefCntObj_P_Acquire_Tagged(void *object, const NEXUS_RefCntDescriptor *descriptor, NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber)
1055{
1056    int result;
1057    NEXUS_RefCnt *cnt;
1058
1059    BDBG_ASSERT(descriptor);
1060
1061    cnt = (void *)((uint8_t *)object + descriptor->offset);
1062    BDBG_REFCNT(("%p: Acquire %p %u %s:%u", cnt->descriptor, object, cnt->ref_cnt, pFileName, lineNumber));
1063    result = b_add_ref_cnf(cnt, 1, module, pFileName, lineNumber);
1064    BDBG_ASSERT(result>0);
1065    return;
1066}
1067
1068void NEXUS_RefCntObj_P_Release_Tagged(void *object, const NEXUS_RefCntDescriptor *descriptor, NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber)
1069{
1070    int result;
1071    NEXUS_RefCnt *cnt;
1072
1073    BDBG_ASSERT(descriptor);
1074
1075    cnt = (void *)((uint8_t *)object + descriptor->offset);
1076    BDBG_REFCNT(("%p: Release %p %u %s:%u", cnt->descriptor, object, cnt->ref_cnt, pFileName, lineNumber));
1077    result = b_add_ref_cnf(cnt, -1, module, pFileName, lineNumber);
1078    BDBG_ASSERT(result>=0);
1079    if(result<=0) {
1080        if(module) {
1081            NEXUS_Module_Lock_Tagged(module, pFileName, lineNumber);
1082        }
1083        BDBG_ASSERT(descriptor->finalizer);
1084        BDBG_REFCNT(("%p: Finalize %p %u %s:%u", cnt->descriptor, object, cnt->ref_cnt, pFileName, lineNumber));
1085        descriptor->finalizer(object);
1086        if(module) {
1087            NEXUS_Module_Unlock_Tagged(module, pFileName, lineNumber);
1088        }
1089    }
1090    return;
1091}
1092
Note: See TracBrowser for help on using the repository browser.