Here’s a great interview with Microsoft Technical Fellow and author of the CLR garbage collector, Patrick Dussud.

How does GC, work, generally? Why is it important? The GC inside of the CLR is of a specfic type – ephemeral, concurrent (the server version has always been concuurent and now with Background GC on the client in CLR 4, GC is concurrent on the client as well, but there are differences…)

Tagged with:  

Live555: Compiling with VS2008

On May 14, 2011, in Code Monkey, by Tom

Compiling Live555 Streaming Media with Visual Studio 2008 isn’t obvious. Using Cygwin or MinGW is just a pain and frankly unnecessary. There is no built-in support for VS solution files, because Windows support is a low priority for the Live555 community. This is evidenced by this forum response from Ross Finlayson:

>4. Is it possible to include a Visual Studio solution in the
>distrubution to make it more convenient for Windows developers to
>use live555?
>5. Is it possible for live555 to generate adequate makefiles for
>Windows systems with development environments newer than Visual
>Studio 2003?

I have no current plans to change this. (These days, fewer and fewer people seem to be using Windows for development of system software.)

Regardless, Live555 works fine on Windows and is actually quite easy to build. Simply do the following:

  1. Open the ‘win32config’ file and change the TOOLS32=... variable to your VS2008 install directory. For me, it’s TOOLS32=C:\Program Files\Microsoft Visual Studio 9.0\VC
  2. In ‘win32config’, modify the LINK_OPTS_0=... line from msvcirt.lib to msvcrt.lib. This fixes the link error:
    LINK : fatal error LNK1181: cannot open input file 'msvcirt.lib'
  3. Open the Visual Studio command prompt.
  4. From the ‘live’ source directory, run genWindowsMakefiles
  5. Now you’re ready to build. Simply run the following commands:
    cd liveMedia
    nmake /B -f liveMedia.mak
    cd ..\groupsock
    nmake /B -f groupsock.mak
    cd ..\UsageEnvironment
    nmake /B -f UsageEnvironment.mak
    cd ..\BasicUsageEnvironment
    nmake /B -f BasicUsageEnvironment.mak
    cd ..\testProgs
    nmake /B -f testProgs.mak
    cd ..\mediaServer
    nmake /B -f mediaServer.mak

That’s it. You should be good to go.

Tagged with:  

Rendering Video with GDI (Example)

On April 20, 2011, in Code Monkey, by Tom

In this post, I outline a basic GDI video window class. GDI is inefficient for rendering video, but it’s also very convinient when writing simple tools on Windows. I find myself doing it often enough that it makes sense to do a brain-dump here. This is only an outline, but it should get you over the biggest hurdles.

Outline

  1. Video Window Class Definition
  2. Creating and Destroying the Window
  3. The Window Thread
  4. The Message Pump
  5. Rendering a Video Frame

Things to note:

  • You will need a thread in your window class to “pump” window events.
  • GDI does NOT do any color conversion, so you will need to convert each frame into the same format as the display (always RGB, usually 24 or 32 bits).

Video Window Class Definition

class VideoWindow
{
public:
    ...
private:
    static DWORD _ThreadMain(void*);
    static LRESULT WINAPI _MsgProc(HWND, UINT, WPARAM, LPARAM);

    CRITICAL_SECTION _lok;
    HANDLE _thread;
    HWND _hWnd;
    HDC _hDC;
    HDC _hFrameDC;
    HFONT _hFont;
    int _bpp;   // bit depth
    volatile bool _exit;
    int _x, _y, _w, _h; // Window dimensions
    int _imgWidth, _imgHeight, _imgLength; // Frame dimensions
    unsigned char *_imgBits;
};

Creating and Destroying the Window

void VideoWindow::Create(int x, int y, int w, int h)
{
    EnterCriticalSection(&_lok);
    _x = x;
    _y = y;
    _w = w;
    _h = h;
    _hWnd = 0;
    _exit = false;
    _thread = CreateThread( NULL, NULL, (LPTHREAD_START_ROUTINE)_ThreadMain,
        this, NULL, 0 );
    LeaveCriticalSection(&_lok);

    // Wait for window to be created. Cheap, but it works.
    while (!_hWnd) {
        ::Sleep(100);
    }
}
 

Continue reading »

Tagged with:  

