読者です 読者をやめる 読者になる 読者になる

ゆとりーなの日記

日記的な事を書いて行くと思はれる

宿が見つからなかったので一週間日記書けないという事態は回避できたか

PSPSDKでも最初に初期化、終了前に後始末しなければいけないものは多々あるので、管理クラスを作ったとします。メイン関数をこんな感じに書いたとしましょう。

int main() {
  application app;
  return app.run();
}

guやaudioの初期化及び後始末があるのでapplicationクラスはこれらを管理するオブジェクトをメンバとして持ってるとします。runメソッドは例よって内部で無限ループを持っています。
で、ホームボタンを押して終了を選ぶとXMBに戻れますが、この処理は一般的に次のように書きます。

int exit_callback(int, int, void *) {
  sceKernelExitGame();
  return 0;
}

int callback_thread(SceSize, void *) {
  const int id = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
  sceKernelRegisterExitCallback(id);
  sceKernelSleepThreadCB();
  return 0;
}
int setup_callbacks() {
  const int id = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, 0);
  if (id >= 0) {
    sceKernelStartThread(id, 0, 0);
  }
  return id;
}

ゲームの最初(applicationのコンストラクタとか)でsetup_callbacksを呼んでやれば実現できます。しかしこれをそのままやっても、ホームボタン経由でゲームを終了するとき、多分applicationクラスのデストラクタがsceKernelExitGame後に呼ばれてしまい、gu等の後始末がsceKernelExitGame後になってしまいます。まぁ正直だからと言ってPSPがバグったりすることはなかったのですが、ここはお行儀よくsceKernelExitGame前にgu等の後始末をしたいところです。しかしexit_callbackの中でgu等の後始末を書いてしまうと、applicationクラスの初期化が終わる前にホームボタン経由でゲームを終了した(そんなタイミングで押せるかは不明ですが)場合にお行儀よくありません。そこでスレッド関連の関数には所謂ユーザーデータを渡す機構が当然の様に備わっているのでこれを使って今動いているapplicationクラスインスタンスの無限ループを終了させるメソッドを呼ぶことにしましょう。

int exit_callback(int, int, void *self) {
  static_cast<application *>(self)->quit();
  return 0;
}

int callback_thread(SceSize, void *self) {
  const int id = sceKernelCreateCallback("Exit Callback", exit_callback, *static_cast<application **>(self));
  sceKernelRegisterExitCallback(id);
  sceKernelSleepThreadCB();
  return 0;
}
int setup_callbacks(application *self) {
  const int id = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, 0);
  if (id >= 0) {
    sceKernelStartThread(id, seizeof(self), &self);
  }
  return id;
}

これでいけるはずです。setup_callbacks呼び出しの際にapplicationのthisポインタを渡してやります。注意としてはsceKernelStartThreadで渡すのは渡したいデータのアドレスであり、callback_threadで渡されるのはダブルポインタになるところですかね。sceKernelStartThreadで単純にselfを渡すとapplicationクラスが丸々コピーされる感じになると思う(sizeofも*selfにする必要がありそう)ので、敢えてダブルポインタにした方がいいんじゃないかな〜と思った次第です。取り敢えずこれで終了しないとかクラッシュするとかいうことは起きてないんで問題なさそうです。