Adium 1.3.3 is Out

February 20th, 2009

Adium.jpg

I learned that Adium 1.3.3 was out this morning, but oddly enough, the built-in updater wasn't able to update from 1.3.2 to 1.3.3. I'm not sure if this is a server-side issue with the upgrade package, or that the Sparkle updater wasn't working in the 1.3.2 release. Not sure, but I have 1.3.3 now, and it's got a bunch of updates.

It's interesting that it's got Facebook connectivity, as we've been going through a bit of that at the house these days. I'll be interesting to see how that integrates. Should be fun.

Did a Little Work on CorePlot Test Cases

February 19th, 2009

CorePlot.jpg

I'm trying to see how an Open Source plotting package for Cocoa on Mac OS X goes. It started a few weeks ago, and I think it's the right thing to do as it's the kind of thing I've wanted to have for the Mac for ages, and being a part of it almost guarantees that I'll understand it well enough to make use of it. So I'm trying my hand at this kind of thing.

Today I looked at the new testing framework someone put in. I can see the value of automated testing but I also see the problems. Today it was sloppy includes, poor test writing and missing test data. They were fixed easily enough, but it brings to mind the problems I see in automated testing in the first place: What do you really test?

I'm all for testing the public APIs of classes. That's what the class is supposed to do, and how it's supposed to do it. But private methods are another thing. I think that's asking for a ton of grief. If the method is useful enough, and important enough to test, then maybe it should be in the public API. If it's not that important, then testing the public API should exercise the private implementation details.

The guy that threw this test frame together didn't share my ideas. He's got compiler warnings testing private methods, and I just think that's not right - from several points of view. First, the testing, and then the compiler warnings. There just shouldn't be any. Period. It's so easy to remove these, and they are there for a reason - you're making a mistake. Maybe not a big one, but it's a mistake, and you need to stop right now and fix it.

Given that this is open source, it's not going to get fixed unless I fix it, but that's OK too. I don't mind being in that role for this project. It's interesting and the outcome is something I've wanted for a long time. We'll just have to roll with the punches and see where it goes.

The Start of My Last Ten Days – T minus 10

February 19th, 2009

cubeLifeView.gif

Well... today starts the first of my last ten days here at the Shop. It's an interesting time - seeing who is chosen to step up and take over pieces of the work I've spent seven and a half years building. It's surprising, and at the same time, about the only choices they can make.

As for me, I'm trying to get done all that I can - given the limited time I have. I can't work on projects that aren't going to be done, it'd be better for me to spend time getting things moved off to other people. But there are a few things I can do, and I'm ticking them off as quickly as I can.

But there's no doubt about it. I'm in the coasting/dispensing phase. I've written up a ton of stuff, people now need to read it and then come back with questions for me. I'm sure it'll get busy, but that's OK, I knew it'd happen.

It's an odd feeling. Anxious... a little nervous... but it's something that it just a part of the job. I'll get through it.

GraphicConverter 6.4 is Out

February 19th, 2009

GraphicConverter.jpg

Years ago when I was just getting back into the Mac scene, I needed something to mess with images for a few web sites I was building. I looked, and certainly couldn't afford Photoshop, and the likes of Acorn and Pixelmator weren't yet out. The low-priced landscape seemed to be dominated by GraphicConverter. Now it's at 6.4 and there are a ton of new features.

I don't use GraphicConverter as much as I used to, but it's something I'll always have because of it's place in getting me back into the Mac scene so nicely. Plus, it's just a great overall tool for graphics manipulation.

I Accepted an Offer from Chicago Trading Company

February 18th, 2009

cubeLifeView.gif

Well... I got a call today from Jeff H. at CTC, and the offer he presented was just too good to pass up. I accepted (verbally) on the phone, and he was thrilled. So was I. He's sending the paperwork out today and I should get it tomorrow. I'll do what's necessary to formally accept the offer once I get it, but that's simply a formality.

I've got a new job!

I was chatting with a few friends about it, and they encouraged me to let my current manager know today, as opposed to tomorrow morning with a formal letter. There's no reason to wait, and it gives them the evening to come to terms with it and begin the planning of what to do on my last ten days. Looking at it that way, I had to see the logic. So I told him.

Interestingly, his first words were: "You're kidding me, right?"

Nope.

We talked about what might have lead to this decision. He's been aware that I haven't been happy for the last several months, and it hasn't come as a complete surprise to him. Still... there's a lot of stuff that needs to be transitioned, and it's going to be up to him to decide how to do it. At this point, I'm answering questions and doing what they want, but I seriously doubt if they are going to be having me do any new work because I can't possible finish it in ten days.

Still... who knows.

More importantly, I'm moving on. It's been long overdue. Jeremy left nearly three years ago, and back then I didn't think I'd last the year. I lasted three. That's a lot of staying power. Troy left 9 months ago, and that was really the final blow. I knew I needed to get out. Thankfully, the position at CTC could not be a better fit. I'm excited about what's ahead, and understandably a little nervous.

Wow.

Horrible Reality TV: Solitary 3.0

February 18th, 2009

TV.jpg

