/* * ======== notifySpinLock ======== */ UInt Core_notifySpinLock() { UInt key; key = Hwi_disable(); while (1) { if (!Core_module->notifyLock) { Core_module->notifyLock = TRUE; break; } else { /* Re-enable interrupts and release inter-core lock */ Hwi_restore(key); /* Wait for lock to be released */ while (Core_module->notifyLock); key = Hwi_disable(); } } /* Release inter-core lock */ Core_unlock(); return (key); }
/* * ======== SysMin_abort ======== */ Void SysMin_abort(String str) { Char ch; if (SysMin_bufSize != 0) { if (str != NULL) { while ((ch = *str++) != '\0') { SysMin_putch(ch); } } /* Only flush if configured to do so */ if (SysMin_flushAtExit) { SysMin_flush(); } } /* * System_abort() in xdc/runtime/System.c enters the System gate * before aborting, but does not leave the gate. Aforementioned * System gate maps to the Inter-core gate entered by the Hwi lock. * Since Hwi lock is never released, the other core's dispacther * may spin forever, waiting to acquire the Hwi lock. * * We Unlock Hwi before returning so all locks are released before * exiting. */ Core_unlock(); }
/* * ======== Core_atexit ======== */ Void Core_atexit(Int arg) { if ((Core_module->exitFlag == TRUE) || (Core_syncExits == FALSE)) { Core_module->exitFlag = FALSE; Task_unlockSched(); Swi_unlockSched(); Core_unlock(); return; } Core_module->exitFlag = TRUE; Task_unlockSched(); Swi_unlockSched(); Core_unlock(); /* interrupt the other core */ Core_interruptCore(Core_getId() ^ 1); while (Core_module->exitFlag); }
/* * ======== Core_atexit ======== */ Void Core_atexit(Int arg) { UInt key; UInt coreId = Core_getId(); Task_unlockSched(); Swi_unlockSched(); Core_unlock(); /* force other cores to exit */ key = Core_notifySpinLock(); Core_notify(&Core_exit, (UArg)coreId, (Core_CPUMASK ^ (0x1 << coreId))); Core_notifySpinUnlock(key); }
/* * ======== Core_exit ======== */ Void Core_exit(UArg arg) { Task_unlockSched(); Swi_unlockSched(); Core_unlock(); /* Signal operation complete */ Core_module->syncCores[arg][Core_getId()] = TRUE; /* * Call _exit() instead of abort. abort() internally * calls raise() which will invoke ReentSupport_getReent() * from a Hwi context and cause an assertion failure. */ _exit(0); }
/* * ======== Core_hwiFunc ======== */ Void Core_hwiFunc(UArg arg) { UInt coreId = Core_getId(); Core_module->schedulerInts[coreId] += 1; if (Core_module->exitFlag == TRUE) { Core_module->exitFlag = FALSE; Task_unlockSched(); Swi_unlockSched(); Core_unlock(); abort(); } if (coreId == 0) { Hwi_flushVnvic(); } }
/* * ======== SysMin_exit ======== */ Void SysMin_exit(Int stat) { /* * System_rtsExit() in xdc/runtime/System.c enters the System gate * before exiting, but does not leave the gate. The BASEPRI * register on Arm M3 is therefore not restored to 0 (disabled state). * When SysMin_flush() enters Hwi gate, the key returned by * Hwi_disable() is incorrect (Its equal to Hwi disable priority * instead of 0). This prevents the Hwi_restore() function, * called when SysMin_flush() exits, from freeing the Hwi lock. * Since Hwi lock is never released, the other core's dispacther * may spin forever, waiting to acquire the Hwi lock. * * We Unlock Hwi before returning so all locks are released before * exiting. */ if ((SysMin_flushAtExit) && (SysMin_bufSize != 0)) { SysMin_flush(); Core_unlock(); } }