LoginSignup
10
10

More than 5 years have passed since last update.

SwiftからMachのhost_info()を呼び出す(UnsafePointerのキャスト)

Posted at

実はSwift用のMach IPCインターフェース定義が用意されています。
これを使えば簡単に呼び出せると思いきや、ものによってはタイプセーフなSwiftと相性が悪く呼び出すのが難しい場合があります。

たとえばホストの情報を取得するhost_info()の定義は以下のようになっています。

Darwin/Mach/mach_host
func host_info(host: host_t, flavor: host_flavor_t, host_info_out: host_info_t, host_info_outCnt: UnsafePointer<mach_msg_type_number_t>) -> kern_return_t

flavorに欲しい情報の種類を指定して、値を収めるメモリのポインタとその大きさを渡すとその領域にセットしてくれるというものです。flavorごとにhost_info_outに指定する構造体の型と長さが異なるのでこうなっているわけですが、この実にC言語っぽい仕様はSwiftでは曲者です。

とりあえずflavor HOST_BASIC_INFOを取得する場合のコードは以下のようになります。

import Foundation

/// カーネル用のポートを取得する
var hostPort = mach_host_self()

/// メモリ領域を確保してそのポインタを得る
/// 意味はmalloc(sizeof(host_basic_info) * 1)と同じ
var buffer = UnsafePointer<host_basic_info>.alloc(1)
/// HOST_BASIC_INFO_COUNTが定義されていないので自分で計算する
var bufferCount = mach_msg_type_number_t(sizeof(host_basic_info) / sizeof(integer_t))

/// 引数の型に合わせてポインタをキャストする
var ptr = host_info_t(buffer)

/// host_info()を呼び出して値を取得する
var result = host_info(hostPort, HOST_BASIC_INFO, ptr, &bufferCount)

/// ポインタの先をstruct host_basic_infoとして参照する
var basic_info = buffer.memory

var max_cpus         = basic_info.max_cpus
var avail_cpus       = basic_info.avail_cpus
var memory_size      = basic_info.memory_size
var cpu_type         = basic_info.cpu_type
var cpu_subtype      = basic_info.cpu_subtype
var cpu_threadtype   = basic_info.cpu_threadtype
var physical_cpu     = basic_info.physical_cpu
var physical_cpu_max = basic_info.physical_cpu_max
var logical_cpu      = basic_info.logical_cpu
var logical_cpu_max  = basic_info.logical_cpu_max
var max_mem          = basic_info.max_mem

/// 確保したメモリを破棄する
buffer.destroy()

host_info()の引数host_info_outの型であるhost_info_tUnsafePointer<integer_t>のエイリアスです。この引数の場合はinteger_t単位のメモリ領域の先頭アドレスという意味になります。host_info_outCntにはその領域がinteger_t何個分の大きさなのかを指定します。

ポインタの型がUnsafePointer<host_basic_info>であれば簡単な話なのですが、そうではないのでなんとかしてUnsafePointer<integer_t>にキャストする必要があります。

が、UnsafePointerにキャストできるのはUnsafePointerCOpaquePointerだけのようです。

そして、Swiftの中でUnsafePointerを作り出す方法は以下の方法しかないようです。

  • COpaquePointerから
  • 任意のアドレス値から
  • UnsafePointerから
  • ConstUnsafePointerから
  • ヌルポインタとして
  • メモリを確保してそこへのポインタとして

ということでUnsafePointer<host_basic_info>.alloc()でアンセーフなメモリを確保して、その中に返してもらって、利用後に速やかに破棄するという感じにしかならないようです。

10
10
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10