OpenRTX/lib/miosix-kernel/miosix/kernel/kernel.h

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