User talk:Montrom
Jump to navigation
Jump to search
About this Page
This page is an attempt to consolidate all of the most useful information contributed by members of the OSDEV forum. This information was collected from a thread at OSDEV forums that asked for members to submit knowledge that they have gained while making mistakes. I tried to collect the most useful of that knowledge and to place it here in a more organized manner. If you would like to view the original thread, then please scroll to the bottom of this page for the link.
Getting Started
- Design Phase: Design is something that should be done on paper first. I made the newbie mistake to rush right into it, and I finally discovered that I needed to redo (almost rewrite) most of my code, because I decided on a different design midway through, and I am still fighting with all the problems these changes have produced. And, each time I veer in a new direction, change destroys pieces of old logic. The amount of time I spend fixing those mistakes, sometimes rewriting entire files of code, all this could have been avoided.
- TODO LIST: A todo list is worth its weight in gold if done properly. I keep a spiral notebook that I use to keep track of what needs to to be done and in what order. I keep notes about what bugs I have and a description of how to replicate it, etc. I have never been more organized and productive in my life. Thank you, todo list.
- Build Your Toolbox: Once I start typing the same compound statement two or three times, I make it an alias or a shell function and put it in my ~/.bashrc (Linux or Cygwin, doesn't matter.). What is useful strongly depends on your environment. Don't waste your time typing trivial things, automate them. (And keep the code around so you can transfer it to other systems as necessary.)
- Automation: I made a simple script to perform all steps necessary to build the different versions of my kernel and run them using the different environments mentioned above. It calls autoconf, automake etc. if necessary, configures with the desired kernel options (i686, x86_64, with or without ACPI / SMP support...), builds the kernel and drivers, creates a boot floppy... This simplifies the build process a lot.
Backups/Subversion
- Backups: Make backups just as often as you make significant progress. Either place your new code online or offline somewhere. Do not replace any confirmed to be working code with unproven new code without first testing the new code on real hardware. This is especially true once you've begun developing a GUI. You'll do most of your development in an emulated environment, but all final cuts should be made in a real environment, where it will one day be forced to survive.
- Use version control software: Strong contenders today are git, Mercurial, and SVN. But don't be afraid to use even lowly RCS if in a pinch. (I use RCS regularily when hacking a script or a config file.) Nothing beats the ability to go back in time to check when something broke, and which change broke it.
- Use a issue tracker: Mantis, Bugzilla, Trac - again the tool doesn't matter much as long as you use it. (Of course you could use full backups of your source tree and a CHANGES.txt file instead. That would still be better than nothing, but those tools I mentioned above are there for a reason - they add huge amounts of productivity.)
- Control your changesets: One changeset should address one issue only, and should be describable with a single line checkin comment. If the issue is too complicated for a one-liner, create a ticket in your issue tracker, document things there, and reference the ticket number in your checkin comment.
Testing/Debugging
- Assert: It costs nothing (if NDEBUG'd out) at runtime and provides a commentary if correctly used.
- Testing 1, 2, 3: Every test should be done at least twice if the first test failed. Sometimes bugs work themselves out after the second or so try.
- Keep functions small and test early: So you just completed you 2K-LOC function. Great. Now, how are you going to find which parts need testing in it ? It's better to make small functions, and to test those as soon as they are completed in a multitude of way. Just another good general-purpose programming practice, that becomes especially important when you get into OSdeving.
- Write good test suites: If possible, write a test case for every feature you add. When you discover a bug, fix it and add a test case for it to your test suite. Don't forget test cases which should fail.
- Real v Fake Environments: Fake Environments are where you develop the driver. Real Environments are where you test them.
- Multiple test environments: I found it quite useful to have a multitude of test environments for running my kernel. For example, I use several Bochs builds (32 / 64 bit, SMP / UP...), QEMU, AMD SimNow! (SMP / UP), different VirtualBox machines and sometimes even MS VirtualPC. If the code runs fine on most of them but fails on a single one, there must be something going wrong. This way I found quite a lot of problems in my code that were silently ignored by some of these virtual machines.
Sound Advice
- Drivers and Apps: It is stupid to mix your drivers and applications into one file. This is what you do when you're testing, make sure to strip out those codes and to put them in another file when your driver is done. You would severely limit your driver otherwise. Don't even use a printx inside the driver.
- Be Consistent: Always try to do things the same way. e.g. All my for loops look the same: for (i=0; i<n; ++i) etc.
- Driver Dev: I discovered that it was much easier to develop drivers in VGA mode. So, when I developed my GUI, I found that I needed to write a mouse driver (for example) and that doing so was difficult trying to test and debug it in the GUI. So, I stripped out my VBE code and created a complete new environment that was like my GUI environment, except it was much easier to debug code in. And any changes that I made to the kernel would not effect my real project.
- JavaScript: I discovered that it was quicker and much easier to write some of my code in JavaScript first. I'm talking more about the logical parts of my drivers and design. Such as the scroll bar, or my browser window, even something math related. For example, I worked out the logic for both my browser (how it will work with icons and a mouse) and the scroll bar (how it will work when 10 icons are there and how it will work when n amount of icons are there, and what it will do when I drag the track bar or click the up or down arrow buttons, etc) using JavaScript and HTML. And, it honestly made the entire process much quicker since I didn't need to compile my kernel, assemble my loader, wait for the VM to load, wait for the VM to load my loader, wait for my loader to load my kernel, invoke the browser/scroll bar, reboot, and repeat.
- Syntax highlighting: It makes it a lot easier to see what some code does, or to find something in your code, if you use an editor with syntax highlighting. I wouldn't want to miss it.
- Userspace: It's worth writing your userspace in such a way that it can be easily runned on the host OS, where debugging is much easier.
- Anticipate: If something can go wrong, it will go wrong someday. A lost pointer down in the kernel because of unexpected return can be worth years of trying to fix the floating fallout bugs in userspace. "I'll add the code to check for that highly unlikely condition later" attitude guarantees that it won't be added.
- Cornercase design: Do not work from the average case when building a design, but instead work from all the possible extremities. This yields a design which covers everything cleanly, instead of one that uses a bunch hacks to support non-standard cases. Use refactor-first approaches when you find new cornercases for the same reason.
Original Thread
Please visit http://forum.osdev.org/viewtopic.php?f=11&t=22004&start=0 to view the original thread where this all began.