159 lines
4.0 KiB
C++
159 lines
4.0 KiB
C++
// vim: set noet ts=4 sw=4:
|
|
|
|
/*! \file
|
|
* \brief \ref Thread abstraction required for multithreading
|
|
*/
|
|
|
|
/*! \defgroup thread Multithreading
|
|
* \brief The Multithreading Subsystem
|
|
*
|
|
* The group Multithreading contains all elements that form the foundation
|
|
* of CPU multiplexing. This module's objective is to provide the abstraction
|
|
* thread that provides a virtualized CPU for the user's applications.
|
|
*/
|
|
|
|
#pragma once
|
|
#include "../arch/context.h"
|
|
#include "../object/queue.h"
|
|
#include "../types.h"
|
|
#include "../sync/semaphore.h"
|
|
|
|
#include "../memory/pagetable.h"
|
|
|
|
/// Stack size for each thread
|
|
constexpr uint32_t STACK_SIZE = 3472;
|
|
|
|
|
|
struct IpcStruct {
|
|
uintptr_t ptr;
|
|
size_t size;
|
|
int pid;
|
|
bool is_answer;
|
|
IpcStruct* queue_link = nullptr;
|
|
};
|
|
|
|
|
|
|
|
/*! \brief The Thread is an object used by the scheduler.
|
|
* \ingroup thread
|
|
*/
|
|
class Thread {
|
|
private:
|
|
/*! \brief pointer to the next element of the readylist
|
|
*/
|
|
Thread* queue_link;
|
|
bool isKernel;
|
|
void* start;
|
|
|
|
|
|
|
|
friend class Queue<Thread>;
|
|
friend class Semaphore;
|
|
/*! \brief Memory reserved for this threads stack
|
|
*/
|
|
// alignas(16) char reserved_stack_space_user[STACK_SIZE];
|
|
alignas(16) char reserved_stack_space_isr[STACK_SIZE];
|
|
|
|
/*! \brief Context of the thread, used for saving and restoring the register
|
|
* values when context switching.
|
|
*/
|
|
|
|
/*! \brief The thread's entry point.
|
|
*
|
|
* For the first activation of a thread, we need a "return address"
|
|
* pointing to a function that will take care of calling C++ virtual
|
|
* methods (e.g. \ref action()), based on the thread object pointer.
|
|
* For this purpose, we use this `kickoff()` function.
|
|
*
|
|
* \note As this function is never actually called, but only executed by
|
|
* returning from the co-routine's initial stack, it may never
|
|
* return. Otherwise garbage values from the stack will be interpreted as
|
|
* return address and the system might crash.
|
|
*
|
|
* \param param1 Thread to be started
|
|
* \param param2 Second parameter (will be used later)
|
|
* \param param3 Third parameter (will be used later)
|
|
*
|
|
*/
|
|
|
|
static void kickoffUsermode (Thread *object);
|
|
void map_app(void* code_paddr, uint16_t code_page_num, void* stack_vaddr, uint16_t stack_page_num);
|
|
public:
|
|
static void kickoff(uintptr_t param1, uintptr_t param2, uintptr_t param3);
|
|
struct{
|
|
void* user;
|
|
void* isr;
|
|
} StackPointer;
|
|
void* operator new ( size_t count )noexcept;
|
|
|
|
Context context;
|
|
four_lvl_paging_t* paging_tree;
|
|
|
|
void* code_paddr;
|
|
int code_pagenum;
|
|
|
|
Semaphore ipc_sem;
|
|
Queue<IpcStruct> ipc_queue;
|
|
|
|
|
|
|
|
|
|
/*! \brief Unique thread id */
|
|
const int id;
|
|
|
|
|
|
|
|
|
|
/*! \brief Marker for a dying thread
|
|
*/
|
|
volatile bool kill_flag;
|
|
|
|
// Naively moving or copying esp. the (user) stack of a thread would be a
|
|
// bad idea:
|
|
Thread(const Thread&) = delete;
|
|
Thread(Thread&&) = delete;
|
|
Thread& operator=(const Thread&) = delete;
|
|
Thread& operator=(Thread&&) = delete;
|
|
|
|
/*! \brief Constructor
|
|
* Initializes the context using \ref prepareContext with the thread's
|
|
* stack space.
|
|
*
|
|
*/
|
|
explicit Thread();
|
|
explicit Thread (bool kernel, void* start_addr, void * codeframe=0, int code_frame_num=1);
|
|
|
|
/*! \brief Activates the first thread on this CPU.
|
|
*
|
|
* Calling the method starts the first thread on the calling CPU.
|
|
* From then on, \ref Thread::resume() must be used for all subsequent
|
|
* context switches.
|
|
*
|
|
*/
|
|
void go();
|
|
|
|
void load_paging(Thread* t);
|
|
|
|
/*! \brief Switches from the currently running thread to the `next` one.
|
|
*
|
|
* The values currently present in the callee-saved registers will be
|
|
* stored in this threads context-structure, the corresponding values
|
|
* belonging to `next` thread will be loaded.
|
|
* \param next Pointer to the next thread.
|
|
*
|
|
*/
|
|
void resume(Thread* next);
|
|
|
|
/*! \brief Method that contains the thread's program code.
|
|
*
|
|
* Derived classes are meant to override this method to provide
|
|
* meaningful code to be run in this thread.
|
|
*/
|
|
virtual void action(); // XXX: why is this not always pure virtual?
|
|
//
|
|
//
|
|
//
|
|
|
|
|
|
};
|