[En-Nut-Discussion] Bug in Nut Init?
Ralph Mason
ralph.mason at telogis.com
Tue Apr 1 10:16:31 CEST 2003
Hi,
While we are on the topic of non-optimised ethernut.
Non optimised code doesn't get inline functions - thus NutEnter/Exit
Critical break the stack. I have changed these to be macros (under GCC) and
all seems OK in debug.
Also, I noticed that the context switch saves all the registers, from the
GCC documentation it seems that r0,r1,r18-r27,r31,r31 do not need saving -
(giving a 14 byte of stack space saving). The complete save would be needed
if it was premeptive, but as it's a function call it doesn't appear to be
necessary. Is there some underlying reason that I have overlooked?
I also implemented a ThreadKill, it basically uses a priority of 255 to kill
a thread (meaning Idle becomes 254)
The following is the modified code (if anyone wants it)
In thread.c
/*!
* \brief Thread to be killed.
*
* Priority ordered linked list of NUTTHREADINFO structures
* of all threads which are ready to run.
*/
NUTTHREADINFO *volatile kill = 0;
/*!
* \brief End the current thread
*
* Terminates the current thread, in due course the memory
* associated with the thread will be released back to the OS
* this is done by the idle thread.
*/
void NutThreadExit(void){
NutThreadSetPriority(255);
}
/*!
* \brief Set the current thread's priority.
*
* The priority of newly created threads is set to 64,
* but may be changed when the thread starts running.
*
* When another thread with a higher or equal priority
* is ready to run, the current thread will be stopped
* and control of the CPU is passed to the other thread.
*
* The function returns the old priority, which makes it
* easy to temporarily switch to another priority and
* later set back the old one.
*
* A priority of 255 kills the thread.
*
* \param level New priority level.
*
* \return The old priority of this thread.
*/
u_char NutThreadSetPriority(u_char level)
{
u_char last = runningThread->td_priority;
NutEnterCritical();
#ifdef NUTDEBUG
if (__os_trf)
fprintf(__os_trs, "Pri%u<%04x>", level, (u_int) runningThread);
#endif
NutThreadRemoveQueue(runningThread, &runQueue);
runningThread->td_priority = level;
if ( level != 255 )
NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
else
NutKillThread();
#ifdef NUTDEBUG
if (__os_trf)
NutDumpThreadList(__os_trs);
//NutDumpThreadQueue(__os_trs, runQueue);
#endif
if (runningThread == runQueue)
runningThread->td_state = TDS_RUNNING;
else {
runningThread->td_state = TDS_READY;
#ifdef NUTDEBUG
if (__os_trf)
fprintf(__os_trs, "SWC<%04x %04x>", (u_int) runningThread,
(u_int) runQueue);
#endif
NutThreadSwitch();
}
NutExitCritical();
return last;
}
/*!
* \brief Free a thread that was previously killed and release memory back
to the OS
*
* Called when another thread is killed and by the idle thread
*
* Applications generally do not call this function, however you could call
it
* to try to reclaim memory
*/
void NutFreeKilledThread(){
if ( kill != 0 ){
NutHeapFree(kill->td_memory);
kill = 0;
}
}
/*!
* \brief Kill the running thread
*
* The thread is moved from the schedule que and
*
* Applications generally do not call this function
*/
void NutKillThread(){
NUTTHREADINFO* pCur = nutThreadList;
NUTTHREADINFO** pp= (NUTTHREADINFO**)&nutThreadList;
//Free up any unfinished already killed threads
NutFreeKilledThread();
//Remove from the thread list
while ( pCur ){
if ( pCur == runningThread ){
*pp = pCur->td_next;
break;
}
pp = (NUTTHREADINFO**)&pCur->td_next;
pCur = pCur->td_next;
}
//Schedule for cleanup
kill = runningThread;
}
The Idle thread is also updated
/*! \fn NutIdle(void *arg)
* \brief Idle thread.
*/
THREAD(NutIdle, arg)
{
NutTimerInit();
NutThreadCreate("main", NutMain, 0, 768);
NutThreadSetPriority(254);
for (;;) {
NutThreadYield();
NutFreeKilledThread();
#ifdef _PC
//Yield to the OS so we don't hog the processor
PC_SYS_CODE_START
Sleep(10);
PC_SYS_CODE_END
#else
//Nothing to do - save power!
sbi( MCUCR,5) ; asm volatile("sleep" ::);
#endif
}
}
Cheers,
Ralph
> -----Original Message-----
> From: en-nut-discussion-admin at egnite.de
> [mailto:en-nut-discussion-admin at egnite.de]On Behalf Of Harald Kipp
> Sent: Tuesday, 1 April 2003 6:50
> To: en-nut-discussion at egnite.de
> Subject: Re: [En-Nut-Discussion] Bug in Nut Init?
>
>
> Ralph,
>
> you are perfectly right. Thanks.
>
> Harald
>
> At 07:15 01.04.2003 +1200, you wrote:
> >I noticed a bug in the NutInit function
> >
> >register volatile u_char * xramend = ((volatile u_char *)0x7FFF);
> >
> >Doesn't work unless you have some optimisation turned on,
> because it saves
> >xramend in a non existent stackframe. (As one should not
> allocate variables
> >in naked functions - register or otherwise )
> >
> >Changing the line to
> >
> >#define xramend ((volatile u_char *)0x7FFF)
> >
> >Creates exactly the same code as the above (when it works) but works both
> >optimised and unoptimised.
> >
> >Ralph
>
> _______________________________________________
> En-Nut-Discussion mailing list
> En-Nut-Discussion at egnite.de
> http://www.egnite.de/mailman/listinfo/en-nut-discussion
>
> ---
> Incoming mail is certified Virus Free.
> Checked by AVG anti-virus system (http://www.grisoft.com).
> Version: 6.0.461 / Virus Database: 260 - Release Date: 10/03/2003
>
---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.461 / Virus Database: 260 - Release Date: 10/03/2003
More information about the En-Nut-Discussion
mailing list