static uint32_t
appIoThreadEntry(uint32_t coreId, void *arg2)
{
   auto queue = &sAppIo->queues[coreId];
   OSInitMessageQueue(queue, &sAppIo->messages[coreId * MessagesPerCore], MessagesPerCore);

   while (true) {
      OSMessage msg;
      OSReceiveMessage(queue, &msg, OSMessageFlags::Blocking);

      auto funcType = static_cast<OSFunctionType>(msg.args[2].value());

      switch (funcType) {
      case OSFunctionType::FsaCmdAsync:
      {
         auto result = FSAGetAsyncResult(&msg);
         if (result->userCallback) {
            result->userCallback(result->error,
                                 result->command,
                                 result->request,
                                 result->response,
                                 result->userContext);
         }
         break;
      }
      case OSFunctionType::FsCmdAsync:
      {
         auto result = FSGetAsyncResult(&msg);
         if (result->asyncData.userCallback) {
            result->asyncData.userCallback(result->client,
                                           result->block,
                                           result->status,
                                           result->asyncData.userContext);
         }
         break;
      }
      case OSFunctionType::FsCmdHandler:
      {
         fsCmdBlockHandleResult(reinterpret_cast<FSCmdBlockBody *>(msg.message.get()));
         break;
      }
      default:
         decaf_abort(fmt::format("Unimplemented OSFunctionType {}", funcType));
      }
   }
}
int msgThreadEntry(int argc, const char **argv)
{
   // Give main thread a chance to block on the message queue
   OSMessage msg;
   sMessagesRead = 0;

   while (sMessagesRead < NumMessages) {
      // Receive message
      test_eq(OSReceiveMessage(&sQueue, &msg, OS_MESSAGE_FLAGS_BLOCKING), TRUE);
      test_eq(msg.message, (void *)1);
      test_eq(msg.args[0], 2 + sMessagesRead);
      test_eq(msg.args[1], 3);
      test_eq(msg.args[2], 4);
      ++sMessagesRead;
   }

   return 0;
}