The C99 spec requires that math.h should define the constant float value NAN. However, NAN isn’t defined in the Visual Studio version of math.h, so you have to define it yourself (VS only implements C89). It’s pretty straight-forward for 32-bit machines… here’s my implementation with cross-platform protection:

#ifdef WIN32
    #ifndef NAN
        static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
        #define NAN (*(const float *) __nan)
    #endif
#endif

This code is adapted from an MSDN example.

Tagged with:  

Cross-Platform IPv6 Socket Programming

On February 28, 2011, in Code Monkey, by Tom

IPv6 NetworkingWriting code that works on Windows, Linux, and Mac is frequently challenging. Socket programming is no exception. Modern versions of Linux and Mac have full implementations of the latest IPv6 socket API extensions defined in RFC 3493. Windows, however, has only a partial implementation of the original (deprecated) version, RFC 2553. This sounds worse than it is, but it’s something you have to consider.

Note: This post assumes you are already familiar with the socket extensions for IPv6 (RFC 3493).

Linux and Mac
Good news… they both fully support RFC 3493.

Windows
Windows IPv6 support varies based on which version you’re targeting. Microsoft started adding IPv6 in Windows 2000, and they’ve continued adding more of the socket extensions as time went on. Most of the core functionality is present in XP, and what’s missing is easily replaced by using Winsock calls directly (more on this later).

Windows gained IPv6 support while RFC 2553 was still the supported standard. Since then, it has been deprecated by RFC 3493. However, Microsoft doesn’t want to break existing code written against it’s API, so the older API lives on. The main impact of this is that sockaddr_in6 and sockaddr_storage are slightly different on Windows than Mac and Linux. The size of the structures across platforms is the same (the sa_family_t member was shortened), it’s just that the Windows structures don’t begin with the length member. For example:

// Linux and Mac
struct sockaddr_in6 {
    uint8_t      sin6_len;    /* Added in RFC 3493 */
    sa_family_t  sin6_family;
    ...
};
struct sockaddr_storage {
    uint8_t      ss_len;      /* Added in RFC 3493 */
    sa_family_t  ss_family;
    ...
};

// Windows
struct sockaddr_in6 {
    sa_family_t  sin6_family;
    ...
};
struct sockaddr_storage {
    sa_family_t  ss_family;
    ...
};

I’ve never had a problem with this, because the size of sockaddr_in6 is easily determined (sizeof(sockaddr_in6)) and I always end up casting sockaddr_storage to the specific type (sockaddr_in or sockaddr_in6) based on ss_family.

Besides the data structure differences, it’s important to remember that Microsoft added IPv6 support over multiple versions. Support first appeared in Windows 2000, but more of the extensions have been added over time. Most of the core functionality was present in XP (including multicast), but not everything is implemented as of Windows 7. It’s annoying, but I will say that what’s missing is easily replaced by using Winsock calls directly.

Here’s the breakdown of IPv6 socket extensions by Windows version:

Socket Extension 2K XP Vista 7 Comments
if_indextoname() x x GetAdaptersAddresses() for XP
if_nametoindex() x x GetAdaptersAddresses() for XP
if_nameindex() GetAdaptersAddresses() (XP, later)
if_freenameindex()
getaddrinfo() x x x x
getnameinfo() x x x x
freeaddrinfo() x x x x
gai_strerror() x x x x
inet_pton() x x WSAStringToAddress() (2000, XP)
inet_ntop() x x WSAAddressToString() (2000, XP)
All IN6_IS_ADDR_* macros x x x Ex: IN6_IS_ADDR_LOOPBACK()
struct sockaddr_storage x x x
Multicast support x x x

As you can see, you may still have to call Winsock directly depending on what version of Windows you are targeting. In my opinion, programming IPv6 on Windows is a lot easier if you only support XP and later, but I know that’s not always possible.

Summary

Modern operating systems all support IPv6. However, for business reasons, Windows has a slightly older version of the socket API which requires special consideration. My goal was to enumerate those differences to help make the transition to IPv6 smoother. Writing cross-platform code can be a fun challenge at times, but it’s also a little tedious. Hopefully, this post helps ease the pain.

Tagged with:  

CPU Profiling on Windows: Very Sleepy

On December 21, 2010, in Code Monkey, by Tom

A colleague of mine found a pretty cool profiling tool for Windows called Very Sleepy. It’s simple, straight-forward, free, and it works… everything I like in a tool (this is why I like the Sysinternals stuff so much). It’s also got call-graph and 64-bit support. Definitely worth checking out.

