I keep getting this message when I try to compile:
task.c++:54:102: error: invalid use of non-static member function
this->createTask(&otherTask, this->otherMain, mainTask.regs.eflags, (uint32_t*)mainTask.regs.cr3);
Here is my task.c++ function:
#include "task.h"
static task_q *runningTask;
static task_q mainTask;
static task_q otherTask;
static PhyiscalMemoryManager *pmm_task;
static Heap *heap_task;
extern void switch_task_a();
TaskManager::TaskManager(Heap *heap)
{
heap_task = heap;
}
TaskManager::~TaskManager()
{}
Task::Task()
{}
Task::~Task()
{}
void TaskManager::otherMain()
{
printf("Hello multitasking world!"); // Not implemented here...
preempt();
}
void TaskManager::createTask(task_q* task, void(*task_main)(), uint32_t flags, uint32_t* pageDir)
{
task->regs.ebx = 0;
task->regs.ecx = 0;
task->regs.edx = 0;
task->regs.esi = 0;
task->regs.edi = 0;
task->regs.eflags = flags;
task->regs.eip = (uint32_t) task_main;
task->regs.cr3 = (uint32_t) pageDir;
task->regs.esp = (uint32_t) (heap_task->k_malloc(TASK_STACK_SIZE)) + 0x1000; // Not implemented here
task->next = 0;
}
void TaskManager::init_tasking()
{
// Get EFLAGS and CR3
__asm __volatile("movl %%cr3, %%eax; movl %%eax, %0;":"=m"(mainTask.regs.cr3)::"%eax");
__asm __volatile("pushfl; movl (%%esp), %%eax; movl %%eax, %0; popfl;":"=m"(mainTask.regs.eflags)::"%eax");
this->createTask(&otherTask, this->otherMain, mainTask.regs.eflags, (uint32_t*)mainTask.regs.cr3);
mainTask.next = &otherTask;
otherTask.next = &mainTask;
runningTask = &mainTask;
}
void TaskManager::switchTask(Registers *old, Registers *new_)
{
switch_task_a();
}
void TaskManager::preempt()
{
task_q *last = runningTask;
runningTask = runningTask->next;
switchTask(&last->regs, &runningTask->regs);
}
And here is my task.h:
#ifndef _TASK_H_
#define _TASK_H_ 1
#include <stdarg.h>
#include <stdint.h>
#include "gdt.h"
#include "stdio.h"
#include "heap.h"
#include "pmm.h"
#define TASK_STACK_SIZE 0x2000
typedef struct {
uint32_t eax, ebx, ecx, edx, esi, edi,
esp, ebp, eip, eflags, cr3;
} Registers;
typedef struct task_q {
Registers regs;
struct task_q *next;
} task_q;
class Task
{
friend class TaskManager;
public:
Task();
~Task();
private:
};
class TaskManager
{
public:
TaskManager(Heap *heap);
~TaskManager();
void init_tasking();
static void createTask(task_q* task, void(*task_main)(), uint32_t flags, uint32_t* pageDir);
void preempt();
private:
void switchTask(Registers *old, Registers *new_);
void otherMain();
};
#endif
Is this something wrong with calling this->OtherMain()
inside this->createTask()
?
void(*task_main)()
is expecting a pointer to a function. You attempt to feed it void otherMain();
which is a class method and has a hidden this
parameter.
This stuff gets a little whacky. Here is a great write-up on some of the badness and how to avoid it.
You're going to have to do a bit of a rethink on how you do this. You can use a static void task_runner(void * userparam)
method (no this
) and a user parameter that can be cast by the static method to provide a TaskManager
on which you can invoke otherMain
. You can turn void(*task_main)()
into void(TaskManager::*task_main)()
and you'll still have to provide a TaskManager
to invoke the method pointer on.
It's a really nasty business, but can I interest you in exploring std::bind
instead?
Task runner is something along the lines of this:
class taskRunner
{
public:
virtual execute() = 0;
static void task_runner(void * userparam)
{
taskRunner* task = (taskRunner*)userparam;
task->execute();
}
};
Downsides are everything you try to run MUST be a class that inherits taskRunner
and implements execute
and something must keep track of userparam
. Non trivial effort is involved, but what the hell. Looks like you're writing yourself an OS. Non trivial effort all-around.
Probably better for you it to push the abstraction up one level and only accept free functions and static methods. Let the function being run sort out whether it's a class or not.
This means that otherMain
cannot be a member of TaskManager
unless it's static and this will require a re-write of TaskManager
to allow cross-cutting behaviour like a task's ability to sleep, yield its timeslice, and other OS goodies to be called without knowing the internals of TaskManager
.
otherMain
could just be
void otherMain()
{
printf("Hello multitasking world!");
yield(); // a free function that calls into the system's TaskManager to preempt
}
The second parameter to createTask()
is a:
void(*task_main)()
This is a pointer to a function that returns void
.
You are passing a:
this->otherMain
otherMain
is not a function that returns void
. It is a class member that returns void
. A class member is not exactly the same as a function.
The correct parameter type for createTask
, to match a class method that returns void would be:
void (TaskManager::*task_main)()
and the otherMain
class method can be passed as simply:
&TaskManager::otherMain
This would solve the immediate problem of the compilation error for this function call.
However, you will likely now have a new, different problem. Your existing code attempts to stuff the function pointer into something that resembles a CPU register.
Well, you don't have a function pointer any more. You now have a class method pointer. Whether or not the existing code will work, as is, depends on your C++ implementation. Probably not, but that would be a different question.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.