実はSwift用のMach IPCインターフェース定義が用意されています。
これを使えば簡単に呼び出せると思いきや、ものによってはタイプセーフなSwiftと相性が悪く呼び出すのが難しい場合があります。
たとえばホストの情報を取得するhost_info()
の定義は以下のようになっています。
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_t
はUnsafePointer<integer_t>
のエイリアスです。この引数の場合はinteger_t
単位のメモリ領域の先頭アドレスという意味になります。host_info_outCntにはその領域がinteger_t
何個分の大きさなのかを指定します。
ポインタの型がUnsafePointer<host_basic_info>
であれば簡単な話なのですが、そうではないのでなんとかしてUnsafePointer<integer_t>
にキャストする必要があります。
が、UnsafePointer
にキャストできるのはUnsafePointer
かCOpaquePointer
だけのようです。
そして、Swiftの中でUnsafePointer
を作り出す方法は以下の方法しかないようです。
-
COpaquePointer
から - 任意のアドレス値から
-
UnsafePointer
から -
ConstUnsafePointer
から - ヌルポインタとして
- メモリを確保してそこへのポインタとして
ということでUnsafePointer<host_basic_info>.alloc()
でアンセーフなメモリを確保して、その中に返してもらって、利用後に速やかに破棄するという感じにしかならないようです。