I was watching an episode of Solitary 3.0 this weekend, and I have to say that reality TV has hit a brand new low for me. I mean, I can see that some reality TV is just trash from the word 'go', but this seemed like it might have had a shred of interesting content in that it could have been done in a format where people were really stressed, and really was the equivalent of solitary confinement.

But no... this is just individual achievement. Better to call it "Everyone for Themselves". There's no extended period of silence. No sensory deprivation. No real psychological stress put on these folks... they get to smell crappy things, sit on painful seats, do stupid drinking games with Root Beer... it's constant games. Not like any solitary any prisoner ever faced.

In the end, I realize that they can't really hurt someone for fear of a lawsuit. But they could have made it a lot more interesting. I can't imagine I'll ever watch again.

The Case of the International Prima Dona

February 18th, 2009

cubeLifeView.gif

Yeah... remote access to work is both a blessing and a curse. There are a few times when it's nice to be able to be at home and get a little work done, but in reality, my work is done on several monitors, with (literally) a dozen different Vim sessions open and at least a half dozen shells open to edit, compile, run, monitor and debug the code. It's work. So having a laptop with a 14" screen is not really getting that kind of work done, but in a pinch, it can be done.

No, realistically, it's the support of production systems that remote access is for. That's where it really pays for itself. If you have to get in and fix a database issue, or do a quick fix to a script, then there's nothing like it. Nothing. Getting in a car, driving 45 mins to the office at midnight is just not realistic. You need to be able to do some things - triage the problem, remotely in a few minutes. That's what remote access into work is for.

So while "new guys" look upon it as a liberating, no almost empowering status symbol. "I have remote access now." But then a few years on, they realize that they have no recourse when work needs to be done on off-hours. So it's the thoughtful, or egocentric person that refuses remote access even when it's asked that he have it.

Such was the case today I learned of a co-worker in another land. This co-worker is going to hold up the deployment of a multi-million dollar system because he doesn't want to come in on the weekend and refuses to accept the offered remote access solution so it can be done from home. Interesting idea. Part of me is impressed at this guy's sense of boundaries. There is work, and there is home, and they are not to be confused with one another. Bravo.

But if I were this guy's boss, it'd be a simple business fact of life. One person, no matter how well-intentioned, respected, kind, generous, and giving, can hold up a multi-million dollar project. No one. Period. If he can't do it, then he's got one choice - get it or get out. It's as simple as that. Management is not about being nice. It's about managing a project with risks and rewards. If one person has the ability to hold up that process, then they are a fundamental risk that needs to be addressed. That risk must be eliminated, or at least significantly reduced.

And while I admire his bravado, I am appalled at his arrogance. I don't want to answer problems in the middle of the night. But I do. It's a fact of life in a team where the business runs 24x5. Period. I've taken countless calls - from this guy in the middle of the night, and not complained about it. Yet he feels he's entitled to be the one holdout to this invasion of our personal time.

Good for him. But if I were this guy's manager he'd be toeing the line or walking out the door. It's that simple. This place needs to have a little sacrifice. There aren't enough people to cover things completely all the time. You have to take the lumps now and then. And by making this stand, he's saying there's no reason to do it, and thus empowering the next person to take a similar stand.

If this catches on, there's not going to be anyone for him to call when he needs help. I'm sure he doesn't care, as he'd blame us for not being available.

So I label this person an International Prima Dona. They believe the rules apply to everyone except them. They are the One, after all. In the end, he's nothing more than someone expecting special treatment, and that's likely to get him special treatment by a lot of folks. I hope he's really ready for it.

GIMP on Mac OS X 2.6.5 is Out

February 18th, 2009

Gimp.jpg

I've been a user of GIMP for more than a decade, and it's always been a solid graphics tool - invaluable on some platforms that have nothing else, but even a nice to have on the Mac. There are just some things that it does exceptionally well. But of late, the builds of GIMP for Mac OS X for Leopard have required that you update the X11 package to a more recent build of the XQuartz project - the basis of Apple's X11 package. While I've wanted to stay current with GIMP, I did not want to have a non-standard X11 install. So I was stuck.

Until now. Today I saw that GIMP for Mac OS X 2.6.5 was released, and I decided to download it on the off-chance that it would run on a stock Leopard install. It did! Fantastic!

While it's not going to be something I run all the time, like Acorn, it's something I'm really glad I have at my disposal when I need it. This is wonderful news.

Interesting Application of Thread-Safe Lockless Data Structures

February 17th, 2009

cplusplus.jpg

I was looking at lockless data structures for multi-threaded programming again this morning, and I came across a link to TransactionKit. This sounds very interesting to me. Basically, the group has implemented a thread-safe NSDictionary and NSMutableDictionary pair that are completely safe for multi-threaded environments, use no locks, and offer the basics of transactional integrity: begin transaction, commit and rollback functionality. And I have to admit I'm very intrigued.

The biggest challenge to me in working with these lockless data structures is that you might not know you're going to need them when you start the project. It's only after you build the project, see it scale for a while, and then hit a fundamental limit that you see it's time to switch over. Problem is, by then, you're stuck. You've got all this code that uses one form of thread-safety, and now what you realize you need is something else all together. But you can't justify the complete re-write.

