diff --git a/miosix/_tools/testsuite/testsuite.cpp b/miosix/_tools/testsuite/testsuite.cpp index 9cfeb7fa78f618ad989d76c3dfeb5a80d1b1f75d..0202daa8693649f37f0617492553c1889eed73ea 100644 --- a/miosix/_tools/testsuite/testsuite.cpp +++ b/miosix/_tools/testsuite/testsuite.cpp @@ -817,10 +817,10 @@ static void t3_p1(void *argv) const int SLEEP_TIME=100;//ms for(;;) { - if(Thread::testTerminate()) break; //Test that Thread::sleep sleeps the desired time long long x1=getTime(); //getTime returns passed time in ns Thread::sleep(SLEEP_TIME); + if(Thread::testTerminate()) break; long long x2=getTime(); if(llabs((x2-x1)/1000000-SLEEP_TIME)>0) //Max tolerated error is 1ms fail("Thread::sleep() or getTime()"); diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp index f2e785186691db20d2c1a7e6a947050cc47dd506..8398c9e1ac11ae614a8997522d774d32f9423029 100755 --- a/miosix/kernel/kernel.cpp +++ b/miosix/kernel/kernel.cpp @@ -369,25 +369,22 @@ void Thread::nanoSleepUntil(long long absoluteTimeNs) //Disallow absolute sleeps with negative or too low values, as the ns2tick() //algorithm in TimeConversion can't handle negative values and may undeflow //even with very low values due to a negative adjustOffsetNs. As an unlikely - //side effect, very shor sleeps done very early at boot will be extended. + //side effect, very short sleeps done very early at boot will be extended. absoluteTimeNs=std::max(absoluteTimeNs,100000LL); - //The SleepData variable has to be in scope till Thread::yield() returns - //as IRQaddToSleepingList() makes it part of a linked list till the - //thread wakes up (i.e: after Thread::yield() returns) - SleepData d(const_cast<Thread*>(runningThread),absoluteTimeNs); //pauseKernel() here is not enough since even if the kernel is stopped //the timer isr will wake threads, modifying the sleepingList { - FastInterruptDisableLock lock; + FastInterruptDisableLock dLock; + SleepData d(const_cast<Thread*>(runningThread),absoluteTimeNs); d.thread->flags.IRQsetSleep(); //Sleeping thread: set sleep flag IRQaddToSleepingList(&d); + { + FastInterruptEnableLock eLock(dLock); + Thread::yield(); + } + //Only required for interruptibility when terminate is called + sleepingList.removeFast(&d); } - // NOTE: There is no need to synchronize the timer (calling IRQsetNextInterrupt) - // with the list at this point. Because, Thread::yield will make a supervisor - // call and subsequently it will call the IRQfindNextThread. IRQfindNextThread - // keeps the timer synchronized with the sleeping list head and beginning of - // next burst time. See ISR_yield() in portability.cpp - Thread::yield(); } void Thread::wait() @@ -527,7 +524,9 @@ void Thread::terminate() //doing a read-modify-write operation on this->status, so pauseKernel is //not enough, we need to disable interrupts FastInterruptDisableLock lock; + if(this->flags.isDeleting()) return; //Prevent sleep interruption abuse this->flags.IRQsetDeleting(); + this->flags.IRQclearSleepAndWait(); //Interruptibility } bool Thread::testTerminate() diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h index 520a017065f85a5eef178148897df65cb45549e8..886ee4afd6f8f01e2bb89913c366b146547e9a88 100755 --- a/miosix/kernel/kernel.h +++ b/miosix/kernel/kernel.h @@ -832,7 +832,9 @@ public: * terminate. The user is responsible for implementing correctly this * functionality.<br>Thread termination is implemented like this to give * time to a thread to deallocate resources, close files... before - * terminating. <br>Can be called when the kernel is paused. + * terminating.<br>The first call to terminate on a thread will make it + * return prematurely form wait(), sleep() and timedWait() call, but only + * once.<br>Can be called when the kernel is paused. */ void terminate();