Very Sleep Screen Shot

Tagged with:  

Melting ClockHigh-performance timing is hard… no doubt about it. I can’t tell you how many times I’ve seen high-performance timing code done wrong. Timing is one of those things where a little knowledge can be problematic; the code may work, but it either won’t perform or will exhibit “unexplained” behavior. The purpose of this post is to explain a foundational component to getting timing right: the clock. I won’t focus on theory… this post is meant to be pragmatic.

Note: I’m talking here about interval timing (i.e. accurately measuring the duration between 2 events). This is different than synchronizing different clocks or maintaining accurate wall time.

Anatomy of the Clock

The first mistake most people make when doing timing is to use functions like gettimeofday(), GetSystemTime(), etc. These functions return what is called “wall time”… time that corresponds to a calendar date/time. These clocks suffer from the follow limitations:

  1. They have a low resolution: “High-performance” timing, by my definition, requires clock resolutions into the microseconds or better.
  2. They can jump forwards and backwards in time: Computer clocks all tick at slightly different rates, which causes the time to drift. Most systems have NTP enabled which periodically adjusts the system clock to keep them in sync with “actual” time. The adjustment can cause the clock to suddenly jump forward (artificially inflating your timing numbers) or jump backwards (causing your timing calculations to go negative or hugely positive).

For interval timing, all that’s needed for a clock is a simple counter that increments at a stable rate. For high-performance timing, the rate this counter increments should be high. A related constraint is that the counter must be monotonic (can never “tick” backwards… ever). The counter may overflow and wrap back to 0, but using unsigned math in your timing calculations can compensate for that (see example below).

Something to note: since we are usually measuring short durations, the drift of the clock is so small that we aren’t concerned by it (what matters is the drift between successive reads, not total drift over time).

Continue reading »

Tagged with:  

Software BugWe got an interesting application crash yesterday with a confusing message similar to this:

Fault bucket 42424242, type 1
Event Name: APPCRASH
Response: None
Cab Id: 0

Problem signature:
P1: MyApp.exe
P2: 1.42.42.42
P3: 598773cf
P4: StackHash_ac62
P5: 0.0.0.0
P6: 00000000
P7: c0000007
P8: 00000000
P9:
P10:

We spent some time wondering if our crypto libraries were the problem (we just made some changes recently), but concluded that was unlikely. So what the heck is the “StackHash” module? Did our trashed stack cause the kernel to think we were a different module? Nope.

The answer is that the Windows executive couldn’t identify the module we were in when the application crashed (it uses the instruction pointer to determine what code was executing). In this case, the kernel simply takes a hash of the stack so at least we might be able to identify if we’ve seen this exact crash before. Here’s the answer summarized by an engineer from Microsoft:

In the OS when I try to get a faulting module name it is possible that there is no module laoded (sic) at that address. For example in this case the EIP was zero. So in those cases where a module is not loaded and it is not also in the unloaded module list, I take a stack hash of the stack so that we can identify this crash from other crashes where also the module is not known.

Tagged with:  

I’ve been jealous of Rob’s screensaver for awhile now. I thought it was Mac only until I asked him about it… nope. I installed the Windows version today. What a beautiful piece of art! The creator, Jesson Yip, describes it like this:

Analogy is a typographic clock which fuses the immediacy of digital with the visual-spatial quality of analogue into a hybrid format. It presents an everyday object with a fresh twist.

Click on the image below to visit his site and download it. Enjoy!

Analogy Screensaver

Tagged with:  

ACE LogoThe Windows development environment provided by VisualStudio has some neat tools for detecting memory leaks in code. You simply #define _CRTDBG_MAP_ALLOC before including your headers, and #include <crtdbg.h> as the last header:

#define _CRTDBG_MAP_ALLOC
// Include other header files here
#include <crtdbg.h>

Then, you call _CrtDumpMemoryLeaks() before your application exits. If your program exits at many points, you can alternatively call _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ) at the beginning of you application, which will cause the leaks to also be printed when it exits. The results are printed to the Debug Window and look like the following:

Detected memory leaks!
Dumping objects ->
C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) :
{18} normal block at 0x00780E80, 64 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Cool, Huh?! However, some libraries don’t play nice with this, as I explain below.

Continue reading »

Tagged with: