[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