initalizing a class

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Adek336

Re:initalizing a class

Post by Adek336 »

Runtime-checked cast:
How is it checked on runtime?
Until you really understood C++, you should stick to C.
One way to learn C++ is to use it :)
I second Pype's urgent advice not to assume the binary layout of a class. Use accessor functions!
I will try to copy the necessary data to a struct in the C code and then access the struct instead of a class. Is this a good idea?

Cheers,
Adrian.
Tim

Re:initalizing a class

Post by Tim »

Adek336 wrote:One way to learn C++ is to use it :)
Absolutely, but it's better to learn in a nice, controlled environment with good debuggers and runtime support, and not as a basis for your own OS. Learning the language while you write an OS is a pretty bad idea, as you will have to keep starting again as you learn that what you have already written is wrong. What's more, not knowing the language makes it hard to come up with a detailed design beforehand.
Adek336

Re:initalizing a class

Post by Adek336 »

Yea, I see your point. Anyways, I find learning C++ in osdev more interesting so I try my best to keep it working in C++ instead of C.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:initalizing a class

Post by Pype.Clicker »

why not simply writing the scheduling code in C++ aswell ? Or if you really need a component to be written in asm, giving it the address of the field it must operate on rather than the address of the struct which holds the field ? ...

Even different version of the same compiler may have different binary encoding of some structure, not even mentionning the fact that the structure themselves may change (and beleive me, the internal organization of your task *will* change) ...

What you can safely assume from some ASM code is that entries in an array occupy contiguous memory places when the size of 1 entry is a multiple of its alignment, and that in a ((packed)) C structure, fields will come in the order you provided them and use no more bytes that what they actually require (i.e. padding is ignored, iirc).
Schol-R-LEA

Re:initalizing a class

Post by Schol-R-LEA »

I am hesitant to mention it, as it has hideous potential for abuse, but...

There is a special construct in C++. called a 'pointer to member offset', that will allow you to capture an offset to a member variable securely, bypassing normal object encapsulation to a limited degree; it still requires a pointer to the object that is being modified, but it does allow you to get an offset independent of a specific object of a given class at runtime.

It is not something to be used casually; like [tt]goto[/tt], it exists in the language solely for the extremely rare instances when the alternatives are even worse. I would not even consider using it unless I had exhausted all other reasonable approaches.

The pointer-to-member has to be specifically declared as such, and specially assigned as well. If you have class Foo:

Code: Select all

class Foo 
{
  Foo();
  int x;
  int y();
}


... then pointer-to-member-offsets would be declared and used as so:

Code: Select all

int z;
int Foo::*bar;
int (Foo::*baz)();
Foo quux;
Foo *gah;

gah = new Foo();
bar = &Foo::x;
baz = &(Foo::y)();

gah->*bar = 5;
quux.*bar = gah->*baz();
z = quux.*baz();
}
(Note that this code example may not be completely correct; corrections and comments welcome).

This is the closest thing I know of to what you want, and it still woud probably be hard to use the way you are looking to. Since it is an offset, not a true pointer, passing it to an assembly language routine would still require a pointer to the object itself, and since the implementation of the offsets themselves is compiler-specific, it may have to be reinterpreted in order to be used by the assembly routine.

Again, I advise against using this unless there are no other reasonable approaches, and then only after you are absolutely certain you understand how they work (I must admit, I am not entirely clear about them myself). Using accessor functions to read and modify member variables is infinitely preferable, and in this case, probably the better solution, regardless of extra overhead.
Adek336

Re:initalizing a class

Post by Adek336 »

Your post resembles me a moment in The Lord of The Rings, where Frodo has been found by the Nazgul, but the Nazgul could not find his position accuratedly; Frodo hesitated whether to put the Ring or not. The atmosphere of your post was somekind similar. ;D

But if you say it is not a good srategy, I wil try what Tim said: build the scheduler in C++. I will reply how well does it work (oh well who cares for such small speed differencies?)

Cheers,
Adrian.
Tim

Re:initalizing a class

Post by Tim »

Don't be too concerned about speed at this stage; better to have a working implementation that's 98% efficient than endlessly hacking at a 100% efficient implementation.

