Thursday, July 12, 2018

Minecraft java.lang.OutOfMemoryError

My son tried to launch Minecraft recently.   For some reason it's stopped working and shows java.lang.OutOfMemoryError  when he tries to launch it.  The full error being the following

java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3332) at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:569) at java.lang.StringBuilder.append(StringBuilder.java:190) at com.google.gson.stream.JsonReader.nextQuotedValue(JsonReader.java:1003) at com.google.gson.stream.JsonReader.nextString(JsonReader.java:815) at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:418) at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:406) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) at

The fix:  Clean up Minecraft\installs\options.txt by removing any entries that looked bad.

The explanation:
Searching the internet didn't provide much help other than 'reinstall'.  Rather than risk losing saves, I poked around some of the files and was able to fix it.  I noticed the file Minecraft\installs\options.txt was 300MB.  This seemed a little large for a txt file that was supposed to be options.  Looking through the file there are a bunch of key:value entries.  One of them called 'resourcePacks' had a value that looked like 300MB of garbage.  Looking at Options.txt  said these should be readable names.   Since it was random non-printable characters, I removed the whole 300MB entry.  Minecraft now loads just fine.

Seems Minecraft was choaking on trying to load of 300MB of resourcePack names.  StringBuilder was called to keep appending and ran of of room.  After all a 300MB string is rather large.



Wednesday, May 27, 2015

Common Source Code Directories

I placing this here to keep a list of common source code directories and their uses.  I'll update this periodically


  • src - Compiled source code
  • include - Header files
  • deps - External dependencies, or ".d" dependency files
  • .deps - .d dependency files
  • build - build scripts
  • dist - distribution files.  Final compiled files
  • debug - files compile in debug mode
  • release - files compiled in release mode
  • obj(s) - Compiled object files
  • bin - Binaries, or compiled executable
  • lib - library files (so, a, dll, lib), either external or compiled
  • test(suite) - test suite code
  • externs/ext - External dependencies
  • contrib - external dependencies, or additional code not officially part of the main line
  • patches - patch files to apply to build
  • tools - tools used in build, but not necessarily part of final project
  • doc - documents
  • res - resources

Some source trees include directories for each file type, such as css, js, xml

Saturday, March 21, 2015

How to fix Battle.net App video playback

Blizzard has a Battle.net desktop app for their games.  Its supposed to support video playback, but it
seems its a common bug to lose video playback in the battle.net desktop app.

Instead of a video, just a black window that says "The Adobe Flash Player or an HTML5 supported browser is required for video playback" shows up.

After re-installing my computer I was hit with this bug.  I had a HTML5 supported browser. (chrome), and I tried installed firefox, but this did not fix it. Since battle.net uses CEF (Chromium Embedded Framework), I assumed getting flash for Chrome (PPAPI) would fix it.   I then tried the other versions for Firefox and Internet explorer.  None of these fixed it.

What finally fixed it was this link, that explained to install the version of flash found at
https://get.adobe.com/flashplayer/?fpchrome, I'm not exactly sure what version this is suppsoed to be, because I can't find a link to it on adobes site, but it works.

Friday, August 2, 2013

container_of and offsetof in C++

I'm just putting this here for future reference

Linux uses a macro called container_of in kernel

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({                      \
      const typeof(((type *)0)->member) * __mptr = (ptr);     \
      (type *)((char *)__mptr - offsetof(type, member)); })

BSD has one

#define CONTAINING_RECORD(addr, type, field)    \
      ((type *)((vm_offset_t)(addr) - (vm_offset_t)(&((type *)0)->field)))

and so does windows

#define CONTAINING_RECORD(address, type, field) ((type *)( \
                                              (PCHAR)(address) - \
                                              (ULONG_PTR)(&((type *)0)->field)))

