Managed World

Techno-babble from yet another babbler RSS 2.0
# Wednesday, June 20, 2007

The more I work with TxF, the more I realize that our (Microsoft's) coverage of certain KTM topics is sorely lacking. One of those areas is around documentation and samples of managing resource managers (important if you are wanting to investigate programatically the running status of a resource manager).

Sometimes, being an evangelist can be quite fun (or frustrating) because the documentation leaves something to be desired and you can't run to the internet because the only results you get back or to the documentation on MSDN. And of course, since you're on the cutting searching for the control codes online provides you with two results, both pointing back to MSDN. It becomes doubly "interesting" if you are a managed developer because a large number of management-oriented information for KTM is all done through DeviceIoControl (an API that is NOT fun to try to P/Invoke into, especially using certain control codes).

Anyways, that's all beside the point... moving right along.

If you are writing an application to monitor TxF (or even building it into your own application), there are some core "things" that you need to do. One of the first ones (and the one I will cover in this post) is to get a list of transactions in a given resource manager. This is done using the FSCTL_TXFS_LIST_TRANSACTIONS control code.

What structure is DeviceIoControl passing back to us in this instance? A TXFS_LIST_TRANSACTIONS structure. Looking at this structure, we see two fields: NumberOfTransactions and BufferSizeRequired.
That's nice and all, but where is the information about those transactions? The information is stored in a TXFS_LIST_TRANSACTIONS_ENTRY structure.

The trick is that the TXFS_LIST_TRANSACTIONS_ENTRY structure is mentioned nowhere in the documentation for FSCTL_TXFS_LIST_TRANSACTIONS. So how do you get to it? An array of TXFS_LIST_TRANSACTIONS_ENTRY structures are stored in memory after your TXFS_LIST_TRANSACTIONS structure. So assuming you have two running transactions in the given resource manager, you would pass in a pointer to the TXFS_LIST_TRANSACTIONS structure, and here is what the memory would actually look like coming back from DeviceIoControl:

The impact of this is that you need to allocate enough memory for not only your TXFS_LIST_TRANSACTIONS structure, but the array of TXFS_LIST_TRANSACTIONS_ENTRY structures as well. You might notice a little bit of a "chicken and egg" problem here. If I'm using FSCTL_TXFS_LIST_TRANSACTIONS to retrieve the transactions, how could I know how many entry structures to allocate when I don't know how many transactions there are yet?

Well, assuming there are one or more running transactions in the resource manager, you have to call DeviceIoControl with FSCTL_TXFS_LIST_TRANSACTIONS at least twice: once to find out how big of a buffer you need to allocate (read: to calculate how many ENTRY structures to accomodate for), and then another time after allocating the extra memory to have it fill the actual ENTRY structures.

Why do I say "at least" twice? Because, between the time we make our first call and the time we make our second call, more transactions could have appeared and we will have to allocate even more memory. A little bit of a "cat and mouse game," I must say.

If you are a managed developer, this may sound a bit scary. Don't be scared though, it's not too bad (and I know I at least have fun writing this kind of lower-level code :P).

So let's dive right in and look at the code to make this work!

In pseudo-code, this is what we have to do:

------------------------
while (true)
{
     // Deallocate memory from last loop through this

     // Allocate memory for transaction list buffer

     // Call DeviceIoControl with FSCTL_TXFS_LIST_TRANSACTIONS

     // If DeviceIoControl Succeeded

          // Get list of transaction entries after TXFS_LIST_TRANSACTIONS structure
}

// Deallocate any remaining memory
------------------------

Not that bad really. So here it is implemented in native code:

 

    1 #include <windows.h>

    2 #include <tchar.h>

    3 #include <stdio.h>

    4 #include "Winioctl.h"

    5 

    6 int _tmain(int argc, LPTSTR argv)

    7 {

    8     DWORD lastError, bytesReturned;

    9     HANDLE rmDirectory;

   10     TXFS_LIST_TRANSACTIONS *txList = NULL;

   11 

   12     // Get handle to directory where resource manager resides

   13     rmDirectory = CreateFile(TEXT("C:\\"),

   14         GENERIC_READ,

   15         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,

   16         NULL,

   17         OPEN_EXISTING,

   18         FILE_FLAG_BACKUP_SEMANTICS,

   19         NULL);

   20 

   21     if (rmDirectory != INVALID_HANDLE_VALUE)

   22     {

   23         // Get a list of transactions within the given

   24         // resource manager

   25         DWORD neededBufferSize = sizeof(TXFS_LIST_TRANSACTIONS);

   26         while (true)

   27         {

   28             // Deallocate previously allocated memory if we are back

   29             // here after getting back ERROR_MORE_DATA

   30             if (NULL != txList)

   31             {

   32                 delete[] (char*)txList;

   33                 txList = NULL;

   34             }

   35 

   36             // Get the list of running transactions in the RM

   37             txList = (TXFS_LIST_TRANSACTIONS*)new char[neededBufferSize];

   38             if (!DeviceIoControl(rmDirectory,

   39                     FSCTL_TXFS_LIST_TRANSACTIONS,

   40                     NULL,

   41                     0,

   42                     txList,

   43                     neededBufferSize,

   44                     &bytesReturned,

   45                     NULL))

   46             {

   47                 // How did we fail?

   48                 lastError = GetLastError();

   49                 if (lastError == ERROR_MORE_DATA)

   50                 {

   51                     // We need to enlarge the buffer and try again

   52                     neededBufferSize = txList->BufferSizeRequired;

   53                     continue;

   54                 }

   55                 else

   56                 {

   57                     _tprintf(TEXT("Unhandled exception: %u\n"), lastError);

   58                     break;

   59                 }

   60             }

   61             else

   62             {

   63                 _tprintf(TEXT("Transaction Count: %u\n\n"), txList->NumberOfTransactions);

   64 

   65                 // List Tx details

   66                 TXFS_LIST_TRANSACTIONS_ENTRY *txEntry;

   67                 txEntry = (TXFS_LIST_TRANSACTIONS_ENTRY *)((char *)txList + sizeof(TXFS_LIST_TRANSACTIONS));

   68                 for (DWORD i = 0; i < txList->NumberOfTransactions; i++)

   69                 {

   70                     txEntry += i;

   71 

   72                     // Get GUID string

   73                     WCHAR szGuid[40];

   74                     StringFromGUID2(txEntry->TransactionId, (WCHAR *)&szGuid, 40);

   75 

   76                     // Print Tx info

   77                     _tprintf(TEXT("TX %s: %u\n"),

   78                         szGuid,

   79                         txEntry->TransactionState);

   80                 }

   81 

   82                 break;

   83             }

   84         }

   85 

   86         // Any memory left to deallocate?

   87         if (NULL != txList)

   88         {

   89             delete[] (char*)txList;

   90             txList = NULL;

   91         }

   92     }

   93     else

   94     {

   95         _tprintf(TEXT("Unable to get valid handle to Resource Manager\n"));

   96         return 1;

   97     }

   98 

   99     _tprintf(TEXT("\nPress any key to exit...\n"));

  100     getchar();

  101 

  102     return 0;

  103 }

And that's how you do it. It's not the most fun getting in to DeviceIoControl (unless you're a geek like me and enjoying this kind of stuff), but hopefully with this post out there to help it will be easier to find out how to do this since there is a lack of documentation around this area.

In closing, there is some work that needs to be done around making management of kernel-level transactions a lot easier than it is now. In some ways, it is pretty clear that this is still a "1.0" technology. So while you could use the KTM directly for your transaction coordination, I would highly recommend sticking with using DTC for your transaction coordination as it is much more mature from a management perspective (and there are quite a few enhancements with DTC in Vista and Windows Server 2008).

Posted in
 #       Comments [0]
# Friday, June 08, 2007

Well, it's official, again, for now. I just went and canceled my WoW account. With the birth of my first child, I have come to the realization that I don't have enough time for WoW (or, better put, what time I do have should be spent either with my son, or doing a hobby that's creative and produces results I can show off).

What's funny is that I don't miss it in the least bit. At first, I made the decision to stop playing WoW because I simply had to play games where I could pause at a moment's notice to help out with Baby Xander. Then, after several weeks of not playing WoW, I realized I didn't miss it at all and have really enjoyed spending time either with music, or in doing Windows system programming in C (yeah, I'm a geek, I know it).

So, I say farewell to World of Warcraft for the third time in my life. Hopefully this is for good (or until the _next_ expansion pack comes out :P).

P.S. Back to reading my current book, Windows Internals.

Posted in Personal
 #       Comments [4]
# Monday, May 07, 2007

I know, no posts in a while. There's a good reason though: last night, at 10:32pm, my wife gave birth to our beautiful baby son. He weighed 8lbs 13oz, and measured 20.5 inches. The name isn't "official" yet, but we are leaning strongly towards "Alexander Lewis Olson". Needless to say, I'm just soaking it all in and enjoying fatherhood.

Once we are out of the hospital (we wanted a home birth, so long story), I'll write up a longer post with our birth story. It was filled with all sorts of turns and changes, but it ended well, so we are happy :).

And with that, I leave you with some pictures of our beautiful baby boy. Sorry about the size of the pictures, but I'm a bit too pre-occupied to resize them right now :).

Posted in Personal
 #       Comments [15]
# Wednesday, April 25, 2007

Well, it's official. Beta 3 of Windows Server "Longhorn" has launched. With it, I finally get to release some of the work I've been working on lately.

If you are a developer, I encourage to take a look at "The Top Ways To Light Up Your Apps On Windows Server 'Longhorn'" that was just launched today. It outlines key ways that you, the developer, can leverage all the new and improved enhancements to the Server platform to really make your applications shine in a whole new light.

I encourage any of you with access to Beta 3 to try it out. Windows Server "Longhorn" is quickly shaping up to be the best Server release from Microsoft ever.  

 #       Comments [0]
# Thursday, April 19, 2007

Okay, I admit it, I'm a WoW junkie. I spend WAY too much time in WoW, and not enough time doing the things that actually matter. Well, until recently (hopefully the trend continues). I started diving back into XNA again. Only this time, I'm diving back into it from a 3d perspective, not the 2d route I have always gone before. But why the sudden change?

Two months ago or so, I sent out an idea to an internal XNA discussion list at Microsoft that a bunch of us "hobbyists" should get together every other week just to geek out and do some game development after work. People loved the idea, so a bunch of us have been getting together after work to write some code and show each other what we are doing. Perhaps the coolest part is that since we are doing it in the same building where the XNA team is based out of, several XNA team members have dropped by just to check out what's going on.

In fact, at the first get together, Mitch Walker and others dropped by. Mitch had an idea about doing a month-long game development contest. So, that game development contest just concluded last Tuesday night. Oh MAN, were there some AWESOME games that people worked on. Me, being a total and utter dork, did not have anything to show. Truth be told, I had been writing next to NO XNA code, so there was literally _nothing_ to show. However, seeing some of these great games that were done, I figured it was about time to get back into it again. With how supportive this "user group" (of sorts) has turned out, I look forward to actually participating for a change.

So I'm back diving into XNA again. Instead of doing the usual 2d programming that I've always done in XNA, I figured it was about time for me to get involved in the 3d world. The game I'm going to do uses all the art assets from Spacewars and is going to be a vertical-scrolling shooter (like Ikaruga). Tonight, I decided it was about time to start prototyping the controls out and to make sure I could figure out how to display a 3d model (and show it from the top down).

Here's what the Shox Tonera prototype looks like after this evening:

I know that's not the best resolution, but you can at least see the ship (sort of). When you go left or right, the ship "rolls" to that side. When you go forward or backward, the ship "pitches" towards the direction. This is actually quite easy because the ship is technically in 3d. While the screenshot looks like a 2d game, it's actual 3d with the camera up in the air pointed straight down.

Also, you can see that the playing field is just the middle. I got bounding working so that the ship cannot leave the playing area. That was actually not too hard to do (easier than I thought it would be). I'm using the View and Project matrices to "project" the ship's position in the World into the actual screen coordinates. Then I can used the projected screen coordinates to ensure that the ship will not leave the area the playing area contains.

For those that are familiar with the Spacewars starter kit, I am just reusing the art assets from that in my own game. I will continue to do this for as long as possible. It definitely saves time.

The next thing I would like to do is to create the firing action of the ship using Point Sprits for the visuals. Hopefully either tomorrow night or this weekend I will get around to that. I would also like to do some refactoring to clean up the code. Tonight, I just threw it all in the game class for now to see if I could get it working (quite the departure from my usual behavior as any of my friends can attest to). I just need to be very careful not to get too wrapped up in refactoring and architecture like I usually do, because then I won't make _any_ progress on the game.

So why "Shox Tonera" for the name? Because I'm an unoriginal bastard, that's why. "Shox Tonera" is simply the letters from "XNA Shooter" scrambled up. I personally felt it sounded kind of cool too, so if you disagree, I don't want to hear about it :P.

Posted in Game Development | Programming | XNA
 #       Comments [2]
# Wednesday, April 04, 2007

I recently posted the second screencast in my new "Developer, Meet Server" screencast series. This latest screencast covers using Transactional NTFS in a service-oriented environment via WCF.

Enjoy!

 #       Comments [0]

Contact

Email Me Send mail to the author(s)

Calendar

<June 2007>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

About this site

Jason Olson's thoughts on Programming, Games, Music and Life in General

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2008
Jason Olson

Sign In
All Content © 2008, Jason Olson
Theme based on 'Business' created by Christoph De Baene (delarou)