In any case, any speed increase you might get from writing your scheduler in assembly is going to be tiny compared to the overhead imposed by the kernel-user transitions, and virtually zero compared to the period between calls to the scheduler.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:initalizing a class

Post by Solar »

Adek336 wrote: I find learning C++ in osdev more interesting so I try my best to keep it working in C++ instead of C.
Adek336, I salute your courage.

I mean, I know the C language and most of its standard lib inside out. I consider myself being quite proficient in C++. I know most of the more arcane "dark places" of the C++ language, I've written (and debugged and refactored) tons of C++ code, I've read stuff about the ABI, runtime requirements, and implementation details that probably would make your toenails curl. I discuss stuff with a language lawyer and C++ Standards Committee member for fun in my lunch breaks.

And I am, slowly, carefully, inching my way forward in designing a C++ kernel, and feel the pain of not really knowing what I'm to do next with every step.

And here you are, telling me you want to learn C++ while writing an OS kernel.

If asked if that is a wise thing to do, I wouldn't hesitate a second before yelling "NO!", but you sure got a pair of balls there.

I just had to say that - respect!
Every good solution is obvious once you've found it.
Adek336

Re:initalizing a class

Post by Adek336 »

Adek336, I salute your courage.
lol, thanx :)
I mean, I know the C language and most of its standard lib inside out. I consider myself being quite proficient in C++. I know most of the more arcane "dark places" of the C++ language, I've written (and debugged and refactored) tons of C++ code, I've read stuff about the ABI, runtime requirements, and implementation details that probably would make your toenails curl. I discuss stuff with a language lawyer and C++ Standards Committee member for fun in my lunch breaks.
I'm into C++ since 2 weeks, now
I just had to say that - respect!
Thanx - cool!

I think it is not my courage, I suppose it is rather that I know so little about programming. You make me have goosebumps when I read your post, I have only 2 weeks experience with C++ and one month with gcc...

Anyways, I will be now trying to take the next big step - create a second adress space, map the "CLI HLT" instructions into 0x80000000 and throw that through my scheduler. I wonder how well will it work? :o

Cheers,
Adrian. Salute Solar!
Adek336

Re:initalizing a class

Post by Adek336 »

if I reload cr3 with a pgd which has the same mapping of the currently running code as the old cr3, do I need to reload selectors? or perhaps I don't have to reload them even if the mapping is other?

Cheers,
Adrian.
Curufir

Re:initalizing a class

Post by Curufir »

Tim Robinson wrote: In any case, any speed increase you might get from writing your scheduler in assembly is going to be tiny compared to the overhead imposed by the kernel-user transitions, and virtually zero compared to the period between calls to the scheduler.
Just to throw in my 2 cents.

People need to remember that it takes a lot of patience and knowledge to create highly optimised assembly programs. If you haven't got that knowledge and don't like the idea of working through your code by hand to optimise size/scheduling of instructions then the compiler of your choice is probably going to create a faster/smaller binary than you are, and give you less headaches in the process.

In short assembly language isn't the magic speed/size panacea people sometimes make it out to be. If you're good you can beat the compilers most of the time, if you're really good you can beat them all the time, but if you're average then it's hit or miss as to whether you'll beat them at all.

That having been said there's something incredibly satisfying about saving that single byte, or figuring out some alternate instruction scheduling, which brings your program a tiny bit closer to perfection. You don't really get that in other languages.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:initalizing a class

Post by Solar »

Whoa, I overlooked that one...
Tim Robinson wrote: In any case, any speed increase you might get from writing your scheduler in assembly is going to be tiny compared to the overhead imposed by the kernel-user transitions, and virtually zero compared to the period between calls to the scheduler.
Before you look at whether you can save a couple of clock cycles by writing your scheduler in Assembler, check the Algorithm of your scheduler, its complexity. What happens to the scheduler execution times when the number of tasks in your queues increases? How does it scale?

Quick intro into complexities. Let's say you have n tasks in your system.

If the execution time of your scheduler roughly n^2, that's notated as O(n^2), and called "exponential complexity". Bad, your algorithm needs some improvement.

