Using GLFW with libdispatch on OS X
One of the benefits of using GLFW is that it largely strips out a lot of the work you'd need to do on OS X to create a GL window and so on (this isn't a large amount of work, granted, but it's boilerplate crap nobody likes doing). Unfortunately, libdispatch doesn't play nice with it or really any other UI library without knowing a little about how OS X does windowing and how libdispatch expects you to do things.
When creating an application that uses libdispatch, your first instinct might be to queue up a task that would otherwise contain the entry point/initialization routine of your program and call
dispatch_main() to give the process over to libdispatch. This works extremely well for command-line utilities where you don't need to know anything but you do need to work with the main queue (if you're not using the main queue, you don't need to call
dispatch_main(), but this is unlikely in game dev). This doesn't work well in other scenarios because dispatch_main terminates thread zero, the thread OS X expects all UI code to run on. So, it plays hell with OS X and, as a result, also screws with GLFW.
The trick is to keep the main queue on thread zero. The downside is this requires a little platform-specific code. Specifically, you'll want to use Cocoa's NSRunLoop to kick off the application's main run loop, which will in turn receive events and process the main dispatch queue. This is as simple as calling
[[NSRunLoop mainRunLoop] run]. You may also be able to use
CFRunLoopRun(), but I recommend using Cocoa instead of Core Foundation where possible (it makes life easier).
So, with the NSRunLoop working, your next instinct might be to again throw your initialization task on the main queue and begin your frame loop in that task, but that would then block the main queue, which you'll need in order to poll for events and so on. Instead, you want to create a new thread for your frame loop, then using libdispatch, create tasks on the main thread to poll for events as needed. Make note of what has to be done on the main thread and push that off to tasks run on the main thread.
Once the frame loop thread has started, you can leave your init code and let the main queue handle whatever it needs to via the
NSRunLoop. This includes windowing, events, and so on that your frame loop can blissfully ignore until it's needed. In other words, it prevents the UI from blocking game logic except where needed and it prevents game logic from blocking the UI. Most everything ends up being relatively lag-free.
Your frame loop can then handle input, rendering, and whatever else. Note that you do not have to do rendering on the frameloop thread. You might want to create a serial queue specifically for working with OpenGL, thereby allowing your rendering and game logic to run concurrently without blocking one another. You'll also need to create a thread-safe way to send events to the frame loop thread, but that's easy enough and makes it a lot safer to work with GLFW events (without worrying about callback restrictions). I've already done all that, so it's not hard, especially given what libdispatch lets you do to simplify synchronization.
Because I'm crap at explaining all this, however, I've also included the source code for a very bare-bones main source file using libdispatch and GLFW 3.0 on OS X. This code sample requires a C++11 compiler. I use Clang and libc++, but really the most prevalent compilers now should support enough of C++11 for this. The sample also assumes you are defining
TARGET_OS_MAC and passing
-ObjC++ (so you can make use of ObjC features) in your compiler flags. The example is attached below.
And for those wondering how to handle using libdispatch on other operating systems, you might want to check out xdispatch (link below, not attached), which ports it to other OSes. Granted, the other OSes won't have the same performance as OS X and the BSDs since they lack kqueue, which allows all of this to be done very, very quickly. Still, it's a handy tool and something to keep in mind.
(I originally posted this on SoCoder, but will also throw it on Google+ since I don't actually know a lot of folks who frequent SoCoder.)