What you need is lockless alternatives to standard data components that are easily swapped in when the 'going gets tough'. For example, I like TransactionKit's take on the inclusion in Objective-C - make it look like a simple NSDictionary and NSMutableDictionary so that it's a simple search and replace for the vast majority of the retrofitting. This makes things a lot simpler.

But now I'm looking at the CKit stuff. It'd be one thing to have a truly lockless CKFIFOQueue. Then another that uses mutexes for those times when it's not a major issue for speed. Finally, one that uses the lockless atomic calls to make it appear to be lockless, in fact, you can even simply No-Op the lock() and unlock() methods in the subclass, but all the while, the thread-safe behavior is in play.

The problems with general coding are a lot more difficult, however. Take for example, the retain/release code I posted a few days ago. That's not so simple. Previously, I had:

void Instrument::retain()
{
    // first, lock this guy up
    CKStackLocker      lockem(&mRetainReleaseMutex);
    // now up the count
    ++mRetainReleaseCount;
    // see if it's in the pool to be released, if so, remove it
    if (mRetainReleaseCount == 1) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        mReleasePool.remove(this);
    }
}
 
void Instrument::release()
{
    // first, lock this guy up
    CKStackLocker      lockem(&mRetainReleaseMutex);
    // no decrease the count
    --mRetainReleaseCount;
    // see if it's an error
    if (mRetainReleaseCount < 0) {
        getLog() << l_error.setErrorId("Instrument.release")
                 << "the release count for " << mmSym() << " went negative! ("
                 << mRetainReleaseCount << ") This is a serious problem." << endl;
    }
    // see if it's at zero, and then if so, add it to the pool
    if (mRetainReleaseCount <= 0) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        if (!mReleasePool.contains(this)) {
            // log that we're going to dump it in the trash
            getLog() << l_error.setErrorId("Instrument.release")
                     << "adding " << mmSym() << " with retain cnt="
                     << mRetainReleaseCount << " to garbage" << endl;
            // ...and then do it.
            mReleasePool.addBack(this);
        }
    }
}

where the critical points were one (1) in the retain() code and anything less than or equal to zero in the release() code. This was due to the logical assumption that the value of mRetainReleaseCount would be initialized to 1. But what if we have it initialized to zero? Then the critical points are zero for the retain() code and anything negative for the release() code.

#include <asm/atomic.h>
 
void Instrument::retain()
{
    /*
     * Increment the count. If it's zero, then we were ready to flush this guy
     * and now we need to pull him out of the garbage before he gets flushed.
     */
    if (atomic_inc_and_test(&mRetainReleaseCount)) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        mReleasePool.remove(this);
    }
}
 
void Instrument::release()
{
    /*
     * Decrement the count, and if we are negative then it's time to add this
     * guy to the release pool for deletion.
     */
    if (atomic_add_negative(-1, &mRetainReleaseCount)) {
        CKStackLocker      lockem(&mReleasePoolMutex);
        if (!mReleasePool.contains(this)) {
            // log that we're going to dump it in the trash
            getLog() << l_error.setErrorId("Instrument.release")
                     << "adding " << mmSym() << " with retain cnt="
                     << mRetainReleaseCount << " to garbage" << endl;
            // ...and then do it.
            mReleasePool.addBack(this);
        }
    }
}

if I then initialize the value of mRetainReleaseCount with:

    ...
    mRetainReleaseCount(ATOMIC_INIT(0)),
    ...

in the constructor's code, then we'll start with zero, climb positive, and then when we go negative we'll by tossed into the release pool for the next cycle on the garbage collector thread. Since the garbage collector thread also checks the retain/release count before it wipes out the instance, we're safe.

At least I'm pretty sure we are...

Well... here's the problem I see now. Because we have removed the mutex on the retain() and release() methods, we can be doing both at once. The count will be handled properly, but what if the release() hits it's counter operation first, but the retain() method's if() body executes first to get the lock on the second mutex?

Now we're in trouble. The counter will be saying 'leave the instrument out of the pool', but the code will execute in the order indicating that the instance will be placed into the pool. Crud.

Yup, this is not easy. I was ready to put the code into play, but there's no guarantee that the body of the conditional will execute in the same order as the atomic operation. This means that it's possible to have them in the wrong order. This, in turn, tells me that the greatest application of these atomic operations are in the thread-safe lockless data structures. That's about it. When you have two operations that need to be treated atomically, then you're sunk. Darn.

VelaClock 2.1.11 is Out

February 17th, 2009

VelaClock.gif

I have users in many different timezones, and I do my best to keep them all straight - most of the time. But there are times - around the switches where I'm not exactly sure what the time is in London - or Hong Kong. So a few years ago, I got VelaClock for my Mac.

It's a wonderful little Dashboard widget that allows me to keep track of each timezone in a nice, little, compact widget. It's much better than the World Clock widget from Apple, and it's got all kinds of nice little capabilities that I just don't use.

This morning, I noticed that they released version 2.1.11. It's too bad the auto-updater in the widget doesn't work, but that's no big deal. I can go to the site and download it from there. Nice to have for people dealing with a lot of different timezones.