If it's directly proportional to n, it's written O(n), called "linear complexity" - quite well already.

If execution time roughly doubles for every order of magnitude of n (like, 100 tasks take twice as long as 10 tasks), that's O(log(n)) - "logarhitmic complexity", and you have one of the best algorhithms around.

However, quite recently the Linux scheduler was improved to O(1) - "constant complexity": No matter how many tasks are involved, the scheduler always takes the same time to figure out which one to run. That's the state of the art, there.

(Note that in all these calculations, details don't matter; e.g. whether your execution time doubles or tripples with a logarhithmic complexity, it's still in the O(log(n)) category. And do note that a constant-time scheduler can take much longer for a given schedule than a O(n^2) scheduler - but the O(n^2) is more likely to collapse when the load increases...)

Bottom line, find out if you have a performance problem, where you have it, and if the algorhithm of the code section in question is already optimal. Only then start writing it in Assembler. It's far too easy to start saving every possible bit and byte in an algorhithm, only to find out that a different algorhithm written in C/C++ beats the living daylights out of your Assembly... ;-)
Every good solution is obvious once you've found it.
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:initalizing a class

Post by distantvoices »

If a class is considered to be "something like a c structure", then why not putting the pointer to the desired incarnation of the class in a from-asm-accessible-pointer-variable, and manipulating the desired memory location by using some neat offsets into the object. It's but merely a conglommerate of data put in a certain order. So, at least the FIRST element should be accessible by asm without having to deal with eventual padding. ... I just wonder ... (and no, I don't sweat it *gg*)

@Solar: you've guts, gosh, to do a kernel in c++. writing all that extra runtime mumbojumbo needed to have classes, inheritance, templates and new and delete and co ... balls (groin's foine) is all I say :P*gg* I for my part am happy to master C at the moment.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:initalizing a class

Post by Solar »

beyond infinity wrote: If a class is considered to be "something like a c structure", then why not putting the pointer to the desired incarnation of the class in a from-asm-accessible-pointer-variable, and manipulating the desired memory location by using some neat offsets into the object.
That's called "data hiding". Let's say your data is held in a data structure X. Later, you realize that data structure Y would be better.

With accessor functions (and private data members), all you have to do is changing X to Y, and adapt the accessor functions to access Y instead of X. All your code will continue to work flawlessly. If efficiency is a concern (i.e., the existing accessor functions are now doing some nasty X-to-Y conversion stuff you'd like to avoid), you can create new accessor functions taking different parameters that better suit Y, and replace calls to the old accessors with calls to the new ones, step by step.

At no point does your code break.

Without accessor functions, public data members, and assembler code poking in your class' internals, you must never change the data structure, or you have to make sure you found all references to those structures in your whole code base...
@Solar: you've guts, gosh, to do a kernel in c++.
Well, compared to Adek, at least I know the language... ;-)
..writing all that extra runtime mumbojumbo needed to have classes, inheritance, templates and new and delete and co ...
Once you have malloc() and free(), operator new() and delete() is trivial. Templates don't need runtime support, neither do classes or inheritance (unless they are instantiated globally / statically, but that is handled with 10 lines of code). That's all handled by the compiler.

What's a bit more tricky is RTTI (needed for typeid() and dynamic_cast<>, but you can work around either), and exceptions - but especially exceptions can offer so much, compared to ERRNO / return code checking, if you keep an eye on the code size / clock cycle tradeoff.

Add to that all the syntactic suggar C++ offers, making large-scale codebases so much easier to maintain... I was pro C++ right from the start, and while it's a bit harder to do this because there's so little documentation / tutorials available, I think it's worth the cost.

When I feel ready, I'll announce my "Kernel Space C++" tutorial / forum at this place. (It's rather pathetic ATM, but it'll grow.)
Every good solution is obvious once you've found it.
Adek336

Re:initalizing a class

Post by Adek336 »

Well, compared to Adek, at least I know the language... ;-)
It doesn't mean I cannot use both C-like and C++ constructs. I'm sure I'll have the best os around here ;D
Post Reply