/** * Used to initialize static objects only once, in a threadsafe way * \param g guard struct * \return 0 if object already initialized, 1 if this thread has to initialize * it, or lock if another thread has already started initializing it */ extern "C" int __cxa_guard_acquire(__guard *g) { miosix::InterruptDisableLock dLock; volatile MiosixGuard *guard=reinterpret_cast<volatile MiosixGuard*>(g); for(;;) { if(guard->flag==1) return 0; //Object already initialized, good if(guard->flag==0) { //Object uninitialized, and no other thread trying to initialize it guard->owner=miosix::Thread::IRQgetCurrentThread(); //guard->owner serves the double task of being the thread id of //the thread initializing the object, and being the flag to signal //that the object is initialized or not. If bit #0 of guard->owner //is @ 1 the object is initialized. All this works on the assumption //that Thread* pointers never have bit #0 @ 1, and this assetion //checks that this condition really holds if(guard->flag & 1) miosix::errorHandler(miosix::UNEXPECTED); return 1; } //If we get here, the object is being initialized by another thread if(guard->owner==miosix::Thread::IRQgetCurrentThread()) { //Wait, the other thread initializing the object is this thread?!? //We have a recursive initialization error. Not throwing an //exception to avoid pulling in exceptions even with -fno-exception IRQerrorLog("Recursive initialization\r\n"); _exit(1); } { miosix::InterruptEnableLock eLock(dLock); miosix::Thread::yield(); //Sort of a spinlock, a "yieldlock"... } } }
void errorHandler(Error e) { // Here we must be careful since this function can be called within an // interrupt routine, and disabling interrupts within an interrupt // routine must be avoided. bool interrupts=areInterruptsEnabled(); if(interrupts) disableInterrupts(); bool isUnrecoverable=false; //Recoverable errors switch(e) { case INVALID_PARAMETERS: IRQerrorLog("\r\n***Invalid parameter\r\n"); break; case PROPAGATED_EXCEPTION: IRQerrorLog("\r\n***An exception propagated through a thread\r\n"); break; case MUTEX_UNLOCK_NOT_OWNER: IRQerrorLog("\r\n***unlock() called on a non locked mutex\r\n"); default: isUnrecoverable=true; } //Unrecoverable errors switch(e) { case OUT_OF_MEMORY: IRQerrorLog("\r\n***Out of memory\r\n"); break; case STACK_OVERFLOW: IRQerrorLog("\r\n***Stack overflow\r\n"); break; case UNEXPECTED: IRQerrorLog("\r\n***Unexpected error\r\n"); break; case PAUSE_KERNEL_NESTING: IRQerrorLog("\r\n***Pause kernel nesting\r\n"); break; case DISABLE_INTERRUPTS_NESTING: IRQerrorLog("\r\n***Disable interrupt nesting\r\n"); break; case MUTEX_DEADLOCK: IRQerrorLog("\r\n***Deadlock\r\n"); break; case NESTING_OVERFLOW: IRQerrorLog("\r\n***Nesting overflow\r\n"); break; case INTERRUPTS_ENABLED_AT_BOOT: IRQerrorLog("\r\n***Interrupts enabled at boot\r\n"); break; default: break; } if(isUnrecoverable) miosix_private::IRQsystemReboot(); if(interrupts) enableInterrupts(); }