-3

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()?

zondo
  • 19,901
  • 8
  • 44
  • 83
amanuel2
  • 4,508
  • 4
  • 36
  • 67
  • Possible duplicate of [invalid use of non-static member function](http://stackoverflow.com/questions/29286863/invalid-use-of-non-static-member-function) – gsamaras Sep 10 '16 at 00:29
  • @gsamaras thats the first question i saw before many , before asking this question – amanuel2 Sep 10 '16 at 00:35

2 Answers2

1

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?

Edit

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
}
Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54
1

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.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Well The Only Tasks I create have to be from a TaskManager then ? – amanuel2 Sep 10 '16 at 00:43
  • Doesn't matter. A function pointer is not a class method pointer. Full stop. – Sam Varshavchik Sep 10 '16 at 00:44
  • Well when i do that error here : https://github.com/amanuel2/OS_Mirror/blob/master/task.c%2B%2B#L42 Error Bieng : sk.c++:42:34: error: invalid cast from type 'void (TaskManager::*)()' to type 'uint32_t {aka long unsigned int}' task->regs.eip = (uint32_t) task_main; – amanuel2 Sep 10 '16 at 00:45
  • Sam Is there a way to acomplish this without doing TaskManager::*task_main ? i think i will have to forget about classes on this code.. ofcourse making it more C Like – amanuel2 Sep 10 '16 at 00:46
  • Insufficient information to answer that. It all depends on what, when, and how, that CPU-like register is used for. Instead of passing a class method, pass a static class function, which would be an ordinary function. When it gets invoked, it will have obtain the pointer to the object, in some form or fashion, and then invoke the real callback method. – Sam Varshavchik Sep 10 '16 at 00:49