/*************************************************************************** * (c)2008-2011 Broadcom Corporation * * This program is the proprietary software of Broadcom Corporation and/or its licensors, * and may only be used, duplicated, modified or distributed pursuant to the terms and * conditions of a separate, written license agreement executed between you and Broadcom * (an "Authorized License"). Except as set forth in an Authorized License, Broadcom grants * no license (express or implied), right to use, or waiver of any kind with respect to the * Software, and Broadcom expressly reserves all rights in and to the Software and all * intellectual property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU * HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY * NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. * * Except as expressly set forth in the Authorized License, * * 1. This program, including its structure, sequence and organization, constitutes the valuable trade * secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof, * and to use this information only in connection with your use of Broadcom integrated circuit products. * * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" * AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO * THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, * LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION * OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF * USE OR PERFORMANCE OF THE SOFTWARE. * * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS * LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR * EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR * USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT * ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF * ANY LIMITED REMEDY. * * $brcm_Workfile: nexus_base.c $ * $brcm_Revision: 42 $ * $brcm_Date: 11/29/11 11:37a $ * * API Description: * * Revision History: * * $brcm_Log: /nexus/base/src/nexus_base.c $ * * 42 11/29/11 11:37a erickson * SW7420-2129: store current default heap per module * * 41 11/11/11 2:59p vsilyaev * SW7125-1156, SW7420-2085: Fixed debug output * * 40 11/4/11 1:54p vsilyaev * SW7231-439: Improved debuggability * * 39 11/4/11 1:01p vsilyaev * SW7231-439, SW7420-2085: Added debug code for the reference counting * * 38 10/7/11 1:49p vsilyaev * SW7420-2085: Added support for object reference counting * * 37 9/14/11 2:10p erickson * SW7405-5478: add NEXUS_Module_GetName for debug * * 36 8/5/11 5:13p erickson * SW7420-1123: attempt to give more helpful error if module handle is * NULL. likely just uninitialized. * * 35 8/2/11 2:58p vsilyaev * SW7125-1014 : Add additional scheduler threads for active standby * modules * * SW7125-1014/3 8/2/11 10:09a gmohile * SW7125-1014 : Add additional scheduler threads for active standby * modules * * 34 7/21/11 2:32p vsilyaev * SW7125-1014 : Add module enable/disable * * SW7125-1014/2 7/20/11 4:38p gmohile * SW7125-1014 : Add module enable/disable * * SW7125-1014/1 7/12/11 3:05p gmohile * SW7125-1014 : Add module enable function * * 33 5/31/11 3:12p erickson * SW7420-1907: unlock module in NEXUS_Module_Create if param check fails * * 32 5/13/11 4:13p erickson * SWDTV-6386: add "nx_" namespace prefix for internal nexus threads * * 31 4/5/11 12:16p vsilyaev * SW7405-5221: Fixed linuxkernel build * * 30 4/4/11 6:14p vsilyaev * SW7405-5221: Added option to forward debug output to FIFO * * 29 3/30/11 6:56p vsilyaev * SW7335-1214: Serialize access to the field that holds a timer handle * * 28 3/16/11 10:11a erickson * SW7420-1642: add NEXUS_Base_Settings.driverModuleInit and * .driverModuleUninit * * 27 2/9/11 10:43a erickson * SW7425-63: refactor default NEXUS_ModuleSettings to fix uninitialized * memory * * 26 1/28/11 11:48a mphillip * SW7425-63: Fix initializer warning * * 25 1/19/11 11:11a erickson * SW7420-1123: add NEXUS_Module_GetSettings * * 24 11/15/10 3:11p vsilyaev * SW7405-4996: Added NEXUS_StrCmp * * 23 11/15/10 3:05p vsilyaev * SWNOOS-430: Replaced NO_OS with NO_OS_DIAGS * * 22 9/23/10 2:12p erickson * SW7420-943: refactor for driver/firmware partitioning * * 21 11/24/09 12:25p erickson * SW7405-3439: rename nexus/base external scheduler interface functions * * 20 6/23/09 5:27p vsilyaev * PR 54926: Added NEXUS_Module_EnumerateAll * * 19 6/19/09 3:20p vsilyaev * PR 54926: Added debug options to the module settings * * 18 4/19/09 7:20p agin * PR54339: Add nexus no-os scheduler support. * * 17 4/8/09 12:33p erickson * PR53862: use NEXUS_P_SchedulerGetInfo to get scheduler's callback_lock * * 16 2/6/09 10:22a erickson * PR51878: fix warning * * 15 1/28/09 6:27p vsilyaev * PR 51392: Moved magnum initialization from Nexus base to the platform. * Initialize only magnum layer inside of * NEXUS_Platform_GetDefaultSettings * * 14 1/20/09 3:46p vsilyaev * PR 49285, PR 50582: Improved debugability of scheduller and fixed * problem in the scheduller, where it goes to WaitForGroup to extended * amount of time * * 13 11/7/08 11:49a erickson * PR35457: update comments * * 12 11/5/08 12:15p vsilyaev * PR 48694: Separated handling of linuxkernel and linuxkernel with * driver/ioctls/proxy * * 11 8/19/08 12:49p erickson * PR45859: print module priority using BDBG_MSG * * 10 8/6/08 2:24p erickson * PR45469: move NEXUS_Base_GetDefaultSettings to OS specific code * * 9 6/9/08 7:11p vsilyaev * PR 43184: Changed phase of detection for outstanding callbacks * * 8 6/5/08 2:19p vsilyaev * PR 42318: Rearranged scheduller to share the same context in user and * kernel mode, this allows to serve callback from kernel to user with * single transition kernel<->user * * 7 4/2/08 11:31a erickson * PR40198: fix DEBUG=n warning * * 6 3/27/08 5:29p rjlewis * PR40352: zero malloced memory. * * 5 3/20/08 6:15p rjlewis * PR40352: type mismatch compile error under VxWorks. * * 4 2/28/08 9:39p vsilyaev * PR 40103: Added NEXUS_TaskCallback functions * * 3 2/22/08 10:52a erickson * PR39870: convert assert to runtime check for coverity * * 2 1/31/08 11:49a vsilyaev * PR 38682: Added support for runtime options * * 1 1/18/08 2:13p jgarrett * PR 38808: Merging to main branch * * Nexus_Devel/19 1/16/08 3:37p vsilyaev * PR 38682: Don't execute KNI/DBG initialization in the linuxkernel * * Nexus_Devel/18 11/14/07 5:22p vsilyaev * PR 35824: Fixed NEXUS_Module_Assert behaviour on unknown threads * * Nexus_Devel/17 11/9/07 5:59p vsilyaev * PR 34419: Added check for the recursive used of locks * * Nexus_Devel/16 10/23/07 4:16p vsilyaev * PR 36199: Added memory mapper sub-module * * Nexus_Devel/15 10/12/07 5:42p vsilyaev * PR 35824: Fixed NEXUS_TryLockModules * * Nexus_Devel/14 10/10/07 4:19p vsilyaev * PR 35824: Added NEXUS_Time type * * Nexus_Devel/13 10/3/07 2:51p vsilyaev * PR 34419: Renamed cntx to context * * Nexus_Devel/12 9/28/07 6:47p vsilyaev * PR 34419: Added functions to fire callback from the interrupt context * * Nexus_Devel/11 9/28/07 1:03p vsilyaev * PR 34419: Added more debug output on exit and fixed typo in the debug * print * * Nexus_Devel/10 9/24/07 10:24p vsilyaev * PR 34419: Fixed memory leak * * Nexus_Devel/9 9/24/07 6:15p jgarrett * PR 35002: Fixing string funcs * * Nexus_Devel/8 9/24/07 10:33a vsilyaev * PR 34419: Added tagged versions of Nexus_Module_Lock and NEXUS_atoi * function * * Nexus_Devel/7 9/21/07 6:26p jgarrett * PR 35002: Fixing Base_Init(NULL) * * Nexus_Devel/6 9/10/07 4:32p vsilyaev * PR 34419: Added NEXUS_CallbackDesc * * Nexus_Devel/5 9/7/07 3:07p vsilyaev * PR 34419: Create schedullers on demand * * Nexus_Devel/4 9/4/07 2:43p vsilyaev * PR 34419: Use GetDefaultSettings * * Nexus_Devel/3 8/31/07 6:02p vsilyaev * PR 34419: Added configuration structure for NEXUS_Base * * Nexus_Devel/2 8/30/07 7:07p vsilyaev * PR 34419: More complete implementation * * Nexus_Devel/1 8/28/07 6:39p vsilyaev * PR 34419: Initial implementation * ***************************************************************************/ #include "nexus_base.h" #include "nexus_base_priv.h" #include "nexus_base_os_types.h" #include "bkni_multi.h" #define BDBG_MSG_TRACE(x) BDBG_MSG(x) BDBG_MODULE(nexus_base); static struct { NEXUS_P_Scheduler *schedulers[NEXUS_ModulePriority_eMax]; BLST_S_HEAD(NEXUS_P_ModuleList, NEXUS_Module) modules; BKNI_MutexHandle callbackHandlerLock; /* lock that serializes access to the field that holds timer handle */ NEXUS_Base_Settings settings; bool coreInit; } NEXUS_P_Base_State; static const char NEXUS_P_Base_Name[] = "NEXUS_Base"; void NEXUS_Module_GetDefaultSettings(NEXUS_ModuleSettings *pSettings) { BKNI_Memset(pSettings, 0, sizeof(*pSettings)); pSettings->priority = NEXUS_ModulePriority_eDefault; } BDBG_OBJECT_ID(NEXUS_Module); NEXUS_ModuleHandle NEXUS_Base=NULL; #if BDBG_DEBUG_BUILD static const char * NEXUS_P_Base_StrChr(const char *str, char c) { for(;;str++) { char ch = *str; if( ch==c) { return str; } else if (ch=='\0') { return NULL; } } } static char * NEXUS_P_Base_Strncpy(char *dst, const char *src, size_t len) { char *buf; for(buf=dst;len>0;buf++,src++) { char ch = *src; *buf=ch; len--; if(ch=='\0') { break; } } for(;len>0;len--,buf++) { *buf='\0'; } return dst; } static void NEXUS_P_Base_SetModuleDebugLevel(const char *modulelist, BDBG_Level level) { if(!modulelist) { return; } for(;;) { char buf[64]; const char *end = NEXUS_P_Base_StrChr(modulelist, ','); size_t name_len; if (!end) { if(*modulelist) { BDBG_SetModuleLevel(modulelist, level); } break; } name_len = end-modulelist; if(name_len>0 && name_lencallback = NULL; desc->context = NULL; desc->param = 0; return; } NEXUS_ModuleHandle NEXUS_Module_Create(const char *pModuleName, const NEXUS_ModuleSettings *pSettings) { NEXUS_ModuleHandle module; NEXUS_ModuleHandle prev,cur; BERR_Code rc; NEXUS_ModuleSettings defaultSettings; BDBG_ASSERT(pModuleName); if(pModuleName!=NEXUS_P_Base_Name) { NEXUS_LockModule(); } if(pSettings==NULL) { NEXUS_Module_GetDefaultSettings(&defaultSettings); pSettings = &defaultSettings; } if ((unsigned)pSettings->priority >= sizeof(NEXUS_P_Base_State.schedulers)/sizeof(NEXUS_P_Base_State.schedulers[0])) { rc = BERR_TRACE(BERR_INVALID_PARAMETER); goto err_paramcheck; } module = BKNI_Malloc(sizeof(*module)); if(!module) { rc = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY); goto err_alloc; } BKNI_Memset(module, 0, sizeof(*module)); BDBG_OBJECT_INIT(module, NEXUS_Module); module->settings = *pSettings; module->pModuleName = pModuleName; module->currentClient.heap = NULL; module->currentClient.untrusted = false; rc = BKNI_CreateMutex(&module->lock); if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); goto err_lock; } if(pModuleName!=NEXUS_P_Base_Name) { if(NEXUS_P_Base_State.schedulers[pSettings->priority]==NULL) { /* create scheduler on demand */ 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]); if(NEXUS_P_Base_State.schedulers[pSettings->priority]==NULL) { rc = BERR_TRACE(BERR_OS_ERROR); goto err_scheduler; } } module->scheduler = NEXUS_P_Base_State.schedulers[pSettings->priority]; } else { module->scheduler = NULL; } /* insert into the sorted list */ for(prev=NULL, cur=BLST_S_FIRST(&NEXUS_P_Base_State.modules); cur!=NULL; cur=BLST_S_NEXT(cur, link)) { int cmp; cmp = NEXUS_P_Base_StrCmp(pModuleName, cur->pModuleName); if(cmp<0) { break; /* Bingo */ } else if(cmp==0) { BDBG_ERR(("NEXUS_Module_Create: duplicated module name")); rc = BERR_TRACE(BERR_INVALID_PARAMETER); goto err_name; } prev = cur; } if(prev) { BLST_S_INSERT_AFTER(&NEXUS_P_Base_State.modules, prev, module, link); } else { BLST_S_INSERT_HEAD(&NEXUS_P_Base_State.modules, module, link); } if (NEXUS_P_Base_State.settings.driverModuleInit) { (NEXUS_P_Base_State.settings.driverModuleInit)(NEXUS_P_Base_State.settings.procContext, module, pModuleName, pSettings); } module->enabled = true; if(pModuleName!=NEXUS_P_Base_Name) { NEXUS_UnlockModule(); } BDBG_MSG(("Creating module %s, priority %d", pModuleName, pSettings->priority)); return module; err_name: err_scheduler: BKNI_DestroyMutex(module->lock); err_lock: BKNI_Free(module); err_alloc: err_paramcheck: if(pModuleName!=NEXUS_P_Base_Name) { NEXUS_UnlockModule(); } return NULL; } void NEXUS_Module_Destroy(NEXUS_ModuleHandle module) { BDBG_OBJECT_ASSERT(module, NEXUS_Module); NEXUS_LockModule(); if (NEXUS_P_Base_State.settings.driverModuleUninit) { (NEXUS_P_Base_State.settings.driverModuleUninit)(NEXUS_P_Base_State.settings.procContext, module, module->pModuleName, &module->settings); } BDBG_MSG(("Destroying module %s", module->pModuleName)); module->enabled = false; BLST_S_REMOVE(&NEXUS_P_Base_State.modules, module, NEXUS_Module, link); NEXUS_UnlockModule(); BKNI_DestroyMutex(module->lock); BDBG_OBJECT_DESTROY(module, NEXUS_Module); BKNI_Free(module); return; } const char *NEXUS_Module_GetName(NEXUS_ModuleHandle module) { BDBG_OBJECT_ASSERT(module, NEXUS_Module); return module->pModuleName; } void NEXUS_Module_GetSettings( NEXUS_ModuleHandle module, NEXUS_ModuleSettings *pSettings ) { BDBG_OBJECT_ASSERT(module, NEXUS_Module); NEXUS_LockModule(); *pSettings = module->settings; NEXUS_UnlockModule(); } /* See nexus/base/src/$(OS)/nexus_base_os.c for NEXUS_Base_GetDefaultSettings */ #if NEXUS_BASE_EXTERNAL_SCHEDULER /** Allow an external scheduler to drive the scheduler state machine. This allows for thread consolidation in complex systems like linux kernel mode. */ static NEXUS_Error NEXUS_P_Base_ExternalSchedulerInit(void) { unsigned i; for(i=0;iname = NEXUS_P_Scheduler_names[priority]; config->pSettings = &NEXUS_P_Base_State.settings.threadSettings[priority]; if (NEXUS_P_Base_State.schedulers[priority]) { NEXUS_P_SchedulerInfo info; NEXUS_P_SchedulerGetInfo(NEXUS_P_Base_State.schedulers[priority], &info); config->callback_lock = info.callback_lock; } } return; } #endif NEXUS_Error NEXUS_Base_Core_Init(void) { NEXUS_Error rc; BDBG_ASSERT(NEXUS_Base==NULL); rc = NEXUS_P_Base_Os_Init(); if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); goto err_os; } #if BDBG_DEBUG_BUILD NEXUS_P_Base_SetModuleDebugLevel(NEXUS_GetEnv("wrn_modules"), BDBG_eWrn); NEXUS_P_Base_SetModuleDebugLevel(NEXUS_GetEnv("msg_modules"), BDBG_eMsg); NEXUS_P_Base_SetModuleDebugLevel(NEXUS_GetEnv("trace_modules"), BDBG_eTrace); #endif NEXUS_P_Base_State.coreInit = true; return NEXUS_SUCCESS; err_os: return BERR_TRACE(rc); } void NEXUS_Base_Core_Uninit(void) { BDBG_ASSERT(NEXUS_Base==NULL); BDBG_MSG_TRACE(("NEXUS_Base_Core_Uninit: NEXUS_P_Base_Os_Uninit")); NEXUS_P_Base_Os_Uninit(); NEXUS_P_Base_State.coreInit = false; return; } NEXUS_Error NEXUS_Base_Init(const NEXUS_Base_Settings *pSettings) { BERR_Code rc; unsigned i; NEXUS_Base_Settings settings; if(!pSettings) { NEXUS_Base_GetDefaultSettings(&settings); pSettings = &settings; } if(!NEXUS_P_Base_State.coreInit) { BDBG_ERR(("NEXUS_Base_Core_Init should be called prior to NEXUS_Base_Init")); NEXUS_Base_Core_Init(); } BLST_S_INIT(&NEXUS_P_Base_State.modules); NEXUS_P_Base_State.settings = *pSettings; NEXUS_P_MapInit(); BDBG_ASSERT(NEXUS_Base==NULL); rc = BKNI_CreateMutex(&NEXUS_P_Base_State.callbackHandlerLock); if(rc!=BERR_SUCCESS) { rc = BERR_TRACE(rc); goto err_calback_handler_lock; } for(i=0;i")); NEXUS_LockModule(); BDBG_MSG_TRACE(("NEXUS_Base_Uninit:Locked")); for(i=0;istack)>0) { entry = BLIFO_READ(&info->stack); return entry->module == module; } else if (!module->enabled) { return true; } else { return false; } } return true; } static void NEXUS_Module_P_CheckLock(const char *function, NEXUS_P_ThreadInfo *info, NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber) { BSTD_UNUSED(pFileName); BSTD_UNUSED(lineNumber); BSTD_UNUSED(function); if(info && BLIFO_READ_PEEK(&info->stack)>0) { const NEXUS_P_LockEntry *entry; entry = BLIFO_READ(&info->stack); if(entry->module == module) { 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)); BDBG_ASSERT(0); } } } void NEXUS_Module_Lock_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber) { NEXUS_P_ThreadInfo *info; NEXUS_P_LockEntry *entry; BERR_Code rc; BSTD_UNUSED(pFileName); BSTD_UNUSED(lineNumber); if (!module) { BDBG_ERR(("Locking a NULL module handle. It is possible that the module was not initialized and the application is calling its API.")); } BDBG_OBJECT_ASSERT(module, NEXUS_Module); info = NEXUS_P_ThreadInfo_Get(); NEXUS_Module_P_CheckLock("NEXUS_Module_Lock_Tagged", info, module, pFileName, lineNumber); rc = BKNI_AcquireMutex(module->lock); BDBG_ASSERT(rc==BERR_SUCCESS); if(info) { if(BLIFO_WRITE_PEEK(&info->stack)>0) { entry = BLIFO_WRITE(&info->stack); entry->module = module; entry->pFileName = pFileName; entry->lineNumber = lineNumber; BLIFO_WRITE_COMMIT(&info->stack, 1); } else { BDBG_WRN(("NEXUS_Module_Lock[%s]: overflow of lock LIFO %s:%u", info->pThreadName, NEXUS_P_FILENAME(pFileName), lineNumber)); } } return; } bool NEXUS_Module_TryLock_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber ) { NEXUS_P_ThreadInfo *info; NEXUS_P_LockEntry *entry; BERR_Code rc; BSTD_UNUSED(pFileName); BSTD_UNUSED(lineNumber); BDBG_OBJECT_ASSERT(module, NEXUS_Module); info = NEXUS_P_ThreadInfo_Get(); NEXUS_Module_P_CheckLock("NEXUS_Module_TryLock_Tagged", info, module, pFileName, lineNumber); rc = BKNI_TryAcquireMutex(module->lock); if(rc==BERR_SUCCESS && info) { if(BLIFO_WRITE_PEEK(&info->stack)>0) { entry = BLIFO_WRITE(&info->stack); entry->module = module; entry->pFileName = pFileName; entry->lineNumber = lineNumber; BLIFO_WRITE_COMMIT(&info->stack, 1); } else { BDBG_WRN(("NEXUS_Module_TryLock[%s]: overflow of lock LIFO %s:%u", info->pThreadName, NEXUS_P_FILENAME(pFileName), lineNumber)); } } return rc==BERR_SUCCESS; } void NEXUS_Module_Unlock_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber) { NEXUS_P_ThreadInfo *info; NEXUS_P_LockEntry *entry; BSTD_UNUSED(pFileName); BSTD_UNUSED(lineNumber); BDBG_OBJECT_ASSERT(module, NEXUS_Module); info = NEXUS_P_ThreadInfo_Get(); if(info) { if(BLIFO_READ_PEEK(&info->stack)>0) { entry = BLIFO_READ(&info->stack); if(entry->module!=module) { 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)); BDBG_ASSERT(0); } BLIFO_READ_COMMIT(&info->stack, 1); } else { BDBG_ERR(("NEXUS_Module_Unlock[%s]: underflow of lock LIFO (%s:%u)", info->pThreadName, NEXUS_P_FILENAME(pFileName), lineNumber)); BDBG_ASSERT(0); } } BKNI_ReleaseMutex(module->lock); return; } void NEXUS_Module_Enable_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber) { BSTD_UNUSED(pFileName); BSTD_UNUSED(lineNumber); BDBG_OBJECT_ASSERT(module, NEXUS_Module); BDBG_ASSERT(module->enabled == false); module->enabled = true; BKNI_ReleaseMutex(module->lock); BDBG_MSG(("Enabling %s Module", module->pModuleName)); return; } void NEXUS_Module_Disable_Tagged(NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber) { BERR_Code rc; BSTD_UNUSED(pFileName); BSTD_UNUSED(lineNumber); BDBG_OBJECT_ASSERT(module, NEXUS_Module); BDBG_ASSERT(module->enabled == true); BDBG_MSG(("Disabling %s Module", module->pModuleName)); rc = BKNI_AcquireMutex(module->lock); BDBG_ASSERT(rc==BERR_SUCCESS); module->enabled = false; return; } void NEXUS_Module_Use(NEXUS_ModuleHandle upModule, NEXUS_ModuleHandle downModule, const char *pFileName, unsigned lineNumber) { BSTD_UNUSED(pFileName); BSTD_UNUSED(lineNumber); BSTD_UNUSED(upModule); BSTD_UNUSED(downModule); return; } void NEXUS_Module_SetCurrentClient(NEXUS_ModuleHandle module, NEXUS_HeapHandle heap, bool untrusted) { module->currentClient.heap = heap; module->currentClient.untrusted = untrusted; } NEXUS_HeapHandle NEXUS_Module_GetDefaultHeap(NEXUS_ModuleHandle module, bool boundsHeap) { if (!boundsHeap || module->currentClient.untrusted) { return module->currentClient.heap; } /* only NULL if bounds heap for trusted client */ return NULL; } void NEXUS_P_ThreadInfo_Init(NEXUS_P_ThreadInfo *info) { BLIFO_INIT(&info->stack, info->locks, NEXUS_P_BASE_MAX_LOCKS); return ; } void NEXUS_Module_GetPriority(NEXUS_ModuleHandle module, NEXUS_ModulePriority *pPriority) { BDBG_OBJECT_ASSERT(module, NEXUS_Module); BDBG_ASSERT(pPriority); *pPriority = module->settings.priority; return ; } bool NEXUS_Module_ActiveStandyCompatible(NEXUS_ModuleHandle module) { BDBG_OBJECT_ASSERT(module, NEXUS_Module); if(module->settings.priority == NEXUS_ModulePriority_eIdleActiveStandby || module->settings.priority == NEXUS_ModulePriority_eLowActiveStandby || module->settings.priority == NEXUS_ModulePriority_eHighActiveStandby) { return true; } else { return false; } } #ifdef NO_OS_DIAGS void NEXUS_Base_NO_OS_Scheduler_Dispatch(void) { int idx; for (idx=0; idxpModuleName,&module->settings); } NEXUS_UnlockModule(); return ; } int NEXUS_StrCmp(const char *str1, const char *str2) { if(str1==NULL) { if(str2==NULL) { return 0; } else { return 1; } } else if(str2==NULL) { return -1; } else { return NEXUS_P_Base_StrCmp(str1, str2); } } BDBG_OBJECT_ID(NEXUS_CallbackHandler); BDBG_FILE_MODULE(nexus_callbackhandler); #define BDBG_MSG_CALLBACK(x) /* BDBG_MODULE_MSG(nexus_callbackhandler, x) */ void NEXUS_Base_P_CallbackHandler_Init(NEXUS_CallbackHandler *handler, NEXUS_ModuleHandle module, void (*pCallback)(void *), void *pContext,const char *pFileName,unsigned lineNumber) { BDBG_ASSERT(handler); BDBG_OBJECT_INIT(handler, NEXUS_CallbackHandler); BDBG_MSG_CALLBACK(("Init:%#x", (unsigned)handler)); handler->module = module; handler->pCallback = pCallback; handler->pContext = pContext; handler->pFileName = pFileName; handler->lineNumber = lineNumber; handler->pCallbackGuard = NULL; handler->timer = NULL; return; } static void NEXUS_Base_P_CallbackHandler_TimerDispatch(void *context) { NEXUS_CallbackHandler *handler=context; BDBG_OBJECT_ASSERT(handler, NEXUS_CallbackHandler); /* module lock already acquired by the scheduller */ BKNI_AcquireMutex(NEXUS_P_Base_State.callbackHandlerLock); handler->timer=NULL; BKNI_ReleaseMutex(NEXUS_P_Base_State.callbackHandlerLock); if(handler->pCallbackGuard) { NEXUS_Error rc = handler->pCallbackGuard(handler->pContext); if(rc!=NEXUS_SUCCESS) { BDBG_MSG_CALLBACK(("Timer Deflected:%#x", (unsigned)handler)); return; } } BDBG_MSG_CALLBACK(("Timer:%#x", (unsigned)handler)); handler->pCallback(handler->pContext); return; } static void NEXUS_Base_P_CallbackHandler_TimerCancel(NEXUS_CallbackHandler *handler) { BDBG_MSG_CALLBACK(("TimerCanceled:%#x %#x", (unsigned)handler, (unsigned)handler->timer)); BKNI_AcquireMutex(NEXUS_P_Base_State.callbackHandlerLock); if(handler->timer) { NEXUS_Module_CancelTimer(handler->module, handler->timer, handler->pFileName, handler->lineNumber); handler->timer = NULL; } BKNI_ReleaseMutex(NEXUS_P_Base_State.callbackHandlerLock); return; } void NEXUS_Base_P_CallbackHandler_Dispatch(void *context, int arg) { NEXUS_CallbackHandler *handler=context; BSTD_UNUSED(arg); BDBG_OBJECT_ASSERT(handler, NEXUS_CallbackHandler); if(handler->pCallbackGuard) { NEXUS_Error rc = handler->pCallbackGuard(handler->pContext); if(rc!=NEXUS_SUCCESS) { BDBG_MSG_CALLBACK(("Deflected:%#x", (unsigned)handler)); return; } } if(NEXUS_Module_TryLock_Tagged(handler->module, handler->pFileName, handler->lineNumber)) { /* don't check timer, if it was set it would just cause 1:1 mapping between schedulled callback and callbacks executed */ BDBG_MSG_CALLBACK(("Locked:%#x", (unsigned)handler)); handler->pCallback(handler->pContext); NEXUS_Module_Unlock_Tagged(handler->module, handler->pFileName, handler->lineNumber); } else { BKNI_AcquireMutex(NEXUS_P_Base_State.callbackHandlerLock); if(handler->timer==NULL) { BDBG_MSG_CALLBACK(("Queued:%#x", (unsigned)handler)); handler->timer = NEXUS_Module_ScheduleTimer(handler->module, 0, NEXUS_Base_P_CallbackHandler_TimerDispatch, handler, handler->pFileName, handler->lineNumber); } else { BDBG_MSG_CALLBACK(("Skipped:%#x %#x", (unsigned)handler, (unsigned)handler->timer)); /* 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 */ } BKNI_ReleaseMutex(NEXUS_P_Base_State.callbackHandlerLock); } return; } void NEXUS_Base_P_CallbackHandler_Stop(NEXUS_CallbackHandler *handler) { BDBG_OBJECT_ASSERT(handler, NEXUS_CallbackHandler); BDBG_MSG_CALLBACK(("Stop:%#x", (unsigned)handler)); /* cancel any pending timer */ NEXUS_Base_P_CallbackHandler_TimerCancel(handler); return; } void NEXUS_Base_P_CallbackHandler_Shutdown(NEXUS_CallbackHandler *handler) { BDBG_OBJECT_ASSERT(handler, NEXUS_CallbackHandler); BDBG_MSG_CALLBACK(("Shutdown:%#x", (unsigned)handler)); NEXUS_Base_P_CallbackHandler_TimerCancel(handler); #if 0 BDBG_OBJECT_UNSET(handler, NEXUS_CallbackHandler); #else BDBG_OBJECT_DESTROY(handler, NEXUS_CallbackHandler); #endif return; } BDBG_FILE_MODULE(nexus_refcnt); #define BDBG_REFCNT(x) BDBG_MODULE_MSG(nexus_refcnt,x) void NEXUS_RefCntObj_P_Init(NEXUS_RefCnt *cnt, const NEXUS_RefCntDescriptor *descriptor) { BDBG_ASSERT(cnt); BDBG_ASSERT(descriptor); BDBG_REFCNT(("%p: Init %p", descriptor, ((uint8_t *)cnt)-descriptor->offset)); cnt->ref_cnt = 1; cnt->descriptor = descriptor; return; } static int b_add_ref_cnf(NEXUS_RefCnt *cnt, int add, NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber) { int result; if(module) { NEXUS_Module_Lock_Tagged(module, pFileName, lineNumber); } result = cnt->ref_cnt + add; cnt->ref_cnt = result; if(module) { NEXUS_Module_Unlock_Tagged(module, pFileName, lineNumber); } return result; } void NEXUS_RefCntObj_P_Acquire_Tagged(void *object, const NEXUS_RefCntDescriptor *descriptor, NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber) { int result; NEXUS_RefCnt *cnt; BDBG_ASSERT(descriptor); cnt = (void *)((uint8_t *)object + descriptor->offset); BDBG_REFCNT(("%p: Acquire %p %u %s:%u", cnt->descriptor, object, cnt->ref_cnt, pFileName, lineNumber)); result = b_add_ref_cnf(cnt, 1, module, pFileName, lineNumber); BDBG_ASSERT(result>0); return; } void NEXUS_RefCntObj_P_Release_Tagged(void *object, const NEXUS_RefCntDescriptor *descriptor, NEXUS_ModuleHandle module, const char *pFileName, unsigned lineNumber) { int result; NEXUS_RefCnt *cnt; BDBG_ASSERT(descriptor); cnt = (void *)((uint8_t *)object + descriptor->offset); BDBG_REFCNT(("%p: Release %p %u %s:%u", cnt->descriptor, object, cnt->ref_cnt, pFileName, lineNumber)); result = b_add_ref_cnf(cnt, -1, module, pFileName, lineNumber); BDBG_ASSERT(result>=0); if(result<=0) { if(module) { NEXUS_Module_Lock_Tagged(module, pFileName, lineNumber); } BDBG_ASSERT(descriptor->finalizer); BDBG_REFCNT(("%p: Finalize %p %u %s:%u", cnt->descriptor, object, cnt->ref_cnt, pFileName, lineNumber)); descriptor->finalizer(object); if(module) { NEXUS_Module_Unlock_Tagged(module, pFileName, lineNumber); } } return; }