( These were all found at http://stackoverflow.com/questions/8240273/a-portable-way-to-calculate-pointer-to-the-whole-structure-using-pointer-to-a-fi )

I've written the linux version as a C++ template.

template<class P, class M>
size_t offsetof(const M P::*member)
{
    return (size_t) &( reinterpret_cast<P*>(0)->*member);
}

template<class P, class M>
P* container_of(M* ptr, const M P::*member)
{
    return (P*)( (char*)ptr - offsetof(member));
}

This has the added benefit of being able to 'step-into' the function, unlike a macro call.  But this also requires it to be done in C++, and not C.

In C you would call the macro        container_of( pointer, Foo, bar)
In C++ you would call the function container_of( pointer,  &Foo::bar )

Monday, July 15, 2013

Microsoft Visual C memory segments

If you look in a file called Microsoft Visual Studio\VC\crt\src\sect_attribs.h you'll see a list of #pragma's for section attributes.  This is here to define memory segments in your compiled software.   After a little searching on the internet I wasn't able to find a list of what each of this segments were for.  Poking around the rest of the CRT source was able to give me some clues.


#pragma section(".CRTMP$XCA",long,read)
#pragma section(".CRTMP$XCZ",long,read)
#pragma section(".CRTMP$XIA",long,read)
#pragma section(".CRTMP$XIZ",long,read)

#pragma section(".CRTMA$XCA",long,read)
#pragma section(".CRTMA$XCZ",long,read)
#pragma section(".CRTMA$XIA",long,read)
#pragma section(".CRTMA$XIZ",long,read)

#pragma section(".CRTVT$XCA",long,read)
#pragma section(".CRTVT$XCZ",long,read)

These sections are used for initializers of globals when you are building a managed binary.  The $XI are C initializes while the $XC are C++ initializers.   The MP means managed per process, while the MA means managed per app domain.  The VT stands for VTABLE, in other words your virtual method initializers.  I found this all in crt\src\mstartup.cpp.   Something interesting is the C initializers are never called.

#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCC",long,read)
#pragma section(".CRT$XCZ",long,read)
#pragma section(".CRT$XIA",long,read)
#pragma section(".CRT$XIC",long,read)
#pragma section(".CRT$XID",long,read)
#pragma section(".CRT$XIY",long,read)
#pragma section(".CRT$XIZ",long,read)

These sections are used for native initializers. Like before $XI are C while $XC are C++ initializers.  The XCC section is the list of C++ initializers and the XIC are the C initializers.  The XID and XIY seems to be a special sections of C initializers that are to be run after all the C initializers

#pragma section(".CRT$XCAA",long,read)
#pragma section(".CRT$XIAA",long,read)

These sections are for native PRE-initializers.  That is, they are run before the above initializers.

#pragma section(".CRT$XPA",long,read)
#pragma section(".CRT$XPB",long,read)
#pragma section(".CRT$XPX",long,read)
#pragma section(".CRT$XPXA",long,read)
#pragma section(".CRT$XPZ",long,read)
#pragma section(".CRT$XTA",long,read)
#pragma section(".CRT$XTB",long,read)
#pragma section(".CRT$XTX",long,read)
#pragma section(".CRT$XTZ",long,read)

These are C terminators (read destructors), that get called on exit.  $XP are pre-terminators, and $XT are normal terminators.

#pragma section(".CRT$XDA",long,read)
#pragma section(".CRT$XDC",long,read)
#pragma section(".CRT$XDL",long,read)
#pragma section(".CRT$XDU",long,read)
#pragma section(".CRT$XDZ",long,read)

These are used for Thread Local Storage dynamic initializers.  You can find a detailed explanation in crt\src\tlsdyn.c.

#pragma section(".CRT$XLA",long,read)
#pragma section(".CRT$XLC",long,read)
#pragma section(".CRT$XLD",long,read)
#pragma section(".CRT$XLZ",long,read)

These seem to be for bootstrapping for Thread Local Storage.  From a comment in src\crt\tlssup.c
/* Start section for TLS callback array examined by the OS loader code.
 * If dynamic TLS initialization is used, then a pointer to __dyn_tls_init
 * will be placed in .CRT$XLC by inclusion of tlsdyn.obj.  This will cause
 * the .CRT$XD? array of individual TLS variable initialization callbacks
 * to be walked.
 */
If I understand this correctly, it means that if you have Thread Local Storage enabled, a pointer to __dyn_tls_init will be placed in .CRT$XLC, which should cause it to be called and your TLS to be initialized as needed.  The XLD points to _dyn_tls_dtor, which calls the destructors for Thread Local Storage.

For an explanation on what these sections are used for read this blog

Tuesday, July 3, 2012

Floating point accuracy

Here are two pieces of code that do that same thing, but produce different results

This one doesn't work


            double majorTickStart = majorStep * Math.Floor(min / majorStep);
            double majorTickEnd = majorStep * Math.Floor(max / majorStep);
            for (double x = majorTickStart; x <= majorTickEnd; x += majorStep)
            {
                Point p1 = new Point((x - min) * scale, 0);
                Point p2 = new Point((x - min) * scale, 16);
                drawingContext.DrawLine(majorTickPen, p1, p2);
            }


This one does work


            double majorTickStart = majorStep * Math.Floor(min / majorStep);
            double majorTickEnd = majorStep * Math.Floor(max / majorStep);
            double majorSteps = (majorTickEnd - majorTickStart);
            for (double x = 0; x <= majorSteps; x += majorStep)
            {
                double _x = (x + (majorTickStart - min)) * scale;
                Point p1 = new Point(_x, 0);
                Point p2 = new Point(_x, 16);
                drawingContext.DrawLine(majorTickPen, p1, p2);
            }


If you look closely that math turns out to be the same on both of them.  What this is meant to do is draw the tick marks you would see on a graph along the axis.   The first two lines compute the offsets of where to start and stop drawing tick marks, since the beginning value, "min", doesn't necessarily start on a boundary.   Next the for loop will iterate between those two values with a step size of, "majorStep".  This would normally be a power of 10.  
The problem the happens is the first set of code turns into an infinite loop under certain conditions.  If "majorsStep" is small compared to the start and end values, x will never increase.  "small" means that there is more than 52bits of precision between the two of them.  In other words a factor of more that 4503599627370496.   This has to do with how a computer stores an IEEE754 (64 bit double) number.  It stores it using 1 bit sign, 11bit exponent , and 52bit fractional.   To get the number it represents 2 raise to the power of the exponent times the fractional bits.   Stated another way the exponent is the number of bits that are ignored.  If it takes more than 52 bits to represent the number, you will lose the lower E bits of accuracy.    Adding 1 to your 53 bit number will result in the lowest bit being ignore, and this the 1 turns into a 0.

How do you fix this?  Make sure you do all your math with numbers that are close to each other.  The second one works because we start "x" at 0 and add the small value of "majorStep" to it.  We also subtract "min" from "majorTickStart" to get a small value before we add it to x, which will also be small.  If we tried to add "x" to "majorTickStart" and then subtract "min" we would end up with just "majorTickStart - min", because the value in x would be ignored.

Sunday, June 24, 2012

CableCards and Tuning Adapters

I've been using my Ceton turner card for a while now and its been pretty nice.  Being able to DVR multiple shows and once is very nice.  The only problem I've had so far, is that some channels will not tune some times.

tl;dr - Tuning adapters case 99% of the problems

I wake up in the morning with a notice that it wasn't able to record my sons cartoon because the channel couldn't be found.  To Cetons credit it is NOT their fault.  Its actually Time Warner's fault.  They use SDV (switch digital video) on a lot of their channels.  To receive SDV channels Time Warner gives you a "tuning adapter".  Its a small box that plugs into your computer through USB and your cable line.  The computer queries the tuner adapter for the frequency of a given channel and the tuning adapter does it magic and tells the computer where it can find the channel.  The problem is these adapters seem to have MANY, MANY problems.  Some times they don'y sync up to the cable company and suddenly you can not use half of your channels.


Raspberry Pi

After many months I got my Raspberry Pi in the mail.  Even though I've seen many pictures of it, it still looks much smaller than I thought.  If you don't know what a Raspberry Pi is, its a tiny computer about the size of a deck of cards.   Its just the board through, no fancy case.  It also has a bunch of extra pins on it so you can do some I/O, like reading switches and setting LEDs.  You also need to supply your own power supply and memory card.

I used my USB phone charger cable to power it.  I've read some phone cables don't work, but this one seems to work, so far.  I copied the Debian image from the Raspberry Pi website on to the memory card and booted up with no problem.  Next I looked for something interesting to try out.  I found this post about streaming Pandora music.  I followed it and was able to connect to Pandora, but the music would stop after a second or two.  Turns out there was a bug in the ALSA (sound) drivers.   If you background the task (Ctrl-Z) and then foreground it again (fg), it would play for a few more seconds.  I next tried the beta Debian image on the Raspberry Pi website, since it was newer.  It still had the problem.  After a a little google search I found this.  Apparently they just fixed the driver a few days ago.  To update the firmware I used Hexxah's raspi-update tool.  Just had to run it and reboot when it finishes.  I tried pianobar and it work that time.

Next was the GPIO pins.  They are perfectly spaced out for an old ribbon cable.  I first tried and IDE cable but realized it was one of the UMA 66 with extra conductors in it.  Rather than chance anything funny with that cable I found an old floppy drive cable.  It fits over the pins with the last 4 rows sticking out.  I then wired an old bread board I had to an LED and switch using this diagram.  I next used the RPi.GPIO library and wrote a script to toggle the LED on the switch.  The LED was a little dim the for the first test, so I swapped the resistor for a smaller one and its much brighter now.

Something of note, I had used the wrong pin diagram incorrectly wired the wrong GPIO to the switch, and the Pi instantly turned off.  Thought I had blown something, but after only minute of being off it came back up fine.  Another thing to know is the GPIO to turn a LED on is TRUE and FALSE to turn it off, while reading a switch is TRUE when its open and FALSE when its closed.

If any cares I can post pictures.

Friday, April 13, 2012

Old server is gone

I used to have a CoLocated server.  Its no longer co-located anywhere with internet, so its doing me no good.  It used to run my blog, but I have since switch over to here.  One of the popular posts on it was about my old Acer laptop having a WHITE SCREEN OF DEATH.  Basically the computer would only show a White screen when you powered it on.

The solution is to open the panel on the top right side above the keyboard.  This is where the LCD screen connects to the mother board.  The ribbon cable is only held in with some tape and can easily become loose.  When it does, the screen will go white.   Just push the connection all the way back on and secure it with something better.  I used some blue painter tape.  Some people have noticed the round toroid on the ribbon cable.  This is supposed to be there.  It is to filter the signal LCD screen.  Do not remove it. 

4 HD Tuners

Months ago I bought a ceton 4 tuner HD card.  Its been sitting in my computer picking up over the air HD channels.  Though nice, it wasn't using the full potential of the card.  I finally call the cable company to get someone out to install a CableCard and Network tuner.  Technically, they are required to let me do this for free, but insisted  on sending someone out and charger us for it.  Mainly because they have issues with CableCards not working the first time.

The CableCard worked the first time and I was able to pick up cable channels on the card.  A small issue happened when tried to watch the HD channels.  Seems all the HD channels use SDV (switched digital video). To watch SDV channels, you need a tuner adapter.  Because there are so many cable channels now, they can't send them all down the pipe at the same time.  The tuning adapter is an extra box that connects via USB to the computer.  The computer tells it which channel you want to watch and it reports back what frequency that channel will show up on.  

The tuner adapter did not connect to the computer the first day, or the second.  I opened a ticket with Ceton about it, they were quick to respond and had me send a few diagnostic logs.  Then, a few days later it just started working on its own.  Might have had to do with the fact the computer finally auto installed SP1 on it.

Now that its working correctly, I have to say its pretty nice.  I'm able to watch 1 channel and record 3 others at the same time.  I can even share the tuners over the network so other computers can watch tv too.

Some things I'm sad about.  Media Center will not allow you to watch 2 channels at the same time, ala Picture in Picture.  The hard drive in the computer is TOO small.  I used an old 80gb laptop one I had laying around.  This is not even close to what you need when recording HD video.

Monday, October 3, 2011

Classes and DLLs

DLLs are libraries with named functions in them. Usually the names are human readable. C++ has this thing in it call named mangling.  This is to allow for overloaded functions and other things.  When you build a C++ DLL, all the functions will be exported as their mangled names.  Every compiler mangles differently.  This isn't a problem if you use the LIB file, because the compiler will automatically link to the correct mangled name in the DLL.  This requires that you be statically linked to the DLL, and that it be compiled with the same compiler.  If you want to load DLLs at runtime using LoadLibrary, you will need to know the mangled name for use with GetProcAddress.  So all this gets complicated really fast.

There is a simple way around this using a factory method.  Take for example DirectX.   You call Direct3DCreate9 to get pointer to a IDirect3D9 object.  Instead of calling "new Direct3D9()", you call the factory method.  Instead of calling "delete obj" you call Release.

To do this, you have to follow a few rules.   You must use the factory method to create, and use the release method delete.  This is to keep the memory allocator happy.

You can expand on the factory method by passing in an argument to select the type of object to return.
MyObject* obj = (MyObject*) CreateObject( MY_OBJECT_TYPE );

CreateObject figgures out the correct object to create/return based on the supplied argument.  The supplied argument could be an enum if you are returning a fix number of known object types.   You could alternatively pass in a string to match against and build a look up table to match against.

hmod = LoadLibrary("some.dll");
Fn CreateObject = (void* (*(char*)) )GetProcAddress( hmod, "CreateObject");
CreateObject("MyObject);

Monday, September 26, 2011

New DVR

Ordered a Centon Infinitv. For those who don't know, its a PCIe card for your computer that allows you to record up to 4 digital (HD) cable channels. So now I can set up to 4 shows to DVR at once. Only needed to run the setup and restart the computer. Windows Media Center picked it up right away as 4 tuners. The longest part was waiting for all the channels to be found.

One feature that is really cool is being able to use the extra tuners on other PC's on the network. Ceton refers to this as 'network tuners'. Requires you to install software on both computers and to have a fairly fast network. I tried it over 54mb wireless. The software warns against this but I tried anyways. It worked, but saturated my wireless. Using a full 100mbit or gigabit would probably work just fine.

The only problem with digital cable is you need a M-Card from the cable company. This requires a service tech to come out to install/activate one. As far as I can tell, they are required to come out because you aren't guaranteeing a card will work the first time. I still need to schedule that, since summer seems to be the busiest time, its hard to get one to come out

Friday, August 26, 2011

"Shims" in C++/CLI

I saw this post about writing a plugin DLL for the Optimus Mini Three. The DLL needs to be written in C++ but what if you wanted to write it in .NET (ie C#). C# doesnt allow you to directly write normal DLLs that C++ can call into. Instead you need what is called a "shim". A little piece of glue code.

Here is some example glue code to create a plugin for the Mini Three

#define WIN32_LEAN_AND_MEAN  
#include "windows.h"  
#include "OptPlugin.h" 
 #include <vcclr.h>
template<typename T>
 class Shim : public OptimusMiniPlugin {
 	gcroot obj; 
public: 	
Shim(int f) { obj = gcnew T(f);	}
virtual BOOL __stdcall Paint(HDC hdc){ return obj->Paint( IntPtr(hdc) );} 
virtual void __stdcall OnKeyDown(){ obj->OnKeyDown();} 
virtual LPARAM __stdcall GetInfo(int index) { 
#ifdef _WIN64
  return obj->GetInfo(index).ToInt64();
#else
  return obj->GetInfo(index).ToInt32();
#endif
  } 
};   
PLUGIN_EXPORT(Shim)

"Shim" is a C++ class while SomeDotNetClass is a managed class. PLUGIN_EXPORT is the provided macro from Optimus to create the plugin exports. The key to this is the gcroot. It allows you to reference a managed object from the non-managed class. You then just forward call your calls to the managed class. Create your managed class in a C# assembly and reference it from the C++ dll.

Thursday, August 25, 2011

Macros in C#

Macros are a wonder feature found in C++. It allows you to write a template of sorts and use throughout. I bet you didn't know C# allows for templates too.

There is a wonderful template library built in to visual studio called T4. Just add a new file to your project and change the extension to ".tt"



<#@ template language="C#" #>
// This code was generated by a tool.
// Any changes made manually will be lost
// the next time this code is regenerated.
using System;

public class <#= this.ClassName #>
{
 public static void SayHello()
 {
 Console.WriteLine(”Hello World”);
 }
}
<#+
string ClassName = "MyClass";
#>

When you compile this will make a ".cs" file of the same name automatically. These templates are much more powerful than C macros. You have full access to any assemblies in the GAC (for example XML, Networking, and IO).

Tuesday, March 15, 2011

Realtime translation with jquery

For those who might be trying to follow the news in japan on ustream, you might notice all the comments are in Japanese. Here is some javascript to translate real time


var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'http://code.jquery.com/jquery-1.5.1.min.js';
head.appendChild(script);

var script2= document.createElement('script');
script2.type= 'text/javascript';
script2.src= 'http://jquery-translate.googlecode.com/files/jquery.translate-1.4.7-debug-all.js';
head.appendChild(script2);

tr = function(){
$('iframe').contents().find('*[data-template="ssMessageItem"]').translate('jp','en');
setTimeout("tr()", 100);
}
tr();




If you care what it does. It loads up jQuery, then loads up a jQuery plugin to do google translation. Sets up a timer to translate all the elements that look like messages '*[data-template="ssMessageItem"]' from jp to en.

Saturday, February 19, 2011

down casting unknown types

In C++ you have classes. Classes are objects that can be based off of other classes. Casting between class types is usually done by.

Foo* f = new Foo()
Bar *b = (Bar*)f;

The problem with this is its not safe. If Bar is not a base class of Foo then b is invalid and will do who knows what. There is a second possible problem too. If Foo has multiple base classes, say Bar and Baz, the cast might not work either. This depends on how the class was declared

class Foo : public Bar, public Baz

or

class Foo : public Baz, public Bar

If it was the first one, the code would have been okay. If it was the second then we just tried to cast a pointer to Baz into a pointer to Bar, which isn't okay. Casting to a base type is called down casting. How do you safely cast into Bar?

Welcome our good friend dynamic_cast. dynamic_cast knows how the classes were declared and will correct cast for you. It'll shift pointers around and return the right thing. And in case you tried to cast to something that is impossible, it returns a null. The one thing dynamic_cast wont do is cast from a void*. This is known as up casting, or casting from a base class to a derived class.

void* v = new Foo();
Bar* b = (Bar*)new Foo();
Foo* x = dynamic_cast(v); // returns null
Foo* y = dynamic_cast(b); // returns Foo*

There is no path to Bar from void, so dynamic_cast wont work here. Using void* as a generic pointer is pretty common, but unfortunately you can't dynamic_cast from it. What you need to do is create a common base class for everything to share. Lets call it Object

class Object{};

class Bar : public Object
{ };
class Baz : public Object
{ };
class Foo : public Bar, public Baz
{};

Now everything shares a common base class called Object. The problem is Foo has 2 Object base classes, one for Bar and one for Baz. If you drew out the memory, it might look something like this.

Foo
+-----
|Object
|Bar
+-----
+-----
| Object
| Baz
+-----

Now, if you tried to cast Foo to Object, which Object should it point to, the one in Bar or the one in Baz. Using a normal (Object*)new Foo() would get you the Object from bar. Using dynamic_cast would result in a compile warning of C4540 (dynamic_cast used to convert to inaccessible or ambiguous base) and it would return null. You can fix this by using a virtual base class.


class Object{};

class Bar : virtual public Object
{ };
class Baz : virtual public Object
{ };
class Foo : public Bar, public Baz
{};

Notice the "virtual public Object". This tells the compiler to only make one Object for Foo, and have Bar and Baz share it. Now dynamic_cast will be able to cast from Object to Foo and vise-versa. Now you can use Object* instead of void* as your generic pointer. This will allow you to dynamic_cast up and down all you want. The one thing you can't use this for is for primitives like int, char, float. But you can't derive anything from that anyway so it shouldn't matter.

One idea, you can use these for a Service Registry. Just make all your services have a virtual base class of IService.

class ServiceRegistry
{
public:
void Add(char* name, IService *i);
IService Find(char* name);
}

// cast to IService to add
reg->Add("my_service", dynamic_cast(my_service) );
// cast from IService to get
MyService* find = dynamic_cast( reg->Find("my_service") );


Thursday, February 3, 2011

Zombies from Microsoft

Apparently there is a bug in windows that causes Zombie Console windows.


Whats a zombie window? Its a window with no process. Every window should have a process associated with it. When that process closes, so should its window. But if the process closes some how without ever closing the window, it turns into a Zombie window.

Zombie windows are bad because they can't be closed and they prevent you from shutting down, and logging out of windows. Windows gets stuck trying to close them.

I have never seen a solution on how to get rid of them, so I came up with my own. I call it Zombie Killer.

What it does is list all your windows and lets you select one to close. You just need to double click the window in the list and it will be handled.


Wednesday, September 15, 2010

HDR in DirectX

HDR in DirectX isn't as simple as they make it out to be. What is HDR? HDR or high dynamic range is images with more than 256 colors (8bits) per channel (red.green,blue). Formats with 16, or 32 bits per channel are common. DirectX will even support a floating point number per channel, for a very large range of values.

So the obvious thing when working with HDR is that you cant render directly to your screen. Your screen only has 8bits per channel. DirectX allows you to render to an off screen buffer called a render target. Using a render target you can render in any format your gpu supports.

After you tell the GPU to use a render target you should be able to what ever you want in HDR right? Unfortunately this is not the experience I had. I set up my render target and drew a image and what I got back out was only an 8bit image. It didn't matter what format the render target was in, or what I drew for an image, it was always rendering to 8bits.

Turns out you need to also use a pixel shader. You need nothing more than:

texld r1, t0, s0
mov oC0, r1

All this does it get the value of the pixel in the texture and return it. This should be exactly what is happening by default without a pixel shader, but it doesn't seem to be. Using these 2 lines of pixel shader suddenly I was getting more than 8bits out.

Not sure why it works this way, maybe someone knows more than I do?

Monday, May 31, 2010

C++ gotchas

I was testing the timing of some code the other day. To make test easy to exit I used _kbhit(). This way hitting any key would exit the test. The problem is _kbhit() takes a LONG time.

while(!_kbhit())
{
do_something()
}

The problem here is that do_something was the method I needed to test, but _kbhit was adding a lot of extra time to each call and I was not meeting my timing. Spent a few hours trying to improve the do_something code just to find out all I had to do was call _kbhit less often.


Another gotcha is .LIB files. .LIB are like DLLs except they are compiled into the EXE file. That way you don't need to have lots of dlls with the program. The problem with lib files is they need to be build the exact same way your program is built. DLLs run in their own little memory space, while LIB share the memory space with your EXE. If you program uses Foo-v2.dll while the LIB file was compiled to use Foo-v1.dll you'll have a conflict. This shows up when the LIB file is compiled for RELEASE, and your EXE is compiled for debug. If the lib tries to allocate memory, it will use the release version of the C-library and allocate on its heap. You're program will use the debug version of the C-library and allocate on its heap. Now you have memory allocated on two different heaps. When the program closes, C will check all the memory to ensure their wasn't any memory leaks or what not. This is a great feature if you are in debug mode. When its checking the memory, it is expecting everything to be on the 'debug heap'. It will find memory allocated from the LIB file on the 'release heap' and throw a big warning about a possible memory leak because it found memory outside of where it should have been. Moral of the story is build your LIB files with the same memory model and linked libraries as you will build your EXE. If you are giving the LIB to someone else give them a debug and release version and make sure all the other linked libraries are the same.

Saturday, March 27, 2010

NFS in windows over putty

Setting up a NFS share in windows is simple. First you need a NFS client. Windows 7 ultimate comes with a client. Programs and Features -> Turn Windows features on or off -> Services for NFS (install all of it). Other versions of windows can use Window Services for UNIX. The nfs share needs to be setup for "insecure" ports. This means ports above 1024. To do this add 'insecure' to the list of options in /etc/exports. Once you have a NFS setup on the linux box you can mount it in windows using

mount server:/path/to/share x:

This works if you do not have a firewall between you and the server. If you do you need to tunnel some ports. You need to tunnel portmapper, mountd, and nfs. On the linux server run

rpcinfo -p | grep tcp

you should see something like

100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100000 2 tcp 111 portmapper
100011 1 tcp 875 rquotad
100011 2 tcp 875 rquotad
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100021 1 tcp 1047 nlockmgr
100021 3 tcp 1047 nlockmgr
100021 4 tcp 1047 nlockmgr
100005 1 tcp 21050 mountd
100005 2 tcp 21050 mountd
100005 3 tcp 21050 mountd


This shows portmapper running on port 111, nfs on port 2049, and mountd on port 21050. Mountd runs on a random port so you may see a different number. If you want to tell mountd to run on a specific port, in fedora edit /etc/sysconfig/nfs. Restart NFS after editing the file.

In putty you want to tunnel ports 111, 2049, and 21050 (or whatever you set mountd up with). To do this goto settings -> Connection -> Tunnels

Source port: 2049, Desitnation: 127.0.0.1:2049 click Add. Repeat this for ports 111 and 21050.

Now when you mount the server used 127.0.0.1 for the server address. For example

mount 127.0.0.1/path/to/share x:

One thing you might notice is you connect as uid -2. This is the default value for an unknown user. You can change this in the registry.

HKLM\software\microsoft\clientfornfs\currentversion\default

add a DWORD called AnonymousGid, and AnonymousUid. Set it to any uid you like. Reboot and when you connect it will be as that user.