kopia lustrzana https://github.com/OpenRTX/OpenRTX
1078 wiersze
36 KiB
C++
1078 wiersze
36 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 by Terraneo Federico *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* As a special exception, if other files instantiate templates or use *
|
|
* macros or inline functions from this file, or you compile this file *
|
|
* and link it with other works to produce a work based on this file, *
|
|
* this file does not by itself cause the resulting work to be covered *
|
|
* by the GNU General Public License. However the source code for this *
|
|
* file must still be made available in accordance with the GNU General *
|
|
* Public License. This exception does not invalidate any other reasons *
|
|
* why a work based on this file might be covered by the GNU General *
|
|
* Public License. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
|
***************************************************************************/
|
|
//Miosix kernel
|
|
|
|
#ifndef KERNEL_H
|
|
#define KERNEL_H
|
|
|
|
//Include settings.
|
|
#include "config/miosix_settings.h"
|
|
#include "interfaces/portability.h"
|
|
#include "kernel/scheduler/sched_types.h"
|
|
#include "stdlib_integration/libstdcpp_integration.h"
|
|
#include <cstdlib>
|
|
#include <new>
|
|
#include <functional>
|
|
|
|
// some pthread functions are friends of Thread
|
|
#include <pthread.h>
|
|
|
|
/**
|
|
* \namespace miosix
|
|
* All user available kernel functions, classes are inside this namespace.
|
|
*/
|
|
namespace miosix {
|
|
|
|
/**
|
|
* \addtogroup Kernel
|
|
* \{
|
|
*/
|
|
|
|
/**
|
|
* Disable interrupts, if interrupts were enable prior to calling this function.
|
|
*
|
|
* Please note that starting from Miosix 1.51 disableInterrupts() and
|
|
* enableInterrupts() can be nested. You can therefore call disableInterrupts()
|
|
* multiple times as long as each call is matched by a call to
|
|
* enableInterrupts().<br>
|
|
* This replaced disable_and_save_interrupts() and restore_interrupts()
|
|
*
|
|
* disableInterrupts() cannot be called within an interrupt routine, but can be
|
|
* called before the kernel is started (and does nothing in this case)
|
|
*/
|
|
void disableInterrupts();
|
|
|
|
/**
|
|
* Enable interrupts.<br>
|
|
* Please note that starting from Miosix 1.51 disableInterrupts() and
|
|
* enableInterrupts() can be nested. You can therefore call disableInterrupts()
|
|
* multiple times as long as each call is matched by a call to
|
|
* enableInterrupts().<br>
|
|
* This replaced disable_and_save_interrupts() and restore_interrupts()
|
|
*
|
|
* enableInterrupts() cannot be called within an interrupt routine, but can be
|
|
* called before the kernel is started (and does nothing in this case)
|
|
*/
|
|
void enableInterrupts();
|
|
|
|
/**
|
|
* Fast version of disableInterrupts().<br>
|
|
* Despite faster, it has a couple of preconditions:
|
|
* - calls to fastDisableInterrupts() can't be nested
|
|
* - it can't be used in code that is called before the kernel is started
|
|
*/
|
|
inline void fastDisableInterrupts()
|
|
{
|
|
miosix_private::doDisableInterrupts();
|
|
}
|
|
|
|
/**
|
|
* Fast version of enableInterrupts().<br>
|
|
* Despite faster, it has a couple of preconditions:
|
|
* - calls to fastDisableInterrupts() can't be nested
|
|
* - it can't be used in code that is called before the kernel is started,
|
|
* because it will (incorreclty) lead to interrupts being enabled before the
|
|
* kernel is started
|
|
*/
|
|
inline void fastEnableInterrupts()
|
|
{
|
|
miosix_private::doEnableInterrupts();
|
|
}
|
|
|
|
/**
|
|
* This class is a RAII lock for disabling interrupts. This call avoids
|
|
* the error of not reenabling interrupts since it is done automatically.
|
|
*/
|
|
class InterruptDisableLock
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor, disables interrupts.
|
|
*/
|
|
InterruptDisableLock()
|
|
{
|
|
disableInterrupts();
|
|
}
|
|
|
|
/**
|
|
* Destructor, reenables interrupts
|
|
*/
|
|
~InterruptDisableLock()
|
|
{
|
|
enableInterrupts();
|
|
}
|
|
|
|
private:
|
|
//Unwanted methods
|
|
InterruptDisableLock(const InterruptDisableLock& l);
|
|
InterruptDisableLock& operator= (const InterruptDisableLock& l);
|
|
};
|
|
|
|
/**
|
|
* This class allows to temporarily re enable interrpts in a scope where
|
|
* they are disabled with an InterruptDisableLock.<br>
|
|
* Example:
|
|
* \code
|
|
*
|
|
* //Interrupts enabled
|
|
* {
|
|
* InterruptDisableLock dLock;
|
|
*
|
|
* //Now interrupts disabled
|
|
*
|
|
* {
|
|
* InterruptEnableLock eLock(dLock);
|
|
*
|
|
* //Now interrupts back enabled
|
|
* }
|
|
*
|
|
* //Now interrupts again disabled
|
|
* }
|
|
* //Finally interrupts enabled
|
|
* \endcode
|
|
*/
|
|
class InterruptEnableLock
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor, enables back interrupts.
|
|
* \param l the InteruptDisableLock that disabled interrupts. Note that
|
|
* this parameter is not used internally. It is only required to prevent
|
|
* erroneous use of this class by making an instance of it without an
|
|
* active InterruptEnabeLock
|
|
*/
|
|
InterruptEnableLock(InterruptDisableLock& l)
|
|
{
|
|
(void)l;
|
|
enableInterrupts();
|
|
}
|
|
|
|
/**
|
|
* Destructor.
|
|
* Disable back interrupts.
|
|
*/
|
|
~InterruptEnableLock()
|
|
{
|
|
disableInterrupts();
|
|
}
|
|
|
|
private:
|
|
//Unwanted methods
|
|
InterruptEnableLock(const InterruptEnableLock& l);
|
|
InterruptEnableLock& operator= (const InterruptEnableLock& l);
|
|
};
|
|
|
|
/**
|
|
* This class is a RAII lock for disabling interrupts. This call avoids
|
|
* the error of not reenabling interrupts since it is done automatically.
|
|
* As opposed to InterruptDisableLock, this version doesn't support nesting
|
|
*/
|
|
class FastInterruptDisableLock
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor, disables interrupts.
|
|
*/
|
|
FastInterruptDisableLock()
|
|
{
|
|
fastDisableInterrupts();
|
|
}
|
|
|
|
/**
|
|
* Destructor, reenables interrupts
|
|
*/
|
|
~FastInterruptDisableLock()
|
|
{
|
|
fastEnableInterrupts();
|
|
}
|
|
|
|
private:
|
|
//Unwanted methods
|
|
FastInterruptDisableLock(const FastInterruptDisableLock& l);
|
|
FastInterruptDisableLock& operator= (const FastInterruptDisableLock& l);
|
|
};
|
|
|
|
/**
|
|
* This class allows to temporarily re enable interrpts in a scope where
|
|
* they are disabled with an FastInterruptDisableLock.
|
|
*/
|
|
class FastInterruptEnableLock
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor, enables back interrupts.
|
|
* \param l the InteruptDisableLock that disabled interrupts. Note that
|
|
* this parameter is not used internally. It is only required to prevent
|
|
* erroneous use of this class by making an instance of it without an
|
|
* active InterruptEnabeLock
|
|
*/
|
|
FastInterruptEnableLock(FastInterruptDisableLock& l)
|
|
{
|
|
(void)l;
|
|
fastEnableInterrupts();
|
|
}
|
|
|
|
/**
|
|
* Destructor.
|
|
* Disable back interrupts.
|
|
*/
|
|
~FastInterruptEnableLock()
|
|
{
|
|
fastDisableInterrupts();
|
|
}
|
|
|
|
private:
|
|
//Unwanted methods
|
|
FastInterruptEnableLock(const FastInterruptEnableLock& l);
|
|
FastInterruptEnableLock& operator= (const FastInterruptEnableLock& l);
|
|
};
|
|
|
|
/**
|
|
* Pause the kernel.<br>Interrupts will continue to occur, but no preemption is
|
|
* possible. Call to this function are cumulative: if you call pauseKernel()
|
|
* two times, you need to call restartKernel() two times.<br>Pausing the kernel
|
|
* must be avoided if possible because it is easy to cause deadlock. Calling
|
|
* file related functions (fopen, Directory::open() ...), serial port related
|
|
* functions (printf ...) or kernel functions that cannot be called when the
|
|
* kernel is paused will cause deadlock. Therefore, if possible, it is better to
|
|
* use a Mutex instead of pausing the kernel<br>This function is safe to be
|
|
* called even before the kernel is started. In this case it has no effect.
|
|
*/
|
|
void pauseKernel();
|
|
|
|
/**
|
|
* Restart the kernel.<br>This function will yield immediately if a tick has
|
|
* been missed. Since calls to pauseKernel() are cumulative, if you call
|
|
* pauseKernel() two times, you need to call restartKernel() two times.<br>
|
|
* This function is safe to be called even before the kernel is started. In this
|
|
* case it has no effect.
|
|
*/
|
|
void restartKernel();
|
|
|
|
/**
|
|
* \return true if interrupts are enabled
|
|
*/
|
|
bool areInterruptsEnabled();
|
|
|
|
/**
|
|
* This class is a RAII lock for pausing the kernel. This call avoids
|
|
* the error of not restarting the kernel since it is done automatically.
|
|
*/
|
|
class PauseKernelLock
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor, pauses the kernel.
|
|
*/
|
|
PauseKernelLock()
|
|
{
|
|
pauseKernel();
|
|
}
|
|
|
|
/**
|
|
* Destructor, restarts the kernel
|
|
*/
|
|
~PauseKernelLock()
|
|
{
|
|
restartKernel();
|
|
}
|
|
|
|
private:
|
|
//Unwanted methods
|
|
PauseKernelLock(const PauseKernelLock& l);
|
|
PauseKernelLock& operator= (const PauseKernelLock& l);
|
|
};
|
|
|
|
/**
|
|
* This class allows to temporarily restart kernel in a scope where it is
|
|
* paused with an InterruptDisableLock.<br>
|
|
* Example:
|
|
* \code
|
|
*
|
|
* //Kernel started
|
|
* {
|
|
* PauseKernelLock dLock;
|
|
*
|
|
* //Now kernel paused
|
|
*
|
|
* {
|
|
* RestartKernelLock eLock(dLock);
|
|
*
|
|
* //Now kernel back started
|
|
* }
|
|
*
|
|
* //Now kernel again paused
|
|
* }
|
|
* //Finally kernel started
|
|
* \endcode
|
|
*/
|
|
class RestartKernelLock
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor, restarts kernel.
|
|
* \param l the PauseKernelLock that disabled interrupts. Note that
|
|
* this parameter is not used internally. It is only required to prevent
|
|
* erroneous use of this class by making an instance of it without an
|
|
* active PauseKernelLock
|
|
*/
|
|
RestartKernelLock(PauseKernelLock& l)
|
|
{
|
|
(void)l;
|
|
restartKernel();
|
|
}
|
|
|
|
/**
|
|
* Destructor.
|
|
* Disable back interrupts.
|
|
*/
|
|
~RestartKernelLock()
|
|
{
|
|
pauseKernel();
|
|
}
|
|
|
|
private:
|
|
//Unwanted methods
|
|
RestartKernelLock(const RestartKernelLock& l);
|
|
RestartKernelLock& operator= (const RestartKernelLock& l);
|
|
};
|
|
|
|
/**
|
|
* \internal
|
|
* Start the kernel.<br> There is no way to stop the kernel once it is
|
|
* started, except a (software or hardware) system reset.<br>
|
|
* Calls errorHandler(OUT_OF_MEMORY) if there is no heap to create the idle
|
|
* thread. If the function succeds in starting the kernel, it never returns;
|
|
* otherwise it will call errorHandler(OUT_OF_MEMORY) and then return
|
|
* immediately. startKernel() must not be called when the kernel is already
|
|
* started.
|
|
*/
|
|
void startKernel();
|
|
|
|
/**
|
|
* Return true if kernel is running, false if it is not started, or paused.<br>
|
|
* Warning: disabling/enabling interrupts does not affect the result returned by
|
|
* this function.
|
|
* \return true if kernel is running (started && not paused)
|
|
*/
|
|
bool isKernelRunning();
|
|
|
|
/**
|
|
* Returns the current kernel tick.<br>Can be called also with interrupts
|
|
* disabled and/or kernel paused.
|
|
* \return current kernel tick
|
|
*/
|
|
long long getTick();
|
|
|
|
//Forwrd declaration
|
|
struct SleepData;
|
|
class MemoryProfiling;
|
|
class Mutex;
|
|
class ConditionVariable;
|
|
#ifdef WITH_PROCESSES
|
|
class ProcessBase;
|
|
#endif //WITH_PROCESSES
|
|
|
|
/**
|
|
* This class represents a thread. It has methods for creating, deleting and
|
|
* handling threads.<br>It has private constructor and destructor, since memory
|
|
* for a thread is handled by the kernel.<br>To create a thread use the static
|
|
* producer method create().<br>
|
|
* Methods that have an effect on the current thread, that is, the thread that
|
|
* is calling the method are static.<br>
|
|
* Calls to non static methods must be done with care, because a thread can
|
|
* terminate at any time. For example, if you call wakeup() on a terminated
|
|
* thread, the behavior is undefined.
|
|
*/
|
|
class Thread
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* Thread options, can be passed to Thread::create to set additional options
|
|
* of the thread.
|
|
* More options can be specified simultaneously by ORing them together.
|
|
* The DEFAULT option indicates the default thread creation.
|
|
*/
|
|
enum Options
|
|
{
|
|
DEFAULT=0, ///< Default thread options
|
|
JOINABLE=1<<0 ///< Thread is joinable instead of detached
|
|
};
|
|
|
|
/**
|
|
* Producer method, creates a new thread.
|
|
* \param startfunc the entry point function for the thread
|
|
* \param stacksize size of thread stack, its minimum is the constant
|
|
* STACK_MIN.
|
|
* The size of the stack must be divisible by 4, otherwise it will be
|
|
* rounded to a number divisible by 4.
|
|
* \param priority the thread's priority, between 0 (lower) and
|
|
* PRIORITY_MAX-1 (higher)
|
|
* \param argv a void* pointer that is passed as pararmeter to the entry
|
|
* point function
|
|
* \param options thread options, such ad Thread::JOINABLE
|
|
* \return a reference to the thread created, that can be used, for example,
|
|
* to delete it, or NULL in case of errors.
|
|
*
|
|
* Can be called when the kernel is paused.
|
|
*/
|
|
static Thread *create(void *(*startfunc)(void *), unsigned int stacksize,
|
|
Priority priority=Priority(), void *argv=NULL,
|
|
unsigned short options=DEFAULT);
|
|
|
|
/**
|
|
* Same as create(void (*startfunc)(void *), unsigned int stacksize,
|
|
* Priority priority=1, void *argv=NULL)
|
|
* but in this case the entry point of the thread returns a void*
|
|
* \param startfunc the entry point function for the thread
|
|
* \param stacksize size of thread stack, its minimum is the constant
|
|
* STACK_MIN.
|
|
* The size of the stack must be divisible by 4, otherwise it will be
|
|
* rounded to a number divisible by 4.
|
|
* \param priority the thread's priority, between 0 (lower) and
|
|
* PRIORITY_MAX-1 (higher)
|
|
* \param argv a void* pointer that is passed as pararmeter to the entry
|
|
* point function
|
|
* \param options thread options, such ad Thread::JOINABLE
|
|
* \return a reference to the thread created, that can be used, for example,
|
|
* to delete it, or NULL in case of errors.
|
|
*/
|
|
static Thread *create(void (*startfunc)(void *), unsigned int stacksize,
|
|
Priority priority=Priority(), void *argv=NULL,
|
|
unsigned short options=DEFAULT);
|
|
|
|
/**
|
|
* When called, suggests the kernel to pause the current thread, and run
|
|
* another one.
|
|
* <br>CANNOT be called when the kernel is paused.
|
|
*/
|
|
static void yield();
|
|
|
|
/**
|
|
* This method needs to be called periodically inside the thread's main
|
|
* loop.
|
|
* \return true if somebody outside the thread called terminate() on this
|
|
* thread.
|
|
*
|
|
* If it returns true the thread must free all resources and terminate by
|
|
* returning from its main function.
|
|
* <br>Can be called when the kernel is paused.
|
|
*/
|
|
static bool testTerminate();
|
|
|
|
/**
|
|
* Put the thread to sleep for a number of milliseconds.<br>The actual
|
|
* precision depends on the kernel tick used. If the specified wait time is
|
|
* lower than the tick accuracy, the thread will be put to sleep for one
|
|
* tick.<br>Maximum sleep time is (2^32-1) / TICK_FREQ. If a sleep time
|
|
* higher than that value is specified, the behaviour is undefined.
|
|
* \param ms the number of millisecond. If it is ==0 this method will
|
|
* return immediately
|
|
*
|
|
* CANNOT be called when the kernel is paused.
|
|
*/
|
|
static void sleep(unsigned int ms);
|
|
|
|
/**
|
|
* Put the thread to sleep until the specified absolute time is reached.
|
|
* If the time is in the past, returns immediately.
|
|
* To make a periodic thread, this is the recomended way
|
|
* \code
|
|
* void periodicThread()
|
|
* {
|
|
* //Run every 90 milliseconds
|
|
* const int period=static_cast<int>(TICK_FREQ*0.09);
|
|
* long long tick=getTick();
|
|
* for(;;)
|
|
* {
|
|
* //Do work
|
|
* tick+=period;
|
|
* Thread::sleepUntil(tick);
|
|
* }
|
|
* }
|
|
* \endcode
|
|
* \param absoluteTime when to wake up
|
|
*
|
|
* CANNOT be called when the kernel is paused.
|
|
*/
|
|
static void sleepUntil(long long absoluteTime);
|
|
|
|
/**
|
|
* Return a pointer to the Thread class of the current thread.
|
|
* \return a pointer to the current thread.
|
|
*
|
|
* Can be called when the kernel is paused.
|
|
* Returns a valid pointer also if called before the kernel is started.
|
|
*/
|
|
static Thread *getCurrentThread();
|
|
|
|
/**
|
|
* Check if a thread exists
|
|
* \param p thread to check
|
|
* \return true if thread exists, false if does not exist or has been
|
|
* deleted. A joinable thread is considered existing until it has been
|
|
* joined, even if it returns from its entry point (unless it is detached
|
|
* and terminates).
|
|
*
|
|
* Can be called when the kernel is paused.
|
|
*/
|
|
static bool exists(Thread *p);
|
|
|
|
/**
|
|
* Returns the priority of a thread.<br>
|
|
* To get the priority of the current thread use:
|
|
* \code Thread::getCurrentThread()->getPriority(); \endcode
|
|
* If the thread is currently locking one or more mutexes, this member
|
|
* function returns the current priority, which can be higher than the
|
|
* original priority due to priority inheritance.
|
|
* \return current priority of the thread
|
|
*
|
|
* Can be called when the kernel is paused.
|
|
*/
|
|
Priority getPriority();
|
|
|
|
/**
|
|
* Set the priority of this thread.<br>
|
|
* This member function changed from previous Miosix versions since it is
|
|
* now static. This implies a thread can no longer set the priority of
|
|
* another thread.
|
|
* \param pr desired priority. Must be 0<=pr<PRIORITY_MAX
|
|
*
|
|
* Can be called when the kernel is paused.
|
|
*/
|
|
static void setPriority(Priority pr);
|
|
|
|
/**
|
|
* Suggests a thread to terminate itself. Note that this method only makes
|
|
* testTerminate() return true on the specified thread. If the thread does
|
|
* not call testTerminate(), or if it calls it but does not delete itself
|
|
* by returning from entry point function, it will NEVER
|
|
* 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.
|
|
*/
|
|
void terminate();
|
|
|
|
/**
|
|
* This method stops the thread until another thread calls wakeup() on this
|
|
* thread.<br>Calls to wait are not cumulative. If wait() is called two
|
|
* times, only one call to wakeup() is needed to wake the thread.
|
|
* <br>CANNOT be called when the kernel is paused.
|
|
*/
|
|
static void wait();
|
|
|
|
/**
|
|
* Wakeup a thread.
|
|
* <br>CANNOT be called when the kernel is paused.
|
|
*/
|
|
void wakeup();
|
|
|
|
/**
|
|
* Wakeup a thread.
|
|
* <br>Can be called when the kernel is paused.
|
|
*/
|
|
void PKwakeup();
|
|
|
|
/**
|
|
* Detach the thread if it was joinable, otherwise do nothing.<br>
|
|
* If called on a deleted joinable thread on which join was not yet called,
|
|
* it allows the thread's memory to be deallocated.<br>
|
|
* If called on a thread that is not yet deleted, the call detaches the
|
|
* thread without deleting it.
|
|
* If called on an already detached thread, it has undefined behaviour.
|
|
*/
|
|
void detach();
|
|
|
|
/**
|
|
* \return true if the thread is detached
|
|
*/
|
|
bool isDetached() const;
|
|
|
|
/**
|
|
* Wait until a joinable thread is terminated.<br>
|
|
* If the thread already terminated, this function returns immediately.<br>
|
|
* Calling join() on the same thread multiple times, from the same or
|
|
* multiple threads is not recomended, but in the current implementation
|
|
* the first call will wait for join, and the other will return false.<br>
|
|
* Trying to join the thread join is called in returns false, but must be
|
|
* avoided.<br>
|
|
* Calling join on a detached thread might cause undefined behaviour.
|
|
* \param result If the entry point function of the thread to join returns
|
|
* void *, the return value of the entry point is stored here, otherwise
|
|
* the content of this variable is undefined. If NULL is passed as result
|
|
* the return value will not be stored.
|
|
* \return true on success, false on failure
|
|
*/
|
|
bool join(void** result=NULL);
|
|
|
|
/**
|
|
* Same as get_current_thread(), but meant to be used insida an IRQ, when
|
|
* interrupts are disabled or when the kernel is paused.
|
|
*/
|
|
static Thread *IRQgetCurrentThread();
|
|
|
|
/**
|
|
* Same as getPriority(), but meant to be used inside an IRQ, when
|
|
* interrupts are disabled or when the kernel is paused.
|
|
*/
|
|
Priority IRQgetPriority();
|
|
|
|
/**
|
|
* Same as wait(), but is meant to be used only inside an IRQ or when
|
|
* interrupts are disabled.<br>
|
|
* Note: this method is meant to put the current thread in wait status in a
|
|
* piece of code where interrupts are disbled; it returns immediately, so
|
|
* the user is responsible for re-enabling interrupts and calling yield to
|
|
* effectively put the thread in wait status.
|
|
*
|
|
* \code
|
|
* disableInterrupts();
|
|
* ...
|
|
* Thread::IRQwait();//Return immediately
|
|
* enableInterrupts();
|
|
* Thread::yield();//After this, thread is in wait status
|
|
* \endcode
|
|
*/
|
|
static void IRQwait();
|
|
|
|
/**
|
|
* Same as wakeup(), but is meant to be used only inside an IRQ or when
|
|
* interrupts are disabled.
|
|
*/
|
|
void IRQwakeup();
|
|
|
|
/**
|
|
* Same as exists() but is meant to be called only inside an IRQ or when
|
|
* interrupts are disabled.
|
|
*/
|
|
static bool IRQexists(Thread *p);
|
|
|
|
/**
|
|
* \internal
|
|
* This method is only meant to implement functions to check the available
|
|
* stack in a thread. Returned pointer is constant because modifying the
|
|
* stack through it must be avoided.
|
|
* \return pointer to bottom of stack of current thread.
|
|
*/
|
|
static const unsigned int *getStackBottom();
|
|
|
|
/**
|
|
* \internal
|
|
* \return the size of the stack of the current thread.
|
|
*/
|
|
static int getStackSize();
|
|
|
|
#ifdef WITH_PROCESSES
|
|
|
|
/**
|
|
* \return the process associated with the thread
|
|
*/
|
|
ProcessBase *getProcess() { return proc; }
|
|
|
|
/**
|
|
* \internal
|
|
* Can only be called inside an IRQ, its use is to switch a thread between
|
|
* userspace/kernelspace and back to perform context switches
|
|
*/
|
|
static void IRQhandleSvc(unsigned int svcNumber);
|
|
|
|
/**
|
|
* \internal
|
|
* Can only be called inside an IRQ, its use is to report a fault so that
|
|
* in case the fault has occurred within a process while it was executing
|
|
* in userspace, the process can be terminated.
|
|
* \param fault data about the occurred fault
|
|
* \return true if the fault was caused by a process, false otherwise.
|
|
*/
|
|
static bool IRQreportFault(const miosix_private::FaultData& fault);
|
|
|
|
#endif //WITH_PROCESSES
|
|
|
|
private:
|
|
//Unwanted methods
|
|
Thread(const Thread& p);///< No public copy constructor
|
|
Thread& operator = (const Thread& p);///< No publc operator =
|
|
|
|
class ThreadFlags
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor, sets flags to default.
|
|
*/
|
|
ThreadFlags() : flags(0) {}
|
|
|
|
/**
|
|
* Set the wait flag of the thread.
|
|
* Can only be called with interrupts disabled or within an interrupt.
|
|
* \param waiting if true the flag will be set, otherwise cleared
|
|
*/
|
|
void IRQsetWait(bool waiting);
|
|
|
|
/**
|
|
* Set the wait_join flag of the thread.
|
|
* Can only be called with interrupts disabled or within an interrupt.
|
|
* \param waiting if true the flag will be set, otherwise cleared
|
|
*/
|
|
void IRQsetJoinWait(bool waiting);
|
|
|
|
/**
|
|
* Set wait_cond flag of the thread.
|
|
* Can only be called with interrupts disabled or within an interrupt.
|
|
* \param waiting if true the flag will be set, otherwise cleared
|
|
*/
|
|
void IRQsetCondWait(bool waiting);
|
|
|
|
/**
|
|
* Set the sleep flag of the thread.
|
|
* Can only be called with interrupts disabled or within an interrupt.
|
|
* \param sleeping if true the flag will be set, otherwise cleared
|
|
*/
|
|
void IRQsetSleep(bool sleeping);
|
|
|
|
/**
|
|
* Set the deleted flag of the thread. This flag can't be cleared.
|
|
* Can only be called with interrupts disabled or within an interrupt.
|
|
*/
|
|
void IRQsetDeleted();
|
|
|
|
/**
|
|
* Set the sleep flag of the thread. This flag can't be cleared.
|
|
* Can only be called with interrupts disabled or within an interrupt.
|
|
*/
|
|
void IRQsetDeleting()
|
|
{
|
|
flags |= DELETING;
|
|
}
|
|
|
|
/**
|
|
* Set the detached flag. This flag can't be cleared.
|
|
* Can only be called with interrupts disabled or within an interrupt.
|
|
*/
|
|
void IRQsetDetached()
|
|
{
|
|
flags |= DETACHED;
|
|
}
|
|
|
|
/**
|
|
* Set the userspace flag of the thread.
|
|
* Can only be called with interrupts disabled or within an interrupt.
|
|
* \param sleeping if true the flag will be set, otherwise cleared
|
|
*/
|
|
void IRQsetUserspace(bool userspace)
|
|
{
|
|
if(userspace) flags |= USERSPACE; else flags &= ~USERSPACE;
|
|
}
|
|
|
|
/**
|
|
* \return true if the wait flag is set
|
|
*/
|
|
bool isWaiting() const { return flags & WAIT; }
|
|
|
|
/**
|
|
* \return true if the sleep flag is set
|
|
*/
|
|
bool isSleeping() const { return flags & SLEEP; }
|
|
|
|
/**
|
|
* \return true if the deleted and the detached flags are set
|
|
*/
|
|
bool isDeleted() const { return (flags & 0x14)==0x14; }
|
|
|
|
/**
|
|
* \return true if the thread has been deleted, but its resources cannot
|
|
* be reclaimed because it has not yet been joined
|
|
*/
|
|
bool isDeletedJoin() const { return flags & DELETED; }
|
|
|
|
/**
|
|
* \return true if the deleting flag is set
|
|
*/
|
|
bool isDeleting() const { return flags & DELETING; }
|
|
|
|
/**
|
|
* \return true if the thread is in the ready status
|
|
*/
|
|
bool isReady() const { return (flags & 0x67)==0; }
|
|
|
|
/**
|
|
* \return true if the thread is detached
|
|
*/
|
|
bool isDetached() const { return flags & DETACHED; }
|
|
|
|
/**
|
|
* \return true if the thread is waiting a join
|
|
*/
|
|
bool isWaitingJoin() const { return flags & WAIT_JOIN; }
|
|
|
|
/**
|
|
* \return true if the thread is waiting on a condition variable
|
|
*/
|
|
bool isWaitingCond() const { return flags & WAIT_COND; }
|
|
|
|
/**
|
|
* \return true if the thread is running unprivileged inside a process.
|
|
*/
|
|
bool isInUserspace() const { return flags & USERSPACE; }
|
|
|
|
private:
|
|
///\internal Thread is in the wait status. A call to wakeup will change
|
|
///this
|
|
static const unsigned int WAIT=1<<0;
|
|
|
|
///\internal Thread is sleeping.
|
|
static const unsigned int SLEEP=1<<1;
|
|
|
|
///\internal Thread is deleted. It will continue to exist until the
|
|
///idle thread deallocates its resources
|
|
static const unsigned int DELETED=1<<2;
|
|
|
|
///\internal Somebody outside the thread asked this thread to delete
|
|
///itself.<br>This will make Thread::testTerminate() return true.
|
|
static const unsigned int DELETING=1<<3;
|
|
|
|
///\internal Thread is detached
|
|
static const unsigned int DETACHED=1<<4;
|
|
|
|
///\internal Thread is waiting for a join
|
|
static const unsigned int WAIT_JOIN=1<<5;
|
|
|
|
///\internal Thread is waiting on a condition variable
|
|
static const unsigned int WAIT_COND=1<<6;
|
|
|
|
///\internal Thread is running in userspace
|
|
static const unsigned int USERSPACE=1<<7;
|
|
|
|
unsigned short flags;///<\internal flags are stored here
|
|
};
|
|
|
|
#ifdef WITH_PROCESSES
|
|
|
|
/**
|
|
* \internal
|
|
* Causes a thread belonging to a process to switch to userspace, and
|
|
* execute userspace code. This function returns when the process performs
|
|
* a syscall or faults.
|
|
* \return the syscall parameters used to serve the system call.
|
|
*/
|
|
static miosix_private::SyscallParameters switchToUserspace();
|
|
|
|
/**
|
|
* Create a thread to be used inside a process. The thread is created in
|
|
* WAIT status, a wakeup() on it is required to actually start it.
|
|
* \param startfunc entry point
|
|
* \param argv parameter to be passed to the entry point
|
|
* \param options thread options
|
|
* \param proc process to which this thread belongs
|
|
*/
|
|
static Thread *createUserspace(void *(*startfunc)(void *),
|
|
void *argv, unsigned short options, Process *proc);
|
|
|
|
/**
|
|
* Setup the userspace context of the thread, so that it can be later
|
|
* switched to userspace. Must be called only once for each thread instance
|
|
* \param entry userspace entry point
|
|
* \param gotBase base address of the GOT, also corresponding to the start
|
|
* of the RAM image of the process
|
|
* \param ramImageSize size of the process ram image
|
|
*/
|
|
static void setupUserspaceContext(unsigned int entry, unsigned int *gotBase,
|
|
unsigned int ramImageSize);
|
|
|
|
#endif //WITH_PROCESSES
|
|
|
|
/**
|
|
* Constructor, initializes thread data.
|
|
* \param watermark pointer to watermark area
|
|
* \param stacksize thread's stack size
|
|
* \param defaultReent true if the global reentrancy structure is to be used
|
|
*/
|
|
Thread(unsigned int *watermark, unsigned int stacksize, bool defaultReent);
|
|
|
|
/**
|
|
* Destructor
|
|
*/
|
|
~Thread();
|
|
|
|
/**
|
|
* Helper function to initialize a Thread
|
|
* \param startfunc entry point function
|
|
* \param stacksize stack size for the thread
|
|
* \param argv argument passed to the thread entry point
|
|
* \param options thread options
|
|
* \param defaultReent true if the default C reentrancy data should be used
|
|
* \return a pointer to a thread, or NULL in case there are not enough
|
|
* resources to create one.
|
|
*/
|
|
static Thread *doCreate(void *(*startfunc)(void *), unsigned int stacksize,
|
|
void *argv, unsigned short options, bool defaultReent);
|
|
|
|
/**
|
|
* Thread launcher, all threads start from this member function, which calls
|
|
* the user specified entry point. When the entry point function returns,
|
|
* it marks the thread as deleted so that the idle thread can dellocate it.
|
|
* If exception handling is enebled, this member function also catches any
|
|
* exception that propagates through the entry point.
|
|
* \param threadfunc pointer to the entry point function
|
|
* \param argv argument passed to the entry point
|
|
*/
|
|
static void threadLauncher(void *(*threadfunc)(void*), void *argv);
|
|
|
|
/**
|
|
* Allocates the idle thread and makes cur point to it
|
|
* Can only be called before the kernel is started, is called exactly once
|
|
* so that getCurrentThread() always returns a pointer to a valid thread or
|
|
* by startKernel to create the idle thread, whichever comes first.
|
|
* \return the newly allocated idle thread
|
|
*/
|
|
static Thread *allocateIdleThread();
|
|
|
|
/**
|
|
* \return the C reentrancy structure of the currently running thread
|
|
*/
|
|
static struct _reent *getCReent();
|
|
|
|
//Thread data
|
|
SchedulerData schedData; ///< Scheduler data, only used by class Scheduler
|
|
ThreadFlags flags;///< thread status
|
|
///Saved priority. Its value is relevant only if mutexLockedCount>0; it
|
|
///stores the value of priority that this thread will have when it unlocks
|
|
///all mutexes. This is because when a thread locks a mutex its priority
|
|
///can change due to priority inheritance.
|
|
Priority savedPriority;
|
|
///List of mutextes locked by this thread
|
|
Mutex *mutexLocked;
|
|
///If the thread is waiting on a Mutex, mutexWaiting points to that Mutex
|
|
Mutex *mutexWaiting;
|
|
unsigned int *watermark;///< pointer to watermark area
|
|
unsigned int ctxsave[CTXSAVE_SIZE];///< Holds cpu registers during ctxswitch
|
|
unsigned int stacksize;///< Contains stack size
|
|
///This union is used to join threads. When the thread to join has not yet
|
|
///terminated and no other thread called join it contains (Thread *)NULL,
|
|
///when a thread calls join on this thread it contains the thread waiting
|
|
///for the join, and when the thread terminated it contains (void *)result
|
|
union
|
|
{
|
|
Thread *waitingForJoin;///<Thread waiting to join this
|
|
void *result; ///<Result returned by entry point
|
|
} joinData;
|
|
/// Per-thread instance of data to make the C and C++ libraries thread safe.
|
|
struct _reent *cReentrancyData;
|
|
CppReentrancyData cppReentrancyData;
|
|
#ifdef WITH_PROCESSES
|
|
///Process to which this thread belongs. Null if it is a kernel thread.
|
|
ProcessBase *proc;
|
|
///Pointer to the set of saved registers for when the thread is running in
|
|
///user mode. For kernel threads (i.e, threads where proc==kernel) this
|
|
///pointer is null
|
|
unsigned int *userCtxsave;
|
|
#endif //WITH_PROCESSES
|
|
|
|
//friend functions
|
|
//Needs access to watermark, ctxsave
|
|
friend void miosix_private::IRQstackOverflowCheck();
|
|
//Need access to status
|
|
friend void IRQaddToSleepingList(SleepData *x);
|
|
//Needs access to status
|
|
friend bool IRQwakeThreads();
|
|
//Needs access to watermark, status, next
|
|
friend void *idleThread(void *argv);
|
|
//Needs to create the idle thread
|
|
friend void startKernel();
|
|
//Needs threadLauncher
|
|
friend void miosix_private::initCtxsave(unsigned int *ctxsave,
|
|
void *(*pc)(void *), unsigned int *sp, void *argv);
|
|
//Needs access to priority, savedPriority, mutexLocked and flags.
|
|
friend class Mutex;
|
|
//Needs access to flags
|
|
friend class ConditionVariable;
|
|
//Needs access to flags, schedData
|
|
friend class PriorityScheduler;
|
|
//Needs access to flags, schedData
|
|
friend class ControlScheduler;
|
|
//Needs access to flags, schedData
|
|
friend class EDFScheduler;
|
|
//Needs access to flags
|
|
friend int ::pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
|
|
//Needs access to flags
|
|
friend int ::pthread_cond_signal(pthread_cond_t *cond);
|
|
//Needs access to flags
|
|
friend int ::pthread_cond_broadcast(pthread_cond_t *cond);
|
|
//Needs access to cppReent
|
|
friend class CppReentrancyAccessor;
|
|
#ifdef WITH_PROCESSES
|
|
//Needs PKcreateUserspace(), setupUserspaceContext(), switchToUserspace()
|
|
friend class Process;
|
|
#endif //WITH_PROCESSES
|
|
};
|
|
|
|
/**
|
|
* Function object to compare the priority of two threads.
|
|
*/
|
|
class LowerPriority: public std::binary_function<Thread*,Thread*,bool>
|
|
{
|
|
public:
|
|
/**
|
|
* \param a first thread to compare
|
|
* \param b second thread to compare
|
|
* \return true if a->getPriority() < b->getPriority()
|
|
*
|
|
* Can be called when the kernel is paused. or with interrupts disabled
|
|
*/
|
|
bool operator() (Thread* a, Thread *b)
|
|
{
|
|
return a->getPriority() < b->getPriority();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \internal
|
|
* \struct Sleep_data
|
|
* This struct is used to make a list of sleeping threads.
|
|
* It is used by the kernel, and should not be used by end users.
|
|
*/
|
|
struct SleepData
|
|
{
|
|
///\internal Thread that is sleeping
|
|
Thread *p;
|
|
|
|
///\internal When this number becomes equal to the kernel tick,
|
|
///the thread will wake
|
|
long long wakeup_time;
|
|
|
|
SleepData *next;///<\internal Next thread in the list
|
|
};
|
|
|
|
/**
|
|
* \}
|
|
*/
|
|
|
|
} //namespace miosix
|
|
|
|
#endif //KERNEL_H
|